On Mon, Feb 09, 2015 at 11:52:11AM +0800, Li Jun wrote:
> From: Li Jun <[email protected]>
>
> 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 <[email protected]>
> ---
> 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_HSP BIT(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..6e18f40 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -861,6 +861,34 @@ 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 a_idle wakeup by data pulse, handle it like normal SRP */
Do we need this comment? From the name of function, it is SRP.
> + 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 +922,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 +951,8 @@ 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);
Better have a blank line like below.
> 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) && 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;
> }
> @@ -585,6 +595,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
> 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) {
> /*
> @@ -609,8 +620,13 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
> */
> 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;
> }
The others are ok.
--
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html