Adding self-wakeup timer support
authorNathael Pajani <nathael.pajani@ed3l.fr>
Sun, 30 Jan 2022 03:25:51 +0000 (04:25 +0100)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Fri, 10 Feb 2023 18:02:59 +0000 (19:02 +0100)
core/system.c
include/core/pmu.h
include/core/system.h

index 2f0ff33..09ec18f 100644 (file)
@@ -32,6 +32,7 @@
 #include "core/lpc_regs.h"
 #include "core/lpc_core.h"
 #include "core/system.h"
+#include "core/pmu.h"
 
 
 /* Private defines */
@@ -44,11 +45,15 @@ struct lpc_desc_private {
        uint32_t main_clock;
        uint8_t brown_out_detection_enabled;
        uint8_t need_IRC;
+       uint8_t need_watchdog;
+       uint8_t need_self_wakeup_timer;
 };
 static struct lpc_desc_private lpc_private = {
        .main_clock = LPC_IRC_OSC_CLK,
        .brown_out_detection_enabled = 0,
        .need_IRC = 1,
+       .need_watchdog = 0,
+       .need_self_wakeup_timer = 0,
 };
 
 /***************************************************************************** */
@@ -79,6 +84,30 @@ uint8_t system_brown_out_detection_enabled(void)
        return lpc_private.brown_out_detection_enabled;
 }
 
+/* Store the watchdog requirement info */
+void system_need_watchdog(uint8_t val)
+{
+       lpc_private.need_watchdog = val;
+}
+
+/* Return the status of watchdog config */
+uint8_t system_watchdog_enabled(void)
+{
+       return lpc_private.need_watchdog;
+}
+
+/* Store the Self Wakeup timer requirement info */
+void system_need_self_wakeup_timer(uint8_t val)
+{
+       lpc_private.need_self_wakeup_timer = val;
+}
+
+/* Return the status of Self Wakeup timer config */
+uint8_t system_self_wakeup_timer_enabled(void)
+{
+       return lpc_private.need_self_wakeup_timer;
+}
+
 
 /***************************************************************************** */
 /*                       Power                                                 */
@@ -130,6 +159,22 @@ void subsystem_reset(uint32_t reset_bit)
        subsystem_reset_release(reset_bit);
 }
 
+
+/***************************************************************************** */
+/*                      Start logic                                            */
+/***************************************************************************** */
+void enable_pin_intr_wake_source(uint32_t src)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       sys_config->start_log_ctrl[0].wakeup_en |= src;
+}
+void enable_intr_wake_source(uint32_t src)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       sys_config->start_log_ctrl[1].wakeup_en |= src;
+}
+
+
 /***************************************************************************** */
 /*                      System Clock                                           */
 /***************************************************************************** */
@@ -294,3 +339,88 @@ static inline void def_usleep(uint32_t us)
 void msleep(uint32_t ms) __attribute__ ((weak, alias ("def_msleep")));
 void usleep(uint32_t us) __attribute__ ((weak, alias ("def_usleep")));
 
