This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / usb / host / ehci-au1xxx.c
1 /*
2  * EHCI HCD (Host Controller Driver) for USB.
3  *
4  * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
5  *
6  * Bus Glue for AMD Alchemy Au1xxx
7  *
8  * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
9  *
10  * Modified for AMD Alchemy Au1200 EHC
11  *  by K.Boge <karsten.boge@amd.com>
12  *
13  * This file is licenced under the GPL.
14  */
15
16 #include <linux/platform_device.h>
17 #include <asm/mach-au1x00/au1000.h>
18
19 #ifndef CONFIG_SOC_AU1200
20 #error "this Alchemy chip doesn't have EHCI"
21 #else                           /* Au1200 */
22
23 #define USB_HOST_CONFIG   (USB_MSR_BASE + USB_MSR_MCFG)
24 #define USB_MCFG_PFEN     (1<<31)
25 #define USB_MCFG_RDCOMB   (1<<30)
26 #define USB_MCFG_SSDEN    (1<<23)
27 #define USB_MCFG_PHYPLLEN (1<<19)
28 #define USB_MCFG_EHCCLKEN (1<<17)
29 #define USB_MCFG_UCAM     (1<<7)
30 #define USB_MCFG_EBMEN    (1<<3)
31 #define USB_MCFG_EMEMEN   (1<<2)
32
33 #define USBH_ENABLE_CE    (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
34
35 #ifdef CONFIG_DMA_COHERENT
36 #define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
37                          | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
38                          | USB_MCFG_SSDEN | USB_MCFG_UCAM \
39                          | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
40 #else
41 #define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
42                          | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
43                          | USB_MCFG_SSDEN \
44                          | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
45 #endif
46 #define USBH_DISABLE      (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
47
48 #endif                          /* Au1200 */
49
50 extern int usb_disabled(void);
51
52 /*-------------------------------------------------------------------------*/
53
54 static void au1xxx_start_ehc(struct platform_device *dev)
55 {
56         pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n");
57
58         /* write HW defaults again in case Yamon cleared them */
59         if (au_readl(USB_HOST_CONFIG) == 0) {
60                 au_writel(0x00d02000, USB_HOST_CONFIG);
61                 au_readl(USB_HOST_CONFIG);
62                 udelay(1000);
63         }
64         /* enable host controller */
65         au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
66         au_readl(USB_HOST_CONFIG);
67         udelay(1000);
68         au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG),
69                   USB_HOST_CONFIG);
70         au_readl(USB_HOST_CONFIG);
71         udelay(1000);
72
73         pr_debug(__FILE__ ": Clock to USB host has been enabled\n");
74 }
75
76 static void au1xxx_stop_ehc(struct platform_device *dev)
77 {
78         pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n");
79
80         /* Disable mem */
81         au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
82         udelay(1000);
83         /* Disable clock */
84         au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG),
85                   USB_HOST_CONFIG);
86         au_readl(USB_HOST_CONFIG);
87 }
88
89 /*-------------------------------------------------------------------------*/
90
91 /* configure so an HC device and id are always provided */
92 /* always called with process context; sleeping is OK */
93
94 /**
95  * usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs
96  * Context: !in_interrupt()
97  *
98  * Allocates basic resources for this USB host controller, and
99  * then invokes the start() method for the HCD associated with it
100  * through the hotplug entry's driver_data.
101  *
102  */
103 int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
104                           struct usb_hcd **hcd_out, struct platform_device *dev)
105 {
106         int retval;
107         struct usb_hcd *hcd;
108         struct ehci_hcd *ehci;
109
110 #if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
111
112         /* Au1200 AB USB does not support coherent memory */
113         if (!(read_c0_prid() & 0xff)) {
114                 pr_info("%s: this is chip revision AB!\n", dev->dev.name);
115                 pr_info("%s: update your board or re-configure the kernel\n",
116                         dev->dev.name);
117                 return -ENODEV;
118         }
119 #endif
120
121         au1xxx_start_ehc(dev);
122
123         if (dev->resource[1].flags != IORESOURCE_IRQ) {
124                 pr_debug("resource[1] is not IORESOURCE_IRQ");
125                 retval = -ENOMEM;
126         }
127         hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
128         if (!hcd)
129                 return -ENOMEM;
130         hcd->rsrc_start = dev->resource[0].start;
131         hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
132
133         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
134                 pr_debug("request_mem_region failed");
135                 retval = -EBUSY;
136                 goto err1;
137         }
138
139         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
140         if (!hcd->regs) {
141                 pr_debug("ioremap failed");
142                 retval = -ENOMEM;
143                 goto err2;
144         }
145
146         ehci = hcd_to_ehci(hcd);
147         ehci->caps = hcd->regs;
148         ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
149         /* cache this readonly data; minimize chip reads */
150         ehci->hcs_params = readl(&ehci->caps->hcs_params);
151
152         /* ehci_hcd_init(hcd_to_ehci(hcd)); */
153
154         retval =
155             usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
156         if (retval == 0)
157                 return retval;
158
159         au1xxx_stop_ehc(dev);
160         iounmap(hcd->regs);
161 err2:
162         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
163 err1:
164         usb_put_hcd(hcd);
165         return retval;
166 }
167
168 /* may be called without controller electrically present */
169 /* may be called with controller, bus, and devices active */
170
171 /**
172  * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
173  * @dev: USB Host Controller being removed
174  * Context: !in_interrupt()
175  *
176  * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking
177  * the HCD's stop() method.  It is always called from a thread
178  * context, normally "rmmod", "apmd", or something similar.
179  *
180  */
181 void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
182 {
183         usb_remove_hcd(hcd);
184         iounmap(hcd->regs);
185         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
186         usb_put_hcd(hcd);
187         au1xxx_stop_ehc(dev);
188 }
189
190 /*-------------------------------------------------------------------------*/
191
192 static const struct hc_driver ehci_au1xxx_hc_driver = {
193         .description = hcd_name,
194         .product_desc = "Au1xxx EHCI",
195         .hcd_priv_size = sizeof(struct ehci_hcd),
196
197         /*
198          * generic hardware linkage
199          */
200         .irq = ehci_irq,
201         .flags = HCD_MEMORY | HCD_USB2,
202
203         /*
204          * basic lifecycle operations
205          */
206         .reset = ehci_init,
207         .start = ehci_run,
208         .stop = ehci_stop,
209
210         /*
211          * managing i/o requests and associated device resources
212          */
213         .urb_enqueue = ehci_urb_enqueue,
214         .urb_dequeue = ehci_urb_dequeue,
215         .endpoint_disable = ehci_endpoint_disable,
216
217         /*
218          * scheduling support
219          */
220         .get_frame_number = ehci_get_frame,
221
222         /*
223          * root hub support
224          */
225         .hub_status_data = ehci_hub_status_data,
226         .hub_control = ehci_hub_control,
227 #ifdef  CONFIG_PM
228         .hub_suspend = ehci_hub_suspend,
229         .hub_resume = ehci_hub_resume,
230 #endif
231 };
232
233 /*-------------------------------------------------------------------------*/
234
235 static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
236 {
237         struct platform_device *pdev = to_platform_device(dev);
238         struct usb_hcd *hcd = NULL;
239         int ret;
240
241         pr_debug("In ehci_hcd_au1xxx_drv_probe\n");
242
243         if (usb_disabled())
244                 return -ENODEV;
245
246         ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
247         return ret;
248 }
249
250 static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
251 {
252         struct platform_device *pdev = to_platform_device(dev);
253         struct usb_hcd *hcd = dev_get_drvdata(dev);
254
255         usb_ehci_au1xxx_remove(hcd, pdev);
256         return 0;
257 }
258
259  /*TBD*/
260 /*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
261 {
262         struct platform_device *pdev = to_platform_device(dev);
263         struct usb_hcd *hcd = dev_get_drvdata(dev);
264
265         return 0;
266 }
267 static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
268 {
269         struct platform_device *pdev = to_platform_device(dev);
270         struct usb_hcd *hcd = dev_get_drvdata(dev);
271
272         return 0;
273 }
274 */
275 static struct device_driver ehci_hcd_au1xxx_driver = {
276         .name = "au1xxx-ehci",
277         .bus = &platform_bus_type,
278         .probe = ehci_hcd_au1xxx_drv_probe,
279         .remove = ehci_hcd_au1xxx_drv_remove,
280         /*.suspend      = ehci_hcd_au1xxx_drv_suspend, */
281         /*.resume       = ehci_hcd_au1xxx_drv_resume, */
282 };
283
284 static int __init ehci_hcd_au1xxx_init(void)
285 {
286         pr_debug(DRIVER_INFO " (Au1xxx)\n");
287
288         return driver_register(&ehci_hcd_au1xxx_driver);
289 }
290
291 static void __exit ehci_hcd_au1xxx_cleanup(void)
292 {
293         driver_unregister(&ehci_hcd_au1xxx_driver);
294 }
295
296 module_init(ehci_hcd_au1xxx_init);
297 module_exit(ehci_hcd_au1xxx_cleanup);