USB: serial: visor: fix crash on detecting device without write_urbs
[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, 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         .endpoint_reset         = ehci_endpoint_reset,
103
104         /* scheduling support */
105         .get_frame_number       = ehci_get_frame,
106
107         /* root hub support */
108         .hub_status_data        = ehci_hub_status_data,
109         .hub_control            = ehci_hub_control,
110         .bus_suspend            = ehci_bus_suspend,
111         .bus_resume             = ehci_bus_resume,
112         .relinquish_port        = ehci_relinquish_port,
113         .port_handed_over       = ehci_port_handed_over,
114
115         .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
116 };
117
118 static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
119 {
120         struct usb_hcd *hcd;
121         const struct hc_driver *driver = &ehci_atmel_hc_driver;
122         struct resource *res;
123         int irq;
124         int retval;
125
126         if (usb_disabled())
127                 return -ENODEV;
128
129         pr_debug("Initializing Atmel-SoC USB Host Controller\n");
130
131         irq = platform_get_irq(pdev, 0);
132         if (irq <= 0) {
133                 dev_err(&pdev->dev,
134                         "Found HC with no IRQ. Check %s setup!\n",
135                         dev_name(&pdev->dev));
136                 retval = -ENODEV;
137                 goto fail_create_hcd;
138         }
139
140         hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
141         if (!hcd) {
142                 retval = -ENOMEM;
143                 goto fail_create_hcd;
144         }
145
146         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
147         if (!res) {
148                 dev_err(&pdev->dev,
149                         "Found HC with no register addr. Check %s setup!\n",
150                         dev_name(&pdev->dev));
151                 retval = -ENODEV;
152                 goto fail_request_resource;
153         }
154         hcd->rsrc_start = res->start;
155         hcd->rsrc_len = resource_size(res);
156
157         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
158                                 driver->description)) {
159                 dev_dbg(&pdev->dev, "controller already in use\n");
160                 retval = -EBUSY;
161                 goto fail_request_resource;
162         }
163
164         hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
165         if (hcd->regs == NULL) {
166                 dev_dbg(&pdev->dev, "error mapping memory\n");
167                 retval = -EFAULT;
168                 goto fail_ioremap;
169         }
170
171         iclk = clk_get(&pdev->dev, "ehci_clk");
172         if (IS_ERR(iclk)) {
173                 dev_err(&pdev->dev, "Error getting interface clock\n");
174                 retval = -ENOENT;
175                 goto fail_get_iclk;
176         }
177         fclk = clk_get(&pdev->dev, "uhpck");
178         if (IS_ERR(fclk)) {
179                 dev_err(&pdev->dev, "Error getting function clock\n");
180                 retval = -ENOENT;
181                 goto fail_get_fclk;
182         }
183
184         atmel_start_ehci(pdev);
185
186         retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
187         if (retval)
188                 goto fail_add_hcd;
189
190         return retval;
191
192 fail_add_hcd:
193         atmel_stop_ehci(pdev);
194         clk_put(fclk);
195 fail_get_fclk:
196         clk_put(iclk);
197 fail_get_iclk:
198         iounmap(hcd->regs);
199 fail_ioremap:
200         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
201 fail_request_resource:
202         usb_put_hcd(hcd);
203 fail_create_hcd:
204         dev_err(&pdev->dev, "init %s fail, %d\n",
205                 dev_name(&pdev->dev), retval);
206
207         return retval;
208 }
209
210 static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
211 {
212         struct usb_hcd *hcd = platform_get_drvdata(pdev);
213
214         ehci_shutdown(hcd);
215         usb_remove_hcd(hcd);
216         iounmap(hcd->regs);
217         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
218         usb_put_hcd(hcd);
219
220         atmel_stop_ehci(pdev);
221         clk_put(fclk);
222         clk_put(iclk);
223         fclk = iclk = NULL;
224
225         return 0;
226 }
227
228 static struct platform_driver ehci_atmel_driver = {
229         .probe          = ehci_atmel_drv_probe,
230         .remove         = __devexit_p(ehci_atmel_drv_remove),
231         .shutdown       = usb_hcd_platform_shutdown,
232         .driver.name    = "atmel-ehci",
233 };