Skip to content

Commit 5e38168

Browse files
ozersaoknshn
authored andcommitted
drivers: counter: Add MAX32xxx counter RTC driver
Common RTC counter driver for MAX32xxx MCUs. Time of day alarm is used to generate interrupt. The resolution of time of day interrupt is 1Hz. Subsecond alarm interrupt not works it does not meet zephyr counter driver requirement, so that not used. To use as wakeup source wakeup-source parameter shall be defined as below &rtc_counter { status = "okay"; wakeup-source; }; Co-authored-by: Okan Sahin <[email protected]> Signed-off-by: Sadik Ozer <[email protected]>
1 parent b4d1076 commit 5e38168

File tree

4 files changed

+278
-0
lines changed

4 files changed

+278
-0
lines changed

drivers/counter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,6 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_SNPS_DW counter_dw_timer
5050
zephyr_library_sources_ifdef(CONFIG_COUNTER_SHELL counter_timer_shell.c)
5151
zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_RPI_PICO counter_rpi_pico_timer.c)
5252
zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_MAX32 counter_max32_timer.c)
53+
zephyr_library_sources_ifdef(CONFIG_COUNTER_RTC_MAX32 counter_max32_rtc.c)
5354
zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_MRT counter_nxp_mrt.c)
5455
zephyr_library_sources_ifdef(CONFIG_COUNTER_RA_AGT counter_renesas_ra_agt.c)

drivers/counter/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ source "drivers/counter/Kconfig.rpi_pico"
9898

9999
source "drivers/counter/Kconfig.max32_timer"
100100

101+
source "drivers/counter/Kconfig.max32_rtc"
102+
101103
source "drivers/counter/Kconfig.nxp_mrt"
102104

103105
source "drivers/counter/Kconfig.renesas_ra"

