diff options
Diffstat (limited to 'drivers/usb/host/isp1760-if.c')
-rw-r--r-- | drivers/usb/host/isp1760-if.c | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c deleted file mode 100644 index 09254a43bc01..000000000000 --- a/drivers/usb/host/isp1760-if.c +++ /dev/null | |||
@@ -1,477 +0,0 @@ | |||
1 | /* | ||
2 | * Glue code for the ISP1760 driver and bus | ||
3 | * Currently there is support for | ||
4 | * - OpenFirmware | ||
5 | * - PCI | ||
6 | * - PDEV (generic platform device centralized driver model) | ||
7 | * | ||
8 | * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/usb.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/usb/isp1760.h> | ||
17 | #include <linux/usb/hcd.h> | ||
18 | |||
19 | #include "isp1760-hcd.h" | ||
20 | |||
21 | #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/of_irq.h> | ||
27 | #include <linux/of_gpio.h> | ||
28 | #endif | ||
29 | |||
30 | #ifdef CONFIG_PCI | ||
31 | #include <linux/pci.h> | ||
32 | #endif | ||
33 | |||
34 | #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) | ||
35 | struct isp1760 { | ||
36 | struct usb_hcd *hcd; | ||
37 | int rst_gpio; | ||
38 | }; | ||
39 | |||
40 | static int of_isp1760_probe(struct platform_device *dev) | ||
41 | { | ||
42 | struct isp1760 *drvdata; | ||
43 | struct device_node *dp = dev->dev.of_node; | ||
44 | struct resource *res; | ||
45 | struct resource memory; | ||
46 | int virq; | ||
47 | resource_size_t res_len; | ||
48 | int ret; | ||
49 | unsigned int devflags = 0; | ||
50 | enum of_gpio_flags gpio_flags; | ||
51 | u32 bus_width = 0; | ||
52 | |||
53 | drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); | ||
54 | if (!drvdata) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | ret = of_address_to_resource(dp, 0, &memory); | ||
58 | if (ret) { | ||
59 | ret = -ENXIO; | ||
60 | goto free_data; | ||
61 | } | ||
62 | |||
63 | res_len = resource_size(&memory); | ||
64 | |||
65 | res = request_mem_region(memory.start, res_len, dev_name(&dev->dev)); | ||
66 | if (!res) { | ||
67 | ret = -EBUSY; | ||
68 | goto free_data; | ||
69 | } | ||
70 | |||
71 | virq = irq_of_parse_and_map(dp, 0); | ||
72 | if (!virq) { | ||
73 | ret = -ENODEV; | ||
74 | goto release_reg; | ||
75 | } | ||
76 | |||
77 | if (of_device_is_compatible(dp, "nxp,usb-isp1761")) | ||
78 | devflags |= ISP1760_FLAG_ISP1761; | ||
79 | |||
80 | /* Some systems wire up only 16 of the 32 data lines */ | ||
81 | of_property_read_u32(dp, "bus-width", &bus_width); | ||
82 | if (bus_width == 16) | ||
83 | devflags |= ISP1760_FLAG_BUS_WIDTH_16; | ||
84 | |||
85 | if (of_get_property(dp, "port1-otg", NULL) != NULL) | ||
86 | devflags |= ISP1760_FLAG_OTG_EN; | ||
87 | |||
88 | if (of_get_property(dp, "analog-oc", NULL) != NULL) | ||
89 | devflags |= ISP1760_FLAG_ANALOG_OC; | ||
90 | |||
91 | if (of_get_property(dp, "dack-polarity", NULL) != NULL) | ||
92 | devflags |= ISP1760_FLAG_DACK_POL_HIGH; | ||
93 | |||
94 | if (of_get_property(dp, "dreq-polarity", NULL) != NULL) | ||
95 | devflags |= ISP1760_FLAG_DREQ_POL_HIGH; | ||
96 | |||
97 | drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags); | ||
98 | if (gpio_is_valid(drvdata->rst_gpio)) { | ||
99 | ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev)); | ||
100 | if (!ret) { | ||
101 | if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) { | ||
102 | devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH; | ||
103 | gpio_direction_output(drvdata->rst_gpio, 0); | ||
104 | } else { | ||
105 | gpio_direction_output(drvdata->rst_gpio, 1); | ||
106 | } | ||
107 | } else { | ||
108 | drvdata->rst_gpio = ret; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | drvdata->hcd = isp1760_register(memory.start, res_len, virq, | ||
113 | IRQF_SHARED, drvdata->rst_gpio, | ||
114 | &dev->dev, dev_name(&dev->dev), | ||
115 | devflags); | ||
116 | if (IS_ERR(drvdata->hcd)) { | ||
117 | ret = PTR_ERR(drvdata->hcd); | ||
118 | goto free_gpio; | ||
119 | } | ||
120 | |||
121 | platform_set_drvdata(dev, drvdata); | ||
122 | return ret; | ||
123 | |||
124 | free_gpio: | ||
125 | if (gpio_is_valid(drvdata->rst_gpio)) | ||
126 | gpio_free(drvdata->rst_gpio); | ||
127 | release_reg: | ||
128 | release_mem_region(memory.start, res_len); | ||
129 | free_data: | ||
130 | kfree(drvdata); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int of_isp1760_remove(struct platform_device *dev) | ||
135 | { | ||
136 | struct isp1760 *drvdata = platform_get_drvdata(dev); | ||
137 | |||
138 | usb_remove_hcd(drvdata->hcd); | ||
139 | iounmap(drvdata->hcd->regs); | ||
140 | release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len); | ||
141 | usb_put_hcd(drvdata->hcd); | ||
142 | |||
143 | if (gpio_is_valid(drvdata->rst_gpio)) | ||
144 | gpio_free(drvdata->rst_gpio); | ||
145 | |||
146 | kfree(drvdata); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static const struct of_device_id of_isp1760_match[] = { | ||
151 | { | ||
152 | .compatible = "nxp,usb-isp1760", | ||
153 | }, | ||
154 | { | ||
155 | .compatible = "nxp,usb-isp1761", | ||
156 | }, | ||
157 | { }, | ||
158 | }; | ||
159 | MODULE_DEVICE_TABLE(of, of_isp1760_match); | ||
160 | |||
161 | static struct platform_driver isp1760_of_driver = { | ||
162 | .driver = { | ||
163 | .name = "nxp-isp1760", | ||
164 | .of_match_table = of_isp1760_match, | ||
165 | }, | ||
166 | .probe = of_isp1760_probe, | ||
167 | .remove = of_isp1760_remove, | ||
168 | }; | ||
169 | #endif | ||
170 | |||
171 | #ifdef CONFIG_PCI | ||
172 | static int isp1761_pci_probe(struct pci_dev *dev, | ||
173 | const struct pci_device_id *id) | ||
174 | { | ||
175 | u8 latency, limit; | ||
176 | __u32 reg_data; | ||
177 | int retry_count; | ||
178 | struct usb_hcd *hcd; | ||
179 | unsigned int devflags = 0; | ||
180 | int ret_status = 0; | ||
181 | |||
182 | resource_size_t pci_mem_phy0; | ||
183 | resource_size_t memlength; | ||
184 | |||
185 | u8 __iomem *chip_addr; | ||
186 | u8 __iomem *iobase; | ||
187 | resource_size_t nxp_pci_io_base; | ||
188 | resource_size_t iolength; | ||
189 | |||
190 | if (usb_disabled()) | ||
191 | return -ENODEV; | ||
192 | |||
193 | if (pci_enable_device(dev) < 0) | ||
194 | return -ENODEV; | ||
195 | |||
196 | if (!dev->irq) | ||
197 | return -ENODEV; | ||
198 | |||
199 | /* Grab the PLX PCI mem maped port start address we need */ | ||
200 | nxp_pci_io_base = pci_resource_start(dev, 0); | ||
201 | iolength = pci_resource_len(dev, 0); | ||
202 | |||
203 | if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { | ||
204 | printk(KERN_ERR "request region #1\n"); | ||
205 | return -EBUSY; | ||
206 | } | ||
207 | |||
208 | iobase = ioremap_nocache(nxp_pci_io_base, iolength); | ||
209 | if (!iobase) { | ||
210 | printk(KERN_ERR "ioremap #1\n"); | ||
211 | ret_status = -ENOMEM; | ||
212 | goto cleanup1; | ||
213 | } | ||
214 | /* Grab the PLX PCI shared memory of the ISP 1761 we need */ | ||
215 | pci_mem_phy0 = pci_resource_start(dev, 3); | ||
216 | memlength = pci_resource_len(dev, 3); | ||
217 | if (memlength < 0xffff) { | ||
218 | printk(KERN_ERR "memory length for this resource is wrong\n"); | ||
219 | ret_status = -ENOMEM; | ||
220 | goto cleanup2; | ||
221 | } | ||
222 | |||
223 | if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) { | ||
224 | printk(KERN_ERR "host controller already in use\n"); | ||
225 | ret_status = -EBUSY; | ||
226 | goto cleanup2; | ||
227 | } | ||
228 | |||
229 | /* map available memory */ | ||
230 | chip_addr = ioremap_nocache(pci_mem_phy0,memlength); | ||
231 | if (!chip_addr) { | ||
232 | printk(KERN_ERR "Error ioremap failed\n"); | ||
233 | ret_status = -ENOMEM; | ||
234 | goto cleanup3; | ||
235 | } | ||
236 | |||
237 | /* bad pci latencies can contribute to overruns */ | ||
238 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); | ||
239 | if (latency) { | ||
240 | pci_read_config_byte(dev, PCI_MAX_LAT, &limit); | ||
241 | if (limit && limit < latency) | ||
242 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); | ||
243 | } | ||
244 | |||
245 | /* Try to check whether we can access Scratch Register of | ||
246 | * Host Controller or not. The initial PCI access is retried until | ||
247 | * local init for the PCI bridge is completed | ||
248 | */ | ||
249 | retry_count = 20; | ||
250 | reg_data = 0; | ||
251 | while ((reg_data != 0xFACE) && retry_count) { | ||
252 | /*by default host is in 16bit mode, so | ||
253 | * io operations at this stage must be 16 bit | ||
254 | * */ | ||
255 | writel(0xface, chip_addr + HC_SCRATCH_REG); | ||
256 | udelay(100); | ||
257 | reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff; | ||
258 | retry_count--; | ||
259 | } | ||
260 | |||
261 | iounmap(chip_addr); | ||
262 | |||
263 | /* Host Controller presence is detected by writing to scratch register | ||
264 | * and reading back and checking the contents are same or not | ||
265 | */ | ||
266 | if (reg_data != 0xFACE) { | ||
267 | dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data); | ||
268 | ret_status = -ENOMEM; | ||
269 | goto cleanup3; | ||
270 | } | ||
271 | |||
272 | pci_set_master(dev); | ||
273 | |||
274 | /* configure PLX PCI chip to pass interrupts */ | ||
275 | #define PLX_INT_CSR_REG 0x68 | ||
276 | reg_data = readl(iobase + PLX_INT_CSR_REG); | ||
277 | reg_data |= 0x900; | ||
278 | writel(reg_data, iobase + PLX_INT_CSR_REG); | ||
279 | |||
280 | dev->dev.dma_mask = NULL; | ||
281 | hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq, | ||
282 | IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev), | ||
283 | devflags); | ||
284 | if (IS_ERR(hcd)) { | ||
285 | ret_status = -ENODEV; | ||
286 | goto cleanup3; | ||
287 | } | ||
288 | |||
289 | /* done with PLX IO access */ | ||
290 | iounmap(iobase); | ||
291 | release_mem_region(nxp_pci_io_base, iolength); | ||
292 | |||
293 | pci_set_drvdata(dev, hcd); | ||
294 | return 0; | ||
295 | |||
296 | cleanup3: | ||
297 | release_mem_region(pci_mem_phy0, memlength); | ||
298 | cleanup2: | ||
299 | iounmap(iobase); | ||
300 | cleanup1: | ||
301 | release_mem_region(nxp_pci_io_base, iolength); | ||
302 | return ret_status; | ||
303 | } | ||
304 | |||
305 | static void isp1761_pci_remove(struct pci_dev *dev) | ||
306 | { | ||
307 | struct usb_hcd *hcd; | ||
308 | |||
309 | hcd = pci_get_drvdata(dev); | ||
310 | |||
311 | usb_remove_hcd(hcd); | ||
312 | iounmap(hcd->regs); | ||
313 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
314 | usb_put_hcd(hcd); | ||
315 | |||
316 | pci_disable_device(dev); | ||
317 | } | ||
318 | |||
319 | static void isp1761_pci_shutdown(struct pci_dev *dev) | ||
320 | { | ||
321 | printk(KERN_ERR "ips1761_pci_shutdown\n"); | ||
322 | } | ||
323 | |||
324 | static const struct pci_device_id isp1760_plx [] = { | ||
325 | { | ||
326 | .class = PCI_CLASS_BRIDGE_OTHER << 8, | ||
327 | .class_mask = ~0, | ||
328 | .vendor = PCI_VENDOR_ID_PLX, | ||
329 | .device = 0x5406, | ||
330 | .subvendor = PCI_VENDOR_ID_PLX, | ||
331 | .subdevice = 0x9054, | ||
332 | }, | ||
333 | { } | ||
334 | }; | ||
335 | MODULE_DEVICE_TABLE(pci, isp1760_plx); | ||
336 | |||
337 | static struct pci_driver isp1761_pci_driver = { | ||
338 | .name = "isp1760", | ||
339 | .id_table = isp1760_plx, | ||
340 | .probe = isp1761_pci_probe, | ||
341 | .remove = isp1761_pci_remove, | ||
342 | .shutdown = isp1761_pci_shutdown, | ||
343 | }; | ||
344 | #endif | ||
345 | |||
346 | static int isp1760_plat_probe(struct platform_device *pdev) | ||
347 | { | ||
348 | int ret = 0; | ||
349 | struct usb_hcd *hcd; | ||
350 | struct resource *mem_res; | ||
351 | struct resource *irq_res; | ||
352 | resource_size_t mem_size; | ||
353 | struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev); | ||
354 | unsigned int devflags = 0; | ||
355 | unsigned long irqflags = IRQF_SHARED; | ||
356 | |||
357 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
358 | if (!mem_res) { | ||
359 | pr_warning("isp1760: Memory resource not available\n"); | ||
360 | ret = -ENODEV; | ||
361 | goto out; | ||
362 | } | ||
363 | mem_size = resource_size(mem_res); | ||
364 | if (!request_mem_region(mem_res->start, mem_size, "isp1760")) { | ||
365 | pr_warning("isp1760: Cannot reserve the memory resource\n"); | ||
366 | ret = -EBUSY; | ||
367 | goto out; | ||
368 | } | ||
369 | |||
370 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
371 | if (!irq_res) { | ||
372 | pr_warning("isp1760: IRQ resource not available\n"); | ||
373 | ret = -ENODEV; | ||
374 | goto cleanup; | ||
375 | } | ||
376 | |||
377 | irqflags |= irq_res->flags & IRQF_TRIGGER_MASK; | ||
378 | |||
379 | if (priv) { | ||
380 | if (priv->is_isp1761) | ||
381 | devflags |= ISP1760_FLAG_ISP1761; | ||
382 | if (priv->bus_width_16) | ||
383 | devflags |= ISP1760_FLAG_BUS_WIDTH_16; | ||
384 | if (priv->port1_otg) | ||
385 | devflags |= ISP1760_FLAG_OTG_EN; | ||
386 | if (priv->analog_oc) | ||
387 | devflags |= ISP1760_FLAG_ANALOG_OC; | ||
388 | if (priv->dack_polarity_high) | ||
389 | devflags |= ISP1760_FLAG_DACK_POL_HIGH; | ||
390 | if (priv->dreq_polarity_high) | ||
391 | devflags |= ISP1760_FLAG_DREQ_POL_HIGH; | ||
392 | } | ||
393 | |||
394 | hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, | ||
395 | irqflags, -ENOENT, | ||
396 | &pdev->dev, dev_name(&pdev->dev), devflags); | ||
397 | |||
398 | platform_set_drvdata(pdev, hcd); | ||
399 | |||
400 | if (IS_ERR(hcd)) { | ||
401 | pr_warning("isp1760: Failed to register the HCD device\n"); | ||
402 | ret = -ENODEV; | ||
403 | goto cleanup; | ||
404 | } | ||
405 | |||
406 | pr_info("ISP1760 USB device initialised\n"); | ||
407 | return ret; | ||
408 | |||
409 | cleanup: | ||
410 | release_mem_region(mem_res->start, mem_size); | ||
411 | out: | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int isp1760_plat_remove(struct platform_device *pdev) | ||
416 | { | ||
417 | struct resource *mem_res; | ||
418 | resource_size_t mem_size; | ||
419 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
420 | |||
421 | usb_remove_hcd(hcd); | ||
422 | |||
423 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
424 | mem_size = resource_size(mem_res); | ||
425 | release_mem_region(mem_res->start, mem_size); | ||
426 | |||
427 | usb_put_hcd(hcd); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static struct platform_driver isp1760_plat_driver = { | ||
433 | .probe = isp1760_plat_probe, | ||
434 | .remove = isp1760_plat_remove, | ||
435 | .driver = { | ||
436 | .name = "isp1760", | ||
437 | }, | ||
438 | }; | ||
439 | |||
440 | static int __init isp1760_init(void) | ||
441 | { | ||
442 | int ret, any_ret = -ENODEV; | ||
443 | |||
444 | init_kmem_once(); | ||
445 | |||
446 | ret = platform_driver_register(&isp1760_plat_driver); | ||
447 | if (!ret) | ||
448 | any_ret = 0; | ||
449 | #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) | ||
450 | ret = platform_driver_register(&isp1760_of_driver); | ||
451 | if (!ret) | ||
452 | any_ret = 0; | ||
453 | #endif | ||
454 | #ifdef CONFIG_PCI | ||
455 | ret = pci_register_driver(&isp1761_pci_driver); | ||
456 | if (!ret) | ||
457 | any_ret = 0; | ||
458 | #endif | ||
459 | |||
460 | if (any_ret) | ||
461 | deinit_kmem_cache(); | ||
462 | return any_ret; | ||
463 | } | ||
464 | module_init(isp1760_init); | ||
465 | |||
466 | static void __exit isp1760_exit(void) | ||
467 | { | ||
468 | platform_driver_unregister(&isp1760_plat_driver); | ||
469 | #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) | ||
470 | platform_driver_unregister(&isp1760_of_driver); | ||
471 | #endif | ||
472 | #ifdef CONFIG_PCI | ||
473 | pci_unregister_driver(&isp1761_pci_driver); | ||
474 | #endif | ||
475 | deinit_kmem_cache(); | ||
476 | } | ||
477 | module_exit(isp1760_exit); | ||