Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/saml21: add interaction with pm_layered for peripheral drivers #18821

Merged
merged 10 commits into from
Nov 7, 2022
23 changes: 23 additions & 0 deletions cpu/sam0_common/periph/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (C) 2014-2015 Freie Universität Berlin
* 2015 Kaspar Schleiser <[email protected]>
* 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
Expand Down Expand Up @@ -29,6 +30,7 @@
* @author Thomas Eichinger <[email protected]>
* @author Kaspar Schleiser <[email protected]>
* @author Hauke Petersen <[email protected]>
* @author Juergen Fitschen <[email protected]>
*
* The GPIO implementation here support the PERIPH_GPIO_FAST_READ pseudomodule
* on the cortex-m0/m23 based devices. This trades an increase in power
Expand All @@ -48,6 +50,7 @@

#include "cpu.h"
#include "bitarithm.h"
#include "pm_layered.h"
#include "periph/gpio.h"
#include "periph_conf.h"

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down
80 changes: 67 additions & 13 deletions cpu/sam0_common/periph/rtc_rtt.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <[email protected]>
* 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
Expand All @@ -20,12 +21,14 @@
* @author Baptiste Clenet <[email protected]>
* @author FWX <[email protected]>
* @author Benjamin Valentin <[email protected]>
* @author Juergen Fitschen <[email protected]>
*
* @}
*/

#include <stdint.h>
#include <string.h>
#include "pm_layered.h"
#include "periph/rtc.h"
#include "periph/rtt.h"
#include "periph_conf.h"
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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();
Expand All @@ -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);

Expand All @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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);
}
}
Expand Down
10 changes: 6 additions & 4 deletions cpu/sam0_common/periph/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (C) 2014-2016 Freie Universität Berlin
* 2015 Kaspar Schleiser <[email protected]>
* 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
Expand All @@ -22,6 +23,7 @@
* @author Joakim Nohlgård <[email protected]>
* @author Kaspar Schleiser <[email protected]>
* @author Benjamin Valentin <[email protected]>
* @author Juergen Fitschen <[email protected]>
*
* @}
*/
Expand Down Expand Up @@ -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
}

Expand Down
20 changes: 20 additions & 0 deletions cpu/sam0_common/periph/timer.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -16,6 +17,7 @@
* @brief Low-level timer driver implementation
*
* @author Benjamin Valentin <[email protected]>
* @author Juergen Fitschen <[email protected]>
*
* @}
*/
Expand All @@ -26,6 +28,7 @@

#include "board.h"
#include "cpu.h"
#include "pm_layered.h"

#include "periph/timer.h"
#include "periph_conf.h"
Expand Down Expand Up @@ -328,13 +331,30 @@ 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);
}

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;
}

Expand Down
Loading