diff options
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r-- | drivers/usb/chipidea/core.c | 43 |
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); |