forked from Imagelibrary/rtems
bsp/atsam: Add power support
This commit is contained in:
committed by
Sebastian Huber
parent
5c09e9dd1f
commit
5d0f0de4aa
@@ -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
|
||||
|
||||
@@ -89,6 +89,8 @@ extern char atsam_memory_sdram_size[];
|
||||
|
||||
void atsam_rtc_get_time(rtems_time_of_day *tod);
|
||||
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
245
c/src/lib/libbsp/arm/atsam/include/power.h
Normal file
245
c/src/lib/libbsp/arm/atsam/include/power.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (c) 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@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 */
|
||||
@@ -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)
|
||||
|
||||
44
c/src/lib/libbsp/arm/atsam/startup/power-clock.c
Normal file
44
c/src/lib/libbsp/arm/atsam/startup/power-clock.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@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;
|
||||
}
|
||||
}
|
||||
104
c/src/lib/libbsp/arm/atsam/startup/power-rtc.c
Normal file
104
c/src/lib/libbsp/arm/atsam/startup/power-rtc.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@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;
|
||||
}
|
||||
}
|
||||
102
c/src/lib/libbsp/arm/atsam/startup/power.c
Normal file
102
c/src/lib/libbsp/arm/atsam/startup/power.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user