Commit | Line | Data |
---|---|---|
e47c5a09 PG |
1 | /* |
2 | * ST EHCI driver | |
3 | * | |
4 | * Copyright (C) 2014 STMicroelectronics – All Rights Reserved | |
5 | * | |
6 | * Author: Peter Griffin <peter.griffin@linaro.org> | |
7 | * | |
8 | * Derived from ehci-platform.c | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | ||
15 | #include <linux/clk.h> | |
16 | #include <linux/dma-mapping.h> | |
17 | #include <linux/err.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <linux/hrtimer.h> | |
20 | #include <linux/io.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/of.h> | |
23 | #include <linux/phy/phy.h> | |
24 | #include <linux/platform_device.h> | |
25 | #include <linux/reset.h> | |
26 | #include <linux/usb.h> | |
27 | #include <linux/usb/hcd.h> | |
28 | #include <linux/usb/ehci_pdriver.h> | |
29 | ||
30 | #include "ehci.h" | |
31 | ||
32 | #define USB_MAX_CLKS 3 | |
33 | ||
34 | struct st_ehci_platform_priv { | |
35 | struct clk *clks[USB_MAX_CLKS]; | |
36 | struct clk *clk48; | |
37 | struct reset_control *rst; | |
38 | struct reset_control *pwr; | |
39 | struct phy *phy; | |
40 | }; | |
41 | ||
42 | #define DRIVER_DESC "EHCI STMicroelectronics driver" | |
43 | ||
44 | #define hcd_to_ehci_priv(h) \ | |
45 | ((struct st_ehci_platform_priv *)hcd_to_ehci(h)->priv) | |
46 | ||
47 | static const char hcd_name[] = "ehci-st"; | |
48 | ||
49 | #define EHCI_CAPS_SIZE 0x10 | |
50 | #define AHB2STBUS_INSREG01 (EHCI_CAPS_SIZE + 0x84) | |
51 | ||
52 | static int st_ehci_platform_reset(struct usb_hcd *hcd) | |
53 | { | |
54 | struct platform_device *pdev = to_platform_device(hcd->self.controller); | |
55 | struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); | |
56 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | |
e47c5a09 PG |
57 | u32 threshold; |
58 | ||
59 | /* Set EHCI packet buffer IN/OUT threshold to 128 bytes */ | |
60 | threshold = 128 | (128 << 16); | |
61 | writel(threshold, hcd->regs + AHB2STBUS_INSREG01); | |
62 | ||
63 | ehci->caps = hcd->regs + pdata->caps_offset; | |
16f9c3fd | 64 | return ehci_setup(hcd); |
e47c5a09 PG |
65 | } |
66 | ||
67 | static int st_ehci_platform_power_on(struct platform_device *dev) | |
68 | { | |
69 | struct usb_hcd *hcd = platform_get_drvdata(dev); | |
70 | struct st_ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); | |
71 | int clk, ret; | |
72 | ||
73 | ret = reset_control_deassert(priv->pwr); | |
74 | if (ret) | |
75 | return ret; | |
76 | ||
77 | ret = reset_control_deassert(priv->rst); | |
78 | if (ret) | |
79 | goto err_assert_power; | |
80 | ||
81 | /* some SoCs don't have a dedicated 48Mhz clock, but those that do | |
82 | need the rate to be explicitly set */ | |
83 | if (priv->clk48) { | |
84 | ret = clk_set_rate(priv->clk48, 48000000); | |
85 | if (ret) | |
86 | goto err_assert_reset; | |
87 | } | |
88 | ||
89 | for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++) { | |
90 | ret = clk_prepare_enable(priv->clks[clk]); | |
91 | if (ret) | |
92 | goto err_disable_clks; | |
93 | } | |
94 | ||
95 | ret = phy_init(priv->phy); | |
96 | if (ret) | |
97 | goto err_disable_clks; | |
98 | ||
99 | ret = phy_power_on(priv->phy); | |
100 | if (ret) | |
101 | goto err_exit_phy; | |
102 | ||
103 | return 0; | |
104 | ||
105 | err_exit_phy: | |
106 | phy_exit(priv->phy); | |
107 | err_disable_clks: | |
108 | while (--clk >= 0) | |
109 | clk_disable_unprepare(priv->clks[clk]); | |
110 | err_assert_reset: | |
111 | reset_control_assert(priv->rst); | |
112 | err_assert_power: | |
113 | reset_control_assert(priv->pwr); | |
114 | ||
115 | return ret; | |
116 | } | |
117 | ||
118 | static void st_ehci_platform_power_off(struct platform_device *dev) | |
119 | { | |
120 | struct usb_hcd *hcd = platform_get_drvdata(dev); | |
121 | struct st_ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); | |
122 | int clk; | |
123 | ||
124 | reset_control_assert(priv->pwr); | |
125 | ||
126 | reset_control_assert(priv->rst); | |
127 | ||
128 | phy_power_off(priv->phy); | |
129 | ||
130 | phy_exit(priv->phy); | |
131 | ||
132 | for (clk = USB_MAX_CLKS - 1; clk >= 0; clk--) | |
133 | if (priv->clks[clk]) | |
134 | clk_disable_unprepare(priv->clks[clk]); | |
135 | ||
136 | } | |
137 | ||
138 | static struct hc_driver __read_mostly ehci_platform_hc_driver; | |
139 | ||
140 | static const struct ehci_driver_overrides platform_overrides __initconst = { | |
141 | .reset = st_ehci_platform_reset, | |
142 | .extra_priv_size = sizeof(struct st_ehci_platform_priv), | |
143 | }; | |
144 | ||
145 | static struct usb_ehci_pdata ehci_platform_defaults = { | |
146 | .power_on = st_ehci_platform_power_on, | |
147 | .power_suspend = st_ehci_platform_power_off, | |
148 | .power_off = st_ehci_platform_power_off, | |
149 | }; | |
150 | ||
151 | static int st_ehci_platform_probe(struct platform_device *dev) | |
152 | { | |
153 | struct usb_hcd *hcd; | |
154 | struct resource *res_mem; | |
155 | struct usb_ehci_pdata *pdata = &ehci_platform_defaults; | |
156 | struct st_ehci_platform_priv *priv; | |
157 | struct ehci_hcd *ehci; | |
158 | int err, irq, clk = 0; | |
159 | ||
160 | if (usb_disabled()) | |
161 | return -ENODEV; | |
162 | ||
163 | irq = platform_get_irq(dev, 0); | |
164 | if (irq < 0) { | |
165 | dev_err(&dev->dev, "no irq provided"); | |
166 | return irq; | |
167 | } | |
168 | res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); | |
169 | if (!res_mem) { | |
170 | dev_err(&dev->dev, "no memory resource provided"); | |
171 | return -ENXIO; | |
172 | } | |
173 | ||
174 | hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, | |
175 | dev_name(&dev->dev)); | |
176 | if (!hcd) | |
177 | return -ENOMEM; | |
178 | ||
179 | platform_set_drvdata(dev, hcd); | |
180 | dev->dev.platform_data = pdata; | |
181 | priv = hcd_to_ehci_priv(hcd); | |
182 | ehci = hcd_to_ehci(hcd); | |
183 | ||
184 | priv->phy = devm_phy_get(&dev->dev, "usb"); | |
185 | if (IS_ERR(priv->phy)) { | |
186 | err = PTR_ERR(priv->phy); | |
187 | goto err_put_hcd; | |
188 | } | |
189 | ||
190 | for (clk = 0; clk < USB_MAX_CLKS; clk++) { | |
191 | priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); | |
192 | if (IS_ERR(priv->clks[clk])) { | |
193 | err = PTR_ERR(priv->clks[clk]); | |
194 | if (err == -EPROBE_DEFER) | |
195 | goto err_put_clks; | |
196 | priv->clks[clk] = NULL; | |
197 | break; | |
198 | } | |
199 | } | |
200 | ||
201 | /* some SoCs don't have a dedicated 48Mhz clock, but those that | |
202 | do need the rate to be explicitly set */ | |
203 | priv->clk48 = devm_clk_get(&dev->dev, "clk48"); | |
204 | if (IS_ERR(priv->clk48)) { | |
205 | dev_info(&dev->dev, "48MHz clk not found\n"); | |
206 | priv->clk48 = NULL; | |
207 | } | |
208 | ||
209 | priv->pwr = devm_reset_control_get_optional(&dev->dev, "power"); | |
210 | if (IS_ERR(priv->pwr)) { | |
211 | err = PTR_ERR(priv->pwr); | |
212 | if (err == -EPROBE_DEFER) | |
213 | goto err_put_clks; | |
214 | priv->pwr = NULL; | |
215 | } | |
216 | ||
217 | priv->rst = devm_reset_control_get_optional(&dev->dev, "softreset"); | |
218 | if (IS_ERR(priv->rst)) { | |
219 | err = PTR_ERR(priv->rst); | |
220 | if (err == -EPROBE_DEFER) | |
221 | goto err_put_clks; | |
222 | priv->rst = NULL; | |
223 | } | |
224 | ||
225 | if (pdata->power_on) { | |
226 | err = pdata->power_on(dev); | |
227 | if (err < 0) | |
228 | goto err_put_clks; | |
229 | } | |
230 | ||
231 | hcd->rsrc_start = res_mem->start; | |
232 | hcd->rsrc_len = resource_size(res_mem); | |
233 | ||
234 | hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); | |
235 | if (IS_ERR(hcd->regs)) { | |
236 | err = PTR_ERR(hcd->regs); | |
237 | goto err_put_clks; | |
238 | } | |
239 | ||
240 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); | |
241 | if (err) | |
242 | goto err_put_clks; | |
243 | ||
244 | device_wakeup_enable(hcd->self.controller); | |
245 | platform_set_drvdata(dev, hcd); | |
246 | ||
247 | return err; | |
248 | ||
249 | err_put_clks: | |
250 | while (--clk >= 0) | |
251 | clk_put(priv->clks[clk]); | |
252 | err_put_hcd: | |
253 | if (pdata == &ehci_platform_defaults) | |
254 | dev->dev.platform_data = NULL; | |
255 | ||
256 | usb_put_hcd(hcd); | |
257 | ||
258 | return err; | |
259 | } | |
260 | ||
261 | static int st_ehci_platform_remove(struct platform_device *dev) | |
262 | { | |
263 | struct usb_hcd *hcd = platform_get_drvdata(dev); | |
264 | struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); | |
265 | struct st_ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); | |
266 | int clk; | |
267 | ||
268 | usb_remove_hcd(hcd); | |
269 | ||
270 | if (pdata->power_off) | |
271 | pdata->power_off(dev); | |
272 | ||
273 | for (clk = 0; clk < USB_MAX_CLKS && priv->clks[clk]; clk++) | |
274 | clk_put(priv->clks[clk]); | |
275 | ||
276 | usb_put_hcd(hcd); | |
277 | ||
278 | if (pdata == &ehci_platform_defaults) | |
279 | dev->dev.platform_data = NULL; | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
284 | #ifdef CONFIG_PM_SLEEP | |
285 | ||
286 | static int st_ehci_suspend(struct device *dev) | |
287 | { | |
288 | struct usb_hcd *hcd = dev_get_drvdata(dev); | |
289 | struct usb_ehci_pdata *pdata = dev_get_platdata(dev); | |
290 | struct platform_device *pdev = | |
291 | container_of(dev, struct platform_device, dev); | |
292 | bool do_wakeup = device_may_wakeup(dev); | |
293 | int ret; | |
294 | ||
295 | ret = ehci_suspend(hcd, do_wakeup); | |
296 | if (ret) | |
297 | return ret; | |
298 | ||
299 | if (pdata->power_suspend) | |
300 | pdata->power_suspend(pdev); | |
301 | ||
302 | pinctrl_pm_select_sleep_state(dev); | |
303 | ||
304 | return ret; | |
305 | } | |
306 | ||
307 | static int st_ehci_resume(struct device *dev) | |
308 | { | |
309 | struct usb_hcd *hcd = dev_get_drvdata(dev); | |
310 | struct usb_ehci_pdata *pdata = dev_get_platdata(dev); | |
311 | struct platform_device *pdev = | |
312 | container_of(dev, struct platform_device, dev); | |
313 | int err; | |
314 | ||
315 | pinctrl_pm_select_default_state(dev); | |
316 | ||
317 | if (pdata->power_on) { | |
318 | err = pdata->power_on(pdev); | |
319 | if (err < 0) | |
320 | return err; | |
321 | } | |
322 | ||
323 | ehci_resume(hcd, false); | |
324 | return 0; | |
325 | } | |
326 | ||
327 | static SIMPLE_DEV_PM_OPS(st_ehci_pm_ops, st_ehci_suspend, st_ehci_resume); | |
328 | ||
329 | #endif /* CONFIG_PM_SLEEP */ | |
330 | ||
331 | static const struct of_device_id st_ehci_ids[] = { | |
332 | { .compatible = "st,st-ehci-300x", }, | |
333 | { /* sentinel */ } | |
334 | }; | |
335 | MODULE_DEVICE_TABLE(of, st_ehci_ids); | |
336 | ||
337 | static struct platform_driver ehci_platform_driver = { | |
338 | .probe = st_ehci_platform_probe, | |
339 | .remove = st_ehci_platform_remove, | |
340 | .shutdown = usb_hcd_platform_shutdown, | |
341 | .driver = { | |
342 | .name = "st-ehci", | |
343 | #ifdef CONFIG_PM_SLEEP | |
344 | .pm = &st_ehci_pm_ops, | |
345 | #endif | |
346 | .of_match_table = st_ehci_ids, | |
347 | } | |
348 | }; | |
349 | ||
350 | static int __init ehci_platform_init(void) | |
351 | { | |
352 | if (usb_disabled()) | |
353 | return -ENODEV; | |
354 | ||
355 | pr_info("%s: " DRIVER_DESC "\n", hcd_name); | |
356 | ||
357 | ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); | |
358 | return platform_driver_register(&ehci_platform_driver); | |
359 | } | |
360 | module_init(ehci_platform_init); | |
361 | ||
362 | static void __exit ehci_platform_cleanup(void) | |
363 | { | |
364 | platform_driver_unregister(&ehci_platform_driver); | |
365 | } | |
366 | module_exit(ehci_platform_cleanup); | |
367 | ||
368 | MODULE_DESCRIPTION(DRIVER_DESC); | |
369 | MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); | |
370 | MODULE_LICENSE("GPL"); |