aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavankumar Kondeti <pkondeti@codeaurora.org>2010-12-07 07:23:56 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-12-10 17:23:32 -0500
commitb0848aea10da186372582f33152efdda43944f26 (patch)
tree681c7e880b3d5cd0d279b3eb72b7123a890dd0e8
parente0c201f339fe7fc38d1b0f6f4755ff627686c7e0 (diff)
USB: EHCI: Add MSM Host Controller driver
This patch adds support for EHCI compliant HSUSB Host controller found on MSM chips. The root hub has a single port and TT is built into it. This driver depends on OTG driver for PHY initialization, clock management and powering up VBUS. Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/host/Kconfig11
-rw-r--r--drivers/usb/host/ehci-hcd.c5
-rw-r--r--drivers/usb/host/ehci-msm.c290
4 files changed, 307 insertions, 0 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 6585f0b67801..b8e70a982fd4 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -64,6 +64,7 @@ config USB_ARCH_HAS_EHCI
64 default y if ARCH_OMAP3 64 default y if ARCH_OMAP3
65 default y if ARCH_VT8500 65 default y if ARCH_VT8500
66 default y if PLAT_SPEAR 66 default y if PLAT_SPEAR
67 default y if ARCH_MSM
67 default PCI 68 default PCI
68 69
69# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. 70# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 6a7c688b4781..d8665ec0565b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -141,6 +141,17 @@ config USB_EHCI_HCD_OMAP
141 Enables support for the on-chip EHCI controller on 141 Enables support for the on-chip EHCI controller on
142 OMAP3 and later chips. 142 OMAP3 and later chips.
143 143
144config USB_EHCI_MSM
145 bool "Support for MSM on-chip EHCI USB controller"
146 depends on USB_EHCI_HCD && ARCH_MSM
147 select USB_EHCI_ROOT_HUB_TT
148 select USB_MSM_OTG_72K
149 ---help---
150 Enables support for the USB Host controller present on the
151 Qualcomm chipsets. Root Hub has inbuilt TT.
152 This driver depends on OTG driver for PHY initialization,
153 clock management, powering up VBUS.
154
144config USB_EHCI_HCD_PPC_OF 155config USB_EHCI_HCD_PPC_OF
145 bool "EHCI support for PPC USB controller on OF platform bus" 156 bool "EHCI support for PPC USB controller on OF platform bus"
146 depends on USB_EHCI_HCD && PPC_OF 157 depends on USB_EHCI_HCD && PPC_OF
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 6778fbcf2416..48021d26024c 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1239,6 +1239,11 @@ MODULE_LICENSE ("GPL");
1239#define PLATFORM_DRIVER spear_ehci_hcd_driver 1239#define PLATFORM_DRIVER spear_ehci_hcd_driver
1240#endif 1240#endif
1241 1241
1242#ifdef CONFIG_USB_EHCI_MSM
1243#include "ehci-msm.c"
1244#define PLATFORM_DRIVER ehci_msm_driver
1245#endif
1246
1242#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ 1247#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
1243 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ 1248 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
1244 !defined(XILINX_OF_PLATFORM_DRIVER) 1249 !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
new file mode 100644
index 000000000000..9ed855986599
--- /dev/null
+++ b/drivers/usb/host/ehci-msm.c
@@ -0,0 +1,290 @@
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
29#include <linux/usb/otg.h>
30#include <linux/usb/msm_hsusb_hw.h>
31
32#define MSM_USB_BASE (hcd->regs)
33
34static struct otg_transceiver *otg;
35
36/*
37 * ehci_run defined in drivers/usb/host/ehci-hcd.c reset the controller and
38 * the configuration settings in ehci_msm_reset vanish after controller is
39 * reset. Resetting the controler in ehci_run seems to be un-necessary
40 * provided HCD reset the controller before calling ehci_run. Most of the HCD
41 * do but some are not. So this function is same as ehci_run but we don't
42 * reset the controller here.
43 */
44static int ehci_msm_run(struct usb_hcd *hcd)
45{
46 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
47 u32 temp;
48 u32 hcc_params;
49
50 hcd->uses_new_polling = 1;
51
52 ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
53 ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
54
55 /*
56 * hcc_params controls whether ehci->regs->segment must (!!!)
57 * be used; it constrains QH/ITD/SITD and QTD locations.
58 * pci_pool consistent memory always uses segment zero.
59 * streaming mappings for I/O buffers, like pci_map_single(),
60 * can return segments above 4GB, if the device allows.
61 *
62 * NOTE: the dma mask is visible through dma_supported(), so
63 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
64 * Scsi_Host.highmem_io, and so forth. It's readonly to all
65 * host side drivers though.
66 */
67 hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
68 if (HCC_64BIT_ADDR(hcc_params))
69 ehci_writel(ehci, 0, &ehci->regs->segment);
70
71 /*
72 * Philips, Intel, and maybe others need CMD_RUN before the
73 * root hub will detect new devices (why?); NEC doesn't
74 */
75 ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
76 ehci->command |= CMD_RUN;
77 ehci_writel(ehci, ehci->command, &ehci->regs->command);
78 dbg_cmd(ehci, "init", ehci->command);
79
80 /*
81 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
82 * are explicitly handed to companion controller(s), so no TT is
83 * involved with the root hub. (Except where one is integrated,
84 * and there's no companion controller unless maybe for USB OTG.)
85 *
86 * Turning on the CF flag will transfer ownership of all ports
87 * from the companions to the EHCI controller. If any of the
88 * companions are in the middle of a port reset at the time, it
89 * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
90 * guarantees that no resets are in progress. After we set CF,
91 * a short delay lets the hardware catch up; new resets shouldn't
92 * be started before the port switching actions could complete.
93 */
94 down_write(&ehci_cf_port_reset_rwsem);
95 hcd->state = HC_STATE_RUNNING;
96 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
97 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
98 usleep_range(5000, 5500);
99 up_write(&ehci_cf_port_reset_rwsem);
100 ehci->last_periodic_enable = ktime_get_real();
101
102 temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
103 ehci_info(ehci,
104 "USB %x.%x started, EHCI %x.%02x%s\n",
105 ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
106 temp >> 8, temp & 0xff,
107 ignore_oc ? ", overcurrent ignored" : "");
108
109 ehci_writel(ehci, INTR_MASK,
110 &ehci->regs->intr_enable); /* Turn On Interrupts */
111
112 /* GRR this is run-once init(), being done every time the HC starts.
113 * So long as they're part of class devices, we can't do it init()
114 * since the class device isn't created that early.
115 */
116 create_debug_files(ehci);
117 create_companion_file(ehci);
118
119 return 0;
120}
121
122static int ehci_msm_reset(struct usb_hcd *hcd)
123{
124 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
125 int retval;
126
127 ehci->caps = USB_CAPLENGTH;
128 ehci->regs = USB_CAPLENGTH +
129 HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
130
131 /* cache the data to minimize the chip reads*/
132 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
133
134 hcd->has_tt = 1;
135 ehci->sbrn = HCD_USB2;
136
137 /* data structure init */
138 retval = ehci_init(hcd);
139 if (retval)
140 return retval;
141
142 retval = ehci_reset(ehci);
143 if (retval)
144 return retval;
145
146 /* bursts of unspecified length. */
147 writel(0, USB_AHBBURST);
148 /* Use the AHB transactor */
149 writel(0, USB_AHBMODE);
150 /* Disable streaming mode and select host mode */
151 writel(0x13, USB_USBMODE);
152
153 ehci_port_power(ehci, 1);
154 return 0;
155}
156
157static struct hc_driver msm_hc_driver = {
158 .description = hcd_name,
159 .product_desc = "Qualcomm On-Chip EHCI Host Controller",
160 .hcd_priv_size = sizeof(struct ehci_hcd),
161
162 /*
163 * generic hardware linkage
164 */
165 .irq = ehci_irq,
166 .flags = HCD_USB2 | HCD_MEMORY,
167
168 .reset = ehci_msm_reset,
169 .start = ehci_msm_run,
170
171 .stop = ehci_stop,
172 .shutdown = ehci_shutdown,
173
174 /*
175 * managing i/o requests and associated device resources
176 */
177 .urb_enqueue = ehci_urb_enqueue,
178 .urb_dequeue = ehci_urb_dequeue,
179 .endpoint_disable = ehci_endpoint_disable,
180 .endpoint_reset = ehci_endpoint_reset,
181 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
182
183 /*
184 * scheduling support
185 */
186 .get_frame_number = ehci_get_frame,
187
188 /*
189 * root hub support
190 */
191 .hub_status_data = ehci_hub_status_data,
192 .hub_control = ehci_hub_control,
193 .relinquish_port = ehci_relinquish_port,
194 .port_handed_over = ehci_port_handed_over,
195
196 /*
197 * PM support
198 */
199 .bus_suspend = ehci_bus_suspend,
200 .bus_resume = ehci_bus_resume,
201};
202
203static int ehci_msm_probe(struct platform_device *pdev)
204{
205 struct usb_hcd *hcd;
206 struct resource *res;
207 int ret;
208
209 dev_dbg(&pdev->dev, "ehci_msm proble\n");
210
211 hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
212 if (!hcd) {
213 dev_err(&pdev->dev, "Unable to create HCD\n");
214 return -ENOMEM;
215 }
216
217 hcd->irq = platform_get_irq(pdev, 0);
218 if (hcd->irq < 0) {
219 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
220 ret = hcd->irq;
221 goto put_hcd;
222 }
223
224 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
225 if (!res) {
226 dev_err(&pdev->dev, "Unable to get memory resource\n");
227 ret = -ENODEV;
228 goto put_hcd;
229 }
230
231 hcd->rsrc_start = res->start;
232 hcd->rsrc_len = resource_size(res);
233 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
234 if (!hcd->regs) {
235 dev_err(&pdev->dev, "ioremap failed\n");
236 ret = -ENOMEM;
237 goto put_hcd;
238 }
239
240 /*
241 * OTG driver takes care of PHY initialization, clock management,
242 * powering up VBUS and mapping of registers address space.
243 */
244 otg = otg_get_transceiver();
245 if (!otg) {
246 dev_err(&pdev->dev, "unable to find transceiver\n");
247 ret = -ENODEV;
248 goto unmap;
249 }
250
251 ret = otg_set_host(otg, &hcd->self);
252 if (ret < 0) {
253 dev_err(&pdev->dev, "unable to register with transceiver\n");
254 goto put_transceiver;
255 }
256
257 device_init_wakeup(&pdev->dev, 1);
258 return 0;
259
260put_transceiver:
261 otg_put_transceiver(otg);
262unmap:
263 iounmap(hcd->regs);
264put_hcd:
265 usb_put_hcd(hcd);
266
267 return ret;
268}
269
270static int __devexit ehci_msm_remove(struct platform_device *pdev)
271{
272 struct usb_hcd *hcd = platform_get_drvdata(pdev);
273
274 device_init_wakeup(&pdev->dev, 0);
275
276 otg_set_host(otg, NULL);
277 otg_put_transceiver(otg);
278
279 usb_put_hcd(hcd);
280
281 return 0;
282}
283
284static struct platform_driver ehci_msm_driver = {
285 .probe = ehci_msm_probe,
286 .remove = __devexit_p(ehci_msm_remove),
287 .driver = {
288 .name = "msm_hsusb_host",
289 },
290};