|
@@ -334,6 +334,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
|
|
|
*/
|
|
|
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|
|
{
|
|
|
+ int ret;
|
|
|
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
|
|
|
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
|
|
|
|
|
@@ -345,6 +346,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|
|
/* Clear Remote Wakeup Signaling */
|
|
|
dctl &= ~DCTL_RMTWKUPSIG;
|
|
|
writel(dctl, hsotg->regs + DCTL);
|
|
|
+ ret = dwc2_exit_hibernation(hsotg, true);
|
|
|
+ if (ret)
|
|
|
+ dev_err(hsotg->dev, "exit hibernation failed\n");
|
|
|
+
|
|
|
+ call_gadget(hsotg, resume);
|
|
|
}
|
|
|
/* Change to L0 state */
|
|
|
hsotg->lx_state = DWC2_L0;
|
|
@@ -397,6 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
|
|
|
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|
|
{
|
|
|
u32 dsts;
|
|
|
+ int ret;
|
|
|
|
|
|
dev_dbg(hsotg->dev, "USB SUSPEND\n");
|
|
|
|
|
@@ -411,6 +418,30 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|
|
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
|
|
|
!!(dsts & DSTS_SUSPSTS),
|
|
|
hsotg->hw_params.power_optimized);
|
|
|
+ if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
|
|
|
+ /* Ignore suspend request before enumeration */
|
|
|
+ if (!dwc2_is_device_connected(hsotg)) {
|
|
|
+ dev_dbg(hsotg->dev,
|
|
|
+ "ignore suspend request before enumeration\n");
|
|
|
+ goto clear_int;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = dwc2_enter_hibernation(hsotg);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(hsotg->dev,
|
|
|
+ "enter hibernation failed\n");
|
|
|
+ goto skip_power_saving;
|
|
|
+ }
|
|
|
+
|
|
|
+ udelay(100);
|
|
|
+
|
|
|
+ /* Ask phy to be suspended */
|
|
|
+ if (!IS_ERR_OR_NULL(hsotg->uphy))
|
|
|
+ usb_phy_set_suspend(hsotg->uphy, true);
|
|
|
+skip_power_saving:
|
|
|
+ /* Call gadget suspend callback */
|
|
|
+ call_gadget(hsotg, suspend);
|
|
|
+ }
|
|
|
} else {
|
|
|
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
|
|
|
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
|
|
@@ -426,6 +457,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|
|
/* Change to L2 (suspend) state */
|
|
|
hsotg->lx_state = DWC2_L2;
|
|
|
|
|
|
+clear_int:
|
|
|
/* Clear interrupt */
|
|
|
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
|
|
|
}
|