diff options
-rw-r--r-- | drivers/usb/host/Kconfig | 23 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 20 | ||||
-rw-r--r-- | drivers/usb/host/ohci-ppc-of.c | 232 |
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 | ||
115 | config 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 | |||
123 | config 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 | |||
130 | config 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 | |||
115 | config USB_OHCI_HCD_PCI | 136 | config 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 | |||
22 | static int __devinit | ||
23 | ohci_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 | |||
40 | static 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 | |||
84 | static int __devinit | ||
85 | ohci_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); | ||
147 | err_ioremap: | ||
148 | irq_dispose_mapping(irq); | ||
149 | err_irq: | ||
150 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
151 | err_rmr: | ||
152 | usb_put_hcd(hcd); | ||
153 | |||
154 | return rv; | ||
155 | } | ||
156 | |||
157 | static 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 | |||
175 | static 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 | |||
186 | static 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 | }; | ||
209 | MODULE_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 | |||
217 | static 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 | |||