diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_usb_phy.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_usb_phy.c | 141 |
1 files changed, 102 insertions, 39 deletions
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c index 5b3e51974d3b..8ada255cad55 100644 --- a/arch/arm/mach-tegra/tegra3_usb_phy.c +++ b/arch/arm/mach-tegra/tegra3_usb_phy.c @@ -888,6 +888,7 @@ static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy) mdelay(1); } +#ifdef KERNEL_WARNING static void usb_phy_power_down_pmc(void) { unsigned long val; @@ -931,6 +932,7 @@ static void usb_phy_power_down_pmc(void) UHSIC_MASTER_ENABLE_P0; writel(val, pmc_base + PMC_SLEEP_CFG); } +#endif static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy) { @@ -1142,10 +1144,6 @@ static void utmi_phy_close(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); } - val = readl(base + USB_PORTSC); - val |= USB_PORTSC_WKCN; - writel(val, base + USB_PORTSC); - clk_put(phy->utmi_pad_clk); } @@ -1341,16 +1339,20 @@ static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup) unsigned int inst = phy->inst; DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); - - val = (readl(base + HOSTPC1_DEVLC) >> 25) & + phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & HOSTPC1_DEVLC_PSPD_MASK; - if (val == USB_PHY_PORT_SPEED_HIGH) { + + if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) { /* Disable interrupts */ writel(0, base + USB_USBINTR); /* Clear the run bit to stop SOFs - 2LS WAR */ val = readl(base + USB_USBCMD); val &= ~USB_USBCMD_RS; writel(val, base + USB_USBCMD); + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH, + USB_USBSTS_HCH, 2000)) { + pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__); + } } val = readl(pmc_base + PMC_SLEEP_CFG); @@ -1388,6 +1390,21 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) val |= UTMIP_PD_CHRG; writel(val, base + UTMIP_BAT_CHRG_CFG0); } else { + phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & + HOSTPC1_DEVLC_PSPD_MASK; + + /* Disable interrupts */ + writel(0, base + USB_USBINTR); + + /* Clear the run bit to stop SOFs - 2LS WAR */ + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH, + USB_USBSTS_HCH, 2000)) { + pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__); + } utmip_setup_pmc_wake_detect(phy); } @@ -1409,9 +1426,6 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_pad_power_off(phy); - phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) & - HOSTPC1_DEVLC_PSPD_MASK; - if (phy->pdata->u_data.host.hot_plug) { bool enable_hotplug = true; /* if it is OTG port then make sure to enable hot-plug feature @@ -1776,7 +1790,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 +1911,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 +2167,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 +2177,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 +2228,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 +2367,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 +2388,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 +2444,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, }; |