From: Gregory Herrero <[email protected]>

port resume sequence may be used in different places. Create a
function to handle it. Make hprt0 read-modify-write atomic and
clear HPRT0_SUSP for both writes as it is a "read, write-set,
and self-clear (R_WS_SC)" bit. Since the lock is released
between the writes, read hprt0 again.

Since the phy clock is stopped in dwc2_port_suspend(), enable it
here and remove the PCGCTL write from dwc2_hcd_hub_control()

Signed-off-by: Gregory Herrero <[email protected]>
Signed-off-by: Mian Yousaf Kaukab <[email protected]>
Tested-by: Robert Baldyga <[email protected]>
---
 drivers/usb/dwc2/hcd.c | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 1595d70..b929087 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -1484,6 +1484,35 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, 
u16 windex)
        }
 }
 
+/* Must NOT be called with interrupt disabled or spinlock held */
+static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
+{
+       unsigned long flags;
+       u32 hprt0;
+       u32 pcgctl;
+
+       /* Resume the Phy Clock */
+       pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
+       pcgctl &= ~PCGCTL_STOPPCLK;
+       dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
+       usleep_range(20000, 40000);
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       hprt0 = dwc2_read_hprt0(hsotg);
+       hprt0 |= HPRT0_RES;
+       hprt0 &= ~HPRT0_SUSP;
+       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       msleep(USB_RESUME_TIMEOUT);
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       hprt0 = dwc2_read_hprt0(hsotg);
+       hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
+       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
 /* Handles hub class-specific requests */
 static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                                u16 wvalue, u16 windex, char *buf, u16 wlength)
@@ -1529,17 +1558,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
                case USB_PORT_FEAT_SUSPEND:
                        dev_dbg(hsotg->dev,
                                "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
-                       dwc2_writel(0, hsotg->regs + PCGCTL);
-                       usleep_range(20000, 40000);
 
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       hprt0 |= HPRT0_RES;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
-                       hprt0 &= ~HPRT0_SUSP;
-                       msleep(USB_RESUME_TIMEOUT);
-
-                       hprt0 &= ~HPRT0_RES;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_port_resume(hsotg);
                        break;
 
                case USB_PORT_FEAT_POWER:
-- 
2.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to