1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * STMicroelectronics COMBOPHY STM32MP25 Controller driver. 4 * 5 * Copyright (C) 2024 STMicroelectronics 6 * Author: Christian Bruel <christian.bruel@foss.st.com> 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/clk.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/platform_device.h> 13 #include <linux/phy/phy.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/regmap.h> 16 #include <linux/reset.h> 17 #include <dt-bindings/phy/phy.h> 18 19 #define SYSCFG_COMBOPHY_CR1 0x4c00 20 #define SYSCFG_COMBOPHY_CR2 0x4c04 21 #define SYSCFG_COMBOPHY_CR4 0x4c0c 22 #define SYSCFG_COMBOPHY_CR5 0x4c10 23 #define SYSCFG_COMBOPHY_SR 0x4c14 24 #define SYSCFG_PCIEPRGCR 0x6080 25 26 /* SYSCFG PCIEPRGCR */ 27 #define STM32MP25_PCIEPRGCR_EN BIT(0) 28 #define STM32MP25_PCIEPRG_IMPCTRL_OHM GENMASK(3, 1) 29 #define STM32MP25_PCIEPRG_IMPCTRL_VSWING GENMASK(5, 4) 30 31 /* SYSCFG SYSCFG_COMBOPHY_SR */ 32 #define STM32MP25_PIPE0_PHYSTATUS BIT(1) 33 34 /* SYSCFG CR1 */ 35 #define SYSCFG_COMBOPHY_CR1_REFUSEPAD BIT(0) 36 #define SYSCFG_COMBOPHY_CR1_MPLLMULT GENMASK(7, 1) 37 #define SYSCFG_COMBOPHY_CR1_REFCLKSEL GENMASK(16, 8) 38 #define SYSCFG_COMBOPHY_CR1_REFCLKDIV2 BIT(17) 39 #define SYSCFG_COMBOPHY_CR1_REFSSPEN BIT(18) 40 #define SYSCFG_COMBOPHY_CR1_SSCEN BIT(19) 41 42 /* SYSCFG CR4 */ 43 #define SYSCFG_COMBOPHY_CR4_RX0_EQ GENMASK(2, 0) 44 45 #define MPLLMULT_19_2 (0x02u << 1) 46 #define MPLLMULT_20 (0x7du << 1) 47 #define MPLLMULT_24 (0x68u << 1) 48 #define MPLLMULT_25 (0x64u << 1) 49 #define MPLLMULT_26 (0x60u << 1) 50 #define MPLLMULT_38_4 (0x41u << 1) 51 #define MPLLMULT_48 (0x6cu << 1) 52 #define MPLLMULT_50 (0x32u << 1) 53 #define MPLLMULT_52 (0x30u << 1) 54 #define MPLLMULT_100 (0x19u << 1) 55 56 #define REFCLKSEL_0 0 57 #define REFCLKSEL_1 (0x108u << 8) 58 59 #define REFCLDIV_0 0 60 61 /* SYSCFG CR2 */ 62 #define SYSCFG_COMBOPHY_CR2_MODESEL GENMASK(1, 0) 63 #define SYSCFG_COMBOPHY_CR2_ISO_DIS BIT(15) 64 65 #define COMBOPHY_MODESEL_PCIE 0 66 #define COMBOPHY_MODESEL_USB 3 67 68 /* SYSCFG CR5 */ 69 #define SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS BIT(12) 70 71 #define COMBOPHY_SUP_ANA_MPLL_LOOP_CTL 0xc0 72 #define COMBOPHY_PROP_CNTRL GENMASK(7, 4) 73 74 /* Required apb/ker clocks first, optional pad last. */ 75 static const char * const combophy_clks[] = {"apb", "ker", "pad"}; 76 #define APB_CLK 0 77 #define KER_CLK 1 78 #define PAD_CLK 2 79 80 struct stm32_combophy { 81 struct phy *phy; 82 struct regmap *regmap; 83 struct device *dev; 84 void __iomem *base; 85 struct reset_control *phy_reset; 86 struct clk_bulk_data clks[ARRAY_SIZE(combophy_clks)]; 87 int num_clks; 88 bool have_pad_clk; 89 unsigned int type; 90 bool is_init; 91 int irq_wakeup; 92 }; 93 94 struct clk_impedance { 95 u32 microohm; 96 u32 vswing[4]; 97 }; 98 99 /* 100 * lookup table to hold the settings needed for a ref clock frequency 101 * impedance, the offset is used to set the IMP_CTL and DE_EMP bit of the 102 * PRG_IMP_CTRL register. Use ordered discrete values in the table 103 */ 104 static const struct clk_impedance imp_lookup[] = { 105 { 6090000, { 442000, 564000, 684000, 802000 } }, 106 { 5662000, { 528000, 621000, 712000, 803000 } }, 107 { 5292000, { 491000, 596000, 700000, 802000 } }, 108 { 4968000, { 558000, 640000, 722000, 803000 } }, 109 { 4684000, { 468000, 581000, 692000, 802000 } }, 110 { 4429000, { 554000, 613000, 717000, 803000 } }, 111 { 4204000, { 511000, 609000, 706000, 802000 } }, 112 { 3999000, { 571000, 648000, 726000, 803000 } } 113 }; 114 115 static int stm32_impedance_tune(struct stm32_combophy *combophy) 116 { 117 u8 imp_size = ARRAY_SIZE(imp_lookup); 118 u8 vswing_size = ARRAY_SIZE(imp_lookup[0].vswing); 119 u8 imp_of, vswing_of; 120 u32 max_imp = imp_lookup[0].microohm; 121 u32 min_imp = imp_lookup[imp_size - 1].microohm; 122 u32 max_vswing = imp_lookup[imp_size - 1].vswing[vswing_size - 1]; 123 u32 min_vswing = imp_lookup[0].vswing[0]; 124 u32 val; 125 u32 regval; 126 127 if (!of_property_read_u32(combophy->dev->of_node, "st,output-micro-ohms", &val)) { 128 if (val < min_imp || val > max_imp) { 129 dev_err(combophy->dev, "Invalid value %u for output ohm\n", val); 130 return -EINVAL; 131 } 132 133 regval = 0; 134 for (imp_of = 0; imp_of < ARRAY_SIZE(imp_lookup); imp_of++) { 135 if (imp_lookup[imp_of].microohm <= val) { 136 regval = FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_OHM, imp_of); 137 break; 138 } 139 } 140 141 dev_dbg(combophy->dev, "Set %u micro-ohms output impedance\n", 142 imp_lookup[imp_of].microohm); 143 144 regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, 145 STM32MP25_PCIEPRG_IMPCTRL_OHM, 146 regval); 147 } else { 148 regmap_read(combophy->regmap, SYSCFG_PCIEPRGCR, &val); 149 imp_of = FIELD_GET(STM32MP25_PCIEPRG_IMPCTRL_OHM, val); 150 } 151 152 if (!of_property_read_u32(combophy->dev->of_node, "st,output-vswing-microvolt", &val)) { 153 if (val < min_vswing || val > max_vswing) { 154 dev_err(combophy->dev, "Invalid value %u for output vswing\n", val); 155 return -EINVAL; 156 } 157 158 regval = 0; 159 for (vswing_of = 0; vswing_of < ARRAY_SIZE(imp_lookup[imp_of].vswing); vswing_of++) { 160 if (imp_lookup[imp_of].vswing[vswing_of] >= val) { 161 regval = FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_VSWING, vswing_of); 162 break; 163 } 164 } 165 166 dev_dbg(combophy->dev, "Set %u microvolt swing\n", 167 imp_lookup[imp_of].vswing[vswing_of]); 168 169 regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, 170 STM32MP25_PCIEPRG_IMPCTRL_VSWING, 171 regval); 172 } 173 174 return 0; 175 } 176 177 static int stm32_combophy_pll_init(struct stm32_combophy *combophy) 178 { 179 int ret; 180 u32 refclksel, pllmult, propcntrl, val; 181 u32 clk_rate; 182 struct clk *clk; 183 u32 cr1_val = 0, cr1_mask = 0; 184 185 if (combophy->have_pad_clk) 186 clk = combophy->clks[PAD_CLK].clk; 187 else 188 clk = combophy->clks[KER_CLK].clk; 189 190 clk_rate = clk_get_rate(clk); 191 192 dev_dbg(combophy->dev, "%s pll init rate %d\n", 193 combophy->have_pad_clk ? "External" : "Ker", clk_rate); 194 195 if (combophy->type != PHY_TYPE_PCIE) { 196 cr1_mask |= SYSCFG_COMBOPHY_CR1_REFSSPEN; 197 cr1_val |= SYSCFG_COMBOPHY_CR1_REFSSPEN; 198 } 199 200 if (of_property_present(combophy->dev->of_node, "st,ssc-on")) { 201 dev_dbg(combophy->dev, "Enabling clock with SSC\n"); 202 cr1_mask |= SYSCFG_COMBOPHY_CR1_SSCEN; 203 cr1_val |= SYSCFG_COMBOPHY_CR1_SSCEN; 204 } 205 206 switch (clk_rate) { 207 case 100000000: 208 pllmult = MPLLMULT_100; 209 refclksel = REFCLKSEL_0; 210 propcntrl = 0x8u << 4; 211 break; 212 case 19200000: 213 pllmult = MPLLMULT_19_2; 214 refclksel = REFCLKSEL_1; 215 propcntrl = 0x8u << 4; 216 break; 217 case 25000000: 218 pllmult = MPLLMULT_25; 219 refclksel = REFCLKSEL_0; 220 propcntrl = 0xeu << 4; 221 break; 222 case 24000000: 223 pllmult = MPLLMULT_24; 224 refclksel = REFCLKSEL_1; 225 propcntrl = 0xeu << 4; 226 break; 227 case 20000000: 228 pllmult = MPLLMULT_20; 229 refclksel = REFCLKSEL_0; 230 propcntrl = 0xeu << 4; 231 break; 232 default: 233 dev_err(combophy->dev, "Invalid rate 0x%x\n", clk_rate); 234 return -EINVAL; 235 } 236 237 cr1_mask |= SYSCFG_COMBOPHY_CR1_REFCLKDIV2; 238 cr1_val |= REFCLDIV_0; 239 240 cr1_mask |= SYSCFG_COMBOPHY_CR1_REFCLKSEL; 241 cr1_val |= refclksel; 242 243 cr1_mask |= SYSCFG_COMBOPHY_CR1_MPLLMULT; 244 cr1_val |= pllmult; 245 246 /* 247 * vddcombophy is interconnected with vddcore. Isolation bit should be unset 248 * before using the ComboPHY. 249 */ 250 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, 251 SYSCFG_COMBOPHY_CR2_ISO_DIS, SYSCFG_COMBOPHY_CR2_ISO_DIS); 252 253 reset_control_assert(combophy->phy_reset); 254 255 if (combophy->type == PHY_TYPE_PCIE) { 256 ret = stm32_impedance_tune(combophy); 257 if (ret) 258 goto out_iso; 259 260 cr1_mask |= SYSCFG_COMBOPHY_CR1_REFUSEPAD; 261 cr1_val |= combophy->have_pad_clk ? SYSCFG_COMBOPHY_CR1_REFUSEPAD : 0; 262 } 263 264 if (!of_property_read_u32(combophy->dev->of_node, "st,rx-equalizer", &val)) { 265 dev_dbg(combophy->dev, "Set RX equalizer %u\n", val); 266 if (val > SYSCFG_COMBOPHY_CR4_RX0_EQ) { 267 dev_err(combophy->dev, "Invalid value %u for rx0 equalizer\n", val); 268 ret = -EINVAL; 269 goto out_iso; 270 } 271 272 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR4, 273 SYSCFG_COMBOPHY_CR4_RX0_EQ, val); 274 } 275 276 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, cr1_mask, cr1_val); 277 278 /* 279 * Force elasticity buffer to be tuned for the reference clock as 280 * the separated clock model is not supported 281 */ 282 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR5, 283 SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS, SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS); 284 285 reset_control_deassert(combophy->phy_reset); 286 287 ret = regmap_read_poll_timeout(combophy->regmap, SYSCFG_COMBOPHY_SR, val, 288 !(val & STM32MP25_PIPE0_PHYSTATUS), 289 10, 1000); 290 if (ret) { 291 dev_err(combophy->dev, "timeout, cannot lock PLL\n"); 292 if (combophy->type == PHY_TYPE_PCIE && !combophy->have_pad_clk) 293 regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, 294 STM32MP25_PCIEPRGCR_EN, 0); 295 296 if (combophy->type != PHY_TYPE_PCIE) 297 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, 298 SYSCFG_COMBOPHY_CR1_REFSSPEN, 0); 299 300 goto out; 301 } 302 303 304 if (combophy->type == PHY_TYPE_PCIE) { 305 if (!combophy->have_pad_clk) 306 regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, 307 STM32MP25_PCIEPRGCR_EN, STM32MP25_PCIEPRGCR_EN); 308 309 val = readl_relaxed(combophy->base + COMBOPHY_SUP_ANA_MPLL_LOOP_CTL); 310 val &= ~COMBOPHY_PROP_CNTRL; 311 val |= propcntrl; 312 writel_relaxed(val, combophy->base + COMBOPHY_SUP_ANA_MPLL_LOOP_CTL); 313 } 314 315 return 0; 316 317 out_iso: 318 reset_control_deassert(combophy->phy_reset); 319 320 out: 321 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, 322 SYSCFG_COMBOPHY_CR2_ISO_DIS, 0); 323 324 return ret; 325 } 326 327 static struct phy *stm32_combophy_xlate(struct device *dev, 328 const struct of_phandle_args *args) 329 { 330 struct stm32_combophy *combophy = dev_get_drvdata(dev); 331 unsigned int type; 332 333 if (args->args_count != 1) { 334 dev_err(dev, "invalid number of cells in 'phy' property\n"); 335 return ERR_PTR(-EINVAL); 336 } 337 338 type = args->args[0]; 339 if (type != PHY_TYPE_USB3 && type != PHY_TYPE_PCIE) { 340 dev_err(dev, "unsupported device type: %d\n", type); 341 return ERR_PTR(-EINVAL); 342 } 343 344 if (combophy->have_pad_clk && type != PHY_TYPE_PCIE) { 345 dev_err(dev, "Invalid use of clk_pad for USB3 mode\n"); 346 return ERR_PTR(-EINVAL); 347 } 348 349 combophy->type = type; 350 351 return combophy->phy; 352 } 353 354 static int stm32_combophy_set_mode(struct stm32_combophy *combophy) 355 { 356 int type = combophy->type; 357 u32 val; 358 359 switch (type) { 360 case PHY_TYPE_PCIE: 361 dev_dbg(combophy->dev, "setting PCIe ComboPHY\n"); 362 val = COMBOPHY_MODESEL_PCIE; 363 break; 364 case PHY_TYPE_USB3: 365 dev_dbg(combophy->dev, "setting USB3 ComboPHY\n"); 366 val = COMBOPHY_MODESEL_USB; 367 break; 368 default: 369 dev_err(combophy->dev, "Invalid PHY mode %d\n", type); 370 return -EINVAL; 371 } 372 373 return regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, 374 SYSCFG_COMBOPHY_CR2_MODESEL, val); 375 } 376 377 static int stm32_combophy_suspend_noirq(struct device *dev) 378 { 379 struct stm32_combophy *combophy = dev_get_drvdata(dev); 380 381 /* 382 * Clocks should be turned off since it is not needed for 383 * wakeup capability. In case usb-remote wakeup is not enabled, 384 * combo-phy is already turned off by HCD driver using exit callback 385 */ 386 if (combophy->is_init) { 387 clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); 388 389 /* since wakeup is enabled for ctrl */ 390 enable_irq_wake(combophy->irq_wakeup); 391 } 392 393 return 0; 394 } 395 396 static int stm32_combophy_resume_noirq(struct device *dev) 397 { 398 struct stm32_combophy *combophy = dev_get_drvdata(dev); 399 int ret; 400 401 /* 402 * If clocks was turned off by suspend call for wakeup then needs 403 * to be turned back ON in resume. In case usb-remote wakeup is not 404 * enabled, clocks already turned ON by HCD driver using init callback 405 */ 406 if (combophy->is_init) { 407 /* since wakeup was enabled for ctrl */ 408 disable_irq_wake(combophy->irq_wakeup); 409 410 ret = clk_bulk_prepare_enable(combophy->num_clks, combophy->clks); 411 if (ret) { 412 dev_err(dev, "can't enable clocks (%d)\n", ret); 413 return ret; 414 } 415 } 416 417 return 0; 418 } 419 420 static int stm32_combophy_exit(struct phy *phy) 421 { 422 struct stm32_combophy *combophy = phy_get_drvdata(phy); 423 struct device *dev = combophy->dev; 424 425 combophy->is_init = false; 426 427 if (combophy->type == PHY_TYPE_PCIE && !combophy->have_pad_clk) 428 regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, 429 STM32MP25_PCIEPRGCR_EN, 0); 430 431 if (combophy->type != PHY_TYPE_PCIE) 432 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, 433 SYSCFG_COMBOPHY_CR1_REFSSPEN, 0); 434 435 regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, 436 SYSCFG_COMBOPHY_CR2_ISO_DIS, 0); 437 438 clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); 439 440 pm_runtime_put_noidle(dev); 441 442 return 0; 443 } 444 445 static int stm32_combophy_init(struct phy *phy) 446 { 447 struct stm32_combophy *combophy = phy_get_drvdata(phy); 448 struct device *dev = combophy->dev; 449 int ret; 450 451 pm_runtime_get_noresume(dev); 452 453 ret = clk_bulk_prepare_enable(combophy->num_clks, combophy->clks); 454 if (ret) { 455 dev_err(dev, "can't enable clocks (%d)\n", ret); 456 pm_runtime_put_noidle(dev); 457 return ret; 458 } 459 460 ret = stm32_combophy_set_mode(combophy); 461 if (ret) { 462 dev_err(dev, "combophy mode not set\n"); 463 clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); 464 pm_runtime_put_noidle(dev); 465 return ret; 466 } 467 468 ret = stm32_combophy_pll_init(combophy); 469 if (ret) { 470 clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); 471 pm_runtime_put_noidle(dev); 472 return ret; 473 } 474 475 pm_runtime_disable(dev); 476 pm_runtime_set_active(dev); 477 pm_runtime_enable(dev); 478 479 combophy->is_init = true; 480 481 return ret; 482 } 483 484 static const struct phy_ops stm32_combophy_phy_data = { 485 .init = stm32_combophy_init, 486 .exit = stm32_combophy_exit, 487 .owner = THIS_MODULE 488 }; 489 490 static irqreturn_t stm32_combophy_irq_wakeup_handler(int irq, void *dev_id) 491 { 492 return IRQ_HANDLED; 493 } 494 495 static int stm32_combophy_get_clocks(struct stm32_combophy *combophy) 496 { 497 int i, ret; 498 499 for (i = 0; i < ARRAY_SIZE(combophy_clks); i++) 500 combophy->clks[i].id = combophy_clks[i]; 501 502 combophy->num_clks = ARRAY_SIZE(combophy_clks) - 1; 503 504 ret = devm_clk_bulk_get(combophy->dev, combophy->num_clks, combophy->clks); 505 if (ret) 506 return ret; 507 508 ret = devm_clk_bulk_get_optional(combophy->dev, 1, combophy->clks + combophy->num_clks); 509 if (ret) 510 return ret; 511 512 if (combophy->clks[combophy->num_clks].clk != NULL) { 513 combophy->have_pad_clk = true; 514 combophy->num_clks++; 515 } 516 517 return 0; 518 } 519 520 static int stm32_combophy_probe(struct platform_device *pdev) 521 { 522 struct stm32_combophy *combophy; 523 struct device *dev = &pdev->dev; 524 struct phy_provider *phy_provider; 525 int ret, irq; 526 527 combophy = devm_kzalloc(dev, sizeof(*combophy), GFP_KERNEL); 528 if (!combophy) 529 return -ENOMEM; 530 531 combophy->dev = dev; 532 533 dev_set_drvdata(dev, combophy); 534 535 combophy->base = devm_platform_ioremap_resource(pdev, 0); 536 if (IS_ERR(combophy->base)) 537 return PTR_ERR(combophy->base); 538 539 ret = stm32_combophy_get_clocks(combophy); 540 if (ret) 541 return ret; 542 543 combophy->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); 544 if (IS_ERR(combophy->phy_reset)) 545 return dev_err_probe(dev, PTR_ERR(combophy->phy_reset), 546 "Failed to get PHY reset\n"); 547 548 combophy->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg"); 549 if (IS_ERR(combophy->regmap)) 550 return dev_err_probe(dev, PTR_ERR(combophy->regmap), 551 "No syscfg specified\n"); 552 553 combophy->phy = devm_phy_create(dev, NULL, &stm32_combophy_phy_data); 554 if (IS_ERR(combophy->phy)) 555 return dev_err_probe(dev, PTR_ERR(combophy->phy), 556 "failed to create PCIe/USB3 ComboPHY\n"); 557 558 if (device_property_read_bool(dev, "wakeup-source")) { 559 irq = platform_get_irq(pdev, 0); 560 if (irq < 0) 561 return dev_err_probe(dev, irq, "failed to get IRQ\n"); 562 combophy->irq_wakeup = irq; 563 564 ret = devm_request_threaded_irq(dev, combophy->irq_wakeup, NULL, 565 stm32_combophy_irq_wakeup_handler, IRQF_ONESHOT, 566 NULL, NULL); 567 if (ret) 568 return dev_err_probe(dev, ret, "unable to request wake IRQ %d\n", 569 combophy->irq_wakeup); 570 } 571 572 ret = devm_pm_runtime_enable(dev); 573 if (ret) 574 return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); 575 576 phy_set_drvdata(combophy->phy, combophy); 577 578 phy_provider = devm_of_phy_provider_register(dev, stm32_combophy_xlate); 579 580 return PTR_ERR_OR_ZERO(phy_provider); 581 } 582 583 static const struct dev_pm_ops stm32_combophy_pm_ops = { 584 NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_combophy_suspend_noirq, 585 stm32_combophy_resume_noirq) 586 }; 587 588 static const struct of_device_id stm32_combophy_of_match[] = { 589 { .compatible = "st,stm32mp25-combophy", }, 590 { }, 591 }; 592 MODULE_DEVICE_TABLE(of, stm32_combophy_of_match); 593 594 static struct platform_driver stm32_combophy_driver = { 595 .probe = stm32_combophy_probe, 596 .driver = { 597 .name = "stm32-combophy", 598 .of_match_table = stm32_combophy_of_match, 599 .pm = pm_sleep_ptr(&stm32_combophy_pm_ops) 600 } 601 }; 602 603 module_platform_driver(stm32_combophy_driver); 604 605 MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>"); 606 MODULE_DESCRIPTION("STM32MP25 Combophy USB3/PCIe controller driver"); 607 MODULE_LICENSE("GPL"); 608