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 phy_tx_rise_tune_from_property(u32 percent) 297 { 298 switch (percent) { 299 case 0 ... 98: 300 return 3; 301 case 99: 302 return 2; 303 case 100 ... 101: 304 return 1; 305 default: 306 return 0; 307 } 308 } 309 310 static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp) 311 { 312 microamp = min(microamp, 1800U); 313 314 return microamp / 600; 315 } 316 317 static u32 phy_tx_vboost_level_from_property(u32 microvolt) 318 { 319 switch (microvolt) { 320 case 0 ... 960: 321 return 0; 322 case 961 ... 1160: 323 return 2; 324 default: 325 return 3; 326 } 327 } 328 329 static u32 phy_pcs_tx_deemph_3p5db_from_property(u32 decibel) 330 { 331 return min(decibel, 36U); 332 } 333 334 static u32 phy_comp_dis_tune_from_property(u32 percent) 335 { 336 switch (percent) { 337 case 0 ... 92: 338 return 0; 339 case 93 ... 95: 340 return 1; 341 case 96 ... 97: 342 return 2; 343 case 98 ... 102: 344 return 3; 345 case 103 ... 105: 346 return 4; 347 case 106 ... 109: 348 return 5; 349 case 110 ... 113: 350 return 6; 351 default: 352 return 7; 353 } 354 } 355 static u32 phy_pcs_tx_swing_full_from_property(u32 percent) 356 { 357 percent = min(percent, 100U); 358 359 return (percent * 127) / 100; 360 } 361 362 static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy) 363 { 364 struct device *dev = imx_phy->phy->dev.parent; 365 366 if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent", 367 &imx_phy->tx_vref_tune)) 368 imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT; 369 else 370 imx_phy->tx_vref_tune = 371 phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune); 372 373 if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent", 374 &imx_phy->tx_rise_tune)) 375 imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT; 376 else 377 imx_phy->tx_rise_tune = 378 phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune); 379 380 if (device_property_read_u32(dev, "fsl,phy-tx-preemp-amp-tune-microamp", 381 &imx_phy->tx_preemp_amp_tune)) 382 imx_phy->tx_preemp_amp_tune = PHY_TUNE_DEFAULT; 383 else 384 imx_phy->tx_preemp_amp_tune = 385 phy_tx_preemp_amp_tune_from_property(imx_phy->tx_preemp_amp_tune); 386 387 if (device_property_read_u32(dev, "fsl,phy-tx-vboost-level-microvolt", 388 &imx_phy->tx_vboost_level)) 389 imx_phy->tx_vboost_level = PHY_TUNE_DEFAULT; 390 else 391 imx_phy->tx_vboost_level = 392 phy_tx_vboost_level_from_property(imx_phy->tx_vboost_level); 393 394 if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent", 395 &imx_phy->comp_dis_tune)) 396 imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT; 397 else 398 imx_phy->comp_dis_tune = 399 phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune); 400 401 if (device_property_read_u32(dev, "fsl,phy-pcs-tx-deemph-3p5db-attenuation-db", 402 &imx_phy->pcs_tx_deemph_3p5db)) 403 imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT; 404 else 405 imx_phy->pcs_tx_deemph_3p5db = 406 phy_pcs_tx_deemph_3p5db_from_property(imx_phy->pcs_tx_deemph_3p5db); 407 408 if (device_property_read_u32(dev, "fsl,phy-pcs-tx-swing-full-percent", 409 &imx_phy->pcs_tx_swing_full)) 410 imx_phy->pcs_tx_swing_full = PHY_TUNE_DEFAULT; 411 else 412 imx_phy->pcs_tx_swing_full = 413 phy_pcs_tx_swing_full_from_property(imx_phy->pcs_tx_swing_full); 414 } 415 416 static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy) 417 { 418 u32 value; 419 420 /* PHY tuning */ 421 if (imx_phy->pcs_tx_deemph_3p5db != PHY_TUNE_DEFAULT) { 422 value = readl(imx_phy->base + PHY_CTRL4); 423 value &= ~PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK; 424 value |= FIELD_PREP(PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK, 425 imx_phy->pcs_tx_deemph_3p5db); 426 writel(value, imx_phy->base + PHY_CTRL4); 427 } 428 429 if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) { 430 value = readl(imx_phy->base + PHY_CTRL5); 431 value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK, 432 imx_phy->pcs_tx_swing_full); 433 writel(value, imx_phy->base + PHY_CTRL5); 434 } 435 436 if ((imx_phy->tx_vref_tune & imx_phy->tx_rise_tune & 437 imx_phy->tx_preemp_amp_tune & imx_phy->comp_dis_tune & 438 imx_phy->tx_vboost_level) == PHY_TUNE_DEFAULT) 439 /* If all are the default values, no need update. */ 440 return; 441 442 value = readl(imx_phy->base + PHY_CTRL3); 443 444 if (imx_phy->tx_vref_tune != PHY_TUNE_DEFAULT) { 445 value &= ~PHY_CTRL3_TXVREF_TUNE_MASK; 446 value |= FIELD_PREP(PHY_CTRL3_TXVREF_TUNE_MASK, 447 imx_phy->tx_vref_tune); 448 } 449 450 if (imx_phy->tx_rise_tune != PHY_TUNE_DEFAULT) { 451 value &= ~PHY_CTRL3_TXRISE_TUNE_MASK; 452 value |= FIELD_PREP(PHY_CTRL3_TXRISE_TUNE_MASK, 453 imx_phy->tx_rise_tune); 454 } 455 456 if (imx_phy->tx_preemp_amp_tune != PHY_TUNE_DEFAULT) { 457 value &= ~PHY_CTRL3_TXPREEMP_TUNE_MASK; 458 value |= FIELD_PREP(PHY_CTRL3_TXPREEMP_TUNE_MASK, 459 imx_phy->tx_preemp_amp_tune); 460 } 461 462 if (imx_phy->comp_dis_tune != PHY_TUNE_DEFAULT) { 463 value &= ~PHY_CTRL3_COMPDISTUNE_MASK; 464 value |= FIELD_PREP(PHY_CTRL3_COMPDISTUNE_MASK, 465 imx_phy->comp_dis_tune); 466 } 467 468 if (imx_phy->tx_vboost_level != PHY_TUNE_DEFAULT) { 469 value &= ~PHY_CTRL3_TX_VBOOST_LEVEL_MASK; 470 value |= FIELD_PREP(PHY_CTRL3_TX_VBOOST_LEVEL_MASK, 471 imx_phy->tx_vboost_level); 472 } 473 474 writel(value, imx_phy->base + PHY_CTRL3); 475 } 476 477 static int imx8mq_usb_phy_init(struct phy *phy) 478 { 479 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 480 u32 value; 481 482 value = readl(imx_phy->base + PHY_CTRL1); 483 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 | 484 PHY_CTRL1_COMMONONN); 485 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; 486 writel(value, imx_phy->base + PHY_CTRL1); 487 488 value = readl(imx_phy->base + PHY_CTRL0); 489 value |= PHY_CTRL0_REF_SSP_EN; 490 writel(value, imx_phy->base + PHY_CTRL0); 491 492 value = readl(imx_phy->base + PHY_CTRL2); 493 value |= PHY_CTRL2_TXENABLEN0; 494 writel(value, imx_phy->base + PHY_CTRL2); 495 496 value = readl(imx_phy->base + PHY_CTRL1); 497 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); 498 writel(value, imx_phy->base + PHY_CTRL1); 499 500 return 0; 501 } 502 503 static int imx8mp_usb_phy_init(struct phy *phy) 504 { 505 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 506 u32 value; 507 508 /* USB3.0 PHY signal fsel for 24M ref */ 509 value = readl(imx_phy->base + PHY_CTRL0); 510 value &= ~PHY_CTRL0_FSEL_MASK; 511 value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M); 512 writel(value, imx_phy->base + PHY_CTRL0); 513 514 /* Disable alt_clk_en and use internal MPLL clocks */ 515 value = readl(imx_phy->base + PHY_CTRL6); 516 value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN); 517 writel(value, imx_phy->base + PHY_CTRL6); 518 519 value = readl(imx_phy->base + PHY_CTRL1); 520 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0); 521 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; 522 writel(value, imx_phy->base + PHY_CTRL1); 523 524 value = readl(imx_phy->base + PHY_CTRL0); 525 value |= PHY_CTRL0_REF_SSP_EN; 526 writel(value, imx_phy->base + PHY_CTRL0); 527 528 value = readl(imx_phy->base + PHY_CTRL2); 529 value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE; 530 writel(value, imx_phy->base + PHY_CTRL2); 531 532 udelay(10); 533 534 value = readl(imx_phy->base + PHY_CTRL1); 535 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); 536 writel(value, imx_phy->base + PHY_CTRL1); 537 538 imx8m_phy_tune(imx_phy); 539 540 if (imx_phy->tca) 541 tca_blk_init(imx_phy->tca); 542 543 return 0; 544 } 545 546 static int imx8mq_phy_power_on(struct phy *phy) 547 { 548 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 549 int ret; 550 551 ret = regulator_enable(imx_phy->vbus); 552 if (ret) 553 return ret; 554 555 return clk_prepare_enable(imx_phy->clk); 556 } 557 558 static int imx8mq_phy_power_off(struct phy *phy) 559 { 560 struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 561 562 clk_disable_unprepare(imx_phy->clk); 563 regulator_disable(imx_phy->vbus); 564 565 return 0; 566 } 567 568 static const struct phy_ops imx8mq_usb_phy_ops = { 569 .init = imx8mq_usb_phy_init, 570 .power_on = imx8mq_phy_power_on, 571 .power_off = imx8mq_phy_power_off, 572 .owner = THIS_MODULE, 573 }; 574 575 static const struct phy_ops imx8mp_usb_phy_ops = { 576 .init = imx8mp_usb_phy_init, 577 .power_on = imx8mq_phy_power_on, 578 .power_off = imx8mq_phy_power_off, 579 .owner = THIS_MODULE, 580 }; 581 582 static const struct of_device_id imx8mq_usb_phy_of_match[] = { 583 {.compatible = "fsl,imx8mq-usb-phy", 584 .data = &imx8mq_usb_phy_ops,}, 585 {.compatible = "fsl,imx8mp-usb-phy", 586 .data = &imx8mp_usb_phy_ops,}, 587 {.compatible = "fsl,imx95-usb-phy", 588 .data = &imx8mp_usb_phy_ops,}, 589 { } 590 }; 591 MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match); 592 593 static int imx8mq_usb_phy_probe(struct platform_device *pdev) 594 { 595 struct phy_provider *phy_provider; 596 struct device *dev = &pdev->dev; 597 struct imx8mq_usb_phy *imx_phy; 598 const struct phy_ops *phy_ops; 599 600 imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL); 601 if (!imx_phy) 602 return -ENOMEM; 603 604 imx_phy->clk = devm_clk_get(dev, "phy"); 605 if (IS_ERR(imx_phy->clk)) { 606 dev_err(dev, "failed to get imx8mq usb phy clock\n"); 607 return PTR_ERR(imx_phy->clk); 608 } 609 610 imx_phy->base = devm_platform_ioremap_resource(pdev, 0); 611 if (IS_ERR(imx_phy->base)) 612 return PTR_ERR(imx_phy->base); 613 614 phy_ops = of_device_get_match_data(dev); 615 if (!phy_ops) 616 return -EINVAL; 617 618 imx_phy->phy = devm_phy_create(dev, NULL, phy_ops); 619 if (IS_ERR(imx_phy->phy)) 620 return PTR_ERR(imx_phy->phy); 621 622 imx_phy->vbus = devm_regulator_get(dev, "vbus"); 623 if (IS_ERR(imx_phy->vbus)) 624 return dev_err_probe(dev, PTR_ERR(imx_phy->vbus), "failed to get vbus\n"); 625 626 phy_set_drvdata(imx_phy->phy, imx_phy); 627 628 imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy); 629 if (IS_ERR(imx_phy->tca)) 630 return dev_err_probe(dev, PTR_ERR(imx_phy->tca), 631 "failed to get tca\n"); 632 633 imx8m_get_phy_tuning_data(imx_phy); 634 635 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 636 637 return PTR_ERR_OR_ZERO(phy_provider); 638 } 639 640 static void imx8mq_usb_phy_remove(struct platform_device *pdev) 641 { 642 struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev); 643 644 imx95_usb_phy_put_tca(imx_phy); 645 } 646 647 static struct platform_driver imx8mq_usb_phy_driver = { 648 .probe = imx8mq_usb_phy_probe, 649 .remove = imx8mq_usb_phy_remove, 650 .driver = { 651 .name = "imx8mq-usb-phy", 652 .of_match_table = imx8mq_usb_phy_of_match, 653 } 654 }; 655 module_platform_driver(imx8mq_usb_phy_driver); 656 657 MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver"); 658 MODULE_LICENSE("GPL"); 659