xref: /linux/drivers/usb/dwc3/dwc3-pci.c (revision e4da3fbfbd1de56d2367653e3823e6445e49f8a9)
1 /**
2  * dwc3-pci.c - PCI Specific glue layer
3  *
4  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
5  *
6  * Authors: Felipe Balbi <balbi@ti.com>,
7  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions, and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The names of the above-listed copyright holders may not be used
19  *    to endorse or promote products derived from this software without
20  *    specific prior written permission.
21  *
22  * ALTERNATIVELY, this software may be distributed under the terms of the
23  * GNU General Public License ("GPL") version 2, as published by the Free
24  * Software Foundation.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
28  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
30  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <linux/kernel.h>
40 #include <linux/module.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 
51 struct dwc3_pci {
52 	struct device		*dev;
53 	struct platform_device	*dwc3;
54 };
55 
56 static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
57 
58 static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
59 {
60 	int		id;
61 
62 again:
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 
78 static 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 
91 static 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 
161 err4:
162 	pci_set_drvdata(pci, NULL);
163 	platform_device_put(dwc3);
164 
165 err3:
166 	dwc3_pci_put_device_id(glue, devid);
167 
168 err2:
169 	pci_disable_device(pci);
170 
171 err1:
172 	kfree(pci);
173 
174 err0:
175 	return ret;
176 }
177 
178 static 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 
189 static 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 };
196 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
197 
198 static 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 
205 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
206 MODULE_LICENSE("Dual BSD/GPL");
207 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
208 
209 static int __devinit dwc3_pci_init(void)
210 {
211 	return pci_register_driver(&dwc3_pci_driver);
212 }
213 module_init(dwc3_pci_init);
214 
215 static void __exit dwc3_pci_exit(void)
216 {
217 	pci_unregister_driver(&dwc3_pci_driver);
218 }
219 module_exit(dwc3_pci_exit);
220