diff --git a/cpu/stm32f4/lpm_arch.c b/cpu/stm32f4/lpm_arch.c index c375d44d6..0cb8f20f7 100644 --- a/cpu/stm32f4/lpm_arch.c +++ b/cpu/stm32f4/lpm_arch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2015 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -13,41 +13,86 @@ * @file * @brief Implementation of the kernels power management interface * - * @author Hauke Petersen + * @author Fabian Nack * * @} */ +#include "cpu.h" #include "arch/lpm_arch.h" +static enum lpm_mode current_mode = LPM_UNKNOWN; + void lpm_arch_init(void) { - /* TODO */ + current_mode = LPM_ON; } enum lpm_mode lpm_arch_set(enum lpm_mode target) { - /* TODO */ - return 0; + enum lpm_mode last_mode = current_mode; + + switch (target) { + case LPM_ON: /* STM Run mode */ + current_mode = LPM_ON; + break; + case LPM_IDLE: /* STM Sleep mode */ + current_mode = LPM_IDLE; + /* Reset SLEEPDEEP bit of system control block */ + SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk); + /* Enter sleep mode */ + __WFI(); + break; + case LPM_SLEEP: /* STM Stop mode */ + current_mode = LPM_SLEEP; + /* Clear PDDS and LPDS bits to enter stop mode on */ + /* deepsleep with voltage regulator on */ + PWR->CR &= ~(PWR_CR_PDDS | PWR_CR_LPDS); + /* Set SLEEPDEEP bit of system control block */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + /* Enter stop mode */ + __WFI(); + break; + case LPM_POWERDOWN: /* STM Standby mode */ + /* Fall-through */ + case LPM_OFF: /* STM Standby mode */ + current_mode = LPM_POWERDOWN; + /* Set PDDS to enter standby mode on deepsleep and clear flags */ + PWR->CR |= (PWR_CR_PDDS | PWR_CR_CWUF | PWR_CR_CSBF); + /* Enable WKUP pin to use for wakeup from standby mode */ + PWR->CSR |= PWR_CSR_EWUP; + /* Set SLEEPDEEP bit of system control block */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; +#if defined ( __CC_ARM ) + /* Ensure that store operations are completed */ + __force_stores(); +#endif + /* Enter standby mode */ + __WFI(); + break; + default: + break; + } + + return last_mode; } enum lpm_mode lpm_arch_get(void) { - /* TODO */ - return 0; + return current_mode; } void lpm_arch_awake(void) { - /* TODO */ + if (current_mode == LPM_SLEEP) { + /* After stop mode, the clock system needs to be reconfigured */ + cpu_init(); + } + current_mode = LPM_ON; } -void lpm_arch_begin_awake(void) -{ - /* TODO */ -} +/** Not provided */ +inline void lpm_arch_begin_awake(void) { } -void lpm_arch_end_awake(void) -{ - /* TODO */ -} +/** Not provided */ +inline void lpm_arch_end_awake(void) { }