diff --git a/os/arch/arm/src/amebasmart/amebasmart_pmhelpers.c b/os/arch/arm/src/amebasmart/amebasmart_pmhelpers.c index 24dc276877..90f457517e 100644 --- a/os/arch/arm/src/amebasmart/amebasmart_pmhelpers.c +++ b/os/arch/arm/src/amebasmart/amebasmart_pmhelpers.c @@ -126,7 +126,7 @@ void up_set_pm_timer(unsigned int interval_us) void bsp_pm_domain_register(char *domain_name, int bsp_drv_id) { - int domain_id = pm_domain_register(domain_name); + int domain_id = pm_domain_register(domain_name, PM_BACKGROUND, NULL); if (domain_id < 0) { pmdbg("Unable to register %s DOMAIN\n", domain_name); } else { diff --git a/os/board/rtl8730e/src/component/bluetooth/example/ble_scatternet/scatternet.c b/os/board/rtl8730e/src/component/bluetooth/example/ble_scatternet/scatternet.c index edfce189a8..625364602e 100644 --- a/os/board/rtl8730e/src/component/bluetooth/example/ble_scatternet/scatternet.c +++ b/os/board/rtl8730e/src/component/bluetooth/example/ble_scatternet/scatternet.c @@ -296,7 +296,7 @@ static rtk_bt_evt_cb_ret_t ble_tizenrt_scatternet_gap_app_callback(uint8_t evt_c if (!conn_ind->err) { #ifdef CONFIG_PM /* Register PM_BLE_DOMAIN and Perform 10 minutes timedsuspend */ - domain = pm_domain_register("BLE"); + domain = pm_domain_register("BLE", PM_BACKGROUND, NULL); if (domain < 0) { pmdbg("Unable to register BLE DOMAIN\n"); } else if (pm_timedsuspend(domain, 600000) != 0) { diff --git a/os/drivers/audio/ndp120_voice.c b/os/drivers/audio/ndp120_voice.c index eb11459647..632c3f56f6 100644 --- a/os/drivers/audio/ndp120_voice.c +++ b/os/drivers/audio/ndp120_voice.c @@ -104,13 +104,13 @@ static int ndp120_release(FAR struct audio_lowerhalf_s *dev); static struct ndp120_dev_s *g_ndp120; static int g_ndp120_pm_id; -static void ndp_pm_notify(struct pm_callback_s *cb, enum pm_state_e pmstate); -static int ndp_pm_prepare(struct pm_callback_s *cb, enum pm_state_e pmstate); +static int ndp_pm_sleep(struct pm_callback_s *cb); +static void ndp_pm_wake(struct pm_callback_s *cb); static struct pm_callback_s g_pmndpcb = { - .notify = ndp_pm_notify, - .prepare = ndp_pm_prepare, + .sleep = ndp_pm_sleep, + .wake = ndp_pm_wake, }; #endif @@ -777,7 +777,7 @@ static void ndp120_interrupt_dispatch(int d) #ifdef CONFIG_PM /**************************************************************************** - * Name: ndp_pm_notify + * Name: ndp_pm_sleep * * Description: * Notify the driver of new power state. This callback is called after @@ -785,31 +785,22 @@ static void ndp120_interrupt_dispatch(int d) * ****************************************************************************/ -static void ndp_pm_notify(struct pm_callback_s *cb, enum pm_state_e state) +static int ndp_pm_sleep(struct pm_callback_s *cb) { /* Currently PM follows the state changes as follows, - * On boot, we are in PM_NORMAL. After that we only use PM_STANDBY and PM_SLEEP - * on boot : PM_NORMAL -> PM_STANDBY -> PM_SLEEP, from there on - * PM_SLEEP -> PM_STANBY -> PM_SLEEP -> PM_STANBY........ + * On boot, we are in PM_FOREGROUND. After that we only use PM_BACKGROUND and PM_SLEEP + * on boot : PM_FOREGROUND -> PM_BACKGROUND -> PM_SLEEP, from there on + * PM_SLEEP -> PM_BACKGROUND -> PM_SLEEP -> PM_BACKGROUND........ */ - switch (state) { - case(PM_SLEEP): { - audvdbg("entering SLEEP\n"); + audvdbg("entering SLEEP\n"); #ifdef CONFIG_NDP120_AEC_SUPPORT - ndp120_aec_disable(g_ndp120); + ndp120_aec_disable(g_ndp120); #endif - } - break; - default: { - /* Nothing to do */ - audvdbg("default case\n"); - } - break; - } + return OK; } /**************************************************************************** - * Name: ndp_pm_prepare + * Name: ndp_pm_wake * * Description: * Request the driver to prepare for a new power state. This is a warning @@ -820,10 +811,9 @@ static void ndp_pm_notify(struct pm_callback_s *cb, enum pm_state_e state) * ****************************************************************************/ -static int ndp_pm_prepare(struct pm_callback_s *cb, enum pm_state_e state) +static void ndp_pm_wake(struct pm_callback_s *cb) { audvdbg("entry\n"); - return OK; } #endif /* End of CONFIG_PM */ @@ -880,9 +870,8 @@ FAR struct audio_lowerhalf_s *ndp120_lowerhalf_initialize(FAR struct spi_dev_s * /* only used during pm callbacks */ g_ndp120 = priv; - g_ndp120_pm_id = pm_domain_register("NDP120"); - ret = pm_register(&g_pmndpcb); - DEBUGASSERT(ret == OK); + g_ndp120_pm_id = pm_domain_register("NDP120", PM_BACKGROUND, &g_pmndpcb); + DEBUGASSERT(g_ndp120_pm_id >= 0); #endif return &priv->dev; } diff --git a/os/drivers/audio/syu645b.c b/os/drivers/audio/syu645b.c index 03c08402b0..72cf5d2c83 100644 --- a/os/drivers/audio/syu645b.c +++ b/os/drivers/audio/syu645b.c @@ -96,12 +96,13 @@ static void syu645b_set_equalizer(FAR struct syu645b_dev_s *priv, uint32_t prese #ifdef CONFIG_PM static struct syu645b_dev_s *g_syu645b; -static void syu645b_pm_notify(struct pm_callback_s *cb, enum pm_state_e pmstate); -static int syu645b_pm_prepare(struct pm_callback_s *cb, enum pm_state_e pmstate); +static void syu645b_pm_sleep(struct pm_callback_s *cb); +static int syu645b_pm_wake(struct pm_callback_s *cb); static struct pm_callback_s g_pm_syu645b_cb ={ - .notify = syu645b_pm_notify, - .prepare = syu645b_pm_prepare, + .sleep = syu645b_pm_sleep, + .wake = syu645b_pm_wake, }; +static int syu645b_pm_domain_id = -1; #endif /************************************************************************************ @@ -786,7 +787,7 @@ static int syu645b_enqueuebuffer(FAR struct audio_lowerhalf_s *dev, FAR struct a timeout = (CONFIG_SYU645B_BUFFER_SIZE * CONFIG_SYU645B_NUM_BUFFERS * BYTE_TO_BIT_FACTOR * SEC_TO_MSEC_FACTOR) / (priv->samprate * priv->nchannels * priv->bpsamp) + I2S_TIMEOUT_OFFSET_MS; #ifdef CONFIG_PM - pm_timedsuspend(pm_domain_register("AUDIO"), timeout); + pm_timedsuspend(syu645b_pm_domain_id, timeout); #endif ret = I2S_SEND(priv->i2s, apb, syu645b_txcallback, priv, timeout); @@ -1052,7 +1053,7 @@ static void syu645b_set_equalizer(FAR struct syu645b_dev_s *priv, uint32_t prese #ifdef CONFIG_PM /**************************************************************************** - * Name: syu645b_pm_notify + * Name: syu645b_pm_sleep * * Description: * Notify the driver of new power state. This callback is called after @@ -1060,49 +1061,32 @@ static void syu645b_set_equalizer(FAR struct syu645b_dev_s *priv, uint32_t prese * ****************************************************************************/ -static void syu645b_pm_notify(struct pm_callback_s *cb, enum pm_state_e state) +static int syu645b_pm_sleep(struct pm_callback_s *cb) { /* Currently PM follows the state changes as follows, - * On boot, we are in PM_NORMAL. After that we only use PM_STANDBY and PM_SLEEP - * on boot : PM_NORMAL -> PM_STANDBY -> PM_SLEEP, from there on - * PM_SLEEP -> PM_STANBY -> PM_SLEEP -> PM_STANBY........ + * On boot, we are in PM_FOREGROUND. After that we only use PM_BACKGROUND and PM_SLEEP + * on boot : PM_FOREGROUND -> PM_BACKGROUND -> PM_SLEEP, from there on + * PM_SLEEP -> PM_BACKGROUND -> PM_SLEEP -> PM_BACKGROUND........ */ audvdbg("pmstate : %d\n", state); #if 0 struct syu645b_lower_s *lower = g_syu645b->lower; #endif - switch (state) { - case(PM_SLEEP): { #if 0 - if (lower->control_hw_reset) { - lower->control_hw_reset(true); - up_mdelay(100); - lower->control_hw_reset(false); - up_mdelay(100); - } -#endif - /* To prevent consume 12v, just mute on */ - syu645b_setmute(g_syu645b, true); + if (lower->control_hw_reset) { + lower->control_hw_reset(true); + up_mdelay(100); + lower->control_hw_reset(false); + up_mdelay(100); } - break; - case(PM_STANDBY): { -#if 0 - syu645b_reset_config(g_syu645b); #endif - /* Mute off when wake up */ - syu645b_setmute(g_syu645b, false); - } - break; - default: { - /* Nothing to do */ - audvdbg("default case\n"); - } - break; - } + /* To prevent consume 12v, just mute on */ + syu645b_setmute(g_syu645b, true); + return OK; } /**************************************************************************** - * Name: syu645b_pm_prepare + * Name: syu645b_pm_wake * * Description: * Request the driver to prepare for a new power state. This is a warning @@ -1113,10 +1097,16 @@ static void syu645b_pm_notify(struct pm_callback_s *cb, enum pm_state_e state) * ****************************************************************************/ -static int syu645b_pm_prepare(struct pm_callback_s *cb, enum pm_state_e state) +static void syu645b_pm_wake(struct pm_callback_s *cb) { - audvdbg("pmstate : %d\n", state); - return OK; +#if 0 + struct syu645b_lower_s *lower = g_syu645b->lower; +#endif +#if 0 + syu645b_reset_config(g_syu645b); +#endif + /* Mute off when wake up */ + syu645b_setmute(g_syu645b, false); } #endif /* End of CONFIG_PM */ @@ -1181,8 +1171,8 @@ FAR struct audio_lowerhalf_s *syu645b_initialize(FAR struct i2c_dev_s *i2c, FAR /* only used during pm callbacks */ g_syu645b = priv; - int ret = pm_register(&g_pm_syu645b_cb); - DEBUGASSERT(ret == OK); + syu645b_pm_domain_id = pm_domain_register("AUDIO", PM_FOREGROUND, &g_pm_syu645b_cb); + DEBUGASSERT(syu645b_pm_domain_id >= 0); #endif return &priv->dev; diff --git a/os/drivers/lcd/lcd_dev.c b/os/drivers/lcd/lcd_dev.c index a21e5ab847..33977ddb8b 100644 --- a/os/drivers/lcd/lcd_dev.c +++ b/os/drivers/lcd/lcd_dev.c @@ -454,7 +454,7 @@ int lcddev_register(struct lcd_dev_s *dev) #endif #ifdef CONFIG_PM - lcd_info->pm_domain = pm_domain_register("LCD"); + lcd_info->pm_domain = pm_domain_register("LCD", PM_FOREGROUND, NULL); #endif lcd_init_put_image(dev); diff --git a/os/drivers/pm/pm.c b/os/drivers/pm/pm.c index c4379ab563..a65e7d197e 100644 --- a/os/drivers/pm/pm.c +++ b/os/drivers/pm/pm.c @@ -147,7 +147,7 @@ static int pm_ioctl(FAR struct file *filep, int cmd, unsigned long arg) ret = -EINVAL; pmdbg("Please input correct arguments\n"); } else { - ((pm_domain_arg_t *)arg)->domain_id = pm_domain_register(((pm_domain_arg_t *)arg)->domain_name); + ((pm_domain_arg_t *)arg)->domain_id = pm_domain_register(((pm_domain_arg_t *)arg)->domain_name, PM_BACKGROUND, NULL); if (((pm_domain_arg_t *)arg)->domain_id >= 0) { ret = OK; } diff --git a/os/drivers/serial/serial.c b/os/drivers/serial/serial.c index 9a29562777..df94114904 100644 --- a/os/drivers/serial/serial.c +++ b/os/drivers/serial/serial.c @@ -1238,7 +1238,7 @@ static int uart_open(FAR struct file *filep) #ifdef CONFIG_PM /* Register PM_UART_DOMAIN to access PM APIs during UART operations. */ if (pm_uart_domain_id == -1) { - ret = pm_domain_register(PM_UART_DOMAIN); + ret = pm_domain_register(PM_UART_DOMAIN, PM_BACKGROUND, NULL); if (ret < 0) { return ret; } diff --git a/os/include/tinyara/pm/pm.h b/os/include/tinyara/pm/pm.h index d8d9b81605..8a6a9bdf75 100644 --- a/os/include/tinyara/pm/pm.h +++ b/os/include/tinyara/pm/pm.h @@ -150,28 +150,20 @@ enum pm_state_e { * * PM_RESTORE is used to notify for restore from low power state. */ - PM_NORMAL = 0, /* Normal full power operating mode. If the driver is in + PM_FOREGROUND = 0, /* Normal full power operating mode. If the driver is in * a reduced power usage mode, it should immediately re- - * initialize for normal operatin. + * initialize for normal operation. * - * PM_NORMAL may be followed by PM_IDLE. + * PM_FOREGROUND may be followed by PM_BACKGROUND. */ - PM_IDLE, /* Drivers will receive this state change if it is - * appropriate to enter a simple IDLE power state. This - * would include simple things such as reducing display back- - * lighting. The driver should be ready to resume normal - * activity instantly. - * - * PM_IDLE may be followed by PM_STANDBY or PM_NORMAL. - */ - PM_STANDBY, /* The system is entering standby mode. Standby is a lower + PM_BACKGROUND, /* The system is entering background mode. Background is a lower * power consumption mode that may involve more extensive * power management steps such has disabling clocking or * setting the processor into reduced power consumption * modes. In this state, the system should still be able * to resume normal activity almost immediately. * - * PM_STANDBY may be followed PM_SLEEP or by PM_NORMAL + * PM_BACKGROUND may be followed PM_SLEEP or by PM_FOREGROUND */ PM_SLEEP, /* The system is entering deep sleep mode. The most drastic * power reduction measures possible should be taken in this @@ -179,7 +171,7 @@ enum pm_state_e { * operation from SLEEP (some MCUs may even require going * through reset). * - * PM_SLEEP may be following by PM_NORMAL + * PM_SLEEP may be following by PM_FOREGROUND */ PM_COUNT, }; @@ -208,60 +200,49 @@ struct pm_callback_s { char name[MAX_PM_CALLBACK_NAME]; /* Name of driver which register callback */ /************************************************************************** - * Name: prepare + * Name: sleep * * Description: - * Request the driver to prepare for a new power state. This is a - * warning that the system is about to enter into a new power state. The + * Put the driver into low power mode (or turn OFF). This is a + * warning that the system is about to enter into PM_SLEEP state. The * driver should begin whatever operations that may be required to enter - * power state. The driver may abort the state change mode by returning + * PM_SLEEP state. The driver may abort the state change mode by returning * a non-zero value from the callback function * * Input Parameters: * cb - Returned to the driver. The driver version of the callback * structure may include additional, driver-specific state * data at the end of the structure. - * domain - Identifies the activity domain of the state change - * pmstate - Identifies the new PM state * * Returned Value: * 0 (OK) means the event was successfully processed and that the driver - * is prepared for the PM state change. Non-zero means that the driver + * is prepared for the PM_SLEEP change. Non-zero means that the driver * is not prepared to perform the tasks needed achieve this power setting - * and will cause the state change to be aborted. NOTE: The prepare - * method will also be recalled when reverting from lower back to higher - * power consumption modes (say because another driver refused a lower - * power state change). Drivers are not permitted to return non-zero - * values when reverting back to higher power consumption modes! + * and will cause the state change to be aborted. * **************************************************************************/ - int (*prepare)(FAR struct pm_callback_s *cb, enum pm_state_e pmstate); + int (*sleep)(FAR struct pm_callback_s *cb); /************************************************************************** - * Name: notify + * Name: wake * * Description: - * Notify the driver of new power state. This callback is called after - * all drivers have had the opportunity to prepare for the new power - * state. + * Put the driver into high power mode (or turn ON). This callback is called + * after board change its state from low power to high power. All drivers + * had the opportunity to prepare for the new power state. * * Input Parameters: - * cb - Returned to the driver. The driver version of the callback + * cb - Returned to the driver. The driver version of the callback * structure may include additional, driver-specific state * data at the end of the structure. - * domain - Identifies the activity domain of the state change - * pmstate - Identifies the new PM state * * Returned Value: - * None. The driver already agreed to transition to the low power - * consumption state when when it returned OK to the prepare() call. - * At that time it should have made all preprations necessary to enter - * the new state. Now the driver must make the state transition. + * None. * **************************************************************************/ - void (*notify)(FAR struct pm_callback_s *cb, enum pm_state_e pmstate); + void (*wake)(FAR struct pm_callback_s *cb); }; /**************************************************************************** @@ -333,42 +314,6 @@ void pm_start(void); void pm_initialize(void); -/**************************************************************************** - * Name: pm_register - * - * Description: - * This function is called by a device driver in order to register to - * receive power management event callbacks. - * - * Input parameters: - * callbacks - An instance of struct pm_callback_s providing the driver - * callback functions. - * - * Returned value: - * Zero (OK) on success; otherwise a negated errno value is returned. - * - ****************************************************************************/ - -int pm_register(FAR struct pm_callback_s *callbacks); - -/**************************************************************************** - * Name: pm_unregister - * - * Description: - * This function is called by a device driver in order to unregister - * previously registered power management event callbacks. - * - * Input parameters: - * callbacks - An instance of struct pm_callback_s providing the driver - * callback functions. - * - * Returned value: - * Zero (OK) on success; otherwise a negated errno value is returned. - * - ****************************************************************************/ - -int pm_unregister(FAR struct pm_callback_s *callbacks); - /**************************************************************************** * Name: pm_domain_register * @@ -385,7 +330,7 @@ int pm_unregister(FAR struct pm_callback_s *callbacks); * ****************************************************************************/ -int pm_domain_register(char *domain); +int pm_domain_register(char *domain, enum pm_state_e state, FAR struct pm_callback_s *callbacks); /**************************************************************************** * Name: pm_idle @@ -571,9 +516,7 @@ int pm_metrics(int milliseconds); #define pm_start() #define pm_initialize() -#define pm_register(cb) (0) -#define pm_unregister(cb) (0) -#define pm_domain_register(domain) (0) +#define pm_domain_register(domain, state, callbacks) (0) #define pm_idle() #define pm_suspend(domain_id) (0) #define pm_resume(domain_id) (0) diff --git a/os/pm/Makefile b/os/pm/Makefile index ca90f62e67..4592ceb616 100644 --- a/os/pm/Makefile +++ b/os/pm/Makefile @@ -21,7 +21,7 @@ ASRCS = CSRCS += pm_changestate.c pm_checkstate.c pm_initialize.c pm_idle.c -CSRCS += pm_register.c pm_domain_register.c pm_unregister.c pm_procfs.c +CSRCS += pm_domain_register.c pm_procfs.c CSRCS += pm_suspend.c pm_resume.c pm_timedsuspend.c CSRCS += pm_suspendcount.c pm_wakehandler.c diff --git a/os/pm/pm.h b/os/pm/pm.h index 14530f34cb..d6201534fd 100644 --- a/os/pm/pm.h +++ b/os/pm/pm.h @@ -117,7 +117,7 @@ struct pm_global_s { * must be locked by calling pm_lock() before it is accessed. */ - dq_queue_t registry; + dq_queue_t registry[PM_COUNT]; /* The power state lock count */ @@ -140,6 +140,13 @@ struct pm_global_s { bool is_running; }; +struct pm_domain_s { + char *name; + enum pm_state_e state; +}; + +typedef struct pm_domain_s pm_domain_t; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -155,7 +162,7 @@ extern "C" { /* All PM global data: */ EXTERN struct pm_global_s g_pmglobals; -EXTERN char *pm_domain_map[CONFIG_PM_NDOMAINS]; +EXTERN pm_domain_t pm_domain_map[CONFIG_PM_NDOMAINS]; /************************************************************************************ * Public Function Prototypes ************************************************************************************/ diff --git a/os/pm/pm_changestate.c b/os/pm/pm_changestate.c index 0961d537ff..99d57d76fd 100644 --- a/os/pm/pm_changestate.c +++ b/os/pm/pm_changestate.c @@ -75,13 +75,12 @@ ****************************************************************************/ /**************************************************************************** - * Name: pm_prepall + * Name: pm_prepsleep * * Description: - * Prepare every driver for the state change. + * Put every driver to sleep for the state change. * * Input Parameters: - * domain - Identifies the domain of the new PM state * newstate - Identifies the new PM state * * Returned Value: @@ -95,33 +94,31 @@ * ****************************************************************************/ -static int pm_prepall(enum pm_state_e newstate) +static int pm_prepsleep(enum pm_state_e newstate) { FAR dq_entry_t *entry; int ret = OK; - - if (newstate <= g_pmglobals.state) { - /* Visit each registered callback structure in normal order. */ - - for (entry = dq_peek(&g_pmglobals.registry); entry && ret == OK; entry = dq_next(entry)) { - /* Is the prepare callback supported? */ - - FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; - if (cb->prepare) { - /* Yes.. prepare the driver */ - ret = cb->prepare(cb, newstate); - } + /* Visit each registered callback structure in normal order. */ + for (entry = dq_peek(&g_pmglobals.registry[newstate]); entry && ret == OK; entry = dq_next(entry)) { + /* Is the sleep callback supported? */ + + FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; + if (cb->sleep) { + /* Yes.. sleep the driver */ + ret = cb->sleep(cb); } - } else { - /* Visit each registered callback structure in reverse order. */ + } - for (entry = dq_tail(&g_pmglobals.registry); entry && ret == OK; entry = dq_prev(entry)) { - /* Is the prepare callback supported? */ + if (ret != OK) { + entry = dq_prev(entry); + /* Visit each registered callback structure in reverse order. */ + for (; entry; entry = dq_prev(entry)) { + /* Is the wake callback supported? */ FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; - if (cb->prepare) { - /* Yes.. prepare the driver */ - ret = cb->prepare(cb, newstate); + if (cb->wake) { + /* Yes.. wake the driver */ + cb->wake(cb); } } } @@ -130,14 +127,13 @@ static int pm_prepall(enum pm_state_e newstate) } /**************************************************************************** - * Name: pm_changeall + * Name: pm_prepwake * * Description: * domain - Identifies the domain of the new PM state * Inform all drivers of the state change. * * Input Parameters: - * domain - Identifies the domain of the new PM state * newstate - Identifies the new PM state * * Returned Value: @@ -148,32 +144,17 @@ static int pm_prepall(enum pm_state_e newstate) * ****************************************************************************/ -static inline void pm_changeall(enum pm_state_e newstate) +static inline void pm_prepwake(enum pm_state_e newstate) { FAR dq_entry_t *entry; - if (newstate <= g_pmglobals.state) { - /* Visit each registered callback structure in normal order. */ - - for (entry = dq_peek(&g_pmglobals.registry); entry; entry = dq_next(entry)) { - /* Is the notification callback supported? */ - - FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; - if (cb->notify) { - /* Yes.. notify the driver */ - cb->notify(cb, newstate); - } - } - } else { - /* Visit each registered callback structure in reverse order. */ - - for (entry = dq_tail(&g_pmglobals.registry); entry; entry = dq_prev(entry)) { - /* Is the notification callback supported? */ - - FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; - if (cb->notify) { - /* Yes.. notify the driver */ - cb->notify(cb, newstate); - } + /* Visit each registered callback structure */ + for (entry = dq_peek(&g_pmglobals.registry[newstate]); entry; entry = dq_next(entry)) { + /* Is the wake callback supported? */ + + FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry; + if (cb->wake) { + /* Yes.. wake the driver */ + cb->wake(cb); } } } @@ -212,6 +193,7 @@ static inline void pm_changeall(enum pm_state_e newstate) int pm_changestate(enum pm_state_e newstate) { irqstate_t flags; + enum pm_state_e curstate; int ret = OK; /* Disable interrupts throught this operation... changing driver states @@ -222,22 +204,33 @@ int pm_changestate(enum pm_state_e newstate) flags = enter_critical_section(); + curstate = g_pmglobals.state; + /* First, prepare the drivers for the state change. In this phase, * drivers may refuse the state change. */ if ((newstate != PM_RESTORE) && (newstate != g_pmglobals.state)) { - ret = pm_prepall(newstate); - if (ret != OK) { - goto EXIT; - } - /* All drivers have agreed to the state change (or, one or more have - * disagreed and the state has been reverted). Set the new state. - */ - pm_changeall(newstate); + if (g_pmglobals.state < newstate) { + while (g_pmglobals.state < newstate) { + ret = pm_prepsleep(g_pmglobals.state); + if (ret != OK) { + pm_changestate(curstate); + goto EXIT; + } +#ifdef CONFIG_PM_METRICS + pm_metrics_update_changestate(); +#endif + g_pmglobals.state++; + } + } else { + while (g_pmglobals.state > newstate) { + pm_prepwake(newstate); #ifdef CONFIG_PM_METRICS - pm_metrics_update_changestate(); + pm_metrics_update_changestate(); #endif - g_pmglobals.state = newstate; + g_pmglobals.state--; + } + } } EXIT: /* Restore the interrupt state */ diff --git a/os/pm/pm_checkstate.c b/os/pm/pm_checkstate.c index 6bc8cd67d5..367c4952d4 100644 --- a/os/pm/pm_checkstate.c +++ b/os/pm/pm_checkstate.c @@ -109,15 +109,11 @@ enum pm_state_e pm_checkstate(void) newstate = PM_SLEEP; } - /* If there is power state lock for LCD and IDLE domain, recommended PM_NORMAL State */ - if (g_pmglobals.suspend_count[PM_IDLE_DOMAIN] || g_pmglobals.suspend_count[PM_LCD_DOMAIN]) { - newstate = PM_NORMAL; - } else if (newstate == PM_SLEEP) { - /* Consider the possible power state lock here */ - for (index = 0; index < CONFIG_PM_NDOMAINS; index++) { - if (g_pmglobals.suspend_count[index] != 0) { - newstate = PM_STANDBY; - break; + /* Consider the possible power state lock here */ + for (index = 0; index < CONFIG_PM_NDOMAINS; index++) { + if (g_pmglobals.suspend_count[index] != 0) { + if (pm_domain_map[index].state < newstate) { + newstate = pm_domain_map[index].state; } } } diff --git a/os/pm/pm_domain_register.c b/os/pm/pm_domain_register.c index 7cfff653c5..9726e6e353 100644 --- a/os/pm/pm_domain_register.c +++ b/os/pm/pm_domain_register.c @@ -33,9 +33,9 @@ * Public Variables ************************************************************************/ -/* This array maps the integer domain to its respective string domain */ +/* This array maps the integer domain to its respective struct pm_doamin_s domain */ -char *pm_domain_map[CONFIG_PM_NDOMAINS]; +struct pm_domain_s pm_domain_map[CONFIG_PM_NDOMAINS]; /**************************************************************************** * Public Functions @@ -58,7 +58,7 @@ char *pm_domain_map[CONFIG_PM_NDOMAINS]; ****************************************************************************/ int pm_check_domain(int domain_id) { - if (domain_id < 0 || domain_id >= CONFIG_PM_NDOMAINS || pm_domain_map[domain_id] == NULL) { + if (domain_id < 0 || domain_id >= CONFIG_PM_NDOMAINS || pm_domain_map[domain_id].name == NULL) { set_errno(EINVAL); pmdbg("Invalid Domain: %d\n", domain_id); return ERROR; @@ -81,12 +81,14 @@ int pm_check_domain(int domain_id) * ****************************************************************************/ -int pm_domain_register(char *domain) +int pm_domain_register(char *domain, enum pm_state_e state, FAR struct pm_callback_s *callbacks) { int index; irqstate_t flags; int length = strlen(domain); + DEBUGASSERT((state >= PM_FOREGROUND) && (state < PM_SLEEP)); + /* If domain string length is greater than max allowed then return error */ if (length >= CONFIG_PM_DOMAIN_NAME_SIZE) { set_errno(E2BIG); @@ -97,15 +99,19 @@ int pm_domain_register(char *domain) for (index = 0; index < CONFIG_PM_NDOMAINS; index++) { flags = enter_critical_section(); /* If we have unused domain ID then use it to register given domain */ - if (pm_domain_map[index] == NULL) { - pm_domain_map[index] = (char *)kmm_malloc((length + 1) * sizeof(char)); - if (!pm_domain_map[index]) { + if (pm_domain_map[index].name == NULL) { + pm_domain_map[index].name = (char *)kmm_malloc((length + 1) * sizeof(char)); + if (!pm_domain_map[index].name) { set_errno(ENOMEM); pmdbg("Unable to allocate memory from heap\n"); leave_critical_section(flags); return ERROR; } - strncpy(pm_domain_map[index], domain, length + 1); + strncpy(pm_domain_map[index].name, domain, length + 1); + pm_domain_map[index].state = state; + if (callbacks) { + dq_addlast(&callbacks->entry, &g_pmglobals.registry[state]); + } g_pmglobals.ndomains++; #ifdef CONFIG_PM_METRICS /* For newly registered domain initialize its pm metrics*/ @@ -113,7 +119,8 @@ int pm_domain_register(char *domain) #endif goto EXIT; /* If domain is already registered then return registered domain ID */ - } else if (strncmp(pm_domain_map[index], domain, length + 1) == 0) { + } else if (strncmp(pm_domain_map[index].name, domain, length + 1) == 0) { + pmvdbg("Domain: %s, is already registered\n", domain); goto EXIT; } leave_critical_section(flags); diff --git a/os/pm/pm_initialize.c b/os/pm/pm_initialize.c index 1a2f41e8af..2909474609 100644 --- a/os/pm/pm_initialize.c +++ b/os/pm/pm_initialize.c @@ -76,7 +76,7 @@ */ struct pm_global_s g_pmglobals; -const char *pm_state_name[PM_COUNT] = {"NORMAL", "IDLE", "STANDBY", "SLEEP"}; +const char *pm_state_name[PM_COUNT] = {"FOREGROUND", "BACKGROUND", "SLEEP"}; const char *wakeup_src_name[PM_WAKEUP_SRC_COUNT] = {"UNKNOWN", "BLE", "WIFI", "UART CONSOLE", "UART TTYS2", "GPIO", "HW TIMER"}; /**************************************************************************** @@ -126,7 +126,7 @@ void pm_initialize(void) sem_init(&g_pmglobals.regsem, 0, 1); /* Register Special Domains, which are specific to Kernel*/ - DEBUGASSERT(pm_domain_register("IDLE") == PM_IDLE_DOMAIN); - DEBUGASSERT(pm_domain_register("SCREEN") == PM_LCD_DOMAIN); + DEBUGASSERT(pm_domain_register("IDLE", PM_FOREGROUND, NULL) == PM_IDLE_DOMAIN); + DEBUGASSERT(pm_domain_register("SCREEN", PM_FOREGROUND, NULL) == PM_LCD_DOMAIN); } #endif /* CONFIG_PM */ diff --git a/os/pm/pm_metrics.c b/os/pm/pm_metrics.c index ba4c764e91..a13e397ea9 100644 --- a/os/pm/pm_metrics.c +++ b/os/pm/pm_metrics.c @@ -65,7 +65,7 @@ static void pm_print_metrics(double total_time, int n_domains) pmdbg(" DOMAIN | TOTAL PM SUSPEND TIME [3] | TOTAL SLEEP BLOCKING TIME [4] \n"); pmdbg("----------------------------------|---------------------------|-------------------------------\n"); for (index = 0; index < n_domains; index++) { - pmdbg(" %32s | %13dms (%6.2f%%) | %17dms (%6.2f%%) \n", pm_domain_map[index], TICK2MSEC(g_pm_metrics->domain_metrics.suspend_ticks[index]), + pmdbg(" %32s | %13dms (%6.2f%%) | %17dms (%6.2f%%) \n", pm_domain_map[index].name, TICK2MSEC(g_pm_metrics->domain_metrics.suspend_ticks[index]), ((double)g_pm_metrics->domain_metrics.suspend_ticks[index]) * 100.0 / total_time, g_pm_metrics->domain_metrics.blocking_board_sleep_ticks[index], ((double)g_pm_metrics->domain_metrics.blocking_board_sleep_ticks[index]) * 100.0 / ((double)g_pm_metrics->total_try_ticks)); } @@ -85,8 +85,8 @@ static void pm_print_metrics(double total_time, int n_domains) pmdbg("\n"); pmdbg(" BOARD STATE | PM STATE | TIME \n"); pmdbg("-------------|----------|------------------------\n"); - for (pm_state = PM_NORMAL; pm_state < PM_SLEEP; pm_state++) { - pmdbg(" %11s | %8s | %10dms (%6.2f%%) \n", ((pm_state == PM_NORMAL) ? "WAKEUP" : ""), pm_state_name[pm_state], TICK2MSEC(g_pm_metrics->state_metrics.state_accum_ticks[pm_state]), + for (pm_state = PM_FOREGROUND; pm_state < PM_SLEEP; pm_state++) { + pmdbg(" %11s | %8s | %10dms (%6.2f%%) \n", ((pm_state == PM_FOREGROUND) ? "WAKEUP" : ""), pm_state_name[pm_state], TICK2MSEC(g_pm_metrics->state_metrics.state_accum_ticks[pm_state]), ((double)g_pm_metrics->state_metrics.state_accum_ticks[pm_state]) * 100.0 / total_time); } pmdbg("-------------|----------|------------------------\n"); @@ -290,7 +290,7 @@ int pm_metrics(int milliseconds) flags = enter_critical_section(); start_time = clock_systimer(); g_pm_metrics->state_metrics.stime = start_time; - for (index = 0; (index < CONFIG_PM_NDOMAINS) && pm_domain_map[index]; index++) { + for (index = 0; (index < CONFIG_PM_NDOMAINS) && pm_domain_map[index].name; index++) { pm_metrics_update_domain(index); g_pm_metrics->domain_metrics.stime[index] = start_time; } @@ -316,7 +316,7 @@ int pm_metrics(int milliseconds) flags = enter_critical_section(); g_pm_metrics_running = false; end_time = clock_systimer(); - for (index = 0; (index < CONFIG_PM_NDOMAINS) && pm_domain_map[index]; index++) { + for (index = 0; (index < CONFIG_PM_NDOMAINS) && pm_domain_map[index].name; index++) { if (g_pmglobals.suspend_count[index]) { g_pm_metrics->domain_metrics.suspend_ticks[index] += end_time - g_pm_metrics->domain_metrics.stime[index]; } diff --git a/os/pm/pm_procfs.c b/os/pm/pm_procfs.c index 84f7b9b29c..e329488a40 100644 --- a/os/pm/pm_procfs.c +++ b/os/pm/pm_procfs.c @@ -180,7 +180,7 @@ const struct procfs_operations power_procfsoperations = { static void power_read_domain_info(int domain_id, void (*readprint)(const char *, ...)) { readprint("%-15s : %d\n", "Domain ID", domain_id); - readprint("%-15s : %s\n", "Domain Name", pm_domain_map[domain_id]); + readprint("%-15s : %s\n", "Domain Name", pm_domain_map[domain_id].name); readprint("%-15s : %d\n", "Suspend Count", g_pmglobals.suspend_count[domain_id]); } @@ -190,14 +190,14 @@ static void power_read_domains(void (*readprint)(const char *, ...)) readprint(" DOMAIN ID | DOMAIN NAME | SUSPEND COUNTS \n"); readprint("-----------|-----------------------------------|----------------\n"); for (domain_id = 0; domain_id < g_pmglobals.ndomains; domain_id++) { - readprint(" %9d | %33s | %14d \n", domain_id, pm_domain_map[domain_id], g_pmglobals.suspend_count[domain_id]); + readprint(" %9d | %33s | %14d \n", domain_id, pm_domain_map[domain_id].name, g_pmglobals.suspend_count[domain_id]); } } static void power_read_state(void (*readprint)(const char *, ...)) { enum pm_state_e pm_state; - for (pm_state = PM_NORMAL; pm_state < PM_COUNT; pm_state++) { + for (pm_state = PM_FOREGROUND; pm_state < PM_COUNT; pm_state++) { readprint("%s %s\n", (pm_state == g_pmglobals.state) ? "*" : " ", pm_state_name[pm_state]); } } @@ -252,7 +252,7 @@ static int power_find_dirref(FAR const char *relpath, FAR struct power_dir_s *di } /* Iterate over each domain_name till you find match */ for (domain_id = 0; domain_id < g_pmglobals.ndomains; domain_id++) { - if (checkStart(pm_domain_map[domain_id], true) == OK) { + if (checkStart(pm_domain_map[domain_id].name, true) == OK) { dir->domain_id = domain_id; if (str[0] == '\0') { dir->base.level = POWER_LEVEL_3; @@ -568,7 +568,7 @@ static int power_readdir(struct fs_dirent_s *dir) snprintf(dir->fd_dir.d_name, sizeof(dir->fd_dir.d_name), POWER_INFO); } else { dir->fd_dir.d_type = DTYPE_DIRECTORY; - snprintf(dir->fd_dir.d_name, sizeof(dir->fd_dir.d_name), pm_domain_map[index]); + snprintf(dir->fd_dir.d_name, sizeof(dir->fd_dir.d_name), pm_domain_map[index].name); } powerdir->base.index++; break; diff --git a/os/pm/pm_register.c b/os/pm/pm_register.c deleted file mode 100644 index 32d40a7c63..0000000000 --- a/os/pm/pm_register.c +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** - * - * Copyright 2016 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * pm/pm_register.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include -#include - -#include "pm.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_register - * - * Description: - * This function is called by a device driver in order to register to - * receive power management event callbacks. - * - * Input parameters: - * callbacks - An instance of struct pm_callback_s providing the driver - * callback functions. - * - * Returned value: - * Zero (OK) on success; otherwise a negated errno value is returned. - * - ****************************************************************************/ - -int pm_register(FAR struct pm_callback_s *callbacks) -{ - int ret; - - DEBUGASSERT(callbacks); - - /* Add the new entry to the end of the list of registered callbacks */ - - ret = pm_lock(); - if (ret == OK) { - dq_addlast(&callbacks->entry, &g_pmglobals.registry); - pm_unlock(); - } - - return ret; -} - -#endif /* CONFIG_PM */ diff --git a/os/pm/pm_suspend.c b/os/pm/pm_suspend.c index aa70a79f67..35528f8674 100644 --- a/os/pm/pm_suspend.c +++ b/os/pm/pm_suspend.c @@ -114,6 +114,9 @@ int pm_suspend(int domain_id) pm_metrics_update_suspend(domain_id); #endif g_pmglobals.suspend_count[domain_id]++; + if (pm_domain_map[domain_id].state < g_pmglobals.state) { + pm_changestate(pm_domain_map[domain_id].state); + } errout: leave_critical_section(flags); return ret; diff --git a/os/pm/pm_timedsuspend.c b/os/pm/pm_timedsuspend.c index 769ebb1d05..c9e2f4b5a7 100644 --- a/os/pm/pm_timedsuspend.c +++ b/os/pm/pm_timedsuspend.c @@ -82,7 +82,7 @@ static void timer_timeout(int argc, int domain_id) DEBUGASSERT(domain_timer_map[domain_id] != NULL); /* PM transition will be resume here */ if (pm_resume(domain_id) != OK) { - pmlldbg("Unable to resume domain: %s\n", pm_domain_map[domain_id]); + pmlldbg("Unable to resume domain: %s\n", pm_domain_map[domain_id].name); } (void)wd_delete(domain_timer_map[domain_id]); domain_timer_map[domain_id] = NULL; @@ -114,7 +114,7 @@ int pm_timedsuspend(int domain_id, unsigned int milliseconds) int tick_remain; int ret = ERROR; int delay = MSEC2TICK(milliseconds); - if ((domain_id < 0) || (domain_id >= CONFIG_PM_NDOMAINS) || (pm_domain_map[domain_id] == NULL)) { + if ((domain_id < 0) || (domain_id >= CONFIG_PM_NDOMAINS) || (pm_domain_map[domain_id].name == NULL)) { set_errno(EINVAL); pmdbg("Invalid domain_id: %d\n", domain_id); return ret; @@ -139,7 +139,7 @@ int pm_timedsuspend(int domain_id, unsigned int milliseconds) } /* Unable to suspend domain, so delete the timer */ if (pm_suspend(domain_id) != OK) { - pmdbg("Unable to suspend domain: %s\n", pm_domain_map[domain_id]); + pmdbg("Unable to suspend domain: %s\n", pm_domain_map[domain_id].name); (void)wd_delete(wdog); goto exit; } @@ -148,7 +148,7 @@ int pm_timedsuspend(int domain_id, unsigned int milliseconds) /* New delay is less than running timer ticks left, no need to do anyting */ tick_remain = wd_gettime(wdog); if (delay <= tick_remain) { - pmvdbg("Domain: %s is already suspended for %d milliseconds\n", pm_domain_map[domain_id], TICK2MSEC(tick_remain)); + pmvdbg("Domain: %s is already suspended for %d milliseconds\n", pm_domain_map[domain_id].name, TICK2MSEC(tick_remain)); ret = OK; goto exit; } @@ -159,7 +159,7 @@ int pm_timedsuspend(int domain_id, unsigned int milliseconds) timer_timeout(0, domain_id); goto exit; } - pmvdbg("Domain: %s is suspended for %d milliseconds\n", pm_domain_map[domain_id], milliseconds); + pmvdbg("Domain: %s is suspended for %d milliseconds\n", pm_domain_map[domain_id].name, milliseconds); ret = OK; exit: leave_critical_section(flags); diff --git a/os/pm/pm_unregister.c b/os/pm/pm_unregister.c deleted file mode 100644 index cf176cd4a5..0000000000 --- a/os/pm/pm_unregister.c +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** - * - * Copyright 2018 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * pm/pm_unregister.c - * - * Copyright (C) 2018 Gregory Nutt. All rights reserved. - * Author: Juha Niskanen - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include -#include - -#include "pm.h" - -#ifdef CONFIG_PM - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pm_unregister - * - * Description: - * This function is called by a device driver in order to unregister - * previously registered power management event callbacks. - * - * Input parameters: - * callbacks - An instance of struct pm_callback_s providing the driver - * callback functions. - * - * Returned value: - * Zero (OK) on success; otherwise a negated errno value is returned. - * - ****************************************************************************/ - -int pm_unregister(FAR struct pm_callback_s *callbacks) -{ - int ret; - - DEBUGASSERT(callbacks); - - /* Remove entry from the list of registered callbacks. */ - - ret = pm_lock(); - if (ret == OK) { - dq_rem(&callbacks->entry, &g_pmglobals.registry); - pm_unlock(); - } - - return ret; -} - -#endif /* CONFIG_PM */ diff --git a/os/pm/pm_wakehandler.c b/os/pm/pm_wakehandler.c index 857aa55be3..c2f87b8a43 100644 --- a/os/pm/pm_wakehandler.c +++ b/os/pm/pm_wakehandler.c @@ -78,6 +78,8 @@ void pm_wakehandler(clock_t missing_tick, pm_wakeup_reason_code_t wakeup_src) } #endif /* After wakeup change PM State to STANDBY and reset the time slice */ - pm_changestate(PM_STANDBY); + if (g_pmglobals.state == PM_SLEEP) { + pm_changestate(PM_BACKGROUND); + } leave_critical_section(flags); }