aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c57
1 files changed, 54 insertions, 3 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index fb0394b..037fd42 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -31,6 +31,14 @@
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+#if defined(CONFIG_EMI_ERROR_RECOVERY)
+#define MDM_HSIC_PORT_NUM 2
+#define PORT_ENABLE_DISABLE (1 << 2)
+#define PORT_ENABLE_DISABLE_CHANGE (1 << 3)
+/* count reported port status change */
+static int portstatus_chg_cnt;
+#endif
+
#ifdef CONFIG_PM
static int ehci_hub_control(
@@ -261,6 +269,12 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (t1 & PORT_OWNER)
set_bit(port, &ehci->owned_ports);
else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
+#ifdef CONFIG_MDM_HSIC_PM
+ /*clear RS bit before setting SUSP bit
+ * and wait for HCH to get set*/
+ if (ehci->susp_sof_bug)
+ ehci_halt(ehci);
+#endif
t2 |= PORT_SUSPEND;
set_bit(port, &ehci->bus_suspended);
}
@@ -311,8 +325,12 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (ehci->bus_suspended)
udelay(150);
- /* turn off now-idle HC */
- ehci_halt (ehci);
+#ifdef CONFIG_MDM_HSIC_PM
+ /*if this bit is set, controller is already haled*/
+ if (!ehci->susp_sof_bug)
+#endif
+ /* turn off now-idle HC */
+ ehci_halt(ehci);
hcd->state = HC_STATE_SUSPENDED;
if (ehci->reclaim)
@@ -1349,6 +1367,27 @@ static int ehci_hub_control (
if (status & ~0xffff) /* only if wPortChange is interesting */
#endif
dbg_port (ehci, "GetStatus", wIndex + 1, temp);
+
+#if defined(CONFIG_EMI_ERROR_RECOVERY)
+ if (temp & PORT_ENABLE_DISABLE_CHANGE) {
+ temp = ehci_readl(ehci, status_reg);
+ ehci_dbg(ehci, "recovery port status %d +\n", temp);
+
+ /* ignore 'Current Status Change', by writing 1 */
+ temp &= ~PORT_ENABLE_DISABLE;
+
+ /* clear 'Port Enable/Disable Change', by writng 1 */
+ temp |= PORT_ENABLE_DISABLE_CHANGE;
+
+ ehci_writel(ehci, temp, status_reg);
+ ehci_readl(ehci, status_reg);
+
+ ehci_dbg(ehci, "recovery port status %d -\n",
+ ehci_readl(ehci, status_reg));
+
+ portstatus_chg_cnt++;
+ }
+#endif
put_unaligned_le32(status, buf);
break;
case SetHubFeature:
@@ -1388,6 +1427,12 @@ static int ehci_hub_control (
if ((temp & PORT_PE) == 0
|| (temp & PORT_RESET) != 0)
goto error;
+#ifdef CONFIG_MDM_HSIC_PM
+ /*port gets suspended as part of bus suspend routine*/
+ if (!ehci->susp_sof_bug)
+ ehci_writel(ehci, temp | PORT_SUSPEND,
+ status_reg);
+#endif
/* After above check the port must be connected.
* Set appropriate bit thus could put phy into low power
@@ -1395,7 +1440,13 @@ static int ehci_hub_control (
*/
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
- ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+#ifdef CONFIG_MDM_HSIC_PM
+ if (ehci->susp_sof_bug)
+ ehci_writel(ehci, temp, status_reg);
+ else
+#endif
+ ehci_writel(ehci, temp | PORT_SUSPEND,
+ status_reg);
if (hostpc_reg) {
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(5);/* 5ms for HCD enter low pwr mode */