Merge /home/trondmy/scm/kernel/git/torvalds/linux-2.6
[linux-2.6] / drivers / usb / host / ohci-au1xxx.c
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  * Bus Glue for AMD Alchemy Au1xxx
9  *
10  * Written by Christopher Hoover <ch@hpl.hp.com>
11  * Based on fragments of previous driver by Rusell King et al.
12  *
13  * Modified for LH7A404 from ohci-sa1111.c
14  *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
15  * Modified for AMD Alchemy Au1xxx
16  *  by Matt Porter <mporter@kernel.crashing.org>
17  *
18  * This file is licenced under the GPL.
19  */
20
21 #include <asm/mach-au1x00/au1000.h>
22
23 #define USBH_ENABLE_BE (1<<0)
24 #define USBH_ENABLE_C  (1<<1)
25 #define USBH_ENABLE_E  (1<<2)
26 #define USBH_ENABLE_CE (1<<3)
27 #define USBH_ENABLE_RD (1<<4)
28
29 #ifdef __LITTLE_ENDIAN
30 #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
31 #elif __BIG_ENDIAN
32 #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
33 #else
34 #error not byte order defined
35 #endif
36
37 extern int usb_disabled(void);
38
39 /*-------------------------------------------------------------------------*/
40
41 static void au1xxx_start_hc(struct platform_device *dev)
42 {
43         printk(KERN_DEBUG __FILE__
44                 ": starting Au1xxx OHCI USB Controller\n");
45
46         /* enable host controller */
47         au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
48         udelay(1000);
49         au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
50         udelay(1000);
51
52         /* wait for reset complete (read register twice; see au1500 errata) */
53         while (au_readl(USB_HOST_CONFIG),
54                 !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
55                 udelay(1000);
56
57         printk(KERN_DEBUG __FILE__
58         ": Clock to USB host has been enabled \n");
59 }
60
61 static void au1xxx_stop_hc(struct platform_device *dev)
62 {
63         printk(KERN_DEBUG __FILE__
64                ": stopping Au1xxx OHCI USB Controller\n");
65
66         /* Disable clock */
67         au_writel(readl((void *)USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
68 }
69
70
71 /*-------------------------------------------------------------------------*/
72
73 /* configure so an HC device and id are always provided */
74 /* always called with process context; sleeping is OK */
75
76
77 /**
78  * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
79  * Context: !in_interrupt()
80  *
81  * Allocates basic resources for this USB host controller, and
82  * then invokes the start() method for the HCD associated with it
83  * through the hotplug entry's driver_data.
84  *
85  */
86 int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
87                           struct platform_device *dev)
88 {
89         int retval;
90         struct usb_hcd *hcd;
91
92         if(dev->resource[1].flags != IORESOURCE_IRQ) {
93                 pr_debug ("resource[1] is not IORESOURCE_IRQ");
94                 return -ENOMEM;
95         }
96
97         hcd = usb_create_hcd(driver, &dev->dev, "au1xxx");
98         if (!hcd)
99                 return -ENOMEM;
100         hcd->rsrc_start = dev->resource[0].start;
101         hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
102
103         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
104                 pr_debug("request_mem_region failed");
105                 retval = -EBUSY;
106                 goto err1;
107         }
108
109         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
110         if (!hcd->regs) {
111                 pr_debug("ioremap failed");
112                 retval = -ENOMEM;
113                 goto err2;
114         }
115
116         au1xxx_start_hc(dev);
117         ohci_hcd_init(hcd_to_ohci(hcd));
118
119         retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
120         if (retval == 0)
121                 return retval;
122
123         au1xxx_stop_hc(dev);
124         iounmap(hcd->regs);
125  err2:
126         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
127  err1:
128         usb_put_hcd(hcd);
129         return retval;
130 }
131
132
133 /* may be called without controller electrically present */
134 /* may be called with controller, bus, and devices active */
135
136 /**
137  * usb_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
138  * @dev: USB Host Controller being removed
139  * Context: !in_interrupt()
140  *
141  * Reverses the effect of usb_hcd_au1xxx_probe(), first invoking
142  * the HCD's stop() method.  It is always called from a thread
143  * context, normally "rmmod", "apmd", or something similar.
144  *
145  */
146 void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
147 {
148         usb_remove_hcd(hcd);
149         au1xxx_stop_hc(dev);
150         iounmap(hcd->regs);
151         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
152         usb_put_hcd(hcd);
153 }
154
155 /*-------------------------------------------------------------------------*/
156
157 static int __devinit
158 ohci_au1xxx_start (struct usb_hcd *hcd)
159 {
160         struct ohci_hcd *ohci = hcd_to_ohci (hcd);
161         int             ret;
162
163         ohci_dbg (ohci, "ohci_au1xxx_start, ohci:%p", ohci);
164
165         if ((ret = ohci_init (ohci)) < 0)
166                 return ret;
167
168         if ((ret = ohci_run (ohci)) < 0) {
169                 err ("can't start %s", hcd->self.bus_name);
170                 ohci_stop (hcd);
171                 return ret;
172         }
173
174         return 0;
175 }
176
177 /*-------------------------------------------------------------------------*/
178
179 static const struct hc_driver ohci_au1xxx_hc_driver = {
180         .description =          hcd_name,
181         .product_desc =         "Au1xxx OHCI",
182         .hcd_priv_size =        sizeof(struct ohci_hcd),
183
184         /*
185          * generic hardware linkage
186          */
187         .irq =                  ohci_irq,
188         .flags =                HCD_USB11 | HCD_MEMORY,
189
190         /*
191          * basic lifecycle operations
192          */
193         .start =                ohci_au1xxx_start,
194 #ifdef  CONFIG_PM
195         /* suspend:             ohci_au1xxx_suspend,  -- tbd */
196         /* resume:              ohci_au1xxx_resume,   -- tbd */
197 #endif /*CONFIG_PM*/
198         .stop =                 ohci_stop,
199
200         /*
201          * managing i/o requests and associated device resources
202          */
203         .urb_enqueue =          ohci_urb_enqueue,
204         .urb_dequeue =          ohci_urb_dequeue,
205         .endpoint_disable =     ohci_endpoint_disable,
206
207         /*
208          * scheduling support
209          */
210         .get_frame_number =     ohci_get_frame,
211
212         /*
213          * root hub support
214          */
215         .hub_status_data =      ohci_hub_status_data,
216         .hub_control =          ohci_hub_control,
217 };
218
219 /*-------------------------------------------------------------------------*/
220
221 static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
222 {
223         struct platform_device *pdev = to_platform_device(dev);
224         int ret;
225
226         pr_debug ("In ohci_hcd_au1xxx_drv_probe");
227
228         if (usb_disabled())
229                 return -ENODEV;
230
231         ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
232         return ret;
233 }
234
235 static int ohci_hcd_au1xxx_drv_remove(struct device *dev)
236 {
237         struct platform_device *pdev = to_platform_device(dev);
238         struct usb_hcd *hcd = dev_get_drvdata(dev);
239
240         usb_hcd_au1xxx_remove(hcd, pdev);
241         return 0;
242 }
243         /*TBD*/
244 /*static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
245 {
246         struct platform_device *pdev = to_platform_device(dev);
247         struct usb_hcd *hcd = dev_get_drvdata(dev);
248
249         return 0;
250 }
251 static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
252 {
253         struct platform_device *pdev = to_platform_device(dev);
254         struct usb_hcd *hcd = dev_get_drvdata(dev);
255
256         return 0;
257 }
258 */
259
260 static struct device_driver ohci_hcd_au1xxx_driver = {
261         .name           = "au1xxx-ohci",
262         .bus            = &platform_bus_type,
263         .probe          = ohci_hcd_au1xxx_drv_probe,
264         .remove         = ohci_hcd_au1xxx_drv_remove,
265         /*.suspend      = ohci_hcd_au1xxx_drv_suspend, */
266         /*.resume       = ohci_hcd_au1xxx_drv_resume, */
267 };
268
269 static int __init ohci_hcd_au1xxx_init (void)
270 {
271         pr_debug (DRIVER_INFO " (Au1xxx)");
272         pr_debug ("block sizes: ed %d td %d\n",
273                 sizeof (struct ed), sizeof (struct td));
274
275         return driver_register(&ohci_hcd_au1xxx_driver);
276 }
277
278 static void __exit ohci_hcd_au1xxx_cleanup (void)
279 {
280         driver_unregister(&ohci_hcd_au1xxx_driver);
281 }
282
283 module_init (ohci_hcd_au1xxx_init);
284 module_exit (ohci_hcd_au1xxx_cleanup);