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