diff options
Diffstat (limited to 'drivers/usb/host/ehci-msm.c')
-rw-r--r-- | drivers/usb/host/ehci-msm.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c new file mode 100644 index 000000000000..413f4deca532 --- /dev/null +++ b/drivers/usb/host/ehci-msm.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* ehci-msm.c - HSUSB Host Controller Driver Implementation | ||
2 | * | ||
3 | * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. | ||
4 | * | ||
5 | * Partly derived from ehci-fsl.c and ehci-hcd.c | ||
6 | * Copyright (c) 2000-2004 by David Brownell | ||
7 | * Copyright (c) 2005 MontaVista Software | ||
8 | * | ||
9 | * All source code in this file is licensed under the following license except | ||
10 | * where indicated. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License version 2 as published | ||
14 | * by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
19 | * | ||
20 | * See the GNU General Public License for more details. | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, you can find it at http://www.fsf.org | ||
23 | */ | ||
24 | |||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/pm_runtime.h> | ||
29 | |||
30 | #include <linux/usb/otg.h> | ||
31 | #include <linux/usb/msm_hsusb_hw.h> | ||
32 | |||
33 | #define MSM_USB_BASE (hcd->regs) | ||
34 | |||
35 | static struct otg_transceiver *otg; | ||
36 | |||
37 | /* | ||
38 | * ehci_run defined in drivers/usb/host/ehci-hcd.c reset the controller and | ||
39 | * the configuration settings in ehci_msm_reset vanish after controller is | ||
40 | * reset. Resetting the controler in ehci_run seems to be un-necessary | ||
41 | * provided HCD reset the controller before calling ehci_run. Most of the HCD | ||
42 | * do but some are not. So this function is same as ehci_run but we don't | ||
43 | * reset the controller here. | ||
44 | */ | ||
45 | static int ehci_msm_run(struct usb_hcd *hcd) | ||
46 | { | ||
47 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
48 | u32 temp; | ||
49 | u32 hcc_params; | ||
50 | |||
51 | hcd->uses_new_polling = 1; | ||
52 | |||
53 | ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); | ||
54 | ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); | ||
55 | |||
56 | /* | ||
57 | * hcc_params controls whether ehci->regs->segment must (!!!) | ||
58 | * be used; it constrains QH/ITD/SITD and QTD locations. | ||
59 | * pci_pool consistent memory always uses segment zero. | ||
60 | * streaming mappings for I/O buffers, like pci_map_single(), | ||
61 | * can return segments above 4GB, if the device allows. | ||
62 | * | ||
63 | * NOTE: the dma mask is visible through dma_supported(), so | ||
64 | * drivers can pass this info along ... like NETIF_F_HIGHDMA, | ||
65 | * Scsi_Host.highmem_io, and so forth. It's readonly to all | ||
66 | * host side drivers though. | ||
67 | */ | ||
68 | hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); | ||
69 | if (HCC_64BIT_ADDR(hcc_params)) | ||
70 | ehci_writel(ehci, 0, &ehci->regs->segment); | ||
71 | |||
72 | /* | ||
73 | * Philips, Intel, and maybe others need CMD_RUN before the | ||
74 | * root hub will detect new devices (why?); NEC doesn't | ||
75 | */ | ||
76 | ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); | ||
77 | ehci->command |= CMD_RUN; | ||
78 | ehci_writel(ehci, ehci->command, &ehci->regs->command); | ||
79 | dbg_cmd(ehci, "init", ehci->command); | ||
80 | |||
81 | /* | ||
82 | * Start, enabling full USB 2.0 functionality ... usb 1.1 devices | ||
83 | * are explicitly handed to companion controller(s), so no TT is | ||
84 | * involved with the root hub. (Except where one is integrated, | ||
85 | * and there's no companion controller unless maybe for USB OTG.) | ||
86 | * | ||
87 | * Turning on the CF flag will transfer ownership of all ports | ||
88 | * from the companions to the EHCI controller. If any of the | ||
89 | * companions are in the middle of a port reset at the time, it | ||
90 | * could cause trouble. Write-locking ehci_cf_port_reset_rwsem | ||
91 | * guarantees that no resets are in progress. After we set CF, | ||
92 | * a short delay lets the hardware catch up; new resets shouldn't | ||
93 | * be started before the port switching actions could complete. | ||
94 | */ | ||
95 | down_write(&ehci_cf_port_reset_rwsem); | ||
96 | hcd->state = HC_STATE_RUNNING; | ||
97 | ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); | ||
98 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ | ||
99 | usleep_range(5000, 5500); | ||
100 | up_write(&ehci_cf_port_reset_rwsem); | ||
101 | ehci->last_periodic_enable = ktime_get_real(); | ||
102 | |||
103 | temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); | ||
104 | ehci_info(ehci, | ||
105 | "USB %x.%x started, EHCI %x.%02x%s\n", | ||
106 | ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), | ||
107 | temp >> 8, temp & 0xff, | ||
108 | ignore_oc ? ", overcurrent ignored" : ""); | ||
109 | |||
110 | ehci_writel(ehci, INTR_MASK, | ||
111 | &ehci->regs->intr_enable); /* Turn On Interrupts */ | ||
112 | |||
113 | /* GRR this is run-once init(), being done every time the HC starts. | ||
114 | * So long as they're part of class devices, we can't do it init() | ||
115 | * since the class device isn't created that early. | ||
116 | */ | ||
117 | create_debug_files(ehci); | ||
118 | create_companion_file(ehci); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int ehci_msm_reset(struct usb_hcd *hcd) | ||
124 | { | ||
125 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
126 | int retval; | ||
127 | |||
128 | ehci->caps = USB_CAPLENGTH; | ||
129 | ehci->regs = USB_CAPLENGTH + | ||
130 | HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); | ||
131 | |||
132 | /* cache the data to minimize the chip reads*/ | ||
133 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); | ||
134 | |||
135 | hcd->has_tt = 1; | ||
136 | ehci->sbrn = HCD_USB2; | ||
137 | |||
138 | /* data structure init */ | ||
139 | retval = ehci_init(hcd); | ||
140 | if (retval) | ||
141 | return retval; | ||
142 | |||
143 | retval = ehci_reset(ehci); | ||
144 | if (retval) | ||
145 | return retval; | ||
146 | |||
147 | /* bursts of unspecified length. */ | ||
148 | writel(0, USB_AHBBURST); | ||
149 | /* Use the AHB transactor */ | ||
150 | writel(0, USB_AHBMODE); | ||
151 | /* Disable streaming mode and select host mode */ | ||
152 | writel(0x13, USB_USBMODE); | ||
153 | |||
154 | ehci_port_power(ehci, 1); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static struct hc_driver msm_hc_driver = { | ||
159 | .description = hcd_name, | ||
160 | .product_desc = "Qualcomm On-Chip EHCI Host Controller", | ||
161 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
162 | |||
163 | /* | ||
164 | * generic hardware linkage | ||
165 | */ | ||
166 | .irq = ehci_irq, | ||
167 | .flags = HCD_USB2 | HCD_MEMORY, | ||
168 | |||
169 | .reset = ehci_msm_reset, | ||
170 | .start = ehci_msm_run, | ||
171 | |||
172 | .stop = ehci_stop, | ||
173 | .shutdown = ehci_shutdown, | ||
174 | |||
175 | /* | ||
176 | * managing i/o requests and associated device resources | ||
177 | */ | ||
178 | .urb_enqueue = ehci_urb_enqueue, | ||
179 | .urb_dequeue = ehci_urb_dequeue, | ||
180 | .endpoint_disable = ehci_endpoint_disable, | ||
181 | .endpoint_reset = ehci_endpoint_reset, | ||
182 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
183 | |||
184 | /* | ||
185 | * scheduling support | ||
186 | */ | ||
187 | .get_frame_number = ehci_get_frame, | ||
188 | |||
189 | /* | ||
190 | * root hub support | ||
191 | */ | ||
192 | .hub_status_data = ehci_hub_status_data, | ||
193 | .hub_control = ehci_hub_control, | ||
194 | .relinquish_port = ehci_relinquish_port, | ||
195 | .port_handed_over = ehci_port_handed_over, | ||
196 | |||
197 | /* | ||
198 | * PM support | ||
199 | */ | ||
200 | .bus_suspend = ehci_bus_suspend, | ||
201 | .bus_resume = ehci_bus_resume, | ||
202 | }; | ||
203 | |||
204 | static int ehci_msm_probe(struct platform_device *pdev) | ||
205 | { | ||
206 | struct usb_hcd *hcd; | ||
207 | struct resource *res; | ||
208 | int ret; | ||
209 | |||
210 | dev_dbg(&pdev->dev, "ehci_msm proble\n"); | ||
211 | |||
212 | hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev)); | ||
213 | if (!hcd) { | ||
214 | dev_err(&pdev->dev, "Unable to create HCD\n"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | hcd->irq = platform_get_irq(pdev, 0); | ||
219 | if (hcd->irq < 0) { | ||
220 | dev_err(&pdev->dev, "Unable to get IRQ resource\n"); | ||
221 | ret = hcd->irq; | ||
222 | goto put_hcd; | ||
223 | } | ||
224 | |||
225 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
226 | if (!res) { | ||
227 | dev_err(&pdev->dev, "Unable to get memory resource\n"); | ||
228 | ret = -ENODEV; | ||
229 | goto put_hcd; | ||
230 | } | ||
231 | |||
232 | hcd->rsrc_start = res->start; | ||
233 | hcd->rsrc_len = resource_size(res); | ||
234 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
235 | if (!hcd->regs) { | ||
236 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
237 | ret = -ENOMEM; | ||
238 | goto put_hcd; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * OTG driver takes care of PHY initialization, clock management, | ||
243 | * powering up VBUS, mapping of registers address space and power | ||
244 | * management. | ||
245 | */ | ||
246 | otg = otg_get_transceiver(); | ||
247 | if (!otg) { | ||
248 | dev_err(&pdev->dev, "unable to find transceiver\n"); | ||
249 | ret = -ENODEV; | ||
250 | goto unmap; | ||
251 | } | ||
252 | |||
253 | ret = otg_set_host(otg, &hcd->self); | ||
254 | if (ret < 0) { | ||
255 | dev_err(&pdev->dev, "unable to register with transceiver\n"); | ||
256 | goto put_transceiver; | ||
257 | } | ||
258 | |||
259 | device_init_wakeup(&pdev->dev, 1); | ||
260 | /* | ||
261 | * OTG device parent of HCD takes care of putting | ||
262 | * hardware into low power mode. | ||
263 | */ | ||
264 | pm_runtime_no_callbacks(&pdev->dev); | ||
265 | pm_runtime_enable(&pdev->dev); | ||
266 | |||
267 | return 0; | ||
268 | |||
269 | put_transceiver: | ||
270 | otg_put_transceiver(otg); | ||
271 | unmap: | ||
272 | iounmap(hcd->regs); | ||
273 | put_hcd: | ||
274 | usb_put_hcd(hcd); | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | static int __devexit ehci_msm_remove(struct platform_device *pdev) | ||
280 | { | ||
281 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
282 | |||
283 | device_init_wakeup(&pdev->dev, 0); | ||
284 | pm_runtime_disable(&pdev->dev); | ||
285 | pm_runtime_set_suspended(&pdev->dev); | ||
286 | |||
287 | otg_set_host(otg, NULL); | ||
288 | otg_put_transceiver(otg); | ||
289 | |||
290 | usb_put_hcd(hcd); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | #ifdef CONFIG_PM | ||
296 | static int ehci_msm_pm_suspend(struct device *dev) | ||
297 | { | ||
298 | struct usb_hcd *hcd = dev_get_drvdata(dev); | ||
299 | bool wakeup = device_may_wakeup(dev); | ||
300 | |||
301 | dev_dbg(dev, "ehci-msm PM suspend\n"); | ||
302 | |||
303 | /* | ||
304 | * EHCI helper function has also the same check before manipulating | ||
305 | * port wakeup flags. We do check here the same condition before | ||
306 | * calling the same helper function to avoid bringing hardware | ||
307 | * from Low power mode when there is no need for adjusting port | ||
308 | * wakeup flags. | ||
309 | */ | ||
310 | if (hcd->self.root_hub->do_remote_wakeup && !wakeup) { | ||
311 | pm_runtime_resume(dev); | ||
312 | ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), | ||
313 | wakeup); | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int ehci_msm_pm_resume(struct device *dev) | ||
320 | { | ||
321 | struct usb_hcd *hcd = dev_get_drvdata(dev); | ||
322 | |||
323 | dev_dbg(dev, "ehci-msm PM resume\n"); | ||
324 | ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | #else | ||
329 | #define ehci_msm_pm_suspend NULL | ||
330 | #define ehci_msm_pm_resume NULL | ||
331 | #endif | ||
332 | |||
333 | static const struct dev_pm_ops ehci_msm_dev_pm_ops = { | ||
334 | .suspend = ehci_msm_pm_suspend, | ||
335 | .resume = ehci_msm_pm_resume, | ||
336 | }; | ||
337 | |||
338 | static struct platform_driver ehci_msm_driver = { | ||
339 | .probe = ehci_msm_probe, | ||
340 | .remove = __devexit_p(ehci_msm_remove), | ||
341 | .driver = { | ||
342 | .name = "msm_hsusb_host", | ||
343 | .pm = &ehci_msm_dev_pm_ops, | ||
344 | }, | ||
345 | }; | ||