diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 15:09:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 15:09:47 -0500 |
commit | 55b81e6f2795484ea8edf5805c95c007cacfa736 (patch) | |
tree | c3724975107857fcc03b5dd649c462e4f72397be /drivers/usb/dwc3/core.c | |
parent | 5983faf942f260023e547f3c5f38c1033c35cc9b (diff) | |
parent | 08e87d0d773dc9ca5faf4c3306e238ed0ea129b0 (diff) |
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (232 commits)
USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c
xhci: Clean up 32-bit build warnings.
USB: update documentation for usbmon
usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops
drivers/usb/class/cdc-acm.c: clear dangling pointer
drivers/usb/dwc3/dwc3-pci.c: introduce missing kfree
drivers/usb/host/isp1760-if.c: introduce missing kfree
usb: option: add ZD Incorporated HSPA modem
usb: ch9: fix up MaxStreams helper
USB: usb-skeleton.c: cleanup open_count
USB: usb-skeleton.c: fix open/disconnect race
xhci: Properly handle COMP_2ND_BW_ERR
USB: remove dead code from suspend/resume path
USB: add quirk for another camera
drivers: usb: wusbcore: Fix dependency for USB_WUSB
xhci: Better debugging for critical host errors.
xhci: Be less verbose during URB cancellation.
xhci: Remove debugging about ring structure allocation.
xhci: Remove debugging about toggling cycle bits.
xhci: Remove debugging for individual transfers.
...
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r-- | drivers/usb/dwc3/core.c | 209 |
1 files changed, 174 insertions, 35 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 600d82348511..7c9df630dbe4 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
@@ -59,6 +59,60 @@ | |||
59 | 59 | ||
60 | #include "debug.h" | 60 | #include "debug.h" |
61 | 61 | ||
62 | static char *maximum_speed = "super"; | ||
63 | module_param(maximum_speed, charp, 0); | ||
64 | MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); | ||
65 | |||
66 | /* -------------------------------------------------------------------------- */ | ||
67 | |||
68 | #define DWC3_DEVS_POSSIBLE 32 | ||
69 | |||
70 | static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); | ||
71 | |||
72 | int dwc3_get_device_id(void) | ||
73 | { | ||
74 | int id; | ||
75 | |||
76 | again: | ||
77 | id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE); | ||
78 | if (id < DWC3_DEVS_POSSIBLE) { | ||
79 | int old; | ||
80 | |||
81 | old = test_and_set_bit(id, dwc3_devs); | ||
82 | if (old) | ||
83 | goto again; | ||
84 | } else { | ||
85 | pr_err("dwc3: no space for new device\n"); | ||
86 | id = -ENOMEM; | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(dwc3_get_device_id); | ||
92 | |||
93 | void dwc3_put_device_id(int id) | ||
94 | { | ||
95 | int ret; | ||
96 | |||
97 | if (id < 0) | ||
98 | return; | ||
99 | |||
100 | ret = test_bit(id, dwc3_devs); | ||
101 | WARN(!ret, "dwc3: ID %d not in use\n", id); | ||
102 | clear_bit(id, dwc3_devs); | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(dwc3_put_device_id); | ||
105 | |||
106 | void dwc3_set_mode(struct dwc3 *dwc, u32 mode) | ||
107 | { | ||
108 | u32 reg; | ||
109 | |||
110 | reg = dwc3_readl(dwc->regs, DWC3_GCTL); | ||
111 | reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); | ||
112 | reg |= DWC3_GCTL_PRTCAPDIR(mode); | ||
113 | dwc3_writel(dwc->regs, DWC3_GCTL, reg); | ||
114 | } | ||
115 | |||
62 | /** | 116 | /** |
63 | * dwc3_core_soft_reset - Issues core soft reset and PHY reset | 117 | * dwc3_core_soft_reset - Issues core soft reset and PHY reset |
64 | * @dwc: pointer to our context structure | 118 | * @dwc: pointer to our context structure |
@@ -150,7 +204,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) | |||
150 | struct dwc3_event_buffer *evt; | 204 | struct dwc3_event_buffer *evt; |
151 | int i; | 205 | int i; |
152 | 206 | ||
153 | for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { | 207 | for (i = 0; i < dwc->num_event_buffers; i++) { |
154 | evt = dwc->ev_buffs[i]; | 208 | evt = dwc->ev_buffs[i]; |
155 | if (evt) { | 209 | if (evt) { |
156 | dwc3_free_one_event_buffer(dwc, evt); | 210 | dwc3_free_one_event_buffer(dwc, evt); |
@@ -162,17 +216,25 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) | |||
162 | /** | 216 | /** |
163 | * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length | 217 | * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length |
164 | * @dwc: Pointer to out controller context structure | 218 | * @dwc: Pointer to out controller context structure |
165 | * @num: number of event buffers to allocate | ||
166 | * @length: size of event buffer | 219 | * @length: size of event buffer |
167 | * | 220 | * |
168 | * Returns 0 on success otherwise negative errno. In error the case, dwc | 221 | * Returns 0 on success otherwise negative errno. In error the case, dwc |
169 | * may contain some buffers allocated but not all which were requested. | 222 | * may contain some buffers allocated but not all which were requested. |
170 | */ | 223 | */ |
171 | static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num, | 224 | static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) |
172 | unsigned length) | ||
173 | { | 225 | { |
226 | int num; | ||
174 | int i; | 227 | int i; |
175 | 228 | ||
229 | num = DWC3_NUM_INT(dwc->hwparams.hwparams1); | ||
230 | dwc->num_event_buffers = num; | ||
231 | |||
232 | dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); | ||
233 | if (!dwc->ev_buffs) { | ||
234 | dev_err(dwc->dev, "can't allocate event buffers array\n"); | ||
235 | return -ENOMEM; | ||
236 | } | ||
237 | |||
176 | for (i = 0; i < num; i++) { | 238 | for (i = 0; i < num; i++) { |
177 | struct dwc3_event_buffer *evt; | 239 | struct dwc3_event_buffer *evt; |
178 | 240 | ||
@@ -198,7 +260,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) | |||
198 | struct dwc3_event_buffer *evt; | 260 | struct dwc3_event_buffer *evt; |
199 | int n; | 261 | int n; |
200 | 262 | ||
201 | for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { | 263 | for (n = 0; n < dwc->num_event_buffers; n++) { |
202 | evt = dwc->ev_buffs[n]; | 264 | evt = dwc->ev_buffs[n]; |
203 | dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", | 265 | dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", |
204 | evt->buf, (unsigned long long) evt->dma, | 266 | evt->buf, (unsigned long long) evt->dma, |
@@ -221,7 +283,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) | |||
221 | struct dwc3_event_buffer *evt; | 283 | struct dwc3_event_buffer *evt; |
222 | int n; | 284 | int n; |
223 | 285 | ||
224 | for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { | 286 | for (n = 0; n < dwc->num_event_buffers; n++) { |
225 | evt = dwc->ev_buffs[n]; | 287 | evt = dwc->ev_buffs[n]; |
226 | dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); | 288 | dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); |
227 | dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); | 289 | dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); |
@@ -285,8 +347,32 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) | |||
285 | cpu_relax(); | 347 | cpu_relax(); |
286 | } while (true); | 348 | } while (true); |
287 | 349 | ||
288 | ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM, | 350 | dwc3_cache_hwparams(dwc); |
289 | DWC3_EVENT_BUFFERS_SIZE); | 351 | |
352 | reg = dwc3_readl(dwc->regs, DWC3_GCTL); | ||
353 | reg &= ~DWC3_GCTL_SCALEDOWN(3); | ||
354 | reg &= ~DWC3_GCTL_DISSCRAMBLE; | ||
355 | |||
356 | switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { | ||
357 | case DWC3_GHWPARAMS1_EN_PWROPT_CLK: | ||
358 | reg &= ~DWC3_GCTL_DSBLCLKGTNG; | ||
359 | break; | ||
360 | default: | ||
361 | dev_dbg(dwc->dev, "No power optimization available\n"); | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * WORKAROUND: DWC3 revisions <1.90a have a bug | ||
366 | * when The device fails to connect at SuperSpeed | ||
367 | * and falls back to high-speed mode which causes | ||
368 | * the device to enter in a Connect/Disconnect loop | ||
369 | */ | ||
370 | if (dwc->revision < DWC3_REVISION_190A) | ||
371 | reg |= DWC3_GCTL_U2RSTECN; | ||
372 | |||
373 | dwc3_writel(dwc->regs, DWC3_GCTL, reg); | ||
374 | |||
375 | ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); | ||
290 | if (ret) { | 376 | if (ret) { |
291 | dev_err(dwc->dev, "failed to allocate event buffers\n"); | 377 | dev_err(dwc->dev, "failed to allocate event buffers\n"); |
292 | ret = -ENOMEM; | 378 | ret = -ENOMEM; |
@@ -299,8 +385,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) | |||
299 | goto err1; | 385 | goto err1; |
300 | } | 386 | } |
301 | 387 | ||
302 | dwc3_cache_hwparams(dwc); | ||
303 | |||
304 | return 0; | 388 | return 0; |
305 | 389 | ||
306 | err1: | 390 | err1: |
@@ -320,15 +404,17 @@ static void dwc3_core_exit(struct dwc3 *dwc) | |||
320 | 404 | ||
321 | static int __devinit dwc3_probe(struct platform_device *pdev) | 405 | static int __devinit dwc3_probe(struct platform_device *pdev) |
322 | { | 406 | { |
323 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
324 | struct resource *res; | 407 | struct resource *res; |
325 | struct dwc3 *dwc; | 408 | struct dwc3 *dwc; |
326 | void __iomem *regs; | 409 | |
327 | unsigned int features = id->driver_data; | ||
328 | int ret = -ENOMEM; | 410 | int ret = -ENOMEM; |
329 | int irq; | 411 | int irq; |
412 | |||
413 | void __iomem *regs; | ||
330 | void *mem; | 414 | void *mem; |
331 | 415 | ||
416 | u8 mode; | ||
417 | |||
332 | mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); | 418 | mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); |
333 | if (!mem) { | 419 | if (!mem) { |
334 | dev_err(&pdev->dev, "not enough memory\n"); | 420 | dev_err(&pdev->dev, "not enough memory\n"); |
@@ -343,6 +429,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
343 | goto err1; | 429 | goto err1; |
344 | } | 430 | } |
345 | 431 | ||
432 | dwc->res = res; | ||
433 | |||
346 | res = request_mem_region(res->start, resource_size(res), | 434 | res = request_mem_region(res->start, resource_size(res), |
347 | dev_name(&pdev->dev)); | 435 | dev_name(&pdev->dev)); |
348 | if (!res) { | 436 | if (!res) { |
@@ -370,6 +458,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
370 | dwc->dev = &pdev->dev; | 458 | dwc->dev = &pdev->dev; |
371 | dwc->irq = irq; | 459 | dwc->irq = irq; |
372 | 460 | ||
461 | if (!strncmp("super", maximum_speed, 5)) | ||
462 | dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; | ||
463 | else if (!strncmp("high", maximum_speed, 4)) | ||
464 | dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; | ||
465 | else if (!strncmp("full", maximum_speed, 4)) | ||
466 | dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; | ||
467 | else if (!strncmp("low", maximum_speed, 3)) | ||
468 | dwc->maximum_speed = DWC3_DCFG_LOWSPEED; | ||
469 | else | ||
470 | dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; | ||
471 | |||
373 | pm_runtime_enable(&pdev->dev); | 472 | pm_runtime_enable(&pdev->dev); |
374 | pm_runtime_get_sync(&pdev->dev); | 473 | pm_runtime_get_sync(&pdev->dev); |
375 | pm_runtime_forbid(&pdev->dev); | 474 | pm_runtime_forbid(&pdev->dev); |
@@ -380,13 +479,44 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
380 | goto err3; | 479 | goto err3; |
381 | } | 480 | } |
382 | 481 | ||
383 | if (features & DWC3_HAS_PERIPHERAL) { | 482 | mode = DWC3_MODE(dwc->hwparams.hwparams0); |
483 | |||
484 | switch (mode) { | ||
485 | case DWC3_MODE_DEVICE: | ||
486 | dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); | ||
384 | ret = dwc3_gadget_init(dwc); | 487 | ret = dwc3_gadget_init(dwc); |
385 | if (ret) { | 488 | if (ret) { |
386 | dev_err(&pdev->dev, "failed to initialized gadget\n"); | 489 | dev_err(&pdev->dev, "failed to initialize gadget\n"); |
387 | goto err4; | 490 | goto err4; |
388 | } | 491 | } |
492 | break; | ||
493 | case DWC3_MODE_HOST: | ||
494 | dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); | ||
495 | ret = dwc3_host_init(dwc); | ||
496 | if (ret) { | ||
497 | dev_err(&pdev->dev, "failed to initialize host\n"); | ||
498 | goto err4; | ||
499 | } | ||
500 | break; | ||
501 | case DWC3_MODE_DRD: | ||
502 | dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); | ||
503 | ret = dwc3_host_init(dwc); | ||
504 | if (ret) { | ||
505 | dev_err(&pdev->dev, "failed to initialize host\n"); | ||
506 | goto err4; | ||
507 | } | ||
508 | |||
509 | ret = dwc3_gadget_init(dwc); | ||
510 | if (ret) { | ||
511 | dev_err(&pdev->dev, "failed to initialize gadget\n"); | ||
512 | goto err4; | ||
513 | } | ||
514 | break; | ||
515 | default: | ||
516 | dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); | ||
517 | goto err4; | ||
389 | } | 518 | } |
519 | dwc->mode = mode; | ||
390 | 520 | ||
391 | ret = dwc3_debugfs_init(dwc); | 521 | ret = dwc3_debugfs_init(dwc); |
392 | if (ret) { | 522 | if (ret) { |
@@ -399,8 +529,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
399 | return 0; | 529 | return 0; |
400 | 530 | ||
401 | err5: | 531 | err5: |
402 | if (features & DWC3_HAS_PERIPHERAL) | 532 | switch (mode) { |
533 | case DWC3_MODE_DEVICE: | ||
534 | dwc3_gadget_exit(dwc); | ||
535 | break; | ||
536 | case DWC3_MODE_HOST: | ||
537 | dwc3_host_exit(dwc); | ||
538 | break; | ||
539 | case DWC3_MODE_DRD: | ||
540 | dwc3_host_exit(dwc); | ||
403 | dwc3_gadget_exit(dwc); | 541 | dwc3_gadget_exit(dwc); |
542 | break; | ||
543 | default: | ||
544 | /* do nothing */ | ||
545 | break; | ||
546 | } | ||
404 | 547 | ||
405 | err4: | 548 | err4: |
406 | dwc3_core_exit(dwc); | 549 | dwc3_core_exit(dwc); |
@@ -420,10 +563,8 @@ err0: | |||
420 | 563 | ||
421 | static int __devexit dwc3_remove(struct platform_device *pdev) | 564 | static int __devexit dwc3_remove(struct platform_device *pdev) |
422 | { | 565 | { |
423 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
424 | struct dwc3 *dwc = platform_get_drvdata(pdev); | 566 | struct dwc3 *dwc = platform_get_drvdata(pdev); |
425 | struct resource *res; | 567 | struct resource *res; |
426 | unsigned int features = id->driver_data; | ||
427 | 568 | ||
428 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 569 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
429 | 570 | ||
@@ -432,8 +573,21 @@ static int __devexit dwc3_remove(struct platform_device *pdev) | |||
432 | 573 | ||
433 | dwc3_debugfs_exit(dwc); | 574 | dwc3_debugfs_exit(dwc); |
434 | 575 | ||
435 | if (features & DWC3_HAS_PERIPHERAL) | 576 | switch (dwc->mode) { |
577 | case DWC3_MODE_DEVICE: | ||
578 | dwc3_gadget_exit(dwc); | ||
579 | break; | ||
580 | case DWC3_MODE_HOST: | ||
581 | dwc3_host_exit(dwc); | ||
582 | break; | ||
583 | case DWC3_MODE_DRD: | ||
584 | dwc3_host_exit(dwc); | ||
436 | dwc3_gadget_exit(dwc); | 585 | dwc3_gadget_exit(dwc); |
586 | break; | ||
587 | default: | ||
588 | /* do nothing */ | ||
589 | break; | ||
590 | } | ||
437 | 591 | ||
438 | dwc3_core_exit(dwc); | 592 | dwc3_core_exit(dwc); |
439 | release_mem_region(res->start, resource_size(res)); | 593 | release_mem_region(res->start, resource_size(res)); |
@@ -443,30 +597,15 @@ static int __devexit dwc3_remove(struct platform_device *pdev) | |||
443 | return 0; | 597 | return 0; |
444 | } | 598 | } |
445 | 599 | ||
446 | static const struct platform_device_id dwc3_id_table[] __devinitconst = { | ||
447 | { | ||
448 | .name = "dwc3-omap", | ||
449 | .driver_data = (DWC3_HAS_PERIPHERAL | ||
450 | | DWC3_HAS_XHCI | ||
451 | | DWC3_HAS_OTG), | ||
452 | }, | ||
453 | { | ||
454 | .name = "dwc3-pci", | ||
455 | .driver_data = DWC3_HAS_PERIPHERAL, | ||
456 | }, | ||
457 | { }, /* Terminating Entry */ | ||
458 | }; | ||
459 | MODULE_DEVICE_TABLE(platform, dwc3_id_table); | ||
460 | |||
461 | static struct platform_driver dwc3_driver = { | 600 | static struct platform_driver dwc3_driver = { |
462 | .probe = dwc3_probe, | 601 | .probe = dwc3_probe, |
463 | .remove = __devexit_p(dwc3_remove), | 602 | .remove = __devexit_p(dwc3_remove), |
464 | .driver = { | 603 | .driver = { |
465 | .name = "dwc3", | 604 | .name = "dwc3", |
466 | }, | 605 | }, |
467 | .id_table = dwc3_id_table, | ||
468 | }; | 606 | }; |
469 | 607 | ||
608 | MODULE_ALIAS("platform:dwc3"); | ||
470 | MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); | 609 | MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); |
471 | MODULE_LICENSE("Dual BSD/GPL"); | 610 | MODULE_LICENSE("Dual BSD/GPL"); |
472 | MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); | 611 | MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); |