diff options
author | Rebecca Schultz Zavin <rebecca@android.com> | 2011-05-02 12:29:14 -0700 |
---|---|---|
committer | Rebecca Schultz Zavin <rebecca@android.com> | 2011-05-02 12:29:14 -0700 |
commit | 6553d6b02a6ef7d3de4cbf10d9e7059a03f380de (patch) | |
tree | 60de016e0f2f0592d998dfe6fb4d41964138b1a3 | |
parent | 2e35e1d7b965893e68f2fb1af77129406be5ff05 (diff) | |
parent | 82e4366278f9037761488e9b7e03eaff4d90c9c9 (diff) | |
download | tegra-6553d6b02a6ef7d3de4cbf10d9e7059a03f380de.tar.gz |
Merge remote branch 'tegra/linux-tegra-2.6.36' into android-tegra-2.6.36
-rw-r--r-- | arch/arm/mach-tegra/include/mach/usb_phy.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/usb_phy.c | 108 |
2 files changed, 92 insertions, 17 deletions
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index d4b8f9e298a8..bca649d80e38 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -59,6 +59,7 @@ struct tegra_usb_phy { enum tegra_usb_phy_mode mode; void *config; struct otg_transceiver *ulpi; + int initialized; }; struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 88081bb3ec52..ef07efd11b19 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -30,8 +30,12 @@ #include <asm/mach-types.h> #include <mach/usb_phy.h> #include <mach/iomap.h> +#include <mach/pinmux.h> #define ULPI_VIEWPORT 0x170 +#define ULPI_WAKEUP (1 << 31) +#define ULPI_RUN (1 << 30) +#define ULPI_RD_WR (1 << 29) #define USB_PORTSC1 0x184 #define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) @@ -50,6 +54,7 @@ #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) #define USB_SUSP_CLR (1 << 5) +#define USB_CLKEN (1 << 6) #define USB_PHY_CLK_VALID (1 << 7) #define UTMIP_RESET (1 << 11) #define UHSIC_RESET (1 << 11) @@ -288,7 +293,7 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy) static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) { - unsigned long timeout = 2000; + unsigned long timeout = 2500; do { if ((readl(reg) & mask) == result) return 0; @@ -349,7 +354,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) } if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID)) + USB_PHY_CLK_VALID) < 0) pr_err("%s: timeout waiting for phy to stabilize\n", __func__); } @@ -566,6 +571,36 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy) udelay(10); } +static void ulpi_phy_restore_start(struct tegra_usb_phy *phy, + enum tegra_usb_phy_port_speed port_speed) +{ + unsigned long val; + void __iomem *base = phy->regs; + + /*Tristate ulpi interface before USB controller resume*/ + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_TRISTATE); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_TRISTATE); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_TRISTATE); + + val = readl(base + ULPI_TIMING_CTRL_0); + val &= ~ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); +} + +static void ulpi_phy_restore_end(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); + + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_NORMAL); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_NORMAL); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_NORMAL); +} + static int ulpi_phy_power_on(struct tegra_usb_phy *phy) { int ret; @@ -573,13 +608,16 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) void __iomem *base = phy->regs; struct tegra_ulpi_config *config = phy->config; - gpio_direction_output(config->reset_gpio, 0); - msleep(5); - gpio_direction_output(config->reset_gpio, 1); - clk_enable(phy->clk); msleep(1); + if (!phy->initialized) { + phy->initialized = 1; + gpio_direction_output(config->reset_gpio, 0); + msleep(5); + gpio_direction_output(config->reset_gpio, 1); + } + val = readl(base + USB_SUSP_CTRL); val |= UHSIC_RESET; writel(val, base + USB_SUSP_CTRL); @@ -592,6 +630,21 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) val |= ULPI_PHY_ENABLE; writel(val, base + USB_SUSP_CTRL); + val = readl(base + USB_SUSP_CTRL); + val |= USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); + + if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + USB_PHY_CLK_VALID) < 0) + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + + if (utmi_wait_register(base + USB_SUSP_CTRL, USB_CLKEN, USB_CLKEN) < 0) + pr_err("%s: timeout waiting for AHB clock\n", __func__); + + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); + val = 0; writel(val, base + ULPI_TIMING_CTRL_1); @@ -623,15 +676,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; writel(val, base + USB_PORTSC1); - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - udelay(100); - - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - return 0; } @@ -639,7 +683,25 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; - struct tegra_ulpi_config *config = phy->config; + int ret; + + /* Disable VbusValid, SessEnd comparators */ + ret = otg_io_write(phy->ulpi, 0x00, 0x0D); + if (ret) + pr_err("%s: ulpi write 0x0D failed\n", __func__); + + ret = otg_io_write(phy->ulpi, 0x00, 0x10); + if (ret) + pr_err("%s: ulpi write 0x10 failed\n", __func__); + + /* Disable IdFloat comparator */ + ret = otg_io_write(phy->ulpi, 0x00, 0x19); + if (ret) + pr_err("%s: ulpi write 0x19 failed\n", __func__); + + ret = otg_io_write(phy->ulpi, 0x00, 0x1D); + if (ret) + pr_err("%s: ulpi write 0x1D failed\n", __func__); /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB * Controller to immediately bring the ULPI PHY out of low power @@ -648,7 +710,14 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy) val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); writel(val, base + USB_PORTSC1); - gpio_direction_output(config->reset_gpio, 0); + /* Put the PHY in the low power mode */ + val = readl(base + USB_PORTSC1); + val |= USB_PORTSC1_PHCD; + writel(val, base + USB_PORTSC1); + + if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) + pr_err("%s: timeout waiting for phy to stop\n", __func__); + clk_disable(phy->clk); } @@ -669,6 +738,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, phy->regs = regs; phy->config = config; phy->mode = phy_mode; + phy->initialized = 0; if (!phy->config) { if (phy_is_ulpi(phy)) { @@ -763,12 +833,16 @@ void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, { if (!phy_is_ulpi(phy)) utmi_phy_restore_start(phy, port_speed); + else + ulpi_phy_restore_start(phy, port_speed); } void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) { if (!phy_is_ulpi(phy)) utmi_phy_restore_end(phy); + else + ulpi_phy_restore_end(phy); } void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) |