: 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",
}
#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);
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;
}
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);
}
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);
return;
}
+ if (list_empty(active_timers))
+ pm_runtime_get(ci->dev);
+
timer->count = timer->expires;
list_add_tail(&timer->list, active_timers);
struct ci_otg_fsm_timer *tmp_timer, *del_tmp;
struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t];
struct list_head *active_timers = &ci->fsm_timer->active_timers;
+ int flag = 0;
if (t >= NUM_CI_OTG_FSM_TIMERS)
return;
list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list)
- if (tmp_timer == timer)
+ if (tmp_timer == timer) {
list_del(&timer->list);
+ flag = 1;
+ }
/* Disable 1ms irq if there is no any active timer */
- if (list_empty(active_timers))
+ if (list_empty(active_timers) && (flag == 1)) {
hw_write_otgsc(ci, OTGSC_1MSIE, 0);
+ pm_runtime_put(ci->dev);
+ }
}
/*
}
/* disable 1ms irq if there is no any timer active */
- if ((expired == 1) && list_empty(active_timers))
+ if ((expired == 1) && list_empty(active_timers)) {
hw_write_otgsc(ci, OTGSC_1MSIE, 0);
+ pm_runtime_put(ci->dev);
+ }
return expired;
}
ci->fsm.otg->state < OTG_STATE_A_IDLE)
return 0;
+ pm_runtime_get_sync(ci->dev);
if (otg_statemachine(&ci->fsm)) {
if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
/*
*/
ci_otg_queue_work(ci);
}
+ } else if (ci->fsm.otg->state == OTG_STATE_A_HOST) {
+ pm_runtime_mark_last_busy(ci->dev);
+ pm_runtime_put_autosuspend(ci->dev);
+ return 0;
}
}
+ pm_runtime_put_sync(ci->dev);
return 0;
}