1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * OHCI HCD (Host Controller Driver) for USB. |
4 | * |
5 | * TI DA8xx (OMAP-L1x) Bus Glue |
6 | * |
7 | * Derived from: ohci-omap.c and ohci-s3c2410.c |
8 | * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com> |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/gpio/consumer.h> |
13 | #include <linux/io.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/jiffies.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/phy/phy.h> |
21 | #include <linux/platform_data/usb-davinci.h> |
22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/usb.h> |
24 | #include <linux/usb/hcd.h> |
25 | #include <asm/unaligned.h> |
26 | |
27 | #include "ohci.h" |
28 | |
29 | #define DRIVER_DESC "DA8XX" |
30 | #define DRV_NAME "ohci-da8xx" |
31 | |
32 | static struct hc_driver __read_mostly ohci_da8xx_hc_driver; |
33 | |
34 | static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq, |
35 | u16 wValue, u16 wIndex, char *buf, u16 wLength); |
36 | static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf); |
37 | |
38 | struct da8xx_ohci_hcd { |
39 | struct usb_hcd *hcd; |
40 | struct clk *usb11_clk; |
41 | struct phy *usb11_phy; |
42 | struct regulator *vbus_reg; |
43 | struct notifier_block nb; |
44 | struct gpio_desc *oc_gpio; |
45 | }; |
46 | |
47 | #define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv) |
48 | |
49 | /* Over-current indicator change bitmask */ |
50 | static volatile u16 ocic_mask; |
51 | |
52 | static int ohci_da8xx_enable(struct usb_hcd *hcd) |
53 | { |
54 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
55 | int ret; |
56 | |
57 | ret = clk_prepare_enable(clk: da8xx_ohci->usb11_clk); |
58 | if (ret) |
59 | return ret; |
60 | |
61 | ret = phy_init(phy: da8xx_ohci->usb11_phy); |
62 | if (ret) |
63 | goto err_phy_init; |
64 | |
65 | ret = phy_power_on(phy: da8xx_ohci->usb11_phy); |
66 | if (ret) |
67 | goto err_phy_power_on; |
68 | |
69 | return 0; |
70 | |
71 | err_phy_power_on: |
72 | phy_exit(phy: da8xx_ohci->usb11_phy); |
73 | err_phy_init: |
74 | clk_disable_unprepare(clk: da8xx_ohci->usb11_clk); |
75 | |
76 | return ret; |
77 | } |
78 | |
79 | static void ohci_da8xx_disable(struct usb_hcd *hcd) |
80 | { |
81 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
82 | |
83 | phy_power_off(phy: da8xx_ohci->usb11_phy); |
84 | phy_exit(phy: da8xx_ohci->usb11_phy); |
85 | clk_disable_unprepare(clk: da8xx_ohci->usb11_clk); |
86 | } |
87 | |
88 | static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) |
89 | { |
90 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
91 | struct device *dev = hcd->self.controller; |
92 | int ret; |
93 | |
94 | if (!da8xx_ohci->vbus_reg) |
95 | return 0; |
96 | |
97 | if (on) { |
98 | ret = regulator_enable(regulator: da8xx_ohci->vbus_reg); |
99 | if (ret) { |
100 | dev_err(dev, "Failed to enable regulator: %d\n" , ret); |
101 | return ret; |
102 | } |
103 | } else { |
104 | ret = regulator_disable(regulator: da8xx_ohci->vbus_reg); |
105 | if (ret) { |
106 | dev_err(dev, "Failed to disable regulator: %d\n" , ret); |
107 | return ret; |
108 | } |
109 | } |
110 | |
111 | return 0; |
112 | } |
113 | |
114 | static int ohci_da8xx_get_power(struct usb_hcd *hcd) |
115 | { |
116 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
117 | |
118 | if (da8xx_ohci->vbus_reg) |
119 | return regulator_is_enabled(regulator: da8xx_ohci->vbus_reg); |
120 | |
121 | return 1; |
122 | } |
123 | |
124 | static int ohci_da8xx_get_oci(struct usb_hcd *hcd) |
125 | { |
126 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
127 | unsigned int flags; |
128 | int ret; |
129 | |
130 | if (da8xx_ohci->oc_gpio) |
131 | return gpiod_get_value_cansleep(desc: da8xx_ohci->oc_gpio); |
132 | |
133 | if (!da8xx_ohci->vbus_reg) |
134 | return 0; |
135 | |
136 | ret = regulator_get_error_flags(regulator: da8xx_ohci->vbus_reg, flags: &flags); |
137 | if (ret) |
138 | return ret; |
139 | |
140 | if (flags & REGULATOR_ERROR_OVER_CURRENT) |
141 | return 1; |
142 | |
143 | return 0; |
144 | } |
145 | |
146 | static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) |
147 | { |
148 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
149 | |
150 | if (da8xx_ohci->vbus_reg) |
151 | return 1; |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | static int ohci_da8xx_has_oci(struct usb_hcd *hcd) |
157 | { |
158 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
159 | |
160 | if (da8xx_ohci->oc_gpio) |
161 | return 1; |
162 | |
163 | if (da8xx_ohci->vbus_reg) |
164 | return 1; |
165 | |
166 | return 0; |
167 | } |
168 | |
169 | static int ohci_da8xx_has_potpgt(struct usb_hcd *hcd) |
170 | { |
171 | struct device *dev = hcd->self.controller; |
172 | struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
173 | |
174 | if (hub && hub->potpgt) |
175 | return 1; |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | static int ohci_da8xx_regulator_event(struct notifier_block *nb, |
181 | unsigned long event, void *data) |
182 | { |
183 | struct da8xx_ohci_hcd *da8xx_ohci = |
184 | container_of(nb, struct da8xx_ohci_hcd, nb); |
185 | |
186 | if (event & REGULATOR_EVENT_OVER_CURRENT) { |
187 | ocic_mask |= 1 << 1; |
188 | ohci_da8xx_set_power(hcd: da8xx_ohci->hcd, on: 0); |
189 | } |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | static irqreturn_t ohci_da8xx_oc_thread(int irq, void *data) |
195 | { |
196 | struct da8xx_ohci_hcd *da8xx_ohci = data; |
197 | struct device *dev = da8xx_ohci->hcd->self.controller; |
198 | int ret; |
199 | |
200 | if (gpiod_get_value_cansleep(desc: da8xx_ohci->oc_gpio) && |
201 | da8xx_ohci->vbus_reg) { |
202 | ret = regulator_disable(regulator: da8xx_ohci->vbus_reg); |
203 | if (ret) |
204 | dev_err(dev, "Failed to disable regulator: %d\n" , ret); |
205 | } |
206 | |
207 | return IRQ_HANDLED; |
208 | } |
209 | |
210 | static int ohci_da8xx_register_notify(struct usb_hcd *hcd) |
211 | { |
212 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
213 | struct device *dev = hcd->self.controller; |
214 | int ret = 0; |
215 | |
216 | if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) { |
217 | da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event; |
218 | ret = devm_regulator_register_notifier(regulator: da8xx_ohci->vbus_reg, |
219 | nb: &da8xx_ohci->nb); |
220 | } |
221 | |
222 | if (ret) |
223 | dev_err(dev, "Failed to register notifier: %d\n" , ret); |
224 | |
225 | return ret; |
226 | } |
227 | |
228 | static int ohci_da8xx_reset(struct usb_hcd *hcd) |
229 | { |
230 | struct device *dev = hcd->self.controller; |
231 | struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
232 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
233 | int result; |
234 | u32 rh_a; |
235 | |
236 | dev_dbg(dev, "starting USB controller\n" ); |
237 | |
238 | result = ohci_da8xx_enable(hcd); |
239 | if (result < 0) |
240 | return result; |
241 | |
242 | /* |
243 | * DA8xx only have 1 port connected to the pins but the HC root hub |
244 | * register A reports 2 ports, thus we'll have to override it... |
245 | */ |
246 | ohci->num_ports = 1; |
247 | |
248 | result = ohci_setup(hcd); |
249 | if (result < 0) { |
250 | ohci_da8xx_disable(hcd); |
251 | return result; |
252 | } |
253 | |
254 | /* |
255 | * Since we're providing a board-specific root hub port power control |
256 | * and over-current reporting, we have to override the HC root hub A |
257 | * register's default value, so that ohci_hub_control() could return |
258 | * the correct hub descriptor... |
259 | */ |
260 | rh_a = ohci_readl(ohci, &ohci->regs->roothub.a); |
261 | if (ohci_da8xx_has_set_power(hcd)) { |
262 | rh_a &= ~RH_A_NPS; |
263 | rh_a |= RH_A_PSM; |
264 | } |
265 | if (ohci_da8xx_has_oci(hcd)) { |
266 | rh_a &= ~RH_A_NOCP; |
267 | rh_a |= RH_A_OCPM; |
268 | } |
269 | if (ohci_da8xx_has_potpgt(hcd)) { |
270 | rh_a &= ~RH_A_POTPGT; |
271 | rh_a |= hub->potpgt << 24; |
272 | } |
273 | ohci_writel(ohci, rh_a, &ohci->regs->roothub.a); |
274 | |
275 | return result; |
276 | } |
277 | |
278 | /* |
279 | * Update the status data from the hub with the over-current indicator change. |
280 | */ |
281 | static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf) |
282 | { |
283 | int length = orig_ohci_hub_status_data(hcd, buf); |
284 | |
285 | /* See if we have OCIC bit set on port 1 */ |
286 | if (ocic_mask & (1 << 1)) { |
287 | dev_dbg(hcd->self.controller, "over-current indicator change " |
288 | "on port 1\n" ); |
289 | |
290 | if (!length) |
291 | length = 1; |
292 | |
293 | buf[0] |= 1 << 1; |
294 | } |
295 | return length; |
296 | } |
297 | |
298 | /* |
299 | * Look at the control requests to the root hub and see if we need to override. |
300 | */ |
301 | static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, |
302 | u16 wIndex, char *buf, u16 wLength) |
303 | { |
304 | struct device *dev = hcd->self.controller; |
305 | int temp; |
306 | |
307 | switch (typeReq) { |
308 | case GetPortStatus: |
309 | /* Check the port number */ |
310 | if (wIndex != 1) |
311 | break; |
312 | |
313 | dev_dbg(dev, "GetPortStatus(%u)\n" , wIndex); |
314 | |
315 | temp = roothub_portstatus(hc: hcd_to_ohci(hcd), i: wIndex - 1); |
316 | |
317 | /* The port power status (PPS) bit defaults to 1 */ |
318 | if (!ohci_da8xx_get_power(hcd)) |
319 | temp &= ~RH_PS_PPS; |
320 | |
321 | /* The port over-current indicator (POCI) bit is always 0 */ |
322 | if (ohci_da8xx_get_oci(hcd) > 0) |
323 | temp |= RH_PS_POCI; |
324 | |
325 | /* The over-current indicator change (OCIC) bit is 0 too */ |
326 | if (ocic_mask & (1 << wIndex)) |
327 | temp |= RH_PS_OCIC; |
328 | |
329 | put_unaligned(cpu_to_le32(temp), (__le32 *)buf); |
330 | return 0; |
331 | case SetPortFeature: |
332 | temp = 1; |
333 | goto check_port; |
334 | case ClearPortFeature: |
335 | temp = 0; |
336 | |
337 | check_port: |
338 | /* Check the port number */ |
339 | if (wIndex != 1) |
340 | break; |
341 | |
342 | switch (wValue) { |
343 | case USB_PORT_FEAT_POWER: |
344 | dev_dbg(dev, "%sPortFeature(%u): %s\n" , |
345 | temp ? "Set" : "Clear" , wIndex, "POWER" ); |
346 | |
347 | return ohci_da8xx_set_power(hcd, on: temp) ? -EPIPE : 0; |
348 | case USB_PORT_FEAT_C_OVER_CURRENT: |
349 | dev_dbg(dev, "%sPortFeature(%u): %s\n" , |
350 | temp ? "Set" : "Clear" , wIndex, |
351 | "C_OVER_CURRENT" ); |
352 | |
353 | if (temp) |
354 | ocic_mask |= 1 << wIndex; |
355 | else |
356 | ocic_mask &= ~(1 << wIndex); |
357 | return 0; |
358 | } |
359 | } |
360 | |
361 | return orig_ohci_hub_control(hcd, typeReq, wValue, |
362 | wIndex, buf, wLength); |
363 | } |
364 | |
365 | /*-------------------------------------------------------------------------*/ |
366 | #ifdef CONFIG_OF |
367 | static const struct of_device_id da8xx_ohci_ids[] = { |
368 | { .compatible = "ti,da830-ohci" }, |
369 | { } |
370 | }; |
371 | MODULE_DEVICE_TABLE(of, da8xx_ohci_ids); |
372 | #endif |
373 | |
374 | static int ohci_da8xx_probe(struct platform_device *pdev) |
375 | { |
376 | struct da8xx_ohci_hcd *da8xx_ohci; |
377 | struct device *dev = &pdev->dev; |
378 | int error, hcd_irq, oc_irq; |
379 | struct usb_hcd *hcd; |
380 | struct resource *mem; |
381 | |
382 | hcd = usb_create_hcd(driver: &ohci_da8xx_hc_driver, dev, bus_name: dev_name(dev)); |
383 | if (!hcd) |
384 | return -ENOMEM; |
385 | |
386 | da8xx_ohci = to_da8xx_ohci(hcd); |
387 | da8xx_ohci->hcd = hcd; |
388 | |
389 | da8xx_ohci->usb11_clk = devm_clk_get(dev, NULL); |
390 | if (IS_ERR(ptr: da8xx_ohci->usb11_clk)) { |
391 | error = PTR_ERR(ptr: da8xx_ohci->usb11_clk); |
392 | if (error != -EPROBE_DEFER) |
393 | dev_err(dev, "Failed to get clock.\n" ); |
394 | goto err; |
395 | } |
396 | |
397 | da8xx_ohci->usb11_phy = devm_phy_get(dev, string: "usb-phy" ); |
398 | if (IS_ERR(ptr: da8xx_ohci->usb11_phy)) { |
399 | error = PTR_ERR(ptr: da8xx_ohci->usb11_phy); |
400 | if (error != -EPROBE_DEFER) |
401 | dev_err(dev, "Failed to get phy.\n" ); |
402 | goto err; |
403 | } |
404 | |
405 | da8xx_ohci->vbus_reg = devm_regulator_get_optional(dev, id: "vbus" ); |
406 | if (IS_ERR(ptr: da8xx_ohci->vbus_reg)) { |
407 | error = PTR_ERR(ptr: da8xx_ohci->vbus_reg); |
408 | if (error == -ENODEV) { |
409 | da8xx_ohci->vbus_reg = NULL; |
410 | } else if (error == -EPROBE_DEFER) { |
411 | goto err; |
412 | } else { |
413 | dev_err(dev, "Failed to get regulator\n" ); |
414 | goto err; |
415 | } |
416 | } |
417 | |
418 | da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, con_id: "oc" , flags: GPIOD_IN); |
419 | if (IS_ERR(ptr: da8xx_ohci->oc_gpio)) { |
420 | error = PTR_ERR(ptr: da8xx_ohci->oc_gpio); |
421 | goto err; |
422 | } |
423 | |
424 | if (da8xx_ohci->oc_gpio) { |
425 | oc_irq = gpiod_to_irq(desc: da8xx_ohci->oc_gpio); |
426 | if (oc_irq < 0) { |
427 | error = oc_irq; |
428 | goto err; |
429 | } |
430 | |
431 | error = devm_request_threaded_irq(dev, irq: oc_irq, NULL, |
432 | thread_fn: ohci_da8xx_oc_thread, IRQF_TRIGGER_RISING | |
433 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
434 | devname: "OHCI over-current indicator" , dev_id: da8xx_ohci); |
435 | if (error) |
436 | goto err; |
437 | } |
438 | |
439 | hcd->regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &mem); |
440 | if (IS_ERR(ptr: hcd->regs)) { |
441 | error = PTR_ERR(ptr: hcd->regs); |
442 | goto err; |
443 | } |
444 | hcd->rsrc_start = mem->start; |
445 | hcd->rsrc_len = resource_size(res: mem); |
446 | |
447 | hcd_irq = platform_get_irq(pdev, 0); |
448 | if (hcd_irq < 0) { |
449 | error = -ENODEV; |
450 | goto err; |
451 | } |
452 | |
453 | error = usb_add_hcd(hcd, irqnum: hcd_irq, irqflags: 0); |
454 | if (error) |
455 | goto err; |
456 | |
457 | device_wakeup_enable(dev: hcd->self.controller); |
458 | |
459 | error = ohci_da8xx_register_notify(hcd); |
460 | if (error) |
461 | goto err_remove_hcd; |
462 | |
463 | return 0; |
464 | |
465 | err_remove_hcd: |
466 | usb_remove_hcd(hcd); |
467 | err: |
468 | usb_put_hcd(hcd); |
469 | return error; |
470 | } |
471 | |
472 | static void ohci_da8xx_remove(struct platform_device *pdev) |
473 | { |
474 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
475 | |
476 | usb_remove_hcd(hcd); |
477 | usb_put_hcd(hcd); |
478 | } |
479 | |
480 | #ifdef CONFIG_PM |
481 | static int ohci_da8xx_suspend(struct platform_device *pdev, |
482 | pm_message_t message) |
483 | { |
484 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
485 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
486 | bool do_wakeup = device_may_wakeup(dev: &pdev->dev); |
487 | int ret; |
488 | |
489 | |
490 | if (time_before(jiffies, ohci->next_statechange)) |
491 | msleep(msecs: 5); |
492 | ohci->next_statechange = jiffies; |
493 | |
494 | ret = ohci_suspend(hcd, do_wakeup); |
495 | if (ret) |
496 | return ret; |
497 | |
498 | ohci_da8xx_disable(hcd); |
499 | hcd->state = HC_STATE_SUSPENDED; |
500 | |
501 | return ret; |
502 | } |
503 | |
504 | static int ohci_da8xx_resume(struct platform_device *dev) |
505 | { |
506 | struct usb_hcd *hcd = platform_get_drvdata(pdev: dev); |
507 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
508 | int ret; |
509 | |
510 | if (time_before(jiffies, ohci->next_statechange)) |
511 | msleep(msecs: 5); |
512 | ohci->next_statechange = jiffies; |
513 | |
514 | ret = ohci_da8xx_enable(hcd); |
515 | if (ret) |
516 | return ret; |
517 | |
518 | ohci_resume(hcd, hibernated: false); |
519 | |
520 | return 0; |
521 | } |
522 | #endif |
523 | |
524 | static const struct ohci_driver_overrides da8xx_overrides __initconst = { |
525 | .reset = ohci_da8xx_reset, |
526 | .extra_priv_size = sizeof(struct da8xx_ohci_hcd), |
527 | }; |
528 | |
529 | /* |
530 | * Driver definition to register with platform structure. |
531 | */ |
532 | static struct platform_driver ohci_hcd_da8xx_driver = { |
533 | .probe = ohci_da8xx_probe, |
534 | .remove_new = ohci_da8xx_remove, |
535 | .shutdown = usb_hcd_platform_shutdown, |
536 | #ifdef CONFIG_PM |
537 | .suspend = ohci_da8xx_suspend, |
538 | .resume = ohci_da8xx_resume, |
539 | #endif |
540 | .driver = { |
541 | .name = DRV_NAME, |
542 | .of_match_table = of_match_ptr(da8xx_ohci_ids), |
543 | }, |
544 | }; |
545 | |
546 | static int __init ohci_da8xx_init(void) |
547 | { |
548 | |
549 | if (usb_disabled()) |
550 | return -ENODEV; |
551 | |
552 | ohci_init_driver(drv: &ohci_da8xx_hc_driver, over: &da8xx_overrides); |
553 | |
554 | /* |
555 | * The Davinci da8xx HW has some unusual quirks, which require |
556 | * da8xx-specific workarounds. We override certain hc_driver |
557 | * functions here to achieve that. We explicitly do not enhance |
558 | * ohci_driver_overrides to allow this more easily, since this |
559 | * is an unusual case, and we don't want to encourage others to |
560 | * override these functions by making it too easy. |
561 | */ |
562 | |
563 | orig_ohci_hub_control = ohci_da8xx_hc_driver.hub_control; |
564 | orig_ohci_hub_status_data = ohci_da8xx_hc_driver.hub_status_data; |
565 | |
566 | ohci_da8xx_hc_driver.hub_status_data = ohci_da8xx_hub_status_data; |
567 | ohci_da8xx_hc_driver.hub_control = ohci_da8xx_hub_control; |
568 | |
569 | return platform_driver_register(&ohci_hcd_da8xx_driver); |
570 | } |
571 | module_init(ohci_da8xx_init); |
572 | |
573 | static void __exit ohci_da8xx_exit(void) |
574 | { |
575 | platform_driver_unregister(&ohci_hcd_da8xx_driver); |
576 | } |
577 | module_exit(ohci_da8xx_exit); |
578 | MODULE_DESCRIPTION(DRIVER_DESC); |
579 | MODULE_LICENSE("GPL" ); |
580 | MODULE_ALIAS("platform:" DRV_NAME); |
581 | |