aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-omap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-omap.c')
-rw-r--r--drivers/usb/host/ehci-omap.c184
1 files changed, 174 insertions, 10 deletions
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index a44294d13494..c30435499a02 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -43,6 +43,7 @@
43#include <linux/regulator/consumer.h> 43#include <linux/regulator/consumer.h>
44#include <linux/pm_runtime.h> 44#include <linux/pm_runtime.h>
45#include <linux/gpio.h> 45#include <linux/gpio.h>
46#include <linux/clk.h>
46 47
47/* EHCI Register Set */ 48/* EHCI Register Set */
48#define EHCI_INSNREG04 (0xA0) 49#define EHCI_INSNREG04 (0xA0)
@@ -55,6 +56,15 @@
55#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 56#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
56#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 57#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
57 58
59/* Errata i693 */
60static struct clk *utmi_p1_fck;
61static struct clk *utmi_p2_fck;
62static struct clk *xclk60mhsp1_ck;
63static struct clk *xclk60mhsp2_ck;
64static struct clk *usbhost_p1_fck;
65static struct clk *usbhost_p2_fck;
66static struct clk *init_60m_fclk;
67
58/*-------------------------------------------------------------------------*/ 68/*-------------------------------------------------------------------------*/
59 69
60static const struct hc_driver ehci_omap_hc_driver; 70static const struct hc_driver ehci_omap_hc_driver;
@@ -70,6 +80,41 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
70 return __raw_readl(base + reg); 80 return __raw_readl(base + reg);
71} 81}
72 82
83/* Erratum i693 workaround sequence */
84static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
85{
86 int ret = 0;
87
88 /* Switch to the internal 60 MHz clock */
89 ret = clk_set_parent(utmi_p1_fck, init_60m_fclk);
90 if (ret != 0)
91 ehci_err(ehci, "init_60m_fclk set parent"
92 "failed error:%d\n", ret);
93
94 ret = clk_set_parent(utmi_p2_fck, init_60m_fclk);
95 if (ret != 0)
96 ehci_err(ehci, "init_60m_fclk set parent"
97 "failed error:%d\n", ret);
98
99 clk_enable(usbhost_p1_fck);
100 clk_enable(usbhost_p2_fck);
101
102 /* Wait 1ms and switch back to the external clock */
103 mdelay(1);
104 ret = clk_set_parent(utmi_p1_fck, xclk60mhsp1_ck);
105 if (ret != 0)
106 ehci_err(ehci, "xclk60mhsp1_ck set parent"
107 "failed error:%d\n", ret);
108
109 ret = clk_set_parent(utmi_p2_fck, xclk60mhsp2_ck);
110 if (ret != 0)
111 ehci_err(ehci, "xclk60mhsp2_ck set parent"
112 "failed error:%d\n", ret);
113
114 clk_disable(usbhost_p1_fck);
115 clk_disable(usbhost_p2_fck);
116}
117
73static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port) 118static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
74{ 119{
75 struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); 120 struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
@@ -100,6 +145,50 @@ static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
100 } 145 }
101} 146}
102 147
148static int omap_ehci_hub_control(
149 struct usb_hcd *hcd,
150 u16 typeReq,
151 u16 wValue,
152 u16 wIndex,
153 char *buf,
154 u16 wLength
155)
156{
157 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
158 u32 __iomem *status_reg = &ehci->regs->port_status[
159 (wIndex & 0xff) - 1];
160 u32 temp;
161 unsigned long flags;
162 int retval = 0;
163
164 spin_lock_irqsave(&ehci->lock, flags);
165
166 if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
167 temp = ehci_readl(ehci, status_reg);
168 if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
169 retval = -EPIPE;
170 goto done;
171 }
172
173 temp &= ~PORT_WKCONN_E;
174 temp |= PORT_WKDISC_E | PORT_WKOC_E;
175 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
176
177 omap_ehci_erratum_i693(ehci);
178
179 set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
180 goto done;
181 }
182
183 spin_unlock_irqrestore(&ehci->lock, flags);
184
185 /* Handle the hub control events here */
186 return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
187done:
188 spin_unlock_irqrestore(&ehci->lock, flags);
189 return retval;
190}
191
103static void disable_put_regulator( 192static void disable_put_regulator(
104 struct ehci_hcd_omap_platform_data *pdata) 193 struct ehci_hcd_omap_platform_data *pdata)
105{ 194{
@@ -192,14 +281,13 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
192 } 281 }
193 } 282 }
194 283
284 /* Hold PHYs in reset while initializing EHCI controller */
195 if (pdata->phy_reset) { 285 if (pdata->phy_reset) {
196 if (gpio_is_valid(pdata->reset_gpio_port[0])) 286 if (gpio_is_valid(pdata->reset_gpio_port[0]))
197 gpio_request_one(pdata->reset_gpio_port[0], 287 gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
198 GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
199 288
200 if (gpio_is_valid(pdata->reset_gpio_port[1])) 289 if (gpio_is_valid(pdata->reset_gpio_port[1]))
201 gpio_request_one(pdata->reset_gpio_port[1], 290 gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
202 GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
203 291
204 /* Hold the PHY in RESET for enough time till DIR is high */ 292 /* Hold the PHY in RESET for enough time till DIR is high */
205 udelay(10); 293 udelay(10);
@@ -241,6 +329,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
241 omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params); 329 omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
242 330
243 ehci_reset(omap_ehci); 331 ehci_reset(omap_ehci);
332 ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
333 if (ret) {
334 dev_err(dev, "failed to add hcd with err %d\n", ret);
335 goto err_add_hcd;
336 }
244 337
245 if (pdata->phy_reset) { 338 if (pdata->phy_reset) {
246 /* Hold the PHY in RESET for enough time till 339 /* Hold the PHY in RESET for enough time till
@@ -255,17 +348,79 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
255 gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); 348 gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
256 } 349 }
257 350
258 ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 351 /* root ports should always stay powered */
259 if (ret) { 352 ehci_port_power(omap_ehci, 1);
260 dev_err(dev, "failed to add hcd with err %d\n", ret); 353
354 /* get clocks */
355 utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
356 if (IS_ERR(utmi_p1_fck)) {
357 ret = PTR_ERR(utmi_p1_fck);
358 dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
261 goto err_add_hcd; 359 goto err_add_hcd;
262 } 360 }
263 361
264 /* root ports should always stay powered */ 362 xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
265 ehci_port_power(omap_ehci, 1); 363 if (IS_ERR(xclk60mhsp1_ck)) {
364 ret = PTR_ERR(xclk60mhsp1_ck);
365 dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
366 goto err_utmi_p1_fck;
367 }
368
369 utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
370 if (IS_ERR(utmi_p2_fck)) {
371 ret = PTR_ERR(utmi_p2_fck);
372 dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
373 goto err_xclk60mhsp1_ck;
374 }
375
376 xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
377 if (IS_ERR(xclk60mhsp2_ck)) {
378 ret = PTR_ERR(xclk60mhsp2_ck);
379 dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
380 goto err_utmi_p2_fck;
381 }
382
383 usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
384 if (IS_ERR(usbhost_p1_fck)) {
385 ret = PTR_ERR(usbhost_p1_fck);
386 dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
387 goto err_xclk60mhsp2_ck;
388 }
389
390 usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
391 if (IS_ERR(usbhost_p2_fck)) {
392 ret = PTR_ERR(usbhost_p2_fck);
393 dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
394 goto err_usbhost_p1_fck;
395 }
396
397 init_60m_fclk = clk_get(dev, "init_60m_fclk");
398 if (IS_ERR(init_60m_fclk)) {
399 ret = PTR_ERR(init_60m_fclk);
400 dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
401 goto err_usbhost_p2_fck;
402 }
266 403
267 return 0; 404 return 0;
268 405
406err_usbhost_p2_fck:
407 clk_put(usbhost_p2_fck);
408
409err_usbhost_p1_fck:
410 clk_put(usbhost_p1_fck);
411
412err_xclk60mhsp2_ck:
413 clk_put(xclk60mhsp2_ck);
414
415err_utmi_p2_fck:
416 clk_put(utmi_p2_fck);
417
418err_xclk60mhsp1_ck:
419 clk_put(xclk60mhsp1_ck);
420
421err_utmi_p1_fck:
422 clk_put(utmi_p1_fck);
423
269err_add_hcd: 424err_add_hcd:
270 disable_put_regulator(pdata); 425 disable_put_regulator(pdata);
271 pm_runtime_put_sync(dev); 426 pm_runtime_put_sync(dev);
@@ -294,6 +449,15 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
294 disable_put_regulator(dev->platform_data); 449 disable_put_regulator(dev->platform_data);
295 iounmap(hcd->regs); 450 iounmap(hcd->regs);
296 usb_put_hcd(hcd); 451 usb_put_hcd(hcd);
452
453 clk_put(utmi_p1_fck);
454 clk_put(utmi_p2_fck);
455 clk_put(xclk60mhsp1_ck);
456 clk_put(xclk60mhsp2_ck);
457 clk_put(usbhost_p1_fck);
458 clk_put(usbhost_p2_fck);
459 clk_put(init_60m_fclk);
460
297 pm_runtime_put_sync(dev); 461 pm_runtime_put_sync(dev);
298 pm_runtime_disable(dev); 462 pm_runtime_disable(dev);
299 463
@@ -364,7 +528,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
364 * root hub support 528 * root hub support
365 */ 529 */
366 .hub_status_data = ehci_hub_status_data, 530 .hub_status_data = ehci_hub_status_data,
367 .hub_control = ehci_hub_control, 531 .hub_control = omap_ehci_hub_control,
368 .bus_suspend = ehci_bus_suspend, 532 .bus_suspend = ehci_bus_suspend,
369 .bus_resume = ehci_bus_resume, 533 .bus_resume = ehci_bus_resume,
370 534