1 | // SPDX-License-Identifier: GPL-1.0+ |
2 | /* |
3 | * OHCI HCD (Host Controller Driver) for USB. |
4 | * |
5 | * Copyright (C) 2004 SAN People (Pty) Ltd. |
6 | * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org> |
7 | * |
8 | * AT91 Bus Glue |
9 | * |
10 | * Based on fragments of 2.4 driver by Rick Bronson. |
11 | * Based on ohci-omap.c |
12 | * |
13 | * This file is licenced under the GPL. |
14 | */ |
15 | |
16 | #include <linux/arm-smccc.h> |
17 | #include <linux/clk.h> |
18 | #include <linux/dma-mapping.h> |
19 | #include <linux/gpio/consumer.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/platform_data/atmel.h> |
22 | #include <linux/io.h> |
23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> |
25 | #include <linux/mfd/syscon.h> |
26 | #include <linux/of.h> |
27 | #include <linux/regmap.h> |
28 | #include <linux/usb.h> |
29 | #include <linux/usb/hcd.h> |
30 | #include <soc/at91/atmel-sfr.h> |
31 | |
32 | #include "ohci.h" |
33 | |
34 | #define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) |
35 | #define at91_for_each_port(index) \ |
36 | for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++) |
37 | |
38 | /* interface, function and usb clocks; sometimes also an AHB clock */ |
39 | #define hcd_to_ohci_at91_priv(h) \ |
40 | ((struct ohci_at91_priv *)hcd_to_ohci(h)->priv) |
41 | |
42 | #define AT91_MAX_USBH_PORTS 3 |
43 | struct at91_usbh_data { |
44 | struct gpio_desc *vbus_pin[AT91_MAX_USBH_PORTS]; |
45 | struct gpio_desc *overcurrent_pin[AT91_MAX_USBH_PORTS]; |
46 | u8 ports; /* number of ports on root hub */ |
47 | u8 overcurrent_supported; |
48 | u8 overcurrent_status[AT91_MAX_USBH_PORTS]; |
49 | u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; |
50 | }; |
51 | |
52 | struct ohci_at91_priv { |
53 | struct clk *iclk; |
54 | struct clk *fclk; |
55 | struct clk *hclk; |
56 | bool clocked; |
57 | bool wakeup; /* Saved wake-up state for resume */ |
58 | struct regmap *sfr_regmap; |
59 | u32 suspend_smc_id; |
60 | }; |
61 | /* interface and function clocks; sometimes also an AHB clock */ |
62 | |
63 | #define DRIVER_DESC "OHCI Atmel driver" |
64 | |
65 | static struct hc_driver __read_mostly ohci_at91_hc_driver; |
66 | |
67 | static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst = { |
68 | .extra_priv_size = sizeof(struct ohci_at91_priv), |
69 | }; |
70 | |
71 | /*-------------------------------------------------------------------------*/ |
72 | |
73 | static void at91_start_clock(struct ohci_at91_priv *ohci_at91) |
74 | { |
75 | if (ohci_at91->clocked) |
76 | return; |
77 | |
78 | clk_set_rate(clk: ohci_at91->fclk, rate: 48000000); |
79 | clk_prepare_enable(clk: ohci_at91->hclk); |
80 | clk_prepare_enable(clk: ohci_at91->iclk); |
81 | clk_prepare_enable(clk: ohci_at91->fclk); |
82 | ohci_at91->clocked = true; |
83 | } |
84 | |
85 | static void at91_stop_clock(struct ohci_at91_priv *ohci_at91) |
86 | { |
87 | if (!ohci_at91->clocked) |
88 | return; |
89 | |
90 | clk_disable_unprepare(clk: ohci_at91->fclk); |
91 | clk_disable_unprepare(clk: ohci_at91->iclk); |
92 | clk_disable_unprepare(clk: ohci_at91->hclk); |
93 | ohci_at91->clocked = false; |
94 | } |
95 | |
96 | static void at91_start_hc(struct platform_device *pdev) |
97 | { |
98 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
99 | struct ohci_regs __iomem *regs = hcd->regs; |
100 | struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); |
101 | |
102 | dev_dbg(&pdev->dev, "start\n" ); |
103 | |
104 | /* |
105 | * Start the USB clocks. |
106 | */ |
107 | at91_start_clock(ohci_at91); |
108 | |
109 | /* |
110 | * The USB host controller must remain in reset. |
111 | */ |
112 | writel(val: 0, addr: ®s->control); |
113 | } |
114 | |
115 | static void at91_stop_hc(struct platform_device *pdev) |
116 | { |
117 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
118 | struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); |
119 | |
120 | dev_dbg(&pdev->dev, "stop\n" ); |
121 | |
122 | /* |
123 | * Put the USB host controller into reset. |
124 | */ |
125 | usb_hcd_platform_shutdown(dev: pdev); |
126 | |
127 | /* |
128 | * Stop the USB clocks. |
129 | */ |
130 | at91_stop_clock(ohci_at91); |
131 | } |
132 | |
133 | |
134 | /*-------------------------------------------------------------------------*/ |
135 | |
136 | static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); |
137 | |
138 | static u32 at91_dt_suspend_smc(struct device *dev) |
139 | { |
140 | u32 suspend_smc_id; |
141 | |
142 | if (!dev->of_node) |
143 | return 0; |
144 | |
145 | if (of_property_read_u32(np: dev->of_node, propname: "microchip,suspend-smc-id" , out_value: &suspend_smc_id)) |
146 | return 0; |
147 | |
148 | return suspend_smc_id; |
149 | } |
150 | |
151 | static struct regmap *at91_dt_syscon_sfr(void) |
152 | { |
153 | struct regmap *regmap; |
154 | |
155 | regmap = syscon_regmap_lookup_by_compatible(s: "atmel,sama5d2-sfr" ); |
156 | if (IS_ERR(ptr: regmap)) { |
157 | regmap = syscon_regmap_lookup_by_compatible(s: "microchip,sam9x60-sfr" ); |
158 | if (IS_ERR(ptr: regmap)) |
159 | regmap = NULL; |
160 | } |
161 | |
162 | return regmap; |
163 | } |
164 | |
165 | /* configure so an HC device and id are always provided */ |
166 | /* always called with process context; sleeping is OK */ |
167 | |
168 | |
169 | /* |
170 | * usb_hcd_at91_probe - initialize AT91-based HCDs |
171 | * @driver: Pointer to hc driver instance |
172 | * @pdev: USB controller to probe |
173 | * |
174 | * Context: task context, might sleep |
175 | * |
176 | * Allocates basic resources for this USB host controller, and |
177 | * then invokes the start() method for the HCD associated with it |
178 | * through the hotplug entry's driver_data. |
179 | */ |
180 | static int usb_hcd_at91_probe(const struct hc_driver *driver, |
181 | struct platform_device *pdev) |
182 | { |
183 | struct at91_usbh_data *board; |
184 | struct ohci_hcd *ohci; |
185 | int retval; |
186 | struct usb_hcd *hcd; |
187 | struct ohci_at91_priv *ohci_at91; |
188 | struct device *dev = &pdev->dev; |
189 | struct resource *res; |
190 | int irq; |
191 | |
192 | irq = platform_get_irq(pdev, 0); |
193 | if (irq < 0) |
194 | return irq; |
195 | |
196 | hcd = usb_create_hcd(driver, dev, bus_name: "at91" ); |
197 | if (!hcd) |
198 | return -ENOMEM; |
199 | ohci_at91 = hcd_to_ohci_at91_priv(hcd); |
200 | |
201 | hcd->regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
202 | if (IS_ERR(ptr: hcd->regs)) { |
203 | retval = PTR_ERR(ptr: hcd->regs); |
204 | goto err; |
205 | } |
206 | hcd->rsrc_start = res->start; |
207 | hcd->rsrc_len = resource_size(res); |
208 | |
209 | ohci_at91->iclk = devm_clk_get(dev, id: "ohci_clk" ); |
210 | if (IS_ERR(ptr: ohci_at91->iclk)) { |
211 | dev_err(dev, "failed to get ohci_clk\n" ); |
212 | retval = PTR_ERR(ptr: ohci_at91->iclk); |
213 | goto err; |
214 | } |
215 | ohci_at91->fclk = devm_clk_get(dev, id: "uhpck" ); |
216 | if (IS_ERR(ptr: ohci_at91->fclk)) { |
217 | dev_err(dev, "failed to get uhpck\n" ); |
218 | retval = PTR_ERR(ptr: ohci_at91->fclk); |
219 | goto err; |
220 | } |
221 | ohci_at91->hclk = devm_clk_get(dev, id: "hclk" ); |
222 | if (IS_ERR(ptr: ohci_at91->hclk)) { |
223 | dev_err(dev, "failed to get hclk\n" ); |
224 | retval = PTR_ERR(ptr: ohci_at91->hclk); |
225 | goto err; |
226 | } |
227 | |
228 | ohci_at91->suspend_smc_id = at91_dt_suspend_smc(dev); |
229 | if (!ohci_at91->suspend_smc_id) { |
230 | dev_dbg(dev, "failed to find sfr suspend smc id, using regmap\n" ); |
231 | ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); |
232 | if (!ohci_at91->sfr_regmap) |
233 | dev_dbg(dev, "failed to find sfr node\n" ); |
234 | } |
235 | |
236 | board = hcd->self.controller->platform_data; |
237 | ohci = hcd_to_ohci(hcd); |
238 | ohci->num_ports = board->ports; |
239 | at91_start_hc(pdev); |
240 | |
241 | /* |
242 | * The RemoteWakeupConnected bit has to be set explicitly |
243 | * before calling ohci_run. The reset value of this bit is 0. |
244 | */ |
245 | ohci->hc_control = OHCI_CTRL_RWC; |
246 | |
247 | retval = usb_add_hcd(hcd, irqnum: irq, IRQF_SHARED); |
248 | if (retval == 0) { |
249 | device_wakeup_enable(dev: hcd->self.controller); |
250 | return retval; |
251 | } |
252 | |
253 | /* Error handling */ |
254 | at91_stop_hc(pdev); |
255 | |
256 | err: |
257 | usb_put_hcd(hcd); |
258 | return retval; |
259 | } |
260 | |
261 | |
262 | /* may be called with controller, bus, and devices active */ |
263 | |
264 | /* |
265 | * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs |
266 | * @hcd: USB controller to remove |
267 | * @pdev: Platform device required for cleanup |
268 | * |
269 | * Context: task context, might sleep |
270 | * |
271 | * Reverses the effect of usb_hcd_at91_probe(), first invoking |
272 | * the HCD's stop() method. It is always called from a thread |
273 | * context, "rmmod" or something similar. |
274 | */ |
275 | static void usb_hcd_at91_remove(struct usb_hcd *hcd, |
276 | struct platform_device *pdev) |
277 | { |
278 | usb_remove_hcd(hcd); |
279 | at91_stop_hc(pdev); |
280 | usb_put_hcd(hcd); |
281 | } |
282 | |
283 | /*-------------------------------------------------------------------------*/ |
284 | static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) |
285 | { |
286 | if (!valid_port(port)) |
287 | return; |
288 | |
289 | gpiod_set_value(desc: pdata->vbus_pin[port], value: enable); |
290 | } |
291 | |
292 | static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) |
293 | { |
294 | if (!valid_port(port)) |
295 | return -EINVAL; |
296 | |
297 | return gpiod_get_value(desc: pdata->vbus_pin[port]); |
298 | } |
299 | |
300 | /* |
301 | * Update the status data from the hub with the over-current indicator change. |
302 | */ |
303 | static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) |
304 | { |
305 | struct at91_usbh_data *pdata = hcd->self.controller->platform_data; |
306 | int length = ohci_hub_status_data(hcd, buf); |
307 | int port; |
308 | |
309 | at91_for_each_port(port) { |
310 | if (pdata->overcurrent_changed[port]) { |
311 | if (!length) |
312 | length = 1; |
313 | buf[0] |= 1 << (port + 1); |
314 | } |
315 | } |
316 | |
317 | return length; |
318 | } |
319 | |
320 | static int ohci_at91_port_suspend(struct ohci_at91_priv *ohci_at91, u8 set) |
321 | { |
322 | struct regmap *regmap = ohci_at91->sfr_regmap; |
323 | u32 regval; |
324 | int ret; |
325 | |
326 | if (ohci_at91->suspend_smc_id) { |
327 | struct arm_smccc_res res; |
328 | |
329 | arm_smccc_smc(ohci_at91->suspend_smc_id, set, 0, 0, 0, 0, 0, 0, &res); |
330 | if (res.a0) |
331 | return -EINVAL; |
332 | } else if (regmap) { |
333 | ret = regmap_read(map: regmap, AT91_SFR_OHCIICR, val: ®val); |
334 | if (ret) |
335 | return ret; |
336 | |
337 | if (set) |
338 | regval |= AT91_OHCIICR_USB_SUSPEND; |
339 | else |
340 | regval &= ~AT91_OHCIICR_USB_SUSPEND; |
341 | |
342 | regmap_write(map: regmap, AT91_SFR_OHCIICR, val: regval); |
343 | } |
344 | |
345 | return 0; |
346 | } |
347 | |
348 | /* |
349 | * Look at the control requests to the root hub and see if we need to override. |
350 | */ |
351 | static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, |
352 | u16 wIndex, char *buf, u16 wLength) |
353 | { |
354 | struct at91_usbh_data *pdata = dev_get_platdata(dev: hcd->self.controller); |
355 | struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); |
356 | struct usb_hub_descriptor *desc; |
357 | int ret = -EINVAL; |
358 | u32 *data = (u32 *)buf; |
359 | |
360 | dev_dbg(hcd->self.controller, |
361 | "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n" , |
362 | hcd, typeReq, wValue, wIndex, buf, wLength); |
363 | |
364 | wIndex--; |
365 | |
366 | switch (typeReq) { |
367 | case SetPortFeature: |
368 | switch (wValue) { |
369 | case USB_PORT_FEAT_POWER: |
370 | dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n" ); |
371 | if (valid_port(wIndex)) { |
372 | ohci_at91_usb_set_power(pdata, port: wIndex, enable: 1); |
373 | ret = 0; |
374 | } |
375 | |
376 | goto out; |
377 | |
378 | case USB_PORT_FEAT_SUSPEND: |
379 | dev_dbg(hcd->self.controller, "SetPortFeat: SUSPEND\n" ); |
380 | if (valid_port(wIndex)) { |
381 | ohci_at91_port_suspend(ohci_at91, set: 1); |
382 | return 0; |
383 | } |
384 | break; |
385 | } |
386 | break; |
387 | |
388 | case ClearPortFeature: |
389 | switch (wValue) { |
390 | case USB_PORT_FEAT_C_OVER_CURRENT: |
391 | dev_dbg(hcd->self.controller, |
392 | "ClearPortFeature: C_OVER_CURRENT\n" ); |
393 | |
394 | if (valid_port(wIndex)) { |
395 | pdata->overcurrent_changed[wIndex] = 0; |
396 | pdata->overcurrent_status[wIndex] = 0; |
397 | } |
398 | |
399 | goto out; |
400 | |
401 | case USB_PORT_FEAT_OVER_CURRENT: |
402 | dev_dbg(hcd->self.controller, |
403 | "ClearPortFeature: OVER_CURRENT\n" ); |
404 | |
405 | if (valid_port(wIndex)) |
406 | pdata->overcurrent_status[wIndex] = 0; |
407 | |
408 | goto out; |
409 | |
410 | case USB_PORT_FEAT_POWER: |
411 | dev_dbg(hcd->self.controller, |
412 | "ClearPortFeature: POWER\n" ); |
413 | |
414 | if (valid_port(wIndex)) { |
415 | ohci_at91_usb_set_power(pdata, port: wIndex, enable: 0); |
416 | return 0; |
417 | } |
418 | break; |
419 | |
420 | case USB_PORT_FEAT_SUSPEND: |
421 | dev_dbg(hcd->self.controller, "ClearPortFeature: SUSPEND\n" ); |
422 | if (valid_port(wIndex)) { |
423 | ohci_at91_port_suspend(ohci_at91, set: 0); |
424 | return 0; |
425 | } |
426 | break; |
427 | } |
428 | break; |
429 | } |
430 | |
431 | ret = ohci_hub_control(hcd, typeReq, wValue, wIndex: wIndex + 1, buf, wLength); |
432 | if (ret) |
433 | goto out; |
434 | |
435 | switch (typeReq) { |
436 | case GetHubDescriptor: |
437 | |
438 | /* update the hub's descriptor */ |
439 | |
440 | desc = (struct usb_hub_descriptor *)buf; |
441 | |
442 | dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n" , |
443 | desc->wHubCharacteristics); |
444 | |
445 | /* remove the old configurations for power-switching, and |
446 | * over-current protection, and insert our new configuration |
447 | */ |
448 | |
449 | desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); |
450 | desc->wHubCharacteristics |= |
451 | cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM); |
452 | |
453 | if (pdata->overcurrent_supported) { |
454 | desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); |
455 | desc->wHubCharacteristics |= |
456 | cpu_to_le16(HUB_CHAR_INDV_PORT_OCPM); |
457 | } |
458 | |
459 | dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n" , |
460 | desc->wHubCharacteristics); |
461 | |
462 | return ret; |
463 | |
464 | case GetPortStatus: |
465 | /* check port status */ |
466 | |
467 | dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n" , wIndex); |
468 | |
469 | if (valid_port(wIndex)) { |
470 | if (!ohci_at91_usb_get_power(pdata, port: wIndex)) |
471 | *data &= ~cpu_to_le32(RH_PS_PPS); |
472 | |
473 | if (pdata->overcurrent_changed[wIndex]) |
474 | *data |= cpu_to_le32(RH_PS_OCIC); |
475 | |
476 | if (pdata->overcurrent_status[wIndex]) |
477 | *data |= cpu_to_le32(RH_PS_POCI); |
478 | } |
479 | } |
480 | |
481 | out: |
482 | return ret; |
483 | } |
484 | |
485 | /*-------------------------------------------------------------------------*/ |
486 | |
487 | static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) |
488 | { |
489 | struct platform_device *pdev = data; |
490 | struct at91_usbh_data *pdata = dev_get_platdata(dev: &pdev->dev); |
491 | int val, port; |
492 | |
493 | /* From the GPIO notifying the over-current situation, find |
494 | * out the corresponding port */ |
495 | at91_for_each_port(port) { |
496 | if (gpiod_to_irq(desc: pdata->overcurrent_pin[port]) == irq) |
497 | break; |
498 | } |
499 | |
500 | if (port == AT91_MAX_USBH_PORTS) { |
501 | dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n" ); |
502 | return IRQ_HANDLED; |
503 | } |
504 | |
505 | val = gpiod_get_value(desc: pdata->overcurrent_pin[port]); |
506 | |
507 | /* When notified of an over-current situation, disable power |
508 | on the corresponding port, and mark this port in |
509 | over-current. */ |
510 | if (!val) { |
511 | ohci_at91_usb_set_power(pdata, port, enable: 0); |
512 | pdata->overcurrent_status[port] = 1; |
513 | pdata->overcurrent_changed[port] = 1; |
514 | } |
515 | |
516 | dev_dbg(& pdev->dev, "overcurrent situation %s\n" , |
517 | val ? "exited" : "notified" ); |
518 | |
519 | return IRQ_HANDLED; |
520 | } |
521 | |
522 | static const struct of_device_id at91_ohci_dt_ids[] = { |
523 | { .compatible = "atmel,at91rm9200-ohci" }, |
524 | { /* sentinel */ } |
525 | }; |
526 | |
527 | MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); |
528 | |
529 | /*-------------------------------------------------------------------------*/ |
530 | |
531 | static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) |
532 | { |
533 | struct device_node *np = pdev->dev.of_node; |
534 | struct at91_usbh_data *pdata; |
535 | int i; |
536 | int ret; |
537 | int err; |
538 | u32 ports; |
539 | |
540 | /* Right now device-tree probed devices don't get dma_mask set. |
541 | * Since shared usb code relies on it, set it here for now. |
542 | * Once we have dma capability bindings this can go away. |
543 | */ |
544 | ret = dma_coerce_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(32)); |
545 | if (ret) |
546 | return ret; |
547 | |
548 | pdata = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pdata), GFP_KERNEL); |
549 | if (!pdata) |
550 | return -ENOMEM; |
551 | |
552 | pdev->dev.platform_data = pdata; |
553 | |
554 | if (!of_property_read_u32(np, propname: "num-ports" , out_value: &ports)) |
555 | pdata->ports = ports; |
556 | |
557 | at91_for_each_port(i) { |
558 | if (i >= pdata->ports) |
559 | break; |
560 | |
561 | pdata->vbus_pin[i] = |
562 | devm_gpiod_get_index_optional(dev: &pdev->dev, con_id: "atmel,vbus" , |
563 | index: i, flags: GPIOD_OUT_HIGH); |
564 | if (IS_ERR(ptr: pdata->vbus_pin[i])) { |
565 | err = PTR_ERR(ptr: pdata->vbus_pin[i]); |
566 | dev_err(&pdev->dev, "unable to claim gpio \"vbus\": %d\n" , err); |
567 | continue; |
568 | } |
569 | } |
570 | |
571 | at91_for_each_port(i) { |
572 | if (i >= pdata->ports) |
573 | break; |
574 | |
575 | pdata->overcurrent_pin[i] = |
576 | devm_gpiod_get_index_optional(dev: &pdev->dev, con_id: "atmel,oc" , |
577 | index: i, flags: GPIOD_IN); |
578 | if (!pdata->overcurrent_pin[i]) |
579 | continue; |
580 | if (IS_ERR(ptr: pdata->overcurrent_pin[i])) { |
581 | err = PTR_ERR(ptr: pdata->overcurrent_pin[i]); |
582 | dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n" , err); |
583 | continue; |
584 | } |
585 | |
586 | ret = devm_request_irq(dev: &pdev->dev, |
587 | irq: gpiod_to_irq(desc: pdata->overcurrent_pin[i]), |
588 | handler: ohci_hcd_at91_overcurrent_irq, |
589 | IRQF_SHARED, |
590 | devname: "ohci_overcurrent" , dev_id: pdev); |
591 | if (ret) |
592 | dev_info(&pdev->dev, "failed to request gpio \"overcurrent\" IRQ\n" ); |
593 | } |
594 | |
595 | device_init_wakeup(dev: &pdev->dev, enable: 1); |
596 | return usb_hcd_at91_probe(driver: &ohci_at91_hc_driver, pdev); |
597 | } |
598 | |
599 | static void ohci_hcd_at91_drv_remove(struct platform_device *pdev) |
600 | { |
601 | struct at91_usbh_data *pdata = dev_get_platdata(dev: &pdev->dev); |
602 | int i; |
603 | |
604 | if (pdata) { |
605 | at91_for_each_port(i) |
606 | ohci_at91_usb_set_power(pdata, port: i, enable: 0); |
607 | } |
608 | |
609 | device_init_wakeup(dev: &pdev->dev, enable: 0); |
610 | usb_hcd_at91_remove(hcd: platform_get_drvdata(pdev), pdev); |
611 | } |
612 | |
613 | static int __maybe_unused |
614 | ohci_hcd_at91_drv_suspend(struct device *dev) |
615 | { |
616 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
617 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
618 | struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); |
619 | int ret; |
620 | |
621 | /* |
622 | * Disable wakeup if we are going to sleep with slow clock mode |
623 | * enabled. |
624 | */ |
625 | ohci_at91->wakeup = device_may_wakeup(dev) |
626 | && !at91_suspend_entering_slow_clock(); |
627 | |
628 | if (ohci_at91->wakeup) |
629 | enable_irq_wake(irq: hcd->irq); |
630 | |
631 | ret = ohci_suspend(hcd, do_wakeup: ohci_at91->wakeup); |
632 | if (ret) { |
633 | if (ohci_at91->wakeup) |
634 | disable_irq_wake(irq: hcd->irq); |
635 | return ret; |
636 | } |
637 | /* |
638 | * The integrated transceivers seem unable to notice disconnect, |
639 | * reconnect, or wakeup without the 48 MHz clock active. so for |
640 | * correctness, always discard connection state (using reset). |
641 | * |
642 | * REVISIT: some boards will be able to turn VBUS off... |
643 | */ |
644 | if (!ohci_at91->wakeup) { |
645 | ohci->rh_state = OHCI_RH_HALTED; |
646 | |
647 | /* flush the writes */ |
648 | (void) ohci_readl (ohci, &ohci->regs->control); |
649 | msleep(msecs: 1); |
650 | ohci_at91_port_suspend(ohci_at91, set: 1); |
651 | at91_stop_clock(ohci_at91); |
652 | } else { |
653 | ohci_at91_port_suspend(ohci_at91, set: 1); |
654 | } |
655 | |
656 | return ret; |
657 | } |
658 | |
659 | static int __maybe_unused |
660 | ohci_hcd_at91_drv_resume(struct device *dev) |
661 | { |
662 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
663 | struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); |
664 | |
665 | ohci_at91_port_suspend(ohci_at91, set: 0); |
666 | |
667 | if (ohci_at91->wakeup) |
668 | disable_irq_wake(irq: hcd->irq); |
669 | else |
670 | at91_start_clock(ohci_at91); |
671 | |
672 | /* |
673 | * According to the comment in ohci_hcd_at91_drv_suspend() |
674 | * we need to do a reset if the 48Mhz clock was stopped, |
675 | * that is, if ohci_at91->wakeup is clear. Tell ohci_resume() |
676 | * to reset in this case by setting its "hibernated" flag. |
677 | */ |
678 | ohci_resume(hcd, hibernated: !ohci_at91->wakeup); |
679 | |
680 | return 0; |
681 | } |
682 | |
683 | static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend, |
684 | ohci_hcd_at91_drv_resume); |
685 | |
686 | static struct platform_driver ohci_hcd_at91_driver = { |
687 | .probe = ohci_hcd_at91_drv_probe, |
688 | .remove_new = ohci_hcd_at91_drv_remove, |
689 | .shutdown = usb_hcd_platform_shutdown, |
690 | .driver = { |
691 | .name = "at91_ohci" , |
692 | .pm = &ohci_hcd_at91_pm_ops, |
693 | .of_match_table = at91_ohci_dt_ids, |
694 | }, |
695 | }; |
696 | |
697 | static int __init ohci_at91_init(void) |
698 | { |
699 | if (usb_disabled()) |
700 | return -ENODEV; |
701 | |
702 | ohci_init_driver(drv: &ohci_at91_hc_driver, over: &ohci_at91_drv_overrides); |
703 | |
704 | /* |
705 | * The Atmel HW has some unusual quirks, which require Atmel-specific |
706 | * workarounds. We override certain hc_driver functions here to |
707 | * achieve that. We explicitly do not enhance ohci_driver_overrides to |
708 | * allow this more easily, since this is an unusual case, and we don't |
709 | * want to encourage others to override these functions by making it |
710 | * too easy. |
711 | */ |
712 | |
713 | ohci_at91_hc_driver.hub_status_data = ohci_at91_hub_status_data; |
714 | ohci_at91_hc_driver.hub_control = ohci_at91_hub_control; |
715 | |
716 | return platform_driver_register(&ohci_hcd_at91_driver); |
717 | } |
718 | module_init(ohci_at91_init); |
719 | |
720 | static void __exit ohci_at91_cleanup(void) |
721 | { |
722 | platform_driver_unregister(&ohci_hcd_at91_driver); |
723 | } |
724 | module_exit(ohci_at91_cleanup); |
725 | |
726 | MODULE_DESCRIPTION(DRIVER_DESC); |
727 | MODULE_LICENSE("GPL" ); |
728 | MODULE_ALIAS("platform:at91_ohci" ); |
729 | |