diff options
author | Felipe Balbi <balbi@ti.com> | 2011-10-12 07:08:26 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-12-12 04:48:12 -0500 |
commit | d07e8819a03dc2d1f03f725194ae56544e6c680b (patch) | |
tree | 0715634a05d360ef7939fd0c23befaf11c40919a /drivers/usb/dwc3 | |
parent | 0949e99b05736946cf0ac78e37194be0807e497e (diff) |
usb: dwc3: add xHCI Host support
The Designware USB3 IP can be configured with
an internal xHCI. If we're running on such a
version, let's start the xHCI stack.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/dwc3/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.c | 39 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 9 | ||||
-rw-r--r-- | drivers/usb/dwc3/host.c | 116 |
5 files changed, 164 insertions, 3 deletions
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 3c1d67d324fd..2c05ec9cf352 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig | |||
@@ -2,6 +2,7 @@ config USB_DWC3 | |||
2 | tristate "DesignWare USB3 DRD Core Support" | 2 | tristate "DesignWare USB3 DRD Core Support" |
3 | depends on (USB || USB_GADGET) | 3 | depends on (USB || USB_GADGET) |
4 | select USB_OTG_UTILS | 4 | select USB_OTG_UTILS |
5 | select USB_XHCI_PLATFORM | ||
5 | help | 6 | help |
6 | Say Y or M here if your system has a Dual Role SuperSpeed | 7 | Say Y or M here if your system has a Dual Role SuperSpeed |
7 | USB controller based on the DesignWare USB3 IP Core. | 8 | USB controller based on the DesignWare USB3 IP Core. |
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 593d1dbc465b..0926e71142b9 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile | |||
@@ -4,11 +4,13 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG | |||
4 | obj-$(CONFIG_USB_DWC3) += dwc3.o | 4 | obj-$(CONFIG_USB_DWC3) += dwc3.o |
5 | 5 | ||
6 | dwc3-y := core.o | 6 | dwc3-y := core.o |
7 | dwc3-y += host.o | ||
7 | 8 | ||
8 | ifneq ($(CONFIG_USB_GADGET_DWC3),) | 9 | ifneq ($(CONFIG_USB_GADGET_DWC3),) |
9 | dwc3-y += gadget.o ep0.o | 10 | dwc3-y += gadget.o ep0.o |
10 | endif | 11 | endif |
11 | 12 | ||
13 | |||
12 | ifneq ($(CONFIG_DEBUG_FS),) | 14 | ifneq ($(CONFIG_DEBUG_FS),) |
13 | dwc3-y += debugfs.o | 15 | dwc3-y += debugfs.o |
14 | endif | 16 | endif |
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index df151992e49d..410835e28cf6 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
@@ -350,6 +350,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
350 | goto err1; | 350 | goto err1; |
351 | } | 351 | } |
352 | 352 | ||
353 | dwc->res = res; | ||
354 | |||
353 | res = request_mem_region(res->start, resource_size(res), | 355 | res = request_mem_region(res->start, resource_size(res), |
354 | dev_name(&pdev->dev)); | 356 | dev_name(&pdev->dev)); |
355 | if (!res) { | 357 | if (!res) { |
@@ -401,7 +403,6 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
401 | mode = DWC3_MODE(dwc->hwparams.hwparams0); | 403 | mode = DWC3_MODE(dwc->hwparams.hwparams0); |
402 | 404 | ||
403 | switch (mode) { | 405 | switch (mode) { |
404 | case DWC3_MODE_DRD: | ||
405 | case DWC3_MODE_DEVICE: | 406 | case DWC3_MODE_DEVICE: |
406 | ret = dwc3_gadget_init(dwc); | 407 | ret = dwc3_gadget_init(dwc); |
407 | if (ret) { | 408 | if (ret) { |
@@ -409,6 +410,26 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
409 | goto err4; | 410 | goto err4; |
410 | } | 411 | } |
411 | break; | 412 | break; |
413 | case DWC3_MODE_HOST: | ||
414 | ret = dwc3_host_init(dwc); | ||
415 | if (ret) { | ||
416 | dev_err(&pdev->dev, "failed to initialize host\n"); | ||
417 | goto err4; | ||
418 | } | ||
419 | break; | ||
420 | case DWC3_MODE_DRD: | ||
421 | ret = dwc3_host_init(dwc); | ||
422 | if (ret) { | ||
423 | dev_err(&pdev->dev, "failed to initialize host\n"); | ||
424 | goto err4; | ||
425 | } | ||
426 | |||
427 | ret = dwc3_gadget_init(dwc); | ||
428 | if (ret) { | ||
429 | dev_err(&pdev->dev, "failed to initialize gadget\n"); | ||
430 | goto err4; | ||
431 | } | ||
432 | break; | ||
412 | default: | 433 | default: |
413 | dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); | 434 | dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); |
414 | goto err4; | 435 | goto err4; |
@@ -427,10 +448,16 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
427 | 448 | ||
428 | err5: | 449 | err5: |
429 | switch (mode) { | 450 | switch (mode) { |
430 | case DWC3_MODE_DRD: | ||
431 | case DWC3_MODE_DEVICE: | 451 | case DWC3_MODE_DEVICE: |
432 | dwc3_gadget_exit(dwc); | 452 | dwc3_gadget_exit(dwc); |
433 | break; | 453 | break; |
454 | case DWC3_MODE_HOST: | ||
455 | dwc3_host_exit(dwc); | ||
456 | break; | ||
457 | case DWC3_MODE_DRD: | ||
458 | dwc3_host_exit(dwc); | ||
459 | dwc3_gadget_exit(dwc); | ||
460 | break; | ||
434 | default: | 461 | default: |
435 | /* do nothing */ | 462 | /* do nothing */ |
436 | break; | 463 | break; |
@@ -465,10 +492,16 @@ static int __devexit dwc3_remove(struct platform_device *pdev) | |||
465 | dwc3_debugfs_exit(dwc); | 492 | dwc3_debugfs_exit(dwc); |
466 | 493 | ||
467 | switch (dwc->mode) { | 494 | switch (dwc->mode) { |
468 | case DWC3_MODE_DRD: | ||
469 | case DWC3_MODE_DEVICE: | 495 | case DWC3_MODE_DEVICE: |
470 | dwc3_gadget_exit(dwc); | 496 | dwc3_gadget_exit(dwc); |
471 | break; | 497 | break; |
498 | case DWC3_MODE_HOST: | ||
499 | dwc3_host_exit(dwc); | ||
500 | break; | ||
501 | case DWC3_MODE_DRD: | ||
502 | dwc3_host_exit(dwc); | ||
503 | dwc3_gadget_exit(dwc); | ||
504 | break; | ||
472 | default: | 505 | default: |
473 | /* do nothing */ | 506 | /* do nothing */ |
474 | break; | 507 | break; |
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a3ef8f34bf77..a77554373224 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h | |||
@@ -41,6 +41,7 @@ | |||
41 | 41 | ||
42 | #include <linux/device.h> | 42 | #include <linux/device.h> |
43 | #include <linux/spinlock.h> | 43 | #include <linux/spinlock.h> |
44 | #include <linux/ioport.h> | ||
44 | #include <linux/list.h> | 45 | #include <linux/list.h> |
45 | #include <linux/dma-mapping.h> | 46 | #include <linux/dma-mapping.h> |
46 | #include <linux/mm.h> | 47 | #include <linux/mm.h> |
@@ -560,6 +561,7 @@ struct dwc3_hwparams { | |||
560 | * @ep0_bounce_addr: dma address of ep0_bounce | 561 | * @ep0_bounce_addr: dma address of ep0_bounce |
561 | * @lock: for synchronizing | 562 | * @lock: for synchronizing |
562 | * @dev: pointer to our struct device | 563 | * @dev: pointer to our struct device |
564 | * @xhci: pointer to our xHCI child | ||
563 | * @event_buffer_list: a list of event buffers | 565 | * @event_buffer_list: a list of event buffers |
564 | * @gadget: device side representation of the peripheral controller | 566 | * @gadget: device side representation of the peripheral controller |
565 | * @gadget_driver: pointer to the gadget driver | 567 | * @gadget_driver: pointer to the gadget driver |
@@ -598,6 +600,9 @@ struct dwc3 { | |||
598 | spinlock_t lock; | 600 | spinlock_t lock; |
599 | struct device *dev; | 601 | struct device *dev; |
600 | 602 | ||
603 | struct platform_device *xhci; | ||
604 | struct resource *res; | ||
605 | |||
601 | struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_MAX]; | 606 | struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_MAX]; |
602 | struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; | 607 | struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; |
603 | 608 | ||
@@ -782,4 +787,8 @@ union dwc3_event { | |||
782 | #define DWC3_HAS_XHCI BIT(1) | 787 | #define DWC3_HAS_XHCI BIT(1) |
783 | #define DWC3_HAS_OTG BIT(3) | 788 | #define DWC3_HAS_OTG BIT(3) |
784 | 789 | ||
790 | /* prototypes */ | ||
791 | int dwc3_host_init(struct dwc3 *dwc); | ||
792 | void dwc3_host_exit(struct dwc3 *dwc); | ||
793 | |||
785 | #endif /* __DRIVERS_USB_DWC3_CORE_H */ | 794 | #endif /* __DRIVERS_USB_DWC3_CORE_H */ |
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c new file mode 100644 index 000000000000..9b300a26fceb --- /dev/null +++ b/drivers/usb/dwc3/host.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /** | ||
2 | * host.c - DesignWare USB3 DRD Controller Host Glue | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Authors: Felipe Balbi <balbi@ti.com>, | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions, and the following disclaimer, | ||
13 | * without modification. | ||
14 | * 2. Redistributions in binary form must reproduce the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer in the | ||
16 | * documentation and/or other materials provided with the distribution. | ||
17 | * 3. The names of the above-listed copyright holders may not be used | ||
18 | * to endorse or promote products derived from this software without | ||
19 | * specific prior written permission. | ||
20 | * | ||
21 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
22 | * GNU General Public License ("GPL") version 2, as published by the Free | ||
23 | * Software Foundation. | ||
24 | * | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
26 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
27 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
29 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
30 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
31 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
32 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
36 | */ | ||
37 | |||
38 | #include <linux/module.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/spinlock.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | #include <linux/pm_runtime.h> | ||
44 | #include <linux/interrupt.h> | ||
45 | #include <linux/ioport.h> | ||
46 | #include <linux/io.h> | ||
47 | #include <linux/list.h> | ||
48 | #include <linux/delay.h> | ||
49 | #include <linux/dma-mapping.h> | ||
50 | |||
51 | #include "core.h" | ||
52 | #include "io.h" | ||
53 | |||
54 | #include "debug.h" | ||
55 | |||
56 | static struct resource generic_resources[] = { | ||
57 | { | ||
58 | .flags = IORESOURCE_IRQ, | ||
59 | }, | ||
60 | { | ||
61 | .flags = IORESOURCE_MEM, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | int dwc3_host_init(struct dwc3 *dwc) | ||
66 | { | ||
67 | struct platform_device *xhci; | ||
68 | int ret; | ||
69 | |||
70 | xhci = platform_device_alloc("xhci", -1); | ||
71 | if (!xhci) { | ||
72 | dev_err(dwc->dev, "couldn't allocate xHCI device\n"); | ||
73 | ret = -ENOMEM; | ||
74 | goto err0; | ||
75 | } | ||
76 | |||
77 | dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); | ||
78 | |||
79 | xhci->dev.parent = dwc->dev; | ||
80 | xhci->dev.dma_mask = dwc->dev->dma_mask; | ||
81 | xhci->dev.dma_parms = dwc->dev->dma_parms; | ||
82 | |||
83 | dwc->xhci = xhci; | ||
84 | |||
85 | /* setup resources */ | ||
86 | generic_resources[0].start = dwc->irq; | ||
87 | |||
88 | generic_resources[1].start = dwc->res->start; | ||
89 | generic_resources[1].end = dwc->res->start + 0x7fff; | ||
90 | |||
91 | ret = platform_device_add_resources(xhci, generic_resources, | ||
92 | ARRAY_SIZE(generic_resources)); | ||
93 | if (ret) { | ||
94 | dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); | ||
95 | goto err1; | ||
96 | } | ||
97 | |||
98 | ret = platform_device_add(xhci); | ||
99 | if (ret) { | ||
100 | dev_err(dwc->dev, "failed to register xHCI device\n"); | ||
101 | goto err1; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | |||
106 | err1: | ||
107 | platform_device_put(xhci); | ||
108 | |||
109 | err0: | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | void dwc3_host_exit(struct dwc3 *dwc) | ||
114 | { | ||
115 | platform_device_unregister(dwc->xhci); | ||
116 | } | ||