1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Copyright (c) 2017 NXP. */ 3 4 #include <linux/bitfield.h> 5 #include <linux/clk.h> 6 #include <linux/delay.h> 7 #include <linux/io.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/phy/phy.h> 11 #include <linux/platform_device.h> 12 #include <linux/regulator/consumer.h> 13 #include <linux/usb/typec_mux.h> 14 15 #define PHY_CTRL0 0x0 16 #define PHY_CTRL0_REF_SSP_EN BIT(2) 17 #define PHY_CTRL0_FSEL_MASK GENMASK(10, 5) 18 #define PHY_CTRL0_FSEL_24M 0x2a 19 20 #define PHY_CTRL1 0x4 21 #define PHY_CTRL1_RESET BIT(0) 22 #define PHY_CTRL1_COMMONONN BIT(1) 23 #define PHY_CTRL1_ATERESET BIT(3) 24 #define PHY_CTRL1_VDATSRCENB0 BIT(19) 25 #define PHY_CTRL1_VDATDETENB0 BIT(20) 26 27 #define PHY_CTRL2 0x8 28 #define PHY_CTRL2_TXENABLEN0 BIT(8) 29 #define PHY_CTRL2_OTG_DISABLE BIT(9) 30 31 #define PHY_CTRL3 0xc 32 #define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0) 33 #define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15) 34 #define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20) 35 #define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22) 36 #define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29) 37 38 #define PHY_CTRL4 0x10 39 #define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15) 40 41 #define PHY_CTRL5 0x14 42 #define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23) 43 #define PHY_CTRL5_DMPWD_OVERRIDE BIT(22) 44 #define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21) 45 #define PHY_CTRL5_DPPWD_OVERRIDE BIT(20) 46 #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0) 47 48 #define PHY_CTRL6 0x18 49 #define PHY_CTRL6_ALT_CLK_EN BIT(1) 50 #define PHY_CTRL6_ALT_CLK_SEL BIT(0) 51 52 #define PHY_TUNE_DEFAULT 0xffffffff 53 54 #define TCA_CLK_RST 0x00 55 #define TCA_CLK_RST_SW BIT(9) 56 #define TCA_CLK_RST_REF_CLK_EN BIT(1) 57 #define TCA_CLK_RST_SUSPEND_CLK_EN BIT(0) 58 59 #define TCA_INTR_EN 0x04 60 #define TCA_INTR_STS 0x08 61 62 #define TCA_GCFG 0x10 63 #define TCA_GCFG_ROLE_HSTDEV BIT(4) 64 #define TCA_GCFG_OP_MODE GENMASK(1, 0) 65 #define TCA_GCFG_OP_MODE_SYSMODE 0 66 #define TCA_GCFG_OP_MODE_SYNCMODE 1 67 68 #define TCA_TCPC 0x14 69 #define TCA_TCPC_VALID BIT(4) 70 #define TCA_TCPC_LOW_POWER_EN BIT(3) 71 #define TCA_TCPC_ORIENTATION_NORMAL BIT(2) 72 #define TCA_TCPC_MUX_CONTRL GENMASK(1, 0) 73 #define TCA_TCPC_MUX_CONTRL_NO_CONN 0 74 #define TCA_TCPC_MUX_CONTRL_USB_CONN 1 75 76 #define TCA_SYSMODE_CFG 0x18 77 #define TCA_SYSMODE_TCPC_DISABLE BIT(3) 78 #define TCA_SYSMODE_TCPC_FLIP BIT(2) 79 80 #define TCA_CTRLSYNCMODE_CFG0 0x20 81 #define TCA_CTRLSYNCMODE_CFG1 0x20 82 83 #define TCA_PSTATE 0x30 84 #define TCA_PSTATE_CM_STS BIT(4) 85 #define TCA_PSTATE_TX_STS BIT(3) 86 #define TCA_PSTATE_RX_PLL_STS BIT(2) 87 #define TCA_PSTATE_PIPE0_POWER_DOWN GENMASK(1, 0) 88 89 #define TCA_GEN_STATUS 0x34 90 #define TCA_GEN_DEV_POR BIT(12) 91 #define TCA_GEN_REF_CLK_SEL BIT(8) 92 #define TCA_GEN_TYPEC_FLIP_INVERT BIT(4) 93 #define TCA_GEN_PHY_TYPEC_DISABLE BIT(3) 94 #define TCA_GEN_PHY_TYPEC_FLIP BIT(2) 95 96 #define TCA_VBUS_CTRL 0x40 97 #define TCA_VBUS_STATUS 0x44 98 99 #define TCA_INFO 0xfc 100 101 struct tca_blk { 102 struct typec_switch_dev *sw; 103 void __iomem *base; 104 struct mutex mutex; 105 enum typec_orientation orientation; 106 }; 107 108 struct imx8mq_usb_phy { 109 struct phy *phy; 110 struct clk *clk; 111 void __iomem *base; 112 struct regulator *vbus; 113 struct tca_blk *tca; 114 u32 pcs_tx_swing_full; 115 u32 pcs_tx_deemph_3p5db; 116 u32 tx_vref_tune; 117 u32 tx_rise_tune; 118 u32 tx_preemp_amp_tune; 119 u32 tx_vboost_level; 120 u32 comp_dis_tune; 121 }; 122 123 124 static void tca_blk_orientation_set(struct tca_blk *tca, 125 enum typec_orientation orientation); 126 127 #ifdef CONFIG_TYPEC 128 129 static int tca_blk_typec_switch_set(struct typec_switch_dev *sw, 130 enum typec_orientation orientation) 131 { 132 struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw); 133 struct tca_blk *tca = imx_phy->tca; 134 int ret; 135 136 if (tca->orientation == orientation) 137 return 0; 138 139 ret = clk_prepare_enable(imx_phy->clk); 140 if (ret) 141 return ret; 142 143 tca_blk_orientation_set(tca, orientation); 144 clk_disable_unprepare(imx_phy->clk); 145 146 return 0; 147 } 148 149 static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev, 150 struct imx8mq_usb_phy *imx_phy) 151 { 152 struct device *dev = &pdev->dev; 153 struct typec_switch_dev *sw; 154 struct typec_switch_desc sw_desc = { }; 155 156 sw_desc.drvdata = imx_phy; 157 sw_desc.fwnode = dev->fwnode; 158 sw_desc.set = tca_blk_typec_switch_set; 159 sw_desc.name = NULL; 160 161 sw = typec_switch_register(dev, &sw_desc); 162 if (IS_ERR(sw)) { 163 dev_err(dev, "Error register tca orientation switch: %ld", 164 PTR_ERR(sw)); 165 return NULL; 166 } 167 168 return sw; 169 } 170 171 static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) 172 { 173 typec_switch_unregister(sw); 174 } 175 176 #else 177 178 static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev, 179 struct imx8mq_usb_phy *imx_phy) 180 { 181 return NULL; 182 } 183 184 static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) {} 185 186 #endif /* CONFIG_TYPEC */ 187 188 static void tca_blk_orientation_set(struct tca_blk *tca, 189 enum typec_orientation orientation) 190 { 191 u32 val; 192 193 mutex_lock(&tca->mutex); 194 195 if (orientation == TYPEC_ORIENTATION_NONE) { 196 /* 197 * use Controller Synced Mode for TCA low power enable and 198 * put PHY to USB safe state. 199 */ 200 val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE); 201 writel(val, tca->base + TCA_GCFG); 202 203 val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN; 204 writel(val, tca->base + TCA_TCPC); 205 206 goto out; 207 } 208 209 /* use System Configuration Mode for TCA mux control. */ 210 val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE); 211 writel(val, tca->base + TCA_GCFG); 212 213 /* Disable TCA module */ 214 val = readl(tca->base + TCA_SYSMODE_CFG); 215 val |= TCA_SYSMODE_TCPC_DISABLE; 216 writel(val, tca->base + TCA_SYSMODE_CFG); 217 218 if (orientation == TYPEC_ORIENTATION_REVERSE) 219 val |= TCA_SYSMODE_TCPC_FLIP; 220 else if (orientation == TYPEC_ORIENTATION_NORMAL) 221 val &= ~TCA_SYSMODE_TCPC_FLIP; 222 223 writel(val, tca->base + TCA_SYSMODE_CFG); 224 225 /* Enable TCA module */ 226 val &= ~TCA_SYSMODE_TCPC_DISABLE; 227 writel(val, tca->base + TCA_SYSMODE_CFG); 228 229 out: 230 tca->orientation = orientation; 231 mutex_unlock(&tca->mutex); 232 } 233 234 static void tca_blk_init(struct tca_blk *tca) 235 { 236 u32 val; 237 238 /* reset XBar block */ 239 val = readl(tca->base + TCA_CLK_RST); 240 val &= ~TCA_CLK_RST_SW; 241 writel(val, tca->base + TCA_CLK_RST); 242 243 udelay(100); 244 245 /* clear reset */ 246 val |= TCA_CLK_RST_SW; 247 writel(val, tca->base + TCA_CLK_RST); 248 249 tca_blk_orientation_set(tca, tca->orientation); 250 } 251 252 static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev, 253 struct imx8mq_usb_phy *imx_phy) 254 { 255 struct device *dev = &pdev->dev; 256 struct resource *res; 257 struct tca_blk *tca; 258 259 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 260 if (!res) 261 return NULL; 262 263 tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL); 264 if (!tca) 265 return ERR_PTR(-ENOMEM); 266 267 tca->base = devm_ioremap_resource(&pdev->dev, res); 268 if (IS_ERR(tca->base)) 269 return ERR_CAST(tca->base); 270 271 mutex_init(&tca->mutex); 272 273 tca->orientation = TYPEC_ORIENTATION_NORMAL; 274 tca->sw = tca_blk_get_typec_switch(pdev, imx_phy); 275 276 return tca; 277 } 278 279 static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy) 280 { 281 struct tca_blk *tca = imx_phy->tca; 282 283 if (!tca) 284 return; 285 286 tca_blk_put_typec_switch(tca->sw); 287 } 288 289 static u32 phy_tx_vref_tune_from_property(u32 percent) 290 { 291 percent = clamp(percent, 94U, 124U); 292 293 return DIV_ROUND_CLOSEST(percent - 94U, 2); 294 } 295 296 static u32 imx95_phy_tx_vref_tune_from_property(u32 percent) 297 { 298 percent = clamp(percent, 90U, 108U); 299 300 switch (percent) { 301 case 90 ... 91: 302 percent = 0; 303 break; 304 case 92 ... 96: 305 percent -= 91; 306 break; 307 case 97 ... 104: 308 percent -= 92; 309 break; 310 case 105 ... 108: 311 percent -= 93; 312 break; 313 } 314 315 return percent; 316 } 317 318 static u32 phy_tx_rise_tune_from_property(u32 percent) 319 { 320 switch (percent) { 321 case 0 ... 98: 322 return 3; 323 case 99: 324 return 2; 325 case 100 ... 101: 326 return 1; 327 default: 328 return 0; 329 } 330 } 331 332 static u32 imx95_phy_tx_rise_tune_from_property(u32 percent) 333 { 334 percent = clamp(percent, 90U, 120U); 335 336 switch (percent) { 337 case 90 ... 99: 338 return 3; 339 case 101 ... 115: 340 return 1; 341 case 116 ... 120: 342 return 0; 343 default: 344 return 2; 345 } 346 } 347 348 static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp) 349 { 350 microamp = min(microamp, 1800U); 351 352 return microamp / 600; 353 } 354 355 static u32 phy_tx_vboost_level_from_property(u32 microvolt) 356 { 357 switch (microvolt) { 358 case 1156: 359 return 5; 360 case 844: 361 return 3; 362 default: 363 return 4; 364 } 365 } 366 367 static u32 phy_pcs_tx_deemph_3p5db_from_property(u32 decibel) 368 { 369 return min(decibel, 36U); 370 } 371 372 static u32 phy_comp_dis_tune_from_property(u32 percent) 373 { 374 switch (percent) { 375 case 0 ... 92: 376 return 0; 377 case 93 ... 95: 378 return 1; 379 case 96 ... 97: 380 return 2; 381 case 98 ... 102: 382 return 3; 383 case 103 ... 105: 384 return 4; 385 case 106 ... 109: 386 return 5; 387 case 110 ... 113: 388 return 6; 389 default: 390 return 7; 391 } 392 } 393 394 static u32 imx95_phy_comp_dis_tune_from_property(u32 percent) 395 { 396 percent = clamp(percent, 94, 104); 397 398 switch (percent) { 399 case 94 ... 95: 400 percent = 0; 401 break; 402 case 96 ... 98: 403 percent -= 95; 404 break; 405 case 99 ... 102: 406 percent -= 96; 407 break; 408 case 103 ... 104: 409 percent -= 97; 410 break; 411 } 412 413 return percent; 414 } 415 416 static u32 phy_pcs_tx_swing_full_from_property(u32 percent) 417 { 418 percent = min(percent, 100U); 419 420 return (percent * 127) / 100; 421 } 422 423 static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy) 424 { 425 struct device *dev = imx_phy->phy->dev.parent; 426 bool is_imx95 = false; 427 428 if (device_is_compatible(dev, "fsl,imx95-usb-phy")) 429 is_imx95 = true; 430 431 if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent", 432 &imx_phy->tx_vref_tune)) 433 imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT; 434 else if (is_imx95) 435 imx_phy->tx_vref_tune = 436 imx95_phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune); 437 else 438 imx_phy->tx_vref_tune = 439 phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune); 440 441 if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent", 442 &imx_phy->tx_rise_tune)) 443 imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT; 444 else if (is_imx95) 445 imx_phy->tx_rise_tune = 446 imx95_phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune); 447 else 448 imx_phy->tx_rise_tune = 449 phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune); 450 451 if (device_property_read_u32(dev, "fsl,phy-tx-preemp-amp-tune-microamp", 452 &imx_phy->tx_preemp_amp_tune)) 453 imx_phy->tx_preemp_amp_tune = PHY_TUNE_DEFAULT; 454 else 455 imx_phy->tx_preemp_amp_tune = 456 phy_tx_preemp_amp_tune_from_property(imx_phy->tx_preemp_amp_tune); 457 458 if (device_property_read_u32(dev, "fsl,phy-tx-vboost-level-microvolt", 459 &imx_phy->tx_vboost_level)) 460 imx_phy->tx_vboost_level = PHY_TUNE_DEFAULT; 461 else 462 imx_phy->tx_vboost_level = 463 phy_tx_vboost_level_from_property(imx_phy->tx_vboost_level); 464 465 if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent", 466 &imx_phy->comp_dis_tune)) 467 imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT; 468 else if (is_imx95) 469 imx_phy->comp_dis_tune = 470 imx95_phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune); 471 else 472 imx_phy->comp_dis_tune = 473 phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune); 474 475 if (device_property_read_u32(dev, "fsl,phy-pcs-tx-deemph-3p5db-attenuation-db", 476 &imx_phy->pcs_tx_deemph_3p5db)) 477 imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT; 478 else 479 imx_phy->pcs_tx_deemph_3p5db = 480 phy_pcs_tx_deemph_3p5db_from_property(imx_phy->pcs_tx_deemph_3p5db); 481 482 if (device_property_read_u32(dev, "fsl,phy-pcs-tx-swing-full-percent", 483 &imx_phy->pcs_tx_swing_full)) 484 imx_phy->pcs_tx_swing_full = PHY_TUNE_DEFAULT; 485 else 486 imx_phy->pcs_tx_swing_full = 487 phy_pcs_tx_swing_full_from_property(imx_phy->pcs_tx_swing_full); 488 } 489 490 static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy) 491 { 492 u32 value; 493 494 /* PHY tuning */ 495 if (imx_phy->pcs_tx_deemph_3p5db != PHY_TUNE_DEFAULT) { 496 value = readl(imx_phy->base + PHY_CTRL4); 497 value &= ~PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK; 498 value |= FIELD_PREP(PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK, 499 imx_phy->pcs_tx_deemph_3p5db); 500 writel(value, imx_phy->base + PHY_CTRL4); 501 } 502 503 if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) { 504 value = readl(imx_phy->base + PHY_CTRL5); 505 value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK, 506 imx_phy->pcs_tx_swing_full); 507 writel(value, imx_phy->base + PHY_CTRL5); 508 } 509 510 if ((imx_phy->tx_vref_tune & imx_phy->tx_rise_tune & 511 imx_phy->tx_preemp_amp_tune & imx_phy->comp_dis_tune & 512 imx_phy->tx_vboost_level) == PHY_TUNE_DEFAULT) 513 /* If all are the default values, no need update. */ 514 return; 515 516 value = readl(imx_phy->base + PHY_CTRL3); 517 518 if (imx_phy->tx_vref_tune != PHY_TUNE_DEFAULT) { 519 value &= ~PHY_CTRL3_TXVREF_TUNE_MASK; 520 value |= FIELD_PREP(PHY_CTRL3_TXVREF_TUNE_MASK, 521 imx_phy->tx_vref_tune); 522 } 523 524 if (imx_phy->tx_rise_tune != PHY_TUNE_DEFAULT) { 525 value &= ~PHY_CTRL3_TXRISE_TUNE_MASK; 526 value |= FIELD_PREP(PHY_CTRL3_TXRISE_TUNE_MASK, 527 imx_phy->tx_rise_tune); 528 } 529 530 if (imx_phy->tx_preemp_amp_tune != PHY_TUNE_DEFAULT) { 531 value &= ~PHY_CTRL3_TXPREEMP_TUNE_MASK; 532 value |= FIELD_PREP(PHY_CTRL3_TXPREEMP_TUNE_MASK, 533 imx_phy->tx_preemp_amp_tune); 534 } 535 536 if (imx_phy->comp_dis_tune != PHY_TUNE_DEFAULT) { 537 value &= ~PHY_CTRL3_COMPDISTUNE_MASK; 538 value |= FIELD_PREP(PHY_CTRL3_COMPDISTUNE_MASK, 539 imx_phy->comp_dis_tune); 540 } 541 542 if (imx_phy->tx_vboost_level != PHY_TUNE_DEFAULT) { 543 value &= ~PHY_CTRL3_TX_VBOOST_LEVEL_MASK; 544 value |= FIELD_PREP(PHY_CTRL3_TX_VBOOST_LEVEL_MASK, 545 imx_phy->tx_vboost_level); 546 } 547 548 writel(value, imx_phy->base + PHY_CTRL3); 549 } 550 551 static int imx8mq_usb_phy_init(struct phy *phy) 552 { 553 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 554 u32 value; 555 556 value = readl(imx_phy->base + PHY_CTRL1); 557 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 | 558 PHY_CTRL1_COMMONONN); 559 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; 560 writel(value, imx_phy->base + PHY_CTRL1); 561 562 value = readl(imx_phy->base + PHY_CTRL0); 563 value |= PHY_CTRL0_REF_SSP_EN; 564 writel(value, imx_phy->base + PHY_CTRL0); 565 566 value = readl(imx_phy->base + PHY_CTRL2); 567 value |= PHY_CTRL2_TXENABLEN0; 568 writel(value, imx_phy->base + PHY_CTRL2); 569 570 value = readl(imx_phy->base + PHY_CTRL1); 571 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); 572 writel(value, imx_phy->base + PHY_CTRL1); 573 574 return 0; 575 } 576 577 static int imx8mp_usb_phy_init(struct phy *phy) 578 { 579 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 580 u32 value; 581 582 /* USB3.0 PHY signal fsel for 24M ref */ 583 value = readl(imx_phy->base + PHY_CTRL0); 584 value &= ~PHY_CTRL0_FSEL_MASK; 585 value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M); 586 writel(value, imx_phy->base + PHY_CTRL0); 587 588 /* Disable alt_clk_en and use internal MPLL clocks */ 589 value = readl(imx_phy->base + PHY_CTRL6); 590 value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN); 591 writel(value, imx_phy->base + PHY_CTRL6); 592 593 value = readl(imx_phy->base + PHY_CTRL1); 594 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0); 595 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; 596 writel(value, imx_phy->base + PHY_CTRL1); 597 598 value = readl(imx_phy->base + PHY_CTRL0); 599 value |= PHY_CTRL0_REF_SSP_EN; 600 writel(value, imx_phy->base + PHY_CTRL0); 601 602 value = readl(imx_phy->base + PHY_CTRL2); 603 value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE; 604 writel(value, imx_phy->base + PHY_CTRL2); 605 606 udelay(10); 607 608 value = readl(imx_phy->base + PHY_CTRL1); 609 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); 610 writel(value, imx_phy->base + PHY_CTRL1); 611 612 imx8m_phy_tune(imx_phy); 613 614 if (imx_phy->tca) 615 tca_blk_init(imx_phy->tca); 616 617 return 0; 618 } 619 620 static int imx8mq_phy_power_on(struct phy *phy) 621 { 622 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 623 int ret; 624 625 ret = regulator_enable(imx_phy->vbus); 626 if (ret) 627 return ret; 628 629 return clk_prepare_enable(imx_phy->clk); 630 } 631 632 static int imx8mq_phy_power_off(struct phy *phy) 633 { 634 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 635 636 clk_disable_unprepare(imx_phy->clk); 637 regulator_disable(imx_phy->vbus); 638 639 return 0; 640 } 641 642 static const struct phy_ops imx8mq_usb_phy_ops = { 643 .init = imx8mq_usb_phy_init, 644 .power_on = imx8mq_phy_power_on, 645 .power_off = imx8mq_phy_power_off, 646 .owner = THIS_MODULE, 647 }; 648 649 static const struct phy_ops imx8mp_usb_phy_ops = { 650 .init = imx8mp_usb_phy_init, 651 .power_on = imx8mq_phy_power_on, 652 .power_off = imx8mq_phy_power_off, 653 .owner = THIS_MODULE, 654 }; 655 656 static const struct of_device_id imx8mq_usb_phy_of_match[] = { 657 {.compatible = "fsl,imx8mq-usb-phy", 658 .data = &imx8mq_usb_phy_ops,}, 659 {.compatible = "fsl,imx8mp-usb-phy", 660 .data = &imx8mp_usb_phy_ops,}, 661 {.compatible = "fsl,imx95-usb-phy", 662 .data = &imx8mp_usb_phy_ops,}, 663 { } 664 }; 665 MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match); 666 667 static int imx8mq_usb_phy_probe(struct platform_device *pdev) 668 { 669 struct phy_provider *phy_provider; 670 struct device *dev = &pdev->dev; 671 struct imx8mq_usb_phy *imx_phy; 672 const struct phy_ops *phy_ops; 673 674 imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL); 675 if (!imx_phy) 676 return -ENOMEM; 677 678 imx_phy->clk = devm_clk_get(dev, "phy"); 679 if (IS_ERR(imx_phy->clk)) { 680 dev_err(dev, "failed to get imx8mq usb phy clock\n"); 681 return PTR_ERR(imx_phy->clk); 682 } 683 684 imx_phy->base = devm_platform_ioremap_resource(pdev, 0); 685 if (IS_ERR(imx_phy->base)) 686 return PTR_ERR(imx_phy->base); 687 688 phy_ops = of_device_get_match_data(dev); 689 if (!phy_ops) 690 return -EINVAL; 691 692 imx_phy->phy = devm_phy_create(dev, NULL, phy_ops); 693 if (IS_ERR(imx_phy->phy)) 694 return PTR_ERR(imx_phy->phy); 695 696 imx_phy->vbus = devm_regulator_get(dev, "vbus"); 697 if (IS_ERR(imx_phy->vbus)) 698 return dev_err_probe(dev, PTR_ERR(imx_phy->vbus), "failed to get vbus\n"); 699 700 phy_set_drvdata(imx_phy->phy, imx_phy); 701 702 imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy); 703 if (IS_ERR(imx_phy->tca)) 704 return dev_err_probe(dev, PTR_ERR(imx_phy->tca), 705 "failed to get tca\n"); 706 707 imx8m_get_phy_tuning_data(imx_phy); 708 709 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 710 711 return PTR_ERR_OR_ZERO(phy_provider); 712 } 713 714 static void imx8mq_usb_phy_remove(struct platform_device *pdev) 715 { 716 struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev); 717 718 imx95_usb_phy_put_tca(imx_phy); 719 } 720 721 static struct platform_driver imx8mq_usb_phy_driver = { 722 .probe = imx8mq_usb_phy_probe, 723 .remove = imx8mq_usb_phy_remove, 724 .driver = { 725 .name = "imx8mq-usb-phy", 726 .of_match_table = imx8mq_usb_phy_of_match, 727 } 728 }; 729 module_platform_driver(imx8mq_usb_phy_driver); 730 731 MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver"); 732 MODULE_LICENSE("GPL"); 733