1 /*
2  * Copyright (c) 2021, Piotr Mienkowski
3  * Copyright (c) 2023, Gerson Fernando Budke
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT atmel_sam_tc
9 
10 /** @file
11  * @brief Atmel SAM MCU family counter (TC) driver.
12  *
13  * This version of the driver uses a single channel to provide a basic 16-bit
14  * counter (on SAM4E series the counter is 32-bit). Remaining TC channels could
15  * be used in the future to provide additional functionality, e.g. input clock
16  * divider configured via DT properties.
17  *
18  * Remarks:
19  * - The driver is not thread safe.
20  * - The driver does not implement guard periods.
21  * - The driver does not guarantee that short relative alarm will trigger the
22  *   interrupt immediately and not after the full cycle / counter overflow.
23  *
24  * Use at your own risk or submit a patch.
25  */
26 
27 #include <errno.h>
28 #include <zephyr/sys/__assert.h>
29 #include <zephyr/sys/util.h>
30 #include <zephyr/device.h>
31 #include <zephyr/init.h>
32 #include <soc.h>
33 #include <zephyr/drivers/counter.h>
34 #include <zephyr/drivers/pinctrl.h>
35 #include <zephyr/drivers/clock_control/atmel_sam_pmc.h>
36 
37 #include <zephyr/logging/log.h>
38 #include <zephyr/irq.h>
39 LOG_MODULE_REGISTER(counter_sam_tc, CONFIG_COUNTER_LOG_LEVEL);
40 
41 #define MAX_ALARMS_PER_TC_CHANNEL 2
42 #if defined(CONFIG_SOC_SERIES_SAM4E) || defined(CONFIG_SOC_SERIES_SAM3X)
43 #define COUNTER_SAM_TOP_VALUE_MAX UINT32_MAX
44 #else
45 #define COUNTER_SAM_TOP_VALUE_MAX UINT16_MAX
46 #define COUNTER_SAM_16_BIT
47 #endif
48 
49 /* Device constant configuration parameters */
50 struct counter_sam_dev_cfg {
51 	struct counter_config_info info;
52 	Tc *regs;
53 	uint32_t reg_cmr;
54 	uint32_t reg_rc;
55 	void (*irq_config_func)(const struct device *dev);
56 	const struct atmel_sam_pmc_config clock_cfg[TCCHANNEL_NUMBER];
57 	const struct pinctrl_dev_config *pcfg;
58 	uint8_t clk_sel;
59 	bool nodivclk;
60 	uint8_t tc_chan_num;
61 };
62 
63 struct counter_sam_alarm_data {
64 	counter_alarm_callback_t callback;
65 	void *user_data;
66 };
67 
68 /* Device run time data */
69 struct counter_sam_dev_data {
70 	counter_top_callback_t top_cb;
71 	void *top_user_data;
72 
73 	struct counter_sam_alarm_data alarm[MAX_ALARMS_PER_TC_CHANNEL];
74 };
75 
76 static const uint32_t sam_tc_input_freq_table[] = {
77 #if defined(CONFIG_SOC_SERIES_SAME70) || defined(CONFIG_SOC_SERIES_SAMV71)
78 	USEC_PER_SEC,
79 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 8,
80 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 32,
81 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 128,
82 	32768,
83 #elif defined(CONFIG_SOC_SERIES_SAM4L)
84 	USEC_PER_SEC,
85 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 2,
86 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 8,
87 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 32,
88 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 128,
89 #else
90 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 2,
91 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 8,
92 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 32,
93 	SOC_ATMEL_SAM_MCK_FREQ_HZ / 128,
94 	32768,
95 #endif
96 	USEC_PER_SEC, USEC_PER_SEC, USEC_PER_SEC,
97 };
98 
counter_sam_tc_start(const struct device * dev)99 static int counter_sam_tc_start(const struct device *dev)
100 {
101 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
102 	Tc *tc = dev_cfg->regs;
103 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
104 
105 	tc_ch->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
106 
107 	return 0;
108 }
109 
counter_sam_tc_stop(const struct device * dev)110 static int counter_sam_tc_stop(const struct device *dev)
111 {
112 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
113 	Tc *tc = dev_cfg->regs;
114 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
115 
116 	tc_ch->TC_CCR = TC_CCR_CLKDIS;
117 
118 	return 0;
119 }
120 
counter_sam_tc_get_value(const struct device * dev,uint32_t * ticks)121 static int counter_sam_tc_get_value(const struct device *dev, uint32_t *ticks)
122 {
123 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
124 	Tc *tc = dev_cfg->regs;
125 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
126 
127 	*ticks = tc_ch->TC_CV;
128 
129 	return 0;
130 }
131 
counter_sam_tc_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)132 static int counter_sam_tc_set_alarm(const struct device *dev, uint8_t chan_id,
133 				    const struct counter_alarm_cfg *alarm_cfg)
134 {
135 	struct counter_sam_dev_data *data = dev->data;
136 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
137 	Tc *tc = dev_cfg->regs;
138 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
139 	uint32_t top_value;
140 	uint32_t alarm_value;
141 
142 	__ASSERT_NO_MSG(alarm_cfg->callback != NULL);
143 
144 	top_value = tc_ch->TC_RC;
145 
146 	if ((top_value != 0) && (alarm_cfg->ticks > top_value)) {
147 		return -EINVAL;
148 	}
149 
150 #ifdef COUNTER_SAM_16_BIT
151 	if ((top_value == 0) && (alarm_cfg->ticks > UINT16_MAX)) {
152 		return -EINVAL;
153 	}
154 #endif
155 
156 	if (data->alarm[chan_id].callback != NULL) {
157 		return -EBUSY;
158 	}
159 
160 	if (chan_id == 0) {
161 		tc_ch->TC_IDR = TC_IDR_CPAS;
162 	} else {
163 		tc_ch->TC_IDR = TC_IDR_CPBS;
164 	}
165 
166 	data->alarm[chan_id].callback = alarm_cfg->callback;
167 	data->alarm[chan_id].user_data = alarm_cfg->user_data;
168 
169 	if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) != 0) {
170 		alarm_value = alarm_cfg->ticks;
171 	} else {
172 		alarm_value = tc_ch->TC_CV + alarm_cfg->ticks;
173 		if (top_value != 0) {
174 			alarm_value %= top_value;
175 		}
176 	}
177 
178 	if (chan_id == 0) {
179 		tc_ch->TC_RA = alarm_value;
180 		/* Clear interrupt status register */
181 		(void)tc_ch->TC_SR;
182 		tc_ch->TC_IER = TC_IER_CPAS;
183 	} else {
184 		tc_ch->TC_RB = alarm_value;
185 		/* Clear interrupt status register */
186 		(void)tc_ch->TC_SR;
187 		tc_ch->TC_IER = TC_IER_CPBS;
188 	}
189 
190 	LOG_DBG("set alarm: channel %u, count %u", chan_id, alarm_value);
191 
192 	return 0;
193 }
194 
counter_sam_tc_cancel_alarm(const struct device * dev,uint8_t chan_id)195 static int counter_sam_tc_cancel_alarm(const struct device *dev, uint8_t chan_id)
196 {
197 	struct counter_sam_dev_data *data = dev->data;
198 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
199 	Tc *tc = dev_cfg->regs;
200 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
201 
202 	if (chan_id == 0) {
203 		tc_ch->TC_IDR = TC_IDR_CPAS;
204 		tc_ch->TC_RA = 0;
205 	} else {
206 		tc_ch->TC_IDR = TC_IDR_CPBS;
207 		tc_ch->TC_RB = 0;
208 	}
209 
210 	data->alarm[chan_id].callback = NULL;
211 	data->alarm[chan_id].user_data = NULL;
212 
213 	LOG_DBG("cancel alarm: channel %u", chan_id);
214 
215 	return 0;
216 }
217 
counter_sam_tc_set_top_value(const struct device * dev,const struct counter_top_cfg * top_cfg)218 static int counter_sam_tc_set_top_value(const struct device *dev,
219 					const struct counter_top_cfg *top_cfg)
220 {
221 	struct counter_sam_dev_data *data = dev->data;
222 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
223 	Tc *tc = dev_cfg->regs;
224 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
225 	int ret = 0;
226 
227 	for (int i = 0; i < MAX_ALARMS_PER_TC_CHANNEL; i++) {
228 		if (data->alarm[i].callback) {
229 			return -EBUSY;
230 		}
231 	}
232 
233 	/* Disable the compare interrupt */
234 	tc_ch->TC_IDR = TC_IDR_CPCS;
235 
236 	data->top_cb = top_cfg->callback;
237 	data->top_user_data = top_cfg->user_data;
238 
239 	tc_ch->TC_RC = top_cfg->ticks;
240 
241 	if ((top_cfg->flags & COUNTER_TOP_CFG_DONT_RESET) != 0) {
242 		if (tc_ch->TC_CV >= top_cfg->ticks) {
243 			ret = -ETIME;
244 			if ((top_cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) != 0) {
245 				tc_ch->TC_CCR = TC_CCR_SWTRG;
246 			}
247 		}
248 	} else {
249 		tc_ch->TC_CCR = TC_CCR_SWTRG;
250 	}
251 
252 	/* Enable the compare interrupt */
253 	tc_ch->TC_IER = TC_IER_CPCS;
254 
255 	return ret;
256 }
257 
counter_sam_tc_get_top_value(const struct device * dev)258 static uint32_t counter_sam_tc_get_top_value(const struct device *dev)
259 {
260 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
261 	Tc *tc = dev_cfg->regs;
262 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
263 
264 	return tc_ch->TC_RC;
265 }
266 
counter_sam_tc_get_pending_int(const struct device * dev)267 static uint32_t counter_sam_tc_get_pending_int(const struct device *dev)
268 {
269 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
270 	Tc *tc = dev_cfg->regs;
271 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
272 
273 	return tc_ch->TC_SR & tc_ch->TC_IMR;
274 }
275 
counter_sam_tc_isr(const struct device * dev)276 static void counter_sam_tc_isr(const struct device *dev)
277 {
278 	struct counter_sam_dev_data *data = dev->data;
279 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
280 	Tc *tc = dev_cfg->regs;
281 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
282 	uint32_t status;
283 
284 	status = tc_ch->TC_SR;
285 
286 	if ((status & TC_SR_CPAS) != 0) {
287 		tc_ch->TC_IDR = TC_IDR_CPAS;
288 		if (data->alarm[0].callback) {
289 			counter_alarm_callback_t cb = data->alarm[0].callback;
290 
291 			data->alarm[0].callback = NULL;
292 			cb(dev, 0, tc_ch->TC_RA, data->alarm[0].user_data);
293 		}
294 	}
295 
296 	if ((status & TC_SR_CPBS) != 0) {
297 		tc_ch->TC_IDR = TC_IDR_CPBS;
298 		if (data->alarm[1].callback) {
299 			counter_alarm_callback_t cb = data->alarm[1].callback;
300 
301 			data->alarm[1].callback = NULL;
302 			cb(dev, 1, tc_ch->TC_RB, data->alarm[1].user_data);
303 		}
304 	}
305 
306 	if ((status & TC_SR_CPCS) != 0) {
307 		if (data->top_cb) {
308 			data->top_cb(dev, data->top_user_data);
309 		}
310 	}
311 }
312 
counter_sam_initialize(const struct device * dev)313 static int counter_sam_initialize(const struct device *dev)
314 {
315 	const struct counter_sam_dev_cfg *const dev_cfg = dev->config;
316 	Tc *const tc = dev_cfg->regs;
317 	TcChannel *tc_ch = &tc->TcChannel[dev_cfg->tc_chan_num];
318 	int retval;
319 
320 	/* Connect pins to the peripheral */
321 	retval = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
322 	if (retval < 0) {
323 		return retval;
324 	}
325 
326 	/* Enable channel's clock */
327 	(void)clock_control_on(SAM_DT_PMC_CONTROLLER,
328 			       (clock_control_subsys_t)&dev_cfg->clock_cfg[dev_cfg->tc_chan_num]);
329 
330 	/* Clock and Mode Selection */
331 	tc_ch->TC_CMR = dev_cfg->reg_cmr;
332 	tc_ch->TC_RC = dev_cfg->reg_rc;
333 
334 #ifdef TC_EMR_NODIVCLK
335 	if (dev_cfg->nodivclk) {
336 		tc_ch->TC_EMR = TC_EMR_NODIVCLK;
337 	}
338 #endif
339 	dev_cfg->irq_config_func(dev);
340 
341 	LOG_INF("Device %s initialized", dev->name);
342 
343 	return 0;
344 }
345 
346 static const struct counter_driver_api counter_sam_driver_api = {
347 	.start = counter_sam_tc_start,
348 	.stop = counter_sam_tc_stop,
349 	.get_value = counter_sam_tc_get_value,
350 	.set_alarm = counter_sam_tc_set_alarm,
351 	.cancel_alarm = counter_sam_tc_cancel_alarm,
352 	.set_top_value = counter_sam_tc_set_top_value,
353 	.get_top_value = counter_sam_tc_get_top_value,
354 	.get_pending_int = counter_sam_tc_get_pending_int,
355 };
356 
357 #define COUNTER_SAM_TC_CMR(n)	\
358 		 (TC_CMR_TCCLKS(DT_INST_PROP_OR(n, clk, 0)) \
359 		| TC_CMR_WAVEFORM_WAVSEL_UP_RC \
360 		| TC_CMR_WAVE)
361 
362 #define COUNTER_SAM_TC_REG_CMR(n) \
363 		DT_INST_PROP_OR(n, reg_cmr, COUNTER_SAM_TC_CMR(n))
364 
365 #define COUNTER_SAM_TC_INPUT_FREQUENCY(n)	\
366 		COND_CODE_1(DT_INST_PROP(n, nodivclk), \
367 			    (SOC_ATMEL_SAM_MCK_FREQ_HZ), \
368 			    (sam_tc_input_freq_table[COUNTER_SAM_TC_REG_CMR(n) \
369 						     & TC_CMR_TCCLKS_Msk]))
370 
371 #define COUNTER_SAM_TC_INIT(n)					\
372 PINCTRL_DT_INST_DEFINE(n);					\
373 								\
374 static void counter_##n##_sam_config_func(const struct device *dev); \
375 								\
376 static const struct counter_sam_dev_cfg counter_##n##_sam_config = { \
377 	.info = {						\
378 		.max_top_value = COUNTER_SAM_TOP_VALUE_MAX,	\
379 		.freq = COUNTER_SAM_TC_INPUT_FREQUENCY(n),	\
380 		.flags = COUNTER_CONFIG_INFO_COUNT_UP,		\
381 		.channels = MAX_ALARMS_PER_TC_CHANNEL		\
382 	},							\
383 	.regs = (Tc *)DT_INST_REG_ADDR(n),			\
384 	.reg_cmr = COUNTER_SAM_TC_REG_CMR(n),			\
385 	.reg_rc = DT_INST_PROP_OR(n, reg_rc, 0),		\
386 	.irq_config_func = &counter_##n##_sam_config_func,	\
387 	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),		\
388 	.nodivclk = DT_INST_PROP(n, nodivclk),			\
389 	.tc_chan_num = DT_INST_PROP_OR(n, channel, 0),		\
390 	.clock_cfg = SAM_DT_INST_CLOCKS_PMC_CFG(n),		\
391 };								\
392 								\
393 static struct counter_sam_dev_data counter_##n##_sam_data;	\
394 								\
395 DEVICE_DT_INST_DEFINE(n, counter_sam_initialize, NULL, \
396 		&counter_##n##_sam_data, &counter_##n##_sam_config, \
397 		PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY,	\
398 		&counter_sam_driver_api);			\
399 								\
400 static void counter_##n##_sam_config_func(const struct device *dev) \
401 {								\
402 	IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq),		\
403 		    DT_INST_IRQ_BY_IDX(n, 0, priority),		\
404 		    counter_sam_tc_isr,				\
405 		    DEVICE_DT_INST_GET(n), 0);			\
406 	irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq));		\
407 								\
408 	IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 1, irq),		\
409 		    DT_INST_IRQ_BY_IDX(n, 1, priority),		\
410 		    counter_sam_tc_isr,				\
411 		    DEVICE_DT_INST_GET(n), 0);			\
412 	irq_enable(DT_INST_IRQ_BY_IDX(n, 1, irq));		\
413 								\
414 	IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 2, irq),		\
415 		    DT_INST_IRQ_BY_IDX(n, 2, priority),		\
416 		    counter_sam_tc_isr,				\
417 		    DEVICE_DT_INST_GET(n), 0);			\
418 	irq_enable(DT_INST_IRQ_BY_IDX(n, 2, irq));		\
419 }
420 
421 DT_INST_FOREACH_STATUS_OKAY(COUNTER_SAM_TC_INIT)
422