]>
Commit | Line | Data |
---|---|---|
39a269c0 AV |
1 | /* |
2 | * OHCI HCD (Host Controller Driver) for USB. | |
3 | * | |
4 | * Copyright (C) 2004 SAN People (Pty) Ltd. | |
5 | * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org> | |
6 | * | |
0365ee0a | 7 | * AT91 Bus Glue |
39a269c0 AV |
8 | * |
9 | * Based on fragments of 2.4 driver by Rick Bronson. | |
10 | * Based on ohci-omap.c | |
11 | * | |
12 | * This file is licenced under the GPL. | |
13 | */ | |
14 | ||
15 | #include <linux/clk.h> | |
16 | #include <linux/platform_device.h> | |
2419730f JCPV |
17 | #include <linux/of_platform.h> |
18 | #include <linux/of_gpio.h> | |
bcd2360c | 19 | #include <linux/platform_data/atmel.h> |
39a269c0 | 20 | |
a09e64fb | 21 | #include <mach/hardware.h> |
4bde4a4c DB |
22 | #include <asm/gpio.h> |
23 | ||
a09e64fb | 24 | #include <mach/cpu.h> |
39a269c0 | 25 | |
0365ee0a DB |
26 | #ifndef CONFIG_ARCH_AT91 |
27 | #error "CONFIG_ARCH_AT91 must be defined." | |
39a269c0 AV |
28 | #endif |
29 | ||
0ee6d1ee NF |
30 | #define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) |
31 | #define at91_for_each_port(index) \ | |
32 | for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++) | |
33 | ||
6b0a1cf7 BB |
34 | /* interface, function and usb clocks; sometimes also an AHB clock */ |
35 | static struct clk *iclk, *fclk, *uclk, *hclk; | |
0365ee0a | 36 | static int clocked; |
39a269c0 AV |
37 | |
38 | extern int usb_disabled(void); | |
39 | ||
40 | /*-------------------------------------------------------------------------*/ | |
41 | ||
ed077bb7 AV |
42 | static void at91_start_clock(void) |
43 | { | |
6b0a1cf7 BB |
44 | if (IS_ENABLED(CONFIG_COMMON_CLK)) { |
45 | clk_set_rate(uclk, 48000000); | |
46 | clk_prepare_enable(uclk); | |
47 | } | |
8e82d8d9 BB |
48 | clk_prepare_enable(hclk); |
49 | clk_prepare_enable(iclk); | |
50 | clk_prepare_enable(fclk); | |
ed077bb7 AV |
51 | clocked = 1; |
52 | } | |
53 | ||
54 | static void at91_stop_clock(void) | |
55 | { | |
8e82d8d9 BB |
56 | clk_disable_unprepare(fclk); |
57 | clk_disable_unprepare(iclk); | |
58 | clk_disable_unprepare(hclk); | |
6b0a1cf7 BB |
59 | if (IS_ENABLED(CONFIG_COMMON_CLK)) |
60 | clk_disable_unprepare(uclk); | |
ed077bb7 AV |
61 | clocked = 0; |
62 | } | |
63 | ||
39a269c0 AV |
64 | static void at91_start_hc(struct platform_device *pdev) |
65 | { | |
66 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | |
67 | struct ohci_regs __iomem *regs = hcd->regs; | |
68 | ||
0365ee0a | 69 | dev_dbg(&pdev->dev, "start\n"); |
39a269c0 AV |
70 | |
71 | /* | |
72 | * Start the USB clocks. | |
73 | */ | |
ed077bb7 | 74 | at91_start_clock(); |
39a269c0 AV |
75 | |
76 | /* | |
77 | * The USB host controller must remain in reset. | |
78 | */ | |
79 | writel(0, ®s->control); | |
80 | } | |
81 | ||
82 | static void at91_stop_hc(struct platform_device *pdev) | |
83 | { | |
84 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | |
85 | struct ohci_regs __iomem *regs = hcd->regs; | |
86 | ||
0365ee0a | 87 | dev_dbg(&pdev->dev, "stop\n"); |
39a269c0 AV |
88 | |
89 | /* | |
90 | * Put the USB host controller into reset. | |
91 | */ | |
92 | writel(0, ®s->control); | |
93 | ||
94 | /* | |
95 | * Stop the USB clocks. | |
96 | */ | |
ed077bb7 | 97 | at91_stop_clock(); |
39a269c0 AV |
98 | } |
99 | ||
100 | ||
101 | /*-------------------------------------------------------------------------*/ | |
102 | ||
fb4e98ab | 103 | static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); |
39a269c0 AV |
104 | |
105 | /* configure so an HC device and id are always provided */ | |
106 | /* always called with process context; sleeping is OK */ | |
107 | ||
108 | ||
109 | /** | |
0365ee0a | 110 | * usb_hcd_at91_probe - initialize AT91-based HCDs |
39a269c0 AV |
111 | * Context: !in_interrupt() |
112 | * | |
113 | * Allocates basic resources for this USB host controller, and | |
114 | * then invokes the start() method for the HCD associated with it | |
115 | * through the hotplug entry's driver_data. | |
39a269c0 | 116 | */ |
41ac7b3a | 117 | static int usb_hcd_at91_probe(const struct hc_driver *driver, |
0365ee0a | 118 | struct platform_device *pdev) |
39a269c0 AV |
119 | { |
120 | int retval; | |
121 | struct usb_hcd *hcd = NULL; | |
122 | ||
123 | if (pdev->num_resources != 2) { | |
124 | pr_debug("hcd probe: invalid num_resources"); | |
125 | return -ENODEV; | |
126 | } | |
127 | ||
0365ee0a DB |
128 | if ((pdev->resource[0].flags != IORESOURCE_MEM) |
129 | || (pdev->resource[1].flags != IORESOURCE_IRQ)) { | |
39a269c0 AV |
130 | pr_debug("hcd probe: invalid resource type\n"); |
131 | return -ENODEV; | |
132 | } | |
133 | ||
0365ee0a | 134 | hcd = usb_create_hcd(driver, &pdev->dev, "at91"); |
39a269c0 AV |
135 | if (!hcd) |
136 | return -ENOMEM; | |
137 | hcd->rsrc_start = pdev->resource[0].start; | |
7a82f612 | 138 | hcd->rsrc_len = resource_size(&pdev->resource[0]); |
39a269c0 AV |
139 | |
140 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | |
141 | pr_debug("request_mem_region failed\n"); | |
142 | retval = -EBUSY; | |
143 | goto err1; | |
144 | } | |
145 | ||
146 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | |
147 | if (!hcd->regs) { | |
148 | pr_debug("ioremap failed\n"); | |
149 | retval = -EIO; | |
150 | goto err2; | |
151 | } | |
152 | ||
153 | iclk = clk_get(&pdev->dev, "ohci_clk"); | |
6813463c JCPV |
154 | if (IS_ERR(iclk)) { |
155 | dev_err(&pdev->dev, "failed to get ohci_clk\n"); | |
156 | retval = PTR_ERR(iclk); | |
157 | goto err3; | |
158 | } | |
39a269c0 | 159 | fclk = clk_get(&pdev->dev, "uhpck"); |
6813463c JCPV |
160 | if (IS_ERR(fclk)) { |
161 | dev_err(&pdev->dev, "failed to get uhpck\n"); | |
162 | retval = PTR_ERR(fclk); | |
163 | goto err4; | |
164 | } | |
0af4316b | 165 | hclk = clk_get(&pdev->dev, "hclk"); |
6813463c JCPV |
166 | if (IS_ERR(hclk)) { |
167 | dev_err(&pdev->dev, "failed to get hclk\n"); | |
168 | retval = PTR_ERR(hclk); | |
169 | goto err5; | |
170 | } | |
6b0a1cf7 BB |
171 | if (IS_ENABLED(CONFIG_COMMON_CLK)) { |
172 | uclk = clk_get(&pdev->dev, "usb_clk"); | |
173 | if (IS_ERR(uclk)) { | |
174 | dev_err(&pdev->dev, "failed to get uclk\n"); | |
175 | retval = PTR_ERR(uclk); | |
176 | goto err6; | |
177 | } | |
178 | } | |
39a269c0 AV |
179 | |
180 | at91_start_hc(pdev); | |
181 | ohci_hcd_init(hcd_to_ohci(hcd)); | |
182 | ||
2f2cac3c | 183 | retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); |
39a269c0 AV |
184 | if (retval == 0) |
185 | return retval; | |
186 | ||
187 | /* Error handling */ | |
188 | at91_stop_hc(pdev); | |
189 | ||
6b0a1cf7 BB |
190 | if (IS_ENABLED(CONFIG_COMMON_CLK)) |
191 | clk_put(uclk); | |
192 | err6: | |
0af4316b | 193 | clk_put(hclk); |
6813463c | 194 | err5: |
39a269c0 | 195 | clk_put(fclk); |
6813463c | 196 | err4: |
39a269c0 AV |
197 | clk_put(iclk); |
198 | ||
6813463c | 199 | err3: |
39a269c0 AV |
200 | iounmap(hcd->regs); |
201 | ||
202 | err2: | |
203 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | |
204 | ||
205 | err1: | |
206 | usb_put_hcd(hcd); | |
207 | return retval; | |
208 | } | |
209 | ||
210 | ||
39a269c0 AV |
211 | /* may be called with controller, bus, and devices active */ |
212 | ||
213 | /** | |
0365ee0a | 214 | * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs |
39a269c0 AV |
215 | * @dev: USB Host Controller being removed |
216 | * Context: !in_interrupt() | |
217 | * | |
218 | * Reverses the effect of usb_hcd_at91_probe(), first invoking | |
219 | * the HCD's stop() method. It is always called from a thread | |
0365ee0a | 220 | * context, "rmmod" or something similar. |
39a269c0 AV |
221 | * |
222 | */ | |
fb4e98ab | 223 | static void usb_hcd_at91_remove(struct usb_hcd *hcd, |
0365ee0a | 224 | struct platform_device *pdev) |
39a269c0 AV |
225 | { |
226 | usb_remove_hcd(hcd); | |
227 | at91_stop_hc(pdev); | |
228 | iounmap(hcd->regs); | |
68ba61b8 | 229 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
421b4bf5 | 230 | usb_put_hcd(hcd); |
39a269c0 | 231 | |
6b0a1cf7 BB |
232 | if (IS_ENABLED(CONFIG_COMMON_CLK)) |
233 | clk_put(uclk); | |
0af4316b | 234 | clk_put(hclk); |
68ba61b8 DB |
235 | clk_put(fclk); |
236 | clk_put(iclk); | |
ed077bb7 | 237 | fclk = iclk = hclk = NULL; |
39a269c0 AV |
238 | } |
239 | ||
240 | /*-------------------------------------------------------------------------*/ | |
241 | ||
41ac7b3a | 242 | static int |
07e4e556 | 243 | ohci_at91_reset (struct usb_hcd *hcd) |
39a269c0 | 244 | { |
d4f09e28 | 245 | struct at91_usbh_data *board = dev_get_platdata(hcd->self.controller); |
39a269c0 AV |
246 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
247 | int ret; | |
248 | ||
249 | if ((ret = ohci_init(ohci)) < 0) | |
250 | return ret; | |
251 | ||
cd22afda | 252 | ohci->num_ports = board->ports; |
07e4e556 NF |
253 | return 0; |
254 | } | |
255 | ||
41ac7b3a | 256 | static int |
07e4e556 NF |
257 | ohci_at91_start (struct usb_hcd *hcd) |
258 | { | |
259 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | |
260 | int ret; | |
0365ee0a | 261 | |
39a269c0 | 262 | if ((ret = ohci_run(ohci)) < 0) { |
2418d5f9 GKH |
263 | dev_err(hcd->self.controller, "can't start %s\n", |
264 | hcd->self.bus_name); | |
39a269c0 AV |
265 | ohci_stop(hcd); |
266 | return ret; | |
267 | } | |
39a269c0 AV |
268 | return 0; |
269 | } | |
270 | ||
aa6e52a3 TP |
271 | static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) |
272 | { | |
0ee6d1ee | 273 | if (!valid_port(port)) |
aa6e52a3 TP |
274 | return; |
275 | ||
8a7a49d1 | 276 | if (!gpio_is_valid(pdata->vbus_pin[port])) |
770f0baa JCPV |
277 | return; |
278 | ||
8134ff55 | 279 | gpio_set_value(pdata->vbus_pin[port], |
1e7caf8b | 280 | pdata->vbus_pin_active_low[port] ^ enable); |
aa6e52a3 TP |
281 | } |
282 | ||
283 | static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) | |
284 | { | |
0ee6d1ee | 285 | if (!valid_port(port)) |
aa6e52a3 TP |
286 | return -EINVAL; |
287 | ||
8a7a49d1 | 288 | if (!gpio_is_valid(pdata->vbus_pin[port])) |
770f0baa JCPV |
289 | return -EINVAL; |
290 | ||
8134ff55 | 291 | return gpio_get_value(pdata->vbus_pin[port]) ^ |
1e7caf8b | 292 | pdata->vbus_pin_active_low[port]; |
aa6e52a3 TP |
293 | } |
294 | ||
295 | /* | |
296 | * Update the status data from the hub with the over-current indicator change. | |
297 | */ | |
298 | static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) | |
299 | { | |
d4f09e28 | 300 | struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); |
aa6e52a3 TP |
301 | int length = ohci_hub_status_data(hcd, buf); |
302 | int port; | |
303 | ||
0ee6d1ee | 304 | at91_for_each_port(port) { |
aa6e52a3 | 305 | if (pdata->overcurrent_changed[port]) { |
0ee6d1ee | 306 | if (!length) |
aa6e52a3 TP |
307 | length = 1; |
308 | buf[0] |= 1 << (port + 1); | |
309 | } | |
310 | } | |
311 | ||
312 | return length; | |
313 | } | |
314 | ||
315 | /* | |
316 | * Look at the control requests to the root hub and see if we need to override. | |
317 | */ | |
318 | static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |
319 | u16 wIndex, char *buf, u16 wLength) | |
320 | { | |
d4f09e28 | 321 | struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); |
aa6e52a3 TP |
322 | struct usb_hub_descriptor *desc; |
323 | int ret = -EINVAL; | |
324 | u32 *data = (u32 *)buf; | |
325 | ||
326 | dev_dbg(hcd->self.controller, | |
327 | "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", | |
328 | hcd, typeReq, wValue, wIndex, buf, wLength); | |
329 | ||
0ee6d1ee NF |
330 | wIndex--; |
331 | ||
aa6e52a3 TP |
332 | switch (typeReq) { |
333 | case SetPortFeature: | |
334 | if (wValue == USB_PORT_FEAT_POWER) { | |
335 | dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); | |
0ee6d1ee NF |
336 | if (valid_port(wIndex)) { |
337 | ohci_at91_usb_set_power(pdata, wIndex, 1); | |
338 | ret = 0; | |
339 | } | |
340 | ||
aa6e52a3 TP |
341 | goto out; |
342 | } | |
343 | break; | |
344 | ||
345 | case ClearPortFeature: | |
346 | switch (wValue) { | |
347 | case USB_PORT_FEAT_C_OVER_CURRENT: | |
348 | dev_dbg(hcd->self.controller, | |
349 | "ClearPortFeature: C_OVER_CURRENT\n"); | |
350 | ||
0ee6d1ee NF |
351 | if (valid_port(wIndex)) { |
352 | pdata->overcurrent_changed[wIndex] = 0; | |
353 | pdata->overcurrent_status[wIndex] = 0; | |
aa6e52a3 TP |
354 | } |
355 | ||
356 | goto out; | |
357 | ||
358 | case USB_PORT_FEAT_OVER_CURRENT: | |
359 | dev_dbg(hcd->self.controller, | |
360 | "ClearPortFeature: OVER_CURRENT\n"); | |
361 | ||
0ee6d1ee NF |
362 | if (valid_port(wIndex)) |
363 | pdata->overcurrent_status[wIndex] = 0; | |
aa6e52a3 TP |
364 | |
365 | goto out; | |
366 | ||
367 | case USB_PORT_FEAT_POWER: | |
368 | dev_dbg(hcd->self.controller, | |
369 | "ClearPortFeature: POWER\n"); | |
370 | ||
0ee6d1ee NF |
371 | if (valid_port(wIndex)) { |
372 | ohci_at91_usb_set_power(pdata, wIndex, 0); | |
aa6e52a3 TP |
373 | return 0; |
374 | } | |
375 | } | |
376 | break; | |
377 | } | |
378 | ||
0ee6d1ee | 379 | ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength); |
aa6e52a3 TP |
380 | if (ret) |
381 | goto out; | |
382 | ||
383 | switch (typeReq) { | |
384 | case GetHubDescriptor: | |
385 | ||
386 | /* update the hub's descriptor */ | |
387 | ||
388 | desc = (struct usb_hub_descriptor *)buf; | |
389 | ||
390 | dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", | |
391 | desc->wHubCharacteristics); | |
392 | ||
393 | /* remove the old configurations for power-switching, and | |
394 | * over-current protection, and insert our new configuration | |
395 | */ | |
396 | ||
397 | desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); | |
398 | desc->wHubCharacteristics |= cpu_to_le16(0x0001); | |
399 | ||
400 | if (pdata->overcurrent_supported) { | |
401 | desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); | |
402 | desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); | |
403 | } | |
404 | ||
405 | dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", | |
406 | desc->wHubCharacteristics); | |
407 | ||
408 | return ret; | |
409 | ||
410 | case GetPortStatus: | |
411 | /* check port status */ | |
412 | ||
413 | dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); | |
414 | ||
0ee6d1ee NF |
415 | if (valid_port(wIndex)) { |
416 | if (!ohci_at91_usb_get_power(pdata, wIndex)) | |
aa6e52a3 | 417 | *data &= ~cpu_to_le32(RH_PS_PPS); |
aa6e52a3 | 418 | |
0ee6d1ee | 419 | if (pdata->overcurrent_changed[wIndex]) |
aa6e52a3 | 420 | *data |= cpu_to_le32(RH_PS_OCIC); |
aa6e52a3 | 421 | |
0ee6d1ee | 422 | if (pdata->overcurrent_status[wIndex]) |
aa6e52a3 | 423 | *data |= cpu_to_le32(RH_PS_POCI); |
aa6e52a3 TP |
424 | } |
425 | } | |
426 | ||
427 | out: | |
428 | return ret; | |
429 | } | |
430 | ||
39a269c0 AV |
431 | /*-------------------------------------------------------------------------*/ |
432 | ||
433 | static const struct hc_driver ohci_at91_hc_driver = { | |
434 | .description = hcd_name, | |
0365ee0a | 435 | .product_desc = "AT91 OHCI", |
39a269c0 AV |
436 | .hcd_priv_size = sizeof(struct ohci_hcd), |
437 | ||
438 | /* | |
439 | * generic hardware linkage | |
440 | */ | |
441 | .irq = ohci_irq, | |
442 | .flags = HCD_USB11 | HCD_MEMORY, | |
443 | ||
444 | /* | |
445 | * basic lifecycle operations | |
446 | */ | |
07e4e556 | 447 | .reset = ohci_at91_reset, |
39a269c0 AV |
448 | .start = ohci_at91_start, |
449 | .stop = ohci_stop, | |
dd9048af | 450 | .shutdown = ohci_shutdown, |
39a269c0 AV |
451 | |
452 | /* | |
453 | * managing i/o requests and associated device resources | |
454 | */ | |
455 | .urb_enqueue = ohci_urb_enqueue, | |
456 | .urb_dequeue = ohci_urb_dequeue, | |
457 | .endpoint_disable = ohci_endpoint_disable, | |
458 | ||
459 | /* | |
460 | * scheduling support | |
461 | */ | |
462 | .get_frame_number = ohci_get_frame, | |
463 | ||
464 | /* | |
465 | * root hub support | |
466 | */ | |
aa6e52a3 TP |
467 | .hub_status_data = ohci_at91_hub_status_data, |
468 | .hub_control = ohci_at91_hub_control, | |
39a269c0 | 469 | #ifdef CONFIG_PM |
68ba61b8 DB |
470 | .bus_suspend = ohci_bus_suspend, |
471 | .bus_resume = ohci_bus_resume, | |
39a269c0 AV |
472 | #endif |
473 | .start_port_reset = ohci_start_port_reset, | |
474 | }; | |
475 | ||
476 | /*-------------------------------------------------------------------------*/ | |
477 | ||
aa6e52a3 TP |
478 | static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) |
479 | { | |
480 | struct platform_device *pdev = data; | |
d4f09e28 | 481 | struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev); |
aa6e52a3 TP |
482 | int val, gpio, port; |
483 | ||
484 | /* From the GPIO notifying the over-current situation, find | |
485 | * out the corresponding port */ | |
0ee6d1ee | 486 | at91_for_each_port(port) { |
01bb6501 JE |
487 | if (gpio_is_valid(pdata->overcurrent_pin[port]) && |
488 | gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { | |
e4499079 | 489 | gpio = pdata->overcurrent_pin[port]; |
aa6e52a3 | 490 | break; |
e4499079 | 491 | } |
aa6e52a3 TP |
492 | } |
493 | ||
0ee6d1ee | 494 | if (port == AT91_MAX_USBH_PORTS) { |
aa6e52a3 TP |
495 | dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n"); |
496 | return IRQ_HANDLED; | |
497 | } | |
498 | ||
499 | val = gpio_get_value(gpio); | |
500 | ||
501 | /* When notified of an over-current situation, disable power | |
502 | on the corresponding port, and mark this port in | |
503 | over-current. */ | |
0ee6d1ee | 504 | if (!val) { |
aa6e52a3 TP |
505 | ohci_at91_usb_set_power(pdata, port, 0); |
506 | pdata->overcurrent_status[port] = 1; | |
507 | pdata->overcurrent_changed[port] = 1; | |
508 | } | |
509 | ||
510 | dev_dbg(& pdev->dev, "overcurrent situation %s\n", | |
511 | val ? "exited" : "notified"); | |
512 | ||
513 | return IRQ_HANDLED; | |
514 | } | |
515 | ||
2419730f JCPV |
516 | #ifdef CONFIG_OF |
517 | static const struct of_device_id at91_ohci_dt_ids[] = { | |
518 | { .compatible = "atmel,at91rm9200-ohci" }, | |
519 | { /* sentinel */ } | |
520 | }; | |
521 | ||
522 | MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); | |
523 | ||
41ac7b3a | 524 | static int ohci_at91_of_init(struct platform_device *pdev) |
2419730f JCPV |
525 | { |
526 | struct device_node *np = pdev->dev.of_node; | |
aaf9f5fc | 527 | int i, gpio; |
2419730f JCPV |
528 | enum of_gpio_flags flags; |
529 | struct at91_usbh_data *pdata; | |
530 | u32 ports; | |
531 | ||
532 | if (!np) | |
533 | return 0; | |
534 | ||
535 | /* Right now device-tree probed devices don't get dma_mask set. | |
536 | * Since shared usb code relies on it, set it here for now. | |
537 | * Once we have dma capability bindings this can go away. | |
538 | */ | |
539 | if (!pdev->dev.dma_mask) | |
3b9561e9 SW |
540 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; |
541 | if (!pdev->dev.coherent_dma_mask) | |
542 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | |
2419730f JCPV |
543 | |
544 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | |
545 | if (!pdata) | |
546 | return -ENOMEM; | |
547 | ||
548 | if (!of_property_read_u32(np, "num-ports", &ports)) | |
549 | pdata->ports = ports; | |
550 | ||
0ee6d1ee | 551 | at91_for_each_port(i) { |
2419730f JCPV |
552 | gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags); |
553 | pdata->vbus_pin[i] = gpio; | |
554 | if (!gpio_is_valid(gpio)) | |
555 | continue; | |
556 | pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW; | |
2419730f JCPV |
557 | } |
558 | ||
0ee6d1ee | 559 | at91_for_each_port(i) |
aaf9f5fc NF |
560 | pdata->overcurrent_pin[i] = |
561 | of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); | |
2419730f JCPV |
562 | |
563 | pdev->dev.platform_data = pdata; | |
564 | ||
565 | return 0; | |
566 | } | |
567 | #else | |
41ac7b3a | 568 | static int ohci_at91_of_init(struct platform_device *pdev) |
2419730f JCPV |
569 | { |
570 | return 0; | |
571 | } | |
572 | #endif | |
573 | ||
aa6e52a3 TP |
574 | /*-------------------------------------------------------------------------*/ |
575 | ||
41ac7b3a | 576 | static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) |
39a269c0 | 577 | { |
2419730f | 578 | struct at91_usbh_data *pdata; |
4bde4a4c | 579 | int i; |
aaf9f5fc NF |
580 | int gpio; |
581 | int ret; | |
4bde4a4c | 582 | |
1887ab2b NF |
583 | ret = ohci_at91_of_init(pdev); |
584 | if (ret) | |
585 | return ret; | |
2419730f | 586 | |
d4f09e28 | 587 | pdata = dev_get_platdata(&pdev->dev); |
2419730f | 588 | |
4bde4a4c | 589 | if (pdata) { |
0ee6d1ee | 590 | at91_for_each_port(i) { |
6fffb77c NF |
591 | /* |
592 | * do not configure PIO if not in relation with | |
593 | * real USB port on board | |
594 | */ | |
595 | if (i >= pdata->ports) { | |
596 | pdata->vbus_pin[i] = -EINVAL; | |
597 | pdata->overcurrent_pin[i] = -EINVAL; | |
598 | break; | |
599 | } | |
600 | ||
8a7a49d1 | 601 | if (!gpio_is_valid(pdata->vbus_pin[i])) |
4bde4a4c | 602 | continue; |
aaf9f5fc NF |
603 | gpio = pdata->vbus_pin[i]; |
604 | ||
605 | ret = gpio_request(gpio, "ohci_vbus"); | |
606 | if (ret) { | |
607 | dev_err(&pdev->dev, | |
608 | "can't request vbus gpio %d\n", gpio); | |
609 | continue; | |
610 | } | |
611 | ret = gpio_direction_output(gpio, | |
612 | !pdata->vbus_pin_active_low[i]); | |
613 | if (ret) { | |
614 | dev_err(&pdev->dev, | |
615 | "can't put vbus gpio %d as output %d\n", | |
616 | gpio, !pdata->vbus_pin_active_low[i]); | |
617 | gpio_free(gpio); | |
618 | continue; | |
619 | } | |
620 | ||
aa6e52a3 TP |
621 | ohci_at91_usb_set_power(pdata, i, 1); |
622 | } | |
623 | ||
0ee6d1ee | 624 | at91_for_each_port(i) { |
8a7a49d1 | 625 | if (!gpio_is_valid(pdata->overcurrent_pin[i])) |
aa6e52a3 | 626 | continue; |
aaf9f5fc NF |
627 | gpio = pdata->overcurrent_pin[i]; |
628 | ||
629 | ret = gpio_request(gpio, "ohci_overcurrent"); | |
630 | if (ret) { | |
631 | dev_err(&pdev->dev, | |
632 | "can't request overcurrent gpio %d\n", | |
633 | gpio); | |
634 | continue; | |
635 | } | |
636 | ||
637 | ret = gpio_direction_input(gpio); | |
638 | if (ret) { | |
639 | dev_err(&pdev->dev, | |
640 | "can't configure overcurrent gpio %d as input\n", | |
641 | gpio); | |
642 | gpio_free(gpio); | |
643 | continue; | |
644 | } | |
aa6e52a3 | 645 | |
aaf9f5fc | 646 | ret = request_irq(gpio_to_irq(gpio), |
aa6e52a3 TP |
647 | ohci_hcd_at91_overcurrent_irq, |
648 | IRQF_SHARED, "ohci_overcurrent", pdev); | |
649 | if (ret) { | |
aaf9f5fc NF |
650 | gpio_free(gpio); |
651 | dev_err(&pdev->dev, | |
652 | "can't get gpio IRQ for overcurrent\n"); | |
aa6e52a3 | 653 | } |
4bde4a4c DB |
654 | } |
655 | } | |
656 | ||
0365ee0a DB |
657 | device_init_wakeup(&pdev->dev, 1); |
658 | return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); | |
39a269c0 AV |
659 | } |
660 | ||
fb4e98ab | 661 | static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) |
39a269c0 | 662 | { |
d4f09e28 | 663 | struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev); |
4bde4a4c DB |
664 | int i; |
665 | ||
666 | if (pdata) { | |
0ee6d1ee | 667 | at91_for_each_port(i) { |
8a7a49d1 | 668 | if (!gpio_is_valid(pdata->vbus_pin[i])) |
4bde4a4c | 669 | continue; |
aa6e52a3 | 670 | ohci_at91_usb_set_power(pdata, i, 0); |
4bde4a4c DB |
671 | gpio_free(pdata->vbus_pin[i]); |
672 | } | |
aa6e52a3 | 673 | |
0ee6d1ee | 674 | at91_for_each_port(i) { |
8a7a49d1 | 675 | if (!gpio_is_valid(pdata->overcurrent_pin[i])) |
aa6e52a3 TP |
676 | continue; |
677 | free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev); | |
678 | gpio_free(pdata->overcurrent_pin[i]); | |
679 | } | |
4bde4a4c DB |
680 | } |
681 | ||
0365ee0a | 682 | device_init_wakeup(&pdev->dev, 0); |
421b4bf5 PZ |
683 | usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev); |
684 | return 0; | |
39a269c0 AV |
685 | } |
686 | ||
687 | #ifdef CONFIG_PM | |
39a269c0 | 688 | |
68ba61b8 | 689 | static int |
0365ee0a | 690 | ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) |
68ba61b8 | 691 | { |
0365ee0a DB |
692 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
693 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | |
694 | ||
695 | if (device_may_wakeup(&pdev->dev)) | |
696 | enable_irq_wake(hcd->irq); | |
0365ee0a DB |
697 | |
698 | /* | |
699 | * The integrated transceivers seem unable to notice disconnect, | |
700 | * reconnect, or wakeup without the 48 MHz clock active. so for | |
701 | * correctness, always discard connection state (using reset). | |
702 | * | |
703 | * REVISIT: some boards will be able to turn VBUS off... | |
704 | */ | |
705 | if (at91_suspend_entering_slow_clock()) { | |
706 | ohci_usb_reset (ohci); | |
869aa98c PV |
707 | /* flush the writes */ |
708 | (void) ohci_readl (ohci, &ohci->regs->control); | |
ed077bb7 | 709 | at91_stop_clock(); |
0365ee0a | 710 | } |
39a269c0 AV |
711 | |
712 | return 0; | |
713 | } | |
714 | ||
0365ee0a | 715 | static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) |
39a269c0 | 716 | { |
6dde896e MP |
717 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
718 | ||
719 | if (device_may_wakeup(&pdev->dev)) | |
720 | disable_irq_wake(hcd->irq); | |
721 | ||
ed077bb7 AV |
722 | if (!clocked) |
723 | at91_start_clock(); | |
39a269c0 | 724 | |
cfa49b4b | 725 | ohci_resume(hcd, false); |
39a269c0 AV |
726 | return 0; |
727 | } | |
728 | #else | |
729 | #define ohci_hcd_at91_drv_suspend NULL | |
730 | #define ohci_hcd_at91_drv_resume NULL | |
731 | #endif | |
732 | ||
f4fce61d | 733 | MODULE_ALIAS("platform:at91_ohci"); |
68ba61b8 | 734 | |
39a269c0 AV |
735 | static struct platform_driver ohci_hcd_at91_driver = { |
736 | .probe = ohci_hcd_at91_drv_probe, | |
7690417d | 737 | .remove = ohci_hcd_at91_drv_remove, |
64a21d02 | 738 | .shutdown = usb_hcd_platform_shutdown, |
39a269c0 AV |
739 | .suspend = ohci_hcd_at91_drv_suspend, |
740 | .resume = ohci_hcd_at91_drv_resume, | |
741 | .driver = { | |
0365ee0a | 742 | .name = "at91_ohci", |
39a269c0 | 743 | .owner = THIS_MODULE, |
2419730f | 744 | .of_match_table = of_match_ptr(at91_ohci_dt_ids), |
39a269c0 AV |
745 | }, |
746 | }; |