2b53e487f8759487ceb1cc7c80de6e1d689c4b57
[openembedded.git] /
1 From 944afcaa19737396ed514e3e845a3db2de9377f3 Mon Sep 17 00:00:00 2001
2 From: Sylvain Munaut <tnt@246tNt.com>
3 Date: Wed, 13 Dec 2006 21:03:30 +0100
4 Subject: [PATCH] [PATCH] ohci: Add support for OHCI controller on the of_platform bus
5
6 PPC embedded systems can have a ohci controller builtin. In the
7 new model, it will end up as a driver on the of_platform bus,
8 this patches takes care of them.
9
10 Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
11 Acked-by: David Brownell <dbrownell@users.sourceforge.net>
12 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
13 ---
14  drivers/usb/host/Kconfig       |   23 ++++-
15  drivers/usb/host/ohci-hcd.c    |   20 ++++
16  drivers/usb/host/ohci-ppc-of.c |  232 ++++++++++++++++++++++++++++++++++++++++
17  3 files changed, 274 insertions(+), 1 deletions(-)
18
19 diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
20 index faabce8..c49715d 100644
21 --- a/drivers/usb/host/Kconfig
22 +++ b/drivers/usb/host/Kconfig
23 @@ -107,9 +107,30 @@ config USB_OHCI_HCD_PPC_SOC
24           Enables support for the USB controller on the MPC52xx or
25           STB03xxx processor chip.  If unsure, say Y.
26  
27 +config USB_OHCI_HCD_PPC_OF
28 +       bool "OHCI support for PPC USB controller on OF platform bus"
29 +       depends on USB_OHCI_HCD && PPC_OF
30 +       default y
31 +       ---help---
32 +         Enables support for the USB controller PowerPC present on the
33 +         OpenFirmware platform bus.
34 +
35 +config USB_OHCI_HCD_PPC_OF_BE
36 +       bool "Support big endian HC"
37 +       depends on USB_OHCI_HCD_PPC_OF
38 +       default y
39 +       select USB_OHCI_BIG_ENDIAN_DESC
40 +       select USB_OHCI_BIG_ENDIAN_MMIO
41 +
42 +config USB_OHCI_HCD_PPC_OF_LE
43 +       bool "Support little endian HC"
44 +       depends on USB_OHCI_HCD_PPC_OF
45 +       default n
46 +       select USB_OHCI_LITTLE_ENDIAN
47 +
48  config USB_OHCI_HCD_PCI
49         bool "OHCI support for PCI-bus USB controllers"
50 -       depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
51 +       depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
52         default y
53         select USB_OHCI_LITTLE_ENDIAN
54         ---help---
55 diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
56 index 9926b8f..c6ae1ff 100644
57 --- a/drivers/usb/host/ohci-hcd.c
58 +++ b/drivers/usb/host/ohci-hcd.c
59 @@ -914,8 +914,14 @@ MODULE_LICENSE ("GPL");
60  #endif
61  
62  
63 +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
64 +#include "ohci-ppc-of.c"
65 +#define OF_PLATFORM_DRIVER     ohci_hcd_ppc_of_driver
66 +#endif
67 +
68  #if    !defined(PCI_DRIVER) &&         \
69         !defined(PLATFORM_DRIVER) &&    \
70 +       !defined(OF_PLATFORM_DRIVER) && \
71         !defined(SA1111_DRIVER)
72  #error "missing bus glue for ohci-hcd"
73  #endif
74 @@ -939,6 +945,13 @@ static int __init ohci_hcd_mod_init(void)
75         ls++;
76  #endif
77  
78 +#ifdef OF_PLATFORM_DRIVER
79 +       retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
80 +       if (retval < 0)
81 +               goto error;
82 +       ls++;
83 +#endif
84 +
85  #ifdef SA1111_DRIVER
86         retval = sa1111_driver_register(&SA1111_DRIVER);
87         if (retval < 0)
88 @@ -961,6 +974,10 @@ error:
89         if (ls--)
90                 platform_driver_unregister(&PLATFORM_DRIVER);
91  #endif
92 +#ifdef OF_PLATFORM_DRIVER
93 +       if (ls--)
94 +               of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
95 +#endif
96  #ifdef SA1111_DRIVER
97         if (ls--)
98                 sa1111_driver_unregister(&SA1111_DRIVER);
99 @@ -977,6 +994,9 @@ static void __exit ohci_hcd_mod_exit(void)
100  #ifdef SA1111_DRIVER
101         sa1111_driver_unregister(&SA1111_DRIVER);
102  #endif
103 +#ifdef OF_PLATFORM_DRIVER
104 +       of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
105 +#endif
106  #ifdef PLATFORM_DRIVER
107         platform_driver_unregister(&PLATFORM_DRIVER);
108  #endif
109 diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
110 new file mode 100644
111 index 0000000..84b555b
112 --- /dev/null
113 +++ b/drivers/usb/host/ohci-ppc-of.c
114 @@ -0,0 +1,232 @@
115 +/*
116 + * OHCI HCD (Host Controller Driver) for USB.
117 + *
118 + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
119 + * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
120 + * (C) Copyright 2002 Hewlett-Packard Company
121 + * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
122 + *
123 + * Bus glue for OHCI HC on the of_platform bus
124 + *
125 + * Modified for of_platform bus from ohci-sa1111.c
126 + *
127 + * This file is licenced under the GPL.
128 + */
129 +
130 +#include <linux/signal.h>
131 +
132 +#include <asm/of_platform.h>
133 +#include <asm/prom.h>
134 +
135 +
136 +static int __devinit
137 +ohci_ppc_of_start(struct usb_hcd *hcd)
138 +{
139 +       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
140 +       int             ret;
141 +
142 +       if ((ret = ohci_init(ohci)) < 0)
143 +               return ret;
144 +
145 +       if ((ret = ohci_run(ohci)) < 0) {
146 +               err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
147 +               ohci_stop(hcd);
148 +               return ret;
149 +       }
150 +
151 +       return 0;
152 +}
153 +
154 +static const struct hc_driver ohci_ppc_of_hc_driver = {
155 +       .description =          hcd_name,
156 +       .product_desc =         "OF OHCI",
157 +       .hcd_priv_size =        sizeof(struct ohci_hcd),
158 +
159 +       /*
160 +        * generic hardware linkage
161 +        */
162 +       .irq =                  ohci_irq,
163 +       .flags =                HCD_USB11 | HCD_MEMORY,
164 +
165 +       /*
166 +        * basic lifecycle operations
167 +        */
168 +       .start =                ohci_ppc_of_start,
169 +       .stop =                 ohci_stop,
170 +       .shutdown =             ohci_shutdown,
171 +
172 +       /*
173 +        * managing i/o requests and associated device resources
174 +        */
175 +       .urb_enqueue =          ohci_urb_enqueue,
176 +       .urb_dequeue =          ohci_urb_dequeue,
177 +       .endpoint_disable =     ohci_endpoint_disable,
178 +
179 +       /*
180 +        * scheduling support
181 +        */
182 +       .get_frame_number =     ohci_get_frame,
183 +
184 +       /*
185 +        * root hub support
186 +        */
187 +       .hub_status_data =      ohci_hub_status_data,
188 +       .hub_control =          ohci_hub_control,
189 +       .hub_irq_enable =       ohci_rhsc_enable,
190 +#ifdef CONFIG_PM
191 +       .bus_suspend =          ohci_bus_suspend,
192 +       .bus_resume =           ohci_bus_resume,
193 +#endif
194 +       .start_port_reset =     ohci_start_port_reset,
195 +};
196 +
197 +
198 +static int __devinit
199 +ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
200 +{
201 +       struct device_node *dn = op->node;
202 +       struct usb_hcd *hcd;
203 +       struct ohci_hcd *ohci;
204 +       struct resource res;
205 +       int irq;
206 +
207 +       int rv;
208 +       int is_bigendian;
209 +
210 +       if (usb_disabled())
211 +               return -ENODEV;
212 +
213 +       is_bigendian = 
214 +               device_is_compatible(dn, "ohci-bigendian") ||
215 +               device_is_compatible(dn, "ohci-be");;
216 +
217 +       dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
218 +
219 +       rv = of_address_to_resource(dn, 0, &res);
220 +       if (rv)
221 +               return rv;
222 +
223 +       hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
224 +       if (!hcd)
225 +               return -ENOMEM;
226 +
227 +       hcd->rsrc_start = res.start;
228 +       hcd->rsrc_len = res.end - res.start + 1;
229 +
230 +       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
231 +               printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
232 +               rv = -EBUSY;
233 +               goto err_rmr;
234 +       }
235 +
236 +       irq = irq_of_parse_and_map(dn, 0);
237 +       if (irq == NO_IRQ) {
238 +               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
239 +               rv = -EBUSY;
240 +               goto err_irq;
241 +       }
242 +
243 +       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
244 +       if (!hcd->regs) {
245 +               printk(KERN_ERR __FILE__ ": ioremap failed\n");
246 +               rv = -ENOMEM;
247 +               goto err_ioremap;
248 +       }
249 +
250 +       ohci = hcd_to_ohci(hcd);
251 +       if (is_bigendian)
252 +               ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
253 +
254 +       ohci_hcd_init(ohci);
255 +
256 +       rv = usb_add_hcd(hcd, irq, 0);
257 +       if (rv == 0)
258 +               return 0;
259 +
260 +       iounmap(hcd->regs);
261 +err_ioremap:
262 +       irq_dispose_mapping(irq);
263 +err_irq:
264 +       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
265 +err_rmr:
266 +       usb_put_hcd(hcd);
267 +
268 +       return rv;
269 +}
270 +
271 +static int ohci_hcd_ppc_of_remove(struct of_device *op)
272 +{
273 +       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
274 +       dev_set_drvdata(&op->dev, NULL);
275 +
276 +       dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
277 +
278 +       usb_remove_hcd(hcd);
279 +
280 +       iounmap(hcd->regs);
281 +       irq_dispose_mapping(hcd->irq);
282 +       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
283 +
284 +       usb_put_hcd(hcd);
285 +
286 +       return 0;
287 +}
288 +
289 +static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
290 +{
291 +       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
292 +
293 +        if (hcd->driver->shutdown)
294 +                hcd->driver->shutdown(hcd);
295 +
296 +       return 0;
297 +}
298 +
299 +
300 +static struct of_device_id ohci_hcd_ppc_of_match[] = {
301 +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
302 +       {
303 +               .name = "usb",
304 +               .compatible = "ohci-bigendian",
305 +       },
306 +       {
307 +               .name = "usb",
308 +               .compatible = "ohci-be",
309 +       },
310 +#endif
311 +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
312 +       {
313 +               .name = "usb",
314 +               .compatible = "ohci-littledian",
315 +       },
316 +       {
317 +               .name = "usb",
318 +               .compatible = "ohci-le",
319 +       },
320 +#endif
321 +       {},
322 +};
323 +MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); 
324 +
325 +#if    !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
326 +       !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
327 +#error "No endianess selected for ppc-of-ohci"
328 +#endif
329 +
330 +
331 +static struct of_platform_driver ohci_hcd_ppc_of_driver = {
332 +       .name           = "ppc-of-ohci",
333 +       .match_table    = ohci_hcd_ppc_of_match,
334 +       .probe          = ohci_hcd_ppc_of_probe,
335 +       .remove         = ohci_hcd_ppc_of_remove,
336 +       .shutdown       = ohci_hcd_ppc_of_shutdown,
337 +#ifdef CONFIG_PM
338 +       /*.suspend      = ohci_hcd_ppc_soc_drv_suspend,*/
339 +       /*.resume       = ohci_hcd_ppc_soc_drv_resume,*/
340 +#endif
341 +       .driver         = {
342 +               .name   = "ppc-of-ohci",
343 +               .owner  = THIS_MODULE,
344 +       },
345 +};
346 +
347 -- 
348 1.4.4.2
349