summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/usb_phy.c
diff options
context:
space:
mode:
authorBenoit Goby <benoit@android.com>2010-07-23 17:02:26 -0700
committerColin Cross <ccross@android.com>2010-10-06 16:27:17 -0700
commita0e0319691daddef0dbcfa17264ed34356e55bf8 (patch)
treea92fdcd47b5ad6c4b5124dae6c8c130848df1958 /arch/arm/mach-tegra/usb_phy.c
parent288b58e155306231dfb5eccb3220e58bbc953b1e (diff)
[ARM] tegra: Setup USB PHY as recommended by NVIDIA
This fixes enumeration issues with some devices Change-Id: I6283a6fb49a9e4505ad388cacdd88ecf1bdf1b9d Signed-off-by: Benoit Goby <benoit@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/usb_phy.c')
-rw-r--r--arch/arm/mach-tegra/usb_phy.c66
1 files changed, 45 insertions, 21 deletions
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 602f4afa1eef..fb829861f5d4 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -35,6 +35,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_PHY_CLK_VALID (1 << 7)
#define UTMIP_RESET (1 << 11)
#define UTMIP_PHY_ENABLE (1 << 12)
#define USB_SUSP_SET (1 << 14)
@@ -54,6 +55,8 @@
#define UTMIP_XCVR_CFG0 0x808
#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
@@ -117,10 +120,27 @@ static const u16 udc_debounce_table[] = {
0xFDE8, /* 26 MHz */
};
+static int utmi_phy_wait_stable(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = phy->regs;
+ unsigned long timeout = jiffies + HZ;
+
+ while (time_before(jiffies, timeout)) {
+ if (readl(base + USB_SUSP_CTRL) & USB_PHY_CLK_VALID)
+ return 0;
+ udelay(10);
+ cpu_relax();
+ }
+ if (readl(base + USB_SUSP_CTRL) & USB_PHY_CLK_VALID)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel)
{
unsigned long val;
- void *base = phy->regs;
+ void __iomem *base = phy->regs;
val = readl(base + USB_SUSP_CTRL);
val |= UTMIP_RESET;
@@ -132,10 +152,6 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel)
writel(val, base + USB1_LEGACY_CTRL);
}
- val = readl(base + UTMIP_TX_CFG0);
- val |= UTMIP_FS_PREABMLE_J;
- writel(val, base + UTMIP_TX_CFG0);
-
val = readl(base + UTMIP_HSRX_CFG0);
val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
val |= UTMIP_IDLE_WAIT(17) | UTMIP_ELASTIC_LIMIT(16);
@@ -168,27 +184,31 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel)
writel(val, base + UTMIP_PLL_CFG1);
}
-void utmi_phy_power_on(struct tegra_usb_phy *phy)
+void utmi_phy_power_on(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_mode phy_mode)
{
unsigned long val;
- void *base = phy->regs;
+ void __iomem *base = phy->regs;
- val = readl(base + USB_SUSP_CTRL);
- val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
- writel(val, base + USB_SUSP_CTRL);
+ if (phy_mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+ }
val = readl(base + UTMIP_XCVR_CFG0);
val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
- UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
- UTMIP_XCVR_HSSLEW_MSB(~0));
- val |= UTMIP_XCVR_SETUP(0xF);
- /* TODO: slow rise/fall times in host mode */
+ UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0));
+ if (phy_mode == TEGRA_USB_PHY_MODE_HOST) {
+ val &= ~(UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0));
+ val |= UTMIP_XCVR_LSFSLEW(2) | UTMIP_XCVR_LSRSLEW(2);
+ val |= UTMIP_XCVR_SETUP(0x9);
+ } else {
+ val &= ~(UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(0xF);
+ }
writel(val, base + UTMIP_XCVR_CFG0);
- val = readl(base + UTMIP_SPARE_CFG0);
- val &= ~FUSE_SETUP_SEL;
- writel(val, base + UTMIP_SPARE_CFG0);
-
val = readl(base + UTMIP_BIAS_CFG0);
val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
writel(val, base + UTMIP_BIAS_CFG0);
@@ -234,6 +254,9 @@ void utmi_phy_power_on(struct tegra_usb_phy *phy)
writel(val, base + USB_SUSP_CTRL);
}
+ if (utmi_phy_wait_stable(phy))
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val &= ~USB_PORTSC1_PTS(~0);
@@ -244,7 +267,7 @@ void utmi_phy_power_on(struct tegra_usb_phy *phy)
void utmi_phy_power_off(struct tegra_usb_phy *phy)
{
unsigned long val;
- void *base = phy->regs;
+ void __iomem *base = phy->regs;
if (phy->instance == 0) {
val = readl(base + USB_SUSP_CTRL);
@@ -333,12 +356,13 @@ err0:
return ERR_PTR(err);
}
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
+int tegra_usb_phy_power_on(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_mode phy_mode)
{
/* TODO usb2 ulpi */
clk_enable(phy->pll_u);
if (phy->instance != 1)
- utmi_phy_power_on(phy);
+ utmi_phy_power_on(phy, phy_mode);
return 0;
}