aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-09 15:09:47 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-09 15:09:47 -0500
commit55b81e6f2795484ea8edf5805c95c007cacfa736 (patch)
treec3724975107857fcc03b5dd649c462e4f72397be /drivers/usb/dwc3/core.c
parent5983faf942f260023e547f3c5f38c1033c35cc9b (diff)
parent08e87d0d773dc9ca5faf4c3306e238ed0ea129b0 (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.c209
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
62static char *maximum_speed = "super";
63module_param(maximum_speed, charp, 0);
64MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
65
66/* -------------------------------------------------------------------------- */
67
68#define DWC3_DEVS_POSSIBLE 32
69
70static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE);
71
72int dwc3_get_device_id(void)
73{
74 int id;
75
76again:
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}
91EXPORT_SYMBOL_GPL(dwc3_get_device_id);
92
93void 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}
104EXPORT_SYMBOL_GPL(dwc3_put_device_id);
105
106void 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 */
171static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num, 224static 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
306err1: 390err1:
@@ -320,15 +404,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)
320 404
321static int __devinit dwc3_probe(struct platform_device *pdev) 405static 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
401err5: 531err5:
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
405err4: 548err4:
406 dwc3_core_exit(dwc); 549 dwc3_core_exit(dwc);
@@ -420,10 +563,8 @@ err0:
420 563
421static int __devexit dwc3_remove(struct platform_device *pdev) 564static 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
446static 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};
459MODULE_DEVICE_TABLE(platform, dwc3_id_table);
460
461static struct platform_driver dwc3_driver = { 600static 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
608MODULE_ALIAS("platform:dwc3");
470MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 609MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
471MODULE_LICENSE("Dual BSD/GPL"); 610MODULE_LICENSE("Dual BSD/GPL");
472MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); 611MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");