diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index 2f50619af015..6c3ea0d2c02c 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -2,6 +2,7 @@ * Copyright (C) 2014-2015 Freie Universität Berlin * 2015 Kaspar Schleiser * 2015 FreshTemp, LLC. + * 2022 SSV Software Systems GmbH * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -29,6 +30,7 @@ * @author Thomas Eichinger * @author Kaspar Schleiser * @author Hauke Petersen + * @author Juergen Fitschen * * The GPIO implementation here support the PERIPH_GPIO_FAST_READ pseudomodule * on the cortex-m0/m23 based devices. This trades an increase in power @@ -48,6 +50,7 @@ #include "cpu.h" #include "bitarithm.h" +#include "pm_layered.h" #include "periph/gpio.h" #include "periph_conf.h" @@ -365,6 +368,12 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, #endif /* clear interrupt flag and enable the interrupt line and line wakeup */ _EIC->INTFLAG.reg = (1 << exti); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_GPIO_PM_BLOCK) + /* block pm mode if it hasn't been blocked before */ + if (!(_EIC->INTENSET.reg & (1 << exti))) { + pm_block(SAM0_GPIO_PM_BLOCK); + } +#endif _EIC->INTENSET.reg = (1 << exti); #ifdef CPU_COMMON_SAMD21 _EIC->WAKEUP.reg |= (1 << exti); @@ -456,6 +465,13 @@ void gpio_irq_enable(gpio_t pin) /* clear stale interrupt */ _EIC->INTFLAG.reg = 1 << exti; +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_GPIO_PM_BLOCK) + /* unblock power mode */ + if (!(_EIC->INTENSET.reg & (1 << exti))) { + pm_block(SAM0_GPIO_PM_BLOCK); + } +#endif + /* enable interrupt */ _EIC->INTENSET.reg = 1 << exti; @@ -470,6 +486,13 @@ void gpio_irq_disable(gpio_t pin) return; } +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_GPIO_PM_BLOCK) + /* unblock power mode */ + if (_EIC->INTENSET.reg & (1 << exti)) { + pm_unblock(SAM0_GPIO_PM_BLOCK); + } +#endif + /* disable interrupt */ _EIC->INTENCLR.reg = 1 << exti; diff --git a/cpu/sam0_common/periph/rtc_rtt.c b/cpu/sam0_common/periph/rtc_rtt.c index cda8c442404f..ab4777f589a5 100644 --- a/cpu/sam0_common/periph/rtc_rtt.c +++ b/cpu/sam0_common/periph/rtc_rtt.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Kaspar Schleiser * 2015 FreshTemp, LLC. + * 2022 SSV Software Systems GmbH * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -20,12 +21,14 @@ * @author Baptiste Clenet * @author FWX * @author Benjamin Valentin + * @author Juergen Fitschen * * @} */ #include #include +#include "pm_layered.h" #include "periph/rtc.h" #include "periph/rtt.h" #include "periph_conf.h" @@ -62,11 +65,45 @@ typedef struct { static rtc_state_t alarm_cb; static rtc_state_t overflow_cb; +#if (IS_ACTIVE(MODULE_PERIPH_RTC) || IS_ACTIVE(MODULE_PERIPH_RTT)) && \ + IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_RTCRTT_PM_BLOCK) + +static bool _pm_alarm = false; +#if IS_ACTIVE(MODULE_PERIPH_RTT) +static bool _pm_overflow = false; +#endif + +static inline void _pm_block(bool *flag) +{ + if (!*flag) { + pm_block(SAM0_RTCRTT_PM_BLOCK); + *flag = true; + } +} + +static inline void _pm_unblock(bool *flag) +{ + if (*flag) { + pm_unblock(SAM0_RTCRTT_PM_BLOCK); + *flag = false; + } +} + +#else + +/* Use empty stubs if pm is disabled */ +#define _pm_block(x) +#define _pm_unblock(x) + +#endif + +#if IS_ACTIVE(MODULE_PERIPH_RTC) /* At 1Hz, RTC goes till 63 years (2^5, see 17.8.22 in datasheet) * struct tm younts the year since 1900, use the difference to RIOT_EPOCH * as an offset so the user can set years in RIOT_EPOCH + 63 */ -static uint16_t reference_year = RIOT_EPOCH - 1900; +static const uint16_t reference_year = RIOT_EPOCH - 1900; +#endif static void _wait_syncbusy(void) { @@ -309,6 +346,9 @@ static void _rtc_init(void) void rtc_init(void) { + /* clear previously set pm mode blockers */ + _pm_unblock(&_pm_alarm); + _poweroff(); _rtc_clock_setup(); _poweron(); @@ -318,12 +358,8 @@ void rtc_init(void) /* disable all interrupt sources */ RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_MASK; - /* enable overflow interrupt */ - RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_OVF; - /* Clear interrupt flags */ - RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_OVF - | RTC_MODE2_INTFLAG_ALARM0; + RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; _rtc_set_enabled(1); @@ -334,6 +370,9 @@ void rtc_init(void) #ifdef MODULE_PERIPH_RTT void rtt_init(void) { + /* clear previously set pm mode blockers */ + _pm_unblock(&_pm_alarm); + _pm_unblock(&_pm_overflow); _rtt_clock_setup(); _poweron(); @@ -581,6 +620,11 @@ int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg) RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; + /* block power mode if callback function is present */ + if (alarm_cb.cb) { + _pm_block(&_pm_alarm); + } + return 0; } @@ -610,6 +654,8 @@ void rtc_clear_alarm(void) { /* disable alarm interrupt */ RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_ALARM0; + + _pm_unblock(&_pm_alarm); } void rtc_poweron(void) @@ -635,11 +681,18 @@ void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) /* enable overflow interrupt */ RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_OVF; + + /* block power mode if callback function is present */ + if (overflow_cb.cb) { + _pm_block(&_pm_overflow); + } } void rtt_clear_overflow_cb(void) { /* disable overflow interrupt */ RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_OVF; + + _pm_unblock(&_pm_overflow); } uint32_t rtt_get_counter(void) @@ -676,12 +729,19 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) /* enable compare interrupt and clear flag */ RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; + + /* block power mode if callback function is present */ + if (alarm_cb.cb) { + _pm_block(&_pm_alarm); + } } void rtt_clear_alarm(void) { /* disable compare interrupt */ RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; + + _pm_unblock(&_pm_alarm); } void rtt_poweron(void) @@ -709,13 +769,6 @@ static void _isr_rtc(void) alarm_cb.cb(alarm_cb.arg); } } - if (RTC->MODE2.INTFLAG.bit.OVF) { - /* clear flag */ - RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_OVF; - /* At 1Hz, RTC goes till 63 years (2^5, see 17.8.22 in datasheet) - * Start RTC again with reference_year 64 years more (Be careful with alarm set) */ - reference_year += 64; - } } static void _isr_rtt(void) @@ -736,6 +789,7 @@ static void _isr_rtt(void) /* disable interrupt */ RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; if (alarm_cb.cb) { + _pm_unblock(&_pm_alarm); alarm_cb.cb(alarm_cb.arg); } } diff --git a/cpu/sam0_common/periph/spi.c b/cpu/sam0_common/periph/spi.c index bf50aee126da..ebed25f335d9 100644 --- a/cpu/sam0_common/periph/spi.c +++ b/cpu/sam0_common/periph/spi.c @@ -2,6 +2,7 @@ * Copyright (C) 2014-2016 Freie Universität Berlin * 2015 Kaspar Schleiser * 2015 FreshTemp, LLC. + * 2022 SSV Software Systems GmbH * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -22,6 +23,7 @@ * @author Joakim Nohlgård * @author Kaspar Schleiser * @author Benjamin Valentin + * @author Juergen Fitschen * * @} */ @@ -459,15 +461,15 @@ static void _blocking_transfer(spi_t bus, const void *out, void *in, size_t len) static void _dma_execute(spi_t bus) { -#if defined(CPU_COMMON_SAMD21) - pm_block(SAMD21_PM_IDLE_1); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_SPI_PM_BLOCK) + pm_block(SAM0_SPI_PM_BLOCK); #endif dma_start(_dma_state[bus].rx_dma); dma_start(_dma_state[bus].tx_dma); dma_wait(_dma_state[bus].rx_dma); -#if defined(CPU_COMMON_SAMD21) - pm_unblock(SAMD21_PM_IDLE_1); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_SPI_PM_BLOCK) + pm_unblock(SAM0_SPI_PM_BLOCK); #endif } diff --git a/cpu/sam0_common/periph/timer.c b/cpu/sam0_common/periph/timer.c index f2790ea2c565..4e9ccbd7f47a 100644 --- a/cpu/sam0_common/periph/timer.c +++ b/cpu/sam0_common/periph/timer.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2019 ML!PA Consulting GmbH + * 2022 SSV Software Systems GmbH * * * This file is subject to the terms and conditions of the GNU Lesser @@ -16,6 +17,7 @@ * @brief Low-level timer driver implementation * * @author Benjamin Valentin + * @author Juergen Fitschen * * @} */ @@ -26,6 +28,7 @@ #include "board.h" #include "cpu.h" +#include "pm_layered.h" #include "periph/timer.h" #include "periph_conf.h" @@ -328,6 +331,14 @@ unsigned int timer_read(tim_t tim) void timer_stop(tim_t tim) { +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_TIMER_PM_BLOCK) + /* unblock power mode if the timer is running */ + if (dev(tim)->CTRLA.bit.ENABLE) { + DEBUG("[timer %d] pm_unblock\n", tim); + pm_unblock(SAM0_TIMER_PM_BLOCK); + } +#endif + dev(tim)->CTRLA.bit.ENABLE = 0; wait_synchronization(tim); } @@ -335,6 +346,15 @@ void timer_stop(tim_t tim) void timer_start(tim_t tim) { wait_synchronization(tim); + +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_TIMER_PM_BLOCK) + /* block power mode if the timer is not running, yet */ + if (!dev(tim)->CTRLA.bit.ENABLE) { + DEBUG("[timer %d] pm_block\n", tim); + pm_block(SAM0_TIMER_PM_BLOCK); + } +#endif + dev(tim)->CTRLA.bit.ENABLE = 1; } diff --git a/cpu/sam0_common/periph/uart.c b/cpu/sam0_common/periph/uart.c index 25aca6d51195..a2bdda61a76f 100644 --- a/cpu/sam0_common/periph/uart.c +++ b/cpu/sam0_common/periph/uart.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Freie Universität Berlin * 2015 FreshTemp, LLC. + * 2022 SSV Software Systems GmbH * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -20,11 +21,13 @@ * @author Hauke Petersen * @author Dylan Laduranty * @author Benjamin Valentin + * @author Juergen Fitschen * * @} */ #include "cpu.h" +#include "pm_layered.h" #include "periph/uart.h" #include "periph/gpio.h" @@ -162,6 +165,23 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) return UART_NODEV; } + /* enable peripheral clock */ + sercom_clk_en(dev(uart)); + +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) + /* clear previously blocked power modes */ + if (dev(uart)->CTRLA.bit.ENABLE) { + /* RX IRQ is enabled */ + if (dev(uart)->INTENSET.bit.RXC) { + pm_unblock(SAM0_UART_PM_BLOCK); + } + /* data reg empty IRQ is enabled -> sending data was in progress */ + if (dev(uart)->INTENSET.bit.DRE) { + pm_unblock(SAM0_UART_PM_BLOCK); + } + } +#endif + /* must disable here first to ensure idempotency */ dev(uart)->CTRLA.reg = 0; @@ -173,9 +193,6 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) /* configure pins */ _configure_pins(uart); - /* enable peripheral clock */ - sercom_clk_en(dev(uart)); - /* reset the UART device */ _reset(dev(uart)); @@ -236,6 +253,10 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) #endif /* UART_HAS_TX_ISR */ dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_RXEN; dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC; +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) + /* block power mode for rx IRQs */ + pm_block(SAM0_UART_PM_BLOCK); +#endif /* set wakeup receive from sleep if enabled */ if (uart_config[uart].flags & UART_FLAG_WAKEUP) { dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_SFDE; @@ -303,6 +324,10 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) return; } + if (!dev(uart)->CTRLA.bit.ENABLE) { + return; + } + #ifdef MODULE_PERIPH_UART_NONBLOCKING for (const void* end = data + len; data != end; ++data) { if (irq_is_in() || __get_PRIMASK()) { @@ -316,7 +341,20 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) else { while (tsrb_add_one(&uart_tx_rb[uart], *data) < 0) {} } + /* check and enable DRE IRQs atomically */ +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) + unsigned state = irq_disable(); + /* tsrb_add_one() is blocking the thread. It may happen that + * the corresponding ISR has turned off DRE IRQs and, thus, + * unblocked the corresponding power mode. */ + if (!dev(uart)->INTENSET.bit.DRE) { + pm_block(SAM0_UART_PM_BLOCK); + } dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; + irq_restore(state); +#else + dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; +#endif } #else for (const void* end = data + len; data != end; ++data) { @@ -330,13 +368,48 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) void uart_poweron(uart_t uart) { sercom_clk_en(dev(uart)); + + /* the enable bit must be read and written atomically */ + unsigned state = irq_disable(); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) + /* block required power modes */ + if (!dev(uart)->CTRLA.bit.ENABLE) { + /* RX IRQ is enabled */ + if (dev(uart)->INTENSET.bit.RXC) { + pm_block(SAM0_UART_PM_BLOCK); + } + /* data reg empty IRQ is enabled -> sending data was in progress */ + if (dev(uart)->INTENSET.bit.DRE) { + pm_block(SAM0_UART_PM_BLOCK); + } + } +#endif dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + irq_restore(state); + _syncbusy(dev(uart)); } void uart_poweroff(uart_t uart) { + /* the enable bit must be read and written atomically */ + unsigned state = irq_disable(); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) + /* clear blocked power modes */ + if (dev(uart)->CTRLA.bit.ENABLE) { + /* RX IRQ is enabled */ + if (dev(uart)->INTENSET.bit.RXC) { + pm_unblock(SAM0_UART_PM_BLOCK); + } + /* data reg empty IRQ is enabled -> sending data is in progress */ + if (dev(uart)->INTENSET.bit.DRE) { + pm_unblock(SAM0_UART_PM_BLOCK); + } + } +#endif dev(uart)->CTRLA.reg &= ~(SERCOM_USART_CTRLA_ENABLE); + irq_restore(state); + sercom_clk_dis(dev(uart)); } @@ -500,6 +573,11 @@ static inline void irq_handler_tx(unsigned uartnum) /* disable the interrupt if there are no more bytes to send */ if (tsrb_empty(&uart_tx_rb[uartnum])) { dev(uartnum)->INTENCLR.reg = SERCOM_USART_INTENSET_DRE; +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) + /* we really should be in IRQ context! */ + assert(irq_is_in()); + pm_unblock(SAM0_UART_PM_BLOCK); +#endif } } #endif diff --git a/cpu/sam0_common/periph/usbdev.c b/cpu/sam0_common/periph/usbdev.c index 4a545118468e..1e814b90b8dd 100644 --- a/cpu/sam0_common/periph/usbdev.c +++ b/cpu/sam0_common/periph/usbdev.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2019 Koen Zandberg + * 2022 SSV Software Systems GmbH * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -13,6 +14,7 @@ * @brief Low level USB interface functions for the sam0 class devices * * @author Koen Zandberg + * @author Juergen Fitschen * @} */ @@ -279,20 +281,6 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, return res; } -static void _block_pm(void) -{ -#if defined(CPU_COMMON_SAMD21) - pm_block(SAMD21_PM_IDLE_1); -#endif -} - -static void _unblock_pm(void) -{ -#if defined(CPU_COMMON_SAMD21) - pm_unblock(SAMD21_PM_IDLE_1); -#endif -} - static void _setup(sam0_common_usb_t *usbdev, const sam0_common_usb_config_t *config) { @@ -319,6 +307,18 @@ static void _usbdev_init(usbdev_t *dev) /* Only one usb device on this board */ sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev; + /* clear previously set pm blockers */ + if (usbdev->config->device->CTRLA.bit.ENABLE) { +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_IDLE_PM_BLOCK) + pm_unblock(SAM0_USB_IDLE_PM_BLOCK); +#endif + if (!usbdev->suspended) { +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK) + pm_unblock(SAM0_USB_ACTIVE_PM_BLOCK); +#endif + } + } + /* Set GPIO */ gpio_init(usbdev->config->dp, GPIO_IN); gpio_init(usbdev->config->dm, GPIO_IN); @@ -347,7 +347,13 @@ static void _usbdev_init(usbdev_t *dev) usbdev->config->device->CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS; _enable_irq(usbdev); - _block_pm(); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_IDLE_PM_BLOCK) + pm_block(SAM0_USB_IDLE_PM_BLOCK); +#endif +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK) + pm_block(SAM0_USB_ACTIVE_PM_BLOCK); +#endif + usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_HOST_CONNECT); /* Interrupt configuration */ #ifdef CPU_COMMON_SAMD5X @@ -542,8 +548,10 @@ static void _usbdev_esr(usbdev_t *dev) USB_DEVICE_INTFLAG_SUSPEND; usbdev->suspended = true; usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_SUSPEND); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK) /* Low power modes are available while suspended */ - _unblock_pm(); + pm_unblock(SAM0_USB_ACTIVE_PM_BLOCK); +#endif } else if (usbdev->config->device->INTFLAG.bit.WAKEUP && usbdev->suspended) { @@ -551,8 +559,10 @@ static void _usbdev_esr(usbdev_t *dev) USB_DEVICE_INTFLAG_SUSPEND; usbdev->suspended = false; usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_RESUME); +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_USB_ACTIVE_PM_BLOCK) /* Device wakeup detected, blocking low power modes */ - _block_pm(); + pm_block(SAM0_USB_ACTIVE_PM_BLOCK); +#endif } else { DEBUG("sam_usb: Unhandled interrupt\n"); diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index 3ae48378a50c..c66d0f389c90 100644 --- a/cpu/samd21/include/periph_cpu.h +++ b/cpu/samd21/include/periph_cpu.h @@ -53,6 +53,20 @@ extern "C" { #define SAMD21_PM_IDLE_0 (3U) /**< Idle 0 (stops CPU) */ /** @} */ +/** + * @name SPI configuration + * @{ + */ +#define SAM0_SPI_PM_BLOCK SAMD21_PM_IDLE_1 /**< Stay in Idle 0 mode */ +/** @} */ + +/** + * @name USB configuration + * @{ + */ +#define SAM0_USB_ACTIVE_PM_BLOCK SAMD21_PM_IDLE_1 /**< Stay in Idle 0 mode */ +/** @} */ + /** * @name SAMD21 GCLK definitions * @{ diff --git a/cpu/saml21/include/periph_cpu.h b/cpu/saml21/include/periph_cpu.h index 3c7d6963aeaf..22e6dbd5037a 100644 --- a/cpu/saml21/include/periph_cpu.h +++ b/cpu/saml21/include/periph_cpu.h @@ -41,6 +41,27 @@ extern "C" { #define SAML21_PM_MODE_IDLE (2) /**< CPU sleeping, peripherals are active */ /** @} */ +/** + * @name Peripheral power mode requirements + * @{ + */ +#define SAM0_GPIO_PM_BLOCK SAML21_PM_MODE_BACKUP /**< GPIO IRQs require STANDBY mode */ +#define SAM0_RTCRTT_PM_BLOCK SAML21_PM_MODE_BACKUP /**< RTC/TRR require STANDBY mode */ +#define SAM0_SPI_PM_BLOCK SAML21_PM_MODE_STANDBY /**< SPI in DMA mode require IDLE mode */ +#define SAM0_TIMER_PM_BLOCK SAML21_PM_MODE_STANDBY /**< Timers require IDLE mode */ +#define SAM0_UART_PM_BLOCK SAML21_PM_MODE_STANDBY /**< UART RX IRQ require IDLE mode */ +#define SAM0_USB_IDLE_PM_BLOCK SAML21_PM_MODE_BACKUP /**< Idle USB require STANDBY mode */ +#define SAM0_USB_ACTIVE_PM_BLOCK SAML21_PM_MODE_STANDBY /**< Active USB require IDLE mode */ +/** @} */ + +/** + * @brief Override the default initial PM blocker + * All peripheral drivers ensure required pm modes are blocked + */ +#ifndef PM_BLOCKER_INITIAL +#define PM_BLOCKER_INITIAL { 0, 0, 0 } +#endif + /** * @name SAML21 GCLK definitions * @{