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 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
116 
117 	error_code = sl_sleeptimer_start_timer(&top_timer, dev_data->top_data.ticks, top_callback,
118 					       (void *)&dev_data->top_data, 0, 0);
119 	return error_code;
120 }
121 
counter_gecko_stop(const struct device * dev)122 static int counter_gecko_stop(const struct device *dev)
123 {
124 	ARG_UNUSED(dev);
125 
126 	sl_status_t error_code;
127 	bool is_top_timer_running = false;
128 
129 	error_code = sl_sleeptimer_is_timer_running(&top_timer, &is_top_timer_running);
130 	if ((error_code == SL_STATUS_OK) && (is_top_timer_running == true)) {
131 		sl_sleeptimer_stop_timer(&top_timer);
132 	}
133 	return error_code;
134 }
135 
counter_gecko_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)136 static int counter_gecko_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg)
137 {
138 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
139 	sl_status_t error_code;
140 	bool is_top_timer_running = false;
141 
142 #ifdef CONFIG_SOC_GECKO_HAS_ERRATA_RTCC_E201
143 	const struct counter_gecko_config *const dev_cfg =
144 		(const struct counter_gecko_config *const)(dev)->config;
145 
146 	if (dev_cfg->prescaler != 1) {
147 		LOG_ERR(ERRATA_RTCC_E201_MESSAGE);
148 		return -EINVAL;
149 	}
150 #endif
151 
152 	error_code = sl_sleeptimer_is_timer_running(&top_timer, &is_top_timer_running);
153 	if ((error_code == SL_STATUS_OK) && (is_top_timer_running == true)) {
154 		sl_sleeptimer_stop_timer(&top_timer);
155 	}
156 
157 	dev_data->top_data.callback = cfg->callback;
158 	dev_data->top_data.ticks = cfg->ticks;
159 	dev_data->top_data.dev = (struct device *)dev;
160 	dev_data->top_data.user_data = (struct counter_top_cfg *)cfg;
161 
162 	error_code = sl_sleeptimer_start_periodic_timer(&top_timer, cfg->ticks, top_callback,
163 							(void *)&dev_data->top_data, 0, cfg->flags);
164 
165 	return error_code;
166 }
167 
counter_gecko_get_top_value(const struct device * dev)168 static uint32_t counter_gecko_get_top_value(const struct device *dev)
169 {
170 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
171 
172 	return dev_data->top_data.ticks;
173 }
174 
counter_gecko_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)175 static int counter_gecko_set_alarm(const struct device *dev, uint8_t chan_id,
176 				   const struct counter_alarm_cfg *alarm_cfg)
177 {
178 	bool is_alarm_timer_running = false;
179 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
180 	sl_status_t error_code;
181 	uint32_t now_ticks = 0;
182 	uint32_t top_val = counter_gecko_get_top_value(dev);
183 
184 	if ((top_val != 0) && (alarm_cfg->ticks > top_val)) {
185 		return -EINVAL;
186 	}
187 
188 	if (chan_id >= STIMER_ALARM_NUM) {
189 		printk("Alarm timer count exceeded\n");
190 		return -EINVAL;
191 	}
192 
193 	error_code = sl_sleeptimer_is_timer_running(&alarm_timer[chan_id], &is_alarm_timer_running);
194 	if ((error_code == SL_STATUS_OK) && (is_alarm_timer_running == true)) {
195 		sl_sleeptimer_stop_timer(&alarm_timer[chan_id]);
196 	}
197 
198 	if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) != 0) {
199 		/* Absolute */
200 		error_code = counter_gecko_get_value(dev, &now_ticks);
201 		if (now_ticks < alarm_cfg->ticks) {
202 			dev_data->alarm[chan_id].ticks = top_val + (alarm_cfg->ticks - now_ticks);
203 		} else {
204 			dev_data->alarm[chan_id].ticks =
205 				(top_val - (now_ticks - alarm_cfg->ticks)) % top_val;
206 		}
207 
208 	} else {
209 		/* Relative */
210 		dev_data->alarm[chan_id].ticks = alarm_cfg->ticks;
211 	}
212 
213 	dev_data->alarm[chan_id].callback = alarm_cfg->callback;
214 	dev_data->alarm[chan_id].chan_id = chan_id;
215 	dev_data->alarm[chan_id].dev = (struct device *)dev;
216 	dev_data->alarm[chan_id].user_data = (struct counter_alarm_cfg *)alarm_cfg;
217 
218 	error_code =
219 		sl_sleeptimer_start_timer(&alarm_timer[chan_id], dev_data->alarm[chan_id].ticks,
220 					  alarm_callback, (void *)&dev_data->alarm[chan_id], 0, 0);
221 
222 	return 0;
223 }
224 
counter_gecko_cancel_alarm(const struct device * dev,uint8_t chan_id)225 static int counter_gecko_cancel_alarm(const struct device *dev, uint8_t chan_id)
226 {
227 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
228 
229 	if (chan_id >= STIMER_ALARM_NUM) {
230 		LOG_DBG("Alarm timer count exceeded\n");
231 		return -EINVAL;
232 	}
233 
234 	sl_sleeptimer_stop_timer(&alarm_timer[chan_id]);
235 
236 	dev_data->alarm[chan_id].callback = NULL;
237 	dev_data->alarm[chan_id].user_data = NULL;
238 
239 	LOG_DBG("cancel alarm: channel %u", chan_id);
240 
241 	return 0;
242 }
243 
counter_gecko_get_pending_int(const struct device * dev)244 static uint32_t counter_gecko_get_pending_int(const struct device *dev)
245 {
246 	ARG_UNUSED(dev);
247 
248 	return 0;
249 }
250 
counter_gecko_init(const struct device * dev)251 static int counter_gecko_init(const struct device *dev)
252 {
253 	const struct counter_gecko_config *const dev_cfg =
254 		(const struct counter_gecko_config *const)(dev)->config;
255 	struct counter_gecko_data *const dev_data = (struct counter_gecko_data *const)(dev)->data;
256 
257 	sl_sleeptimer_init();
258 	dev_data->top_data.ticks = STIMER_MAX_VALUE;
259 
260 	/* Configure & enable module interrupts */
261 	dev_cfg->irq_config();
262 
263 	LOG_INF("Device %s initialized", (dev)->name);
264 
265 	return 0;
266 }
267 
268 static const struct counter_driver_api counter_gecko_driver_api = {
269 	.start = counter_gecko_start,
270 	.stop = counter_gecko_stop,
271 	.get_value = counter_gecko_get_value,
272 	.set_alarm = counter_gecko_set_alarm,
273 	.cancel_alarm = counter_gecko_cancel_alarm,
274 	.set_top_value = counter_gecko_set_top_value,
275 	.get_pending_int = counter_gecko_get_pending_int,
276 	.get_top_value = counter_gecko_get_top_value,
277 };
278 
279 BUILD_ASSERT((DT_INST_PROP(0, prescaler) > 0U) && (DT_INST_PROP(0, prescaler) <= 32768U));
280 
counter_gecko_0_irq_config(void)281 static void counter_gecko_0_irq_config(void)
282 {
283 	IRQ_DIRECT_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), STIMER_IRQ_HANDLER, 0);
284 	irq_enable(DT_INST_IRQN(0));
285 }
286 
287 static const struct counter_gecko_config counter_gecko_0_config = {
288 	.info = {
289 			.max_top_value = STIMER_MAX_VALUE,
290 			.freq = DT_INST_PROP(0, clock_frequency) / DT_INST_PROP(0, prescaler),
291 			.flags = COUNTER_CONFIG_INFO_COUNT_UP,
292 			.channels = STIMER_ALARM_NUM,
293 		},
294 	.irq_config = counter_gecko_0_irq_config,
295 	.prescaler = DT_INST_PROP(0, prescaler),
296 };
297 
298 static struct counter_gecko_data counter_gecko_0_data;
299 
300 DEVICE_DT_INST_DEFINE(0, counter_gecko_init, NULL, &counter_gecko_0_data, &counter_gecko_0_config,
301 		      PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &counter_gecko_driver_api);
302