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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



- 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@xxxxxxxxxxxx>
Signed-off-by: Minas Harutyunyan <hminas@xxxxxxxxxxxx>
---
 drivers/usb/dwc2/core_intr.c | 19 +++++++++----------
 drivers/usb/dwc2/hcd.c       |  3 +++
 2 files changed, 12 insertions(+), 10 deletions(-)

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");
-- 
2.11.0




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux