1 /*
2  * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT espressif_esp32_timer
8 
9 #include <esp_clk_tree.h>
10 #include <driver/timer_types_legacy.h>
11 #include <hal/timer_hal.h>
12 #include <hal/timer_ll.h>
13 
14 #include <zephyr/drivers/counter.h>
15 #include <zephyr/drivers/clock_control.h>
16 #include <zephyr/kernel.h>
17 #if defined(CONFIG_RISCV)
18 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
19 #else
20 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
21 #endif
22 #include <zephyr/device.h>
23 #include <zephyr/logging/log.h>
24 
25 LOG_MODULE_REGISTER(esp32_counter, CONFIG_COUNTER_LOG_LEVEL);
26 
27 #if defined(CONFIG_RISCV)
28 #define ISR_HANDLER isr_handler_t
29 #else
30 #define ISR_HANDLER intr_handler_t
31 #endif
32 
33 static void counter_esp32_isr(void *arg);
34 
35 typedef bool (*timer_isr_t)(void *);
36 
37 struct timer_isr_func_t {
38 	timer_isr_t fn;
39 	void *args;
40 	struct intr_handle_data_t *timer_isr_handle;
41 	timer_group_t isr_timer_group;
42 };
43 
44 struct counter_esp32_config {
45 	struct counter_config_info counter_info;
46 	timer_config_t config;
47 	const struct device *clock_dev;
48 	const clock_control_subsys_t clock_subsys;
49 	timer_group_t group;
50 	timer_idx_t index;
51 	int irq_source;
52 	int irq_priority;
53 	int irq_flags;
54 };
55 
56 struct counter_esp32_data {
57 	struct counter_alarm_cfg alarm_cfg;
58 	uint32_t ticks;
59 	uint32_t clock_src_hz;
60 	timer_hal_context_t hal_ctx;
61 	struct timer_isr_func_t timer_isr_fun;
62 };
63 
counter_esp32_init(const struct device * dev)64 static int counter_esp32_init(const struct device *dev)
65 {
66 	const struct counter_esp32_config *cfg = dev->config;
67 	struct counter_esp32_data *data = dev->data;
68 
69 	if (!device_is_ready(cfg->clock_dev)) {
70 		return -ENODEV;
71 	}
72 
73 	/* Return value is not checked below, as clock might have been already enabled
74 	 * by another timer of the same group.
75 	 */
76 	clock_control_on(cfg->clock_dev, cfg->clock_subsys);
77 
78 	timer_hal_init(&data->hal_ctx, cfg->group, cfg->index);
79 	data->alarm_cfg.callback = NULL;
80 	timer_ll_enable_intr(data->hal_ctx.dev, TIMER_LL_EVENT_ALARM(data->hal_ctx.timer_id),
81 			     false);
82 	timer_ll_clear_intr_status(data->hal_ctx.dev, TIMER_LL_EVENT_ALARM(data->hal_ctx.timer_id));
83 	timer_ll_enable_auto_reload(data->hal_ctx.dev, data->hal_ctx.timer_id,
84 				    cfg->config.auto_reload);
85 	timer_ll_set_clock_source(data->hal_ctx.dev, data->hal_ctx.timer_id,
86 				  GPTIMER_CLK_SRC_DEFAULT);
87 	timer_ll_set_clock_prescale(data->hal_ctx.dev, data->hal_ctx.timer_id, cfg->config.divider);
88 	timer_ll_set_count_direction(data->hal_ctx.dev, data->hal_ctx.timer_id,
89 				     cfg->config.counter_dir);
90 	timer_ll_enable_alarm(data->hal_ctx.dev, data->hal_ctx.timer_id, cfg->config.alarm_en);
91 	timer_ll_set_reload_value(data->hal_ctx.dev, data->hal_ctx.timer_id, 0);
92 	timer_ll_enable_counter(data->hal_ctx.dev, data->hal_ctx.timer_id, cfg->config.counter_en);
93 
94 	esp_clk_tree_src_get_freq_hz(GPTIMER_CLK_SRC_DEFAULT,
95 				     ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &data->clock_src_hz);
96 
97 	int ret = esp_intr_alloc(cfg->irq_source,
98 				 ESP_PRIO_TO_FLAGS(cfg->irq_priority) |
99 					 ESP_INT_FLAGS_CHECK(cfg->irq_flags),
100 				 (ISR_HANDLER)counter_esp32_isr, (void *)dev, NULL);
101 
102 	if (ret != 0) {
103 		LOG_ERR("could not allocate interrupt (err %d)", ret);
104 	}
105 
106 	return ret;
107 }
108 
counter_esp32_start(const struct device * dev)109 static int counter_esp32_start(const struct device *dev)
110 {
111 	struct counter_esp32_data *data = dev->data;
112 
113 	timer_ll_enable_counter(data->hal_ctx.dev, data->hal_ctx.timer_id, TIMER_START);
114 
115 	return 0;
116 }
117 
counter_esp32_stop(const struct device * dev)118 static int counter_esp32_stop(const struct device *dev)
119 {
120 	struct counter_esp32_data *data = dev->data;
121 
122 	timer_ll_enable_counter(data->hal_ctx.dev, data->hal_ctx.timer_id, TIMER_PAUSE);
123 
124 	return 0;
125 }
126 
counter_esp32_get_value(const struct device * dev,uint32_t * ticks)127 static int counter_esp32_get_value(const struct device *dev, uint32_t *ticks)
128 {
129 	struct counter_esp32_data *data = dev->data;
130 
131 	timer_ll_trigger_soft_capture(data->hal_ctx.dev, data->hal_ctx.timer_id);
132 	*ticks = (uint32_t)timer_ll_get_counter_value(data->hal_ctx.dev, data->hal_ctx.timer_id);
133 
134 	return 0;
135 }
136 
counter_esp32_get_value_64(const struct device * dev,uint64_t * ticks)137 static int counter_esp32_get_value_64(const struct device *dev, uint64_t *ticks)
138 {
139 	struct counter_esp32_data *data = dev->data;
140 
141 	timer_ll_trigger_soft_capture(data->hal_ctx.dev, data->hal_ctx.timer_id);
142 	*ticks = timer_ll_get_counter_value(data->hal_ctx.dev, data->hal_ctx.timer_id);
143 
144 	return 0;
145 }
146 
counter_esp32_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)147 static int counter_esp32_set_alarm(const struct device *dev, uint8_t chan_id,
148 				   const struct counter_alarm_cfg *alarm_cfg)
149 {
150 	ARG_UNUSED(chan_id);
151 	struct counter_esp32_data *data = dev->data;
152 	uint32_t now;
153 
154 	counter_esp32_get_value(dev, &now);
155 
156 	if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
157 		timer_ll_set_alarm_value(data->hal_ctx.dev, data->hal_ctx.timer_id,
158 					 (now + alarm_cfg->ticks));
159 	} else {
160 		timer_ll_set_alarm_value(data->hal_ctx.dev, data->hal_ctx.timer_id,
161 					 alarm_cfg->ticks);
162 	}
163 
164 	timer_ll_enable_intr(data->hal_ctx.dev, TIMER_LL_EVENT_ALARM(data->hal_ctx.timer_id), true);
165 	timer_ll_enable_alarm(data->hal_ctx.dev, data->hal_ctx.timer_id, TIMER_ALARM_EN);
166 	data->alarm_cfg.callback = alarm_cfg->callback;
167 	data->alarm_cfg.user_data = alarm_cfg->user_data;
168 
169 	return 0;
170 }
171 
counter_esp32_cancel_alarm(const struct device * dev,uint8_t chan_id)172 static int counter_esp32_cancel_alarm(const struct device *dev, uint8_t chan_id)
173 {
174 	ARG_UNUSED(chan_id);
175 	struct counter_esp32_data *data = dev->data;
176 
177 	timer_ll_enable_intr(data->hal_ctx.dev, TIMER_LL_EVENT_ALARM(data->hal_ctx.timer_id),
178 			     false);
179 	timer_ll_enable_alarm(data->hal_ctx.dev, data->hal_ctx.timer_id, TIMER_ALARM_DIS);
180 
181 	return 0;
182 }
183 
counter_esp32_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)184 static int counter_esp32_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg)
185 {
186 	const struct counter_esp32_config *config = dev->config;
187 
188 	if (cfg->ticks != config->counter_info.max_top_value) {
189 		return -ENOTSUP;
190 	} else {
191 		return 0;
192 	}
193 }
194 
counter_esp32_get_pending_int(const struct device * dev)195 static uint32_t counter_esp32_get_pending_int(const struct device *dev)
196 {
197 	struct counter_esp32_data *data = dev->data;
198 
199 	return timer_ll_get_intr_status(data->hal_ctx.dev);
200 }
201 
counter_esp32_get_top_value(const struct device * dev)202 static uint32_t counter_esp32_get_top_value(const struct device *dev)
203 {
204 	const struct counter_esp32_config *config = dev->config;
205 
206 	return config->counter_info.max_top_value;
207 }
208 
counter_esp32_get_freq(const struct device * dev)209 uint32_t counter_esp32_get_freq(const struct device *dev)
210 {
211 	const struct counter_esp32_config *config = dev->config;
212 	struct counter_esp32_data *data = dev->data;
213 
214 	return data->clock_src_hz / config->config.divider;
215 }
216 
217 static DEVICE_API(counter, counter_api) = {
218 	.start = counter_esp32_start,
219 	.stop = counter_esp32_stop,
220 	.get_value = counter_esp32_get_value,
221 	.get_value_64 = counter_esp32_get_value_64,
222 	.set_alarm = counter_esp32_set_alarm,
223 	.cancel_alarm = counter_esp32_cancel_alarm,
224 	.set_top_value = counter_esp32_set_top_value,
225 	.get_pending_int = counter_esp32_get_pending_int,
226 	.get_top_value = counter_esp32_get_top_value,
227 	.get_freq = counter_esp32_get_freq,
228 };
229 
counter_esp32_isr(void * arg)230 static void counter_esp32_isr(void *arg)
231 {
232 	const struct device *dev = (const struct device *)arg;
233 	struct counter_esp32_data *data = dev->data;
234 	uint32_t now;
235 
236 	counter_esp32_cancel_alarm(dev, 0);
237 	counter_esp32_get_value(dev, &now);
238 
239 	if (data->alarm_cfg.callback) {
240 		data->alarm_cfg.callback(dev, 0, now, data->alarm_cfg.user_data);
241 	}
242 
243 	timer_ll_clear_intr_status(data->hal_ctx.dev, TIMER_LL_EVENT_ALARM(data->hal_ctx.timer_id));
244 }
245 
246 #define ESP32_COUNTER_GET_CLK_DIV(idx)                                                             \
247 	(((DT_INST_PROP(idx, prescaler) & UINT16_MAX) < 2)                                         \
248 		 ? 2                                                                               \
249 		 : (DT_INST_PROP(idx, prescaler) & UINT16_MAX))
250 
251 #define ESP32_COUNTER_INIT(idx)                                                                    \
252                                                                                                    \
253 	static struct counter_esp32_data counter_data_##idx;                                       \
254                                                                                                    \
255 	static const struct counter_esp32_config counter_config_##idx = {                          \
256 		.counter_info = {.max_top_value = UINT32_MAX,                                      \
257 				 .flags = COUNTER_CONFIG_INFO_COUNT_UP,                            \
258 				 .channels = 1},                                                   \
259 		.config =                                                                          \
260 			{                                                                          \
261 				.alarm_en = TIMER_ALARM_DIS,                                       \
262 				.counter_en = TIMER_START,                                         \
263 				.intr_type = TIMER_INTR_LEVEL,                                     \
264 				.counter_dir = TIMER_COUNT_UP,                                     \
265 				.auto_reload = TIMER_AUTORELOAD_DIS,                               \
266 				.divider = ESP32_COUNTER_GET_CLK_DIV(idx),                         \
267 			},                                                                         \
268 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)),                              \
269 		.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset),          \
270 		.group = DT_INST_PROP(idx, group),                                                 \
271 		.index = DT_INST_PROP(idx, index),                                                 \
272 		.irq_source = DT_INST_IRQ_BY_IDX(idx, 0, irq),                                     \
273 		.irq_priority = DT_INST_IRQ_BY_IDX(idx, 0, priority),                              \
274 		.irq_flags = DT_INST_IRQ_BY_IDX(idx, 0, flags)};                                   \
275                                                                                                    \
276 	DEVICE_DT_INST_DEFINE(idx, counter_esp32_init, NULL, &counter_data_##idx,                  \
277 			      &counter_config_##idx, PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY,   \
278 			      &counter_api);
279 
280 DT_INST_FOREACH_STATUS_OKAY(ESP32_COUNTER_INIT);
281