summaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r--drivers/usb/chipidea/core.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 4b22d7cb6557..74fea4fa41b1 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -798,11 +798,11 @@ static int ci_hdrc_probe(struct platform_device *pdev)
: CI_ROLE_GADGET;
}
- /* only update vbus status for peripheral */
- if (ci->role == CI_ROLE_GADGET)
- ci_handle_vbus_change(ci);
-
if (!ci_otg_is_fsm_mode(ci)) {
+ /* only update vbus status for peripheral */
+ if (ci->role == CI_ROLE_GADGET)
+ ci_handle_vbus_change(ci);
+
ret = ci_role_start(ci, ci->role);
if (ret) {
dev_err(dev, "can't start %s role\n",
@@ -861,6 +861,33 @@ static int ci_hdrc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
+/* Prepare wakeup by SRP before suspend */
+static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
+{
+ if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
+ !hw_read_otgsc(ci, OTGSC_ID)) {
+ hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
+ PORTSC_PP);
+ hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN,
+ PORTSC_WKCN);
+ }
+}
+
+/* Handle SRP when wakeup by data pulse */
+static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci)
+{
+ if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
+ (ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) {
+ if (!hw_read_otgsc(ci, OTGSC_ID)) {
+ ci->fsm.a_srp_det = 1;
+ ci->fsm.a_bus_drop = 0;
+ } else {
+ ci->fsm.id = 1;
+ }
+ ci_otg_queue_work(ci);
+ }
+}
+
static void ci_controller_suspend(struct ci_hdrc *ci)
{
disable_irq(ci->irq);
@@ -894,6 +921,8 @@ static int ci_controller_resume(struct device *dev)
pm_runtime_mark_last_busy(ci->dev);
pm_runtime_put_autosuspend(ci->dev);
enable_irq(ci->irq);
+ if (ci_otg_is_fsm_mode(ci))
+ ci_otg_fsm_wakeup_by_srp(ci);
}
return 0;
@@ -921,6 +950,9 @@ static int ci_suspend(struct device *dev)
}
if (device_may_wakeup(dev)) {
+ if (ci_otg_is_fsm_mode(ci))
+ ci_otg_fsm_suspend_for_srp(ci);
+
usb_phy_set_wakeup(ci->usb_phy, true);
enable_irq_wake(ci->irq);
}
@@ -963,6 +995,9 @@ static int ci_runtime_suspend(struct device *dev)
return 0;
}
+ if (ci_otg_is_fsm_mode(ci))
+ ci_otg_fsm_suspend_for_srp(ci);
+
usb_phy_set_wakeup(ci->usb_phy, true);
ci_controller_suspend(ci);