[PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode
From: Li Jun b47...@freescale.com This patch adds runtime power management support for otg fsm mode, since A-device in a_idle state cannot detect data pulse irq after suspended, here enable wakeup by connection before suspend to make it can be resumed by DP; and handle wakeup from that state like SRP. Signed-off-by: Li Jun jun...@freescale.com --- drivers/usb/chipidea/bits.h|1 + drivers/usb/chipidea/core.c| 35 +++ drivers/usb/chipidea/otg_fsm.c | 22 +++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index e69424d..3cb9bda 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -63,6 +63,7 @@ #define PORTSC_HSPBIT(9) #define PORTSC_PP BIT(12) #define PORTSC_PTC(0x0FUL 16) +#define PORTSC_WKCN BIT(20) #define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23)) /* PTS and PTW for non lpm version only */ #define PORTSC_PFSC BIT(24) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 4b22d7c..5a186e3 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -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); diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 562e581..e3cf5be 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -225,6 +225,9 @@ static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) return; } + if (list_empty(active_timers)) + pm_runtime_get(ci-dev); + timer-count = timer-expires; list_add_tail(timer-list, active_timers); @@ -241,17 +244,22 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) 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); + } } /* @@ -275,8 +283,10 @@ static inline int ci_otg_tick_timer(struct ci_hdrc *ci) } /* disable 1ms irq if there is no any timer active */ - if ((expired == 1)
Re: [PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode
On Mon, Feb 09, 2015 at 02:45:30PM +0800, Li Jun wrote: From: Li Jun b47...@freescale.com This patch adds runtime power management support for otg fsm mode, since A-device in a_idle state cannot detect data pulse irq after suspended, here enable wakeup by connection before suspend to make it can be resumed by DP; and handle wakeup from that state like SRP. Signed-off-by: Li Jun jun...@freescale.com --- drivers/usb/chipidea/bits.h|1 + drivers/usb/chipidea/core.c| 35 +++ drivers/usb/chipidea/otg_fsm.c | 22 +++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index e69424d..3cb9bda 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -63,6 +63,7 @@ #define PORTSC_HSPBIT(9) #define PORTSC_PP BIT(12) #define PORTSC_PTC(0x0FUL 16) +#define PORTSC_WKCN BIT(20) #define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23)) /* PTS and PTW for non lpm version only */ #define PORTSC_PFSC BIT(24) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 4b22d7c..5a186e3 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -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); diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 562e581..e3cf5be 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -225,6 +225,9 @@ static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) return; } + if (list_empty(active_timers)) + pm_runtime_get(ci-dev); + timer-count = timer-expires; list_add_tail(timer-list, active_timers); @@ -241,17 +244,22 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) 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); + } } /* @@ -275,8 +283,10 @@ static inline int ci_otg_tick_timer(struct ci_hdrc *ci) } /* disable 1ms irq
Re: [PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode
On Mon, Feb 09, 2015 at 03:22:17PM +0800, Peter Chen wrote: On Mon, Feb 09, 2015 at 02:45:30PM +0800, Li Jun wrote: From: Li Jun b47...@freescale.com This patch adds runtime power management support for otg fsm mode, since A-device in a_idle state cannot detect data pulse irq after suspended, here enable wakeup by connection before suspend to make it can be resumed by DP; and handle wakeup from that state like SRP. Signed-off-by: Li Jun jun...@freescale.com --- drivers/usb/chipidea/bits.h|1 + drivers/usb/chipidea/core.c| 35 +++ drivers/usb/chipidea/otg_fsm.c | 22 +++--- 3 files changed, 55 insertions(+), 3 deletions(-) I meet system hang at my imx6sx board after running below commands at B device, at A device, it did not meet the system hang during the boots up with this patch. root@imx6sxsabresd:~# modprobe g_mass_storage file=/dev/mmcblk0p1 removable=1 [ 43.202180] Number of LUNs=8 [ 43.205103] Mass Storage Function, version: 2009/09/11 [ 43.211669] LUN: removable file: (no medium) [ 43.217236] Number of LUNs=1 [ 43.221121] LUN: removable file: /dev/mmcblk0p1 [ 43.225802] Number of LUNs=1 [ 43.231027] g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11 [ 43.238126] g_mass_storage gadget: userspace failed to provide iSerialNumber [ 43.245249] g_mass_storage gadget: g_mass_storage ready Reproduced on my i.MX6SX-SDB board, I checked and found it's due to there is vbus glitch on otg port during another host-only port initialization, it should not hang and there is the same problem if load gadget driver with vbus on(e.g. connect to a PC host), I will submit another patch to fix it, but cannot cover vbus glitch case. Li Jun -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html