aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2006-12-13 15:09:55 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 18:44:33 -0500
commit495a678fc62e850d15f860d39faee07ba0a8910c (patch)
tree4f8f12bafc2039fadda6e88efdc1b57729ca31d8
parent5e16fabe5dbcff15de6cdcba406195fe6e4380df (diff)
ohci: Add support for OHCI controller on the of_platform bus
PPC embedded systems can have a ohci controller builtin. In the new model, it will end up as a driver on the of_platform bus, this patches takes care of them. Signed-off-by: Sylvain Munaut <tnt@246tNt.com> Acked-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/Kconfig23
-rw-r--r--drivers/usb/host/ohci-hcd.c20
-rw-r--r--drivers/usb/host/ohci-ppc-of.c232
3 files changed, 274 insertions, 1 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 832599852106..62711870f8ee 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -112,9 +112,30 @@ config USB_OHCI_HCD_PPC_SOC
112 Enables support for the USB controller on the MPC52xx or 112 Enables support for the USB controller on the MPC52xx or
113 STB03xxx processor chip. If unsure, say Y. 113 STB03xxx processor chip. If unsure, say Y.
114 114
115config USB_OHCI_HCD_PPC_OF
116 bool "OHCI support for PPC USB controller on OF platform bus"
117 depends on USB_OHCI_HCD && PPC_OF
118 default y
119 ---help---
120 Enables support for the USB controller PowerPC present on the
121 OpenFirmware platform bus.
122
123config USB_OHCI_HCD_PPC_OF_BE
124 bool "Support big endian HC"
125 depends on USB_OHCI_HCD_PPC_OF
126 default y
127 select USB_OHCI_BIG_ENDIAN_DESC
128 select USB_OHCI_BIG_ENDIAN_MMIO
129
130config USB_OHCI_HCD_PPC_OF_LE
131 bool "Support little endian HC"
132 depends on USB_OHCI_HCD_PPC_OF
133 default n
134 select USB_OHCI_LITTLE_ENDIAN
135
115config USB_OHCI_HCD_PCI 136config USB_OHCI_HCD_PCI
116 bool "OHCI support for PCI-bus USB controllers" 137 bool "OHCI support for PCI-bus USB controllers"
117 depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) 138 depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
118 default y 139 default y
119 select USB_OHCI_LITTLE_ENDIAN 140 select USB_OHCI_LITTLE_ENDIAN
120 ---help--- 141 ---help---
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 3f80003b40bd..8baecbdf0621 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -914,8 +914,14 @@ MODULE_LICENSE ("GPL");
914#endif 914#endif
915 915
916 916
917#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
918#include "ohci-ppc-of.c"
919#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
920#endif
921
917#if !defined(PCI_DRIVER) && \ 922#if !defined(PCI_DRIVER) && \
918 !defined(PLATFORM_DRIVER) && \ 923 !defined(PLATFORM_DRIVER) && \
924 !defined(OF_PLATFORM_DRIVER) && \
919 !defined(SA1111_DRIVER) 925 !defined(SA1111_DRIVER)
920#error "missing bus glue for ohci-hcd" 926#error "missing bus glue for ohci-hcd"
921#endif 927#endif
@@ -939,6 +945,13 @@ static int __init ohci_hcd_mod_init(void)
939 ls++; 945 ls++;
940#endif 946#endif
941 947
948#ifdef OF_PLATFORM_DRIVER
949 retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
950 if (retval < 0)
951 goto error;
952 ls++;
953#endif
954
942#ifdef SA1111_DRIVER 955#ifdef SA1111_DRIVER
943 retval = sa1111_driver_register(&SA1111_DRIVER); 956 retval = sa1111_driver_register(&SA1111_DRIVER);
944 if (retval < 0) 957 if (retval < 0)
@@ -961,6 +974,10 @@ error:
961 if (ls--) 974 if (ls--)
962 platform_driver_unregister(&PLATFORM_DRIVER); 975 platform_driver_unregister(&PLATFORM_DRIVER);
963#endif 976#endif
977#ifdef OF_PLATFORM_DRIVER
978 if (ls--)
979 of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
980#endif
964#ifdef SA1111_DRIVER 981#ifdef SA1111_DRIVER
965 if (ls--) 982 if (ls--)
966 sa1111_driver_unregister(&SA1111_DRIVER); 983 sa1111_driver_unregister(&SA1111_DRIVER);
@@ -977,6 +994,9 @@ static void __exit ohci_hcd_mod_exit(void)
977#ifdef SA1111_DRIVER 994#ifdef SA1111_DRIVER
978 sa1111_driver_unregister(&SA1111_DRIVER); 995 sa1111_driver_unregister(&SA1111_DRIVER);
979#endif 996#endif
997#ifdef OF_PLATFORM_DRIVER
998 of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
999#endif
980#ifdef PLATFORM_DRIVER 1000#ifdef PLATFORM_DRIVER
981 platform_driver_unregister(&PLATFORM_DRIVER); 1001 platform_driver_unregister(&PLATFORM_DRIVER);
982#endif 1002#endif
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644
index 000000000000..08e237c7bc43
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -0,0 +1,232 @@
1/*
2 * OHCI HCD (Host Controller Driver) for USB.
3 *
4 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
5 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
6 * (C) Copyright 2002 Hewlett-Packard Company
7 * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
8 *
9 * Bus glue for OHCI HC on the of_platform bus
10 *
11 * Modified for of_platform bus from ohci-sa1111.c
12 *
13 * This file is licenced under the GPL.
14 */
15
16#include <linux/signal.h>
17
18#include <asm/of_platform.h>
19#include <asm/prom.h>
20
21
22static int __devinit
23ohci_ppc_of_start(struct usb_hcd *hcd)
24{
25 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
26 int ret;
27
28 if ((ret = ohci_init(ohci)) < 0)
29 return ret;
30
31 if ((ret = ohci_run(ohci)) < 0) {
32 err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
33 ohci_stop(hcd);
34 return ret;
35 }
36
37 return 0;
38}
39
40static const struct hc_driver ohci_ppc_of_hc_driver = {
41 .description = hcd_name,
42 .product_desc = "OF OHCI",
43 .hcd_priv_size = sizeof(struct ohci_hcd),
44
45 /*
46 * generic hardware linkage
47 */
48 .irq = ohci_irq,
49 .flags = HCD_USB11 | HCD_MEMORY,
50
51 /*
52 * basic lifecycle operations
53 */
54 .start = ohci_ppc_of_start,
55 .stop = ohci_stop,
56 .shutdown = ohci_shutdown,
57
58 /*
59 * managing i/o requests and associated device resources
60 */
61 .urb_enqueue = ohci_urb_enqueue,
62 .urb_dequeue = ohci_urb_dequeue,
63 .endpoint_disable = ohci_endpoint_disable,
64
65 /*
66 * scheduling support
67 */
68 .get_frame_number = ohci_get_frame,
69
70 /*
71 * root hub support
72 */
73 .hub_status_data = ohci_hub_status_data,
74 .hub_control = ohci_hub_control,
75 .hub_irq_enable = ohci_rhsc_enable,
76#ifdef CONFIG_PM
77 .bus_suspend = ohci_bus_suspend,
78 .bus_resume = ohci_bus_resume,
79#endif
80 .start_port_reset = ohci_start_port_reset,
81};
82
83
84static int __devinit
85ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
86{
87 struct device_node *dn = op->node;
88 struct usb_hcd *hcd;
89 struct ohci_hcd *ohci;
90 struct resource res;
91 int irq;
92
93 int rv;
94 int is_bigendian;
95
96 if (usb_disabled())
97 return -ENODEV;
98
99 is_bigendian =
100 device_is_compatible(dn, "ohci-bigendian") ||
101 device_is_compatible(dn, "ohci-be");
102
103 dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
104
105 rv = of_address_to_resource(dn, 0, &res);
106 if (rv)
107 return rv;
108
109 hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
110 if (!hcd)
111 return -ENOMEM;
112
113 hcd->rsrc_start = res.start;
114 hcd->rsrc_len = res.end - res.start + 1;
115
116 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
117 printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
118 rv = -EBUSY;
119 goto err_rmr;
120 }
121
122 irq = irq_of_parse_and_map(dn, 0);
123 if (irq == NO_IRQ) {
124 printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
125 rv = -EBUSY;
126 goto err_irq;
127 }
128
129 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
130 if (!hcd->regs) {
131 printk(KERN_ERR __FILE__ ": ioremap failed\n");
132 rv = -ENOMEM;
133 goto err_ioremap;
134 }
135
136 ohci = hcd_to_ohci(hcd);
137 if (is_bigendian)
138 ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
139
140 ohci_hcd_init(ohci);
141
142 rv = usb_add_hcd(hcd, irq, 0);
143 if (rv == 0)
144 return 0;
145
146 iounmap(hcd->regs);
147err_ioremap:
148 irq_dispose_mapping(irq);
149err_irq:
150 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
151err_rmr:
152 usb_put_hcd(hcd);
153
154 return rv;
155}
156
157static int ohci_hcd_ppc_of_remove(struct of_device *op)
158{
159 struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
160 dev_set_drvdata(&op->dev, NULL);
161
162 dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
163
164 usb_remove_hcd(hcd);
165
166 iounmap(hcd->regs);
167 irq_dispose_mapping(hcd->irq);
168 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
169
170 usb_put_hcd(hcd);
171
172 return 0;
173}
174
175static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
176{
177 struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
178
179 if (hcd->driver->shutdown)
180 hcd->driver->shutdown(hcd);
181
182 return 0;
183}
184
185
186static struct of_device_id ohci_hcd_ppc_of_match[] = {
187#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
188 {
189 .name = "usb",
190 .compatible = "ohci-bigendian",
191 },
192 {
193 .name = "usb",
194 .compatible = "ohci-be",
195 },
196#endif
197#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
198 {
199 .name = "usb",
200 .compatible = "ohci-littledian",
201 },
202 {
203 .name = "usb",
204 .compatible = "ohci-le",
205 },
206#endif
207 {},
208};
209MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
210
211#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
212 !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
213#error "No endianess selected for ppc-of-ohci"
214#endif
215
216
217static struct of_platform_driver ohci_hcd_ppc_of_driver = {
218 .name = "ppc-of-ohci",
219 .match_table = ohci_hcd_ppc_of_match,
220 .probe = ohci_hcd_ppc_of_probe,
221 .remove = ohci_hcd_ppc_of_remove,
222 .shutdown = ohci_hcd_ppc_of_shutdown,
223#ifdef CONFIG_PM
224 /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
225 /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
226#endif
227 .driver = {
228 .name = "ppc-of-ohci",
229 .owner = THIS_MODULE,
230 },
231};
232