diff --git a/cpu/samd21/lpm_arch.c b/cpu/samd21/lpm_arch.c index fd6dbe4d4875..f249eabc02d0 100644 --- a/cpu/samd21/lpm_arch.c +++ b/cpu/samd21/lpm_arch.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2015 Saurabh Singh * * 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 @@ -14,40 +15,112 @@ * @brief Implementation of the kernels power management interface * * @author Thomas Eichinger + * @author Saurabh Singh * * @} */ - +#include "cpu.h" #include "arch/lpm_arch.h" +enum system_sleepmode { + /** + * Idle 0 mode. + * Potential Wake Up sources: Synchronous(APB, AHB), asynchronous. + */ + SYSTEM_SLEEPMODE_IDLE_0, + /** + * Idle 1 mode. + * Potential Wake Up sources: Synchronous (APB), asynchronous + */ + SYSTEM_SLEEPMODE_IDLE_1, + /** + * Idle 2 mode. + * Potential Wake Up sources: Asynchronous + */ + SYSTEM_SLEEPMODE_IDLE_2, + /** + * Standby mode. + * Potential Wake Up sources: Asynchronous + */ + SYSTEM_SLEEPMODE_STANDBY, +}; + +static enum lpm_mode current_mode; + +static void start_lpm(void); + + 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; -enum lpm_mode lpm_arch_get(void) -{ - // TODO - return 0; + switch (target) { + case LPM_ON: /* Run mode */ + current_mode = LPM_ON; + break; + case LPM_IDLE: /* Sleep mode Idle 0 */ + current_mode = LPM_IDLE; + /* Idle Mode 0 */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = SYSTEM_SLEEPMODE_IDLE_0; + start_lpm(); + break; + case LPM_SLEEP: /* Sleep mode Idle 1 */ + current_mode = LPM_SLEEP; + /* Idle Mode 1 */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = SYSTEM_SLEEPMODE_IDLE_1; + start_lpm(); + break; + case LPM_POWERDOWN: /* Sleep mode Idle 2 */ + /* Idle Mode 2 */ + current_mode = LPM_POWERDOWN; + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = SYSTEM_SLEEPMODE_IDLE_2; + start_lpm(); + break; + case LPM_OFF: /* Standby Mode - Potential Wake Up sources: Asynchronous */ + current_mode = LPM_OFF; + /* Standby Mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + start_lpm(); + break; + default: + break; + } + + return last_mode; } -void lpm_arch_awake(void) +static void start_lpm(void) { - // TODO + /* Executes a device DSB (Data Synchronization Barrier) */ + __DSB(); + /* Enter standby mode */ + __WFI(); } -void lpm_arch_begin_awake(void) +enum lpm_mode lpm_arch_get(void) { - // TODO + return current_mode; } -void lpm_arch_end_awake(void) +void lpm_arch_awake(void) { - // TODO + if (current_mode == LPM_SLEEP) { + /* Re-init */ + cpu_init(); + } + current_mode = LPM_ON; } + +/** Not needed */ +void lpm_arch_begin_awake(void){ } + +/** Not needed */ +void lpm_arch_end_awake(void){ }