diff options
author | Sevak Arakelyan <sevaka@synopsys.com> | 2018-01-24 17:42:14 +0400 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2018-03-13 10:47:48 +0200 |
commit | 273d576c4d41d0577551176040c9c78d30c0cf16 (patch) | |
tree | b9d928f745d69bdb72cc7dc43a3638bb6fd837c8 /drivers/usb | |
parent | 6f80b6de0ecf65077b53c86967c714d42f4299e0 (diff) | |
download | blackbird-op-linux-273d576c4d41d0577551176040c9c78d30c0cf16.tar.gz blackbird-op-linux-273d576c4d41d0577551176040c9c78d30c0cf16.zip |
usb: dwc2: gadget: Add functionality to exit from LPM L1 state
Add a function which will be called if device is in L1 sleep state
and Resume/Remote Wakeup Detected interrupt is asserted.
Signed-off-by: Sevak Arakelyan <sevaka@synopsys.com>
Signed-off-by: Grigor Tovmasyan <tovmasya@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/dwc2/core_intr.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index ab3fa1630853..6baa0c937bff 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -335,6 +335,53 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) } } +/** + * dwc2_wakeup_from_lpm_l1 - Exit the device from LPM L1 state + * + * @hsotg: Programming view of DWC_otg controller + * + */ +static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg) +{ + u32 glpmcfg; + u32 i = 0; + + if (hsotg->lx_state != DWC2_L1) { + dev_err(hsotg->dev, "Core isn't in DWC2_L1 state\n"); + return; + } + + glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); + if (dwc2_is_device_mode(hsotg)) { + dev_dbg(hsotg->dev, "Exit from L1 state\n"); + glpmcfg &= ~GLPMCFG_ENBLSLPM; + glpmcfg &= ~GLPMCFG_HIRD_THRES_EN; + dwc2_writel(glpmcfg, hsotg->regs + GLPMCFG); + + do { + glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); + + if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK | + GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS))) + break; + + udelay(1); + } while (++i < 200); + + if (i == 200) { + dev_err(hsotg->dev, "Failed to exit L1 sleep state in 200us.\n"); + return; + } + } else { + /* TODO */ + dev_err(hsotg->dev, "Host side LPM is not supported.\n"); + return; + } + + /* Change to L0 state */ + hsotg->lx_state = DWC2_L0; +} + /* * This interrupt indicates that the DWC_otg controller has detected a * resume or remote wakeup sequence. If the DWC_otg controller is in @@ -352,6 +399,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n"); dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state); + if (hsotg->lx_state == DWC2_L1) { + dwc2_wakeup_from_lpm_l1(hsotg); + return; + } + if (dwc2_is_device_mode(hsotg)) { dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dwc2_readl(hsotg->regs + DSTS)); |