diff options
author | Keshava Munegowda <Keshava_mgowda@ti.com> | 2011-05-22 16:51:26 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-05-26 13:45:52 -0400 |
commit | 7e6502d577106fb5b202bbaac64c5f1b065e6daa (patch) | |
tree | b534ce2e049696ce10130d6755dcc1840cdcdff4 /drivers/mfd | |
parent | 74e32d1b68f177f9c998041d789253df9c7f3575 (diff) |
mfd: Add omap-usbhs runtime PM support
The usbhs core driver does not enable/disable the interface and
functional clocks; These clocks are handled by hwmod and runtime pm,
hence insted of the clock enable/disable, the runtime pm APIS are
used. however,the port clocks and tll clocks are handled
by the usbhs core.
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/omap-usb-host.c | 131 |
1 files changed, 9 insertions, 122 deletions
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 1717144fe7f4..855219526ccb 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -26,6 +26,7 @@ | |||
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> | ||
29 | 30 | ||
30 | #define USBHS_DRIVER_NAME "usbhs-omap" | 31 | #define USBHS_DRIVER_NAME "usbhs-omap" |
31 | #define OMAP_EHCI_DEVICE "ehci-omap" | 32 | #define OMAP_EHCI_DEVICE "ehci-omap" |
@@ -146,9 +147,6 @@ | |||
146 | 147 | ||
147 | 148 | ||
148 | struct usbhs_hcd_omap { | 149 | struct usbhs_hcd_omap { |
149 | struct clk *usbhost_ick; | ||
150 | struct clk *usbhost_hs_fck; | ||
151 | struct clk *usbhost_fs_fck; | ||
152 | struct clk *xclk60mhsp1_ck; | 150 | struct clk *xclk60mhsp1_ck; |
153 | struct clk *xclk60mhsp2_ck; | 151 | struct clk *xclk60mhsp2_ck; |
154 | struct clk *utmi_p1_fck; | 152 | struct clk *utmi_p1_fck; |
@@ -158,8 +156,6 @@ struct usbhs_hcd_omap { | |||
158 | struct clk *usbhost_p2_fck; | 156 | struct clk *usbhost_p2_fck; |
159 | struct clk *usbtll_p2_fck; | 157 | struct clk *usbtll_p2_fck; |
160 | struct clk *init_60m_fclk; | 158 | struct clk *init_60m_fclk; |
161 | struct clk *usbtll_fck; | ||
162 | struct clk *usbtll_ick; | ||
163 | 159 | ||
164 | void __iomem *uhh_base; | 160 | void __iomem *uhh_base; |
165 | void __iomem *tll_base; | 161 | void __iomem *tll_base; |
@@ -353,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) | |||
353 | omap->platdata.ehci_data = pdata->ehci_data; | 349 | omap->platdata.ehci_data = pdata->ehci_data; |
354 | omap->platdata.ohci_data = pdata->ohci_data; | 350 | omap->platdata.ohci_data = pdata->ohci_data; |
355 | 351 | ||
356 | omap->usbhost_ick = clk_get(dev, "usbhost_ick"); | 352 | pm_runtime_enable(&pdev->dev); |
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 | } | ||
390 | 353 | ||
391 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | 354 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); |
392 | if (IS_ERR(omap->utmi_p1_fck)) { | 355 | if (IS_ERR(omap->utmi_p1_fck)) { |
393 | ret = PTR_ERR(omap->utmi_p1_fck); | 356 | ret = PTR_ERR(omap->utmi_p1_fck); |
394 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | 357 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); |
395 | goto err_usbtll_ick; | 358 | goto err_end; |
396 | } | 359 | } |
397 | 360 | ||
398 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | 361 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); |
@@ -522,22 +485,8 @@ err_xclk60mhsp1_ck: | |||
522 | err_utmi_p1_fck: | 485 | err_utmi_p1_fck: |
523 | clk_put(omap->utmi_p1_fck); | 486 | clk_put(omap->utmi_p1_fck); |
524 | 487 | ||
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 | |||
540 | err_end: | 488 | err_end: |
489 | pm_runtime_disable(&pdev->dev); | ||
541 | kfree(omap); | 490 | kfree(omap); |
542 | 491 | ||
543 | end_probe: | 492 | end_probe: |
@@ -571,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) | |||
571 | clk_put(omap->utmi_p2_fck); | 520 | clk_put(omap->utmi_p2_fck); |
572 | clk_put(omap->xclk60mhsp1_ck); | 521 | clk_put(omap->xclk60mhsp1_ck); |
573 | clk_put(omap->utmi_p1_fck); | 522 | clk_put(omap->utmi_p1_fck); |
574 | clk_put(omap->usbtll_ick); | 523 | pm_runtime_disable(&pdev->dev); |
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); | ||
579 | kfree(omap); | 524 | kfree(omap); |
580 | 525 | ||
581 | return 0; | 526 | return 0; |
@@ -695,7 +640,6 @@ static int usbhs_enable(struct device *dev) | |||
695 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 640 | struct usbhs_omap_platform_data *pdata = &omap->platdata; |
696 | unsigned long flags = 0; | 641 | unsigned long flags = 0; |
697 | int ret = 0; | 642 | int ret = 0; |
698 | unsigned long timeout; | ||
699 | unsigned reg; | 643 | unsigned reg; |
700 | 644 | ||
701 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | 645 | dev_dbg(dev, "starting TI HSUSB Controller\n"); |
@@ -708,11 +652,7 @@ static int usbhs_enable(struct device *dev) | |||
708 | if (omap->count > 0) | 652 | if (omap->count > 0) |
709 | goto end_count; | 653 | goto end_count; |
710 | 654 | ||
711 | clk_enable(omap->usbhost_ick); | 655 | pm_runtime_get_sync(dev); |
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); | ||
716 | 656 | ||
717 | if (pdata->ehci_data->phy_reset) { | 657 | if (pdata->ehci_data->phy_reset) { |
718 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { | 658 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { |
@@ -736,50 +676,6 @@ static int usbhs_enable(struct device *dev) | |||
736 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | 676 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); |
737 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | 677 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); |
738 | 678 | ||
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 | |||
783 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | 679 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); |
784 | /* setup ULPI bypass and burst configurations */ | 680 | /* setup ULPI bypass and burst configurations */ |
785 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | 681 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
@@ -919,6 +815,8 @@ end_count: | |||
919 | return 0; | 815 | return 0; |
920 | 816 | ||
921 | err_tll: | 817 | err_tll: |
818 | pm_runtime_put_sync(dev); | ||
819 | spin_unlock_irqrestore(&omap->lock, flags); | ||
922 | if (pdata->ehci_data->phy_reset) { | 820 | if (pdata->ehci_data->phy_reset) { |
923 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 821 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) |
924 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | 822 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); |
@@ -926,13 +824,6 @@ err_tll: | |||
926 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 824 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) |
927 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | 825 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); |
928 | } | 826 | } |
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); | ||
936 | return ret; | 827 | return ret; |
937 | } | 828 | } |
938 | 829 | ||
@@ -1005,11 +896,7 @@ static void usbhs_disable(struct device *dev) | |||
1005 | clk_disable(omap->utmi_p1_fck); | 896 | clk_disable(omap->utmi_p1_fck); |
1006 | } | 897 | } |
1007 | 898 | ||
1008 | clk_disable(omap->usbtll_ick); | 899 | pm_runtime_put_sync(dev); |
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); | ||
1013 | 900 | ||
1014 | /* The gpio_free migh sleep; so unlock the spinlock */ | 901 | /* The gpio_free migh sleep; so unlock the spinlock */ |
1015 | spin_unlock_irqrestore(&omap->lock, flags); | 902 | spin_unlock_irqrestore(&omap->lock, flags); |