drivers/counter/Kconfig.max32_rtc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2024 Analog Devices, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config COUNTER_RTC_MAX32
5+
bool "MAX32xxx counter rtc driver"
6+
default y
7+
depends on DT_HAS_ADI_MAX32_RTC_COUNTER_ENABLED
8+
help
9+
Enable the counter rtc driver for MAX32 MCUs.
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
/*
2+
* Copyright (c) 2024 Analog Devices, Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT adi_max32_rtc_counter
8+
9+
#include <zephyr/drivers/counter.h>
10+
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
#include <zephyr/irq.h>
13+
14+
#include <rtc.h>
15+
#include <wrap_max32_lp.h>
16+
17+
/* Resoultion is 1sec for time of day alarm*/
18+
#define MAX32_RTC_COUNTER_FREQ 1
19+
20+
/* 20bits used for time of day alarm */
21+
#define MAX32_RTC_COUNTER_MAX_VALUE ((1 << 21) - 1)
22+
23+
#define MAX32_RTC_COUNTER_INT_FL MXC_RTC_INT_FL_LONG
24+
#define MAX32_RTC_COUNTER_INT_EN MXC_RTC_INT_EN_LONG
25+
26+
struct max32_rtc_data {
27+
counter_alarm_callback_t alarm_callback;
28+
counter_top_callback_t top_callback;
29+
void *alarm_user_data;
30+
void *top_user_data;
31+
};
32+
33+
struct max32_rtc_config {
34+
struct counter_config_info info;
35+
mxc_rtc_regs_t *regs;
36+
void (*irq_func)(void);
37+
};
38+
39+
static int api_start(const struct device *dev)
40+
{
41+
/* Ensure that both sec and subsec are reset to 0 */
42+
while (MXC_RTC_Init(0, 0) == E_BUSY) {
43+
;
44+
}
45+
46+
while (MXC_RTC_Start() == E_BUSY) {
47+
;
48+
}
49+
50+
while (MXC_RTC_EnableInt(MAX32_RTC_COUNTER_INT_EN) == E_BUSY) {
51+
;
52+
}
53+
54+
return 0;
55+
}
56+
57+
static int api_stop(const struct device *dev)
58+
{
59+
ARG_UNUSED(dev);
60+
61+
while (MXC_RTC_DisableInt(MAX32_RTC_COUNTER_INT_EN) == E_BUSY) {
62+
;
63+
}
64+
MXC_RTC_Stop();
65+
66+
return 0;
67+
}
68+
69+
static int api_get_value(const struct device *dev, uint32_t *ticks)
70+
{
71+
const struct max32_rtc_config *cfg = dev->config;
72+
mxc_rtc_regs_t *regs = cfg->regs;
73+
uint32_t sec = 0, subsec = 0;
74+
75+
/* Read twice incase of glitch */
76+
sec = regs->sec;
77+
if (regs->sec != sec) {
78+
sec = regs->sec;
79+
}
80+
81+
/* Read twice incase of glitch */
82+
subsec = regs->ssec;
83+
if (regs->ssec != subsec) {
84+
subsec = regs->ssec;
85+
}
86+
87+
*ticks = sec;
88+
if (subsec >= (MXC_RTC_MAX_SSEC / 2)) {
89+
*ticks += 1;
90+
}
91+
92+
return 0;
93+
}
94+
95+
static int api_set_top_value(const struct device *dev, const struct counter_top_cfg *counter_cfg)
96+
{
97+
const struct max32_rtc_config *cfg = dev->config;
98+
struct max32_rtc_data *const data = dev->data;
99+
100+
if (counter_cfg->ticks == 0) {
101+
return -EINVAL;
102+
}
103+
104+
if (counter_cfg->ticks != cfg->info.max_top_value) {
105+
return -ENOTSUP;
106+
}
107+
108+
data->top_callback = counter_cfg->callback;
109+
data->top_user_data = counter_cfg->user_data;
110+
111+
return 0;
112+
}
113+
114+
static uint32_t api_get_pending_int(const struct device *dev)
115+
{
116+
ARG_UNUSED(dev);
117+
int flags = MXC_RTC_GetFlags();
118+
119+
if (flags & MAX32_RTC_COUNTER_INT_FL) {
120+
return 1;
121+
}
122+
123+
return 0;
124+
}
125+
126+
static uint32_t api_get_top_value(const struct device *dev)
127+
{
128+
const struct max32_rtc_config *cfg = dev->config;
129+
130+
return cfg->info.max_top_value;
131+
}
132+
133+
static int api_set_alarm(const struct device *dev, uint8_t chan,
134+
const struct counter_alarm_cfg *alarm_cfg)
135+
{
136+
int ret;
137+
struct max32_rtc_data *data = dev->data;
138+
uint32_t ticks = alarm_cfg->ticks;
139+
uint32_t current;
140+
141+
/* Alarm frequenct is 1Hz so that it seems ticks becomes 0
142+
* some times, in that case system being blocked.
143+
* Set it to 1 if ticks is 0
144+
*/
145+
if (ticks == 0) {
146+
ticks = 1;
147+
}
148+
149+
if (alarm_cfg->ticks > api_get_top_value(dev)) {
150+
return -EINVAL;
151+
}
152+
153+
if (data->alarm_callback != NULL) {
154+
return -EBUSY;
155+
}
156+
157+
api_stop(dev);
158+
159+
api_get_value(dev, &current);
160+
if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
161+
ticks += current;
162+
}
163+
164+
ret = MXC_RTC_SetTimeofdayAlarm(ticks);
165+
if (ret == E_BUSY) {
166+
ret = -EBUSY;
167+
}
168+
169+
if (ret == 0) {
170+
data->alarm_callback = alarm_cfg->callback;
171+
data->alarm_user_data = alarm_cfg->user_data;
172+
}
173+
174+
api_start(dev);
175+
176+
return ret;
177+
}
178+
179+
static int api_cancel_alarm(const struct device *dev, uint8_t chan)
180+
{
181+
struct max32_rtc_data *data = dev->data;
182+
183+
while (MXC_RTC_DisableInt(MAX32_RTC_COUNTER_INT_EN) == E_BUSY) {
184+
;
185+
}
186+
data->alarm_callback = NULL;
187+
188+
return 0;
189+
}
190+
191+
static void rtc_max32_isr(const struct device *dev)
192+
{
193+
struct max32_rtc_data *const data = dev->data;
194+
int flags = MXC_RTC_GetFlags();
195+
196+
if (flags & MAX32_RTC_COUNTER_INT_FL) {
197+
if (data->alarm_callback) {
198+
counter_alarm_callback_t cb;
199+
uint32_t current;
200+
201+
api_get_value(dev, &current);
202+
203+
cb = data->alarm_callback;
204+
data->alarm_callback = NULL;
205+
cb(dev, 0, current, data->alarm_user_data);
206+
}
207+
}
208+
209+
/* Clear all flags */
210+
MXC_RTC_ClearFlags(flags);
211+
}
212+
213+
static int rtc_max32_init(const struct device *dev)
214+
{
215+
const struct max32_rtc_config *cfg = dev->config;
216+
217+
while (MXC_RTC_Init(0, 0) == E_BUSY) {
218+
;
219+
}
220+
221+
api_stop(dev);
222+
223+
cfg->irq_func();
224+
225+
return 0;
226+
}
227+
228+
static const struct counter_driver_api counter_rtc_max32_driver_api = {
229+
.start = api_start,
230+
.stop = api_stop,
231+
.get_value = api_get_value,
232+
.set_top_value = api_set_top_value,
233+
.get_pending_int = api_get_pending_int,
234+
.get_top_value = api_get_top_value,
235+
.set_alarm = api_set_alarm,
236+
.cancel_alarm = api_cancel_alarm,
237+
};
238+
239+
#define COUNTER_RTC_MAX32_INIT(_num) \
240+
static struct max32_rtc_data rtc_max32_data_##_num; \
241+
static void max32_rtc_irq_init_##_num(void) \
242+
{ \
243+
IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), rtc_max32_isr, \
244+
DEVICE_DT_INST_GET(_num), 0); \
245+
irq_enable(DT_INST_IRQN(_num)); \
246+
if (DT_INST_PROP(_num, wakeup_source)) { \
247+
MXC_LP_EnableRTCAlarmWakeup(); \
248+
} \
249+
}; \
250+
static const struct max32_rtc_config rtc_max32_config_##_num = { \
251+
.info = \
252+
{ \
253+
.max_top_value = MAX32_RTC_COUNTER_MAX_VALUE, \
254+
.freq = MAX32_RTC_COUNTER_FREQ, \
255+
.flags = COUNTER_CONFIG_INFO_COUNT_UP, \
256+
.channels = 1, \
257+
}, \
258+
.regs = (mxc_rtc_regs_t *)DT_INST_REG_ADDR(_num), \
259+
.irq_func = max32_rtc_irq_init_##_num, \
260+
}; \
261+
\
262+
DEVICE_DT_INST_DEFINE(_num, &rtc_max32_init, NULL, &rtc_max32_data_##_num, \
263+
&rtc_max32_config_##_num, PRE_KERNEL_1, \
264+
CONFIG_COUNTER_INIT_PRIORITY, &counter_rtc_max32_driver_api);
265+
266+
DT_INST_FOREACH_STATUS_OKAY(COUNTER_RTC_MAX32_INIT)

0 commit comments

Comments
 (0)