Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.16-rc2 676 lines 18 kB view raw
1/* 2 * Samsung EXYNOS5 SoC series USB DRD PHY driver 3 * 4 * Phy provider for USB 3.0 DRD controller on Exynos5 SoC series 5 * 6 * Copyright (C) 2014 Samsung Electronics Co., Ltd. 7 * Author: Vivek Gautam <gautam.vivek@samsung.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14#include <linux/clk.h> 15#include <linux/delay.h> 16#include <linux/io.h> 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/of.h> 20#include <linux/of_address.h> 21#include <linux/phy/phy.h> 22#include <linux/platform_device.h> 23#include <linux/mutex.h> 24#include <linux/mfd/syscon.h> 25#include <linux/mfd/syscon/exynos5-pmu.h> 26#include <linux/regmap.h> 27#include <linux/regulator/consumer.h> 28 29/* Exynos USB PHY registers */ 30#define EXYNOS5_FSEL_9MHZ6 0x0 31#define EXYNOS5_FSEL_10MHZ 0x1 32#define EXYNOS5_FSEL_12MHZ 0x2 33#define EXYNOS5_FSEL_19MHZ2 0x3 34#define EXYNOS5_FSEL_20MHZ 0x4 35#define EXYNOS5_FSEL_24MHZ 0x5 36#define EXYNOS5_FSEL_50MHZ 0x7 37 38/* EXYNOS5: USB 3.0 DRD PHY registers */ 39#define EXYNOS5_DRD_LINKSYSTEM 0x04 40 41#define LINKSYSTEM_FLADJ_MASK (0x3f << 1) 42#define LINKSYSTEM_FLADJ(_x) ((_x) << 1) 43#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27) 44 45#define EXYNOS5_DRD_PHYUTMI 0x08 46 47#define PHYUTMI_OTGDISABLE BIT(6) 48#define PHYUTMI_FORCESUSPEND BIT(1) 49#define PHYUTMI_FORCESLEEP BIT(0) 50 51#define EXYNOS5_DRD_PHYPIPE 0x0c 52 53#define EXYNOS5_DRD_PHYCLKRST 0x10 54 55#define PHYCLKRST_EN_UTMISUSPEND BIT(31) 56 57#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23) 58#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23) 59 60#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21) 61#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21) 62 63#define PHYCLKRST_SSC_EN BIT(20) 64#define PHYCLKRST_REF_SSP_EN BIT(19) 65#define PHYCLKRST_REF_CLKDIV2 BIT(18) 66 67#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11) 68#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11) 69#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x32 << 11) 70#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11) 71#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11) 72#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11) 73 74#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5) 75#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8) 76#define PHYCLKRST_FSEL(_x) ((_x) << 5) 77#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5) 78#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5) 79#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5) 80#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5) 81 82#define PHYCLKRST_RETENABLEN BIT(4) 83 84#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2) 85#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2) 86#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2) 87 88#define PHYCLKRST_PORTRESET BIT(1) 89#define PHYCLKRST_COMMONONN BIT(0) 90 91#define EXYNOS5_DRD_PHYREG0 0x14 92#define EXYNOS5_DRD_PHYREG1 0x18 93 94#define EXYNOS5_DRD_PHYPARAM0 0x1c 95 96#define PHYPARAM0_REF_USE_PAD BIT(31) 97#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26) 98#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26) 99 100#define EXYNOS5_DRD_PHYPARAM1 0x20 101 102#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0) 103#define PHYPARAM1_PCS_TXDEEMPH (0x1c) 104 105#define EXYNOS5_DRD_PHYTERM 0x24 106 107#define EXYNOS5_DRD_PHYTEST 0x28 108 109#define PHYTEST_POWERDOWN_SSP BIT(3) 110#define PHYTEST_POWERDOWN_HSP BIT(2) 111 112#define EXYNOS5_DRD_PHYADP 0x2c 113 114#define EXYNOS5_DRD_PHYUTMICLKSEL 0x30 115 116#define PHYUTMICLKSEL_UTMI_CLKSEL BIT(2) 117 118#define EXYNOS5_DRD_PHYRESUME 0x34 119#define EXYNOS5_DRD_LINKPORT 0x44 120 121#define KHZ 1000 122#define MHZ (KHZ * KHZ) 123 124enum exynos5_usbdrd_phy_id { 125 EXYNOS5_DRDPHY_UTMI, 126 EXYNOS5_DRDPHY_PIPE3, 127 EXYNOS5_DRDPHYS_NUM, 128}; 129 130struct phy_usb_instance; 131struct exynos5_usbdrd_phy; 132 133struct exynos5_usbdrd_phy_config { 134 u32 id; 135 void (*phy_isol)(struct phy_usb_instance *inst, u32 on); 136 void (*phy_init)(struct exynos5_usbdrd_phy *phy_drd); 137 unsigned int (*set_refclk)(struct phy_usb_instance *inst); 138}; 139 140struct exynos5_usbdrd_phy_drvdata { 141 const struct exynos5_usbdrd_phy_config *phy_cfg; 142 u32 pmu_offset_usbdrd0_phy; 143 u32 pmu_offset_usbdrd1_phy; 144}; 145 146/** 147 * struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY 148 * @dev: pointer to device instance of this platform device 149 * @reg_phy: usb phy controller register memory base 150 * @clk: phy clock for register access 151 * @drv_data: pointer to SoC level driver data structure 152 * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY 153 * instances each with its 'phy' and 'phy_cfg'. 154 * @extrefclk: frequency select settings when using 'separate 155 * reference clocks' for SS and HS operations 156 * @ref_clk: reference clock to PHY block from which PHY's 157 * operational clocks are derived 158 * @ref_rate: rate of above reference clock 159 */ 160struct exynos5_usbdrd_phy { 161 struct device *dev; 162 void __iomem *reg_phy; 163 struct clk *clk; 164 const struct exynos5_usbdrd_phy_drvdata *drv_data; 165 struct phy_usb_instance { 166 struct phy *phy; 167 u32 index; 168 struct regmap *reg_pmu; 169 u32 pmu_offset; 170 const struct exynos5_usbdrd_phy_config *phy_cfg; 171 } phys[EXYNOS5_DRDPHYS_NUM]; 172 u32 extrefclk; 173 struct clk *ref_clk; 174 struct regulator *vbus; 175}; 176 177static inline 178struct exynos5_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst) 179{ 180 return container_of((inst), struct exynos5_usbdrd_phy, 181 phys[(inst)->index]); 182} 183 184/* 185 * exynos5_rate_to_clk() converts the supplied clock rate to the value that 186 * can be written to the phy register. 187 */ 188static unsigned int exynos5_rate_to_clk(unsigned long rate, u32 *reg) 189{ 190 /* EXYNOS5_FSEL_MASK */ 191 192 switch (rate) { 193 case 9600 * KHZ: 194 *reg = EXYNOS5_FSEL_9MHZ6; 195 break; 196 case 10 * MHZ: 197 *reg = EXYNOS5_FSEL_10MHZ; 198 break; 199 case 12 * MHZ: 200 *reg = EXYNOS5_FSEL_12MHZ; 201 break; 202 case 19200 * KHZ: 203 *reg = EXYNOS5_FSEL_19MHZ2; 204 break; 205 case 20 * MHZ: 206 *reg = EXYNOS5_FSEL_20MHZ; 207 break; 208 case 24 * MHZ: 209 *reg = EXYNOS5_FSEL_24MHZ; 210 break; 211 case 50 * MHZ: 212 *reg = EXYNOS5_FSEL_50MHZ; 213 break; 214 default: 215 return -EINVAL; 216 } 217 218 return 0; 219} 220 221static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst, 222 unsigned int on) 223{ 224 unsigned int val; 225 226 if (!inst->reg_pmu) 227 return; 228 229 val = on ? 0 : EXYNOS5_PHY_ENABLE; 230 231 regmap_update_bits(inst->reg_pmu, inst->pmu_offset, 232 EXYNOS5_PHY_ENABLE, val); 233} 234 235/* 236 * Sets the pipe3 phy's clk as EXTREFCLK (XXTI) which is internal clock 237 * from clock core. Further sets multiplier values and spread spectrum 238 * clock settings for SuperSpeed operations. 239 */ 240static unsigned int 241exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) 242{ 243 static u32 reg; 244 struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 245 246 /* restore any previous reference clock settings */ 247 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); 248 249 /* Use EXTREFCLK as ref clock */ 250 reg &= ~PHYCLKRST_REFCLKSEL_MASK; 251 reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK; 252 253 /* FSEL settings corresponding to reference clock */ 254 reg &= ~PHYCLKRST_FSEL_PIPE_MASK | 255 PHYCLKRST_MPLL_MULTIPLIER_MASK | 256 PHYCLKRST_SSC_REFCLKSEL_MASK; 257 switch (phy_drd->extrefclk) { 258 case EXYNOS5_FSEL_50MHZ: 259 reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF | 260 PHYCLKRST_SSC_REFCLKSEL(0x00)); 261 break; 262 case EXYNOS5_FSEL_24MHZ: 263 reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | 264 PHYCLKRST_SSC_REFCLKSEL(0x88)); 265 break; 266 case EXYNOS5_FSEL_20MHZ: 267 reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF | 268 PHYCLKRST_SSC_REFCLKSEL(0x00)); 269 break; 270 case EXYNOS5_FSEL_19MHZ2: 271 reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF | 272 PHYCLKRST_SSC_REFCLKSEL(0x88)); 273 break; 274 default: 275 dev_dbg(phy_drd->dev, "unsupported ref clk\n"); 276 break; 277 } 278 279 return reg; 280} 281 282/* 283 * Sets the utmi phy's clk as EXTREFCLK (XXTI) which is internal clock 284 * from clock core. Further sets the FSEL values for HighSpeed operations. 285 */ 286static unsigned int 287exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst) 288{ 289 static u32 reg; 290 struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 291 292 /* restore any previous reference clock settings */ 293 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); 294 295 reg &= ~PHYCLKRST_REFCLKSEL_MASK; 296 reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK; 297 298 reg &= ~PHYCLKRST_FSEL_UTMI_MASK | 299 PHYCLKRST_MPLL_MULTIPLIER_MASK | 300 PHYCLKRST_SSC_REFCLKSEL_MASK; 301 reg |= PHYCLKRST_FSEL(phy_drd->extrefclk); 302 303 return reg; 304} 305 306static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) 307{ 308 u32 reg; 309 310 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); 311 /* Set Tx De-Emphasis level */ 312 reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; 313 reg |= PHYPARAM1_PCS_TXDEEMPH; 314 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); 315 316 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 317 reg &= ~PHYTEST_POWERDOWN_SSP; 318 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 319} 320 321static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) 322{ 323 u32 reg; 324 325 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); 326 /* Set Loss-of-Signal Detector sensitivity */ 327 reg &= ~PHYPARAM0_REF_LOSLEVEL_MASK; 328 reg |= PHYPARAM0_REF_LOSLEVEL; 329 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); 330 331 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); 332 /* Set Tx De-Emphasis level */ 333 reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; 334 reg |= PHYPARAM1_PCS_TXDEEMPH; 335 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); 336 337 /* UTMI Power Control */ 338 writel(PHYUTMI_OTGDISABLE, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); 339 340 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 341 reg &= ~PHYTEST_POWERDOWN_HSP; 342 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 343} 344 345static int exynos5_usbdrd_phy_init(struct phy *phy) 346{ 347 int ret; 348 u32 reg; 349 struct phy_usb_instance *inst = phy_get_drvdata(phy); 350 struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 351 352 ret = clk_prepare_enable(phy_drd->clk); 353 if (ret) 354 return ret; 355 356 /* Reset USB 3.0 PHY */ 357 writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); 358 writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYRESUME); 359 360 /* 361 * Setting the Frame length Adj value[6:1] to default 0x20 362 * See xHCI 1.0 spec, 5.2.4 363 */ 364 reg = LINKSYSTEM_XHCI_VERSION_CONTROL | 365 LINKSYSTEM_FLADJ(0x20); 366 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); 367 368 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); 369 /* Select PHY CLK source */ 370 reg &= ~PHYPARAM0_REF_USE_PAD; 371 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); 372 373 /* This bit must be set for both HS and SS operations */ 374 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL); 375 reg |= PHYUTMICLKSEL_UTMI_CLKSEL; 376 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL); 377 378 /* UTMI or PIPE3 specific init */ 379 inst->phy_cfg->phy_init(phy_drd); 380 381 /* reference clock settings */ 382 reg = inst->phy_cfg->set_refclk(inst); 383 384 /* Digital power supply in normal operating mode */ 385 reg |= PHYCLKRST_RETENABLEN | 386 /* Enable ref clock for SS function */ 387 PHYCLKRST_REF_SSP_EN | 388 /* Enable spread spectrum */ 389 PHYCLKRST_SSC_EN | 390 /* Power down HS Bias and PLL blocks in suspend mode */ 391 PHYCLKRST_COMMONONN | 392 /* Reset the port */ 393 PHYCLKRST_PORTRESET; 394 395 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); 396 397 udelay(10); 398 399 reg &= ~PHYCLKRST_PORTRESET; 400 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); 401 402 clk_disable_unprepare(phy_drd->clk); 403 404 return 0; 405} 406 407static int exynos5_usbdrd_phy_exit(struct phy *phy) 408{ 409 int ret; 410 u32 reg; 411 struct phy_usb_instance *inst = phy_get_drvdata(phy); 412 struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 413 414 ret = clk_prepare_enable(phy_drd->clk); 415 if (ret) 416 return ret; 417 418 reg = PHYUTMI_OTGDISABLE | 419 PHYUTMI_FORCESUSPEND | 420 PHYUTMI_FORCESLEEP; 421 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); 422 423 /* Resetting the PHYCLKRST enable bits to reduce leakage current */ 424 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); 425 reg &= ~(PHYCLKRST_REF_SSP_EN | 426 PHYCLKRST_SSC_EN | 427 PHYCLKRST_COMMONONN); 428 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); 429 430 /* Control PHYTEST to remove leakage current */ 431 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 432 reg |= PHYTEST_POWERDOWN_SSP | 433 PHYTEST_POWERDOWN_HSP; 434 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 435 436 clk_disable_unprepare(phy_drd->clk); 437 438 return 0; 439} 440 441static int exynos5_usbdrd_phy_power_on(struct phy *phy) 442{ 443 int ret; 444 struct phy_usb_instance *inst = phy_get_drvdata(phy); 445 struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 446 447 dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); 448 449 clk_prepare_enable(phy_drd->ref_clk); 450 451 /* Enable VBUS supply */ 452 if (phy_drd->vbus) { 453 ret = regulator_enable(phy_drd->vbus); 454 if (ret) { 455 dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); 456 goto fail_vbus; 457 } 458 } 459 460 /* Power-on PHY*/ 461 inst->phy_cfg->phy_isol(inst, 0); 462 463 return 0; 464 465fail_vbus: 466 clk_disable_unprepare(phy_drd->ref_clk); 467 468 return ret; 469} 470 471static int exynos5_usbdrd_phy_power_off(struct phy *phy) 472{ 473 struct phy_usb_instance *inst = phy_get_drvdata(phy); 474 struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 475 476 dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n"); 477 478 /* Power-off the PHY */ 479 inst->phy_cfg->phy_isol(inst, 1); 480 481 /* Disable VBUS supply */ 482 if (phy_drd->vbus) 483 regulator_disable(phy_drd->vbus); 484 485 clk_disable_unprepare(phy_drd->ref_clk); 486 487 return 0; 488} 489 490static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, 491 struct of_phandle_args *args) 492{ 493 struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev); 494 495 if (WARN_ON(args->args[0] > EXYNOS5_DRDPHYS_NUM)) 496 return ERR_PTR(-ENODEV); 497 498 return phy_drd->phys[args->args[0]].phy; 499} 500 501static struct phy_ops exynos5_usbdrd_phy_ops = { 502 .init = exynos5_usbdrd_phy_init, 503 .exit = exynos5_usbdrd_phy_exit, 504 .power_on = exynos5_usbdrd_phy_power_on, 505 .power_off = exynos5_usbdrd_phy_power_off, 506 .owner = THIS_MODULE, 507}; 508 509const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { 510 { 511 .id = EXYNOS5_DRDPHY_UTMI, 512 .phy_isol = exynos5_usbdrd_phy_isol, 513 .phy_init = exynos5_usbdrd_utmi_init, 514 .set_refclk = exynos5_usbdrd_utmi_set_refclk, 515 }, 516 { 517 .id = EXYNOS5_DRDPHY_PIPE3, 518 .phy_isol = exynos5_usbdrd_phy_isol, 519 .phy_init = exynos5_usbdrd_pipe3_init, 520 .set_refclk = exynos5_usbdrd_pipe3_set_refclk, 521 }, 522}; 523 524const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { 525 .phy_cfg = phy_cfg_exynos5, 526 .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, 527 .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, 528}; 529 530const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { 531 .phy_cfg = phy_cfg_exynos5, 532 .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, 533}; 534 535static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { 536 { 537 .compatible = "samsung,exynos5250-usbdrd-phy", 538 .data = &exynos5250_usbdrd_phy 539 }, { 540 .compatible = "samsung,exynos5420-usbdrd-phy", 541 .data = &exynos5420_usbdrd_phy 542 }, 543 { }, 544}; 545 546static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) 547{ 548 struct device *dev = &pdev->dev; 549 struct device_node *node = dev->of_node; 550 struct exynos5_usbdrd_phy *phy_drd; 551 struct phy_provider *phy_provider; 552 struct resource *res; 553 const struct of_device_id *match; 554 const struct exynos5_usbdrd_phy_drvdata *drv_data; 555 struct regmap *reg_pmu; 556 u32 pmu_offset; 557 unsigned long ref_rate; 558 int i, ret; 559 int channel; 560 561 phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL); 562 if (!phy_drd) 563 return -ENOMEM; 564 565 dev_set_drvdata(dev, phy_drd); 566 phy_drd->dev = dev; 567 568 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 569 phy_drd->reg_phy = devm_ioremap_resource(dev, res); 570 if (IS_ERR(phy_drd->reg_phy)) 571 return PTR_ERR(phy_drd->reg_phy); 572 573 match = of_match_node(exynos5_usbdrd_phy_of_match, pdev->dev.of_node); 574 575 drv_data = match->data; 576 phy_drd->drv_data = drv_data; 577 578 phy_drd->clk = devm_clk_get(dev, "phy"); 579 if (IS_ERR(phy_drd->clk)) { 580 dev_err(dev, "Failed to get clock of phy controller\n"); 581 return PTR_ERR(phy_drd->clk); 582 } 583 584 phy_drd->ref_clk = devm_clk_get(dev, "ref"); 585 if (IS_ERR(phy_drd->ref_clk)) { 586 dev_err(dev, "Failed to get reference clock of usbdrd phy\n"); 587 return PTR_ERR(phy_drd->ref_clk); 588 } 589 ref_rate = clk_get_rate(phy_drd->ref_clk); 590 591 ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); 592 if (ret) { 593 dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", 594 ref_rate); 595 return ret; 596 } 597 598 reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, 599 "samsung,pmu-syscon"); 600 if (IS_ERR(reg_pmu)) { 601 dev_err(dev, "Failed to lookup PMU regmap\n"); 602 return PTR_ERR(reg_pmu); 603 } 604 605 /* 606 * Exynos5420 SoC has multiple channels for USB 3.0 PHY, with 607 * each having separate power control registers. 608 * 'channel' facilitates to set such registers. 609 */ 610 channel = of_alias_get_id(node, "usbdrdphy"); 611 if (channel < 0) 612 dev_dbg(dev, "Not a multi-controller usbdrd phy\n"); 613 614 switch (channel) { 615 case 1: 616 pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy; 617 break; 618 case 0: 619 default: 620 pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy; 621 break; 622 } 623 624 /* Get Vbus regulator */ 625 phy_drd->vbus = devm_regulator_get(dev, "vbus"); 626 if (IS_ERR(phy_drd->vbus)) { 627 ret = PTR_ERR(phy_drd->vbus); 628 if (ret == -EPROBE_DEFER) 629 return ret; 630 631 dev_warn(dev, "Failed to get VBUS supply regulator\n"); 632 phy_drd->vbus = NULL; 633 } 634 635 dev_vdbg(dev, "Creating usbdrd_phy phy\n"); 636 637 for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { 638 struct phy *phy = devm_phy_create(dev, &exynos5_usbdrd_phy_ops, 639 NULL); 640 if (IS_ERR(phy)) { 641 dev_err(dev, "Failed to create usbdrd_phy phy\n"); 642 return PTR_ERR(phy); 643 } 644 645 phy_drd->phys[i].phy = phy; 646 phy_drd->phys[i].index = i; 647 phy_drd->phys[i].reg_pmu = reg_pmu; 648 phy_drd->phys[i].pmu_offset = pmu_offset; 649 phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i]; 650 phy_set_drvdata(phy, &phy_drd->phys[i]); 651 } 652 653 phy_provider = devm_of_phy_provider_register(dev, 654 exynos5_usbdrd_phy_xlate); 655 if (IS_ERR(phy_provider)) { 656 dev_err(phy_drd->dev, "Failed to register phy provider\n"); 657 return PTR_ERR(phy_provider); 658 } 659 660 return 0; 661} 662 663static struct platform_driver exynos5_usb3drd_phy = { 664 .probe = exynos5_usbdrd_phy_probe, 665 .driver = { 666 .of_match_table = exynos5_usbdrd_phy_of_match, 667 .name = "exynos5_usb3drd_phy", 668 .owner = THIS_MODULE, 669 } 670}; 671 672module_platform_driver(exynos5_usb3drd_phy); 673MODULE_DESCRIPTION("Samsung EXYNOS5 SoCs USB 3.0 DRD controller PHY driver"); 674MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>"); 675MODULE_LICENSE("GPL v2"); 676MODULE_ALIAS("platform:exynos5_usb3drd_phy");