diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 1595d7061f2ca3b8ab12670e56a0b8d153397dd3..b929087f26f29807b4fe6db1e92896560b330739 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: