Update for power management (sleep and power down) support.
authorNathael Pajani <nathael.pajani@ed3l.fr>
Sat, 1 May 2021 19:32:59 +0000 (21:32 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Fri, 10 Feb 2023 18:02:59 +0000 (19:02 +0100)
core/pmu.c [new file with mode: 0644]
core/system.c
include/core/lpc_regs.h
include/core/pmu.h [new file with mode: 0644]
include/core/system.h

diff --git a/core/pmu.c b/core/pmu.c
new file mode 100644 (file)
index 0000000..1a57cfe
--- /dev/null
@@ -0,0 +1,108 @@
+/****************************************************************************
+ *   core/pmu.c
+ *
+ * Sleep, deep sleep, power-down and deep power-down control.
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#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 */
+}
+
index c0a2dbf..73cc6c9 100644 (file)
@@ -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)
 {
index 5861049..0616b9c 100644 (file)
 
 
 
-/***************************************************************************** */
-/*                     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 (file)
index 0000000..19232a8
--- /dev/null
@@ -0,0 +1,82 @@
+/****************************************************************************
+ *   core/pmu.h
+ *
+ * Cortex-M0 Core Registers definitions
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+#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 */
index e91ef27..de474b5 100644 (file)
@@ -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))