summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Lin <stlin@nvidia.com>2011-10-17 14:22:21 -0700
committerRyan Wong <ryanw@nvidia.com>2011-10-19 17:10:51 -0700
commite694acfd92427450476c98905a8b87816edaec96 (patch)
treec2a1b3795bc70b1695b38a58b501a4476b3c4b6e
parent4711968d8d3864a0eedf383e31183b61519c59b1 (diff)
arm: tegra: usb: Adding phy_restore functions for null ULPI
Adding phy_restore_start and phy_restore_end functions for null ULPI. Forcing ehci_restart after LP0 for null ULPI. Bug 863224 Reviewed-on: http://git-master/r/58474 (cherry picked from commit 5f5e7961c8a6a5be853fcdba4ae10d0bd6efc5f3) Change-Id: If49f6acdcf15661f765c345431a52695bc045d29 Reviewed-on: http://git-master/r/59200 Reviewed-by: Ryan Wong <ryanw@nvidia.com> Tested-by: Ryan Wong <ryanw@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/include/mach/usb_phy.h5
-rw-r--r--arch/arm/mach-tegra/usb_phy.c125
-rw-r--r--drivers/usb/host/ehci-tegra.c30
3 files changed, 125 insertions, 35 deletions
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
index a6fa0944ce23..fa2a759230df 100644
--- a/arch/arm/mach-tegra/include/mach/usb_phy.h
+++ b/arch/arm/mach-tegra/include/mach/usb_phy.h
@@ -51,6 +51,8 @@ struct tegra_ulpi_config {
int (*post_phy_on)(void);
int (*pre_phy_off)(void);
int (*post_phy_off)(void);
+ void (*phy_restore_start)(void);
+ void (*phy_restore_end)(void);
};
struct tegra_uhsic_config {
@@ -108,6 +110,9 @@ struct tegra_usb_phy {
};
typedef int (*tegra_phy_fp)(struct tegra_usb_phy *phy, bool is_dpd);
+typedef void (*tegra_phy_restore_start_fp)(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed);
+typedef void (*tegra_phy_restore_end_fp)(struct tegra_usb_phy *phy);
struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
void *config, enum tegra_usb_phy_mode phy_mode,
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index e147b10d32fe..4d9765cb65ee 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -1605,29 +1605,16 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
#endif
}
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
static void ulpi_set_tristate(bool enable)
{
int tristate = (enable)? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
-#else
- 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_CLK, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_STP, tristate);
- tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate);
-#endif
}
+#endif
static void ulpi_phy_reset(void __iomem *base)
{
@@ -1833,12 +1820,75 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
return 0;
}
+static void null_phy_set_tristate(bool enable)
+{
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
+#else
+ 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);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate);
+
+ if (enable)
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate);
+#endif
+}
+
+static void null_phy_restore_start(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed port_speed)
+{
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ struct tegra_ulpi_config *config = phy->config;
+
+ if (config->phy_restore_start)
+ config->phy_restore_start();
+#endif
+}
+
+static void null_phy_restore_end(struct tegra_usb_phy *phy)
+{
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = phy->config;
+
+ if (config->phy_restore_end)
+ config->phy_restore_end();
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+
+ udelay(500);
+
+ /* remove ULPI tristate except DIR */
+ null_phy_set_tristate(false);
+ udelay(20);
+
+ /* enable ULPI CLK output pad */
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ /* remove DIR tristate */
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, TEGRA_TRI_NORMAL);
+#endif
+}
+
static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
{
const struct tegra_ulpi_trimmer default_trimmer = {0, 0, 4, 4};
unsigned long val;
void __iomem *base = phy->regs;
struct tegra_ulpi_config *config = phy->config;
+ static bool cold_boot = true;
if (!config->trimmer)
config->trimmer = &default_trimmer;
@@ -1856,8 +1906,6 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
writel(val, base + ULPI_TIMING_CTRL_0);
- ulpi_set_tristate(false);
-
if (config->pre_phy_on && config->pre_phy_on())
return -EAGAIN;
@@ -1926,9 +1974,12 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
val &= ~ULPI_PADS_RESET;
writel(val, base + USB_SUSP_CTRL);
#endif
- val = readl(base + ULPI_TIMING_CTRL_0);
- val |= ULPI_CLK_PADOUT_ENA;
- writel(val, base + ULPI_TIMING_CTRL_0);
+ if (cold_boot) {
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ cold_boot = false;
+ }
udelay(10);
@@ -1940,14 +1991,12 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
static int null_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
{
- unsigned long val;
- void __iomem *base = phy->regs;
struct tegra_ulpi_config *config = phy->config;
if (config->pre_phy_off && config->pre_phy_off())
return -EAGAIN;
- ulpi_set_tristate(true);
+ null_phy_set_tristate(true);
if (config->post_phy_off && config->post_phy_off())
return -EAGAIN;
@@ -1979,6 +2028,8 @@ static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd)
unsigned long val;
void __iomem *base = phy->regs;
+ ulpi_set_host(base);
+
/* remove slave0 reset */
val = readl(base + USB_SUSP_CTRL);
val &= ~ULPIS2S_SLV0_RESET;
@@ -1988,8 +2039,6 @@ static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd)
val &= ~ULPIS2S_SLV0_CLAMP_XMIT;
writel(val, base + ULPIS2S_CTRL);
udelay(10);
-
- ulpi_set_host(base);
#endif
return 0;
}
@@ -2434,18 +2483,28 @@ void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd)
void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
enum tegra_usb_phy_port_speed port_speed)
{
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP)
- utmi_phy_restore_start(phy, port_speed);
- else
- ulpi_phy_restore_start(phy, port_speed);
+ const tegra_phy_restore_start_fp phy_restore_start[] = {
+ utmi_phy_restore_start,
+ ulpi_phy_restore_start,
+ null_phy_restore_start,
+ NULL,
+ };
+
+ if (phy_restore_start[phy->usb_phy_type])
+ phy_restore_start[phy->usb_phy_type](phy, port_speed);
}
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
{
- if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP)
- utmi_phy_restore_end(phy);
- else
- ulpi_phy_restore_end(phy);
+ const tegra_phy_restore_end_fp phy_restore_end[] = {
+ utmi_phy_restore_end,
+ ulpi_phy_restore_end,
+ null_phy_restore_end,
+ NULL,
+ };
+
+ if (phy_restore_end[phy->usb_phy_type])
+ phy_restore_end[phy->usb_phy_type](phy);
}
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index fcce552769ba..89b7771df901 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -437,14 +437,17 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_regs __iomem *hw = ehci->regs;
unsigned long val;
- int hsic = 0;
+ bool hsic;
+ bool null_ulpi;
+ null_ulpi = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI);
hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC);
tegra_ehci_power_up(hcd, is_dpd);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- if ((tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) || (hsic))
+ if ((tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) || (hsic) ||
+ (null_ulpi))
goto restart;
/* Force the phy to keep data lines in suspend state */
@@ -540,6 +543,29 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
return 0;
restart:
+ if (null_ulpi) {
+ bool LP0 = !readl(&hw->async_next);
+
+ if (LP0) {
+ static int cnt = 1;
+
+ pr_info("LP0 restart %d\n", cnt++);
+ tegra_ehci_phy_restore_start(tegra->phy,
+ tegra->port_speed);
+ }
+
+ val = readl(&hw->port_status[0]);
+ if (!((val & PORT_POWER) && (val & PORT_PE))) {
+ tegra_ehci_restart(hcd);
+ usb_set_device_state(udev, USB_STATE_CONFIGURED);
+ }
+
+ if (LP0)
+ tegra_ehci_phy_restore_end(tegra->phy);
+
+ return 0;
+ }
+
if ((tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) && (!hsic))
tegra_ehci_phy_restore_end(tegra->phy);
if (hsic) {