usb: ehci: tegra: continues driving FS-J during resume
authorJay Cheng <jacheng@nvidia.com>
Fri, 7 Jan 2011 07:03:46 +0000 (02:03 -0500)
committerBenoit Goby <benoit@android.com>
Mon, 10 Jan 2011 01:41:59 +0000 (17:41 -0800)
To prevent USB glitch.
Also only program PTC bits when resume from LP0

Change-Id: Iced668e33f986828d3a483b411055948b5b257e1
Signed-off-by: Jay Cheng <jacheng@nvidia.com>
drivers/usb/host/ehci-tegra.c

index 0e9b6458da846e60f0ef36a7b6edbc23978ef066..2341904808bce0d2d5a5f6ce046a78e10a33ac9f 100644 (file)
@@ -253,6 +253,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd)
        struct tegra_ehci_context *context = &tegra->context;
        struct ehci_regs __iomem *hw = tegra->ehci->regs;
        unsigned long val;
+       int lp0_resume = 0;
 
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        tegra_ehci_power_up(ehci_to_hcd(tegra->ehci));
@@ -264,6 +265,13 @@ static int tegra_usb_resume(struct usb_hcd *hcd)
                goto restart;
        }
 
+       tegra_ehci_phy_restore_start(tegra->phy);
+
+       /* Check if the phy resume from LP0. When the phy resume from LP0
+        * USB register will be reset. */
+       if (!readl(&hw->async_next))
+               lp0_resume = 1;
+
        /* Restore register context */
        writel(TEGRA_USB_USBMODE_HOST, &hw->reserved[19]);
        writel(context->otgsc,         &hw->reserved[18]);
@@ -278,17 +286,19 @@ static int tegra_usb_resume(struct usb_hcd *hcd)
        writel(val, &hw->port_status[0]);
        udelay(10);
 
-       /* Program the field PTC in PORTSC based on the saved speed mode */
-       val = readl(&hw->port_status[0]);
-       val &= ~(TEGRA_USB_PORTSC1_PTC(~0));
-       if (context->port_speed == TEGRA_USB_PHY_PORT_HIGH)
-               val |= TEGRA_USB_PORTSC1_PTC(5);
-       else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL)
-               val |= TEGRA_USB_PORTSC1_PTC(6);
-       else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
-               val |= TEGRA_USB_PORTSC1_PTC(7);
-       writel(val, &hw->port_status[0]);
-       udelay(10);
+       if (lp0_resume) {
+               /* Program the field PTC in PORTSC based on the saved speed mode */
+               val = readl(&hw->port_status[0]);
+               val &= ~(TEGRA_USB_PORTSC1_PTC(~0));
+               if (context->port_speed == TEGRA_USB_PHY_PORT_HIGH)
+                       val |= TEGRA_USB_PORTSC1_PTC(5);
+               else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL)
+                       val |= TEGRA_USB_PORTSC1_PTC(6);
+               else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
+                       val |= TEGRA_USB_PORTSC1_PTC(7);
+               writel(val, &hw->port_status[0]);
+               udelay(10);
+       }
 
        /* Disable test mode by setting PTC field to NORMAL_OP */
        val = readl(&hw->port_status[0]);
@@ -330,9 +340,11 @@ static int tegra_usb_resume(struct usb_hcd *hcd)
                }
        }
 
+       tegra_ehci_phy_restore_end(tegra->phy);
        return 0;
 
 restart:
+       tegra_ehci_phy_restore_end(tegra->phy);
        tegra_ehci_restart(hcd);
        return 0;
 }