aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/isp1760-if.c
diff options
context:
space:
mode:
authorSebastian Siewior <bigeasy@linutronix.de>2008-04-23 18:37:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-05-02 13:25:50 -0400
commitdb11e47dd7b09b7f76c7eaa236277f23391331e7 (patch)
tree56f2d03ddc18369128cb33b823ebc918af459985 /drivers/usb/host/isp1760-if.c
parent886c35fbcf6fb2eee15687efc2d64d99b6ad9a4a (diff)
USB: ISP1760 HCD driver
This driver has been written from scratch and supports the ISP1760. ISP1761 might (should) work as well but the OTG isn't supported. Also ISO packets are not. However, it works on my little PowerPC board. Signed-off-by: Sebastian Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/isp1760-if.c')
-rw-r--r--drivers/usb/host/isp1760-if.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
new file mode 100644
index 000000000000..73fb2a38f1e4
--- /dev/null
+++ b/drivers/usb/host/isp1760-if.c
@@ -0,0 +1,298 @@
1/*
2 * Glue code for the ISP1760 driver and bus
3 * Currently there is support for
4 * - OpenFirmware
5 * - PCI
6 *
7 * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
8 *
9 */
10
11#include <linux/usb.h>
12#include <linux/io.h>
13
14#include "../core/hcd.h"
15#include "isp1760-hcd.h"
16
17#ifdef CONFIG_USB_ISP1760_OF
18#include <linux/of.h>
19#include <linux/of_platform.h>
20#endif
21
22#ifdef CONFIG_USB_ISP1760_PCI
23#include <linux/pci.h>
24#endif
25
26#ifdef CONFIG_USB_ISP1760_OF
27static int of_isp1760_probe(struct of_device *dev,
28 const struct of_device_id *match)
29{
30 struct usb_hcd *hcd;
31 struct device_node *dp = dev->node;
32 struct resource *res;
33 struct resource memory;
34 struct of_irq oirq;
35 int virq;
36 u64 res_len;
37 int ret;
38
39 ret = of_address_to_resource(dp, 0, &memory);
40 if (ret)
41 return -ENXIO;
42
43 res = request_mem_region(memory.start, memory.end - memory.start + 1,
44 dev->dev.bus_id);
45 if (!res)
46 return -EBUSY;
47
48 res_len = memory.end - memory.start + 1;
49
50 if (of_irq_map_one(dp, 0, &oirq)) {
51 ret = -ENODEV;
52 goto release_reg;
53 }
54
55 virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
56 oirq.size);
57
58 hcd = isp1760_register(memory.start, res_len, virq,
59 IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
60 if (IS_ERR(hcd)) {
61 ret = PTR_ERR(hcd);
62 goto release_reg;
63 }
64
65 dev_set_drvdata(&dev->dev, hcd);
66 return ret;
67
68release_reg:
69 release_mem_region(memory.start, memory.end - memory.start + 1);
70 return ret;
71}
72
73static int of_isp1760_remove(struct of_device *dev)
74{
75 struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
76
77 dev_set_drvdata(&dev->dev, NULL);
78
79 usb_remove_hcd(hcd);
80 iounmap(hcd->regs);
81 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
82 usb_put_hcd(hcd);
83 return 0;
84}
85
86static struct of_device_id of_isp1760_match[] = {
87 {
88 .compatible = "nxp,usb-isp1760",
89 },
90 { },
91};
92MODULE_DEVICE_TABLE(of, of_isp1760_match);
93
94static struct of_platform_driver isp1760_of_driver = {
95 .name = "nxp-isp1760",
96 .match_table = of_isp1760_match,
97 .probe = of_isp1760_probe,
98 .remove = of_isp1760_remove,
99};
100#endif
101
102#ifdef CONFIG_USB_ISP1760_PCI
103static u32 nxp_pci_io_base;
104static u32 iolength;
105static u32 pci_mem_phy0;
106static u32 length;
107static u8 *chip_addr;
108static u8 *iobase;
109
110static int __devinit isp1761_pci_probe(struct pci_dev *dev,
111 const struct pci_device_id *id)
112{
113 u8 latency, limit;
114 __u32 reg_data;
115 int retry_count;
116 int length;
117 int status = 1;
118 struct usb_hcd *hcd;
119
120 if (usb_disabled())
121 return -ENODEV;
122
123 if (pci_enable_device(dev) < 0)
124 return -ENODEV;
125
126 if (!dev->irq)
127 return -ENODEV;
128
129 /* Grab the PLX PCI mem maped port start address we need */
130 nxp_pci_io_base = pci_resource_start(dev, 0);
131 iolength = pci_resource_len(dev, 0);
132
133 if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
134 printk(KERN_ERR "request region #1\n");
135 return -EBUSY;
136 }
137
138 iobase = ioremap_nocache(nxp_pci_io_base, iolength);
139 if (!iobase) {
140 printk(KERN_ERR "ioremap #1\n");
141 release_mem_region(nxp_pci_io_base, iolength);
142 return -ENOMEM;
143 }
144 /* Grab the PLX PCI shared memory of the ISP 1761 we need */
145 pci_mem_phy0 = pci_resource_start(dev, 3);
146 length = pci_resource_len(dev, 3);
147
148 if (length < 0xffff) {
149 printk(KERN_ERR "memory length for this resource is less than "
150 "required\n");
151 release_mem_region(nxp_pci_io_base, iolength);
152 iounmap(iobase);
153 return -ENOMEM;
154 }
155
156 if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
157 printk(KERN_ERR "host controller already in use\n");
158 release_mem_region(nxp_pci_io_base, iolength);
159 iounmap(iobase);
160 return -EBUSY;
161 }
162
163 /* bad pci latencies can contribute to overruns */
164 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
165 if (latency) {
166 pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
167 if (limit && limit < latency)
168 pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
169 }
170
171 /* Try to check whether we can access Scratch Register of
172 * Host Controller or not. The initial PCI access is retried until
173 * local init for the PCI bridge is completed
174 */
175 retry_count = 20;
176 reg_data = 0;
177 while ((reg_data != 0xFACE) && retry_count) {
178 /*by default host is in 16bit mode, so
179 * io operations at this stage must be 16 bit
180 * */
181 writel(0xface, chip_addr + HC_SCRATCH_REG);
182 udelay(100);
183 reg_data = readl(chip_addr + HC_SCRATCH_REG);
184 retry_count--;
185 }
186
187 /* Host Controller presence is detected by writing to scratch register
188 * and reading back and checking the contents are same or not
189 */
190 if (reg_data != 0xFACE) {
191 err("scratch register mismatch %x", reg_data);
192 goto clean;
193 }
194
195 pci_set_master(dev);
196
197 status = readl(iobase + 0x68);
198 status |= 0x900;
199 writel(status, iobase + 0x68);
200
201 dev->dev.dma_mask = NULL;
202 hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
203 IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
204 pci_set_drvdata(dev, hcd);
205 if (!hcd)
206 return 0;
207clean:
208 status = -ENODEV;
209 iounmap(iobase);
210 release_mem_region(pci_mem_phy0, length);
211 release_mem_region(nxp_pci_io_base, iolength);
212 return status;
213}
214static void isp1761_pci_remove(struct pci_dev *dev)
215{
216 struct usb_hcd *hcd;
217
218 hcd = pci_get_drvdata(dev);
219
220 usb_remove_hcd(hcd);
221 iounmap(hcd->regs);
222 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
223 usb_put_hcd(hcd);
224
225 pci_disable_device(dev);
226
227 iounmap(iobase);
228 iounmap(chip_addr);
229
230 release_mem_region(nxp_pci_io_base, iolength);
231 release_mem_region(pci_mem_phy0, length);
232}
233
234static void isp1761_pci_shutdown(struct pci_dev *dev)
235{
236 printk(KERN_ERR "ips1761_pci_shutdown\n");
237}
238
239static const struct pci_device_id isp1760_plx [] = { {
240 /* handle any USB 2.0 EHCI controller */
241 PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
242 .driver_data = 0,
243},
244{ /* end: all zeroes */ }
245};
246MODULE_DEVICE_TABLE(pci, isp1760_plx);
247
248static struct pci_driver isp1761_pci_driver = {
249 .name = "isp1760",
250 .id_table = isp1760_plx,
251 .probe = isp1761_pci_probe,
252 .remove = isp1761_pci_remove,
253 .shutdown = isp1761_pci_shutdown,
254};
255#endif
256
257static int __init isp1760_init(void)
258{
259 int ret;
260
261 init_kmem_once();
262
263#ifdef CONFIG_USB_ISP1760_OF
264 ret = of_register_platform_driver(&isp1760_of_driver);
265 if (ret) {
266 deinit_kmem_cache();
267 return ret;
268 }
269#endif
270#ifdef CONFIG_USB_ISP1760_PCI
271 ret = pci_register_driver(&isp1761_pci_driver);
272 if (ret)
273 goto unreg_of;
274#endif
275 return ret;
276
277#ifdef CONFIG_USB_ISP1760_PCI
278unreg_of:
279#endif
280#ifdef CONFIG_USB_ISP1760_OF
281 of_unregister_platform_driver(&isp1760_of_driver);
282#endif
283 deinit_kmem_cache();
284 return ret;
285}
286module_init(isp1760_init);
287
288static void __exit isp1760_exit(void)
289{
290#ifdef CONFIG_USB_ISP1760_OF
291 of_unregister_platform_driver(&isp1760_of_driver);
292#endif
293#ifdef CONFIG_USB_ISP1760_PCI
294 pci_unregister_driver(&isp1761_pci_driver);
295#endif
296 deinit_kmem_cache();
297}
298module_exit(isp1760_exit);