diff options
-rw-r--r-- | drivers/usb/host/Kconfig | 10 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ohci-platform.c | 194 | ||||
-rw-r--r-- | include/linux/usb/ohci_pdriver.h | 38 |
4 files changed, 247 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 | ||
400 | config 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 | |||
400 | config USB_OHCI_BIG_ENDIAN_DESC | 410 | config 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 | |||
19 | static 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 | |||
39 | static 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 | |||
53 | static 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 | |||
82 | static 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 | |||
131 | err_iounmap: | ||
132 | iounmap(hcd->regs); | ||
133 | err_release_region: | ||
134 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
135 | err_put_hcd: | ||
136 | usb_put_hcd(hcd); | ||
137 | return err; | ||
138 | } | ||
139 | |||
140 | static 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 | |||
155 | static int ohci_platform_suspend(struct device *dev) | ||
156 | { | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static 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 | |||
173 | static const struct platform_device_id ohci_platform_table[] = { | ||
174 | { "ohci-platform", 0 }, | ||
175 | { } | ||
176 | }; | ||
177 | MODULE_DEVICE_TABLE(platform, ohci_platform_table); | ||
178 | |||
179 | static const struct dev_pm_ops ohci_platform_pm_ops = { | ||
180 | .suspend = ohci_platform_suspend, | ||
181 | .resume = ohci_platform_resume, | ||
182 | }; | ||
183 | |||
184 | static 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 | }; | ||
diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h new file mode 100644 index 000000000000..2808f2a9cce8 --- /dev/null +++ b/include/linux/usb/ohci_pdriver.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
12 | * for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software Foundation, | ||
16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | #ifndef __USB_CORE_OHCI_PDRIVER_H | ||
20 | #define __USB_CORE_OHCI_PDRIVER_H | ||
21 | |||
22 | /** | ||
23 | * struct usb_ohci_pdata - platform_data for generic ohci driver | ||
24 | * | ||
25 | * @big_endian_desc: BE descriptors | ||
26 | * @big_endian_mmio: BE registers | ||
27 | * @no_big_frame_no: no big endian frame_no shift | ||
28 | * | ||
29 | * These are general configuration options for the OHCI controller. All of | ||
30 | * these options are activating more or less workarounds for some hardware. | ||
31 | */ | ||
32 | struct usb_ohci_pdata { | ||
33 | unsigned big_endian_desc:1; | ||
34 | unsigned big_endian_mmio:1; | ||
35 | unsigned no_big_frame_no:1; | ||
36 | }; | ||
37 | |||
38 | #endif /* __USB_CORE_OHCI_PDRIVER_H */ | ||