aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc2/core_intr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc2/core_intr.c')
-rw-r--r--drivers/usb/dwc2/core_intr.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 6cf047878dba..927be1e8b3dc 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -334,6 +334,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
334 */ 334 */
335static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) 335static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
336{ 336{
337 int ret;
337 dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n"); 338 dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
338 dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state); 339 dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
339 340
@@ -345,6 +346,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
345 /* Clear Remote Wakeup Signaling */ 346 /* Clear Remote Wakeup Signaling */
346 dctl &= ~DCTL_RMTWKUPSIG; 347 dctl &= ~DCTL_RMTWKUPSIG;
347 writel(dctl, hsotg->regs + DCTL); 348 writel(dctl, hsotg->regs + DCTL);
349 ret = dwc2_exit_hibernation(hsotg, true);
350 if (ret && (ret != -ENOTSUPP))
351 dev_err(hsotg->dev, "exit hibernation failed\n");
352
353 call_gadget(hsotg, resume);
348 } 354 }
349 /* Change to L0 state */ 355 /* Change to L0 state */
350 hsotg->lx_state = DWC2_L0; 356 hsotg->lx_state = DWC2_L0;
@@ -397,6 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
397static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) 403static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
398{ 404{
399 u32 dsts; 405 u32 dsts;
406 int ret;
400 407
401 dev_dbg(hsotg->dev, "USB SUSPEND\n"); 408 dev_dbg(hsotg->dev, "USB SUSPEND\n");
402 409
@@ -411,10 +418,43 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
411 "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n", 418 "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
412 !!(dsts & DSTS_SUSPSTS), 419 !!(dsts & DSTS_SUSPSTS),
413 hsotg->hw_params.power_optimized); 420 hsotg->hw_params.power_optimized);
421 if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
422 /* Ignore suspend request before enumeration */
423 if (!dwc2_is_device_connected(hsotg)) {
424 dev_dbg(hsotg->dev,
425 "ignore suspend request before enumeration\n");
426 goto clear_int;
427 }
428
429 ret = dwc2_enter_hibernation(hsotg);
430 if (ret) {
431 if (ret != -ENOTSUPP)
432 dev_err(hsotg->dev,
433 "enter hibernation failed\n");
434 goto skip_power_saving;
435 }
436
437 udelay(100);
438
439 /* Ask phy to be suspended */
440 if (!IS_ERR_OR_NULL(hsotg->uphy))
441 usb_phy_set_suspend(hsotg->uphy, true);
442skip_power_saving:
443 /*
444 * Change to L2 (suspend) state before releasing
445 * spinlock
446 */
447 hsotg->lx_state = DWC2_L2;
448
449 /* Call gadget suspend callback */
450 call_gadget(hsotg, suspend);
451 }
414 } else { 452 } else {
415 if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) { 453 if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
416 dev_dbg(hsotg->dev, "a_peripheral->a_host\n"); 454 dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
417 455
456 /* Change to L2 (suspend) state */
457 hsotg->lx_state = DWC2_L2;
418 /* Clear the a_peripheral flag, back to a_host */ 458 /* Clear the a_peripheral flag, back to a_host */
419 spin_unlock(&hsotg->lock); 459 spin_unlock(&hsotg->lock);
420 dwc2_hcd_start(hsotg); 460 dwc2_hcd_start(hsotg);
@@ -423,9 +463,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
423 } 463 }
424 } 464 }
425 465
426 /* Change to L2 (suspend) state */ 466clear_int:
427 hsotg->lx_state = DWC2_L2;
428
429 /* Clear interrupt */ 467 /* Clear interrupt */
430 writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); 468 writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
431} 469}
@@ -522,4 +560,3 @@ out:
522 spin_unlock(&hsotg->lock); 560 spin_unlock(&hsotg->lock);
523 return retval; 561 return retval;
524} 562}
525EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);