]> Git Repo - linux.git/blob - drivers/usb/chipidea/ci_hdrc_imx.c
mfd: cros-ec: Increase maximum mkbp event size
[linux.git] / drivers / usb / chipidea / ci_hdrc_imx.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2012 Freescale Semiconductor, Inc.
4  * Copyright (C) 2012 Marek Vasut <[email protected]>
5  * on behalf of DENX Software Engineering GmbH
6  */
7
8 #include <linux/module.h>
9 #include <linux/of_platform.h>
10 #include <linux/of_gpio.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/dma-mapping.h>
14 #include <linux/usb/chipidea.h>
15 #include <linux/usb/of.h>
16 #include <linux/clk.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 of_device_id ci_hdrc_imx_dt_ids[] = {
68         { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
69         { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
70         { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
71         { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
72         { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
73         { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
74         { .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
75         { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
76         { /* sentinel */ }
77 };
78 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
79
80 struct ci_hdrc_imx_data {
81         struct usb_phy *phy;
82         struct platform_device *ci_pdev;
83         struct clk *clk;
84         struct imx_usbmisc_data *usbmisc_data;
85         bool supports_runtime_pm;
86         bool override_phy_control;
87         bool in_lpm;
88         /* SoC before i.mx6 (except imx23/imx28) needs three clks */
89         bool need_three_clks;
90         struct clk *clk_ipg;
91         struct clk *clk_ahb;
92         struct clk *clk_per;
93         /* --------------------------------- */
94 };
95
96 /* Common functions shared by usbmisc drivers */
97
98 static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
99 {
100         struct platform_device *misc_pdev;
101         struct device_node *np = dev->of_node;
102         struct of_phandle_args args;
103         struct imx_usbmisc_data *data;
104         int ret;
105
106         /*
107          * In case the fsl,usbmisc property is not present this device doesn't
108          * need usbmisc. Return NULL (which is no error here)
109          */
110         if (!of_get_property(np, "fsl,usbmisc", NULL))
111                 return NULL;
112
113         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
114         if (!data)
115                 return ERR_PTR(-ENOMEM);
116
117         ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
118                                         0, &args);
119         if (ret) {
120                 dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
121                         ret);
122                 return ERR_PTR(ret);
123         }
124
125         data->index = args.args[0];
126
127         misc_pdev = of_find_device_by_node(args.np);
128         of_node_put(args.np);
129
130         if (!misc_pdev || !platform_get_drvdata(misc_pdev))
131                 return ERR_PTR(-EPROBE_DEFER);
132
133         data->dev = &misc_pdev->dev;
134
135         if (of_find_property(np, "disable-over-current", NULL))
136                 data->disable_oc = 1;
137
138         if (of_find_property(np, "over-current-active-high", NULL))
139                 data->oc_polarity = 1;
140
141         if (of_find_property(np, "external-vbus-divider", NULL))
142                 data->evdo = 1;
143
144         if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
145                 data->ulpi = 1;
146
147         return data;
148 }
149
150 /* End of common functions shared by usbmisc drivers*/
151 static int imx_get_clks(struct device *dev)
152 {
153         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
154         int ret = 0;
155
156         data->clk_ipg = devm_clk_get(dev, "ipg");
157         if (IS_ERR(data->clk_ipg)) {
158                 /* If the platform only needs one clocks */
159                 data->clk = devm_clk_get(dev, NULL);
160                 if (IS_ERR(data->clk)) {
161                         ret = PTR_ERR(data->clk);
162                         dev_err(dev,
163                                 "Failed to get clks, err=%ld,%ld\n",
164                                 PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
165                         return ret;
166                 }
167                 return ret;
168         }
169
170         data->clk_ahb = devm_clk_get(dev, "ahb");
171         if (IS_ERR(data->clk_ahb)) {
172                 ret = PTR_ERR(data->clk_ahb);
173                 dev_err(dev,
174                         "Failed to get ahb clock, err=%d\n", ret);
175                 return ret;
176         }
177
178         data->clk_per = devm_clk_get(dev, "per");
179         if (IS_ERR(data->clk_per)) {
180                 ret = PTR_ERR(data->clk_per);
181                 dev_err(dev,
182                         "Failed to get per clock, err=%d\n", ret);
183                 return ret;
184         }
185
186         data->need_three_clks = true;
187         return ret;
188 }
189
190 static int imx_prepare_enable_clks(struct device *dev)
191 {
192         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
193         int ret = 0;
194
195         if (data->need_three_clks) {
196                 ret = clk_prepare_enable(data->clk_ipg);
197                 if (ret) {
198                         dev_err(dev,
199                                 "Failed to prepare/enable ipg clk, err=%d\n",
200                                 ret);
201                         return ret;
202                 }
203
204                 ret = clk_prepare_enable(data->clk_ahb);
205                 if (ret) {
206                         dev_err(dev,
207                                 "Failed to prepare/enable ahb clk, err=%d\n",
208                                 ret);
209                         clk_disable_unprepare(data->clk_ipg);
210                         return ret;
211                 }
212
213                 ret = clk_prepare_enable(data->clk_per);
214                 if (ret) {
215                         dev_err(dev,
216                                 "Failed to prepare/enable per clk, err=%d\n",
217                                 ret);
218                         clk_disable_unprepare(data->clk_ahb);
219                         clk_disable_unprepare(data->clk_ipg);
220                         return ret;
221                 }
222         } else {
223                 ret = clk_prepare_enable(data->clk);
224                 if (ret) {
225                         dev_err(dev,
226                                 "Failed to prepare/enable clk, err=%d\n",
227                                 ret);
228                         return ret;
229                 }
230         }
231
232         return ret;
233 }
234
235 static void imx_disable_unprepare_clks(struct device *dev)
236 {
237         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
238
239         if (data->need_three_clks) {
240                 clk_disable_unprepare(data->clk_per);
241                 clk_disable_unprepare(data->clk_ahb);
242                 clk_disable_unprepare(data->clk_ipg);
243         } else {
244                 clk_disable_unprepare(data->clk);
245         }
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         };
255         int ret;
256         const struct of_device_id *of_id;
257         const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
258         struct device_node *np = pdev->dev.of_node;
259
260         of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
261         if (!of_id)
262                 return -ENODEV;
263
264         imx_platform_flag = of_id->data;
265
266         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
267         if (!data)
268                 return -ENOMEM;
269
270         platform_set_drvdata(pdev, data);
271         data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
272         if (IS_ERR(data->usbmisc_data))
273                 return PTR_ERR(data->usbmisc_data);
274
275         ret = imx_get_clks(&pdev->dev);
276         if (ret)
277                 return ret;
278
279         ret = imx_prepare_enable_clks(&pdev->dev);
280         if (ret)
281                 return ret;
282
283         data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
284         if (IS_ERR(data->phy)) {
285                 ret = PTR_ERR(data->phy);
286                 /* Return -EINVAL if no usbphy is available */
287                 if (ret == -ENODEV)
288                         ret = -EINVAL;
289                 goto err_clk;
290         }
291
292         pdata.usb_phy = data->phy;
293
294         if ((of_device_is_compatible(np, "fsl,imx53-usb") ||
295              of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy &&
296             of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) {
297                 pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL;
298                 data->override_phy_control = true;
299                 usb_phy_init(pdata.usb_phy);
300         }
301
302         pdata.flags |= imx_platform_flag->flags;
303         if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
304                 data->supports_runtime_pm = true;
305
306         ret = imx_usbmisc_init(data->usbmisc_data);
307         if (ret) {
308                 dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
309                 goto err_clk;
310         }
311
312         data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
313                                 pdev->resource, pdev->num_resources,
314                                 &pdata);
315         if (IS_ERR(data->ci_pdev)) {
316                 ret = PTR_ERR(data->ci_pdev);
317                 if (ret != -EPROBE_DEFER)
318                         dev_err(&pdev->dev,
319                                 "ci_hdrc_add_device failed, err=%d\n", ret);
320                 goto err_clk;
321         }
322
323         ret = imx_usbmisc_init_post(data->usbmisc_data);
324         if (ret) {
325                 dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret);
326                 goto disable_device;
327         }
328
329         if (data->supports_runtime_pm) {
330                 pm_runtime_set_active(&pdev->dev);
331                 pm_runtime_enable(&pdev->dev);
332         }
333
334         device_set_wakeup_capable(&pdev->dev, true);
335
336         return 0;
337
338 disable_device:
339         ci_hdrc_remove_device(data->ci_pdev);
340 err_clk:
341         imx_disable_unprepare_clks(&pdev->dev);
342         return ret;
343 }
344
345 static int ci_hdrc_imx_remove(struct platform_device *pdev)
346 {
347         struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
348
349         if (data->supports_runtime_pm) {
350                 pm_runtime_get_sync(&pdev->dev);
351                 pm_runtime_disable(&pdev->dev);
352                 pm_runtime_put_noidle(&pdev->dev);
353         }
354         ci_hdrc_remove_device(data->ci_pdev);
355         if (data->override_phy_control)
356                 usb_phy_shutdown(data->phy);
357         imx_disable_unprepare_clks(&pdev->dev);
358
359         return 0;
360 }
361
362 static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
363 {
364         ci_hdrc_imx_remove(pdev);
365 }
366
367 #ifdef CONFIG_PM
368 static int imx_controller_suspend(struct device *dev)
369 {
370         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
371
372         dev_dbg(dev, "at %s\n", __func__);
373
374         imx_disable_unprepare_clks(dev);
375         data->in_lpm = true;
376
377         return 0;
378 }
379
380 static int imx_controller_resume(struct device *dev)
381 {
382         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
383         int ret = 0;
384
385         dev_dbg(dev, "at %s\n", __func__);
386
387         if (!data->in_lpm) {
388                 WARN_ON(1);
389                 return 0;
390         }
391
392         ret = imx_prepare_enable_clks(dev);
393         if (ret)
394                 return ret;
395
396         data->in_lpm = false;
397
398         ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
399         if (ret) {
400                 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
401                 goto clk_disable;
402         }
403
404         return 0;
405
406 clk_disable:
407         imx_disable_unprepare_clks(dev);
408         return ret;
409 }
410
411 #ifdef CONFIG_PM_SLEEP
412 static int ci_hdrc_imx_suspend(struct device *dev)
413 {
414         int ret;
415
416         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
417
418         if (data->in_lpm)
419                 /* The core's suspend doesn't run */
420                 return 0;
421
422         if (device_may_wakeup(dev)) {
423                 ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
424                 if (ret) {
425                         dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
426                                         ret);
427                         return ret;
428                 }
429         }
430
431         return imx_controller_suspend(dev);
432 }
433
434 static int ci_hdrc_imx_resume(struct device *dev)
435 {
436         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
437         int ret;
438
439         ret = imx_controller_resume(dev);
440         if (!ret && data->supports_runtime_pm) {
441                 pm_runtime_disable(dev);
442                 pm_runtime_set_active(dev);
443                 pm_runtime_enable(dev);
444         }
445
446         return ret;
447 }
448 #endif /* CONFIG_PM_SLEEP */
449
450 static int ci_hdrc_imx_runtime_suspend(struct device *dev)
451 {
452         struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
453         int ret;
454
455         if (data->in_lpm) {
456                 WARN_ON(1);
457                 return 0;
458         }
459
460         ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
461         if (ret) {
462                 dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
463                 return ret;
464         }
465
466         return imx_controller_suspend(dev);
467 }
468
469 static int ci_hdrc_imx_runtime_resume(struct device *dev)
470 {
471         return imx_controller_resume(dev);
472 }
473
474 #endif /* CONFIG_PM */
475
476 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
477         SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
478         SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
479                         ci_hdrc_imx_runtime_resume, NULL)
480 };
481 static struct platform_driver ci_hdrc_imx_driver = {
482         .probe = ci_hdrc_imx_probe,
483         .remove = ci_hdrc_imx_remove,
484         .shutdown = ci_hdrc_imx_shutdown,
485         .driver = {
486                 .name = "imx_usb",
487                 .of_match_table = ci_hdrc_imx_dt_ids,
488                 .pm = &ci_hdrc_imx_pm_ops,
489          },
490 };
491
492 module_platform_driver(ci_hdrc_imx_driver);
493
494 MODULE_ALIAS("platform:imx-usb");
495 MODULE_LICENSE("GPL v2");
496 MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
497 MODULE_AUTHOR("Marek Vasut <[email protected]>");
498 MODULE_AUTHOR("Richard Zhao <[email protected]>");
This page took 0.066253 seconds and 4 git commands to generate.