diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/omap-usb-host.c | 131 |
1 files changed, 122 insertions, 9 deletions
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 855219526ccb..1717144fe7f4 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <plat/usb.h> | 28 | #include <plat/usb.h> |
29 | #include <linux/pm_runtime.h> | ||
30 | 29 | ||
31 | #define USBHS_DRIVER_NAME "usbhs-omap" | 30 | #define USBHS_DRIVER_NAME "usbhs-omap" |
32 | #define OMAP_EHCI_DEVICE "ehci-omap" | 31 | #define OMAP_EHCI_DEVICE "ehci-omap" |
@@ -147,6 +146,9 @@ | |||
147 | 146 | ||
148 | 147 | ||
149 | struct usbhs_hcd_omap { | 148 | struct usbhs_hcd_omap { |
149 | struct clk *usbhost_ick; | ||
150 | struct clk *usbhost_hs_fck; | ||
151 | struct clk *usbhost_fs_fck; | ||
150 | struct clk *xclk60mhsp1_ck; | 152 | struct clk *xclk60mhsp1_ck; |
151 | struct clk *xclk60mhsp2_ck; | 153 | struct clk *xclk60mhsp2_ck; |
152 | struct clk *utmi_p1_fck; | 154 | struct clk *utmi_p1_fck; |
@@ -156,6 +158,8 @@ struct usbhs_hcd_omap { | |||
156 | struct clk *usbhost_p2_fck; | 158 | struct clk *usbhost_p2_fck; |
157 | struct clk *usbtll_p2_fck; | 159 | struct clk *usbtll_p2_fck; |
158 | struct clk *init_60m_fclk; | 160 | struct clk *init_60m_fclk; |
161 | struct clk *usbtll_fck; | ||
162 | struct clk *usbtll_ick; | ||
159 | 163 | ||
160 | void __iomem *uhh_base; | 164 | void __iomem *uhh_base; |
161 | void __iomem *tll_base; | 165 | void __iomem *tll_base; |
@@ -349,13 +353,46 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) | |||
349 | omap->platdata.ehci_data = pdata->ehci_data; | 353 | omap->platdata.ehci_data = pdata->ehci_data; |
350 | omap->platdata.ohci_data = pdata->ohci_data; | 354 | omap->platdata.ohci_data = pdata->ohci_data; |
351 | 355 | ||
352 | pm_runtime_enable(&pdev->dev); | 356 | omap->usbhost_ick = clk_get(dev, "usbhost_ick"); |
357 | if (IS_ERR(omap->usbhost_ick)) { | ||
358 | ret = PTR_ERR(omap->usbhost_ick); | ||
359 | dev_err(dev, "usbhost_ick failed error:%d\n", ret); | ||
360 | goto err_end; | ||
361 | } | ||
362 | |||
363 | omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); | ||
364 | if (IS_ERR(omap->usbhost_hs_fck)) { | ||
365 | ret = PTR_ERR(omap->usbhost_hs_fck); | ||
366 | dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); | ||
367 | goto err_usbhost_ick; | ||
368 | } | ||
369 | |||
370 | omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); | ||
371 | if (IS_ERR(omap->usbhost_fs_fck)) { | ||
372 | ret = PTR_ERR(omap->usbhost_fs_fck); | ||
373 | dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); | ||
374 | goto err_usbhost_hs_fck; | ||
375 | } | ||
376 | |||
377 | omap->usbtll_fck = clk_get(dev, "usbtll_fck"); | ||
378 | if (IS_ERR(omap->usbtll_fck)) { | ||
379 | ret = PTR_ERR(omap->usbtll_fck); | ||
380 | dev_err(dev, "usbtll_fck failed error:%d\n", ret); | ||
381 | goto err_usbhost_fs_fck; | ||
382 | } | ||
383 | |||
384 | omap->usbtll_ick = clk_get(dev, "usbtll_ick"); | ||
385 | if (IS_ERR(omap->usbtll_ick)) { | ||
386 | ret = PTR_ERR(omap->usbtll_ick); | ||
387 | dev_err(dev, "usbtll_ick failed error:%d\n", ret); | ||
388 | goto err_usbtll_fck; | ||
389 | } | ||
353 | 390 | ||
354 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | 391 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); |
355 | if (IS_ERR(omap->utmi_p1_fck)) { | 392 | if (IS_ERR(omap->utmi_p1_fck)) { |
356 | ret = PTR_ERR(omap->utmi_p1_fck); | 393 | ret = PTR_ERR(omap->utmi_p1_fck); |
357 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | 394 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); |
358 | goto err_end; | 395 | goto err_usbtll_ick; |
359 | } | 396 | } |
360 | 397 | ||
361 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | 398 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); |
@@ -485,8 +522,22 @@ err_xclk60mhsp1_ck: | |||
485 | err_utmi_p1_fck: | 522 | err_utmi_p1_fck: |
486 | clk_put(omap->utmi_p1_fck); | 523 | clk_put(omap->utmi_p1_fck); |
487 | 524 | ||
525 | err_usbtll_ick: | ||
526 | clk_put(omap->usbtll_ick); | ||
527 | |||
528 | err_usbtll_fck: | ||
529 | clk_put(omap->usbtll_fck); | ||
530 | |||
531 | err_usbhost_fs_fck: | ||
532 | clk_put(omap->usbhost_fs_fck); | ||
533 | |||
534 | err_usbhost_hs_fck: | ||
535 | clk_put(omap->usbhost_hs_fck); | ||
536 | |||
537 | err_usbhost_ick: | ||
538 | clk_put(omap->usbhost_ick); | ||
539 | |||
488 | err_end: | 540 | err_end: |
489 | pm_runtime_disable(&pdev->dev); | ||
490 | kfree(omap); | 541 | kfree(omap); |
491 | 542 | ||
492 | end_probe: | 543 | end_probe: |
@@ -520,7 +571,11 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) | |||
520 | clk_put(omap->utmi_p2_fck); | 571 | clk_put(omap->utmi_p2_fck); |
521 | clk_put(omap->xclk60mhsp1_ck); | 572 | clk_put(omap->xclk60mhsp1_ck); |
522 | clk_put(omap->utmi_p1_fck); | 573 | clk_put(omap->utmi_p1_fck); |
523 | pm_runtime_disable(&pdev->dev); | 574 | clk_put(omap->usbtll_ick); |
575 | clk_put(omap->usbtll_fck); | ||
576 | clk_put(omap->usbhost_fs_fck); | ||
577 | clk_put(omap->usbhost_hs_fck); | ||
578 | clk_put(omap->usbhost_ick); | ||
524 | kfree(omap); | 579 | kfree(omap); |
525 | 580 | ||
526 | return 0; | 581 | return 0; |
@@ -640,6 +695,7 @@ static int usbhs_enable(struct device *dev) | |||
640 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 695 | struct usbhs_omap_platform_data *pdata = &omap->platdata; |
641 | unsigned long flags = 0; | 696 | unsigned long flags = 0; |
642 | int ret = 0; | 697 | int ret = 0; |
698 | unsigned long timeout; | ||
643 | unsigned reg; | 699 | unsigned reg; |
644 | 700 | ||
645 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | 701 | dev_dbg(dev, "starting TI HSUSB Controller\n"); |
@@ -652,7 +708,11 @@ static int usbhs_enable(struct device *dev) | |||
652 | if (omap->count > 0) | 708 | if (omap->count > 0) |
653 | goto end_count; | 709 | goto end_count; |
654 | 710 | ||
655 | pm_runtime_get_sync(dev); | 711 | clk_enable(omap->usbhost_ick); |
712 | clk_enable(omap->usbhost_hs_fck); | ||
713 | clk_enable(omap->usbhost_fs_fck); | ||
714 | clk_enable(omap->usbtll_fck); | ||
715 | clk_enable(omap->usbtll_ick); | ||
656 | 716 | ||
657 | if (pdata->ehci_data->phy_reset) { | 717 | if (pdata->ehci_data->phy_reset) { |
658 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { | 718 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { |
@@ -676,6 +736,50 @@ static int usbhs_enable(struct device *dev) | |||
676 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | 736 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); |
677 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | 737 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); |
678 | 738 | ||
739 | /* perform TLL soft reset, and wait until reset is complete */ | ||
740 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
741 | OMAP_USBTLL_SYSCONFIG_SOFTRESET); | ||
742 | |||
743 | /* Wait for TLL reset to complete */ | ||
744 | timeout = jiffies + msecs_to_jiffies(1000); | ||
745 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
746 | & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { | ||
747 | cpu_relax(); | ||
748 | |||
749 | if (time_after(jiffies, timeout)) { | ||
750 | dev_dbg(dev, "operation timed out\n"); | ||
751 | ret = -EINVAL; | ||
752 | goto err_tll; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | dev_dbg(dev, "TLL RESET DONE\n"); | ||
757 | |||
758 | /* (1<<3) = no idle mode only for initial debugging */ | ||
759 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
760 | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | | ||
761 | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | | ||
762 | OMAP_USBTLL_SYSCONFIG_AUTOIDLE); | ||
763 | |||
764 | /* Put UHH in NoIdle/NoStandby mode */ | ||
765 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); | ||
766 | if (is_omap_usbhs_rev1(omap)) { | ||
767 | reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | ||
768 | | OMAP_UHH_SYSCONFIG_SIDLEMODE | ||
769 | | OMAP_UHH_SYSCONFIG_CACTIVITY | ||
770 | | OMAP_UHH_SYSCONFIG_MIDLEMODE); | ||
771 | reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; | ||
772 | |||
773 | |||
774 | } else if (is_omap_usbhs_rev2(omap)) { | ||
775 | reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; | ||
776 | reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; | ||
777 | reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; | ||
778 | reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; | ||
779 | } | ||
780 | |||
781 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); | ||
782 | |||
679 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | 783 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); |
680 | /* setup ULPI bypass and burst configurations */ | 784 | /* setup ULPI bypass and burst configurations */ |
681 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | 785 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
@@ -815,8 +919,6 @@ end_count: | |||
815 | return 0; | 919 | return 0; |
816 | 920 | ||
817 | err_tll: | 921 | err_tll: |
818 | pm_runtime_put_sync(dev); | ||
819 | spin_unlock_irqrestore(&omap->lock, flags); | ||
820 | if (pdata->ehci_data->phy_reset) { | 922 | if (pdata->ehci_data->phy_reset) { |
821 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 923 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) |
822 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | 924 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); |
@@ -824,6 +926,13 @@ err_tll: | |||
824 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 926 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) |
825 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | 927 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); |
826 | } | 928 | } |
929 | |||
930 | clk_disable(omap->usbtll_ick); | ||
931 | clk_disable(omap->usbtll_fck); | ||
932 | clk_disable(omap->usbhost_fs_fck); | ||
933 | clk_disable(omap->usbhost_hs_fck); | ||
934 | clk_disable(omap->usbhost_ick); | ||
935 | spin_unlock_irqrestore(&omap->lock, flags); | ||
827 | return ret; | 936 | return ret; |
828 | } | 937 | } |
829 | 938 | ||
@@ -896,7 +1005,11 @@ static void usbhs_disable(struct device *dev) | |||
896 | clk_disable(omap->utmi_p1_fck); | 1005 | clk_disable(omap->utmi_p1_fck); |
897 | } | 1006 | } |
898 | 1007 | ||
899 | pm_runtime_put_sync(dev); | 1008 | clk_disable(omap->usbtll_ick); |
1009 | clk_disable(omap->usbtll_fck); | ||
1010 | clk_disable(omap->usbhost_fs_fck); | ||
1011 | clk_disable(omap->usbhost_hs_fck); | ||
1012 | clk_disable(omap->usbhost_ick); | ||
900 | 1013 | ||
901 | /* The gpio_free migh sleep; so unlock the spinlock */ | 1014 | /* The gpio_free migh sleep; so unlock the spinlock */ |
902 | spin_unlock_irqrestore(&omap->lock, flags); | 1015 | spin_unlock_irqrestore(&omap->lock, flags); |