diff options
author | Venu Byravarasu <vbyravarasu@nvidia.com> | 2012-05-29 13:12:21 +0530 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2012-05-31 05:43:33 -0700 |
commit | 4c15f4cbfcd668c4a7c22f0cc31282f358e176b4 (patch) | |
tree | 7a5ebee948ea7ca8fe8a5a36d536ad2d9991dc2f /arch/arm/mach-tegra/tegra3_usb_phy.c | |
parent | 79cf64df799576ca4913f3d911ef61bbbcad93a9 (diff) |
arm: tegra: usb: fix suspend resume issues of ULPI phy
Fixing suspend resume issues observed with ULPI phy during
entering/exiting LP0 on enterprise.
bug 989510
Change-Id: Iaf5da7597281b5e1a78df7bdf32c46422cb5c6ef
Signed-off-by: Venu Byravarasu <vbyravarasu@nvidia.com>
Reviewed-on: http://git-master/r/104959
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_usb_phy.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_usb_phy.c | 107 |
1 files changed, 78 insertions, 29 deletions
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c index 5b3e51974d3b..432dd5509664 100644 --- a/arch/arm/mach-tegra/tegra3_usb_phy.c +++ b/arch/arm/mach-tegra/tegra3_usb_phy.c @@ -1776,7 +1776,7 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - utmip_powerup_pmc_wake_detect(phy); + uhsic_powerup_pmc_wake_detect(phy); if (phy->phy_clk_on) { DBG("%s(%d) inst:[%d] phy clk is already On\n", @@ -1897,7 +1897,7 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); udelay(30); - utmip_powerdown_pmc_wake_detect(phy); + uhsic_powerdown_pmc_wake_detect(phy); phy->phy_clk_on = false; phy->hw_accessible = false; @@ -2153,31 +2153,6 @@ static void ulpi_set_host(void __iomem *base) } - -static inline void null_phy_set_tristate(bool enable) -{ -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; - DBG("%s(%d) inst:[%s] FIXME enable pin group +++\n", __func__, - __LINE__, enable ? "TRISTATE" : "NORMAL"); - - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate); - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate); - - if (enable) - tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate); -#endif - -} - - static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy) { DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); @@ -2188,8 +2163,6 @@ static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy) return 0; } - null_phy_set_tristate(true); - phy->phy_clk_on = false; phy->hw_accessible = false; @@ -2241,6 +2214,52 @@ static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy) return 0; } +static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + ulpi_null_phy_init(phy); + + val = readl(base + USB_USBCMD); + val |= USB_CMD_RESET; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBCMD, + USB_CMD_RESET, 0, 2500) < 0) { + pr_err("%s: timeout waiting for reset\n", __func__); + } + + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + val |= USB_USBMODE_HOST; + writel(val, base + USB_USBMODE); + + ulpi_null_phy_cmd_reset(phy); + + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, + USB_USBCMD_RS, 2000)) { + pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__); + return -ETIMEDOUT; + } + + /* Enable Port Power */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_PP; + writel(val, base + USB_PORTSC); + udelay(10); + + /* disable ULPI pinmux bypass */ + val = readl(base + ULPI_TIMING_CTRL_0); + val &= ~ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + return 0; +} + static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) { unsigned long val; @@ -2334,6 +2353,9 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) val |= ULPI_CLK_PADOUT_ENA; writel(val, base + ULPI_TIMING_CTRL_0); cold_boot = false; + } else { + if (!readl(base + USB_ASYNCLISTADDR)) + ulpi_null_phy_lp0_resume(phy); } udelay(10); @@ -2352,6 +2374,32 @@ int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) return 0; } +static int ulpi_null_phy_resume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + if (!readl(base + USB_ASYNCLISTADDR)) { + /* enable ULPI CLK output pad */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_CLK_PADOUT_ENA; + writel(val, base + ULPI_TIMING_CTRL_0); + + /* enable ULPI pinmux bypass */ + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + udelay(5); +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + /* remove DIR tristate */ + tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, TEGRA_TRI_NORMAL); +#endif + } + return 0; +} + + + static struct tegra_usb_phy_ops utmi_phy_ops = { .open = utmi_phy_open, .close = utmi_phy_close, @@ -2382,6 +2430,7 @@ static struct tegra_usb_phy_ops ulpi_null_phy_ops = { .power_on = ulpi_null_phy_power_on, .power_off = ulpi_null_phy_power_off, .pre_resume = ulpi_null_phy_pre_resume, + .resume = ulpi_null_phy_resume, .reset = ulpi_null_phy_cmd_reset, }; |