fix EHCI driver
[oweals/openwrt.git] / target / linux / ar71xx / files / drivers / usb / host / ehci-ar71xx.c
1 /*
2  * EHCI HCD (Host Controller Driver) for USB.
3  *
4  * Copyright (C) 2007 Atheros Communications, Inc.
5  * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
6  * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
7  *
8  * Bus Glue for Atheros AR71xx built-in EHCI controller
9  *
10  */
11
12 #include <linux/platform_device.h>
13 #include <linux/delay.h>
14
15 extern int usb_disabled(void);
16
17 static void ar71xx_start_ehci(struct platform_device *pdev)
18 {
19 }
20
21 static void ar71xx_stop_ehci(struct platform_device *pdev)
22 {
23         /*
24          * TODO: implement
25          */
26 }
27
28 int usb_ehci_ar71xx_probe(const struct hc_driver *driver,
29                           struct usb_hcd **hcd_out,
30                           struct platform_device *pdev)
31 {
32         struct usb_hcd *hcd;
33         struct ehci_hcd *ehci;
34         struct resource *res;
35         int irq;
36         int ret;
37
38         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
39         if (!res) {
40                 dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
41                         pdev->dev.bus_id);
42                 return -ENODEV;
43         }
44         irq = res->start;
45
46         hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
47         if (!hcd)
48                 return -ENOMEM;
49
50         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
51         if (!res) {
52                 dev_dbg(&pdev->dev, "no base address specified for %s\n",
53                         pdev->dev.bus_id);
54                 ret = -ENODEV;
55                 goto err_put_hcd;
56         }
57         hcd->rsrc_start = res->start;
58         hcd->rsrc_len   = res->end - res->start + 1;
59
60         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
61                 dev_dbg(&pdev->dev, "controller already in use\n");
62                 ret = -EBUSY;
63                 goto err_put_hcd;
64         }
65
66         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
67         if (!hcd->regs) {
68                 dev_dbg(&pdev->dev, "error mapping memory\n");
69                 ret = -EFAULT;
70                 goto err_release_region;
71         }
72
73         ar71xx_start_ehci(pdev);
74
75         ehci            = hcd_to_ehci(hcd);
76         ehci->caps      = hcd->regs;
77         ehci->regs      = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
78         ehci->hcs_params = readl(&ehci->caps->hcs_params);
79
80         ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
81         if (ret)
82                 goto err_stop_ehc;
83
84         return 0;
85
86 err_stop_ehc:
87         ar71xx_stop_ehci(pdev);
88         iounmap(hcd->regs);
89
90 err_release_region:
91         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
92 err_put_hcd:
93         usb_put_hcd(hcd);
94         return ret;
95 }
96
97 /* may be called without controller electrically present */
98 /* may be called with controller, bus, and devices active */
99
100 /**
101  * usb_ehci_ar71xx_remove - shutdown processing for AR71xx-based HCDs
102  * @dev: USB Host Controller being removed
103  * Context: !in_interrupt()
104  *
105  * Reverses the effect of usb_hcd_ar71xx_probe(), first invoking
106  * the HCD's stop() method.  It is always called from a thread
107  * context, normally "rmmod", "apmd", or something similar.
108  *
109  */
110 static void usb_ehci_ar71xx_remove(struct usb_hcd *hcd,
111                                    struct platform_device *pdev)
112 {
113         usb_remove_hcd(hcd);
114         ar71xx_stop_ehci(pdev);
115         iounmap(hcd->regs);
116         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
117         usb_put_hcd(hcd);
118 }
119
120 static const struct hc_driver ehci_ar71xx_hc_driver = {
121         .description    = hcd_name,
122         .product_desc   = "Atheros AR71xx built-in EHCI controller",
123         .hcd_priv_size  = sizeof(struct ehci_hcd),
124         /*
125          * generic hardware linkage
126          */
127         .irq            = ehci_irq,
128         .flags          = HCD_MEMORY | HCD_USB2,
129
130         /*
131          * basic lifecycle operations
132          */
133         .reset          = ehci_init,
134         .start          = ehci_run,
135         .stop           = ehci_stop,
136         .shutdown       = ehci_shutdown,
137
138         /*
139          * managing i/o requests and associated device resources
140          */
141         .urb_enqueue            = ehci_urb_enqueue,
142         .urb_dequeue            = ehci_urb_dequeue,
143         .endpoint_disable       = ehci_endpoint_disable,
144
145         /*
146          * scheduling support
147          */
148         .get_frame_number = ehci_get_frame,
149
150         /*
151          * root hub support
152          */
153         .hub_status_data        = ehci_hub_status_data,
154         .hub_control            = ehci_hub_control,
155 #ifdef CONFIG_PM
156         .hub_suspend            = ehci_hub_suspend,
157         .hub_resume             = ehci_hub_resume,
158 #endif
159 };
160
161 static int ehci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
162 {
163         struct usb_hcd *hcd = NULL;
164         int ret;
165
166         ret = -ENODEV;
167         if (!usb_disabled())
168                 ret = usb_ehci_ar71xx_probe(&ehci_ar71xx_hc_driver, &hcd, pdev);
169
170         return ret;
171 }
172
173 static int ehci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
174 {
175         struct usb_hcd *hcd = platform_get_drvdata(pdev);
176
177         usb_ehci_ar71xx_remove(hcd, pdev);
178         return 0;
179 }
180
181 static struct platform_driver ehci_hcd_ar71xx_driver = {
182         .probe          = ehci_hcd_ar71xx_drv_probe,
183         .remove         = ehci_hcd_ar71xx_drv_remove,
184         .shutdown       = usb_hcd_platform_shutdown,
185         .driver = {
186                 .name   = "ar71xx-ehci",
187                 .bus    = &platform_bus_type
188         }
189 };
190
191 MODULE_ALIAS("ar71xx-ehci");