summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2/core_intr.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-26 15:59:26 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-26 15:59:26 -0700
commit2a298679b41199ae742a77ce69766385dffe816f (patch)
tree93a23c0d828ccca7053f604dbfcdd4d3278972b3 /drivers/usb/dwc2/core_intr.c
parent8c7febe83915332276cab49e89f6580bb963fb9a (diff)
parent50641056d833813b71b0ad51823f7ded8dd62e7f (diff)
Merge tag 'usb-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB updates from Greg KH: "Here's the big USB patchset for 4.2-rc1. As is normal these days, the majority of changes are in the gadget drivers, with a bunch of other small driver changes. All of these have been in linux-next with no reported issues" * tag 'usb-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (175 commits) usb: dwc3: Use ASCII space in Kconfig usb: chipidea: add work-around for Marvell HSIC PHY startup usb: chipidea: allow multiple instances to use default ci_default_pdata dt-bindings: Consolidate ChipIdea USB ci13xxx bindings phy: add Marvell HSIC 28nm PHY phy: Add Marvell USB 2.0 OTG 28nm PHY dt-bindings: Add Marvell PXA1928 USB and HSIC PHY bindings USB: ssb: use devm_kzalloc USB: ssb: fix error handling in ssb_hcd_create_pdev() usb: isp1760: check for null return from kzalloc cdc-acm: Add support of ATOL FPrint fiscal printers usb: chipidea: usbmisc_imx: Remove unneeded semicolon USB: usbtmc: add device quirk for Rigol DS6104 USB: serial: mos7840: Use setup_timer phy: twl4030-usb: add ABI documentation phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe function. phy: twl4030-usb: remove pointless 'suspended' test in 'suspend' callback. phy: twl4030-usb: make runtime pm more reliable. drivers:usb:fsl: Fix compilation error for fsl ehci drv usb: renesas_usbhs: Don't disable the pipe if Control write status stage ...
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)
*/
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 && (ret != -ENOTSUPP))
+ 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,10 +418,43 @@ 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) {
+ if (ret != -ENOTSUPP)
+ 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:
+ /*
+ * Change to L2 (suspend) state before releasing
+ * spinlock
+ */
+ hsotg->lx_state = DWC2_L2;
+
+ /* 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");
+ /* Change to L2 (suspend) state */
+ hsotg->lx_state = DWC2_L2;
/* Clear the a_peripheral flag, back to a_host */
spin_unlock(&hsotg->lock);
dwc2_hcd_start(hsotg);
@@ -423,9 +463,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);
}
@@ -522,4 +560,3 @@ out:
spin_unlock(&hsotg->lock);
return retval;
}
-EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);