diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index bd6672b8c2ff..96799a399393 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1209,6 +1209,7 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); +void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); #else static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -1236,6 +1237,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) { return 0; } +static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 23599e798e24..a8e43948f807 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -372,6 +372,7 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg) dev_err(hsotg->dev, "Failed to exit L1 sleep state in 200us.\n"); return; } + dwc2_gadget_init_lpm(hsotg); } else { /* TODO */ dev_err(hsotg->dev, "Host side LPM is not supported.\n"); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index ddfe6a94a12a..706fecf16b52 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3372,6 +3372,9 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, val |= DCTL_SFTDISCON; dwc2_set_bit(hsotg->regs + DCTL, val); + /* configure the core to support LPM */ + dwc2_gadget_init_lpm(hsotg); + /* must be at-least 3ms to allow bus to see disconnect */ mdelay(3); @@ -4862,3 +4865,26 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) return 0; } + +/** + * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode + * + * @hsotg: Programming view of DWC_otg controller + * + */ +void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) +{ + u32 val; + + if (!hsotg->params.lpm) + return; + + val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES; + val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0; + val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; + val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; + val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; + dwc2_writel(val, hsotg->regs + GLPMCFG); + dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg->regs + + GLPMCFG)); +}