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_mcpwm
8 
9 #include <hal/mcpwm_hal.h>
10 #include <hal/mcpwm_ll.h>
11 #include <driver/mcpwm.h>
12 
13 #include <soc.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <zephyr/drivers/pwm.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/drivers/pinctrl.h>
19 #include <zephyr/drivers/clock_control.h>
20 #include <esp_clk_tree.h>
21 #ifdef CONFIG_PWM_CAPTURE
22 #if defined(CONFIG_RISCV)
23 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
24 #else
25 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
26 #endif
27 #endif /* CONFIG_PWM_CAPTURE */
28 #include <zephyr/logging/log.h>
29 LOG_MODULE_REGISTER(mcpwm_esp32, CONFIG_PWM_LOG_LEVEL);
30 
31 #if defined(CONFIG_RISCV)
32 #define ISR_HANDLER isr_handler_t
33 #else
34 #define ISR_HANDLER intr_handler_t
35 #endif
36 
37 #ifdef CONFIG_PWM_CAPTURE
38 #define SKIP_IRQ_NUM        4U
39 #define CAP_INT_MASK        7U
40 #define CAP_INT_BASE_BIT    27U
41 #define MCPWM_CHANNEL_NUM   8U
42 #define CAPTURE_CHANNEL_IDX 6U
43 #else
44 #define MCPWM_CHANNEL_NUM 6U
45 #endif /* CONFIG_PWM_CAPTURE */
46 
47 struct mcpwm_esp32_data {
48 	mcpwm_hal_context_t hal;
49 	uint32_t mcpwm_clk_hz;
50 	struct k_sem cmd_sem;
51 };
52 
53 #ifdef CONFIG_PWM_CAPTURE
54 struct capture_data {
55 	uint32_t value;
56 	mcpwm_capture_on_edge_t edge;
57 };
58 
59 struct mcpwm_esp32_capture_config {
60 	uint8_t capture_signal;
61 	pwm_capture_callback_handler_t callback;
62 	void *user_data;
63 	uint32_t period;
64 	uint32_t pulse;
65 	uint8_t skip_irq;
66 	bool capture_period;
67 	bool capture_pulse;
68 	bool continuous;
69 	struct capture_data capture_data[SKIP_IRQ_NUM];
70 };
71 #endif /* CONFIG_PWM_CAPTURE */
72 
73 struct mcpwm_esp32_channel_config {
74 	uint8_t idx;
75 	uint8_t timer_id;
76 	uint8_t operator_id;
77 	uint8_t generator_id;
78 	uint32_t freq;
79 	uint32_t duty;
80 	uint8_t prescale;
81 	bool inverted;
82 #ifdef CONFIG_PWM_CAPTURE
83 	struct mcpwm_esp32_capture_config capture;
84 #endif /* CONFIG_PWM_CAPTURE */
85 };
86 
87 struct mcpwm_esp32_config {
88 	const uint8_t index;
89 	const struct pinctrl_dev_config *pincfg;
90 	const struct device *clock_dev;
91 	const clock_control_subsys_t clock_subsys;
92 	uint8_t prescale;
93 	uint8_t prescale_timer0;
94 	uint8_t prescale_timer1;
95 	uint8_t prescale_timer2;
96 	struct mcpwm_esp32_channel_config channel_config[MCPWM_CHANNEL_NUM];
97 #ifdef CONFIG_PWM_CAPTURE
98 	int (*irq_config_func)(const struct device *dev);
99 #endif /* CONFIG_PWM_CAPTURE */
100 };
101 
mcpwm_esp32_duty_set(const struct device * dev,struct mcpwm_esp32_channel_config * channel)102 static void mcpwm_esp32_duty_set(const struct device *dev,
103 				 struct mcpwm_esp32_channel_config *channel)
104 {
105 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
106 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
107 	mcpwm_duty_type_t duty_type;
108 	uint32_t set_duty;
109 
110 	if (channel->inverted) {
111 		duty_type = channel->duty == 0 ?
112 			MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH : channel->duty == 100 ?
113 			MCPWM_HAL_GENERATOR_MODE_FORCE_LOW  : MCPWM_DUTY_MODE_1;
114 	} else {
115 		duty_type = channel->duty == 0 ?
116 			MCPWM_HAL_GENERATOR_MODE_FORCE_LOW  : channel->duty == 100 ?
117 			MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH : MCPWM_DUTY_MODE_0;
118 	}
119 
120 	uint32_t timer_clk_hz = data->mcpwm_clk_hz / config->prescale / channel->prescale;
121 
122 	set_duty = (timer_clk_hz / channel->freq) * channel->duty / 100;
123 	mcpwm_ll_operator_connect_timer(data->hal.dev, channel->operator_id, channel->timer_id);
124 	mcpwm_ll_operator_set_compare_value(data->hal.dev, channel->operator_id,
125 					    channel->generator_id, set_duty);
126 	mcpwm_ll_operator_enable_update_compare_on_tez(data->hal.dev, channel->operator_id,
127 						       channel->generator_id, true);
128 
129 	if (duty_type == MCPWM_DUTY_MODE_0) {
130 		mcpwm_ll_generator_set_action_on_timer_event(
131 			data->hal.dev, channel->operator_id, channel->generator_id,
132 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH);
133 		mcpwm_ll_generator_set_action_on_timer_event(
134 			data->hal.dev, channel->operator_id, channel->generator_id,
135 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_KEEP);
136 		mcpwm_ll_generator_set_action_on_compare_event(
137 			data->hal.dev, channel->operator_id, channel->generator_id,
138 			MCPWM_TIMER_DIRECTION_UP, channel->generator_id, MCPWM_ACTION_FORCE_LOW);
139 	} else if (duty_type == MCPWM_DUTY_MODE_1) {
140 		mcpwm_ll_generator_set_action_on_timer_event(
141 			data->hal.dev, channel->operator_id, channel->generator_id,
142 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW);
143 		mcpwm_ll_generator_set_action_on_timer_event(
144 			data->hal.dev, channel->operator_id, channel->generator_id,
145 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_ACTION_NO_CHANGE);
146 		mcpwm_ll_generator_set_action_on_compare_event(
147 			data->hal.dev, channel->operator_id, channel->generator_id,
148 			MCPWM_TIMER_DIRECTION_UP, channel->generator_id, MCPWM_ACTION_FORCE_HIGH);
149 	} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_LOW) {
150 		mcpwm_ll_generator_set_action_on_timer_event(
151 			data->hal.dev, channel->operator_id, channel->generator_id,
152 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_ACTION_FORCE_LOW);
153 		mcpwm_ll_generator_set_action_on_timer_event(
154 			data->hal.dev, channel->operator_id, channel->generator_id,
155 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_ACTION_FORCE_LOW);
156 		mcpwm_ll_generator_set_action_on_compare_event(
157 			data->hal.dev, channel->operator_id, channel->generator_id,
158 			MCPWM_TIMER_DIRECTION_UP, channel->generator_id, MCPWM_ACTION_FORCE_LOW);
159 	} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH) {
160 		mcpwm_ll_generator_set_action_on_timer_event(
161 			data->hal.dev, channel->operator_id, channel->generator_id,
162 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_ACTION_FORCE_HIGH);
163 		mcpwm_ll_generator_set_action_on_timer_event(
164 			data->hal.dev, channel->operator_id, channel->generator_id,
165 			MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_ACTION_FORCE_HIGH);
166 		mcpwm_ll_generator_set_action_on_compare_event(
167 			data->hal.dev, channel->operator_id, channel->generator_id,
168 			MCPWM_TIMER_DIRECTION_UP, channel->generator_id, MCPWM_ACTION_FORCE_HIGH);
169 	}
170 }
171 
mcpwm_esp32_configure_pinctrl(const struct device * dev)172 static int mcpwm_esp32_configure_pinctrl(const struct device *dev)
173 {
174 	int ret;
175 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
176 
177 	ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
178 	if (ret < 0) {
179 		LOG_ERR("PWM pinctrl setup failed (%d)", ret);
180 		return ret;
181 	}
182 	return 0;
183 }
184 
mcpwm_esp32_timer_set(const struct device * dev,struct mcpwm_esp32_channel_config * channel)185 static int mcpwm_esp32_timer_set(const struct device *dev,
186 				 struct mcpwm_esp32_channel_config *channel)
187 {
188 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
189 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
190 
191 	__ASSERT_NO_MSG(channel->freq > 0);
192 
193 	mcpwm_ll_timer_set_clock_prescale(data->hal.dev, channel->timer_id, channel->prescale);
194 	mcpwm_ll_timer_set_count_mode(data->hal.dev, channel->timer_id, MCPWM_TIMER_COUNT_MODE_UP);
195 	mcpwm_ll_timer_update_period_at_once(data->hal.dev, channel->timer_id);
196 
197 	uint32_t timer_clk_hz = data->mcpwm_clk_hz / config->prescale / channel->prescale;
198 
199 	mcpwm_ll_timer_set_peak(data->hal.dev, channel->timer_id, timer_clk_hz / channel->freq,
200 				false);
201 
202 	return 0;
203 }
204 
mcpwm_esp32_get_cycles_per_sec(const struct device * dev,uint32_t channel_idx,uint64_t * cycles)205 static int mcpwm_esp32_get_cycles_per_sec(const struct device *dev, uint32_t channel_idx,
206 					  uint64_t *cycles)
207 {
208 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
209 	struct mcpwm_esp32_channel_config *channel = &config->channel_config[channel_idx];
210 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
211 
212 	if (!channel) {
213 		LOG_ERR("Error getting channel %d", channel_idx);
214 		return -EINVAL;
215 	}
216 
217 #ifdef CONFIG_PWM_CAPTURE
218 	if (channel->idx >= CAPTURE_CHANNEL_IDX) {
219 #if SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
220 		/* Capture prescaler is disabled by default (equals 1) */
221 		*cycles = (uint64_t)data->mcpwm_clk_hz / (config->prescale + 1) / 1;
222 #else
223 		*cycles = (uint64_t)APB_CLK_FREQ;
224 #endif
225 		return 0;
226 	}
227 #endif /* CONFIG_PWM_CAPTURE */
228 
229 	*cycles =
230 		(uint64_t)data->mcpwm_clk_hz / (config->prescale + 1) / (channel->prescale + 1);
231 
232 	return 0;
233 }
234 
mcpwm_esp32_set_cycles(const struct device * dev,uint32_t channel_idx,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)235 static int mcpwm_esp32_set_cycles(const struct device *dev, uint32_t channel_idx,
236 				  uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags)
237 {
238 	int ret = 0;
239 	uint64_t clk_freq;
240 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
241 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
242 	struct mcpwm_esp32_channel_config *channel = &config->channel_config[channel_idx];
243 
244 	if (!channel) {
245 		LOG_ERR("Error getting channel %d", channel_idx);
246 		return -EINVAL;
247 	}
248 
249 	/* Update PWM frequency according to period_cycles */
250 	mcpwm_esp32_get_cycles_per_sec(dev, channel_idx, &clk_freq);
251 
252 	channel->freq = (uint32_t)(clk_freq / period_cycles);
253 	if (!channel->freq) {
254 		return -EINVAL;
255 	}
256 
257 	k_sem_take(&data->cmd_sem, K_FOREVER);
258 
259 	ret = mcpwm_esp32_timer_set(dev, channel);
260 	if (ret < 0) {
261 		k_sem_give(&data->cmd_sem);
262 		return ret;
263 	}
264 
265 	double duty_cycle = (double)pulse_cycles * 100 / (double)period_cycles;
266 
267 	channel->duty = (uint32_t)duty_cycle;
268 
269 	channel->inverted = (flags & PWM_POLARITY_INVERTED);
270 
271 	mcpwm_esp32_duty_set(dev, channel);
272 
273 	ret = mcpwm_esp32_configure_pinctrl(dev);
274 	if (ret < 0) {
275 		k_sem_give(&data->cmd_sem);
276 		return ret;
277 	}
278 
279 	mcpwm_ll_timer_set_start_stop_command(data->hal.dev, channel->timer_id,
280 					      MCPWM_TIMER_START_NO_STOP);
281 
282 	k_sem_give(&data->cmd_sem);
283 
284 	return ret;
285 }
286 
287 #ifdef CONFIG_PWM_CAPTURE
mcpwm_esp32_configure_capture(const struct device * dev,uint32_t channel_idx,pwm_flags_t flags,pwm_capture_callback_handler_t cb,void * user_data)288 static int mcpwm_esp32_configure_capture(const struct device *dev, uint32_t channel_idx,
289 					 pwm_flags_t flags, pwm_capture_callback_handler_t cb,
290 					 void *user_data)
291 {
292 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
293 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
294 	struct mcpwm_esp32_channel_config *channel = &config->channel_config[channel_idx];
295 	struct mcpwm_esp32_capture_config *capture = &channel->capture;
296 
297 	if (!channel) {
298 		LOG_ERR("Error getting channel %d", channel_idx);
299 		return -EINVAL;
300 	}
301 
302 	if ((channel->idx < CAPTURE_CHANNEL_IDX) || (channel->idx > CAPTURE_CHANNEL_IDX + 2)) {
303 		LOG_ERR("PWM capture only supported on channels 6, 7 and 8");
304 		return -EINVAL;
305 	}
306 
307 	if (data->hal.dev->cap_chn_cfg[capture->capture_signal].capn_en) {
308 		LOG_ERR("PWM Capture already in progress");
309 		return -EBUSY;
310 	}
311 
312 	if (!(flags & PWM_CAPTURE_TYPE_MASK)) {
313 		LOG_ERR("No PWM capture type specified");
314 		return -EINVAL;
315 	}
316 
317 	channel->inverted = (flags & PWM_POLARITY_INVERTED);
318 	capture->capture_signal = channel->idx - CAPTURE_CHANNEL_IDX;
319 	capture->callback = cb;
320 	capture->user_data = user_data;
321 	capture->capture_period = (flags & PWM_CAPTURE_TYPE_PERIOD);
322 	capture->capture_pulse = (flags & PWM_CAPTURE_TYPE_PULSE);
323 	capture->continuous = (flags & PWM_CAPTURE_MODE_CONTINUOUS);
324 
325 	return 0;
326 }
327 
mcpwm_esp32_disable_capture(const struct device * dev,uint32_t channel_idx)328 static int mcpwm_esp32_disable_capture(const struct device *dev, uint32_t channel_idx)
329 {
330 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
331 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
332 	struct mcpwm_esp32_channel_config *channel = &config->channel_config[channel_idx];
333 	struct mcpwm_esp32_capture_config *capture = &channel->capture;
334 
335 	if (!channel) {
336 		LOG_ERR("Error getting channel %d", channel_idx);
337 		return -EINVAL;
338 	}
339 
340 	if ((channel->idx < CAPTURE_CHANNEL_IDX) || (channel->idx > CAPTURE_CHANNEL_IDX + 2)) {
341 		LOG_ERR("PWM capture only supported on channels 6, 7 and 8");
342 		return -EINVAL;
343 	}
344 
345 	mcpwm_ll_capture_enable_channel(data->hal.dev, capture->capture_signal, false);
346 	mcpwm_ll_intr_enable(data->hal.dev, MCPWM_LL_EVENT_CAPTURE(capture->capture_signal), false);
347 
348 	return 0;
349 }
350 
mcpwm_esp32_enable_capture(const struct device * dev,uint32_t channel_idx)351 static int mcpwm_esp32_enable_capture(const struct device *dev, uint32_t channel_idx)
352 {
353 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
354 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
355 	struct mcpwm_esp32_channel_config *channel = &config->channel_config[channel_idx];
356 	struct mcpwm_esp32_capture_config *capture = &channel->capture;
357 
358 	if (!channel) {
359 		LOG_ERR("Error getting channel %d", channel_idx);
360 		return -EINVAL;
361 	}
362 
363 	if (!capture->callback) {
364 		LOG_ERR("Capture not configured");
365 		return -EINVAL;
366 	}
367 
368 	if ((channel->idx < CAPTURE_CHANNEL_IDX) || (channel->idx > CAPTURE_CHANNEL_IDX + 2)) {
369 		LOG_ERR("PWM capture only supported on channels 6, 7 and 8");
370 		return -EINVAL;
371 	}
372 
373 	if (data->hal.dev->cap_chn_cfg[capture->capture_signal].capn_en) {
374 		LOG_ERR("PWM Capture already in progress");
375 		return -EBUSY;
376 	}
377 
378 	/**
379 	 * Capture prescale is different from other modules as it is applied to the input
380 	 * signal, not the timer source. It is disabled by default.
381 	 */
382 	mcpwm_capture_config_t cap_conf = {
383 		.cap_edge = MCPWM_BOTH_EDGE,
384 		.cap_prescale = 1,
385 	};
386 
387 	mcpwm_ll_group_set_clock_prescale(data->hal.dev, config->prescale);
388 	mcpwm_ll_group_enable_shadow_mode(data->hal.dev);
389 	mcpwm_ll_group_flush_shadow(data->hal.dev);
390 
391 	mcpwm_ll_capture_enable_timer(data->hal.dev, true);
392 	mcpwm_ll_capture_enable_channel(data->hal.dev, capture->capture_signal, true);
393 	mcpwm_ll_capture_enable_negedge(data->hal.dev, capture->capture_signal,
394 					cap_conf.cap_edge & MCPWM_NEG_EDGE);
395 	mcpwm_ll_capture_enable_posedge(data->hal.dev, capture->capture_signal,
396 					cap_conf.cap_edge & MCPWM_POS_EDGE);
397 	mcpwm_ll_capture_set_prescale(data->hal.dev, capture->capture_signal,
398 				      cap_conf.cap_prescale);
399 
400 	mcpwm_ll_intr_enable(data->hal.dev, MCPWM_LL_EVENT_CAPTURE(capture->capture_signal), true);
401 	mcpwm_ll_intr_clear_status(data->hal.dev, MCPWM_LL_EVENT_CAPTURE(capture->capture_signal));
402 
403 	capture->skip_irq = 0;
404 
405 	return 0;
406 }
407 #endif /* CONFIG_PWM_CAPTURE */
408 
channel_init(const struct device * dev)409 static void channel_init(const struct device *dev)
410 {
411 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
412 	struct mcpwm_esp32_channel_config *channel;
413 
414 	for (uint8_t i = 0; i < MCPWM_CHANNEL_NUM; i++) {
415 		channel = &config->channel_config[i];
416 		channel->idx = i;
417 		channel->timer_id = i < 2 ? 0 : i < 4 ? 1 : 2;
418 		channel->operator_id = i < 2 ? 0 : i < 4 ? 1 : 2;
419 		channel->generator_id = i % 2 ? 1 : 0;
420 		channel->prescale = i < 2   ? config->prescale_timer0
421 				    : i < 4 ? config->prescale_timer1
422 					    : config->prescale_timer2;
423 	}
424 }
425 
mcpwm_esp32_init(const struct device * dev)426 int mcpwm_esp32_init(const struct device *dev)
427 {
428 	int ret;
429 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
430 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
431 
432 	if (!device_is_ready(config->clock_dev)) {
433 		LOG_ERR("clock control device not ready");
434 		return -ENODEV;
435 	}
436 
437 	mcpwm_ll_group_set_clock_source(data->hal.dev, MCPWM_TIMER_CLK_SRC_DEFAULT);
438 	esp_clk_tree_src_get_freq_hz(MCPWM_TIMER_CLK_SRC_DEFAULT,
439 				     ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &data->mcpwm_clk_hz);
440 
441 	/* Enable peripheral */
442 	ret = clock_control_on(config->clock_dev, config->clock_subsys);
443 	if (ret < 0) {
444 		LOG_ERR("Could not initialize clock (%d)", ret);
445 		return ret;
446 	}
447 
448 	channel_init(dev);
449 
450 	mcpwm_ll_group_set_clock_prescale(data->hal.dev, config->prescale);
451 	mcpwm_ll_group_enable_shadow_mode(data->hal.dev);
452 	mcpwm_ll_group_flush_shadow(data->hal.dev);
453 
454 #ifdef CONFIG_PWM_CAPTURE
455 	ret = config->irq_config_func(dev);
456 
457 	if (ret != 0) {
458 		LOG_ERR("could not allocate interrupt (err %d)", ret);
459 	}
460 #endif /* CONFIG_PWM_CAPTURE */
461 	return ret;
462 }
463 
464 #ifdef CONFIG_PWM_CAPTURE
mcpwm_esp32_isr(const struct device * dev)465 static void IRAM_ATTR mcpwm_esp32_isr(const struct device *dev)
466 {
467 	struct mcpwm_esp32_config *config = (struct mcpwm_esp32_config *)dev->config;
468 	struct mcpwm_esp32_data *data = (struct mcpwm_esp32_data *const)(dev)->data;
469 	struct mcpwm_esp32_channel_config *channel;
470 	struct mcpwm_esp32_capture_config *capture;
471 	uint32_t mcpwm_intr_status, mcpwm_cap_intr_status;
472 	uint8_t cap_id;
473 
474 	mcpwm_intr_status = mcpwm_ll_intr_get_status(data->hal.dev);
475 	mcpwm_cap_intr_status = (mcpwm_intr_status >> CAP_INT_BASE_BIT) & CAP_INT_MASK;
476 
477 	if (!mcpwm_cap_intr_status) {
478 		return;
479 	}
480 
481 	cap_id = __builtin_ctz(mcpwm_cap_intr_status);
482 
483 	mcpwm_ll_intr_clear_status(data->hal.dev,
484 				   mcpwm_intr_status & MCPWM_LL_EVENT_CAPTURE(cap_id));
485 
486 	channel = &config->channel_config[CAPTURE_CHANNEL_IDX + cap_id];
487 	capture = &channel->capture;
488 
489 	/* We need to wait at least 4 (2 positive edges and 2 negative edges) interrupts to
490 	 * calculate the period
491 	 */
492 	if (capture->skip_irq < SKIP_IRQ_NUM) {
493 		capture->capture_data[capture->skip_irq].value =
494 			mcpwm_ll_capture_get_value(data->hal.dev, capture->capture_signal);
495 		capture->capture_data[capture->skip_irq].edge =
496 			mcpwm_ll_capture_get_edge(data->hal.dev, capture->capture_signal) ==
497 					MCPWM_CAP_EDGE_NEG
498 				? MCPWM_NEG_EDGE
499 				: MCPWM_POS_EDGE;
500 		capture->skip_irq++;
501 
502 	} else {
503 		/**
504 		 * The capture timer is a 32-bit counter incrementing continuously, once enabled.
505 		 * On the input it has an APB clock running typically at 80 MHz
506 		 */
507 		capture->period = channel->inverted ?
508 			capture->capture_data[0].edge == MCPWM_NEG_EDGE
509 				? (capture->capture_data[2].value - capture->capture_data[0].value)
510 				: (capture->capture_data[3].value - capture->capture_data[1].value)
511 			: capture->capture_data[0].edge == MCPWM_POS_EDGE
512 				? (capture->capture_data[2].value - capture->capture_data[0].value)
513 				: (capture->capture_data[3].value - capture->capture_data[1].value);
514 
515 		capture->pulse = channel->inverted ?
516 			capture->capture_data[0].edge == MCPWM_NEG_EDGE
517 				? (capture->capture_data[1].value - capture->capture_data[0].value)
518 				: (capture->capture_data[2].value - capture->capture_data[1].value)
519 			: capture->capture_data[0].edge == MCPWM_POS_EDGE
520 				? (capture->capture_data[1].value - capture->capture_data[0].value)
521 				: (capture->capture_data[2].value - capture->capture_data[1].value);
522 
523 		capture->skip_irq = 0;
524 		if (!capture->continuous) {
525 			mcpwm_esp32_disable_capture(dev, channel->idx);
526 		}
527 
528 		if (capture->callback) {
529 			capture->callback(dev, capture->capture_signal + CAPTURE_CHANNEL_IDX,
530 					  capture->capture_period ? capture->period : 0u,
531 					  capture->capture_pulse ? capture->pulse : 0u, 0u,
532 					  capture->user_data);
533 		}
534 	}
535 }
536 #endif /* CONFIG_PWM_CAPTURE */
537 
538 static DEVICE_API(pwm, mcpwm_esp32_api) = {
539 	.set_cycles = mcpwm_esp32_set_cycles,
540 	.get_cycles_per_sec = mcpwm_esp32_get_cycles_per_sec,
541 #ifdef CONFIG_PWM_CAPTURE
542 	.configure_capture = mcpwm_esp32_configure_capture,
543 	.enable_capture = mcpwm_esp32_enable_capture,
544 	.disable_capture = mcpwm_esp32_disable_capture,
545 #endif /* CONFIG_PWM_CAPTURE */
546 };
547 
548 #ifdef CONFIG_PWM_CAPTURE
549 #define IRQ_CONFIG_FUNC(idx)                                                                       \
550 	static int mcpwm_esp32_irq_config_func_##idx(const struct device *dev)                    \
551 	{                                                                                          \
552 		int ret;                                                                   \
553 		ret = esp_intr_alloc(DT_INST_IRQ_BY_IDX(idx, 0, irq),                      \
554 				ESP_PRIO_TO_FLAGS(DT_INST_IRQ_BY_IDX(idx, 0, priority)) |          \
555 				ESP_INT_FLAGS_CHECK(DT_INST_IRQ_BY_IDX(idx, 0, flags)) |          \
556 					ESP_INTR_FLAG_IRAM,                                        \
557 				(ISR_HANDLER)mcpwm_esp32_isr, (void *)dev, NULL);                  \
558 		return ret;                                                                \
559 	}
560 #define CAPTURE_INIT(idx) .irq_config_func = mcpwm_esp32_irq_config_func_##idx
561 #else
562 #define IRQ_CONFIG_FUNC(idx)
563 #define CAPTURE_INIT(idx)
564 #endif /* CONFIG_PWM_CAPTURE */
565 
566 #define ESP32_MCPWM_INIT(idx)                                                                      \
567 	PINCTRL_DT_INST_DEFINE(idx);                                                               \
568 	IRQ_CONFIG_FUNC(idx);                                                                      \
569 	static struct mcpwm_esp32_data mcpwm_esp32_data_##idx = {                                  \
570 		.hal =                                                                             \
571 			{                                                                          \
572 				.dev = (mcpwm_dev_t *)DT_INST_REG_ADDR(idx),                       \
573 			},                                                                         \
574 		.cmd_sem = Z_SEM_INITIALIZER(mcpwm_esp32_data_##idx.cmd_sem, 1, 1),                \
575 	};                                                                                         \
576                                                                                                    \
577 	static struct mcpwm_esp32_config mcpwm_esp32_config_##idx = {                              \
578 		.index = idx,                                                                      \
579 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),                                     \
580 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)),                              \
581 		.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset),          \
582 		.prescale = DT_INST_PROP(idx, prescale),                                           \
583 		.prescale_timer0 = DT_INST_PROP_OR(idx, prescale_timer0, 0),                       \
584 		.prescale_timer1 = DT_INST_PROP_OR(idx, prescale_timer1, 0),                       \
585 		.prescale_timer2 = DT_INST_PROP_OR(idx, prescale_timer2, 0),                       \
586 		CAPTURE_INIT(idx)};                                                                \
587                                                                                                    \
588 	DEVICE_DT_INST_DEFINE(idx, &mcpwm_esp32_init, NULL, &mcpwm_esp32_data_##idx,               \
589 			      &mcpwm_esp32_config_##idx, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY,    \
590 			      &mcpwm_esp32_api);
591 
592 DT_INST_FOREACH_STATUS_OKAY(ESP32_MCPWM_INIT)
593