--- /dev/null
+/****************************************************************************
+ * 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 */
+}
+
}
}
+/* Return the status of brown out detection config */
+uint8_t system_brown_out_detection_enabled(void)
+{
+ return lpc_private.brown_out_detection_enabled;
+}
+
+
/***************************************************************************** */
/* Power */
/***************************************************************************** */
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)
{
-/***************************************************************************** */
-/* 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 */
--- /dev/null
+/****************************************************************************
+ * 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 */
/***************************************************************************** */
/* 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 */
/* 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 */
#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))