]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/usb/chipidea/ci_hdrc_imx.c
MLK-10132-4 usb: chipidea: imx: disable usb wakeup in probe
[karo-tx-linux.git] / drivers / usb / chipidea / ci_hdrc_imx.c
1 /*
2  * Copyright 2012-2015 Freescale Semiconductor, Inc.
3  * Copyright (C) 2012 Marek Vasut <marex@denx.de>
4  * on behalf of DENX Software Engineering GmbH
5  *
6  * The code contained herein is licensed under the GNU General Public
7  * License. You may obtain a copy of the GNU General Public License
8  * Version 2 or later at the following locations:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13
14 #include <linux/module.h>
15 #include <linux/of_platform.h>
16 #include <linux/of_gpio.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/usb/chipidea.h>
21 #include <linux/clk.h>
22 #include <linux/of_device.h>
23 #include <linux/regmap.h>
24 #include <linux/mfd/syscon.h>
25 #include <linux/power/imx6_usb_charger.h>
26 #include <linux/busfreq-imx6.h>
27 #include <linux/regulator/consumer.h>
28
29 #include "ci.h"
30 #include "ci_hdrc_imx.h"
31
32 struct ci_hdrc_imx_platform_flag {
33         unsigned int flags;
34         bool runtime_pm;
35         u32 ahbburst_config;
36         u32 burst_length;
37 };
38
39 static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
40 };
41
42 static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
43         .flags = CI_HDRC_IMX28_WRITE_FIX |
44                 CI_HDRC_IMX_EHCI_QUIRK |
45                 CI_HDRC_DISABLE_STREAMING,
46 };
47
48 static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
49         .flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
50                 CI_HDRC_IMX_EHCI_QUIRK |
51                 CI_HDRC_DISABLE_STREAMING |
52                 CI_HDRC_OVERRIDE_AHB_BURST |
53                 CI_HDRC_OVERRIDE_BURST_LENGTH,
54         .ahbburst_config = 0, /*bit0 - bit2 at $BASE + 0x90 */
55         .burst_length = 0x1010, /*bit0 - bit15 at $BASE + 0x160 */
56 };
57
58 static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
59         .flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
60                 CI_HDRC_IMX_EHCI_QUIRK |
61                 CI_HDRC_DISABLE_HOST_STREAMING |
62                 CI_HDRC_OVERRIDE_AHB_BURST |
63                 CI_HDRC_OVERRIDE_BURST_LENGTH,
64         .ahbburst_config = 0,
65         .burst_length = 0x1010,
66 };
67
68 static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
69         .flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
70                 CI_HDRC_IMX_EHCI_QUIRK |
71                 CI_HDRC_DISABLE_HOST_STREAMING |
72                 CI_HDRC_OVERRIDE_AHB_BURST |
73                 CI_HDRC_OVERRIDE_BURST_LENGTH,
74         .ahbburst_config = 0,
75         .burst_length = 0x1010,
76 };
77
78 static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
79         { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
80         { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
81         { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
82         { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
83         { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
84         { /* sentinel */ }
85 };
86 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
87
88 struct ci_hdrc_imx_data {
89         struct usb_phy *phy;
90         struct platform_device *ci_pdev;
91         struct clk *clk;
92         struct imx_usbmisc_data *usbmisc_data;
93         bool supports_runtime_pm;
94         bool in_lpm;
95         bool imx6_usb_charger_detection;
96         struct usb_charger charger;
97         struct regmap *anatop;
98         struct pinctrl *pinctrl;
99         struct pinctrl_state *pinctrl_hsic_active;
100         struct regulator *hsic_pad_regulator;
101         const struct ci_hdrc_imx_platform_flag *data;
102 };
103
104 static inline bool is_imx6q_con(struct ci_hdrc_imx_data *imx_data)
105 {
106         return imx_data->data == &imx6q_usb_data;
107 }
108
109 static inline bool is_imx6sl_con(struct ci_hdrc_imx_data *imx_data)
110 {
111         return imx_data->data == &imx6sl_usb_data;
112 }
113
114 static inline bool is_imx6sx_con(struct ci_hdrc_imx_data *imx_data)
115 {
116         return imx_data->data == &imx6sx_usb_data;
117 }
118
119 static inline bool imx_has_hsic_con(struct ci_hdrc_imx_data *imx_data)
120 {
121         return is_imx6q_con(imx_data) ||  is_imx6sl_con(imx_data)
122                 || is_imx6sx_con(imx_data);
123 }
124
125 /* Common functions shared by usbmisc drivers */
126
127 static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
128 {
129         struct platform_device *misc_pdev;
130         struct device_node *np = dev->of_node;
131         struct of_phandle_args args;
132         struct imx_usbmisc_data *data;
133         int ret;
134
135         /*
136          * In case the fsl,usbmisc property is not present this device doesn't
137          * need usbmisc. Return NULL (which is no error here)
138          */
139         if (!of_get_property(np, "fsl,usbmisc", NULL))
140                 return NULL;
141
142         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
143         if (!data)
144                 return ERR_PTR(-ENOMEM);
145
146         ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
147                                         0, &args);
148         if (ret) {
149                 dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
150                         ret);
151                 return ERR_PTR(ret);
152         }
153
154         data->index = args.args[0];
155
156         misc_pdev = of_find_device_by_node(args.np);
157         of_node_put(args.np);
158
159         if (!misc_pdev)
160                 return ERR_PTR(-EPROBE_DEFER);
161
162         data->dev = &misc_pdev->dev;
163
164         if (of_find_property(np, "disable-over-current", NULL))
165                 data->disable_oc = 1;
166
167         if (of_find_property(np, "external-vbus-divider", NULL))
168                 data->evdo = 1;
169
170         if (of_find_property(np, "osc-clkgate-delay", NULL)) {
171                 ret = of_property_read_u32(np, "osc-clkgate-delay",
172                         &data->osc_clkgate_delay);
173                 if (ret) {
174                         dev_err(dev,
175                                 "failed to get osc-clkgate-delay value\n");
176                         return ERR_PTR(ret);
177                 }
178                 /*
179                  * 0 <= osc_clkgate_delay <=7
180                  * - 0x0 (default) is 0.5ms,
181                  * - 0x1-0x7: 1-7ms
182                  */
183                 if (data->osc_clkgate_delay > 7) {
184                         dev_err(dev,
185                                 "value of osc-clkgate-delay is incorrect\n");
186                         return ERR_PTR(-EINVAL);
187                 }
188         }
189
190         return data;
191 }
192
193 /* End of common functions shared by usbmisc drivers*/
194
195 static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event)
196 {
197         struct device *dev = ci->dev->parent;
198         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
199         int ret = 0;
200
201         switch (event) {
202         case CI_HDRC_CONTROLLER_VBUS_EVENT:
203                 if (data->usbmisc_data && ci->vbus_active) {
204                         if (data->imx6_usb_charger_detection)
205                                 ret = imx6_usb_vbus_connect(&data->charger);
206                         if (!ret && data->charger.psy.type !=
207                                                 POWER_SUPPLY_TYPE_USB)
208                                 ret = CI_HDRC_NOTIFY_RET_DEFER_EVENT;
209                 } else if (data->usbmisc_data && !ci->vbus_active) {
210                         if (data->imx6_usb_charger_detection)
211                                 ret = imx6_usb_vbus_disconnect(&data->charger);
212                 }
213                 break;
214         case CI_HDRC_CONTROLLER_CHARGER_POST_EVENT:
215                 if (!data->imx6_usb_charger_detection)
216                         return ret;
217                 imx6_usb_charger_detect_post(&data->charger);
218                 break;
219         case CI_HDRC_IMX_HSIC_ACTIVE_EVENT:
220                 if (!IS_ERR(data->pinctrl) &&
221                         !IS_ERR(data->pinctrl_hsic_active)) {
222                         ret = pinctrl_select_state(data->pinctrl,
223                                         data->pinctrl_hsic_active);
224                         if (ret)
225                                 dev_err(dev,
226                                         "hsic_active select failed, err=%d\n",
227                                         ret);
228                         return ret;
229                 }
230                 break;
231         case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
232                 if (data->usbmisc_data) {
233                         ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data);
234                         if (ret)
235                                 dev_err(dev,
236                                         "hsic_set_connect failed, err=%d\n",
237                                         ret);
238                         return ret;
239                 }
240                 break;
241         default:
242                 dev_dbg(dev, "unknown event\n");
243         }
244
245         return ret;
246 }
247
248 static int ci_hdrc_imx_probe(struct platform_device *pdev)
249 {
250         struct ci_hdrc_imx_data *data;
251         struct ci_hdrc_platform_data pdata = {
252                 .name           = dev_name(&pdev->dev),
253                 .capoffset      = DEF_CAPOFFSET,
254                 .notify_event = ci_hdrc_imx_notify_event,
255         };
256         int ret;
257         const struct of_device_id *of_id =
258                         of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
259         const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
260         struct device_node *np = pdev->dev.of_node;
261         struct pinctrl_state *pinctrl_hsic_idle;
262
263         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
264         if (!data)
265                 return -ENOMEM;
266
267         platform_set_drvdata(pdev, data);
268
269         data->data = imx_platform_flag;
270         data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
271         if (IS_ERR(data->usbmisc_data))
272                 return PTR_ERR(data->usbmisc_data);
273
274         data->pinctrl = devm_pinctrl_get(&pdev->dev);
275         if (IS_ERR(data->pinctrl)) {
276                 dev_dbg(&pdev->dev, "pinctrl get failed, err=%ld\n",
277                                                 PTR_ERR(data->pinctrl));
278         } else {
279                 pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle");
280                 if (IS_ERR(pinctrl_hsic_idle)) {
281                         dev_dbg(&pdev->dev,
282                                 "pinctrl_hsic_idle lookup failed, err=%ld\n",
283                                                 PTR_ERR(pinctrl_hsic_idle));
284                 } else {
285                         ret = pinctrl_select_state(data->pinctrl,
286                                                 pinctrl_hsic_idle);
287                         if (ret) {
288                                 dev_err(&pdev->dev,
289                                         "hsic_idle select failed, err=%d\n",
290                                                                         ret);
291                                 return ret;
292                         }
293                 }
294
295                 data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl,
296                                                                 "active");
297                 if (IS_ERR(data->pinctrl_hsic_active))
298                         dev_dbg(&pdev->dev,
299                                 "pinctrl_hsic_active lookup failed, err=%ld\n",
300                                         PTR_ERR(data->pinctrl_hsic_active));
301         }
302
303         data->clk = devm_clk_get(&pdev->dev, NULL);
304         if (IS_ERR(data->clk)) {
305                 dev_err(&pdev->dev,
306                         "Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
307                 return PTR_ERR(data->clk);
308         }
309
310         request_bus_freq(BUS_FREQ_HIGH);
311         ret = clk_prepare_enable(data->clk);
312         if (ret) {
313                 release_bus_freq(BUS_FREQ_HIGH);
314                 dev_err(&pdev->dev,
315                         "Failed to prepare or enable clock, err=%d\n", ret);
316                 return ret;
317         }
318
319         data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
320         if (IS_ERR(data->phy)) {
321                 ret = PTR_ERR(data->phy);
322                 /* Return -EINVAL if no usbphy is available */
323                 if (ret == -ENODEV)
324                         ret = -EINVAL;
325                 goto err_clk;
326         }
327
328         pdata.usb_phy = data->phy;
329         pdata.flags |= imx_platform_flag->flags;
330         if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
331                 data->supports_runtime_pm = true;
332
333         ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
334         if (ret)
335                 goto err_clk;
336
337         if (data->usbmisc_data->index > 1 && (imx_has_hsic_con(data))) {
338                 pdata.flags |= CI_HDRC_IMX_IS_HSIC;
339                 data->hsic_pad_regulator = devm_regulator_get(&pdev->dev,
340                                                                         "pad");
341                 if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) {
342                         ret = -EPROBE_DEFER;
343                         goto err_clk;
344                 } else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
345                         /* no pad regualator is needed */
346                         data->hsic_pad_regulator = NULL;
347                 } else if (IS_ERR(data->hsic_pad_regulator)) {
348                         dev_err(&pdev->dev,
349                                 "Get hsic pad regulator error: %ld\n",
350                                         PTR_ERR(data->hsic_pad_regulator));
351                         ret = PTR_ERR(data->hsic_pad_regulator);
352                         goto err_clk;
353                 }
354
355                 if (data->hsic_pad_regulator) {
356                         ret = regulator_enable(data->hsic_pad_regulator);
357                         if (ret) {
358                                 dev_err(&pdev->dev,
359                                         "Fail to enable hsic pad regulator\n");
360                                 goto err_clk;
361                         }
362                 }
363         }
364
365         if (of_find_property(np, "imx6-usb-charger-detection", NULL))
366                 data->imx6_usb_charger_detection = true;
367
368         if (of_find_property(np, "fsl,anatop", NULL)) {
369                 data->anatop = syscon_regmap_lookup_by_phandle(np,
370                                                         "fsl,anatop");
371                 if (IS_ERR(data->anatop)) {
372                         dev_dbg(&pdev->dev,
373                                 "failed to find regmap for anatop\n");
374                         ret = PTR_ERR(data->anatop);
375                         goto disable_hsic_regulator;
376                 }
377                 if (data->usbmisc_data)
378                         data->usbmisc_data->anatop = data->anatop;
379                 if (data->imx6_usb_charger_detection) {
380                         data->charger.anatop = data->anatop;
381                         data->charger.dev = &pdev->dev;
382                         ret = imx6_usb_create_charger(&data->charger,
383                                                 "imx6_usb_charger");
384                         if (ret && ret != -ENODEV)
385                                 goto disable_hsic_regulator;
386                         if (!ret)
387                                 dev_dbg(&pdev->dev,
388                                         "USB Charger is created\n");
389                 }
390         }
391
392         ret = imx_usbmisc_init(data->usbmisc_data);
393         if (ret) {
394                 dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
395                 goto remove_charger;
396         }
397
398         if (imx_platform_flag->flags & CI_HDRC_OVERRIDE_AHB_BURST)
399                 pdata.ahbburst_config = imx_platform_flag->ahbburst_config;
400
401         if (imx_platform_flag->flags & CI_HDRC_OVERRIDE_BURST_LENGTH)
402                 pdata.burst_length = imx_platform_flag->burst_length;
403
404         data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
405                                 pdev->resource, pdev->num_resources,
406                                 &pdata);
407         if (IS_ERR(data->ci_pdev)) {
408                 ret = PTR_ERR(data->ci_pdev);
409                 dev_err(&pdev->dev,
410                         "Can't register ci_hdrc platform device, err=%d\n",
411                         ret);
412                 goto remove_charger;
413         }
414
415         ret = imx_usbmisc_init_post(data->usbmisc_data);
416         if (ret) {
417                 dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret);
418                 goto disable_device;
419         }
420
421         ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
422         if (ret) {
423                 dev_err(&pdev->dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
424                 goto disable_device;
425         }
426
427         /* usbmisc needs to know dr mode to choose wakeup setting */
428         data->usbmisc_data->available_role =
429                                 ci_hdrc_query_available_role(data->ci_pdev);
430
431         if (data->supports_runtime_pm) {
432                 pm_runtime_set_active(&pdev->dev);
433                 pm_runtime_enable(&pdev->dev);
434         }
435
436         device_set_wakeup_capable(&pdev->dev, true);
437
438         return 0;
439
440 disable_device:
441         ci_hdrc_remove_device(data->ci_pdev);
442 remove_charger:
443         if (data->imx6_usb_charger_detection)
444                 imx6_usb_remove_charger(&data->charger);
445 disable_hsic_regulator:
446         if (data->hsic_pad_regulator)
447                 ret = regulator_disable(data->hsic_pad_regulator);
448 err_clk:
449         clk_disable_unprepare(data->clk);
450         release_bus_freq(BUS_FREQ_HIGH);
451         return ret;
452 }
453
454 static int ci_hdrc_imx_remove(struct platform_device *pdev)
455 {
456         struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
457
458         if (data->supports_runtime_pm) {
459                 pm_runtime_get_sync(&pdev->dev);
460                 pm_runtime_disable(&pdev->dev);
461                 pm_runtime_put_noidle(&pdev->dev);
462         }
463         ci_hdrc_remove_device(data->ci_pdev);
464         clk_disable_unprepare(data->clk);
465         release_bus_freq(BUS_FREQ_HIGH);
466         if (data->imx6_usb_charger_detection)
467                 imx6_usb_remove_charger(&data->charger);
468         if (data->hsic_pad_regulator)
469                 regulator_disable(data->hsic_pad_regulator);
470
471         return 0;
472 }
473
474 #ifdef CONFIG_PM
475 static int imx_controller_suspend(struct device *dev)
476 {
477         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
478         int ret;
479
480         dev_dbg(dev, "at %s\n", __func__);
481
482         if (data->usbmisc_data) {
483                 ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false);
484                 if (ret) {
485                         dev_err(dev,
486                                 "usbmisc hsic_set_clk failed, ret=%d\n", ret);
487                         return ret;
488                 }
489         }
490
491         clk_disable_unprepare(data->clk);
492         release_bus_freq(BUS_FREQ_HIGH);
493         data->in_lpm = true;
494
495         return 0;
496 }
497
498 static int imx_controller_resume(struct device *dev)
499 {
500         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
501         int ret = 0;
502
503         dev_dbg(dev, "at %s\n", __func__);
504
505         if (!data->in_lpm) {
506                 WARN_ON(1);
507                 return 0;
508         }
509
510         request_bus_freq(BUS_FREQ_HIGH);
511         ret = clk_prepare_enable(data->clk);
512         if (ret) {
513                 release_bus_freq(BUS_FREQ_HIGH);
514                 return ret;
515         }
516
517         data->in_lpm = false;
518
519         ret = imx_usbmisc_power_lost_check(data->usbmisc_data);
520         /* re-init if resume from power lost */
521         if (ret > 0) {
522                 ret = imx_usbmisc_init(data->usbmisc_data);
523                 if (ret) {
524                         dev_err(dev, "usbmisc init failed, ret=%d\n", ret);
525                         goto clk_disable;
526                 }
527         }
528
529         ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
530         if (ret) {
531                 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
532                 goto clk_disable;
533         }
534
535         ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true);
536         if (ret) {
537                 dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
538                 goto hsic_set_clk_fail;
539         }
540
541         return 0;
542
543 hsic_set_clk_fail:
544         imx_usbmisc_set_wakeup(data->usbmisc_data, true);
545 clk_disable:
546         clk_disable_unprepare(data->clk);
547         release_bus_freq(BUS_FREQ_HIGH);
548
549         return ret;
550 }
551
552 #ifdef CONFIG_PM_SLEEP
553 static int ci_hdrc_imx_suspend(struct device *dev)
554 {
555         int ret;
556
557         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
558
559         if (data->in_lpm)
560                 /* The core's suspend doesn't run */
561                 return 0;
562
563         if (device_may_wakeup(dev)) {
564                 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
565                 if (ret) {
566                         dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
567                                         ret);
568                         return ret;
569                 }
570         }
571
572         return imx_controller_suspend(dev);
573 }
574
575 static int ci_hdrc_imx_resume(struct device *dev)
576 {
577         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
578         int ret;
579
580         ret = imx_controller_resume(dev);
581         if (!ret && data->supports_runtime_pm) {
582                 pm_runtime_disable(dev);
583                 pm_runtime_set_active(dev);
584                 pm_runtime_enable(dev);
585         }
586
587         return ret;
588 }
589 #endif /* CONFIG_PM_SLEEP */
590
591 #ifdef CONFIG_PM_RUNTIME
592 static int ci_hdrc_imx_runtime_suspend(struct device *dev)
593 {
594         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
595         int ret;
596
597         if (data->in_lpm) {
598                 WARN_ON(1);
599                 return 0;
600         }
601
602         ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
603         if (ret) {
604                 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
605                 return ret;
606         }
607
608         return imx_controller_suspend(dev);
609 }
610
611 static int ci_hdrc_imx_runtime_resume(struct device *dev)
612 {
613         return imx_controller_resume(dev);
614 }
615 #endif /* CONFIG_PM_RUNTIME */
616
617 #endif /* CONFIG_PM */
618
619 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
620         SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
621         SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
622                         ci_hdrc_imx_runtime_resume, NULL)
623 };
624 static struct platform_driver ci_hdrc_imx_driver = {
625         .probe = ci_hdrc_imx_probe,
626         .remove = ci_hdrc_imx_remove,
627         .driver = {
628                 .name = "imx_usb",
629                 .owner = THIS_MODULE,
630                 .of_match_table = ci_hdrc_imx_dt_ids,
631                 .pm = &ci_hdrc_imx_pm_ops,
632          },
633 };
634
635 module_platform_driver(ci_hdrc_imx_driver);
636
637 MODULE_ALIAS("platform:imx-usb");
638 MODULE_LICENSE("GPL v2");
639 MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
640 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
641 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");