Re: [PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Feb 09, 2015 at 02:45:30PM +0800, Li Jun wrote:
> From: Li Jun <b47624@xxxxxxxxxxxxx>
> 
> 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.li@xxxxxxxxxxxxx>
> ---
>  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..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) && 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;
>  }
>  
> -- 

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

-- 

Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux