[kernel] Fix gpio_spi_old module for 2.6.35
[openwrt.git] / target / linux / xburst / patches-2.6.34 / 055-ohci.patch
1 From 633d5f445a0149ae32e814f794eae04ae2571c42 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sat, 24 Apr 2010 17:18:49 +0200
4 Subject: [PATCH] Add jz4740 ohci driver
5
6 ---
7  drivers/usb/Kconfig            |    1 +
8  drivers/usb/host/ohci-hcd.c    |    5 +
9  drivers/usb/host/ohci-jz4740.c |  264 ++++++++++++++++++++++++++++++++++++++++
10  3 files changed, 270 insertions(+), 0 deletions(-)
11  create mode 100644 drivers/usb/host/ohci-jz4740.c
12
13 diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
14 index 6a58cb1..46b8dc6 100644
15 --- a/drivers/usb/Kconfig
16 +++ b/drivers/usb/Kconfig
17 @@ -46,6 +46,7 @@ config USB_ARCH_HAS_OHCI
18         default y if PPC_MPC52xx
19         # MIPS:
20         default y if SOC_AU1X00
21 +       default y if SOC_JZ4740
22         # SH:
23         default y if CPU_SUBTYPE_SH7720
24         default y if CPU_SUBTYPE_SH7721
25 diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
26 index afe59be..d4ec333 100644
27 --- a/drivers/usb/host/ohci-hcd.c
28 +++ b/drivers/usb/host/ohci-hcd.c
29 @@ -1090,6 +1090,11 @@ MODULE_LICENSE ("GPL");
30  #define TMIO_OHCI_DRIVER       ohci_hcd_tmio_driver
31  #endif
32  
33 +#ifdef CONFIG_SOC_JZ4740
34 +#include "ohci-jz4740.c"
35 +#define PLATFORM_DRIVER        ohci_hcd_jz4740_driver
36 +#endif
37 +
38  #if    !defined(PCI_DRIVER) &&         \
39         !defined(PLATFORM_DRIVER) &&    \
40         !defined(OF_PLATFORM_DRIVER) && \
41 diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
42 new file mode 100644
43 index 0000000..ac190b4
44 --- /dev/null
45 +++ b/drivers/usb/host/ohci-jz4740.c
46 @@ -0,0 +1,264 @@
47 +
48 +#include <linux/platform_device.h>
49 +#include <linux/clk.h>
50 +#include <linux/regulator/consumer.h>
51 +
52 +struct jz4740_ohci_hcd {
53 +       struct ohci_hcd ohci_hcd;
54 +
55 +       struct regulator *vbus;
56 +       bool vbus_enabled;
57 +       struct clk *clk;
58 +};
59 +
60 +static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd)
61 +{
62 +       return (struct jz4740_ohci_hcd *)(hcd->hcd_priv);
63 +}
64 +
65 +static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci)
66 +{
67 +       return container_of ((void *) jz4740_ohci, struct usb_hcd, hcd_priv);
68 +}
69 +
70 +
71 +static int ohci_jz4740_start(struct usb_hcd *hcd)
72 +{
73 +       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
74 +       int     ret;
75 +
76 +       ret = ohci_init(ohci);
77 +       if (ret < 0)
78 +               return ret;
79 +
80 +       ohci->num_ports = 1;
81 +
82 +       ret = ohci_run(ohci);
83 +       if (ret < 0) {
84 +               dev_err(hcd->self.controller, "Can not start %s",
85 +                       hcd->self.bus_name);
86 +               ohci_stop(hcd);
87 +               return ret;
88 +       }
89 +       return 0;
90 +}
91 +
92 +static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci,
93 +       bool enabled)
94 +{
95 +       int ret = 0;
96 +
97 +    if (enabled && !jz4740_ohci->vbus_enabled) {
98 +               ret = regulator_enable(jz4740_ohci->vbus);
99 +               if (ret)
100 +                       dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller,
101 +                               "Could not power vbus\n");
102 +       } else if(!enabled && jz4740_ohci->vbus_enabled) {
103 +               ret = regulator_disable(jz4740_ohci->vbus);
104 +       }
105 +
106 +       if (ret == 0)
107 +               jz4740_ohci->vbus_enabled = enabled;
108 +
109 +       return ret;
110 +}
111 +
112 +static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
113 +       u16 wIndex, char *buf, u16 wLength)
114 +{
115 +       struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
116 +       int ret;
117 +
118 +       if (jz4740_ohci->vbus) {
119 +               switch (typeReq) {
120 +               case SetHubFeature:
121 +                       if (wValue == USB_PORT_FEAT_POWER)
122 +                               ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true);
123 +                       break;
124 +               case ClearHubFeature:
125 +                       if (wValue == USB_PORT_FEAT_POWER)
126 +                               ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false);
127 +                       break;
128 +               }
129 +       }
130 +
131 +       if (ret)
132 +               return ret;
133 +
134 +       return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
135 +}
136 +
137 +
138 +static const struct hc_driver ohci_jz4740_hc_driver = {
139 +       .description =          hcd_name,
140 +       .product_desc =         "JZ4740 OHCI",
141 +       .hcd_priv_size =        sizeof(struct jz4740_ohci_hcd),
142 +
143 +       /*
144 +        * generic hardware linkage
145 +        */
146 +       .irq =                  ohci_irq,
147 +       .flags =                HCD_USB11 | HCD_MEMORY,
148 +
149 +       /*
150 +        * basic lifecycle operations
151 +        */
152 +       .start =                ohci_jz4740_start,
153 +       .stop =                 ohci_stop,
154 +       .shutdown =             ohci_shutdown,
155 +
156 +       /*
157 +        * managing i/o requests and associated device resources
158 +        */
159 +       .urb_enqueue =          ohci_urb_enqueue,
160 +       .urb_dequeue =          ohci_urb_dequeue,
161 +       .endpoint_disable =     ohci_endpoint_disable,
162 +
163 +       /*
164 +        * scheduling support
165 +        */
166 +       .get_frame_number =     ohci_get_frame,
167 +
168 +       /*
169 +        * root hub support
170 +        */
171 +       .hub_status_data =      ohci_hub_status_data,
172 +       .hub_control =          ohci_jz4740_hub_control,
173 +#ifdef CONFIG_PM
174 +       .bus_suspend =          ohci_bus_suspend,
175 +       .bus_resume =           ohci_bus_resume,
176 +#endif
177 +       .start_port_reset =     ohci_start_port_reset,
178 +};
179 +
180 +
181 +static __devinit int jz4740_ohci_probe(struct platform_device *pdev)
182 +{
183 +       int ret;
184 +       struct usb_hcd *hcd;
185 +       struct jz4740_ohci_hcd *jz4740_ohci;
186 +       struct resource *res;
187 +       int irq;
188 +
189 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
190 +
191 +       if (!res) {
192 +               dev_err(&pdev->dev, "Failed to get platform resource\n");
193 +               return -ENOENT;
194 +       }
195 +
196 +       irq = platform_get_irq(pdev, 0);
197 +       if (irq < 0) {
198 +               dev_err(&pdev->dev, "Failed to get platform irq\n");
199 +               return irq;
200 +       }
201 +
202 +       hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740");
203 +       if (!hcd) {
204 +               dev_err(&pdev->dev, "Failed to create hcd.\n");
205 +               return -ENOMEM;
206 +       }
207 +
208 +       jz4740_ohci = hcd_to_jz4740_hcd(hcd);
209 +
210 +       res = request_mem_region(res->start, resource_size(res), hcd_name);
211 +
212 +       if (!res) {
213 +               dev_err(&pdev->dev, "Failed to request mem region.\n");
214 +               ret = -EBUSY;
215 +               goto err_free;
216 +       }
217 +
218 +       hcd->rsrc_start = res->start;
219 +       hcd->rsrc_len = resource_size(res);
220 +       hcd->regs = ioremap(res->start, resource_size(res));
221 +
222 +       if (!hcd->regs) {
223 +               dev_err(&pdev->dev, "Failed to ioremap registers.\n");
224 +               ret = -EBUSY;
225 +               goto err_release_mem;
226 +       }
227 +
228 +       jz4740_ohci->clk = clk_get(&pdev->dev, "uhc");
229 +       if (IS_ERR(jz4740_ohci->clk)) {
230 +               ret = PTR_ERR(jz4740_ohci->clk);
231 +               dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
232 +               goto err_iounmap;
233 +       }
234 +
235 +       jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus");
236 +       if (IS_ERR(jz4740_ohci->vbus))
237 +               jz4740_ohci->vbus = NULL;
238 +
239 +
240 +       clk_set_rate(jz4740_ohci->clk, 48000000);
241 +       clk_enable(jz4740_ohci->clk);
242 +       if (jz4740_ohci->vbus)
243 +               ohci_jz4740_set_vbus_power(jz4740_ohci, true);
244 +
245 +       platform_set_drvdata(pdev, hcd);
246 +
247 +       ohci_hcd_init(hcd_to_ohci(hcd));
248 +
249 +       ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
250 +       if (ret) {
251 +               dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret);
252 +               goto err_disable;
253 +       }
254 +
255 +       return 0;
256 +
257 +err_disable:
258 +       platform_set_drvdata(pdev, NULL);
259 +       if (jz4740_ohci->vbus) {
260 +               regulator_disable(jz4740_ohci->vbus);
261 +               regulator_put(jz4740_ohci->vbus);
262 +       }
263 +       clk_disable(jz4740_ohci->clk);
264 +
265 +       clk_put(jz4740_ohci->clk);
266 +err_iounmap:
267 +       iounmap(hcd->regs);
268 +err_release_mem:
269 +       release_mem_region(res->start, resource_size(res));
270 +err_free:
271 +       usb_put_hcd(hcd);
272 +
273 +       return ret;
274 +}
275 +
276 +static __devexit int jz4740_ohci_remove(struct platform_device *pdev)
277 +{
278 +       struct usb_hcd *hcd = platform_get_drvdata(pdev);
279 +       struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
280 +
281 +       usb_remove_hcd(hcd);
282 +
283 +       platform_set_drvdata(pdev, NULL);
284 +
285 +       if (jz4740_ohci->vbus) {
286 +               regulator_disable(jz4740_ohci->vbus);
287 +               regulator_put(jz4740_ohci->vbus);
288 +       }
289 +
290 +       clk_disable(jz4740_ohci->clk);
291 +       clk_put(jz4740_ohci->clk);
292 +
293 +       iounmap(hcd->regs);
294 +       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
295 +
296 +       usb_put_hcd(hcd);
297 +
298 +       return 0;
299 +}
300 +
301 +static struct platform_driver ohci_hcd_jz4740_driver = {
302 +       .probe = jz4740_ohci_probe,
303 +       .remove = __devexit_p(jz4740_ohci_remove),
304 +       .driver = {
305 +               .name = "jz4740-ohci",
306 +               .owner = THIS_MODULE,
307 +       },
308 +};
309 +
310 +MODULE_ALIAS("platfrom:jz4740-ohci");
311 -- 
312 1.5.6.5
313