1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2012 Freescale Semiconductor, Inc. 4 * Copyright (C) 2012 Marek Vasut <marex@denx.de> 5 * on behalf of DENX Software Engineering GmbH 6 */ 7 8 #include <linux/module.h> 9 #include <linux/of_platform.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/usb/chipidea.h> 13 #include <linux/usb/of.h> 14 #include <linux/clk.h> 15 #include <linux/pinctrl/consumer.h> 16 #include <linux/pm_qos.h> 17 18 #include "ci.h" 19 #include "ci_hdrc_imx.h" 20 21 struct ci_hdrc_imx_platform_flag { 22 unsigned int flags; 23 }; 24 25 static const struct ci_hdrc_imx_platform_flag imx23_usb_data = { 26 .flags = CI_HDRC_TURN_VBUS_EARLY_ON | 27 CI_HDRC_DISABLE_STREAMING, 28 }; 29 30 static const struct ci_hdrc_imx_platform_flag imx27_usb_data = { 31 .flags = CI_HDRC_DISABLE_STREAMING, 32 }; 33 34 static const struct ci_hdrc_imx_platform_flag imx28_usb_data = { 35 .flags = CI_HDRC_IMX28_WRITE_FIX | 36 CI_HDRC_TURN_VBUS_EARLY_ON | 37 CI_HDRC_DISABLE_STREAMING, 38 }; 39 40 static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = { 41 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 42 CI_HDRC_TURN_VBUS_EARLY_ON | 43 CI_HDRC_DISABLE_STREAMING, 44 }; 45 46 static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = { 47 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 48 CI_HDRC_TURN_VBUS_EARLY_ON | 49 CI_HDRC_DISABLE_HOST_STREAMING, 50 }; 51 52 static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = { 53 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 54 CI_HDRC_TURN_VBUS_EARLY_ON | 55 CI_HDRC_DISABLE_HOST_STREAMING, 56 }; 57 58 static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = { 59 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 60 CI_HDRC_TURN_VBUS_EARLY_ON, 61 }; 62 63 static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = { 64 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, 65 }; 66 67 static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = { 68 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 69 CI_HDRC_PMQOS, 70 }; 71 72 static const struct of_device_id ci_hdrc_imx_dt_ids[] = { 73 { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data}, 74 { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, 75 { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, 76 { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data}, 77 { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data}, 78 { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data}, 79 { .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data}, 80 { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, 81 { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data}, 82 { /* sentinel */ } 83 }; 84 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); 85 86 struct ci_hdrc_imx_data { 87 struct usb_phy *phy; 88 struct platform_device *ci_pdev; 89 struct clk *clk; 90 struct imx_usbmisc_data *usbmisc_data; 91 bool supports_runtime_pm; 92 bool override_phy_control; 93 bool in_lpm; 94 struct pinctrl *pinctrl; 95 struct pinctrl_state *pinctrl_hsic_active; 96 struct regulator *hsic_pad_regulator; 97 /* SoC before i.mx6 (except imx23/imx28) needs three clks */ 98 bool need_three_clks; 99 struct clk *clk_ipg; 100 struct clk *clk_ahb; 101 struct clk *clk_per; 102 /* --------------------------------- */ 103 struct pm_qos_request pm_qos_req; 104 const struct ci_hdrc_imx_platform_flag *plat_data; 105 }; 106 107 /* Common functions shared by usbmisc drivers */ 108 109 static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) 110 { 111 struct platform_device *misc_pdev; 112 struct device_node *np = dev->of_node; 113 struct of_phandle_args args; 114 struct imx_usbmisc_data *data; 115 int ret; 116 117 /* 118 * In case the fsl,usbmisc property is not present this device doesn't 119 * need usbmisc. Return NULL (which is no error here) 120 */ 121 if (!of_get_property(np, "fsl,usbmisc", NULL)) 122 return NULL; 123 124 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 125 if (!data) 126 return ERR_PTR(-ENOMEM); 127 128 ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", 129 0, &args); 130 if (ret) { 131 dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", 132 ret); 133 return ERR_PTR(ret); 134 } 135 136 data->index = args.args[0]; 137 138 misc_pdev = of_find_device_by_node(args.np); 139 of_node_put(args.np); 140 141 if (!misc_pdev || !platform_get_drvdata(misc_pdev)) 142 return ERR_PTR(-EPROBE_DEFER); 143 144 data->dev = &misc_pdev->dev; 145 146 /* 147 * Check the various over current related properties. If over current 148 * detection is disabled we're not interested in the polarity. 149 */ 150 if (of_find_property(np, "disable-over-current", NULL)) { 151 data->disable_oc = 1; 152 } else if (of_find_property(np, "over-current-active-high", NULL)) { 153 data->oc_pol_active_low = 0; 154 data->oc_pol_configured = 1; 155 } else if (of_find_property(np, "over-current-active-low", NULL)) { 156 data->oc_pol_active_low = 1; 157 data->oc_pol_configured = 1; 158 } else { 159 dev_warn(dev, "No over current polarity defined\n"); 160 } 161 162 data->pwr_pol = of_property_read_bool(np, "power-active-high"); 163 data->evdo = of_property_read_bool(np, "external-vbus-divider"); 164 165 if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) 166 data->ulpi = 1; 167 168 return data; 169 } 170 171 /* End of common functions shared by usbmisc drivers*/ 172 static int imx_get_clks(struct device *dev) 173 { 174 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 175 int ret = 0; 176 177 data->clk_ipg = devm_clk_get(dev, "ipg"); 178 if (IS_ERR(data->clk_ipg)) { 179 /* If the platform only needs one clocks */ 180 data->clk = devm_clk_get(dev, NULL); 181 if (IS_ERR(data->clk)) { 182 ret = PTR_ERR(data->clk); 183 dev_err(dev, 184 "Failed to get clks, err=%ld,%ld\n", 185 PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); 186 return ret; 187 } 188 return ret; 189 } 190 191 data->clk_ahb = devm_clk_get(dev, "ahb"); 192 if (IS_ERR(data->clk_ahb)) { 193 ret = PTR_ERR(data->clk_ahb); 194 dev_err(dev, 195 "Failed to get ahb clock, err=%d\n", ret); 196 return ret; 197 } 198 199 data->clk_per = devm_clk_get(dev, "per"); 200 if (IS_ERR(data->clk_per)) { 201 ret = PTR_ERR(data->clk_per); 202 dev_err(dev, 203 "Failed to get per clock, err=%d\n", ret); 204 return ret; 205 } 206 207 data->need_three_clks = true; 208 return ret; 209 } 210 211 static int imx_prepare_enable_clks(struct device *dev) 212 { 213 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 214 int ret = 0; 215 216 if (data->need_three_clks) { 217 ret = clk_prepare_enable(data->clk_ipg); 218 if (ret) { 219 dev_err(dev, 220 "Failed to prepare/enable ipg clk, err=%d\n", 221 ret); 222 return ret; 223 } 224 225 ret = clk_prepare_enable(data->clk_ahb); 226 if (ret) { 227 dev_err(dev, 228 "Failed to prepare/enable ahb clk, err=%d\n", 229 ret); 230 clk_disable_unprepare(data->clk_ipg); 231 return ret; 232 } 233 234 ret = clk_prepare_enable(data->clk_per); 235 if (ret) { 236 dev_err(dev, 237 "Failed to prepare/enable per clk, err=%d\n", 238 ret); 239 clk_disable_unprepare(data->clk_ahb); 240 clk_disable_unprepare(data->clk_ipg); 241 return ret; 242 } 243 } else { 244 ret = clk_prepare_enable(data->clk); 245 if (ret) { 246 dev_err(dev, 247 "Failed to prepare/enable clk, err=%d\n", 248 ret); 249 return ret; 250 } 251 } 252 253 return ret; 254 } 255 256 static void imx_disable_unprepare_clks(struct device *dev) 257 { 258 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 259 260 if (data->need_three_clks) { 261 clk_disable_unprepare(data->clk_per); 262 clk_disable_unprepare(data->clk_ahb); 263 clk_disable_unprepare(data->clk_ipg); 264 } else { 265 clk_disable_unprepare(data->clk); 266 } 267 } 268 269 static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) 270 { 271 struct device *dev = ci->dev->parent; 272 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 273 int ret = 0; 274 275 switch (event) { 276 case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: 277 if (data->pinctrl) { 278 ret = pinctrl_select_state(data->pinctrl, 279 data->pinctrl_hsic_active); 280 if (ret) 281 dev_err(dev, 282 "hsic_active select failed, err=%d\n", 283 ret); 284 } 285 break; 286 case CI_HDRC_IMX_HSIC_SUSPEND_EVENT: 287 ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data); 288 if (ret) 289 dev_err(dev, 290 "hsic_set_connect failed, err=%d\n", ret); 291 break; 292 default: 293 break; 294 } 295 296 return ret; 297 } 298 299 static int ci_hdrc_imx_probe(struct platform_device *pdev) 300 { 301 struct ci_hdrc_imx_data *data; 302 struct ci_hdrc_platform_data pdata = { 303 .name = dev_name(&pdev->dev), 304 .capoffset = DEF_CAPOFFSET, 305 .notify_event = ci_hdrc_imx_notify_event, 306 }; 307 int ret; 308 const struct of_device_id *of_id; 309 const struct ci_hdrc_imx_platform_flag *imx_platform_flag; 310 struct device_node *np = pdev->dev.of_node; 311 struct device *dev = &pdev->dev; 312 313 of_id = of_match_device(ci_hdrc_imx_dt_ids, dev); 314 if (!of_id) 315 return -ENODEV; 316 317 imx_platform_flag = of_id->data; 318 319 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 320 if (!data) 321 return -ENOMEM; 322 323 data->plat_data = imx_platform_flag; 324 pdata.flags |= imx_platform_flag->flags; 325 platform_set_drvdata(pdev, data); 326 data->usbmisc_data = usbmisc_get_init_data(dev); 327 if (IS_ERR(data->usbmisc_data)) 328 return PTR_ERR(data->usbmisc_data); 329 330 if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) 331 && data->usbmisc_data) { 332 pdata.flags |= CI_HDRC_IMX_IS_HSIC; 333 data->usbmisc_data->hsic = 1; 334 data->pinctrl = devm_pinctrl_get(dev); 335 if (PTR_ERR(data->pinctrl) == -ENODEV) 336 data->pinctrl = NULL; 337 else if (IS_ERR(data->pinctrl)) { 338 if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER) 339 dev_err(dev, "pinctrl get failed, err=%ld\n", 340 PTR_ERR(data->pinctrl)); 341 return PTR_ERR(data->pinctrl); 342 } 343 344 data->hsic_pad_regulator = 345 devm_regulator_get_optional(dev, "hsic"); 346 if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { 347 /* no pad regualator is needed */ 348 data->hsic_pad_regulator = NULL; 349 } else if (IS_ERR(data->hsic_pad_regulator)) { 350 if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER) 351 dev_err(dev, 352 "Get HSIC pad regulator error: %ld\n", 353 PTR_ERR(data->hsic_pad_regulator)); 354 return PTR_ERR(data->hsic_pad_regulator); 355 } 356 357 if (data->hsic_pad_regulator) { 358 ret = regulator_enable(data->hsic_pad_regulator); 359 if (ret) { 360 dev_err(dev, 361 "Failed to enable HSIC pad regulator\n"); 362 return ret; 363 } 364 } 365 } 366 367 /* HSIC pinctrl handling */ 368 if (data->pinctrl) { 369 struct pinctrl_state *pinctrl_hsic_idle; 370 371 pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); 372 if (IS_ERR(pinctrl_hsic_idle)) { 373 dev_err(dev, 374 "pinctrl_hsic_idle lookup failed, err=%ld\n", 375 PTR_ERR(pinctrl_hsic_idle)); 376 return PTR_ERR(pinctrl_hsic_idle); 377 } 378 379 ret = pinctrl_select_state(data->pinctrl, pinctrl_hsic_idle); 380 if (ret) { 381 dev_err(dev, "hsic_idle select failed, err=%d\n", ret); 382 return ret; 383 } 384 385 data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl, 386 "active"); 387 if (IS_ERR(data->pinctrl_hsic_active)) { 388 dev_err(dev, 389 "pinctrl_hsic_active lookup failed, err=%ld\n", 390 PTR_ERR(data->pinctrl_hsic_active)); 391 return PTR_ERR(data->pinctrl_hsic_active); 392 } 393 } 394 395 if (pdata.flags & CI_HDRC_PMQOS) 396 pm_qos_add_request(&data->pm_qos_req, 397 PM_QOS_CPU_DMA_LATENCY, 0); 398 399 ret = imx_get_clks(dev); 400 if (ret) 401 goto disable_hsic_regulator; 402 403 ret = imx_prepare_enable_clks(dev); 404 if (ret) 405 goto disable_hsic_regulator; 406 407 data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); 408 if (IS_ERR(data->phy)) { 409 ret = PTR_ERR(data->phy); 410 /* Return -EINVAL if no usbphy is available */ 411 if (ret == -ENODEV) 412 data->phy = NULL; 413 else 414 goto err_clk; 415 } 416 417 pdata.usb_phy = data->phy; 418 419 if ((of_device_is_compatible(np, "fsl,imx53-usb") || 420 of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy && 421 of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) { 422 pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL; 423 data->override_phy_control = true; 424 usb_phy_init(pdata.usb_phy); 425 } 426 427 if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) 428 data->supports_runtime_pm = true; 429 430 ret = imx_usbmisc_init(data->usbmisc_data); 431 if (ret) { 432 dev_err(dev, "usbmisc init failed, ret=%d\n", ret); 433 goto err_clk; 434 } 435 436 data->ci_pdev = ci_hdrc_add_device(dev, 437 pdev->resource, pdev->num_resources, 438 &pdata); 439 if (IS_ERR(data->ci_pdev)) { 440 ret = PTR_ERR(data->ci_pdev); 441 if (ret != -EPROBE_DEFER) 442 dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", 443 ret); 444 goto err_clk; 445 } 446 447 if (data->usbmisc_data) { 448 if (!IS_ERR(pdata.id_extcon.edev) || 449 of_property_read_bool(np, "usb-role-switch")) 450 data->usbmisc_data->ext_id = 1; 451 452 if (!IS_ERR(pdata.vbus_extcon.edev) || 453 of_property_read_bool(np, "usb-role-switch")) 454 data->usbmisc_data->ext_vbus = 1; 455 } 456 457 ret = imx_usbmisc_init_post(data->usbmisc_data); 458 if (ret) { 459 dev_err(dev, "usbmisc post failed, ret=%d\n", ret); 460 goto disable_device; 461 } 462 463 if (data->supports_runtime_pm) { 464 pm_runtime_set_active(dev); 465 pm_runtime_enable(dev); 466 } 467 468 device_set_wakeup_capable(dev, true); 469 470 return 0; 471 472 disable_device: 473 ci_hdrc_remove_device(data->ci_pdev); 474 err_clk: 475 imx_disable_unprepare_clks(dev); 476 disable_hsic_regulator: 477 if (data->hsic_pad_regulator) 478 /* don't overwrite original ret (cf. EPROBE_DEFER) */ 479 regulator_disable(data->hsic_pad_regulator); 480 if (pdata.flags & CI_HDRC_PMQOS) 481 pm_qos_remove_request(&data->pm_qos_req); 482 data->ci_pdev = NULL; 483 return ret; 484 } 485 486 static int ci_hdrc_imx_remove(struct platform_device *pdev) 487 { 488 struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev); 489 490 if (data->supports_runtime_pm) { 491 pm_runtime_get_sync(&pdev->dev); 492 pm_runtime_disable(&pdev->dev); 493 pm_runtime_put_noidle(&pdev->dev); 494 } 495 if (data->ci_pdev) 496 ci_hdrc_remove_device(data->ci_pdev); 497 if (data->override_phy_control) 498 usb_phy_shutdown(data->phy); 499 if (data->ci_pdev) { 500 imx_disable_unprepare_clks(&pdev->dev); 501 if (data->plat_data->flags & CI_HDRC_PMQOS) 502 pm_qos_remove_request(&data->pm_qos_req); 503 if (data->hsic_pad_regulator) 504 regulator_disable(data->hsic_pad_regulator); 505 } 506 507 return 0; 508 } 509 510 static void ci_hdrc_imx_shutdown(struct platform_device *pdev) 511 { 512 ci_hdrc_imx_remove(pdev); 513 } 514 515 static int __maybe_unused imx_controller_suspend(struct device *dev) 516 { 517 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 518 int ret = 0; 519 520 dev_dbg(dev, "at %s\n", __func__); 521 522 ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false); 523 if (ret) { 524 dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); 525 return ret; 526 } 527 528 imx_disable_unprepare_clks(dev); 529 if (data->plat_data->flags & CI_HDRC_PMQOS) 530 pm_qos_remove_request(&data->pm_qos_req); 531 532 data->in_lpm = true; 533 534 return 0; 535 } 536 537 static int __maybe_unused imx_controller_resume(struct device *dev) 538 { 539 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 540 int ret = 0; 541 542 dev_dbg(dev, "at %s\n", __func__); 543 544 if (!data->in_lpm) { 545 WARN_ON(1); 546 return 0; 547 } 548 549 if (data->plat_data->flags & CI_HDRC_PMQOS) 550 pm_qos_add_request(&data->pm_qos_req, 551 PM_QOS_CPU_DMA_LATENCY, 0); 552 553 ret = imx_prepare_enable_clks(dev); 554 if (ret) 555 return ret; 556 557 data->in_lpm = false; 558 559 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false); 560 if (ret) { 561 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret); 562 goto clk_disable; 563 } 564 565 ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true); 566 if (ret) { 567 dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); 568 goto hsic_set_clk_fail; 569 } 570 571 return 0; 572 573 hsic_set_clk_fail: 574 imx_usbmisc_set_wakeup(data->usbmisc_data, true); 575 clk_disable: 576 imx_disable_unprepare_clks(dev); 577 return ret; 578 } 579 580 static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev) 581 { 582 int ret; 583 584 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 585 586 if (data->in_lpm) 587 /* The core's suspend doesn't run */ 588 return 0; 589 590 if (device_may_wakeup(dev)) { 591 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true); 592 if (ret) { 593 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", 594 ret); 595 return ret; 596 } 597 } 598 599 return imx_controller_suspend(dev); 600 } 601 602 static int __maybe_unused ci_hdrc_imx_resume(struct device *dev) 603 { 604 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 605 int ret; 606 607 ret = imx_controller_resume(dev); 608 if (!ret && data->supports_runtime_pm) { 609 pm_runtime_disable(dev); 610 pm_runtime_set_active(dev); 611 pm_runtime_enable(dev); 612 } 613 614 return ret; 615 } 616 617 static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev) 618 { 619 struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 620 int ret; 621 622 if (data->in_lpm) { 623 WARN_ON(1); 624 return 0; 625 } 626 627 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true); 628 if (ret) { 629 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret); 630 return ret; 631 } 632 633 return imx_controller_suspend(dev); 634 } 635 636 static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev) 637 { 638 return imx_controller_resume(dev); 639 } 640 641 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { 642 SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) 643 SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, 644 ci_hdrc_imx_runtime_resume, NULL) 645 }; 646 static struct platform_driver ci_hdrc_imx_driver = { 647 .probe = ci_hdrc_imx_probe, 648 .remove = ci_hdrc_imx_remove, 649 .shutdown = ci_hdrc_imx_shutdown, 650 .driver = { 651 .name = "imx_usb", 652 .of_match_table = ci_hdrc_imx_dt_ids, 653 .pm = &ci_hdrc_imx_pm_ops, 654 }, 655 }; 656 657 module_platform_driver(ci_hdrc_imx_driver); 658 659 MODULE_ALIAS("platform:imx-usb"); 660 MODULE_LICENSE("GPL"); 661 MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); 662 MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 663 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); 664