EHCI: HSIC: Halt controller before driving suspend on to the bus
There can be SOFs underway after suspending the port
(setting susp bit) which leads to phy lockup or unexpected
device disconnections. Halt the controller before setting
port suspend bit to avoid such issues.
CRs-Fixed: 363920, 356212
Change-Id: I9ab3fe0556e845621d9314b66d2af955251284fb
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index af638f4..4e7c35f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -261,6 +261,11 @@
if (t1 & PORT_OWNER)
set_bit(port, &ehci->owned_ports);
else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
+ /*clear RS bit before setting SUSP bit
+ * and wait for HCH to get set*/
+ if (ehci->susp_sof_bug)
+ ehci_halt(ehci);
+
t2 |= PORT_SUSPEND;
set_bit(port, &ehci->bus_suspended);
}
@@ -311,8 +316,10 @@
if (ehci->bus_suspended)
udelay(150);
- /* turn off now-idle HC */
- ehci_halt (ehci);
+ /*if this bit is set, controller is already haled*/
+ if (!ehci->susp_sof_bug)
+ ehci_halt(ehci); /* turn off now-idle HC */
+
hcd->state = HC_STATE_SUSPENDED;
if (ehci->reclaim)
@@ -1199,8 +1206,10 @@
if ((temp & PORT_PE) == 0
|| (temp & PORT_RESET) != 0)
goto error;
-
- ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+ /*port gets suspended as part of bus suspend routine*/
+ if (!ehci->susp_sof_bug)
+ ehci_writel(ehci, temp | PORT_SUSPEND,
+ status_reg);
#ifdef CONFIG_USB_OTG
if (hcd->self.otg_port == (wIndex + 1) &&
hcd->self.b_hnp_enable) {
@@ -1215,7 +1224,11 @@
*/
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
- ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+ if (ehci->susp_sof_bug)
+ ehci_writel(ehci, temp, status_reg);
+ else
+ 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 */