[rtems commit] bsp/atsam: Add power support
Sebastian Huber
sebh at rtems.org
Mon Aug 8 11:56:53 UTC 2016
Module: rtems
Branch: master
Commit: 5d0f0de4aa3791b32b4b48e5f97a1e68f07641e3
Changeset: http://git.rtems.org/rtems/commit/?id=5d0f0de4aa3791b32b4b48e5f97a1e68f07641e3
Author: Alexander Krutwig <alexander.krutwig at embedded-brains.de>
Date: Thu Jul 28 13:33:50 2016 +0200
bsp/atsam: Add power support
---
c/src/lib/libbsp/arm/atsam/Makefile.am | 4 +
c/src/lib/libbsp/arm/atsam/include/bsp.h | 2 +
c/src/lib/libbsp/arm/atsam/include/power.h | 245 +++++++++++++++++++++++
c/src/lib/libbsp/arm/atsam/preinstall.am | 4 +
c/src/lib/libbsp/arm/atsam/startup/power-clock.c | 44 ++++
c/src/lib/libbsp/arm/atsam/startup/power-rtc.c | 104 ++++++++++
c/src/lib/libbsp/arm/atsam/startup/power.c | 102 ++++++++++
7 files changed, 505 insertions(+)
diff --git a/c/src/lib/libbsp/arm/atsam/Makefile.am b/c/src/lib/libbsp/arm/atsam/Makefile.am
index 68bc075..2cfd227 100644
--- a/c/src/lib/libbsp/arm/atsam/Makefile.am
+++ b/c/src/lib/libbsp/arm/atsam/Makefile.am
@@ -53,6 +53,7 @@ include_bsp_HEADERS += include/irq.h
include_bsp_HEADERS += include/pin-config.h
include_bsp_HEADERS += include/atsam-i2c.h
include_bsp_HEADERS += include/i2c.h
+include_bsp_HEADERS += include/power.h
include_libchipdir = $(includedir)/libchip
@@ -394,6 +395,9 @@ libbsp_a_SOURCES += ../shared/armv7m/startup/bspreset.c
libbsp_a_SOURCES += startup/bspstart.c
libbsp_a_SOURCES += startup/bspstarthooks.c
libbsp_a_SOURCES += startup/pin-config.c
+libbsp_a_SOURCES += startup/power.c
+libbsp_a_SOURCES += startup/power-rtc.c
+libbsp_a_SOURCES += startup/power-clock.c
# IRQ
libbsp_a_SOURCES += ../../shared/src/irq-default-handler.c
diff --git a/c/src/lib/libbsp/arm/atsam/include/bsp.h b/c/src/lib/libbsp/arm/atsam/include/bsp.h
index 2c1992d..89968e9 100644
--- a/c/src/lib/libbsp/arm/atsam/include/bsp.h
+++ b/c/src/lib/libbsp/arm/atsam/include/bsp.h
@@ -89,6 +89,8 @@ extern char atsam_memory_sdram_size[];
void atsam_rtc_get_time(rtems_time_of_day *tod);
+
+
/** @} */
#ifdef __cplusplus
diff --git a/c/src/lib/libbsp/arm/atsam/include/power.h b/c/src/lib/libbsp/arm/atsam/include/power.h
new file mode 100644
index 0000000..a352386
--- /dev/null
+++ b/c/src/lib/libbsp/arm/atsam/include/power.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef LIBBSP_ARM_ATSAM_POWER_H
+#define LIBBSP_ARM_ATSAM_POWER_H
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif /* __cplusplus */
+
+/**
+ * @brief Status of the Low Power Support
+ */
+typedef enum {
+ /**
+ * @brief Used for Initialization of Handlers
+ */
+ ATSAM_POWER_INIT,
+ /**
+ * @brief Used for Switching On of Handlers
+ */
+ ATSAM_POWER_ON,
+ /**
+ * @brief Used for Switching Off of Handlers
+ */
+ ATSAM_POWER_OFF
+} atsam_power_state;
+
+/**
+ * @brief Control structure for power control handling
+ */
+typedef struct atsam_power_control {
+ /**
+ * @brief Data pointer to the handler with its desired state
+ */
+ void (*handler)(
+ const struct atsam_power_control *control,
+ atsam_power_state state
+ );
+ /**
+ * @brief Data chunk that is used by the handler
+ */
+ union {
+ void *arg;
+ struct {
+ uint8_t first;
+ uint8_t last;
+ } peripherals;
+ } data;
+} atsam_power_control;
+
+/**
+ * @brief Performs a power state change according to the state parameter.
+ *
+ * The handlers of the control table are invoked in forward order (invocation
+ * starts with table index zero) for the ATSAM_POWER_INIT and ATSAM_POWER_OFF
+ * states, otherwise the handlers are invoked in reverse order (invocation
+ * starts with the last table index).
+ *
+ * @param controls Table with power controls.
+ * @param n Count of power control table entries.
+ * @param state The desired power state.
+ *
+ * @code
+ * #include <rtems.h>
+ * #include <pthread.h>
+ *
+ * #include <bsp/power.h>
+ *
+ * static atsam_power_data_rtc_driver rtc_data = { .interval = 5 };
+ *
+ * static const atsam_power_control power_controls[] = {
+ * ATSAM_POWER_CLOCK_DRIVER,
+ * ATSAM_POWER_RTC_DRIVER(&rtc_data),
+ * ATSAM_POWER_SLEEP_MODE
+ * };
+ *
+ * static pthread_once_t once = PTHREAD_ONCE_INIT;
+ *
+ * static void init(void)
+ * {
+ * atsam_power_change_state(
+ * &power_controls[0],
+ * RTEMS_ARRAY_SIZE(power_controls),
+ * ATSAM_POWER_INIT
+ * );
+ * }
+ *
+ * void power_init(void)
+ * {
+ * pthread_once(&once, init);
+ * }
+ *
+ * void low_power(void)
+ * {
+ * atsam_power_change_state(
+ * &power_controls[0],
+ * RTEMS_ARRAY_SIZE(power_controls),
+ * ATSAM_POWER_OFF
+ * );
+ * atsam_power_change_state(
+ * &power_controls[0],
+ * RTEMS_ARRAY_SIZE(power_controls),
+ * ATSAM_POWER_ON
+ * );
+ * }
+ * @end
+ */
+void atsam_power_change_state(
+ const atsam_power_control *controls,
+ size_t n,
+ atsam_power_state state
+);
+
+/**
+ * @brief Power handler for a set of peripherals according to the specified
+ * peripheral indices.
+ *
+ * For the power off state, the peripherals are enabled in the PMC.
+ *
+ * For the power on state, the peripherals are disabled in the Power Management
+ * Controller (PMC).
+ *
+ * @see ATSAM_POWER_PERIPHERAL().
+ */
+void atsam_power_handler_peripheral(
+ const atsam_power_control *controls,
+ atsam_power_state state
+);
+
+/**
+ * @brief Power handler for the clock driver.
+ *
+ * For the power off state, the system tick is disabled.
+ *
+ * For the power on state, the system tick is enabled. In case no clock driver
+ * is used by the application, then this may lead to a spurious interrupt
+ * resulting in a fatal error.
+ *
+ * @see ATSAM_POWER_CLOCK_DRIVER().
+ */
+void atsam_power_handler_clock_driver(
+ const atsam_power_control *controls,
+ atsam_power_state state
+);
+
+/**
+ * @brief Power handler for the RTC driver.
+ *
+ * This handler installs an interrupt handler during power support initialization.
+ *
+ * For the power off state, the RTC alarm interrupt is set up according to the
+ * interval of the corresponding handler data.
+ *
+ * For the power on state, the RTC alarm interrupt is disabled.
+ *
+ * @see ATSAM_POWER_RTC_DRIVER().
+ */
+void atsam_power_handler_rtc_driver(
+ const atsam_power_control *controls,
+ atsam_power_state state
+);
+
+/**
+ * @brief Power handler to enter the processor sleep mode.
+ *
+ * For the power off state, the processor is set into the sleep mode and issues
+ * a wait for interrupt instruction.
+ *
+ * @see ATSAM_POWER_SLEEP_MODE().
+ */
+void atsam_power_handler_sleep_mode(
+ const atsam_power_control *controls,
+ atsam_power_state state
+);
+
+/**
+ * @brief Initializer for a peripheral power support.
+ *
+ * @param f The first peripheral index.
+ * @param l The last peripheral index.
+ */
+#define ATSAM_POWER_PERIPHERAL(f, l) \
+ { \
+ .handler = atsam_power_handler_peripheral, \
+ .data = { .peripherals = { .first = f, .last = l } } \
+ }
+
+#define ATSAM_POWER_HANDLER(h, a) \
+ { \
+ .handler = h, \
+ .data = { .arg = a } \
+ }
+
+#define ATSAM_POWER_CLOCK_DRIVER \
+ { .handler = atsam_power_handler_clock_driver }
+
+#define ATSAM_POWER_SLEEP_MODE \
+ { .handler = atsam_power_handler_sleep_mode }
+
+/**
+ * @brief Data for RTC driver power support.
+ *
+ * @see ATSAM_POWER_RTC_DRIVER().
+ */
+typedef struct {
+ /**
+ * @brief Interval in seconds for which the power off mode should be active.
+ */
+ uint8_t interval;
+} atsam_power_data_rtc_driver;
+
+/**
+ * @brief Initializer for RTC driver power support.
+ *
+ * @param a Pointer to RTC driver power data.
+ *
+ * @see atsam_power_data_rtc_driver.
+ */
+#define ATSAM_POWER_RTC_DRIVER(a) \
+ { \
+ .handler = atsam_power_handler_rtc_driver, \
+ .data = { .arg = a } \
+ }
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_ATSAM_POWER_H */
diff --git a/c/src/lib/libbsp/arm/atsam/preinstall.am b/c/src/lib/libbsp/arm/atsam/preinstall.am
index d9494fb..9335a9d 100644
--- a/c/src/lib/libbsp/arm/atsam/preinstall.am
+++ b/c/src/lib/libbsp/arm/atsam/preinstall.am
@@ -141,6 +141,10 @@ $(PROJECT_INCLUDE)/bsp/i2c.h: include/i2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/i2c.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/i2c.h
+$(PROJECT_INCLUDE)/bsp/power.h: include/power.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/power.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/power.h
+
$(PROJECT_INCLUDE)/libchip/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/libchip
@: > $(PROJECT_INCLUDE)/libchip/$(dirstamp)
diff --git a/c/src/lib/libbsp/arm/atsam/startup/power-clock.c b/c/src/lib/libbsp/arm/atsam/startup/power-clock.c
new file mode 100644
index 0000000..e049332
--- /dev/null
+++ b/c/src/lib/libbsp/arm/atsam/startup/power-clock.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/power.h>
+#include <bsp/irq.h>
+
+#include <libchip/chip.h>
+
+#include <rtems/score/armv7m.h>
+
+void atsam_power_handler_clock_driver(
+ const atsam_power_control *control,
+ atsam_power_state state
+)
+{
+ volatile ARMV7M_Systick *systick = _ARMV7M_Systick;
+
+ (void) control;
+
+ switch (state) {
+ case ATSAM_POWER_ON:
+ systick->csr = ARMV7M_SYSTICK_CSR_ENABLE |
+ ARMV7M_SYSTICK_CSR_TICKINT |
+ ARMV7M_SYSTICK_CSR_CLKSOURCE;
+ break;
+ case ATSAM_POWER_OFF:
+ systick->csr = 0;
+ break;
+ default:
+ break;
+ }
+}
diff --git a/c/src/lib/libbsp/arm/atsam/startup/power-rtc.c b/c/src/lib/libbsp/arm/atsam/startup/power-rtc.c
new file mode 100644
index 0000000..b60235a
--- /dev/null
+++ b/c/src/lib/libbsp/arm/atsam/startup/power-rtc.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/power.h>
+#include <bsp/irq.h>
+
+#include <libchip/chip.h>
+
+#define ATSAM_ENABLE_ALARM_INTERRUPT (1u << 1)
+
+static void set_rtc_alarm_interrupt(uint8_t interval)
+{
+ Rtc *rtc = RTC;
+ rtems_time_of_day tod;
+
+ /* Clear current status register */
+ RTC_ClearSCCR(rtc, 0x3F);
+
+ atsam_rtc_get_time(&tod);
+ tod.second = (tod.second + interval) % 60;
+ tod.second = (((tod.second / 10) << 4) | (tod.second % 10));
+
+ rtc->RTC_TIMALR &= ~RTC_TIMALR_SECEN;
+ rtc->RTC_TIMALR = tod.second;
+ rtc->RTC_TIMALR |= RTC_TIMALR_SECEN;
+ RTC_EnableIt(rtc, ATSAM_ENABLE_ALARM_INTERRUPT);
+}
+
+static void rtc_interrupt_handler(void *arg)
+{
+ atsam_power_data_rtc_driver *rtc_data;
+
+ rtc_data = (atsam_power_data_rtc_driver *)arg;
+ set_rtc_alarm_interrupt(rtc_data->interval);
+}
+
+static void rtc_alarm_handler(void *arg)
+{
+ Rtc *rtc = RTC;
+ rtems_status_code sc;
+
+ /* Clear current status register */
+ RTC_ClearSCCR(rtc, 0x3F);
+
+ /* Switch off all RTC interrupts */
+ RTC_DisableIt(rtc, 0x1F);
+
+ /* Install RTC interrupt handler */
+ sc = rtems_interrupt_handler_install(RTC_IRQn,
+ "RTC",
+ RTEMS_INTERRUPT_UNIQUE,
+ rtc_interrupt_handler,
+ arg
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void set_time(void)
+{
+ rtems_time_of_day tod;
+ rtems_status_code sc;
+
+ atsam_rtc_get_time(&tod);
+ sc = rtems_clock_set(&tod);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+void atsam_power_handler_rtc_driver(
+ const atsam_power_control *control,
+ atsam_power_state state
+)
+{
+ atsam_power_data_rtc_driver *rtc_data;
+ Rtc *rtc = RTC;
+
+ rtc_data = (atsam_power_data_rtc_driver *)control->data.arg;
+
+ switch (state) {
+ case ATSAM_POWER_ON:
+ RTC_DisableIt(rtc, ATSAM_ENABLE_ALARM_INTERRUPT);
+ set_time();
+ break;
+ case ATSAM_POWER_OFF:
+ set_rtc_alarm_interrupt(rtc_data->interval);
+ break;
+ case ATSAM_POWER_INIT:
+ rtc_alarm_handler(rtc_data);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/c/src/lib/libbsp/arm/atsam/startup/power.c b/c/src/lib/libbsp/arm/atsam/startup/power.c
new file mode 100644
index 0000000..f9b5a39
--- /dev/null
+++ b/c/src/lib/libbsp/arm/atsam/startup/power.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/power.h>
+#include <bsp/irq.h>
+
+#include <libchip/chip.h>
+
+/* SCR Sleep deep bit */
+#define SCR_SLEEPDEEP (1u << 2)
+
+void atsam_power_change_state(
+ const atsam_power_control *controls,
+ size_t n,
+ atsam_power_state state
+)
+{
+ size_t i;
+
+ switch (state) {
+ case ATSAM_POWER_ON:
+ for (i = n; i > 0; --i) {
+ const atsam_power_control *c;
+
+ c = &controls[i - 1];
+ (*c->handler)(c, state);
+ }
+
+ break;
+ case ATSAM_POWER_INIT:
+ case ATSAM_POWER_OFF:
+ for (i = 0; i < n; ++i) {
+ const atsam_power_control *c;
+
+ c = &controls[i];
+ (*c->handler)(c, state);
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+void atsam_power_handler_peripheral(
+ const atsam_power_control *control,
+ atsam_power_state state
+)
+{
+ uint32_t id;
+ uint32_t end;
+
+ id = control->data.peripherals.first;
+ end = control->data.peripherals.last + 1;
+
+ switch (state) {
+ case ATSAM_POWER_ON:
+ while (id != end) {
+ PMC_EnablePeripheral(id);
+ ++id;
+ }
+ break;
+ case ATSAM_POWER_OFF:
+ while (id != end) {
+ PMC_DisablePeripheral(id);
+ ++id;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void atsam_power_handler_sleep_mode(const atsam_power_control *control, atsam_power_state state)
+{
+ (void) control;
+
+ switch (state) {
+ case ATSAM_POWER_OFF:
+ /* Enable Low Power Mode in the Fast Startup Mode Register */
+ PMC->PMC_FSMR &= (uint32_t)~PMC_FSMR_LPM;
+ /* Do not set deep sleep, but "normal" sleep */
+ SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP;
+
+ __asm__ volatile ("wfi");
+ break;
+ default:
+ break;
+ }
+}
More information about the vc
mailing list