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