diff options
Diffstat (limited to 'drivers/usb/host/ohci-sa1111.c')
-rw-r--r-- | drivers/usb/host/ohci-sa1111.c | 297 |
1 files changed, 142 insertions, 155 deletions
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 4bde4f9821ba..e1004fb37bd9 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c | |||
@@ -16,29 +16,115 @@ | |||
16 | #include <mach/hardware.h> | 16 | #include <mach/hardware.h> |
17 | #include <asm/mach-types.h> | 17 | #include <asm/mach-types.h> |
18 | #include <mach/assabet.h> | 18 | #include <mach/assabet.h> |
19 | #include <mach/badge4.h> | ||
20 | #include <asm/hardware/sa1111.h> | 19 | #include <asm/hardware/sa1111.h> |
21 | 20 | ||
22 | #ifndef CONFIG_SA1111 | 21 | #ifndef CONFIG_SA1111 |
23 | #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." | 22 | #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." |
24 | #endif | 23 | #endif |
25 | 24 | ||
26 | extern int usb_disabled(void); | 25 | #define USB_STATUS 0x0118 |
26 | #define USB_RESET 0x011c | ||
27 | #define USB_IRQTEST 0x0120 | ||
28 | |||
29 | #define USB_RESET_FORCEIFRESET (1 << 0) | ||
30 | #define USB_RESET_FORCEHCRESET (1 << 1) | ||
31 | #define USB_RESET_CLKGENRESET (1 << 2) | ||
32 | #define USB_RESET_SIMSCALEDOWN (1 << 3) | ||
33 | #define USB_RESET_USBINTTEST (1 << 4) | ||
34 | #define USB_RESET_SLEEPSTBYEN (1 << 5) | ||
35 | #define USB_RESET_PWRSENSELOW (1 << 6) | ||
36 | #define USB_RESET_PWRCTRLLOW (1 << 7) | ||
37 | |||
38 | #define USB_STATUS_IRQHCIRMTWKUP (1 << 7) | ||
39 | #define USB_STATUS_IRQHCIBUFFACC (1 << 8) | ||
40 | #define USB_STATUS_NIRQHCIM (1 << 9) | ||
41 | #define USB_STATUS_NHCIMFCLR (1 << 10) | ||
42 | #define USB_STATUS_USBPWRSENSE (1 << 11) | ||
27 | 43 | ||
28 | /*-------------------------------------------------------------------------*/ | 44 | #if 0 |
45 | static void dump_hci_status(struct usb_hcd *hcd, const char *label) | ||
46 | { | ||
47 | unsigned long status = sa1111_readl(hcd->regs + USB_STATUS); | ||
48 | |||
49 | dbg("%s USB_STATUS = { %s%s%s%s%s}", label, | ||
50 | ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), | ||
51 | ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), | ||
52 | ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), | ||
53 | ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), | ||
54 | ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); | ||
55 | } | ||
56 | #endif | ||
29 | 57 | ||
30 | static void sa1111_start_hc(struct sa1111_dev *dev) | 58 | static int ohci_sa1111_reset(struct usb_hcd *hcd) |
31 | { | 59 | { |
32 | unsigned int usb_rst = 0; | 60 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
61 | |||
62 | ohci_hcd_init(ohci); | ||
63 | return ohci_init(ohci); | ||
64 | } | ||
33 | 65 | ||
34 | printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n", | 66 | static int __devinit ohci_sa1111_start(struct usb_hcd *hcd) |
35 | __FILE__); | 67 | { |
68 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
69 | int ret; | ||
36 | 70 | ||
37 | #ifdef CONFIG_SA1100_BADGE4 | 71 | ret = ohci_run(ohci); |
38 | if (machine_is_badge4()) { | 72 | if (ret < 0) { |
39 | badge4_set_5V(BADGE4_5V_USB, 1); | 73 | ohci_err(ohci, "can't start\n"); |
74 | ohci_stop(hcd); | ||
40 | } | 75 | } |
76 | return ret; | ||
77 | } | ||
78 | |||
79 | static const struct hc_driver ohci_sa1111_hc_driver = { | ||
80 | .description = hcd_name, | ||
81 | .product_desc = "SA-1111 OHCI", | ||
82 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
83 | |||
84 | /* | ||
85 | * generic hardware linkage | ||
86 | */ | ||
87 | .irq = ohci_irq, | ||
88 | .flags = HCD_USB11 | HCD_MEMORY, | ||
89 | |||
90 | /* | ||
91 | * basic lifecycle operations | ||
92 | */ | ||
93 | .reset = ohci_sa1111_reset, | ||
94 | .start = ohci_sa1111_start, | ||
95 | .stop = ohci_stop, | ||
96 | .shutdown = ohci_shutdown, | ||
97 | |||
98 | /* | ||
99 | * managing i/o requests and associated device resources | ||
100 | */ | ||
101 | .urb_enqueue = ohci_urb_enqueue, | ||
102 | .urb_dequeue = ohci_urb_dequeue, | ||
103 | .endpoint_disable = ohci_endpoint_disable, | ||
104 | |||
105 | /* | ||
106 | * scheduling support | ||
107 | */ | ||
108 | .get_frame_number = ohci_get_frame, | ||
109 | |||
110 | /* | ||
111 | * root hub support | ||
112 | */ | ||
113 | .hub_status_data = ohci_hub_status_data, | ||
114 | .hub_control = ohci_hub_control, | ||
115 | #ifdef CONFIG_PM | ||
116 | .bus_suspend = ohci_bus_suspend, | ||
117 | .bus_resume = ohci_bus_resume, | ||
41 | #endif | 118 | #endif |
119 | .start_port_reset = ohci_start_port_reset, | ||
120 | }; | ||
121 | |||
122 | static int sa1111_start_hc(struct sa1111_dev *dev) | ||
123 | { | ||
124 | unsigned int usb_rst = 0; | ||
125 | int ret; | ||
126 | |||
127 | dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n"); | ||
42 | 128 | ||
43 | if (machine_is_xp860() || | 129 | if (machine_is_xp860() || |
44 | machine_has_neponset() || | 130 | machine_has_neponset() || |
@@ -51,220 +137,121 @@ static void sa1111_start_hc(struct sa1111_dev *dev) | |||
51 | * host controller in reset. | 137 | * host controller in reset. |
52 | */ | 138 | */ |
53 | sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, | 139 | sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, |
54 | dev->mapbase + SA1111_USB_RESET); | 140 | dev->mapbase + USB_RESET); |
55 | 141 | ||
56 | /* | 142 | /* |
57 | * Now, carefully enable the USB clock, and take | 143 | * Now, carefully enable the USB clock, and take |
58 | * the USB host controller out of reset. | 144 | * the USB host controller out of reset. |
59 | */ | 145 | */ |
60 | sa1111_enable_device(dev); | 146 | ret = sa1111_enable_device(dev); |
61 | udelay(11); | 147 | if (ret == 0) { |
62 | sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET); | 148 | udelay(11); |
149 | sa1111_writel(usb_rst, dev->mapbase + USB_RESET); | ||
150 | } | ||
151 | |||
152 | return ret; | ||
63 | } | 153 | } |
64 | 154 | ||
65 | static void sa1111_stop_hc(struct sa1111_dev *dev) | 155 | static void sa1111_stop_hc(struct sa1111_dev *dev) |
66 | { | 156 | { |
67 | unsigned int usb_rst; | 157 | unsigned int usb_rst; |
68 | printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n", | 158 | |
69 | __FILE__); | 159 | dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n"); |
70 | 160 | ||
71 | /* | 161 | /* |
72 | * Put the USB host controller into reset. | 162 | * Put the USB host controller into reset. |
73 | */ | 163 | */ |
74 | usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET); | 164 | usb_rst = sa1111_readl(dev->mapbase + USB_RESET); |
75 | sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, | 165 | sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, |
76 | dev->mapbase + SA1111_USB_RESET); | 166 | dev->mapbase + USB_RESET); |
77 | 167 | ||
78 | /* | 168 | /* |
79 | * Stop the USB clock. | 169 | * Stop the USB clock. |
80 | */ | 170 | */ |
81 | sa1111_disable_device(dev); | 171 | sa1111_disable_device(dev); |
82 | |||
83 | #ifdef CONFIG_SA1100_BADGE4 | ||
84 | if (machine_is_badge4()) { | ||
85 | /* Disable power to the USB bus */ | ||
86 | badge4_set_5V(BADGE4_5V_USB, 0); | ||
87 | } | ||
88 | #endif | ||
89 | } | ||
90 | |||
91 | |||
92 | /*-------------------------------------------------------------------------*/ | ||
93 | |||
94 | #if 0 | ||
95 | static void dump_hci_status(struct usb_hcd *hcd, const char *label) | ||
96 | { | ||
97 | unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS); | ||
98 | |||
99 | dbg ("%s USB_STATUS = { %s%s%s%s%s}", label, | ||
100 | ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), | ||
101 | ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), | ||
102 | ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), | ||
103 | ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), | ||
104 | ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); | ||
105 | } | 172 | } |
106 | #endif | ||
107 | |||
108 | /*-------------------------------------------------------------------------*/ | ||
109 | |||
110 | /* configure so an HC device and id are always provided */ | ||
111 | /* always called with process context; sleeping is OK */ | ||
112 | |||
113 | 173 | ||
114 | /** | 174 | /** |
115 | * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs | 175 | * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs |
116 | * Context: !in_interrupt() | ||
117 | * | 176 | * |
118 | * Allocates basic resources for this USB host controller, and | 177 | * Allocates basic resources for this USB host controller, and |
119 | * then invokes the start() method for the HCD associated with it | 178 | * then invokes the start() method for the HCD associated with it. |
120 | * through the hotplug entry's driver_data. | ||
121 | * | ||
122 | * Store this function in the HCD's struct pci_driver as probe(). | ||
123 | */ | 179 | */ |
124 | int usb_hcd_sa1111_probe (const struct hc_driver *driver, | 180 | static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) |
125 | struct sa1111_dev *dev) | ||
126 | { | 181 | { |
127 | struct usb_hcd *hcd; | 182 | struct usb_hcd *hcd; |
128 | int retval; | 183 | int ret; |
129 | 184 | ||
130 | hcd = usb_create_hcd (driver, &dev->dev, "sa1111"); | 185 | if (usb_disabled()) |
186 | return -ENODEV; | ||
187 | |||
188 | hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111"); | ||
131 | if (!hcd) | 189 | if (!hcd) |
132 | return -ENOMEM; | 190 | return -ENOMEM; |
191 | |||
133 | hcd->rsrc_start = dev->res.start; | 192 | hcd->rsrc_start = dev->res.start; |
134 | hcd->rsrc_len = resource_size(&dev->res); | 193 | hcd->rsrc_len = resource_size(&dev->res); |
135 | 194 | ||
136 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | 195 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { |
137 | dbg("request_mem_region failed"); | 196 | dbg("request_mem_region failed"); |
138 | retval = -EBUSY; | 197 | ret = -EBUSY; |
139 | goto err1; | 198 | goto err1; |
140 | } | 199 | } |
200 | |||
141 | hcd->regs = dev->mapbase; | 201 | hcd->regs = dev->mapbase; |
142 | 202 | ||
143 | sa1111_start_hc(dev); | 203 | ret = sa1111_start_hc(dev); |
144 | ohci_hcd_init(hcd_to_ohci(hcd)); | 204 | if (ret) |
205 | goto err2; | ||
145 | 206 | ||
146 | retval = usb_add_hcd(hcd, dev->irq[1], 0); | 207 | ret = usb_add_hcd(hcd, dev->irq[1], 0); |
147 | if (retval == 0) | 208 | if (ret == 0) |
148 | return retval; | 209 | return ret; |
149 | 210 | ||
150 | sa1111_stop_hc(dev); | 211 | sa1111_stop_hc(dev); |
212 | err2: | ||
151 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 213 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
152 | err1: | 214 | err1: |
153 | usb_put_hcd(hcd); | 215 | usb_put_hcd(hcd); |
154 | return retval; | 216 | return ret; |
155 | } | 217 | } |
156 | 218 | ||
157 | |||
158 | /* may be called without controller electrically present */ | ||
159 | /* may be called with controller, bus, and devices active */ | ||
160 | |||
161 | /** | 219 | /** |
162 | * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs | 220 | * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs |
163 | * @dev: USB Host Controller being removed | 221 | * @dev: USB Host Controller being removed |
164 | * Context: !in_interrupt() | ||
165 | * | ||
166 | * Reverses the effect of usb_hcd_sa1111_probe(), first invoking | ||
167 | * the HCD's stop() method. It is always called from a thread | ||
168 | * context, normally "rmmod", "apmd", or something similar. | ||
169 | * | 222 | * |
223 | * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking | ||
224 | * the HCD's stop() method. | ||
170 | */ | 225 | */ |
171 | void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev) | 226 | static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev) |
172 | { | 227 | { |
228 | struct usb_hcd *hcd = sa1111_get_drvdata(dev); | ||
229 | |||
173 | usb_remove_hcd(hcd); | 230 | usb_remove_hcd(hcd); |
174 | sa1111_stop_hc(dev); | 231 | sa1111_stop_hc(dev); |
175 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 232 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
176 | usb_put_hcd(hcd); | 233 | usb_put_hcd(hcd); |
177 | } | ||
178 | |||
179 | /*-------------------------------------------------------------------------*/ | ||
180 | 234 | ||
181 | static int __devinit | ||
182 | ohci_sa1111_start (struct usb_hcd *hcd) | ||
183 | { | ||
184 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | ||
185 | int ret; | ||
186 | |||
187 | if ((ret = ohci_init(ohci)) < 0) | ||
188 | return ret; | ||
189 | |||
190 | if ((ret = ohci_run (ohci)) < 0) { | ||
191 | err ("can't start %s", hcd->self.bus_name); | ||
192 | ohci_stop (hcd); | ||
193 | return ret; | ||
194 | } | ||
195 | return 0; | 235 | return 0; |
196 | } | 236 | } |
197 | 237 | ||
198 | /*-------------------------------------------------------------------------*/ | 238 | static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev) |
199 | |||
200 | static const struct hc_driver ohci_sa1111_hc_driver = { | ||
201 | .description = hcd_name, | ||
202 | .product_desc = "SA-1111 OHCI", | ||
203 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
204 | |||
205 | /* | ||
206 | * generic hardware linkage | ||
207 | */ | ||
208 | .irq = ohci_irq, | ||
209 | .flags = HCD_USB11 | HCD_MEMORY, | ||
210 | |||
211 | /* | ||
212 | * basic lifecycle operations | ||
213 | */ | ||
214 | .start = ohci_sa1111_start, | ||
215 | .stop = ohci_stop, | ||
216 | |||
217 | /* | ||
218 | * managing i/o requests and associated device resources | ||
219 | */ | ||
220 | .urb_enqueue = ohci_urb_enqueue, | ||
221 | .urb_dequeue = ohci_urb_dequeue, | ||
222 | .endpoint_disable = ohci_endpoint_disable, | ||
223 | |||
224 | /* | ||
225 | * scheduling support | ||
226 | */ | ||
227 | .get_frame_number = ohci_get_frame, | ||
228 | |||
229 | /* | ||
230 | * root hub support | ||
231 | */ | ||
232 | .hub_status_data = ohci_hub_status_data, | ||
233 | .hub_control = ohci_hub_control, | ||
234 | #ifdef CONFIG_PM | ||
235 | .bus_suspend = ohci_bus_suspend, | ||
236 | .bus_resume = ohci_bus_resume, | ||
237 | #endif | ||
238 | .start_port_reset = ohci_start_port_reset, | ||
239 | }; | ||
240 | |||
241 | /*-------------------------------------------------------------------------*/ | ||
242 | |||
243 | static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev) | ||
244 | { | ||
245 | int ret; | ||
246 | |||
247 | if (usb_disabled()) | ||
248 | return -ENODEV; | ||
249 | |||
250 | ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev) | ||
255 | { | 239 | { |
256 | struct usb_hcd *hcd = sa1111_get_drvdata(dev); | 240 | struct usb_hcd *hcd = sa1111_get_drvdata(dev); |
257 | 241 | ||
258 | usb_hcd_sa1111_remove(hcd, dev); | 242 | if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { |
259 | return 0; | 243 | hcd->driver->shutdown(hcd); |
244 | sa1111_stop_hc(dev); | ||
245 | } | ||
260 | } | 246 | } |
261 | 247 | ||
262 | static struct sa1111_driver ohci_hcd_sa1111_driver = { | 248 | static struct sa1111_driver ohci_hcd_sa1111_driver = { |
263 | .drv = { | 249 | .drv = { |
264 | .name = "sa1111-ohci", | 250 | .name = "sa1111-ohci", |
251 | .owner = THIS_MODULE, | ||
265 | }, | 252 | }, |
266 | .devid = SA1111_DEVID_USB, | 253 | .devid = SA1111_DEVID_USB, |
267 | .probe = ohci_hcd_sa1111_drv_probe, | 254 | .probe = ohci_hcd_sa1111_probe, |
268 | .remove = ohci_hcd_sa1111_drv_remove, | 255 | .remove = ohci_hcd_sa1111_remove, |
256 | .shutdown = ohci_hcd_sa1111_shutdown, | ||
269 | }; | 257 | }; |
270 | |||