diff mbox series

[3/3] usb: dwc2: Fix hibernation between host and device modes.

Message ID a6de644d1541e22b1b88d11cbf5d6435649d14bb.1537451080.git.arturp@synopsys.com (mailing list archive)
State New, archived
Headers show
Series usb: dwc2: Fix hibernation for switching between host and device modes. | expand

Commit Message

Artur Petrosyan Sept. 20, 2018, 1:49 p.m. UTC
- After entering hibernation both in host and
  device modes saved GPWRDN register.

- In handling status change interrupt checking if
  current mode differs from the mode when entered
  hibernation.
  In case when mode is not changed, exiting device
  hibernation without remote wake up.
  On the other hand, if there is device hibernation
  and changed to host, then exiting hibernation
  for device mode with remote wake up.

- Removed workaround for ignore suspend interrupt before
  enumeration.

Signed-off-by: Artur Petrosyan <arturp@synopsys.com>
Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
---
 drivers/usb/dwc2/core_intr.c | 19 +++++++++----------
 drivers/usb/dwc2/hcd.c       |  3 +++
 2 files changed, 12 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 3602aca3316b..47e7dc4100af 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -491,12 +491,6 @@  static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
 			hsotg->hw_params.power_optimized,
 			hsotg->hw_params.hibernation);
 
-		/* Ignore suspend request before enumeration */
-		if (!dwc2_is_device_connected(hsotg)) {
-			dev_dbg(hsotg->dev,
-				"ignore suspend request before enumeration\n");
-			return;
-		}
 		if (dsts & DSTS_SUSPSTS) {
 			switch (hsotg->params.power_down) {
 			case DWC2_POWER_DOWN_PARAM_PARTIAL:
@@ -733,21 +727,26 @@  static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
 			}
 		}
 	}
+
 	if ((gpwrdn & GPWRDN_RST_DET) && (gpwrdn & GPWRDN_RST_DET_MSK)) {
 		dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__);
 		if (!linestate && (gpwrdn & GPWRDN_BSESSVLD))
 			dwc2_exit_hibernation(hsotg, 0, 1, 0);
 	}
+
 	if ((gpwrdn & GPWRDN_STS_CHGINT) &&
-	    (gpwrdn & GPWRDN_STS_CHGINT_MSK) && linestate) {
+	    (gpwrdn & GPWRDN_STS_CHGINT_MSK)) {
 		dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__);
 		if (hsotg->hw_params.hibernation &&
 		    hsotg->hibernated) {
-			if (gpwrdn & GPWRDN_IDSTS) {
+			if ((gpwrdn & GPWRDN_IDSTS) &
+			    (hsotg->gr_backup.gpwrdn & GPWRDN_IDSTS) &&
+			     linestate) {
 				dwc2_exit_hibernation(hsotg, 0, 0, 0);
 				call_gadget(hsotg, resume);
-			} else {
-				dwc2_exit_hibernation(hsotg, 1, 0, 1);
+			} else if (!(gpwrdn & GPWRDN_IDSTS) && !linestate) {
+				dwc2_exit_hibernation(hsotg, 1, 0, 0);
+				call_gadget(hsotg, resume);
 			}
 		}
 	}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 2bd6e6bfc241..0e29b4c4e87b 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5582,6 +5582,9 @@  int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
 	gpwrdn |= GPWRDN_PWRDNSWTCH;
 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
 
+	/* Save gpwrdn register for further usage if stschng interrupt */
+	hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg, GPWRDN);
+
 	hsotg->hibernated = 1;
 	hsotg->bus_suspended = 1;
 	dev_dbg(hsotg->dev, "Host hibernation completed\n");