+
+/***************************************************************************** */
+/*                    Self Wake-up timer functions                             */
+/***************************************************************************** */
+/* Turn ON the Self Wake-Up timer.
+ * - clk_src is one of LPC_WKT_USE_IRC, LPC_WKT_USE_10KHZ or LPC_WKT_USE_PIN_CLK
+ *   Note that LPC_WKT_USE_IRC cannot be used for waking up from deep sleep or any
+ *   power down mode.
+ */
+
+static void (*wkt_callback)(void) = NULL;
+void WKT_Handler(void)
+{
+    self_wakeup_timer_clear();
+       if (wkt_callback != NULL) {
+               wkt_callback();
+       }
+}
+
+void self_wakeup_timer_on(uint8_t clk_src, void (*callback)(void))
+{
+       struct lpc_pm_unit* pmu = LPC_PMU;
+       struct lpc_swt_wkt* swt = LPC_SWT_WKT;
+
+       wkt_callback = callback;
+       system_need_self_wakeup_timer(1);
+
+       subsystem_power(LPC_SYS_AHB_CLK_CTRL_WKT, 1);
+
+       subsystem_reset(LPC_WKT_RESET_N);
+
+       switch (clk_src) {
+               case LPC_WKT_USE_10KHZ:
+                       pmu->deep_power_down_ctrl = LPC_WAKEUP_PIN_DISABLE | LPC_WAKEUP_CLK_10KHZ;
+                       swt->control = LPC_WKT_CLK_SEL_10KHZ;
+                       break;
+               case LPC_WKT_USE_IRC:
+                       /* TODO */
+                       break;
+               case LPC_WKT_USE_PIN_CLK:
+                       /* TODO */
+                       break;
+               default:
+                       break;
+       }
+
+       /* Enable the wake-up timer interrupt as a wakeup source */
+       enable_intr_wake_source(LPC_WKT_INT_WAKEUP_EN);
+
+       /* Interrupt enable */
+       NVIC_EnableIRQ(WKT_IRQ);
+}
+
+/* Turn OFF the Self Wake-Up timer. */
+void self_wakeup_timer_off(void)
+{
+       NVIC_DisableIRQ(WKT_IRQ);
+       self_wakeup_timer_clear();
+       subsystem_reset_hold(LPC_WKT_RESET_N);
+       subsystem_power(LPC_SYS_AHB_CLK_CTRL_WKT, 0);
+}
+
+/* Clear both the alarm flag and the counter value, effectively stopping
+ *  the Self Wake-Up timer
+ */
+void self_wakeup_timer_clear(void)
+{
+       struct lpc_swt_wkt* swt = LPC_SWT_WKT;
+       swt->control |= LPC_WKT_ALARM_FLAG | LPC_WKT_CLEAR_COUNTER;
+}
+
+
+/* Start the Self Wake-Up timer.
+ * - timer_val is the value loaded in the decrementer. Delay depends on the clock
+ *   source selected by "clk_src" parameter given to self_wakeup_timer_on().
+ */
+void self_wakeup_timer_start(uint32_t timer_val)
+{
+       struct lpc_swt_wkt* swt = LPC_SWT_WKT;
+
+       /* Set value */
+       swt->count = timer_val;
+}
+
+
index 19232a8..d27f8fe 100644 (file)
@@ -64,19 +64,29 @@ 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) */
+       volatile uint32_t power_ctrl;  /* 0x000 : PCON - Power control Register (R/W) */
+       volatile uint32_t gp_data[4];  /* 0x004 to 0x010 : GPREG - General purpose Register 0 to 3 (R/W) */
+       volatile uint32_t deep_power_down_ctrl; /* 0x014 : DPDCTRL - 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 */
+/* Power control register fields (PCON) */
+#define LPC_PM_DEFAULT     0x00
+#define LPC_PM_DEEP_SLEEP  0x01
+#define LPC_PM_POWER_DOWN  0x02
+#define LPC_PM_DEEP_POWER_DOWN  0x03
 
+#define LPC_PM_NO_DPD  (0x01 << 3)
+
+
+/* Deep power down control register fields */
+#define LPC_WAKEUP_PIN_HYST     (0x01 << 0)
+#define LPC_WAKEUP_PIN_DISABLE  (0x01 << 1)
+#define LPC_WAKEUP_CLK_10KHZ    (0x01 << 2)
+#define LPC_WAKEUP_LPOSC_IN_DPD (0x01 << 3)
+#define LPC_WAKEUP_CLK_PIN_HYST (0x01 << 4)
+#define LPC_WAKEUP_CLK_PIN_EN   (0x01 << 5)
 
 
 #endif  /* LPC_PMU_H */
index cba038a..aeb913c 100644 (file)
@@ -57,6 +57,19 @@ 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);
 
