aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/dwc3-pci.c
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-08-19 11:10:58 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-22 19:03:11 -0400
commit72246da40f3719af3bfd104a2365b32537c27d83 (patch)
treedb6a4b139c24340e0d5dccab8d9df0b23ab509ef /drivers/usb/dwc3/dwc3-pci.c
parent500fdf8becb9c8d51970c7ac6a4fa308a5481ebe (diff)
usb: Introduce DesignWare USB3 DRD Driver
The DesignWare USB3 is a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. Several other parameters can be configured like amount of FIFO space, amount of TX and RX endpoints, amount of Host Interrupters, etc. The current driver has been validated with a virtual model of version 1.73a of that core and with an FPGA burned with version 1.83a of the DRD core. We have support for PCIe bus, which is used on FPGA prototyping, and for the OMAP5, more adaptation (or glue) layers can be easily added and the driver is half prepared to handle any possible configuration the HW engineer has chosen considering we have the information on one of the GHWPARAMS registers to do runtime checking of certain features. More runtime checks can, and should, be added in order to make this driver even more flexible with regards to number of endpoints, FIFO sizes, transfer types, etc. While this supports only the device side, for now, we will add support for Host side (xHCI - see the updated series Sebastian has sent [1]) and OTG after we have it all stabilized. [1] http://marc.info/?l=linux-usb&m=131341992020339&w=2 Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/dwc3/dwc3-pci.c')
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
new file mode 100644
index 000000000000..257859564f91
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -0,0 +1,219 @@
1/**
2 * dwc3-pci.c - PCI Specific glue layer
3 *
4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
5 * All rights reserved.
6 *
7 * Authors: Felipe Balbi <balbi@ti.com>,
8 * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions, and the following disclaimer,
15 * without modification.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the above-listed copyright holders may not be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * ALTERNATIVELY, this software may be distributed under the terms of the
24 * GNU General Public License ("GPL") version 2, as published by the Free
25 * Software Foundation.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
28 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
29 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <linux/kernel.h>
41#include <linux/slab.h>
42#include <linux/pci.h>
43#include <linux/platform_device.h>
44
45/* FIXME define these in <linux/pci_ids.h> */
46#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
47#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
48
49#define DWC3_PCI_DEVS_POSSIBLE 32
50
51struct dwc3_pci {
52 struct device *dev;
53 struct platform_device *dwc3;
54};
55
56static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
57
58static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
59{
60 int id;
61
62again:
63 id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
64 if (id < DWC3_PCI_DEVS_POSSIBLE) {
65 int old;
66
67 old = test_and_set_bit(id, dwc3_pci_devs);
68 if (old)
69 goto again;
70 } else {
71 dev_err(glue->dev, "no space for new device\n");
72 id = -ENOMEM;
73 }
74
75 return 0;
76}
77
78static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
79{
80 int ret;
81
82 if (id < 0)
83 return;
84
85 ret = test_bit(id, dwc3_pci_devs);
86 WARN(!ret, "Device: %s\nID %d not in use\n",
87 dev_driver_string(glue->dev), id);
88 clear_bit(id, dwc3_pci_devs);
89}
90
91static int __devinit dwc3_pci_probe(struct pci_dev *pci,
92 const struct pci_device_id *id)
93{
94 struct resource res[2];
95 struct platform_device *dwc3;
96 struct dwc3_pci *glue;
97 int ret = -ENOMEM;
98 int devid;
99
100 glue = kzalloc(sizeof(*glue), GFP_KERNEL);
101 if (!glue) {
102 dev_err(&pci->dev, "not enough memory\n");
103 goto err0;
104 }
105
106 glue->dev = &pci->dev;
107
108 ret = pci_enable_device(pci);
109 if (ret) {
110 dev_err(&pci->dev, "failed to enable pci device\n");
111 goto err1;
112 }
113
114 pci_set_power_state(pci, PCI_D0);
115 pci_set_master(pci);
116
117 devid = dwc3_pci_get_device_id(glue);
118 if (devid < 0)
119 goto err2;
120
121 dwc3 = platform_device_alloc("dwc3-pci", devid);
122 if (!dwc3) {
123 dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
124 goto err3;
125 }
126
127 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
128
129 res[0].start = pci_resource_start(pci, 0);
130 res[0].end = pci_resource_end(pci, 0);
131 res[0].name = "dwc_usb3";
132 res[0].flags = IORESOURCE_MEM;
133
134 res[1].start = pci->irq;
135 res[1].name = "dwc_usb3";
136 res[1].flags = IORESOURCE_IRQ;
137
138 ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
139 if (ret) {
140 dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
141 goto err4;
142 }
143
144 pci_set_drvdata(pci, glue);
145
146 dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
147
148 dwc3->dev.dma_mask = pci->dev.dma_mask;
149 dwc3->dev.dma_parms = pci->dev.dma_parms;
150 dwc3->dev.parent = &pci->dev;
151 glue->dwc3 = dwc3;
152
153 ret = platform_device_add(dwc3);
154 if (ret) {
155 dev_err(&pci->dev, "failed to register dwc3 device\n");
156 goto err4;
157 }
158
159 return 0;
160
161err4:
162 pci_set_drvdata(pci, NULL);
163 platform_device_put(dwc3);
164
165err3:
166 dwc3_pci_put_device_id(glue, devid);
167
168err2:
169 pci_disable_device(pci);
170
171err1:
172 kfree(pci);
173
174err0:
175 return ret;
176}
177
178static void __devexit dwc3_pci_remove(struct pci_dev *pci)
179{
180 struct dwc3_pci *glue = pci_get_drvdata(pci);
181
182 dwc3_pci_put_device_id(glue, glue->dwc3->id);
183 platform_device_unregister(glue->dwc3);
184 pci_set_drvdata(pci, NULL);
185 pci_disable_device(pci);
186 kfree(glue);
187}
188
189static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
190 {
191 PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
192 PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
193 },
194 { } /* Terminating Entry */
195};
196MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
197
198static struct pci_driver dwc3_pci_driver = {
199 .name = "pci-dwc3",
200 .id_table = dwc3_pci_id_table,
201 .probe = dwc3_pci_probe,
202 .remove = __devexit_p(dwc3_pci_remove),
203};
204
205MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
206MODULE_LICENSE("Dual BSD/GPL");
207MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
208
209static int __devinit dwc3_pci_init(void)
210{
211 return pci_register_driver(&dwc3_pci_driver);
212}
213module_init(dwc3_pci_init);
214
215static void __exit dwc3_pci_exit(void)
216{
217 pci_unregister_driver(&dwc3_pci_driver);
218}
219module_exit(dwc3_pci_exit);