surprise :p
[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 #if 0
76         ehci            = hcd_to_ehci(hcd);
77         ehci->caps      = hcd->regs;
78         ehci->regs      = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
79         ehci->hcs_params = readl(&ehci->caps->hcs_params);
80 #endif
81
82         ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
83         if (ret)
84                 goto err_stop_ehc;
85
86         return 0;
87
88 err_stop_ehc:
89         ar71xx_stop_ehci(pdev);
90         iounmap(hcd->regs);
91
92 err_release_region:
93         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
94 err_put_hcd:
95         usb_put_hcd(hcd);
96         return ret;
97 }
98
99 /* may be called without controller electrically present */
100 /* may be called with controller, bus, and devices active */
101
102 /**
103  * usb_ehci_ar71xx_remove - shutdown processing for AR71xx-based HCDs
104  * @dev: USB Host Controller being removed
105  * Context: !in_interrupt()
106  *
107  * Reverses the effect of usb_hcd_ar71xx_probe(), first invoking
108  * the HCD's stop() method.  It is always called from a thread
109  * context, normally "rmmod", "apmd", or something similar.
110  *
111  */
112 static void usb_ehci_ar71xx_remove(struct usb_hcd *hcd,
113                                    struct platform_device *pdev)
114 {
115         usb_remove_hcd(hcd);
116         ar71xx_stop_ehci(pdev);
117         iounmap(hcd->regs);
118         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
119         usb_put_hcd(hcd);
120 }
121
122 static const struct hc_driver ehci_ar71xx_hc_driver = {
123         .description    = hcd_name,
124         .product_desc   = "Atheros AR71xx built-in EHCI controller",
125         .hcd_priv_size  = sizeof(struct ehci_hcd),
126         /*
127          * generic hardware linkage
128          */
129         .irq            = ehci_irq,
130         .flags          = HCD_MEMORY | HCD_USB2,
131
132         /*
133          * basic lifecycle operations
134          */
135         .reset          = ehci_init,
136         .start          = ehci_run,
137         .stop           = ehci_stop,
138         .shutdown       = ehci_shutdown,
139
140         /*
141          * managing i/o requests and associated device resources
142          */
143         .urb_enqueue            = ehci_urb_enqueue,
144         .urb_dequeue            = ehci_urb_dequeue,
145         .endpoint_disable       = ehci_endpoint_disable,
146
147         /*
148          * scheduling support
149          */
150         .get_frame_number = ehci_get_frame,
151
152         /*
153          * root hub support
154          */
155         .hub_status_data        = ehci_hub_status_data,
156         .hub_control            = ehci_hub_control,
157 #ifdef CONFIG_PM
158         .hub_suspend            = ehci_hub_suspend,
159         .hub_resume             = ehci_hub_resume,
160 #endif
161 };
162
163 static int ehci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
164 {
165         struct usb_hcd *hcd = NULL;
166         int ret;
167
168         ret = -ENODEV;
169         if (!usb_disabled())
170                 ret = usb_ehci_ar71xx_probe(&ehci_ar71xx_hc_driver, &hcd, pdev);
171
172         return ret;
173 }
174
175 static int ehci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
176 {
177         struct usb_hcd *hcd = platform_get_drvdata(pdev);
178
179         usb_ehci_ar71xx_remove(hcd, pdev);
180         return 0;
181 }
182
183 static struct platform_driver ehci_hcd_ar71xx_driver = {
184         .probe          = ehci_hcd_ar71xx_drv_probe,
185         .remove         = ehci_hcd_ar71xx_drv_remove,
186         .shutdown       = usb_hcd_platform_shutdown,
187         .driver = {
188                 .name   = "ar71xx-ehci",
189                 .bus    = &platform_bus_type
190         }
191 };
192
193 MODULE_ALIAS("ar71xx-ehci");