|
@@ -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);
|
|
|
|