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