ARM: tegra: Verify PHY clock valid before clearing USB_SUSP_CLR bit
authorNathan Connell <w14185@motorola.com>
Mon, 25 Apr 2011 19:17:13 +0000 (14:17 -0500)
committerBenoit Goby <benoit@android.com>
Mon, 25 Apr 2011 22:09:35 +0000 (15:09 -0700)
When enabling the external ULPI PHY, the clock from the PHY must be
valid before the USB_SUSP_CLR bit is cleared in the USB2 controller
interface register.  If the clock from the PHY is not valid when
this bit is cleared, the AHB clock to the host controller may be
stopped, preventing any access to the host controller.

Replace hard-coded delay with poll for USB_PHY_CLK_VALID bit.
Signed-off-by: Nathan Connell <w14185@motorola.com>
Change-Id: I24fa7575641f20ffdba7737776a81ba453f54395
Signed-off-by: Nathan Connell <w14185@motorola.com>
arch/arm/mach-tegra/usb_phy.c

index 70746eee4e5b47b773cc9fef0bd9a450ca12b93c..ef07efd11b19eeae8606d4d2bae139bc1968ed02 100644 (file)
@@ -54,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)
@@ -292,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;
@@ -353,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__);
 }
 
@@ -606,7 +607,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        unsigned long val;
        void __iomem *base = phy->regs;
        struct tegra_ulpi_config *config = phy->config;
-       unsigned long timeout = 2000;
 
        clk_enable(phy->clk);
        msleep(1);
@@ -633,15 +633,18 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        val = readl(base + USB_SUSP_CTRL);
        val |= USB_SUSP_CLR;
        writel(val, base + USB_SUSP_CTRL);
-       udelay(100);
+
+       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);
 
-       if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, USB_PHY_CLK_VALID))
-               pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-
        val = 0;
        writel(val, base + ULPI_TIMING_CTRL_1);
 
@@ -656,24 +659,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        val |= ULPI_DIR_TRIMMER_LOAD;
        writel(val, base + ULPI_TIMING_CTRL_1);
 
-       val = 0;
-       val |= ULPI_WAKEUP;
-       val |= ULPI_RD_WR;
-       writel(val, base + ULPI_VIEWPORT);
-
-
-       do {
-               if ((readl(base + ULPI_VIEWPORT) & ULPI_WAKEUP))
-                       udelay(1);
-               else
-                       break;
-               timeout--;
-       } while (timeout);
-       if (!timeout)
-               pr_err("%s: timeout on ULPI Wakeup\n", __func__);
-
        /* Fix VbusInvalid due to floating VBUS */
-       ret = otg_io_write(phy->ulpi, 0xC0, 0x08);
+       ret = otg_io_write(phy->ulpi, 0x40, 0x08);
        if (ret) {
                pr_err("%s: ulpi write failed\n", __func__);
                return ret;