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
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.
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>
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(-)
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.
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
32 + Enables support for the USB controller PowerPC present on the
33 + OpenFirmware platform bus.
35 +config USB_OHCI_HCD_PPC_OF_BE
36 + bool "Support big endian HC"
37 + depends on USB_OHCI_HCD_PPC_OF
39 + select USB_OHCI_BIG_ENDIAN_DESC
40 + select USB_OHCI_BIG_ENDIAN_MMIO
42 +config USB_OHCI_HCD_PPC_OF_LE
43 + bool "Support little endian HC"
44 + depends on USB_OHCI_HCD_PPC_OF
46 + select USB_OHCI_LITTLE_ENDIAN
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)
53 select USB_OHCI_LITTLE_ENDIAN
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");
63 +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
64 +#include "ohci-ppc-of.c"
65 +#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
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"
74 @@ -939,6 +945,13 @@ static int __init ohci_hcd_mod_init(void)
78 +#ifdef OF_PLATFORM_DRIVER
79 + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
86 retval = sa1111_driver_register(&SA1111_DRIVER);
88 @@ -961,6 +974,10 @@ error:
90 platform_driver_unregister(&PLATFORM_DRIVER);
92 +#ifdef OF_PLATFORM_DRIVER
94 + of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
98 sa1111_driver_unregister(&SA1111_DRIVER);
99 @@ -977,6 +994,9 @@ static void __exit ohci_hcd_mod_exit(void)
101 sa1111_driver_unregister(&SA1111_DRIVER);
103 +#ifdef OF_PLATFORM_DRIVER
104 + of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
106 #ifdef PLATFORM_DRIVER
107 platform_driver_unregister(&PLATFORM_DRIVER);
109 diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
111 index 0000000..84b555b
113 +++ b/drivers/usb/host/ohci-ppc-of.c
116 + * OHCI HCD (Host Controller Driver) for USB.
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>
123 + * Bus glue for OHCI HC on the of_platform bus
125 + * Modified for of_platform bus from ohci-sa1111.c
127 + * This file is licenced under the GPL.
130 +#include <linux/signal.h>
132 +#include <asm/of_platform.h>
133 +#include <asm/prom.h>
136 +static int __devinit
137 +ohci_ppc_of_start(struct usb_hcd *hcd)
139 + struct ohci_hcd *ohci = hcd_to_ohci(hcd);
142 + if ((ret = ohci_init(ohci)) < 0)
145 + if ((ret = ohci_run(ohci)) < 0) {
146 + err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
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),
160 + * generic hardware linkage
163 + .flags = HCD_USB11 | HCD_MEMORY,
166 + * basic lifecycle operations
168 + .start = ohci_ppc_of_start,
170 + .shutdown = ohci_shutdown,
173 + * managing i/o requests and associated device resources
175 + .urb_enqueue = ohci_urb_enqueue,
176 + .urb_dequeue = ohci_urb_dequeue,
177 + .endpoint_disable = ohci_endpoint_disable,
180 + * scheduling support
182 + .get_frame_number = ohci_get_frame,
187 + .hub_status_data = ohci_hub_status_data,
188 + .hub_control = ohci_hub_control,
189 + .hub_irq_enable = ohci_rhsc_enable,
191 + .bus_suspend = ohci_bus_suspend,
192 + .bus_resume = ohci_bus_resume,
194 + .start_port_reset = ohci_start_port_reset,
198 +static int __devinit
199 +ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
201 + struct device_node *dn = op->node;
202 + struct usb_hcd *hcd;
203 + struct ohci_hcd *ohci;
204 + struct resource res;
210 + if (usb_disabled())
214 + device_is_compatible(dn, "ohci-bigendian") ||
215 + device_is_compatible(dn, "ohci-be");;
217 + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
219 + rv = of_address_to_resource(dn, 0, &res);
223 + hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
227 + hcd->rsrc_start = res.start;
228 + hcd->rsrc_len = res.end - res.start + 1;
230 + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
231 + printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
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");
243 + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
245 + printk(KERN_ERR __FILE__ ": ioremap failed\n");
250 + ohci = hcd_to_ohci(hcd);
252 + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
254 + ohci_hcd_init(ohci);
256 + rv = usb_add_hcd(hcd, irq, 0);
260 + iounmap(hcd->regs);
262 + irq_dispose_mapping(irq);
264 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
271 +static int ohci_hcd_ppc_of_remove(struct of_device *op)
273 + struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
274 + dev_set_drvdata(&op->dev, NULL);
276 + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
278 + usb_remove_hcd(hcd);
280 + iounmap(hcd->regs);
281 + irq_dispose_mapping(hcd->irq);
282 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
289 +static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
291 + struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
293 + if (hcd->driver->shutdown)
294 + hcd->driver->shutdown(hcd);
300 +static struct of_device_id ohci_hcd_ppc_of_match[] = {
301 +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
304 + .compatible = "ohci-bigendian",
308 + .compatible = "ohci-be",
311 +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
314 + .compatible = "ohci-littledian",
318 + .compatible = "ohci-le",
323 +MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
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"
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,
338 + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
339 + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
342 + .name = "ppc-of-ohci",
343 + .owner = THIS_MODULE,