KVM: Call pic_clear_isr() on pic reset to reuse logic there
[pandora-kernel.git] / drivers / usb / host / ehci-atmel.c
1 /*
2  * Driver for EHCI UHP on Atmel chips
3  *
4  *  Copyright (C) 2009 Atmel Corporation,
5  *                     Nicolas Ferre <nicolas.ferre@atmel.com>
6  *
7  *  Based on various ehci-*.c drivers
8  *
9  * This file is subject to the terms and conditions of the GNU General Public
10  * License.  See the file COPYING in the main directory of this archive for
11  * more details.
12  */
13
14 #include <linux/clk.h>
15 #include <linux/platform_device.h>
16
17 /* interface and function clocks */
18 static struct clk *iclk, *fclk;
19 static int clocked;
20
21 /*-------------------------------------------------------------------------*/
22
23 static void atmel_start_clock(void)
24 {
25         clk_enable(iclk);
26         clk_enable(fclk);
27         clocked = 1;
28 }
29
30 static void atmel_stop_clock(void)
31 {
32         clk_disable(fclk);
33         clk_disable(iclk);
34         clocked = 0;
35 }
36
37 static void atmel_start_ehci(struct platform_device *pdev)
38 {
39         dev_dbg(&pdev->dev, "start\n");
40         atmel_start_clock();
41 }
42
43 static void atmel_stop_ehci(struct platform_device *pdev)
44 {
45         dev_dbg(&pdev->dev, "stop\n");
46         atmel_stop_clock();
47 }
48
49 /*-------------------------------------------------------------------------*/
50
51 static int ehci_atmel_setup(struct usb_hcd *hcd)
52 {
53         struct ehci_hcd *ehci = hcd_to_ehci(hcd);
54         int retval = 0;
55
56         /* registers start at offset 0x0 */
57         ehci->caps = hcd->regs;
58         ehci->regs = hcd->regs +
59                 HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
60         dbg_hcs_params(ehci, "reset");
61         dbg_hcc_params(ehci, "reset");
62
63         /* cache this readonly data; minimize chip reads */
64         ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
65
66         retval = ehci_halt(ehci);
67         if (retval)
68                 return retval;
69
70         /* data structure init */
71         retval = ehci_init(hcd);
72         if (retval)
73                 return retval;
74
75         ehci->sbrn = 0x20;
76
77         ehci_reset(ehci);
78         ehci_port_power(ehci, 0);
79
80         return retval;
81 }
82
83 static const struct hc_driver ehci_atmel_hc_driver = {
84         .description            = hcd_name,
85         .product_desc           = "Atmel EHCI UHP HS",
86         .hcd_priv_size          = sizeof(struct ehci_hcd),
87
88         /* generic hardware linkage */
89         .irq                    = ehci_irq,
90         .flags                  = HCD_MEMORY | HCD_USB2,
91
92         /* basic lifecycle operations */
93         .reset                  = ehci_atmel_setup,
94         .start                  = ehci_run,
95         .stop                   = ehci_stop,
96         .shutdown               = ehci_shutdown,
97
98         /* managing i/o requests and associated device resources */
99         .urb_enqueue            = ehci_urb_enqueue,
100         .urb_dequeue            = ehci_urb_dequeue,
101         .endpoint_disable       = ehci_endpoint_disable,
102
103         /* scheduling support */
104         .get_frame_number       = ehci_get_frame,
105
106         /* root hub support */
107         .hub_status_data        = ehci_hub_status_data,
108         .hub_control            = ehci_hub_control,
109         .bus_suspend            = ehci_bus_suspend,
110         .bus_resume             = ehci_bus_resume,
111         .relinquish_port        = ehci_relinquish_port,
112         .port_handed_over       = ehci_port_handed_over,
113 };
114
115 static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
116 {
117         struct usb_hcd *hcd;
118         const struct hc_driver *driver = &ehci_atmel_hc_driver;
119         struct resource *res;
120         int irq;
121         int retval;
122
123         if (usb_disabled())
124                 return -ENODEV;
125
126         pr_debug("Initializing Atmel-SoC USB Host Controller\n");
127
128         irq = platform_get_irq(pdev, 0);
129         if (irq <= 0) {
130                 dev_err(&pdev->dev,
131                         "Found HC with no IRQ. Check %s setup!\n",
132                         dev_name(&pdev->dev));
133                 retval = -ENODEV;
134                 goto fail_create_hcd;
135         }
136
137         hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
138         if (!hcd) {
139                 retval = -ENOMEM;
140                 goto fail_create_hcd;
141         }
142
143         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144         if (!res) {
145                 dev_err(&pdev->dev,
146                         "Found HC with no register addr. Check %s setup!\n",
147                         dev_name(&pdev->dev));
148                 retval = -ENODEV;
149                 goto fail_request_resource;
150         }
151         hcd->rsrc_start = res->start;
152         hcd->rsrc_len = res->end - res->start + 1;
153
154         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
155                                 driver->description)) {
156                 dev_dbg(&pdev->dev, "controller already in use\n");
157                 retval = -EBUSY;
158                 goto fail_request_resource;
159         }
160
161         hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
162         if (hcd->regs == NULL) {
163                 dev_dbg(&pdev->dev, "error mapping memory\n");
164                 retval = -EFAULT;
165                 goto fail_ioremap;
166         }
167
168         iclk = clk_get(&pdev->dev, "ehci_clk");
169         if (IS_ERR(iclk)) {
170                 dev_err(&pdev->dev, "Error getting interface clock\n");
171                 retval = -ENOENT;
172                 goto fail_get_iclk;
173         }
174         fclk = clk_get(&pdev->dev, "uhpck");
175         if (IS_ERR(fclk)) {
176                 dev_err(&pdev->dev, "Error getting function clock\n");
177                 retval = -ENOENT;
178                 goto fail_get_fclk;
179         }
180
181         atmel_start_ehci(pdev);
182
183         retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
184         if (retval)
185                 goto fail_add_hcd;
186
187         return retval;
188
189 fail_add_hcd:
190         atmel_stop_ehci(pdev);
191         clk_put(fclk);
192 fail_get_fclk:
193         clk_put(iclk);
194 fail_get_iclk:
195         iounmap(hcd->regs);
196 fail_ioremap:
197         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
198 fail_request_resource:
199         usb_put_hcd(hcd);
200 fail_create_hcd:
201         dev_err(&pdev->dev, "init %s fail, %d\n",
202                 dev_name(&pdev->dev), retval);
203
204         return retval;
205 }
206
207 static int __exit ehci_atmel_drv_remove(struct platform_device *pdev)
208 {
209         struct usb_hcd *hcd = platform_get_drvdata(pdev);
210
211         ehci_shutdown(hcd);
212         usb_remove_hcd(hcd);
213         iounmap(hcd->regs);
214         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
215         usb_put_hcd(hcd);
216
217         atmel_stop_ehci(pdev);
218         clk_put(fclk);
219         clk_put(iclk);
220         fclk = iclk = NULL;
221
222         return 0;
223 }
224
225 static struct platform_driver ehci_atmel_driver = {
226         .probe          = ehci_atmel_drv_probe,
227         .remove         = __exit_p(ehci_atmel_drv_remove),
228         .shutdown       = usb_hcd_platform_shutdown,
229         .driver.name    = "atmel-ehci",
230 };