From 73e22612e218e1817c9eb8e28a72a40e861bcc99 Mon Sep 17 00:00:00 2001 From: Juergen Fitschen Date: Thu, 26 Mar 2020 10:56:10 +0100 Subject: [PATCH] sys/ztimer: add power management for ztimer clocks --- sys/include/ztimer.h | 8 ++++++++ sys/ztimer/auto_init.c | 18 ++++++++++++++++++ sys/ztimer/core.c | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/sys/include/ztimer.h b/sys/include/ztimer.h index 096310801e..37dd23a3a6 100644 --- a/sys/include/ztimer.h +++ b/sys/include/ztimer.h @@ -223,6 +223,11 @@ extern "C" { #endif +/** + * @brief Disables interaction with pm_layered for a clock + */ +#define ZTIMER_CLOCK_NO_REQUIRED_PM_MODE (UINT8_MAX) + /** * @brief ztimer_base_t forward declaration */ @@ -297,6 +302,9 @@ struct ztimer_clock { uint32_t lower_last; /**< timer value at last now() call */ ztimer_now_t checkpoint; /**< cumulated time at last now() call */ #endif +#if MODULE_PM_LAYERED || DOXYGEN + uint8_t required_pm_mode; /**< min. pm mode required for the clock to run */ +#endif }; /** diff --git a/sys/ztimer/auto_init.c b/sys/ztimer/auto_init.c index 456e68d09d..7c4b264c17 100644 --- a/sys/ztimer/auto_init.c +++ b/sys/ztimer/auto_init.c @@ -86,6 +86,14 @@ #define CONFIG_ZTIMER_USEC_WIDTH (32) #endif +#ifndef CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE +#define CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE ZTIMER_CLOCK_NO_REQUIRED_PM_MODE +#endif + +#ifndef CONFIG_ZTIMER_MSEC_REQUIRED_PM_MODE +#define CONFIG_ZTIMER_MSEC_REQUIRED_PM_MODE ZTIMER_CLOCK_NO_REQUIRED_PM_MODE +#endif + #if MODULE_ZTIMER_USEC # if CONFIG_ZTIMER_USEC_TYPE_PERIPH_TIMER static ztimer_periph_timer_t _ztimer_periph_timer_usec = { .min = CONFIG_ZTIMER_USEC_MIN }; @@ -160,6 +168,11 @@ void ztimer_init(void) CONFIG_ZTIMER_USEC_ADJUST); ZTIMER_USEC->adjust = CONFIG_ZTIMER_USEC_ADJUST; # endif +# ifdef MODULE_PM_LAYERED + LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting required_pm_mode to %i\n", + CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE); + ZTIMER_USEC->required_pm_mode = CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE; +# endif #endif #ifdef ZTIMER_RTT_INIT @@ -180,5 +193,10 @@ void ztimer_init(void) CONFIG_ZTIMER_MSEC_ADJUST); ZTIMER_MSEC->adjust = CONFIG_ZTIMER_MSEC_ADJUST; # endif +# ifdef MODULE_PM_LAYERED + LOG_DEBUG("ztimer_init(): ZTIMER_MSEC setting required_pm_mode to %i\n", + CONFIG_ZTIMER_MSEC_REQUIRED_PM_MODE); + ZTIMER_MSEC->required_pm_mode = CONFIG_ZTIMER_MSEC_REQUIRED_PM_MODE; +# endif #endif } diff --git a/sys/ztimer/core.c b/sys/ztimer/core.c index 736fbc31d5..45e143a206 100644 --- a/sys/ztimer/core.c +++ b/sys/ztimer/core.c @@ -27,6 +27,9 @@ #include "kernel_defines.h" #include "irq.h" +#ifdef MODULE_PM_LAYERED +#include "pm_layered.h" +#endif #include "ztimer.h" #define ENABLE_DEBUG (0) @@ -106,6 +109,13 @@ static void _add_entry_to_list(ztimer_clock_t *clock, ztimer_base_t *entry) ztimer_base_t *list = &clock->list; +#ifdef MODULE_PM_LAYERED + /* First timer on the clock's linked list */ + if (list->next == NULL && clock->required_pm_mode != ZTIMER_CLOCK_NO_REQUIRED_PM_MODE) { + pm_block(clock->required_pm_mode); + } +#endif + /* Jump past all entries which are set to an earlier target than the new entry */ while (list->next) { ztimer_base_t *list_entry = list->next; @@ -223,6 +233,13 @@ static void _del_entry_from_list(ztimer_clock_t *clock, ztimer_base_t *entry) } list = list->next; } + +#ifdef MODULE_PM_LAYERED + /* The last timer just got removed from the clock's linked list */ + if (clock->list.next == NULL && clock->required_pm_mode != ZTIMER_CLOCK_NO_REQUIRED_PM_MODE) { + pm_unblock(clock->required_pm_mode); + } +#endif } static ztimer_t *_now_next(ztimer_clock_t *clock) @@ -232,7 +249,13 @@ static ztimer_t *_now_next(ztimer_clock_t *clock) if (entry && (entry->offset == 0)) { clock->list.next = entry->next; if (!entry->next) { + /* The last timer just got removed from the clock's linked list */ clock->last = NULL; +#ifdef MODULE_PM_LAYERED + if (clock->required_pm_mode != ZTIMER_CLOCK_NO_REQUIRED_PM_MODE) { + pm_unblock(clock->required_pm_mode); + } +#endif } return (ztimer_t*)entry; }