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