USB: EHCI: Fix suspend and resume handling

HSIC PHY stuck issue is observed if HSIC HW goes to low power
mode in the middle of resume sequence initiated by remote wakeup.
In case of USB bus resume due to remote wakeup set Run/Stop bit
right after receiving remote wakeup interrupt and do not allow
runtime suspend in the middle of remote wakeup.
Also, add correct way to update PORTSC register in driver suspend
and resume routines.

CRs-Fixed: 360555
Change-Id: I0033541042db028d85ef49907dfd37ad5a75c8aa
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index a83f6d3..5ee1908 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -40,8 +40,6 @@
 #include <mach/msm_xo.h>
 #include <linux/spinlock.h>
 
-#define RUNTIME_SUSP_DELAY 500
-
 #define MSM_USB_BASE (hcd->regs)
 
 struct msm_hsic_hcd {
@@ -59,7 +57,6 @@
 	int			peripheral_status_irq;
 	int			wakeup_irq;
 	bool			wakeup_irq_enabled;
-	bool			pm_resume;
 	uint32_t		bus_perf_client;
 };
 
@@ -348,7 +345,9 @@
 	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
 	 * in failure case.
 	 */
-	val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
+	val = readl_relaxed(USB_PORTSC);
+	val &= ~PORT_RWC_BITS;
+	val |= PORTSC_PHCD;
 	writel_relaxed(val, USB_PORTSC);
 	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
 		if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
@@ -447,7 +446,8 @@
 	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
 		goto skip_phy_resume;
 
-	temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+	temp = readl_relaxed(USB_PORTSC);
+	temp &= ~(PORT_RWC_BITS | PORTSC_PHCD);
 	writel_relaxed(temp, USB_PORTSC);
 	while (cnt < PHY_RESUME_TIMEOUT_USEC) {
 		if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
@@ -489,6 +489,7 @@
 
 	if (atomic_read(&mehci->in_lpm)) {
 		disable_irq_nosync(hcd->irq);
+		dev_dbg(mehci->dev, "phy async intr\n");
 		mehci->async_int = true;
 		pm_runtime_get(mehci->dev);
 		return IRQ_HANDLED;
@@ -955,7 +956,6 @@
 
 	ehci_hsic_msm_debugfs_cleanup();
 	device_init_wakeup(&pdev->dev, 0);
-	mehci->pm_resume = false;
 	pm_runtime_set_suspended(&pdev->dev);
 
 	usb_remove_hcd(hcd);
@@ -981,8 +981,6 @@
 	if (device_may_wakeup(dev))
 		enable_irq_wake(hcd->irq);
 
-	mehci->pm_resume = false;
-
 	return msm_hsic_suspend(mehci);
 }
 
@@ -1019,8 +1017,6 @@
 		disable_irq_nosync(mehci->wakeup_irq);
 	}
 
-	mehci->pm_resume = true;
-
 	ret = msm_hsic_resume(mehci);
 	if (ret)
 		return ret;
@@ -1038,15 +1034,12 @@
 static int msm_hsic_runtime_idle(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
 	dev_dbg(dev, "EHCI runtime idle\n");
 
-	if (mehci->pm_resume) {
-		mehci->pm_resume = false;
-		pm_schedule_suspend(dev, RUNTIME_SUSP_DELAY);
+	/*don't allow runtime suspend in the middle of remote wakeup*/
+	if (readl_relaxed(USB_PORTSC) & PORT_RESUME)
 		return -EAGAIN;
-	}
 
 	return 0;
 }