summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorVenkat Moganty <vmoganty@nvidia.com>2012-01-19 11:34:22 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-01-24 10:59:32 -0800
commit005f572bd229c4072cc618b74847edeba65faf33 (patch)
treefe352aa8bffa315d51d388bd3299a911c06d5644 /drivers/usb/host
parent65ab9647d93da8dce3ea14922a6095bbcf64efcd (diff)
tegra: usb: host: Fix remote wakeup issues on UTMI
Add WAR to fix 2LS voilation during usb remote resume. Bug 880538 Reviewed-on: http://git-master/r/75845 Change-Id: I552c9e657776f67c263ef750a7786c796dc785cb Signed-off-by: Venkat Moganty <vmoganty@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/76822 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/ehci-tegra.c62
-rw-r--r--drivers/usb/host/ehci.h1
3 files changed, 58 insertions, 8 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ab94b512e0ea..1a534c70ea6e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -906,6 +906,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
+#ifdef CONFIG_USB_EHCI_TEGRA
+ ehci->controller_remote_wakeup = true;
+#endif
}
}
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 917796c20d8a..1dbfc4aa1981 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -167,11 +167,14 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd)
struct ehci_regs __iomem *hw = ehci->regs;
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
u32 val;
+ irqreturn_t irq_status;
+ bool pmc_remote_wakeup = false;
if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
(tegra->ehci->has_hostpc)) {
/* check if there is any remote wake event */
if (tegra_usb_phy_is_remotewake_detected(tegra->phy)) {
+ pmc_remote_wakeup = true;
spin_lock (&ehci->lock);
usb_hcd_resume_root_hub(hcd);
spin_unlock (&ehci->lock);
@@ -196,7 +199,21 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd)
}
spin_unlock(&ehci->lock);
}
- return ehci_irq(hcd);
+
+ irq_status = ehci_irq(hcd);
+
+ if (pmc_remote_wakeup) {
+ ehci->controller_remote_wakeup = false;
+ }
+
+ if (ehci->controller_remote_wakeup) {
+ ehci->controller_remote_wakeup = false;
+ /* disable interrupts */
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ tegra_usb_phy_preresume(tegra->phy, true);
+ tegra->port_resuming = 1;
+ }
+ return irq_status;
}
static int tegra_ehci_hub_control(
@@ -219,6 +236,7 @@ static int tegra_ehci_hub_control(
unsigned selector;
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
bool hsic = false;
+ bool do_post_resume = false;
if (!tegra->host_resumed) {
if (buf)
@@ -244,13 +262,18 @@ static int tegra_ehci_hub_control(
} else if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
if (tegra->port_resuming && !(temp & PORT_SUSPEND) &&
- time_after_eq(jiffies, ehci->reset_done[wIndex-1])) {
- /* Resume completed, re-enable disconnect detection */
- tegra->port_resuming = 0;
+ time_after_eq(jiffies, ehci->reset_done[wIndex-1])) {
clear_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
ehci->reset_done[wIndex-1] = 0;
+ do_post_resume = true;
+ } else if (tegra->port_resuming && (temp & PORT_RESUME) &&
+ time_after_eq(jiffies, ehci->reset_done[wIndex-1]) ) {
+ do_post_resume = true;
+ }
+
+ if (do_post_resume) {
+ tegra->port_resuming = 0;
tegra_usb_phy_postresume(tegra->phy, false);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
ehci->command |= CMD_RUN;
/*
@@ -259,9 +282,11 @@ static int tegra_ehci_hub_control(
*/
ehci_writel(ehci, ehci->command,
&ehci->regs->command);
+ /* Now we can safely re-enable irqs */
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
}
-#endif
}
+
} else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
@@ -286,6 +311,13 @@ static int tegra_ehci_hub_control(
set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
+ if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
+ /* Disable RUN bit. */
+ ehci->command &= ~CMD_RUN;
+ ehci_writel(ehci, ehci->command,
+ &ehci->regs->command);
+ }
+
tegra_usb_phy_postsuspend(tegra->phy, false);
goto done;
@@ -318,6 +350,15 @@ static int tegra_ehci_hub_control(
tegra->port_resuming = 1;
+ if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) {
+ /* disable interrupts */
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ /* Disable RUN bit. */
+ ehci->command &= ~CMD_RUN;
+ ehci_writel(ehci, ehci->command,
+ &ehci->regs->command);
+ }
+
/* Disable disconnect detection during port resume */
tegra_usb_phy_preresume(tegra->phy, false);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
@@ -509,6 +550,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
unsigned long val;
bool hsic;
bool null_ulpi;
+ bool utmip_remote_wakeup = false;
null_ulpi = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI);
hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC);
@@ -547,8 +589,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) &&
(tegra->ehci->has_hostpc) && (tegra->phy->remote_wakeup)) {
- ehci->command |= CMD_RUN;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ utmip_remote_wakeup = true;
}
/* Check if the phy resume from LP0. When the phy resume from LP0
@@ -611,6 +652,10 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd)
}
tegra_ehci_phy_restore_end(tegra->phy);
+ if (utmip_remote_wakeup) {
+ ehci->command |= CMD_RUN;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ }
return 0;
restart:
@@ -709,6 +754,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
return retval;
ehci->sbrn = 0x20;
+ ehci->controller_remote_wakeup = false;
if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI) {
tegra_ehci_pre_reset(tegra->phy, false);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 7f0e828631ed..e897262c6a60 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -142,6 +142,7 @@ struct ehci_hcd { /* one per controller */
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
#ifdef CONFIG_USB_EHCI_TEGRA
unsigned controller_resets_phy:1;
+ unsigned controller_remote_wakeup:1;
#endif
/* required for usb32 quirk */