+/* Store the watchdog requirement info */
+void system_need_watchdog(uint8_t val);
+
+/* Return the status of watchdog config */
+uint8_t system_watchdog_enabled(void);
+
+/* Store the Self Wakeup timer requirement info */
+void system_need_self_wakeup_timer(uint8_t val);
+
+/* Return the status of Self Wakeup timer config */
+uint8_t system_self_wakeup_timer_enabled(void);
+
+
 /***************************************************************************** */
 /*                      System Clock                                           */
 /***************************************************************************** */
@@ -257,6 +270,77 @@ struct lpc_sys_config
 
 /* Pin interrupt wakeup enable */
 #define LPC_PINT_WAKEUP_EN(x)   (1 << (x))
+/* Interrupt sources wakeup enable */
+#define LPC_SPI0_INT_WAKEUP_EN   (1 << 0)
+#define LPC_SPI1_INT_WAKEUP_EN   (1 << 1)
+#define LPC_USART0_INT_WAKEUP_EN (1 << 3)
+#define LPC_USART1_INT_WAKEUP_EN (1 << 4)
+#define LPC_USART2_INT_WAKEUP_EN (1 << 5)
+#define LPC_I2C1_INT_WAKEUP_EN   (1 << 7)
+#define LPC_I2C0_INT_WAKEUP_EN   (1 << 8)
+#define LPC_WWDT_INT_WAKEUP_EN   (1 << 12)
+#define LPC_BOD_INT_WAKEUP_EN    (1 << 13)
+#define LPC_WKT_INT_WAKEUP_EN    (1 << 15)
+#define LPC_I2C2_INT_WAKEUP_EN   (1 << 21)
+#define LPC_I2C3_INT_WAKEUP_EN  ((1 << 31) || (1 << 22))
+
+void enable_intr_wake_source(uint32_t src);
+void enable_pin_intr_wake_source(uint32_t src);
+
+
+#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 */
+
+
+
+/***************************************************************************** */
+/*                  Self WakeUp Timer                                          */
+/***************************************************************************** */
+
+/* Self Wake-Up Timer (SWT or WKT) */
+struct lpc_swt_wkt
+{
+       volatile uint32_t control;  /* 0x000 : CTRL - Control Register (R/W) */
+       volatile uint32_t unused[2];
+       volatile uint32_t count;    /* 0x00C : COUNT - Count register (-/W) */
+};
+#define LPC_SWT_WKT ((struct lpc_swt_wkt *) LPC_SWT_BASE)
+
+/* Wake-Up timer */
+#define LPC_WKT_CLK_SEL_IRC    (0x00 << 0)
+#define LPC_WKT_CLK_SEL_10KHZ  (0x01 << 0)
+#define LPC_WKT_ALARM_FLAG     (0x01 << 1)
+#define LPC_WKT_CLEAR_COUNTER  (0x01 << 2)
+#define LPC_WKT_EXT_CLK_SEL    (0x01 << 3)
+
+/* Helpers, unrelated to registers */
+#define LPC_WKT_USE_IRC     1
+#define LPC_WKT_USE_10KHZ   2
+#define LPC_WKT_USE_PIN_CLK 3
+
+/* Turn ON the Self Wake-Up timer.
+ * - clk_src is one of LPC_WKT_USE_IRC, LPC_WKT_USE_10KHZ or LPC_WKT_USE_PIN_CLK
+ *   Note that LPC_WKT_USE_IRC cannot be used for waking up from deep sleep or any
+ *   power down mode.
+ */
+void self_wakeup_timer_on(uint8_t clk_src, void (*callback)(void));
+
+/* Turn OFF the Self Wake-Up timer. */
+void self_wakeup_timer_off(void);
+
+/* Clear both the alarm flag and the counter value, effectively stopping
+ *  the Self Wake-Up timer
+ */
+void self_wakeup_timer_clear(void);
+
+/* Start the Self Wake-Up timer.
+ * - timer_val is the value loaded in the decrementer. Delay depends on the clock
+ *   source selected by "clk_src" parameter given to self_wakeup_timer_on().
+ */
+void self_wakeup_timer_start(uint32_t timer_val);
+
+
 
 /***************************************************************************** */
 /*                  Flash Control                                              */