/* * Called from up_idle(). Checks the power state suggested by the power * management algorithm, then tries to change the power state of all * power-managed drivers. If that succeeds - the bridge-specific power * management code is executed. */ void up_idlepm(void) { int ret, newstate; irqstate_t flags; newstate = pm_checkstate(); if (newstate != tsb_pm_curr_state) { flags = irqsave(); ret = pm_changestate(newstate); if (ret < 0) { /* Restore previous state on failure. */ (void)pm_changestate(tsb_pm_curr_state); } else { tsb_pm_curr_state = newstate; /* This is where bridge-specific pm should be done. */ switch (newstate) { case PM_NORMAL: break; case PM_IDLE: break; case PM_STANDBY: break; case PM_SLEEP: break; default: break; } } irqrestore(flags); } }
static void up_alarmcb(void) { /* This alarm occurs because there wasn't any EXTI interrupt during the * PM_STANDBY period. So just go to sleep. */ pm_changestate(PM_SLEEP); }
static void up_idlepm(void) { static enum pm_state_e oldstate = PM_NORMAL; enum pm_state_e newstate; irqstate_t flags; int ret; /* Decide, which power saving level can be obtained */ newstate = pm_checkstate(); /* Check for state changes */ if (newstate != oldstate) { flags = irqsave(); /* Perform board-specific, state-dependent logic here */ llvdbg("newstate= %d oldstate=%d\n", newstate, oldstate); /* Then force the global state change */ ret = pm_changestate(newstate); if (ret < 0) { /* The new state change failed, revert to the preceding state */ (void)pm_changestate(oldstate); } else { /* Save the new state */ oldstate = newstate; } /* MCU-specific power management logic */ switch (newstate) { case PM_NORMAL: break; case PM_IDLE: break; case PM_STANDBY: lpc43_pmstandby(true); break; case PM_SLEEP: (void)lpc43_pmsleep(); break; default: break; } irqrestore(flags); } }
static void stm32_idlepm(void) { static enum pm_state_e oldstate = PM_NORMAL; enum pm_state_e newstate; int ret; /* The following is logic that is done after the wake-up from PM_STANDBY * state. It decides whether to go back to the PM_NORMAL or to the deeper * power-saving mode PM_SLEEP: If the alarm expired with no "normal" * wake-up event, then PM_SLEEP is entered. * * Logically, this code belongs at the end of the PM_STANDBY case below, * does not work in the position for some unkown reason. */ if (oldstate == PM_STANDBY) { /* Were we awakened by the alarm? */ #ifdef CONFIG_RTC_ALARM if (g_alarmwakeup) { /* Yes.. Go to SLEEP mode */ newstate = PM_SLEEP; } else #endif { /* Resume normal operation */ newstate = PM_NORMAL; } } else { /* Let the PM system decide, which power saving level can be obtained */ newstate = pm_checkstate(); } /* Check for state changes */ if (newstate != oldstate) { llvdbg("newstate= %d oldstate=%d\n", newstate, oldstate); sched_lock(); /* Force the global state change */ ret = pm_changestate(newstate); if (ret < 0) { /* The new state change failed, revert to the preceding state */ (void)pm_changestate(oldstate); /* No state change... */ goto errout; } /* Then perform board-specific, state-dependent logic here */ switch (newstate) { case PM_NORMAL: { /* If we just awakened from PM_STANDBY mode, then reconfigure * clocking. */ if (oldstate == PM_STANDBY) { /* Re-enable clocking */ stm32_clockenable(); /* The system timer was disabled while in PM_STANDBY or * PM_SLEEP modes. But the RTC has still be running: Reset * the system time the current RTC time. */ #ifdef CONFIG_RTC clock_synchronize(); #endif } } break; case PM_IDLE: { } break; case PM_STANDBY: { /* Set the alarm as an EXTI Line */ #ifdef CONFIG_RTC_ALARM stm32_rtc_alarm(CONFIG_PM_ALARM_SEC, CONFIG_PM_ALARM_NSEC, true); #endif /* Wait 10ms */ up_mdelay(10); /* Enter the STM32 stop mode */ (void)stm32_pmstop(false); /* We have been re-awakened by some even: A button press? * An alarm? Cancel any pending alarm and resume the normal * operation. */ #ifdef CONFIG_RTC_ALARM stm32_exti_cancel(); ret = stm32_rtc_cancelalarm(); if (ret < 0) { lldbg("Warning: Cancel alarm failed\n"); } #endif /* Note: See the additional PM_STANDBY related logic at the * beginning of this function. That logic is executed after * this point. */ } break; case PM_SLEEP: { /* We should not return from standby mode. The only way out * of standby is via the reset path. */ /* Configure the RTC alarm to Auto Reset the system */ #ifdef CONFIG_PM_SLEEP_WAKEUP stm32_rtc_alarm(CONFIG_PM_SLEEP_WAKEUP_SEC, CONFIG_PM_SLEEP_WAKEUP_NSEC, false); #endif /* Wait 10ms */ up_mdelay(10); /* Enter the STM32 standby mode */ (void)stm32_pmstandby(); } break; default: break; } /* Save the new state */ oldstate = newstate; errout: sched_unlock(); } }
static void up_idlepm(void) { #ifdef CONFIG_RTC_ALARM struct timespec alarmtime; #endif static enum pm_state_e oldstate = PM_NORMAL; enum pm_state_e newstate; irqstate_t flags; int ret; /* Decide, which power saving level can be obtained */ newstate = pm_checkstate(); /* Check for state changes */ if (newstate != oldstate) { lldbg("newstate= %d oldstate=%d\n", newstate, oldstate); flags = irqsave(); /* Force the global state change */ ret = pm_changestate(newstate); if (ret < 0) { /* The new state change failed, revert to the preceding state */ (void)pm_changestate(oldstate); /* No state change... */ goto errout; } /* Then perform board-specific, state-dependent logic here */ switch (newstate) { case PM_NORMAL: { } break; case PM_IDLE: { } break; case PM_STANDBY: { #ifdef CONFIG_RTC_ALARM /* Disable RTC Alarm interrupt */ #warning "missing logic" /* Configure the RTC alarm to Auto Wake the system */ #warning "missing logic" /* The tv_nsec value must not exceed 1,000,000,000. That * would be an invalid time. */ #warning "missing logic" /* Set the alarm */ #warning "missing logic" #endif /* Call the STM32 stop mode */ stm32_pmstop(true); /* We have been re-awakened by some even: A button press? * An alarm? Cancel any pending alarm and resume the normal * operation. */ #ifdef CONFIG_RTC_ALARM #warning "missing logic" #endif /* Resume normal operation */ pm_changestate(PM_NORMAL); newstate = PM_NORMAL; } break; case PM_SLEEP: { /* We should not return from standby mode. The only way out * of standby is via the reset path. */ (void)stm32_pmstandby(); } break; default: break; } /* Save the new state */ oldstate = newstate; errout: irqrestore(flags); } }
void up_idle(void) { #ifdef CONFIG_SMP /* In the SMP configuration, only one CPU should do these operations. It * should not matter which, however. */ static volatile spinlock_t lock; /* The one that gets the lock is the one that executes the IDLE operations */ if (up_testset(&lock) != SP_UNLOCKED) { /* We didn't get it... Give other pthreads/CPUs a shot and try again * later. */ pthread_yield(); return; } #endif #ifdef CONFIG_SCHED_TICKLESS /* Driver the simulated interval timer */ up_timer_update(); #else /* If the system is idle, then process "fake" timer interrupts. * Hopefully, something will wake up. */ sched_process_timer(); #endif #if defined(CONFIG_DEV_CONSOLE) && !defined(CONFIG_SIM_UART_DATAPOST) /* Handle UART data availability */ if (g_uart_data_available) { g_uart_data_available = 0; simuart_post(); } #endif #ifdef CONFIG_NET_ETHERNET /* Run the network if enabled */ netdriver_loop(); #endif #ifdef CONFIG_PM /* Fake some power management stuff for testing purposes */ { static enum pm_state_e state = PM_NORMAL; enum pm_state_e newstate; newstate = pm_checkstate(); if (newstate != state) { if (pm_changestate(newstate) == OK) { state = newstate; } } } #endif #if defined(CONFIG_SIM_WALLTIME) || defined(CONFIG_SIM_X11FB) /* Wait a bit so that the sched_process_timer() is called close to the * correct rate. */ (void)up_hostusleep(1000000 / CLK_TCK); /* Handle X11-related events */ #ifdef CONFIG_SIM_X11FB if (g_x11initialized) { #if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) /* Drive the X11 event loop */ if (g_eventloop) { up_x11events(); } #endif /* Update the display periodically */ g_x11refresh += 1000000 / CLK_TCK; if (g_x11refresh > 500000) { up_x11update(); } } #endif #endif #ifdef CONFIG_SMP /* Release the spinlock */ lock = SP_UNLOCKED; /* Give other pthreads/CPUs a shot */ pthread_yield(); #endif }
void up_idle(void) { /* If the system is idle, then process "fake" timer interrupts. * Hopefully, something will wake up. */ sched_process_timer(); /* Run the network if enabled */ #ifdef CONFIG_NET uipdriver_loop(); #endif /* Fake some power management stuff for testing purposes */ #ifdef CONFIG_PM { static enum pm_state_e state = PM_NORMAL; enum pm_state_e newstate; newstate = pm_checkstate(); if (newstate != state) { if (pm_changestate(newstate) == OK) { state = newstate; } } } #endif /* Wait a bit so that the sched_process_timer() is called close to the * correct rate. */ #if defined(CONFIG_SIM_WALLTIME) || defined(CONFIG_SIM_X11FB) (void)up_hostusleep(1000000 / CLK_TCK); /* Handle X11-related events */ #ifdef CONFIG_SIM_X11FB if (g_x11initialized) { /* Drive the X11 event loop */ #ifdef CONFIG_SIM_TOUCHSCREEN if (g_eventloop) { up_x11events(); } #endif /* Update the display periodically */ g_x11refresh += 1000000 / CLK_TCK; if (g_x11refresh > 500000) { up_x11update(); } } #endif #endif }