aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-mxc.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/host/ehci-mxc.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/host/ehci-mxc.c')
-rw-r--r--drivers/usb/host/ehci-mxc.c100
1 files changed, 69 insertions, 31 deletions
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index a8ad8ac120a2..0c058be35a38 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -21,17 +21,17 @@
21#include <linux/clk.h> 21#include <linux/clk.h>
22#include <linux/delay.h> 22#include <linux/delay.h>
23#include <linux/usb/otg.h> 23#include <linux/usb/otg.h>
24#include <linux/usb/ulpi.h>
24#include <linux/slab.h> 25#include <linux/slab.h>
25 26
26#include <mach/mxc_ehci.h> 27#include <mach/mxc_ehci.h>
27 28
29#include <asm/mach-types.h>
30
28#define ULPI_VIEWPORT_OFFSET 0x170 31#define ULPI_VIEWPORT_OFFSET 0x170
29#define PORTSC_OFFSET 0x184
30#define USBMODE_OFFSET 0x1a8
31#define USBMODE_CM_HOST 3
32 32
33struct ehci_mxc_priv { 33struct ehci_mxc_priv {
34 struct clk *usbclk, *ahbclk; 34 struct clk *usbclk, *ahbclk, *phy1clk;
35 struct usb_hcd *hcd; 35 struct usb_hcd *hcd;
36}; 36};
37 37
@@ -41,16 +41,14 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
41 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 41 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
42 int retval; 42 int retval;
43 43
44 /* EHCI registers start at offset 0x100 */
45 ehci->caps = hcd->regs + 0x100;
46 ehci->regs = hcd->regs + 0x100 +
47 HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
48 dbg_hcs_params(ehci, "reset"); 44 dbg_hcs_params(ehci, "reset");
49 dbg_hcc_params(ehci, "reset"); 45 dbg_hcc_params(ehci, "reset");
50 46
51 /* cache this readonly data; minimize chip reads */ 47 /* cache this readonly data; minimize chip reads */
52 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 48 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
53 49
50 hcd->has_tt = 1;
51
54 retval = ehci_halt(ehci); 52 retval = ehci_halt(ehci);
55 if (retval) 53 if (retval)
56 return retval; 54 return retval;
@@ -60,8 +58,6 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
60 if (retval) 58 if (retval)
61 return retval; 59 return retval;
62 60
63 hcd->has_tt = 1;
64
65 ehci->sbrn = 0x20; 61 ehci->sbrn = 0x20;
66 62
67 ehci_reset(ehci); 63 ehci_reset(ehci);
@@ -95,6 +91,7 @@ static const struct hc_driver ehci_mxc_hc_driver = {
95 .urb_enqueue = ehci_urb_enqueue, 91 .urb_enqueue = ehci_urb_enqueue,
96 .urb_dequeue = ehci_urb_dequeue, 92 .urb_dequeue = ehci_urb_dequeue,
97 .endpoint_disable = ehci_endpoint_disable, 93 .endpoint_disable = ehci_endpoint_disable,
94 .endpoint_reset = ehci_endpoint_reset,
98 95
99 /* 96 /*
100 * scheduling support 97 * scheduling support
@@ -110,6 +107,8 @@ static const struct hc_driver ehci_mxc_hc_driver = {
110 .bus_resume = ehci_bus_resume, 107 .bus_resume = ehci_bus_resume,
111 .relinquish_port = ehci_relinquish_port, 108 .relinquish_port = ehci_relinquish_port,
112 .port_handed_over = ehci_port_handed_over, 109 .port_handed_over = ehci_port_handed_over,
110
111 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
113}; 112};
114 113
115static int ehci_mxc_drv_probe(struct platform_device *pdev) 114static int ehci_mxc_drv_probe(struct platform_device *pdev)
@@ -117,9 +116,11 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
117 struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; 116 struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
118 struct usb_hcd *hcd; 117 struct usb_hcd *hcd;
119 struct resource *res; 118 struct resource *res;
120 int irq, ret, temp; 119 int irq, ret;
120 unsigned int flags;
121 struct ehci_mxc_priv *priv; 121 struct ehci_mxc_priv *priv;
122 struct device *dev = &pdev->dev; 122 struct device *dev = &pdev->dev;
123 struct ehci_hcd *ehci;
123 124
124 dev_info(&pdev->dev, "initializing i.MX USB Controller\n"); 125 dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
125 126
@@ -163,17 +164,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
163 goto err_ioremap; 164 goto err_ioremap;
164 } 165 }
165 166
166 /* call platform specific init function */
167 if (pdata->init) {
168 ret = pdata->init(pdev);
169 if (ret) {
170 dev_err(dev, "platform init failed\n");
171 goto err_init;
172 }
173 /* platforms need some time to settle changed IO settings */
174 mdelay(10);
175 }
176
177 /* enable clocks */ 167 /* enable clocks */
178 priv->usbclk = clk_get(dev, "usb"); 168 priv->usbclk = clk_get(dev, "usb");
179 if (IS_ERR(priv->usbclk)) { 169 if (IS_ERR(priv->usbclk)) {
@@ -191,18 +181,40 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
191 clk_enable(priv->ahbclk); 181 clk_enable(priv->ahbclk);
192 } 182 }
193 183
194 /* set USBMODE to host mode */ 184 /* "dr" device has its own clock on i.MX51 */
195 temp = readl(hcd->regs + USBMODE_OFFSET); 185 if (cpu_is_mx51() && (pdev->id == 0)) {
196 writel(temp | USBMODE_CM_HOST, hcd->regs + USBMODE_OFFSET); 186 priv->phy1clk = clk_get(dev, "usb_phy1");
187 if (IS_ERR(priv->phy1clk)) {
188 ret = PTR_ERR(priv->phy1clk);
189 goto err_clk_phy;
190 }
191 clk_enable(priv->phy1clk);
192 }
193
194
195 /* call platform specific init function */
196 if (pdata->init) {
197 ret = pdata->init(pdev);
198 if (ret) {
199 dev_err(dev, "platform init failed\n");
200 goto err_init;
201 }
202 /* platforms need some time to settle changed IO settings */
203 mdelay(10);
204 }
205
206 ehci = hcd_to_ehci(hcd);
207
208 /* EHCI registers start at offset 0x100 */
209 ehci->caps = hcd->regs + 0x100;
210 ehci->regs = hcd->regs + 0x100 +
211 HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
197 212
198 /* set up the PORTSCx register */ 213 /* set up the PORTSCx register */
199 writel(pdata->portsc, hcd->regs + PORTSC_OFFSET); 214 ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
200 mdelay(10);
201 215
202 /* setup specific usb hw */ 216 /* is this really needed? */
203 ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); 217 msleep(10);
204 if (ret < 0)
205 goto err_init;
206 218
207 /* Initialize the transceiver */ 219 /* Initialize the transceiver */
208 if (pdata->otg) { 220 if (pdata->otg) {
@@ -227,12 +239,34 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
227 if (ret) 239 if (ret)
228 goto err_add; 240 goto err_add;
229 241
242 if (pdata->otg) {
243 /*
244 * efikamx and efikasb have some hardware bug which is
245 * preventing usb to work unless CHRGVBUS is set.
246 * It's in violation of USB specs
247 */
248 if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
249 flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
250 flags |= ULPI_OTG_CTRL_CHRGVBUS;
251 ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
252 if (ret) {
253 dev_err(dev, "unable to set CHRVBUS\n");
254 goto err_add;
255 }
256 }
257 }
258
230 return 0; 259 return 0;
231 260
232err_add: 261err_add:
233 if (pdata && pdata->exit) 262 if (pdata && pdata->exit)
234 pdata->exit(pdev); 263 pdata->exit(pdev);
235err_init: 264err_init:
265 if (priv->phy1clk) {
266 clk_disable(priv->phy1clk);
267 clk_put(priv->phy1clk);
268 }
269err_clk_phy:
236 if (priv->ahbclk) { 270 if (priv->ahbclk) {
237 clk_disable(priv->ahbclk); 271 clk_disable(priv->ahbclk);
238 clk_put(priv->ahbclk); 272 clk_put(priv->ahbclk);
@@ -276,6 +310,10 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
276 clk_disable(priv->ahbclk); 310 clk_disable(priv->ahbclk);
277 clk_put(priv->ahbclk); 311 clk_put(priv->ahbclk);
278 } 312 }
313 if (priv->phy1clk) {
314 clk_disable(priv->phy1clk);
315 clk_put(priv->phy1clk);
316 }
279 317
280 kfree(priv); 318 kfree(priv);
281 319