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_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 <wrap_max32_tmr.h>
15
16 /** MAX32 MCUs does not have multiple channels */
17 #define MAX32_TIMER_CH 1U
18
19 struct max32_tmr_data {
20 counter_top_callback_t top_callback;
21 void *top_user_data;
22 uint32_t guard_period;
23 };
24
25 struct max32_tmr_ch_data {
26 counter_alarm_callback_t callback;
27 void *user_data;
28 };
29
30 struct max32_tmr_config {
31 struct counter_config_info info;
32 struct max32_tmr_ch_data *ch_data;
33 mxc_tmr_regs_t *regs;
34 const struct device *clock;
35 struct max32_perclk perclk;
36 int clock_source;
37 int prescaler;
38 void (*irq_func)(const struct device *dev);
39 bool wakeup_source;
40 };
41
api_start(const struct device * dev)42 static int api_start(const struct device *dev)
43 {
44 const struct max32_tmr_config *cfg = dev->config;
45
46 Wrap_MXC_TMR_EnableInt(cfg->regs);
47 MXC_TMR_Start(cfg->regs);
48
49 return 0;
50 }
51
api_stop(const struct device * dev)52 static int api_stop(const struct device *dev)
53 {
54 const struct max32_tmr_config *cfg = dev->config;
55
56 Wrap_MXC_TMR_DisableInt(cfg->regs);
57 MXC_TMR_Stop(cfg->regs);
58
59 return 0;
60 }
61
api_get_value(const struct device * dev,uint32_t * ticks)62 static int api_get_value(const struct device *dev, uint32_t *ticks)
63 {
64 const struct max32_tmr_config *cfg = dev->config;
65
66 *ticks = MXC_TMR_GetCount(cfg->regs);
67 return 0;
68 }
69
api_set_top_value(const struct device * dev,const struct counter_top_cfg * counter_cfg)70 static int api_set_top_value(const struct device *dev, const struct counter_top_cfg *counter_cfg)
71 {
72 const struct max32_tmr_config *cfg = dev->config;
73
74 if (counter_cfg->ticks == 0) {
75 return -EINVAL;
76 }
77
78 if (counter_cfg->ticks != cfg->info.max_top_value) {
79 return -ENOTSUP;
80 }
81
82 return 0;
83 }
84
api_get_pending_int(const struct device * dev)85 static uint32_t api_get_pending_int(const struct device *dev)
86 {
87 const struct max32_tmr_config *cfg = dev->config;
88
89 return Wrap_MXC_TMR_GetPendingInt(cfg->regs);
90 }
91
api_get_top_value(const struct device * dev)92 static uint32_t api_get_top_value(const struct device *dev)
93 {
94 const struct max32_tmr_config *cfg = dev->config;
95
96 return cfg->info.max_top_value;
97 }
98
api_get_freq(const struct device * dev)99 static uint32_t api_get_freq(const struct device *dev)
100 {
101 const struct max32_tmr_config *cfg = dev->config;
102
103 return cfg->info.freq;
104 }
105
set_cc(const struct device * dev,uint8_t id,uint32_t val,uint32_t flags)106 static int set_cc(const struct device *dev, uint8_t id, uint32_t val, uint32_t flags)
107 {
108 const struct max32_tmr_config *config = dev->config;
109 struct max32_tmr_data *data = dev->data;
110 mxc_tmr_regs_t *regs = config->regs;
111
112 bool absolute = flags & COUNTER_ALARM_CFG_ABSOLUTE;
113 uint32_t top = api_get_top_value(dev);
114 int err = 0;
115 uint32_t now;
116 uint32_t diff;
117 uint32_t max_rel_val = top;
118 bool irq_on_late = 0;
119
120 now = MXC_TMR_GetCount(regs);
121 MXC_TMR_ClearFlags(regs);
122
123 if (absolute) {
124 max_rel_val = top - data->guard_period;
125 irq_on_late = flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE;
126 } else {
127 val = now + val;
128 }
129
130 MXC_TMR_SetCompare(regs, val);
131 now = MXC_TMR_GetCount(regs);
132
133 diff = (val - now);
134 if (diff > max_rel_val) {
135 if (absolute) {
136 err = -ETIME;
137 }
138
139 /* Interrupt is triggered always for relative alarm and
140 * for absolute depending on the flag.
141 */
142 if (irq_on_late) {
143 NVIC_SetPendingIRQ(MXC_TMR_GET_IRQ(MXC_TMR_GET_IDX(regs)));
144 } else {
145 config->ch_data[id].callback = NULL;
146 }
147 } else {
148 api_start(dev);
149 }
150
151 return err;
152 }
153
api_set_alarm(const struct device * dev,uint8_t chan,const struct counter_alarm_cfg * alarm_cfg)154 static int api_set_alarm(const struct device *dev, uint8_t chan,
155 const struct counter_alarm_cfg *alarm_cfg)
156 {
157 const struct max32_tmr_config *cfg = dev->config;
158 struct max32_tmr_ch_data *chdata = &cfg->ch_data[chan];
159
160 if (alarm_cfg->ticks > api_get_top_value(dev)) {
161 return -EINVAL;
162 }
163
164 if (chdata->callback) {
165 return -EBUSY;
166 }
167
168 chdata->callback = alarm_cfg->callback;
169 chdata->user_data = alarm_cfg->user_data;
170
171 return set_cc(dev, chan, alarm_cfg->ticks, alarm_cfg->flags);
172 }
173
api_cancel_alarm(const struct device * dev,uint8_t chan)174 static int api_cancel_alarm(const struct device *dev, uint8_t chan)
175 {
176 const struct max32_tmr_config *cfg = dev->config;
177
178 MXC_TMR_Stop(cfg->regs);
179 MXC_TMR_SetCount(cfg->regs, 0);
180 MXC_TMR_SetCompare(cfg->regs, cfg->info.max_top_value);
181 Wrap_MXC_TMR_DisableInt(cfg->regs);
182 cfg->ch_data[chan].callback = NULL;
183
184 return 0;
185 }
186
api_get_guard_period(const struct device * dev,uint32_t flags)187 static uint32_t api_get_guard_period(const struct device *dev, uint32_t flags)
188 {
189 struct max32_tmr_data *data = dev->data;
190
191 ARG_UNUSED(flags);
192
193 return data->guard_period;
194 }
195
api_set_guard_period(const struct device * dev,uint32_t ticks,uint32_t flags)196 static int api_set_guard_period(const struct device *dev, uint32_t ticks, uint32_t flags)
197 {
198 struct max32_tmr_data *data = dev->data;
199
200 ARG_UNUSED(flags);
201
202 if (ticks > api_get_top_value(dev)) {
203 return -EINVAL;
204 }
205
206 data->guard_period = ticks;
207 return 0;
208 }
209
max32_alarm_irq_handle(const struct device * dev,uint32_t id)210 static void max32_alarm_irq_handle(const struct device *dev, uint32_t id)
211 {
212 const struct max32_tmr_config *cfg = dev->config;
213 struct max32_tmr_ch_data *chdata;
214 counter_alarm_callback_t cb;
215
216 chdata = &cfg->ch_data[id];
217 cb = chdata->callback;
218 chdata->callback = NULL;
219
220 if (cb) {
221 cb(dev, id, MXC_TMR_GetCount(cfg->regs), chdata->user_data);
222 }
223 }
224
counter_max32_isr(const struct device * dev)225 static void counter_max32_isr(const struct device *dev)
226 {
227 const struct max32_tmr_config *cfg = dev->config;
228 struct max32_tmr_data *data = dev->data;
229
230 MXC_TMR_ClearFlags(cfg->regs);
231 Wrap_MXC_TMR_ClearWakeupFlags(cfg->regs);
232
233 max32_alarm_irq_handle(dev, 0);
234
235 if (data->top_callback) {
236 data->top_callback(dev, data->top_user_data);
237 }
238 }
239
max32_counter_init(const struct device * dev)240 static int max32_counter_init(const struct device *dev)
241 {
242 int ret = 0;
243 const struct max32_tmr_config *cfg = dev->config;
244 mxc_tmr_regs_t *regs = cfg->regs;
245 wrap_mxc_tmr_cfg_t tmr_cfg;
246 int prescaler_index;
247
248 prescaler_index = LOG2(cfg->prescaler);
249 if (prescaler_index == 0) {
250 tmr_cfg.pres = TMR_PRES_1; /* TMR_PRES_1 is 0 */
251 } else {
252 /* TMR_PRES_2 is 1<<X */
253 tmr_cfg.pres = TMR_PRES_2 + (prescaler_index - 1);
254 }
255 tmr_cfg.mode = TMR_MODE_COMPARE;
256 tmr_cfg.cmp_cnt = cfg->info.max_top_value;
257 tmr_cfg.bitMode = 0; /* Timer Mode 32 bit */
258 tmr_cfg.pol = 0;
259
260 tmr_cfg.clock = Wrap_MXC_TMR_GetClockIndex(cfg->clock_source);
261 if (tmr_cfg.clock < 0) {
262 return -ENOTSUP;
263 }
264
265 MXC_TMR_Shutdown(regs);
266
267 /* enable clock */
268 ret = clock_control_on(cfg->clock, (clock_control_subsys_t)&cfg->perclk);
269 if (ret) {
270 return ret;
271 }
272
273 ret = Wrap_MXC_TMR_Init(regs, &tmr_cfg);
274 if (ret != E_NO_ERROR) {
275 return ret;
276 }
277
278 /* Set preload and actually pre-load the counter */
279 MXC_TMR_SetCompare(regs, cfg->info.max_top_value);
280
281 cfg->irq_func(dev);
282
283 if (cfg->wakeup_source) {
284 /* Clear Wakeup status */
285 MXC_LP_ClearWakeStatus();
286 /* Enable Timer wake-up source */
287 Wrap_MXC_TMR_EnableWakeup(regs, &tmr_cfg);
288 }
289
290 return 0;
291 }
292
293 static DEVICE_API(counter, counter_max32_driver_api) = {
294 .start = api_start,
295 .stop = api_stop,
296 .get_value = api_get_value,
297 .set_top_value = api_set_top_value,
298 .get_pending_int = api_get_pending_int,
299 .get_top_value = api_get_top_value,
300 .get_freq = api_get_freq,
301 .set_alarm = api_set_alarm,
302 .cancel_alarm = api_cancel_alarm,
303 .get_guard_period = api_get_guard_period,
304 .set_guard_period = api_set_guard_period,
305 };
306
307 #define TIMER(_num) DT_INST_PARENT(_num)
308 #define MAX32_TIM(idx) ((mxc_tmr_regs_t *)DT_REG_ADDR(TIMER(idx)))
309
310 #define COUNTER_MAX32_DEFINE(_num) \
311 static struct max32_tmr_ch_data counter##_num##_ch_data[MAX32_TIMER_CH]; \
312 static void max32_tmr_irq_init_##_num(const struct device *dev) \
313 { \
314 IRQ_CONNECT(DT_IRQN(TIMER(_num)), DT_IRQ(TIMER(_num), priority), \
315 counter_max32_isr, DEVICE_DT_INST_GET(_num), 0); \
316 irq_enable(DT_IRQN(TIMER(_num))); \
317 }; \
318 static const struct max32_tmr_config max32_tmr_config_##_num = { \
319 .info = \
320 { \
321 .max_top_value = WRAP_MXC_IS_32B_TIMER(MAX32_TIM(_num)) \
322 ? UINT32_MAX \
323 : UINT16_MAX, \
324 .freq = ADI_MAX32_GET_PRPH_CLK_FREQ( \
325 DT_PROP(TIMER(_num), clock_source)) / \
326 DT_PROP(TIMER(_num), prescaler), \
327 .flags = COUNTER_CONFIG_INFO_COUNT_UP, \
328 .channels = MAX32_TIMER_CH, \
329 }, \
330 .regs = (mxc_tmr_regs_t *)DT_REG_ADDR(TIMER(_num)), \
331 .clock = DEVICE_DT_GET(DT_CLOCKS_CTLR(TIMER(_num))), \
332 .perclk.bus = DT_CLOCKS_CELL(TIMER(_num), offset), \
333 .perclk.bit = DT_CLOCKS_CELL(TIMER(_num), bit), \
334 .clock_source = DT_PROP(TIMER(_num), clock_source), \
335 .prescaler = DT_PROP(TIMER(_num), prescaler), \
336 .irq_func = max32_tmr_irq_init_##_num, \
337 .ch_data = counter##_num##_ch_data, \
338 .wakeup_source = DT_PROP(TIMER(_num), wakeup_source), \
339 }; \
340 static struct max32_tmr_data max32_tmr_data##_num; \
341 DEVICE_DT_INST_DEFINE(_num, &max32_counter_init, NULL, &max32_tmr_data##_num, \
342 &max32_tmr_config_##_num, PRE_KERNEL_1, \
343 CONFIG_COUNTER_INIT_PRIORITY, &counter_max32_driver_api);
344
345 DT_INST_FOREACH_STATUS_OKAY(COUNTER_MAX32_DEFINE)
346