diff --git a/drivers/power/pm.h b/drivers/power/pm.h index b597fc4747a..2316e8ed21b 100644 --- a/drivers/power/pm.h +++ b/drivers/power/pm.h @@ -139,6 +139,10 @@ struct pm_domain_s /* stime - The time (in ticks) at the start of the current time slice */ clock_t stime; + + /* The power state lock count */ + + uint16_t stay[PM_COUNT]; }; /* This structure encapsulates all of the global data used by the PM module */ diff --git a/drivers/power/pm_activity.c b/drivers/power/pm_activity.c index ea76bacd906..80d44cfa69b 100644 --- a/drivers/power/pm_activity.c +++ b/drivers/power/pm_activity.c @@ -149,4 +149,81 @@ void pm_activity(int domain, int priority) } } +/**************************************************************************** + * Name: pm_stay + * + * Description: + * This function is called by a device driver to indicate that it is + * performing meaningful activities (non-idle), needs the power at kept + * last the specified level. + * + * Input Parameters: + * domain - The domain of the PM activity + * state - The state want to stay. + * + * As an example, media player might stay in normal state during playback. + * + * Returned Value: + * None. + * + * Assumptions: + * This function may be called from an interrupt handler. + * + ****************************************************************************/ + +void pm_stay(int domain, enum pm_state_e state) +{ + FAR struct pm_domain_s *pdom; + irqstate_t flags; + + /* Get a convenience pointer to minimize all of the indexing */ + + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + pdom = &g_pmglobals.domain[domain]; + + flags = enter_critical_section(); + DEBUGASSERT(state < PM_COUNT); + DEBUGASSERT(pdom->stay[state] < UINT16_MAX); + pdom->stay[state]++; + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: pm_relax + * + * Description: + * This function is called by a device driver to indicate that it is + * idle now, could relax the previous requested power level. + * + * Input Parameters: + * domain - The domain of the PM activity + * state - The state want to relax. + * + * As an example, media player might relax power level after playback. + * + * Returned Value: + * None. + * + * Assumptions: + * This function may be called from an interrupt handler. + * + ****************************************************************************/ + +void pm_relax(int domain, enum pm_state_e state) +{ + FAR struct pm_domain_s *pdom; + irqstate_t flags; + + /* Get a convenience pointer to minimize all of the indexing */ + + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + pdom = &g_pmglobals.domain[domain]; + + flags = enter_critical_section(); + DEBUGASSERT(state < PM_COUNT); + DEBUGASSERT(pdom->stay[state] > 0); + pdom->stay[state]--; + leave_critical_section(flags); +} + #endif /* CONFIG_PM */ diff --git a/drivers/power/pm_checkstate.c b/drivers/power/pm_checkstate.c index d08884165bc..207de1a3997 100644 --- a/drivers/power/pm_checkstate.c +++ b/drivers/power/pm_checkstate.c @@ -89,6 +89,7 @@ enum pm_state_e pm_checkstate(int domain) FAR struct pm_domain_s *pdom; clock_t now; irqstate_t flags; + int index; /* Get a convenience pointer to minimize all of the indexing */ @@ -132,6 +133,17 @@ enum pm_state_e pm_checkstate(int domain) (void)pm_update(domain, accum); } + /* Consider the possible power state lock here */ + + for (index = 0; index < pdom->recommended; index++) + { + if (pdom->stay[index] != 0) + { + pdom->recommended = index; + break; + } + } + leave_critical_section(flags); /* Return the recommended state. Assuming that we are called from the diff --git a/include/nuttx/power/pm.h b/include/nuttx/power/pm.h index 2f906ba5b28..2be7594f11a 100644 --- a/include/nuttx/power/pm.h +++ b/include/nuttx/power/pm.h @@ -267,6 +267,7 @@ enum pm_state_e * * PM_SLEEP may be following by PM_NORMAL */ + PM_COUNT, }; /* This structure contain pointers callback functions in the driver. These @@ -439,6 +440,53 @@ int pm_unregister(FAR struct pm_callback_s *callbacks); void pm_activity(int domain, int priority); +/**************************************************************************** + * Name: pm_stay + * + * Description: + * This function is called by a device driver to indicate that it is + * performing meaningful activities (non-idle), needs the power kept at + * last the specified level. + * + * Input Parameters: + * domain - The domain of the PM activity + * state - The state want to stay. + * + * As an example, media player might stay in normal state during playback. + * + * Returned Value: + * None. + * + * Assumptions: + * This function may be called from an interrupt handler. + * + ****************************************************************************/ + +void pm_stay(int domain, enum pm_state_e state); + +/**************************************************************************** + * Name: pm_relax + * + * Description: + * This function is called by a device driver to indicate that it is + * idle now, could relax the previous requested power level. + * + * Input Parameters: + * domain - The domain of the PM activity + * state - The state want to relax. + * + * As an example, media player might relax power level after playback. + * + * Returned Value: + * None. + * + * Assumptions: + * This function may be called from an interrupt handler. + * + ****************************************************************************/ + +void pm_relax(int domain, enum pm_state_e state); + /**************************************************************************** * Name: pm_checkstate * @@ -523,6 +571,8 @@ int pm_changestate(int domain, enum pm_state_e newstate); # define pm_register(cb) (0) # define pm_unregister(cb) (0) # define pm_activity(domain,prio) +# define pm_stay(domain,state) +# define pm_relax(domain,state) # define pm_checkstate(domain) (0) # define pm_changestate(domain,state)