diff options
| -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); |
