1 /*
2  * Copyright (c) 2021, Sateesh Kotapati
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT silabs_gecko_stimer
8 
9 #include <errno.h>
10 #include <stddef.h>
11 #include <string.h>
12 
13 #include <zephyr/device.h>
14 #include <zephyr/drivers/counter.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/logging/log.h>
17 
18 #include <em_cmu.h>
19 #include <sl_atomic.h>
20 #include <sl_sleeptimer.h>
21 #include <sli_sleeptimer_hal.h>
22 
23 LOG_MODULE_REGISTER(counter_gecko, CONFIG_COUNTER_LOG_LEVEL);
24 
25 #if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_RTCC
26 #define STIMER_IRQ_HANDLER RTCC_IRQHandler
27 #define STIMER_MAX_VALUE _RTCC_CNT_MASK
28 #elif SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC
29 #define STIMER_IRQ_HANDLER SYSRTC_APP_IRQHandler
30 #define STIMER_MAX_VALUE _SYSRTC_CNT_MASK
31 #else
32 #error "Unsupported sleep timer peripheral"
33 #endif
34 
35 #define STIMER_ALARM_NUM 2
36 
37 struct counter_gecko_config {
38 	struct counter_config_info info;
39 	void (*irq_config)(void);
40 	uint32_t prescaler;
41 };
42 
43 struct counter_gecko_alarm_data {
44 	counter_alarm_callback_t callback;
45 	uint8_t chan_id;
46 	uint32_t ticks;
47 	struct device *dev;
48 	void *user_data;
49 };
50 
51 struct counter_gecko_top_data {
52 	counter_top_callback_t callback;
53 	uint32_t ticks;
54 	struct device *dev;
55 	void *user_data;
56 };
57 
58 struct counter_gecko_data {
59 	struct counter_gecko_alarm_data alarm[STIMER_ALARM_NUM];
60 	struct counter_gecko_top_data top_data;
61 };
62 
63 static sl_sleeptimer_timer_handle_t alarm_timer[STIMER_ALARM_NUM];
64 static sl_sleeptimer_timer_handle_t top_timer;
65 
66 #ifdef CONFIG_SOC_GECKO_HAS_ERRATA_RTCC_E201
67 #define ERRATA_RTCC_E201_MESSAGE                                                                   \
68 	"Errata RTCC_E201: In case RTCC prescaler != 1 the module does not "                       \
69 	"reset the counter value on CCV1 compare."
70 #endif
71 
alarm_callback(sl_sleeptimer_timer_handle_t * handle,void * data)72 static void alarm_callback(sl_sleeptimer_timer_handle_t *handle, void *data)
73 {
74 	struct counter_gecko_alarm_data *alarm_data = (struct counter_gecko_alarm_data *)data;
75 	uint32_t count =
76 		((sl_sleeptimer_get_tick_count()) %
77 		 (((struct counter_gecko_data *const)(alarm_data->dev)->data)->top_data.ticks));
78 
79 	if (alarm_data->callback != NULL) {
80 		alarm_data->callback(
81 			alarm_data->dev, alarm_data->chan_id, count,
82 			((struct counter_alarm_cfg *)(alarm_data->user_data))->user_data);
83 	}
84 }
85 
top_callback(sl_sleeptimer_timer_handle_t * handle,void * data)86 static void top_callback(sl_sleeptimer_timer_handle_t *handle, void *data)
87 {
88 	struct counter_gecko_top_data *top_data = (struct counter_gecko_top_data *)data;
89 
90 	if (top_data->callback != NULL) {
91 		top_data->callback(top_data->dev,
92 				   ((struct counter_top_cfg *)(top_data->user_data))->user_data);
93 	}
94 }
95 
counter_gecko_get_value(const struct device * dev,uint32_t * ticks)96 static int counter_gecko_get_value(const struct device *dev, uint32_t *ticks)
97 {
98 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
99 
100 	*ticks = ((sl_sleeptimer_get_tick_count()) % (dev_data->top_data.ticks));
101 
102 	return 0;
103 }
104 
counter_gecko_start(const struct device * dev)105 static int counter_gecko_start(const struct device *dev)
106 {
107 	ARG_UNUSED(dev);
108 
109 	sl_status_t error_code;
110 	bool is_top_timer_running = false;
111 
112 	error_code = sl_sleeptimer_is_timer_running(&top_timer, &is_top_timer_running);
113 	if ((error_code == SL_STATUS_OK) && (is_top_timer_running == true)) {
114 		return 0;
115 	}
116 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
117 
118 	error_code = sl_sleeptimer_start_timer(&top_timer, dev_data->top_data.ticks, top_callback,
119 					       (void *)&dev_data->top_data, 0, 0);
120 	return error_code;
121 }
122 
counter_gecko_stop(const struct device * dev)123 static int counter_gecko_stop(const struct device *dev)
124 {
125 	ARG_UNUSED(dev);
126 
127 	sl_status_t error_code;
128 	bool is_top_timer_running = false;
129 
130 	error_code = sl_sleeptimer_is_timer_running(&top_timer, &is_top_timer_running);
131 	if ((error_code == SL_STATUS_OK) && (is_top_timer_running == true)) {
132 		sl_sleeptimer_stop_timer(&top_timer);
133 	}
134 	return error_code;
135 }
136 
counter_gecko_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)137 static int counter_gecko_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg)
138 {
139 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
140 	sl_status_t error_code;
141 	bool is_top_timer_running = false;
142 
143 #ifdef CONFIG_SOC_GECKO_HAS_ERRATA_RTCC_E201
144 	const struct counter_gecko_config *const dev_cfg =
145 		(const struct counter_gecko_config *const)(dev)->config;
146 
147 	if (dev_cfg->prescaler != 1) {
148 		LOG_ERR(ERRATA_RTCC_E201_MESSAGE);
149 		return -EINVAL;
150 	}
151 #endif
152 
153 	error_code = sl_sleeptimer_is_timer_running(&top_timer, &is_top_timer_running);
154 	if ((error_code == SL_STATUS_OK) && (is_top_timer_running == true)) {
155 		sl_sleeptimer_stop_timer(&top_timer);
156 	}
157 
158 	dev_data->top_data.callback = cfg->callback;
159 	dev_data->top_data.ticks = cfg->ticks;
160 	dev_data->top_data.dev = (struct device *)dev;
161 	dev_data->top_data.user_data = (struct counter_top_cfg *)cfg;
162 
163 	error_code = sl_sleeptimer_start_periodic_timer(&top_timer, cfg->ticks, top_callback,
164 							(void *)&dev_data->top_data, 0, cfg->flags);
165 
166 	return error_code;
167 }
168 
counter_gecko_get_top_value(const struct device * dev)169 static uint32_t counter_gecko_get_top_value(const struct device *dev)
170 {
171 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
172 
173 	return dev_data->top_data.ticks;
174 }
175 
counter_gecko_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)176 static int counter_gecko_set_alarm(const struct device *dev, uint8_t chan_id,
177 				   const struct counter_alarm_cfg *alarm_cfg)
178 {
179 	bool is_alarm_timer_running = false;
180 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
181 	sl_status_t error_code;
182 	uint32_t now_ticks = 0;
183 	uint32_t top_val = counter_gecko_get_top_value(dev);
184 
185 	if ((top_val != 0) && (alarm_cfg->ticks > top_val)) {
186 		return -EINVAL;
187 	}
188 
189 	if (chan_id >= STIMER_ALARM_NUM) {
190 		printk("Alarm timer count exceeded\n");
191 		return -EINVAL;
192 	}
193 
194 	error_code = sl_sleeptimer_is_timer_running(&alarm_timer[chan_id], &is_alarm_timer_running);
195 	if ((error_code == SL_STATUS_OK) && (is_alarm_timer_running == true)) {
196 		sl_sleeptimer_stop_timer(&alarm_timer[chan_id]);
197 	}
198 
199 	if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) != 0) {
200 		/* Absolute */
201 		error_code = counter_gecko_get_value(dev, &now_ticks);
202 		if (now_ticks < alarm_cfg->ticks) {
203 			dev_data->alarm[chan_id].ticks = top_val + (alarm_cfg->ticks - now_ticks);
204 		} else {
205 			dev_data->alarm[chan_id].ticks =
206 				(top_val - (now_ticks - alarm_cfg->ticks)) % top_val;
207 		}
208 
209 	} else {
210 		/* Relative */
211 		dev_data->alarm[chan_id].ticks = alarm_cfg->ticks;
212 	}
213 
214 	dev_data->alarm[chan_id].callback = alarm_cfg->callback;
215 	dev_data->alarm[chan_id].chan_id = chan_id;
216 	dev_data->alarm[chan_id].dev = (struct device *)dev;
217 	dev_data->alarm[chan_id].user_data = (struct counter_alarm_cfg *)alarm_cfg;
218 
219 	error_code =
220 		sl_sleeptimer_start_timer(&alarm_timer[chan_id], dev_data->alarm[chan_id].ticks,
221 					  alarm_callback, (void *)&dev_data->alarm[chan_id], 0, 0);
222 
223 	return 0;
224 }
225 
counter_gecko_cancel_alarm(const struct device * dev,uint8_t chan_id)226 static int counter_gecko_cancel_alarm(const struct device *dev, uint8_t chan_id)
227 {
228 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
229 
230 	if (chan_id >= STIMER_ALARM_NUM) {
231 		LOG_DBG("Alarm timer count exceeded\n");
232 		return -EINVAL;
233 	}
234 
235 	sl_sleeptimer_stop_timer(&alarm_timer[chan_id]);
236 
237 	dev_data->alarm[chan_id].callback = NULL;
238 	dev_data->alarm[chan_id].user_data = NULL;
239 
240 	LOG_DBG("cancel alarm: channel %u", chan_id);
241 
242 	return 0;
243 }
244 
counter_gecko_get_pending_int(const struct device * dev)245 static uint32_t counter_gecko_get_pending_int(const struct device *dev)
246 {
247 	ARG_UNUSED(dev);
248 
249 	return 0;
250 }
251 
counter_gecko_init(const struct device * dev)252 static int counter_gecko_init(const struct device *dev)
253 {
254 	const struct counter_gecko_config *const dev_cfg =
255 		(const struct counter_gecko_config *const)(dev)->config;
256 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
257 
258 	sl_sleeptimer_init();
259 	dev_data->top_data.ticks = STIMER_MAX_VALUE;
260 
261 	/* Configure & enable module interrupts */
262 	dev_cfg->irq_config();
263 
264 	LOG_INF("Device %s initialized", (dev)->name);
265 
266 	return 0;
267 }
268 
269 static DEVICE_API(counter, counter_gecko_driver_api) = {
270 	.start = counter_gecko_start,
271 	.stop = counter_gecko_stop,
272 	.get_value = counter_gecko_get_value,
273 	.set_alarm = counter_gecko_set_alarm,
274 	.cancel_alarm = counter_gecko_cancel_alarm,
275 	.set_top_value = counter_gecko_set_top_value,
276 	.get_pending_int = counter_gecko_get_pending_int,
277 	.get_top_value = counter_gecko_get_top_value,
278 };
279 
280 BUILD_ASSERT((DT_INST_PROP(0, prescaler) > 0U) && (DT_INST_PROP(0, prescaler) <= 32768U));
281 
counter_gecko_0_irq_config(void)282 static void counter_gecko_0_irq_config(void)
283 {
284 	IRQ_DIRECT_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), STIMER_IRQ_HANDLER, 0);
285 	irq_enable(DT_INST_IRQN(0));
286 }
287 
288 static const struct counter_gecko_config counter_gecko_0_config = {
289 	.info = {
290 			.max_top_value = STIMER_MAX_VALUE,
291 			.freq = DT_INST_PROP(0, clock_frequency) / DT_INST_PROP(0, prescaler),
292 			.flags = COUNTER_CONFIG_INFO_COUNT_UP,
293 			.channels = STIMER_ALARM_NUM,
294 		},
295 	.irq_config = counter_gecko_0_irq_config,
296 	.prescaler = DT_INST_PROP(0, prescaler),
297 };
298 
299 static struct counter_gecko_data counter_gecko_0_data;
300 
301 DEVICE_DT_INST_DEFINE(0, counter_gecko_init, NULL, &counter_gecko_0_data, &counter_gecko_0_config,
302 		      PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &counter_gecko_driver_api);
303