drivers: counter: Add MAX32 Wake-Up Timer driver
MAX32 Wake-Up Timer is a 32-bit timer that can wakeup the device from low-power modes. Signed-off-by: Tahsin Mutlugun <Tahsin.Mutlugun@analog.com>
This commit is contained in:
parent
457ade48b4
commit
ab43ceb1eb
@ -58,3 +58,4 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_RENESAS_RZ_GTM counter_renesas_
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_REALTEK_RTS5912_SLWTMR counter_realtek_rts5912_slwtmr.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_REALTEK_RTS5912 counter_realtek_rts5912.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_NEORV32_GPTMR counter_neorv32_gptmr.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_COUNTER_WUT_MAX32 counter_max32_wut.c)
|
||||
|
||||
@ -114,4 +114,6 @@ source "drivers/counter/Kconfig.rts5912"
|
||||
|
||||
source "drivers/counter/Kconfig.neorv32"
|
||||
|
||||
source "drivers/counter/Kconfig.max32_wut"
|
||||
|
||||
endif # COUNTER
|
||||
|
||||
9
drivers/counter/Kconfig.max32_wut
Normal file
9
drivers/counter/Kconfig.max32_wut
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2025 Analog Devices, Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config COUNTER_WUT_MAX32
|
||||
bool "MAX32xxx wake-up timer driver"
|
||||
default y
|
||||
depends on DT_HAS_ADI_MAX32_WUT_ENABLED
|
||||
help
|
||||
Enable the wake-up timer driver for MAX32 MCUs.
|
||||
278
drivers/counter/counter_max32_wut.c
Normal file
278
drivers/counter/counter_max32_wut.c
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Analog Devices, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT adi_max32_wut
|
||||
|
||||
#include <zephyr/drivers/counter.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <wut.h>
|
||||
#include <wrap_max32_lp.h>
|
||||
#include <wrap_max32_sys.h>
|
||||
|
||||
LOG_MODULE_REGISTER(counter_max32_wut, CONFIG_COUNTER_LOG_LEVEL);
|
||||
|
||||
#define MAX32_WUT_COUNTER_FREQ 32768
|
||||
|
||||
struct max32_wut_alarm_data {
|
||||
counter_alarm_callback_t callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct max32_wut_data {
|
||||
struct max32_wut_alarm_data alarm;
|
||||
uint32_t guard_period;
|
||||
};
|
||||
|
||||
struct max32_wut_config {
|
||||
struct counter_config_info info;
|
||||
mxc_wut_regs_t *regs;
|
||||
int clock_source;
|
||||
int prescaler;
|
||||
void (*irq_func)(const struct device *dev);
|
||||
uint32_t irq_number;
|
||||
bool wakeup_source;
|
||||
};
|
||||
|
||||
static int counter_max32_wut_start(const struct device *dev)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
|
||||
MXC_WUT_Enable(cfg->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int counter_max32_wut_stop(const struct device *dev)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
|
||||
MXC_WUT_Disable(cfg->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int counter_max32_wut_get_value(const struct device *dev, uint32_t *ticks)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
|
||||
*ticks = MXC_WUT_GetCount(cfg->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int counter_max32_wut_set_top_value(const struct device *dev,
|
||||
const struct counter_top_cfg *top_cfg)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(top_cfg);
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static uint32_t counter_max32_wut_get_pending_int(const struct device *dev)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
|
||||
return MXC_WUT_GetFlags(cfg->regs);
|
||||
}
|
||||
|
||||
static uint32_t counter_max32_wut_get_top_value(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static uint32_t counter_max32_wut_get_freq(const struct device *dev)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
|
||||
return cfg->info.freq;
|
||||
}
|
||||
|
||||
static uint32_t counter_max32_wut_get_guard_period(const struct device *dev, uint32_t flags)
|
||||
{
|
||||
struct max32_wut_data *data = dev->data;
|
||||
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
return data->guard_period;
|
||||
}
|
||||
|
||||
static int counter_max32_wut_set_guard_period(const struct device *dev, uint32_t ticks,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct max32_wut_data *data = dev->data;
|
||||
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
if (ticks > counter_max32_wut_get_top_value(dev)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->guard_period = ticks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int counter_max32_wut_set_alarm(const struct device *dev, uint8_t chan,
|
||||
const struct counter_alarm_cfg *alarm_cfg)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
struct max32_wut_data *data = dev->data;
|
||||
uint32_t now_ticks, top_ticks;
|
||||
uint64_t abs_ticks, min_abs_ticks;
|
||||
bool irq_on_late = false;
|
||||
bool absolute = alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE;
|
||||
|
||||
counter_max32_wut_get_value(dev, &now_ticks);
|
||||
|
||||
top_ticks = counter_max32_wut_get_top_value(dev);
|
||||
if (alarm_cfg->ticks > top_ticks) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data->alarm.callback != NULL) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
MXC_WUT_ClearFlags(cfg->regs);
|
||||
|
||||
data->alarm.callback = alarm_cfg->callback;
|
||||
data->alarm.user_data = alarm_cfg->user_data;
|
||||
|
||||
if (absolute) {
|
||||
abs_ticks = alarm_cfg->ticks;
|
||||
} else {
|
||||
abs_ticks = (uint64_t)now_ticks + alarm_cfg->ticks;
|
||||
}
|
||||
|
||||
min_abs_ticks = (uint64_t)now_ticks + data->guard_period;
|
||||
if ((!absolute && (abs_ticks < now_ticks)) || (abs_ticks > min_abs_ticks)) {
|
||||
MXC_WUT_SetCompare(cfg->regs, abs_ticks & top_ticks);
|
||||
MXC_WUT_Enable(cfg->regs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
irq_on_late = alarm_cfg->flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE;
|
||||
if (irq_on_late || !absolute) {
|
||||
NVIC_SetPendingIRQ(cfg->irq_number);
|
||||
} else {
|
||||
data->alarm.callback = NULL;
|
||||
data->alarm.user_data = NULL;
|
||||
}
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static int counter_max32_wut_cancel_alarm(const struct device *dev, uint8_t chan)
|
||||
{
|
||||
ARG_UNUSED(chan);
|
||||
struct max32_wut_data *data = dev->data;
|
||||
|
||||
counter_max32_wut_stop(dev);
|
||||
|
||||
data->alarm.callback = NULL;
|
||||
data->alarm.user_data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void counter_max32_wut_isr(const struct device *dev)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
struct max32_wut_data *data = dev->data;
|
||||
|
||||
if (data->alarm.callback) {
|
||||
counter_alarm_callback_t cb = data->alarm.callback;
|
||||
|
||||
data->alarm.callback = NULL;
|
||||
cb(dev, 0, MXC_WUT_GetCount(cfg->regs), data->alarm.user_data);
|
||||
}
|
||||
|
||||
MXC_WUT_ClearFlags(cfg->regs);
|
||||
}
|
||||
|
||||
static int counter_max32_wut_init(const struct device *dev)
|
||||
{
|
||||
const struct max32_wut_config *cfg = dev->config;
|
||||
uint8_t prescaler_lo, prescaler_hi;
|
||||
mxc_wut_pres_t pres;
|
||||
mxc_wut_cfg_t wut_cfg;
|
||||
|
||||
Wrap_MXC_SYS_Select32KClockSource(cfg->clock_source);
|
||||
|
||||
prescaler_lo = FIELD_GET(GENMASK(2, 0), LOG2(cfg->prescaler));
|
||||
prescaler_hi = FIELD_GET(BIT(3), LOG2(cfg->prescaler));
|
||||
|
||||
pres = (prescaler_hi << MXC_F_WUT_CTRL_PRES3_POS) |
|
||||
(prescaler_lo << MXC_F_WUT_CTRL_PRES_POS);
|
||||
|
||||
MXC_WUT_Init(cfg->regs, pres);
|
||||
|
||||
wut_cfg.mode = MXC_WUT_MODE_COMPARE;
|
||||
wut_cfg.cmp_cnt = cfg->info.max_top_value;
|
||||
MXC_WUT_Config(cfg->regs, &wut_cfg);
|
||||
|
||||
MXC_WUT_SetCount(cfg->regs, 0);
|
||||
|
||||
cfg->irq_func(dev);
|
||||
|
||||
if (cfg->wakeup_source) {
|
||||
MXC_LP_EnableWUTAlarmWakeup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct counter_driver_api counter_max32_wut_driver_api = {
|
||||
.start = counter_max32_wut_start,
|
||||
.stop = counter_max32_wut_stop,
|
||||
.get_value = counter_max32_wut_get_value,
|
||||
.set_top_value = counter_max32_wut_set_top_value,
|
||||
.get_pending_int = counter_max32_wut_get_pending_int,
|
||||
.get_top_value = counter_max32_wut_get_top_value,
|
||||
.get_freq = counter_max32_wut_get_freq,
|
||||
.set_alarm = counter_max32_wut_set_alarm,
|
||||
.cancel_alarm = counter_max32_wut_cancel_alarm,
|
||||
.get_guard_period = counter_max32_wut_get_guard_period,
|
||||
.set_guard_period = counter_max32_wut_set_guard_period,
|
||||
};
|
||||
|
||||
#define TIMER(_num) DT_INST_PARENT(_num)
|
||||
#define MAX32_TIM(idx) ((mxc_wut_regs_t *)DT_REG_ADDR(TIMER(idx)))
|
||||
|
||||
#define COUNTER_MAX32_WUT_DEFINE(_num) \
|
||||
static void max32_wut_irq_init_##_num(const struct device *dev) \
|
||||
{ \
|
||||
IRQ_CONNECT(DT_IRQN(TIMER(_num)), DT_IRQ(TIMER(_num), priority), \
|
||||
counter_max32_wut_isr, DEVICE_DT_INST_GET(_num), 0); \
|
||||
irq_enable(DT_IRQN(TIMER(_num))); \
|
||||
}; \
|
||||
static const struct max32_wut_config max32_wut_config_##_num = { \
|
||||
.info = \
|
||||
{ \
|
||||
.max_top_value = UINT32_MAX, \
|
||||
.freq = MAX32_WUT_COUNTER_FREQ / DT_PROP(TIMER(_num), prescaler), \
|
||||
.flags = COUNTER_CONFIG_INFO_COUNT_UP, \
|
||||
.channels = 1, \
|
||||
}, \
|
||||
.regs = (mxc_wut_regs_t *)DT_REG_ADDR(TIMER(_num)), \
|
||||
.clock_source = \
|
||||
DT_PROP_OR(TIMER(_num), clock_source, ADI_MAX32_PRPH_CLK_SRC_ERTCO), \
|
||||
.prescaler = DT_PROP(TIMER(_num), prescaler), \
|
||||
.irq_func = max32_wut_irq_init_##_num, \
|
||||
.irq_number = DT_IRQN(TIMER(_num)), \
|
||||
.wakeup_source = DT_PROP(TIMER(_num), wakeup_source), \
|
||||
}; \
|
||||
static struct max32_wut_data max32_wut_data##_num; \
|
||||
DEVICE_DT_INST_DEFINE(_num, &counter_max32_wut_init, NULL, &max32_wut_data##_num, \
|
||||
&max32_wut_config_##_num, PRE_KERNEL_1, \
|
||||
CONFIG_COUNTER_INIT_PRIORITY, &counter_max32_wut_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(COUNTER_MAX32_WUT_DEFINE)
|
||||
10
dts/bindings/counter/adi,max32-wut.yaml
Normal file
10
dts/bindings/counter/adi,max32-wut.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2025 Analog Devices, Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
ADI MAX32 Wake-Up Timer is a unique instance of a 32-bit timer that can wake up the
|
||||
device from sleep, standby and backup modes.
|
||||
|
||||
compatible: "adi,max32-wut"
|
||||
|
||||
include: [base.yaml]
|
||||
Loading…
Reference in New Issue
Block a user