diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/host/ohci-sa1111.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/usb/host/ohci-sa1111.c')
-rw-r--r-- | drivers/usb/host/ohci-sa1111.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c new file mode 100644 index 000000000000..814d2be4ee7b --- /dev/null +++ b/drivers/usb/host/ohci-sa1111.c | |||
@@ -0,0 +1,289 @@ | |||
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 | * | ||
8 | * SA1111 Bus Glue | ||
9 | * | ||
10 | * Written by Christopher Hoover <ch@hpl.hp.com> | ||
11 | * Based on fragments of previous driver by Rusell King et al. | ||
12 | * | ||
13 | * This file is licenced under the GPL. | ||
14 | */ | ||
15 | |||
16 | #include <asm/hardware.h> | ||
17 | #include <asm/mach-types.h> | ||
18 | #include <asm/arch/assabet.h> | ||
19 | #include <asm/arch/badge4.h> | ||
20 | #include <asm/hardware/sa1111.h> | ||
21 | |||
22 | #ifndef CONFIG_SA1111 | ||
23 | #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." | ||
24 | #endif | ||
25 | |||
26 | extern int usb_disabled(void); | ||
27 | |||
28 | /*-------------------------------------------------------------------------*/ | ||
29 | |||
30 | static void sa1111_start_hc(struct sa1111_dev *dev) | ||
31 | { | ||
32 | unsigned int usb_rst = 0; | ||
33 | |||
34 | printk(KERN_DEBUG __FILE__ | ||
35 | ": starting SA-1111 OHCI USB Controller\n"); | ||
36 | |||
37 | #ifdef CONFIG_SA1100_BADGE4 | ||
38 | if (machine_is_badge4()) { | ||
39 | badge4_set_5V(BADGE4_5V_USB, 1); | ||
40 | } | ||
41 | #endif | ||
42 | |||
43 | if (machine_is_xp860() || | ||
44 | machine_has_neponset() || | ||
45 | machine_is_pfs168() || | ||
46 | machine_is_badge4()) | ||
47 | usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; | ||
48 | |||
49 | /* | ||
50 | * Configure the power sense and control lines. Place the USB | ||
51 | * host controller in reset. | ||
52 | */ | ||
53 | sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, | ||
54 | dev->mapbase + SA1111_USB_RESET); | ||
55 | |||
56 | /* | ||
57 | * Now, carefully enable the USB clock, and take | ||
58 | * the USB host controller out of reset. | ||
59 | */ | ||
60 | sa1111_enable_device(dev); | ||
61 | udelay(11); | ||
62 | sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET); | ||
63 | } | ||
64 | |||
65 | static void sa1111_stop_hc(struct sa1111_dev *dev) | ||
66 | { | ||
67 | unsigned int usb_rst; | ||
68 | printk(KERN_DEBUG __FILE__ | ||
69 | ": stopping SA-1111 OHCI USB Controller\n"); | ||
70 | |||
71 | /* | ||
72 | * Put the USB host controller into reset. | ||
73 | */ | ||
74 | usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET); | ||
75 | sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, | ||
76 | dev->mapbase + SA1111_USB_RESET); | ||
77 | |||
78 | /* | ||
79 | * Stop the USB clock. | ||
80 | */ | ||
81 | 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 | } | ||
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 | |||
114 | /** | ||
115 | * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs | ||
116 | * Context: !in_interrupt() | ||
117 | * | ||
118 | * Allocates basic resources for this USB host controller, and | ||
119 | * 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 | */ | ||
124 | int usb_hcd_sa1111_probe (const struct hc_driver *driver, | ||
125 | struct sa1111_dev *dev) | ||
126 | { | ||
127 | struct usb_hcd *hcd; | ||
128 | int retval; | ||
129 | |||
130 | hcd = usb_create_hcd (driver, &dev->dev, "sa1111"); | ||
131 | if (!hcd) | ||
132 | return -ENOMEM; | ||
133 | hcd->rsrc_start = dev->res.start; | ||
134 | hcd->rsrc_len = dev->res.end - dev->res.start + 1; | ||
135 | |||
136 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | ||
137 | dbg("request_mem_region failed"); | ||
138 | retval = -EBUSY; | ||
139 | goto err1; | ||
140 | } | ||
141 | hcd->regs = dev->mapbase; | ||
142 | |||
143 | sa1111_start_hc(dev); | ||
144 | ohci_hcd_init(hcd_to_ohci(hcd)); | ||
145 | |||
146 | retval = usb_add_hcd(hcd, dev->irq[1], SA_INTERRUPT); | ||
147 | if (retval == 0) | ||
148 | return retval; | ||
149 | |||
150 | sa1111_stop_hc(dev); | ||
151 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
152 | err1: | ||
153 | usb_put_hcd(hcd); | ||
154 | return retval; | ||
155 | } | ||
156 | |||
157 | |||
158 | /* may be called without controller electrically present */ | ||
159 | /* may be called with controller, bus, and devices active */ | ||
160 | |||
161 | /** | ||
162 | * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs | ||
163 | * @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 | * | ||
170 | */ | ||
171 | void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev) | ||
172 | { | ||
173 | usb_remove_hcd(hcd); | ||
174 | sa1111_stop_hc(dev); | ||
175 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
176 | usb_put_hcd(hcd); | ||
177 | } | ||
178 | |||
179 | /*-------------------------------------------------------------------------*/ | ||
180 | |||
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; | ||
196 | } | ||
197 | |||
198 | /*-------------------------------------------------------------------------*/ | ||
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 | #ifdef CONFIG_PM | ||
216 | /* suspend: ohci_sa1111_suspend, -- tbd */ | ||
217 | /* resume: ohci_sa1111_resume, -- tbd */ | ||
218 | #endif | ||
219 | .stop = ohci_stop, | ||
220 | |||
221 | /* | ||
222 | * managing i/o requests and associated device resources | ||
223 | */ | ||
224 | .urb_enqueue = ohci_urb_enqueue, | ||
225 | .urb_dequeue = ohci_urb_dequeue, | ||
226 | .endpoint_disable = ohci_endpoint_disable, | ||
227 | |||
228 | /* | ||
229 | * scheduling support | ||
230 | */ | ||
231 | .get_frame_number = ohci_get_frame, | ||
232 | |||
233 | /* | ||
234 | * root hub support | ||
235 | */ | ||
236 | .hub_status_data = ohci_hub_status_data, | ||
237 | .hub_control = ohci_hub_control, | ||
238 | #ifdef CONFIG_USB_SUSPEND | ||
239 | .hub_suspend = ohci_hub_suspend, | ||
240 | .hub_resume = ohci_hub_resume, | ||
241 | #endif | ||
242 | }; | ||
243 | |||
244 | /*-------------------------------------------------------------------------*/ | ||
245 | |||
246 | static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev) | ||
247 | { | ||
248 | int ret; | ||
249 | |||
250 | if (usb_disabled()) | ||
251 | return -ENODEV; | ||
252 | |||
253 | ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev) | ||
258 | { | ||
259 | struct usb_hcd *hcd = sa1111_get_drvdata(dev); | ||
260 | |||
261 | usb_hcd_sa1111_remove(hcd, dev); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static struct sa1111_driver ohci_hcd_sa1111_driver = { | ||
266 | .drv = { | ||
267 | .name = "sa1111-ohci", | ||
268 | }, | ||
269 | .devid = SA1111_DEVID_USB, | ||
270 | .probe = ohci_hcd_sa1111_drv_probe, | ||
271 | .remove = ohci_hcd_sa1111_drv_remove, | ||
272 | }; | ||
273 | |||
274 | static int __init ohci_hcd_sa1111_init (void) | ||
275 | { | ||
276 | dbg (DRIVER_INFO " (SA-1111)"); | ||
277 | dbg ("block sizes: ed %d td %d", | ||
278 | sizeof (struct ed), sizeof (struct td)); | ||
279 | |||
280 | return sa1111_driver_register(&ohci_hcd_sa1111_driver); | ||
281 | } | ||
282 | |||
283 | static void __exit ohci_hcd_sa1111_cleanup (void) | ||
284 | { | ||
285 | sa1111_driver_unregister(&ohci_hcd_sa1111_driver); | ||
286 | } | ||
287 | |||
288 | module_init (ohci_hcd_sa1111_init); | ||
289 | module_exit (ohci_hcd_sa1111_cleanup); | ||