diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index a61146a3bb..d649964865 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -16,6 +16,15 @@ * @file gpio.c * @brief Low-level GPIO driver implementation * + * On processors that support Deep Sleep the External Interrupt Controller + * will be off during Deep Sleep. + * To wake the CPU up from Deep Sleep the RTC Tamper Detection will be + * used instead. + * Only a few pins (@ref rtc_tamper_pins) can be used for that purpose. + * + * Note that when configuring those pins as interrupt, the RTC/RTT will be + * stopped briefly as the RTC configuration is enable protected. + * * @author Troels Hoffmeyer * @author Thomas Eichinger * @author Kaspar Schleiser @@ -240,11 +249,41 @@ static int _exti(gpio_t pin) return exti_config[port_num][_pin_pos(pin)]; } +/* check if an RTC tamper pin was configured as interrupt */ +__attribute__ ((unused)) +static bool _rtc_irq_enabled(void) +{ +#if MODULE_PERIPH_GPIO_TAMPER_WAKE + for (unsigned i = 0; i < ARRAY_SIZE(rtc_tamper_pins); ++i) { + int exti = _exti(rtc_tamper_pins[i]); + + if (exti == -1) { + continue; + } + + if (_EIC->INTENSET.reg & (1 << exti)) { + return true; + } + } +#endif + return false; +} + +static void _init_rtc_pin(gpio_t pin, gpio_flank_t flank) +{ + if (IS_ACTIVE(MODULE_PERIPH_GPIO_TAMPER_WAKE)) { + rtc_tamper_register(pin, flank); + } +} + int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t cb, void *arg) { int exti = _exti(pin); + /* if it's a tamper pin configure wake from Deep Sleep */ + _init_rtc_pin(pin, flank); + /* make sure EIC channel is valid */ if (exti == -1) { return -1; @@ -330,11 +369,17 @@ void gpio_pm_cb_enter(int deep) { #if defined(PM_SLEEPCFG_SLEEPMODE_STANDBY) (void) deep; + unsigned mode = PM->SLEEPCFG.bit.SLEEPMODE; - if (PM->SLEEPCFG.bit.SLEEPMODE == PM_SLEEPCFG_SLEEPMODE_STANDBY) { + if (mode == PM_SLEEPCFG_SLEEPMODE_STANDBY) { DEBUG_PUTS("gpio: switching EIC to slow clock"); reenable_eic(_EIC_CLOCK_SLOW); } + else if (IS_ACTIVE(MODULE_PERIPH_GPIO_TAMPER_WAKE) + && mode > PM_SLEEPCFG_SLEEPMODE_STANDBY + && _rtc_irq_enabled()) { + rtc_tamper_enable(); + } #else if (deep) { DEBUG_PUTS("gpio: switching EIC to slow clock"); diff --git a/cpu/samd5x/Kconfig b/cpu/samd5x/Kconfig index 786ad65c99..bf9005ef5a 100644 --- a/cpu/samd5x/Kconfig +++ b/cpu/samd5x/Kconfig @@ -12,6 +12,7 @@ config CPU_COMMON_SAMD5X select HAS_BACKUP_RAM select HAS_CORTEXM_MPU select HAS_CPU_SAMD5X + select HAS_PERIPH_GPIO_TAMPER_WAKE select HAS_PERIPH_HWRNG config CPU_FAM_SAMD51 diff --git a/cpu/samd5x/Makefile.dep b/cpu/samd5x/Makefile.dep index eccd575bc9..a51a8aa278 100644 --- a/cpu/samd5x/Makefile.dep +++ b/cpu/samd5x/Makefile.dep @@ -1 +1,5 @@ +ifneq (,$(filter periph_gpio_tamper_wake,$(USEMODULE))) + USEMODULE += periph_rtc_rtt +endif + include $(RIOTCPU)/sam0_common/Makefile.dep diff --git a/cpu/samd5x/Makefile.features b/cpu/samd5x/Makefile.features index 5ef1caaa40..ff90cc6e8b 100644 --- a/cpu/samd5x/Makefile.features +++ b/cpu/samd5x/Makefile.features @@ -3,5 +3,6 @@ CPU_CORE = cortex-m4f FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += backup_ram FEATURES_PROVIDED += cortexm_mpu +FEATURES_PROVIDED += periph_gpio_tamper_wake include $(RIOTCPU)/sam0_common/Makefile.features diff --git a/cpu/samd5x/include/periph_cpu.h b/cpu/samd5x/include/periph_cpu.h index a7b39a952c..21b80c7cdf 100644 --- a/cpu/samd5x/include/periph_cpu.h +++ b/cpu/samd5x/include/periph_cpu.h @@ -116,6 +116,15 @@ typedef enum { #define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ /** @} */ +/** + * @brief RTC input pins that can be used for tamper detection and + * wake from Deep Sleep + */ +static const gpio_t rtc_tamper_pins[RTC_NUM_OF_TAMPERS] = { + GPIO_PIN(PB, 0), GPIO_PIN(PB, 2), GPIO_PIN(PA, 2), + GPIO_PIN(PC, 0), GPIO_PIN(PC, 1) +}; + #ifdef __cplusplus } #endif diff --git a/cpu/saml1x/include/periph_cpu.h b/cpu/saml1x/include/periph_cpu.h index 3c81e6dd58..2429ae4648 100644 --- a/cpu/saml1x/include/periph_cpu.h +++ b/cpu/saml1x/include/periph_cpu.h @@ -82,6 +82,15 @@ typedef enum { #define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ /** @} */ +/** + * @brief RTC input pins that can be used for tamper detection and + * wake from Deep Sleep + */ +static const gpio_t rtc_tamper_pins[RTC_NUM_OF_TAMPERS] = { + GPIO_PIN(PA, 8), GPIO_PIN(PA, 9), GPIO_PIN(PA, 16), + GPIO_PIN(PA, 17) +}; + #ifdef __cplusplus } #endif diff --git a/drivers/periph_common/init.c b/drivers/periph_common/init.c index a6a8ad57d2..c3f6bd4463 100644 --- a/drivers/periph_common/init.c +++ b/drivers/periph_common/init.c @@ -22,6 +22,8 @@ #define USB_H_USER_IS_RIOT_INTERNAL +#include "periph_cpu.h" + #ifdef MODULE_PERIPH_INIT #ifdef MODULE_PERIPH_INIT_I2C #include "periph/i2c.h" @@ -73,6 +75,11 @@ void periph_init(void) rtc_init(); #endif + /* Initialize Tamper Detection */ +#ifdef MODULE_PERIPH_INIT_GPIO_TAMPER_WAKE + rtc_tamper_init(); +#endif + #ifdef MODULE_PERIPH_INIT_HWRNG hwrng_init(); #endif diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index 057ee85e2d..1ce168aebb 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -150,6 +150,12 @@ config HAS_PERIPH_GPIO_FAST_READ operations are faster, usually with a tradeoff against a different property. +config HAS_PERIPH_GPIO_TAMPER_WAKE + bool + help + Indicates that Tamper Detection can be used to wake the CPU from + Deep Sleep. + config HAS_PERIPH_HWRNG bool help