]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
usb: dwc2: host: create a function to handle port_resume
authorGregory Herrero <gregory.herrero@intel.com>
Tue, 22 Sep 2015 13:16:38 +0000 (15:16 +0200)
committerFelipe Balbi <balbi@ti.com>
Thu, 1 Oct 2015 17:40:14 +0000 (12:40 -0500)
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 <gregory.herrero@intel.com>
Signed-off-by: Mian Yousaf Kaukab <yousaf.kaukab@intel.com>
Tested-by: Robert Baldyga <r.baldyga@samsung.com>
Tested-by: Dinh Nguyen <dinguyen@opensource.altera.com>
Tested-by: John Youn <johnyoun@synopsys.com>
Acked-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/hcd.c

index 1595d7061f2ca3b8ab12670e56a0b8d153397dd3..b929087f26f29807b4fe6db1e92896560b330739 100644 (file)
@@ -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: