From: Nathael Pajani Date: Sat, 1 May 2021 19:32:59 +0000 (+0200) Subject: Update for power management (sleep and power down) support. X-Git-Url: http://git.techno-innov.fr/?a=commitdiff_plain;h=59a86e7657c0265cac6e1c8352038f7b93b2e28a;p=soft%2Flpc82x%2Fcore Update for power management (sleep and power down) support. --- diff --git a/core/pmu.c b/core/pmu.c new file mode 100644 index 0000000..1a57cfe --- /dev/null +++ b/core/pmu.c @@ -0,0 +1,108 @@ +/**************************************************************************** + * core/pmu.c + * + * Sleep, deep sleep, power-down and deep power-down control. + * + * Copyright 2012 Nathael Pajani + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + *************************************************************************** */ + + +#include "lib/stdint.h" + +#include "core/lpc_regs.h" +#include "core/lpc_core.h" +#include "core/system.h" +#include "core/pmu.h" +#include "lib/errno.h" + + + + +/* PMU unit */ +int save_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset) +{ + struct lpc_pm_unit* pmu = LPC_PMU; + int i = 0; + + if ((offset + nb) > 4) { + return -EINVAL; + } + for (i = 0; i < nb; i++) { + pmu->gp_data[offset + i] = values[i]; + } + return 0; +} + +int read_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset) +{ + struct lpc_pm_unit* pmu = LPC_PMU; + int i = 0; + + if ((offset + nb) > 4) { + return -EINVAL; + } + for (i = 0; i < nb; i++) { + values[i] = pmu->gp_data[offset + i]; + } + return 0; +} + + +/* Enter simplest sleep state + * - Return to thread mode after interrupt or event + * - do not enter "deep" sleep or power-down mode + * - if "wake_sources_is_all_intrs" is set to 1, also wake up from unconfigured + * interrupt sources + * This function returns after the next interrupt or event. + */ +void enter_sleep(int wake_sources_is_all_intrs) +{ + struct syst_ctrl_block_regs* scb = LPC_SCB; + + /* Configure SCR for sleep mode */ + if (wake_sources_is_all_intrs == 1) { + scb->scr = SCB_SCR_SEVONPEND; /* Wakeup from any interrupt, even those not enabled */ + } else { + scb->scr = 0; + } + wfe(); +} + + +/* Enter deep sleep. + * NOTE : entering deep sleep implies a lot of side effects. I'll try to list them all here + * so this can be done right. + * + * Note : see remark about RTC and deep sleep in section 5.3.3 of UM10441 + */ +void enter_deep_sleep(void) +{ + struct lpc_sys_config* sys_config = LPC_SYS_CONFIG; + + /* Ask for the same clock status when waking up */ + sys_config->powerdown_wake_cfg = sys_config->powerdown_run_cfg; + /* Set deep_sleep config */ + if (system_brown_out_detection_enabled()) { + sys_config->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_ON; + } else { + sys_config->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_OFF; + } + /* Enter deep sleep */ + /* FIXME */ +} + diff --git a/core/system.c b/core/system.c index c0a2dbf..73cc6c9 100644 --- a/core/system.c +++ b/core/system.c @@ -73,6 +73,13 @@ void system_brown_out_detection_config(uint32_t level) } } +/* Return the status of brown out detection config */ +uint8_t system_brown_out_detection_enabled(void) +{ + return lpc_private.brown_out_detection_enabled; +} + + /***************************************************************************** */ /* Power */ /***************************************************************************** */ @@ -86,28 +93,6 @@ void system_set_default_power_state(void) sys_config->sys_AHB_clk_ctrl = LPC_SYS_AHB_CLK_CTRL_MEM_ALL; } -/* Enter deep sleep. - * NOTE : entering deep sleep implies a lot of side effects. I'll try to list them all here - * so this can be done right. - * - * Note : see remark about RTC and deep sleep in section 5.3.3 of UM10441 - */ -void enter_deep_sleep(void) -{ - struct lpc_sys_config* sys_config = LPC_SYS_CONFIG; - - /* Ask for the same clock status when waking up */ - sys_config->powerdown_wake_cfg = sys_config->powerdown_run_cfg; - /* Set deep_sleep config */ - if (lpc_private.brown_out_detection_enabled) { - sys_config->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_ON; - } else { - sys_config->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_OFF; - } - /* Enter deep sleep */ - /* FIXME */ -} - /* Power on or off a subsystem */ void subsystem_power(uint32_t power_bit, uint32_t on_off) { diff --git a/include/core/lpc_regs.h b/include/core/lpc_regs.h index 5861049..0616b9c 100644 --- a/include/core/lpc_regs.h +++ b/include/core/lpc_regs.h @@ -74,26 +74,6 @@ -/***************************************************************************** */ -/* Power Management Unit */ -/***************************************************************************** */ -/* Power Management Unit (PMU) */ -struct lpc_pm_unit -{ - volatile uint32_t power_ctrl; /* 0x000 : Power control Register (R/W) */ - volatile uint32_t gp_data[4]; /* 0x004 to 0x010 : General purpose Register 0 to 3 (R/W) */ - volatile uint32_t system_config; /* 0x014 : System configuration register (R/W) */ - /* (RTC clock control and hysteresis of the WAKEUP pin) */ -}; -#define LPC_PMU ((struct lpc_pm_unit *) LPC_PMU_BASE) - -/* System config register */ -#define LPC_WAKEUP_PIN_HYST_MASK (0x01 << 10) -#define LPC_RTC_CLK_SRC_SHIFT 11 -#define LPC_RTC_CLK_SRC_MASK (0x0F << LPC_RTC_CLK_SRC_SHIFT) -/* See RTC section above for RTC Clock source selection bits */ - - /***************************************************************************** */ /* Synchronous Serial Communication */ diff --git a/include/core/pmu.h b/include/core/pmu.h new file mode 100644 index 0000000..19232a8 --- /dev/null +++ b/include/core/pmu.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * core/pmu.h + * + * Cortex-M0 Core Registers definitions + * + * Copyright 2012 Nathael Pajani + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + *************************************************************************** */ +#ifndef LPC_PMU_H +#define LPC_PMU_H + +#include "lib/stdint.h" +#include "lib/stddef.h" + + + + +/***************************************************************************** */ +/* Power Management Unit */ +/***************************************************************************** */ + + +/* Enter simplest sleep state + * - Return to thread mode after interrupt or event + * - do not enter "deep" sleep or power-down mode + * - if "wake_sources_is_all_intrs" is set to 1, also wake up from unconfigured + * interrupt sources + * This function returns after the next interrupt or event. + */ +void enter_sleep(int wake_sources_is_all_intrs); + + +/* Enter deep sleep. + * NOTE : entering deep sleep implies a lot of side effects. I'll try to list them all here + * so this can be done right. + * + * Note : see remark about RTC and deep sleep in section 5.3.3 of UM10441 + */ +void enter_deep_sleep(void); + + +/* Read from or write to the general purpose retain registers + * Values in these registers are kept over resets, whatever the reset source, so long as + * the part remains powered. (Even accross watchdog resets or flashing the device !) + */ +int save_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset); +int read_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset); + + +/* Power Management Unit (PMU) */ +struct lpc_pm_unit +{ + volatile uint32_t power_ctrl; /* 0x000 : Power control Register (R/W) */ + volatile uint32_t gp_data[4]; /* 0x004 to 0x010 : General purpose Register 0 to 3 (R/W) */ + volatile uint32_t deep_power_down_ctrl; /* 0x014 : Deep power down control register (R/W) */ + /* (WAKEUP pin control) */ +}; +#define LPC_PMU ((struct lpc_pm_unit *) LPC_PMU_BASE) + +/* System config register */ +#define LPC_WAKEUP_PIN_HYST_MASK (0x01 << 10) +#define LPC_RTC_CLK_SRC_SHIFT 11 +#define LPC_RTC_CLK_SRC_MASK (0x0F << LPC_RTC_CLK_SRC_SHIFT) +/* See RTC section above for RTC Clock source selection bits */ + + + +#endif /* LPC_PMU_H */ diff --git a/include/core/system.h b/include/core/system.h index e91ef27..de474b5 100644 --- a/include/core/system.h +++ b/include/core/system.h @@ -42,8 +42,6 @@ void system_set_default_power_state(void); /***************************************************************************** */ /* Power */ /***************************************************************************** */ -void enter_deep_sleep(void); - /* Power on or off a subsystem */ void subsystem_power(uint32_t power_bit, uint32_t on_off); /* Check whether a subsystem is powered or not */ @@ -56,6 +54,8 @@ void subsystem_reset_release(uint32_t reset_bit); /* Configure the brown-out detection. */ void system_brown_out_detection_config(uint32_t level); +/* Return the status of brown out detection config */ +uint8_t system_brown_out_detection_enabled(void); /***************************************************************************** */ /* System Clock */ @@ -251,8 +251,9 @@ struct lpc_sys_config #define LPC_CLKOUT_SRC_WATCHDOG_OSC 0x02 #define LPC_CLKOUT_SRC_MAIN_CLK 0x03 -#define LPC_WDT_DIVSEL(x) (((x) / 2) - 1) +#define LPC_WDT_CLK_DIVIDER(x) (((x) >> 1) - 1) /* X/2 - 1 */ #define LPC_WDT_FREQSEL_600KHz (0x01 << 5) +#define LPC_WDT_FREQSEL_4MHz (0x0C << 5) /* Pin interrupt wakeup enable */ #define LPC_PINT_WAKEUP_EN(x) (1 << (x))