In host mode port power must be turned on when wakeup
detected or session request interrupt is detected.
Because, otherwise core wouldn't exit form partial
power down.

- Turned on the port power by setting HPRT0_PWR bit.

- Called dwc2_hcd_connect() function after enabling
  the power of the port.

Signed-off-by: Artur Petrosyan <art...@synopsys.com>
---
 drivers/usb/dwc2/core_intr.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 19ae2595f1c3..06f8022b1bdb 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -312,6 +312,7 @@ static void dwc2_handle_conn_id_status_change_intr(struct 
dwc2_hsotg *hsotg)
 static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
 {
        int ret;
+       u32 hprt0;
 
        /* Clear interrupt */
        dwc2_writel(hsotg, GINTSTS_SESSREQINT, GINTSTS);
@@ -320,7 +321,9 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg 
*hsotg)
                hsotg->lx_state);
 
        if (dwc2_is_device_mode(hsotg)) {
-               if (hsotg->lx_state == DWC2_L2) {
+               if (hsotg->lx_state == DWC2_L2 &&
+                   hsotg->params.power_down ==
+                   DWC2_POWER_DOWN_PARAM_PARTIAL) {
                        ret = dwc2_exit_partial_power_down(hsotg, true);
                        if (ret && (ret != -ENOTSUPP))
                                dev_err(hsotg->dev,
@@ -332,6 +335,14 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg 
*hsotg)
                 * established
                 */
                dwc2_hsotg_disconnect(hsotg);
+       } else {
+               /* Turn on the port power bit. */
+               hprt0 = dwc2_read_hprt0(hsotg);
+               hprt0 |= HPRT0_PWR;
+               dwc2_writel(hsotg, hprt0, HPRT0);
+
+               /* Connect hcd after port power is set. */
+               dwc2_hcd_connect(hsotg);
        }
 }
 
@@ -396,6 +407,7 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg 
*hsotg)
 static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
 {
        int ret;
+       u32 hprt0;
 
        /* Clear interrupt */
        dwc2_writel(hsotg, GINTSTS_WKUPINT, GINTSTS);
@@ -426,8 +438,6 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
                /* Change to L0 state */
                hsotg->lx_state = DWC2_L0;
        } else {
-               if (hsotg->params.power_down)
-                       return;
 
                if (hsotg->lx_state != DWC2_L1) {
                        u32 pcgcctl = dwc2_readl(hsotg, PCGCTL);
@@ -435,6 +445,15 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
                        /* Restart the Phy Clock */
                        pcgcctl &= ~PCGCTL_STOPPCLK;
                        dwc2_writel(hsotg, pcgcctl, PCGCTL);
+
+                       /* Turn on the port power bit. */
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       hprt0 |= HPRT0_PWR;
+                       dwc2_writel(hsotg, hprt0, HPRT0);
+
+                       /* Connect hcd. */
+                       dwc2_hcd_connect(hsotg);
+
                        mod_timer(&hsotg->wkp_timer,
                                  jiffies + msecs_to_jiffies(71));
                } else {
-- 
2.11.0

Reply via email to