aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2012-03-12 20:04:47 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-15 15:41:58 -0400
commitfa3364b5a2d79b0c94a912b371c92bd3d06bc8fb (patch)
treec1fbe64425df32ad3f821083bf8a2aebd675f208 /drivers
parent57e596f3af88ef52dea9640ed5e34ecd38893a02 (diff)
USB: OHCI: Add a generic platform device driver
This adds a generic driver for platform devices. It works like the PCI driver and is based on it. This is for devices which do not have an own bus but their OHCI controller works like a PCI controller. It will be used for the Broadcom bcma and ssb USB OHCI controller. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/Kconfig10
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-platform.c194
3 files changed, 209 insertions, 0 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b17995829514..1dd6e13077a4 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -397,6 +397,16 @@ config USB_CNS3XXX_OHCI
397 Enable support for the CNS3XXX SOC's on-chip OHCI controller. 397 Enable support for the CNS3XXX SOC's on-chip OHCI controller.
398 It is needed for low-speed USB 1.0 device support. 398 It is needed for low-speed USB 1.0 device support.
399 399
400config USB_OHCI_HCD_PLATFORM
401 bool "Generic OHCI driver for a platform device"
402 depends on USB_OHCI_HCD && EXPERIMENTAL
403 default n
404 ---help---
405 Adds an OHCI host driver for a generic platform device, which
406 provieds a memory space and an irq.
407
408 If unsure, say N.
409
400config USB_OHCI_BIG_ENDIAN_DESC 410config USB_OHCI_BIG_ENDIAN_DESC
401 bool 411 bool
402 depends on USB_OHCI_HCD 412 depends on USB_OHCI_HCD
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index c1c550f2a517..ddd54c70d0fd 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1121,6 +1121,11 @@ MODULE_LICENSE ("GPL");
1121#define PLATFORM_DRIVER ohci_xls_driver 1121#define PLATFORM_DRIVER ohci_xls_driver
1122#endif 1122#endif
1123 1123
1124#ifdef CONFIG_USB_OHCI_HCD_PLATFORM
1125#include "ohci-platform.c"
1126#define PLATFORM_DRIVER ohci_platform_driver
1127#endif
1128
1124#if !defined(PCI_DRIVER) && \ 1129#if !defined(PCI_DRIVER) && \
1125 !defined(PLATFORM_DRIVER) && \ 1130 !defined(PLATFORM_DRIVER) && \
1126 !defined(OMAP1_PLATFORM_DRIVER) && \ 1131 !defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
new file mode 100644
index 000000000000..ec5c6791c8b4
--- /dev/null
+++ b/drivers/usb/host/ohci-platform.c
@@ -0,0 +1,194 @@
1/*
2 * Generic platform ohci driver
3 *
4 * Copyright 2007 Michael Buesch <m@bues.ch>
5 * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
6 *
7 * Derived from the OCHI-SSB driver
8 * Derived from the OHCI-PCI driver
9 * Copyright 1999 Roman Weissgaerber
10 * Copyright 2000-2002 David Brownell
11 * Copyright 1999 Linus Torvalds
12 * Copyright 1999 Gregory P. Smith
13 *
14 * Licensed under the GNU/GPL. See COPYING for details.
15 */
16#include <linux/platform_device.h>
17#include <linux/usb/ohci_pdriver.h>
18
19static int ohci_platform_reset(struct usb_hcd *hcd)
20{
21 struct platform_device *pdev = to_platform_device(hcd->self.controller);
22 struct usb_ohci_pdata *pdata = pdev->dev.platform_data;
23 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
24 int err;
25
26 if (pdata->big_endian_desc)
27 ohci->flags |= OHCI_QUIRK_BE_DESC;
28 if (pdata->big_endian_mmio)
29 ohci->flags |= OHCI_QUIRK_BE_MMIO;
30 if (pdata->no_big_frame_no)
31 ohci->flags |= OHCI_QUIRK_FRAME_NO;
32
33 ohci_hcd_init(ohci);
34 err = ohci_init(ohci);
35
36 return err;
37}
38
39static int ohci_platform_start(struct usb_hcd *hcd)
40{
41 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
42 int err;
43
44 err = ohci_run(ohci);
45 if (err < 0) {
46 ohci_err(ohci, "can't start\n");
47 ohci_stop(hcd);
48 }
49
50 return err;
51}
52
53static const struct hc_driver ohci_platform_hc_driver = {
54 .description = hcd_name,
55 .product_desc = "Generic Platform OHCI Controller",
56 .hcd_priv_size = sizeof(struct ohci_hcd),
57
58 .irq = ohci_irq,
59 .flags = HCD_MEMORY | HCD_USB11,
60
61 .reset = ohci_platform_reset,
62 .start = ohci_platform_start,
63 .stop = ohci_stop,
64 .shutdown = ohci_shutdown,
65
66 .urb_enqueue = ohci_urb_enqueue,
67 .urb_dequeue = ohci_urb_dequeue,
68 .endpoint_disable = ohci_endpoint_disable,
69
70 .get_frame_number = ohci_get_frame,
71
72 .hub_status_data = ohci_hub_status_data,
73 .hub_control = ohci_hub_control,
74#ifdef CONFIG_PM
75 .bus_suspend = ohci_bus_suspend,
76 .bus_resume = ohci_bus_resume,
77#endif
78
79 .start_port_reset = ohci_start_port_reset,
80};
81
82static int __devinit ohci_platform_probe(struct platform_device *dev)
83{
84 struct usb_hcd *hcd;
85 struct resource *res_mem;
86 int irq;
87 int err = -ENOMEM;
88
89 BUG_ON(!dev->dev.platform_data);
90
91 if (usb_disabled())
92 return -ENODEV;
93
94 irq = platform_get_irq(dev, 0);
95 if (irq < 0) {
96 pr_err("no irq provieded");
97 return irq;
98 }
99
100 res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
101 if (!res_mem) {
102 pr_err("no memory recourse provieded");
103 return -ENXIO;
104 }
105
106 hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
107 dev_name(&dev->dev));
108 if (!hcd)
109 return -ENOMEM;
110
111 hcd->rsrc_start = res_mem->start;
112 hcd->rsrc_len = resource_size(res_mem);
113
114 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
115 pr_err("controller already in use");
116 err = -EBUSY;
117 goto err_put_hcd;
118 }
119
120 hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
121 if (!hcd->regs)
122 goto err_release_region;
123 err = usb_add_hcd(hcd, irq, IRQF_SHARED);
124 if (err)
125 goto err_iounmap;
126
127 platform_set_drvdata(dev, hcd);
128
129 return err;
130
131err_iounmap:
132 iounmap(hcd->regs);
133err_release_region:
134 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
135err_put_hcd:
136 usb_put_hcd(hcd);
137 return err;
138}
139
140static int __devexit ohci_platform_remove(struct platform_device *dev)
141{
142 struct usb_hcd *hcd = platform_get_drvdata(dev);
143
144 usb_remove_hcd(hcd);
145 iounmap(hcd->regs);
146 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
147 usb_put_hcd(hcd);
148 platform_set_drvdata(dev, NULL);
149
150 return 0;
151}
152
153#ifdef CONFIG_PM
154
155static int ohci_platform_suspend(struct device *dev)
156{
157 return 0;
158}
159
160static int ohci_platform_resume(struct device *dev)
161{
162 struct usb_hcd *hcd = dev_get_drvdata(dev);
163
164 ohci_finish_controller_resume(hcd);
165 return 0;
166}
167
168#else /* !CONFIG_PM */
169#define ohci_platform_suspend NULL
170#define ohci_platform_resume NULL
171#endif /* CONFIG_PM */
172
173static const struct platform_device_id ohci_platform_table[] = {
174 { "ohci-platform", 0 },
175 { }
176};
177MODULE_DEVICE_TABLE(platform, ohci_platform_table);
178
179static const struct dev_pm_ops ohci_platform_pm_ops = {
180 .suspend = ohci_platform_suspend,
181 .resume = ohci_platform_resume,
182};
183
184static struct platform_driver ohci_platform_driver = {
185 .id_table = ohci_platform_table,
186 .probe = ohci_platform_probe,
187 .remove = __devexit_p(ohci_platform_remove),
188 .shutdown = usb_hcd_platform_shutdown,
189 .driver = {
190 .owner = THIS_MODULE,
191 .name = "ohci-platform",
192 .pm = &ohci_platform_pm_ops,
193 }
194};