83f72a05c0cc0ad163011b3d03856bd203b73cdf
[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          * TODO: implement
21          */
22 }
23
24 static int usb_ehci_ar71xx_probe(const struct hc_driver *driver,
25                                  struct usb_hcd **hcd_out,
26                                  struct platform_device *pdev)
27 {
28         struct usb_hcd *hcd;
29         struct ehci_hcd *ehci;
30         struct resource *res;
31         int irq;
32         int ret;
33
34         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
35         if (!res) {
36                 dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
37                         pdev->dev.bus_id);
38                 return -ENODEV;
39         }
40         irq = res->start;
41
42         hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
43         if (!hcd)
44                 return -ENOMEM;
45
46         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
47         if (!res) {
48                 dev_dbg(&pdev->dev, "no base address specified for %s\n",
49                         pdev->dev.bus_id);
50                 ret = -ENODEV;
51                 goto err_put_hcd;
52         }
53         hcd->rsrc_start = res->start;
54         hcd->rsrc_len   = res->end - res->start + 1;
55
56         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
57                 dev_dbg(&pdev->dev, "controller already in use\n");
58                 ret = -EBUSY;
59                 goto err_put_hcd;
60         }
61
62         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
63         if (!hcd->regs) {
64                 dev_dbg(&pdev->dev, "error mapping memory\n");
65                 ret = -EFAULT;
66                 goto err_release_region;
67         }
68
69         ehci            = hcd_to_ehci(hcd);
70         ehci->caps      = hcd->regs;
71         ehci->regs      = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
72         ehci->hcs_params = readl(&ehci->caps->hcs_params);
73
74         ar71xx_start_ehci(pdev);
75
76         ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
77         if (ret)
78                 goto err_iounmap;
79
80         return 0;
81
82  err_iounmap:
83         iounmap(hcd->regs);
84
85  err_release_region:
86         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
87  err_put_hcd:
88         usb_put_hcd(hcd);
89         return ret;
90 }
91
92 static void usb_ehci_ar71xx_remove(struct usb_hcd *hcd,
93                                    struct platform_device *pdev)
94 {
95         usb_remove_hcd(hcd);
96         iounmap(hcd->regs);
97         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
98         usb_put_hcd(hcd);
99 }
100
101 static const struct hc_driver ehci_ar71xx_hc_driver = {
102         .description            = hcd_name,
103         .product_desc           = "Atheros AR71xx built-in EHCI controller",
104         .hcd_priv_size          = sizeof(struct ehci_hcd),
105
106         /*
107          * generic hardware linkage
108          */
109         .irq                    = ehci_irq,
110         .flags                  = HCD_MEMORY | HCD_USB2,
111
112         /*
113          * basic lifecycle operations
114          */
115         .reset                  = ehci_init,
116         .start                  = ehci_run,
117         .stop                   = ehci_stop,
118         .shutdown               = ehci_shutdown,
119
120         /*
121          * managing i/o requests and associated device resources
122          */
123         .urb_enqueue            = ehci_urb_enqueue,
124         .urb_dequeue            = ehci_urb_dequeue,
125         .endpoint_disable       = ehci_endpoint_disable,
126
127         /*
128          * scheduling support
129          */
130         .get_frame_number       = ehci_get_frame,
131
132         /*
133          * root hub support
134          */
135         .hub_status_data        = ehci_hub_status_data,
136         .hub_control            = ehci_hub_control,
137 #ifdef CONFIG_PM
138         .hub_suspend            = ehci_hub_suspend,
139         .hub_resume             = ehci_hub_resume,
140 #endif
141 };
142
143 static int ehci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
144 {
145         struct usb_hcd *hcd = NULL;
146         int ret;
147
148         ret = -ENODEV;
149         if (!usb_disabled())
150                 ret = usb_ehci_ar71xx_probe(&ehci_ar71xx_hc_driver, &hcd, pdev);
151
152         return ret;
153 }
154
155 static int ehci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
156 {
157         struct usb_hcd *hcd = platform_get_drvdata(pdev);
158
159         usb_ehci_ar71xx_remove(hcd, pdev);
160         return 0;
161 }
162
163 static struct platform_driver ehci_hcd_ar71xx_driver = {
164         .probe          = ehci_hcd_ar71xx_drv_probe,
165         .remove         = ehci_hcd_ar71xx_drv_remove,
166         .driver = {
167                 .name   = "ar71xx-ehci",
168         }
169 };
170
171 MODULE_ALIAS("platform:ar71xx-ehci");