diff options
Diffstat (limited to 'drivers/usb/dwc2/core_intr.c')
-rw-r--r-- | drivers/usb/dwc2/core_intr.c | 45 |
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 | */ |
335 | static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) | 335 | static 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) | |||
397 | static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) | 403 | static 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); | ||
442 | skip_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 */ | 466 | clear_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 | } |
525 | EXPORT_SYMBOL_GPL(dwc2_handle_common_intr); | ||