From 30db103c3ddeb0b616eedb8fd030b88efb1af96f Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Tue, 22 Sep 2015 15:16:38 +0200 Subject: [PATCH] usb: dwc2: host: create a function to handle port_resume 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 Signed-off-by: Mian Yousaf Kaukab Tested-by: Robert Baldyga Tested-by: Dinh Nguyen Tested-by: John Youn Acked-by: John Youn Signed-off-by: Felipe Balbi --- 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 1595d7061f2c..b929087f26f2 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: