1 /*
2  * Copyright 2023-2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/pwm.h>
9 #include <zephyr/drivers/pinctrl.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/irq.h>
12 
13 #include <Emios_Mcl_Ip.h>
14 #include <Emios_Pwm_Ip.h>
15 
16 #ifdef CONFIG_PWM_CAPTURE
17 #include <Emios_Icu_Ip.h>
18 #endif
19 
20 #define LOG_MODULE_NAME nxp_s32_emios_pwm
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_PWM_LOG_LEVEL);
23 
24 #define DT_DRV_COMPAT	nxp_s32_emios_pwm
25 
26 #if !defined(EMIOS_PWM_IP_NUM_OF_CHANNELS_USED)
27 #define EMIOS_PWM_IP_NUM_OF_CHANNELS_USED EMIOS_PWM_IP_NUM_OF_CHANNELS_USED_U8
28 #endif
29 
30 /*
31  * Need to fill to this array at runtime, cannot do at build time like
32  * the HAL over configuration tool due to limitation of the integration
33  */
34 #if EMIOS_PWM_IP_USED
35 extern uint8 eMios_Pwm_Ip_IndexInChState[EMIOS_PWM_IP_INSTANCE_COUNT][EMIOS_PWM_IP_CHANNEL_COUNT];
36 #define EMIOS_PWM_MASTER_CHANNEL(channel, bus)					\
37 	((bus == EMIOS_PWM_IP_BUS_A) ? 23 :					\
38 	((bus == EMIOS_PWM_IP_BUS_F) ? 22 :					\
39 	((bus == EMIOS_PWM_IP_BUS_BCDE) ? ((channel >> 3) * 8) : channel)))
40 #endif
41 
42 #ifdef CONFIG_PWM_CAPTURE
43 extern uint8 eMios_Icu_Ip_IndexInChState[EMIOS_ICU_IP_INSTANCE_COUNT][EMIOS_ICU_IP_NUM_OF_CHANNELS];
44 
45 #define EMIOS_ICU_MASTER_CHANNEL(channel, bus)					\
46 	((bus == EMIOS_ICU_BUS_A) ? 23 :					\
47 	((bus == EMIOS_ICU_BUS_F) ? 22 :					\
48 	((bus == EMIOS_ICU_BUS_DIVERSE) ? ((channel >> 3) * 8) : channel)))
49 
50 /* We need maximum three edges for measure both period and cycle */
51 #define MAX_NUM_EDGE 3
52 #endif
53 
54 struct pwm_nxp_s32_channel_data {
55 	bool inverted;
56 	uint8_t master_channel;
57 
58 #if EMIOS_PWM_IP_USED
59 	uint32_t curr_period;
60 #endif
61 
62 #ifdef CONFIG_PWM_CAPTURE
63 	bool continuous;
64 	bool pulse_capture;
65 	bool period_capture;
66 	void *user_data;
67 	pwm_capture_callback_handler_t callback;
68 	eMios_Icu_ValueType edge_buff[MAX_NUM_EDGE];
69 #endif
70 };
71 
72 struct pwm_nxp_s32_data {
73 	uint32_t emios_clk;
74 #if EMIOS_PWM_IP_USED
75 	uint8_t start_pwm_ch;
76 #endif
77 	struct pwm_nxp_s32_channel_data ch_data[eMIOS_CH_UC_UC_COUNT];
78 };
79 
80 #if EMIOS_PWM_IP_USED
81 struct pwm_nxp_s32_pulse_info {
82 	uint8_t pwm_pulse_channels;
83 	Emios_Pwm_Ip_ChannelConfigType *pwm_info;
84 };
85 #endif
86 
87 struct pwm_nxp_s32_config {
88 	eMIOS_Type *base;
89 	uint8_t instance;
90 	const struct device *clock_dev;
91 	clock_control_subsys_t clock_subsys;
92 	const struct pinctrl_dev_config *pincfg;
93 
94 #if EMIOS_PWM_IP_USED
95 	struct pwm_nxp_s32_pulse_info *pulse_info;
96 #endif
97 
98 #ifdef CONFIG_PWM_CAPTURE
99 	eMios_Icu_Ip_ConfigType * icu_cfg;
100 #endif
101 };
102 
103 #if EMIOS_PWM_IP_USED
104 #ifdef EMIOS_PWM_IP_MODE_OPWFMB_USED
pwm_nxp_s32_set_cycles_opwfmb(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)105 static int pwm_nxp_s32_set_cycles_opwfmb(const struct device *dev, uint32_t channel,
106 					uint32_t period_cycles, uint32_t pulse_cycles,
107 					pwm_flags_t flags)
108 {
109 	const struct pwm_nxp_s32_config *config = dev->config;
110 	struct pwm_nxp_s32_data *data = dev->data;
111 	struct pwm_nxp_s32_channel_data *ch_data = &data->ch_data[channel];
112 
113 	Emios_Pwm_Ip_PolarityType polarity;
114 
115 	unsigned int key;
116 
117 	if ((ch_data->inverted != flags) || (!ch_data->curr_period)) {
118 		/* If PWM flag is changed or this is the first time PWM channel is configured */
119 		polarity = (flags & PWM_POLARITY_MASK) ? EMIOS_PWM_IP_ACTIVE_LOW :
120 							 EMIOS_PWM_IP_ACTIVE_HIGH;
121 
122 		config->base->CH.UC[channel].C &= ~(eMIOS_C_MODE_MASK |
123 						    eMIOS_C_EDPOL_MASK);
124 		config->base->CH.UC[channel].A = pulse_cycles;
125 		config->base->CH.UC[channel].B = period_cycles;
126 
127 		/*
128 		 * When entering OPWFMB mode, Output = Cn[EDPOL]. Unless 100% pulse cycle is
129 		 * expected, Cn[EDPOL] is set to complement value (i.e 0 if active high and
130 		 * 1 if active low).
131 		 */
132 		if (pulse_cycles) {
133 			config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(polarity);
134 		} else {
135 			config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(!polarity);
136 		}
137 
138 		key = irq_lock();
139 		config->base->CH.UC[channel].C |= eMIOS_C_MODE(EMIOS_PWM_IP_MODE_OPWFMB_FLAG);
140 
141 		if (pulse_cycles) {
142 			/* Restore expected value for Cn[EDPOL] */
143 			config->base->CH.UC[channel].C = (config->base->CH.UC[channel].C &
144 							~(eMIOS_C_EDPOL_MASK)) |
145 							eMIOS_C_EDPOL(!polarity);
146 		}
147 		irq_unlock(key);
148 
149 		ch_data->curr_period = period_cycles;
150 		ch_data->inverted = flags;
151 	} else {
152 		key = irq_lock();
153 		config->base->CH.UC[channel].A = pulse_cycles;
154 		config->base->CH.UC[channel].B = period_cycles;
155 		irq_unlock(key);
156 	}
157 
158 	return 0;
159 }
160 #endif
161 
162 #if defined(EMIOS_PWM_IP_MODE_OPWMCB_USED)
pwm_nxp_s32_set_cycles_opwmcb(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,Emios_Pwm_Ip_ChannelConfigType * pwm_info,pwm_flags_t flags)163 static int pwm_nxp_s32_set_cycles_opwmcb(const struct device *dev, uint32_t channel,
164 					uint32_t period_cycles, uint32_t pulse_cycles,
165 					Emios_Pwm_Ip_ChannelConfigType *pwm_info,
166 					pwm_flags_t flags)
167 {
168 	const struct pwm_nxp_s32_config *config = dev->config;
169 	struct pwm_nxp_s32_data *data = dev->data;
170 	struct pwm_nxp_s32_channel_data *ch_data = &data->ch_data[channel];
171 	struct pwm_nxp_s32_channel_data *master_ch_data = &data->ch_data[ch_data->master_channel];
172 
173 	unsigned int key;
174 	Emios_Pwm_Ip_PolarityType polarity;
175 
176 	/* Convert to written value into eMIOS register */
177 	if (pulse_cycles == 0) {
178 		pulse_cycles = EMIOS_PWM_IP_MAX_CNT_VAL;
179 	} else if (pulse_cycles == period_cycles) {
180 		pulse_cycles = 1;
181 	} else {
182 		pulse_cycles = period_cycles - (pulse_cycles >> 1);
183 	}
184 
185 	if ((ch_data->inverted != flags) || (!ch_data->curr_period)) {
186 		/* If PWM flag is changed or this is the first time PWM channel is configured */
187 		polarity = (flags & PWM_POLARITY_MASK) ? EMIOS_PWM_IP_ACTIVE_LOW :
188 							 EMIOS_PWM_IP_ACTIVE_HIGH;
189 
190 		if (master_ch_data->curr_period != period_cycles) {
191 			/*
192 			 * Move timebase channel to GPIO mode --> configure period --> MCB mode
193 			 * Period can be shared between multiple PWM channels, only configure
194 			 * when needed.
195 			 */
196 			config->base->CH.UC[ch_data->master_channel].C &= ~eMIOS_C_MODE_MASK;
197 			config->base->CH.UC[ch_data->master_channel].A = period_cycles;
198 		}
199 
200 		config->base->CH.UC[channel].C &= ~(eMIOS_C_MODE_MASK  |
201 						    eMIOS_C_EDPOL_MASK |
202 						    eMIOS_C_BSL_MASK);
203 
204 		/*
205 		 * When entering OPWMCB mode, Output = !Cn[EDPOL]. If 100% pulse cycle is expected
206 		 * Cn[EDPOL] is set to complement value (i.e 0 if active high and 1 if active low).
207 		 */
208 		if (pulse_cycles == 1) {
209 			/* 100% pulse cycle */
210 			config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(!polarity);
211 		} else {
212 			config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(polarity);
213 		}
214 
215 		config->base->CH.UC[channel].A = pulse_cycles;
216 		config->base->CH.UC[channel].B = pwm_info->DeadTime;
217 
218 		key = irq_lock();
219 		config->base->CH.UC[channel].C |= (eMIOS_C_MODE(pwm_info->Mode) |
220 						   eMIOS_C_BSL(pwm_info->Timebase));
221 
222 		if (pulse_cycles == 1) {
223 			config->base->CH.UC[channel].C = (config->base->CH.UC[channel].C &
224 							 ~eMIOS_C_EDPOL_MASK) |
225 							 eMIOS_C_EDPOL(polarity);
226 		}
227 		irq_unlock(key);
228 
229 		if (master_ch_data->curr_period != period_cycles) {
230 			config->base->CH.UC[ch_data->master_channel].C |=
231 							eMIOS_C_MODE(EMIOS_IP_MCB_UP_DOWN_COUNTER);
232 			master_ch_data->curr_period = period_cycles;
233 		}
234 
235 		ch_data->inverted = flags;
236 		ch_data->curr_period = period_cycles;
237 	} else if (master_ch_data->curr_period != period_cycles) {
238 		key = irq_lock();
239 		config->base->CH.UC[ch_data->master_channel].A = period_cycles;
240 		config->base->CH.UC[channel].A = pulse_cycles;
241 		irq_unlock(key);
242 
243 		master_ch_data->curr_period = period_cycles;
244 	} else {
245 		config->base->CH.UC[channel].A = pulse_cycles;
246 	}
247 
248 	return 0;
249 }
250 #endif
251 
252 #if defined(EMIOS_PWM_IP_MODE_OPWMB_USED)
pwm_nxp_s32_set_cycles_opwmb(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,Emios_Pwm_Ip_ChannelConfigType * pwm_info,pwm_flags_t flags)253 static int pwm_nxp_s32_set_cycles_opwmb(const struct device *dev, uint32_t channel,
254 					uint32_t period_cycles, uint32_t pulse_cycles,
255 					Emios_Pwm_Ip_ChannelConfigType *pwm_info,
256 					pwm_flags_t flags)
257 {
258 	const struct pwm_nxp_s32_config *config = dev->config;
259 	struct pwm_nxp_s32_data *data = dev->data;
260 	struct pwm_nxp_s32_channel_data *ch_data = &data->ch_data[channel];
261 	struct pwm_nxp_s32_channel_data *master_ch_data = &data->ch_data[ch_data->master_channel];
262 
263 	Emios_Pwm_Ip_PolarityType polarity;
264 
265 	unsigned int key;
266 
267 	if ((ch_data->inverted != flags) || (!ch_data->curr_period)) {
268 		/* If PWM flag is changed or this is the first time PWM channel is configured */
269 		polarity = (flags & PWM_POLARITY_MASK) ? EMIOS_PWM_IP_ACTIVE_LOW :
270 							 EMIOS_PWM_IP_ACTIVE_HIGH;
271 
272 		if (master_ch_data->curr_period != period_cycles) {
273 			/*
274 			 * Move timebase channel to GPIO mode --> configure period --> MCB mode
275 			 * Period can be shared between multiple PWM channels, only configure
276 			 * when needed.
277 			 */
278 			config->base->CH.UC[ch_data->master_channel].C &= ~eMIOS_C_MODE_MASK;
279 			config->base->CH.UC[ch_data->master_channel].A = period_cycles;
280 		}
281 
282 		config->base->CH.UC[channel].C &= ~(eMIOS_C_MODE_MASK |
283 						    eMIOS_C_EDPOL_MASK | eMIOS_C_BSL_MASK);
284 
285 		config->base->CH.UC[channel].A = pwm_info->PhaseShift;
286 		config->base->CH.UC[channel].B = pulse_cycles;
287 
288 		/*
289 		 * When entering OPWMB mode, Output = Cn[EDPOL]. Unless 100% pulse cycle is
290 		 * expected, Cn[EDPOL] is set to complement value (i.e 0 if active high and
291 		 * 1 if active low).
292 		 */
293 		if (pulse_cycles == period_cycles) {
294 			config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(polarity);
295 		} else {
296 			config->base->CH.UC[channel].C |= eMIOS_C_EDPOL(!polarity);
297 		}
298 
299 		key = irq_lock();
300 		config->base->CH.UC[channel].C |= eMIOS_C_MODE(pwm_info->Mode) |
301 						  eMIOS_C_BSL(pwm_info->Timebase);
302 
303 		if (pulse_cycles != period_cycles) {
304 			config->base->CH.UC[channel].C = (config->base->CH.UC[channel].C &
305 							~(eMIOS_C_EDPOL_MASK)) |
306 							eMIOS_C_EDPOL(polarity);
307 		}
308 
309 		if (!pwm_info->PhaseShift) {
310 			/*
311 			 * If Phase Shift == 0, Force Match A to ensure PWM pulse can be
312 			 * generated immediately. Otherwise, it will need to wait until
313 			 * next period boundary.
314 			 */
315 			config->base->CH.UC[channel].C |= eMIOS_C_FORCMA(1);
316 		}
317 		irq_unlock(key);
318 
319 		if (master_ch_data->curr_period != period_cycles) {
320 			config->base->CH.UC[ch_data->master_channel].C |=
321 							eMIOS_C_MODE(EMIOS_IP_MCB_UP_COUNTER);
322 			master_ch_data->curr_period = period_cycles;
323 		}
324 
325 		ch_data->inverted = flags;
326 		ch_data->curr_period = period_cycles;
327 	} else if (master_ch_data->curr_period != period_cycles) {
328 		key = irq_lock();
329 		config->base->CH.UC[ch_data->master_channel].A = period_cycles;
330 		config->base->CH.UC[channel].B = pulse_cycles;
331 		irq_unlock(key);
332 
333 		master_ch_data->curr_period = period_cycles;
334 	} else {
335 		config->base->CH.UC[channel].B = pulse_cycles;
336 	}
337 
338 	return 0;
339 }
340 #endif
341 
pwm_nxp_s32_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)342 static int pwm_nxp_s32_set_cycles(const struct device *dev, uint32_t channel,
343 				  uint32_t period_cycles, uint32_t pulse_cycles,
344 				  pwm_flags_t flags)
345 {
346 	const struct pwm_nxp_s32_config *config = dev->config;
347 	struct pwm_nxp_s32_data *data = dev->data;
348 
349 	Emios_Pwm_Ip_ChannelConfigType *pwm_info;
350 	uint8_t logic_ch;
351 
352 	if (channel >= EMIOS_PWM_IP_CHANNEL_COUNT) {
353 		LOG_ERR("invalid channel %d", channel);
354 		return -EINVAL;
355 	}
356 
357 	if (eMios_Pwm_Ip_IndexInChState[config->instance][channel] >=
358 		EMIOS_PWM_IP_NUM_OF_CHANNELS_USED) {
359 		LOG_ERR("Channel %d is not configured for PWM", channel);
360 		return -EINVAL;
361 	}
362 
363 	logic_ch = eMios_Pwm_Ip_IndexInChState[config->instance][channel] - data->start_pwm_ch;
364 	pwm_info = &config->pulse_info->pwm_info[logic_ch];
365 
366 	switch (pwm_info->Mode) {
367 #ifdef EMIOS_PWM_IP_MODE_OPWFMB_USED
368 	case EMIOS_PWM_IP_MODE_OPWFMB_FLAG:
369 
370 		if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) ||
371 			(period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) {
372 			LOG_ERR("Period cycles is out of range");
373 			return -EINVAL;
374 		}
375 
376 		return pwm_nxp_s32_set_cycles_opwfmb(dev, channel, period_cycles,
377 						     pulse_cycles, flags);
378 #endif
379 
380 #ifdef EMIOS_PWM_IP_MODE_OPWMCB_USED
381 	case EMIOS_PWM_IP_MODE_OPWMCB_TRAIL_EDGE_FLAG:
382 	case EMIOS_PWM_IP_MODE_OPWMCB_LEAD_EDGE_FLAG:
383 
384 		period_cycles = (period_cycles + 2) / 2;
385 
386 		if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) ||
387 			(period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) {
388 			LOG_ERR("Period cycles is out of range");
389 			return -EINVAL;
390 		}
391 
392 		return pwm_nxp_s32_set_cycles_opwmcb(dev, channel, period_cycles,
393 						     pulse_cycles, pwm_info, flags);
394 #endif
395 
396 #if defined(EMIOS_PWM_IP_MODE_OPWMB_USED)
397 	case EMIOS_PWM_IP_MODE_OPWMB_FLAG:
398 
399 		if ((period_cycles > EMIOS_PWM_IP_MAX_CNT_VAL) ||
400 			(period_cycles <= EMIOS_PWM_IP_MIN_CNT_VAL)) {
401 			LOG_ERR("Period cycles is out of range");
402 			return -EINVAL;
403 		}
404 
405 		pulse_cycles += pwm_info->PhaseShift;
406 
407 		if (pulse_cycles > period_cycles) {
408 			LOG_ERR("Pulse cycles is out of range");
409 			return -EINVAL;
410 		}
411 
412 		return pwm_nxp_s32_set_cycles_opwmb(dev, channel, period_cycles,
413 						    pulse_cycles, pwm_info, flags);
414 #endif
415 
416 	default:
417 		/* Never reach here */
418 		return 0;
419 	}
420 }
421 #endif
422 
423 #ifdef CONFIG_PWM_CAPTURE
pwm_nxp_s32_capture_calc(eMios_Icu_ValueType first_cnt,eMios_Icu_ValueType second_cnt)424 static ALWAYS_INLINE eMios_Icu_ValueType pwm_nxp_s32_capture_calc(eMios_Icu_ValueType first_cnt,
425 								  eMios_Icu_ValueType second_cnt)
426 {
427 	if (first_cnt < second_cnt) {
428 		return second_cnt - first_cnt;
429 	}
430 
431 	/* Counter top value is always 0xFFFF */
432 	return EMIOS_ICU_IP_COUNTER_MASK - first_cnt + second_cnt;
433 }
434 
pwm_nxp_s32_pulse_calc(bool inverted,eMios_Icu_ValueType * edge_buff,eMios_Icu_Ip_LevelType input_state)435 static ALWAYS_INLINE eMios_Icu_ValueType pwm_nxp_s32_pulse_calc(bool inverted,
436 								eMios_Icu_ValueType *edge_buff,
437 								eMios_Icu_Ip_LevelType input_state)
438 {
439 	eMios_Icu_ValueType first_cnt, second_cnt;
440 
441 	if (input_state ^ inverted) {
442 		 /* 3 edges captured is raise, fall, raise */
443 		first_cnt = edge_buff[0];
444 		second_cnt = edge_buff[1];
445 	} else {
446 		 /* 3 edges captured is fall, raise, fall */
447 		first_cnt = edge_buff[1];
448 		second_cnt = edge_buff[2];
449 	}
450 
451 	return pwm_nxp_s32_capture_calc(first_cnt, second_cnt);
452 }
453 
pwm_nxp_s32_capture_configure(const struct device * dev,uint32_t channel,pwm_flags_t flags,pwm_capture_callback_handler_t cb,void * user_data)454 static int pwm_nxp_s32_capture_configure(const struct device *dev,
455 					uint32_t channel,
456 					pwm_flags_t flags,
457 					pwm_capture_callback_handler_t cb,
458 					void *user_data)
459 {
460 	const struct pwm_nxp_s32_config *config = dev->config;
461 	struct pwm_nxp_s32_data *data = dev->data;
462 
463 	if (channel >= EMIOS_ICU_IP_NUM_OF_CHANNELS) {
464 		LOG_ERR("Invalid channel %d", channel);
465 		return -EINVAL;
466 	}
467 
468 	if (!flags) {
469 		LOG_ERR("Invalid PWM capture flag");
470 		return -EINVAL;
471 	}
472 
473 	if (eMios_Icu_Ip_IndexInChState[config->instance][channel] >=
474 		EMIOS_ICU_IP_NUM_OF_CHANNELS_USED) {
475 		LOG_ERR("Channel %d is not configured for PWM", channel);
476 		return -EINVAL;
477 	}
478 
479 	/* If interrupt is enabled --> channel is on-going */
480 	if (config->base->CH.UC[channel].C & eMIOS_C_FEN_MASK) {
481 		LOG_ERR("Channel %d is busy", channel);
482 		return -EBUSY;
483 	}
484 
485 	data->ch_data[channel].continuous = (flags & PWM_CAPTURE_MODE_MASK);
486 	data->ch_data[channel].inverted = (flags & PWM_POLARITY_MASK);
487 	data->ch_data[channel].pulse_capture = (flags & PWM_CAPTURE_TYPE_PULSE);
488 	data->ch_data[channel].period_capture = (flags & PWM_CAPTURE_TYPE_PERIOD);
489 	data->ch_data[channel].callback = cb;
490 	data->ch_data[channel].user_data = user_data;
491 
492 	return 0;
493 }
494 
pwm_nxp_s32_capture_enable(const struct device * dev,uint32_t channel)495 static int pwm_nxp_s32_capture_enable(const struct device *dev, uint32_t channel)
496 {
497 	const struct pwm_nxp_s32_config *config = dev->config;
498 	struct pwm_nxp_s32_data *data = dev->data;
499 
500 	eMios_Icu_Ip_EdgeType edge;
501 	uint8_t num_edge;
502 
503 	if (channel >= EMIOS_ICU_IP_NUM_OF_CHANNELS) {
504 		LOG_ERR("Invalid channel %d", channel);
505 		return -EINVAL;
506 	}
507 
508 	if (eMios_Icu_Ip_IndexInChState[config->instance][channel] >=
509 		EMIOS_ICU_IP_NUM_OF_CHANNELS_USED) {
510 		LOG_ERR("Channel %d is not configured for PWM", channel);
511 		return -EINVAL;
512 	}
513 
514 	if (!data->ch_data[channel].callback) {
515 		LOG_ERR("Callback is not configured");
516 		return -EINVAL;
517 	}
518 
519 	/* If interrupt is enabled --> channel is on-going */
520 	if (config->base->CH.UC[channel].C & eMIOS_C_FEN_MASK) {
521 		LOG_ERR("Channel %d is busy", channel);
522 		return -EBUSY;
523 	}
524 
525 	/* If just measure period, we just need 2 edges */
526 	if (data->ch_data[channel].period_capture && !data->ch_data[channel].pulse_capture) {
527 		num_edge = 2U;
528 		edge = EMIOS_ICU_RISING_EDGE;
529 	} else {
530 		num_edge = 3U;
531 		edge = EMIOS_ICU_BOTH_EDGES;
532 	}
533 
534 	Emios_Icu_Ip_SetActivation(config->instance, channel, edge);
535 
536 	Emios_Icu_Ip_EnableNotification(config->instance, channel);
537 
538 	Emios_Icu_Ip_StartTimestamp(config->instance, channel,
539 				    data->ch_data[channel].edge_buff,
540 				    MAX_NUM_EDGE, num_edge);
541 
542 	return 0;
543 }
544 
pwm_nxp_s32_capture_disable(const struct device * dev,uint32_t channel)545 static int pwm_nxp_s32_capture_disable(const struct device *dev, uint32_t channel)
546 {
547 	const struct pwm_nxp_s32_config *config = dev->config;
548 
549 	if (channel >= EMIOS_ICU_IP_NUM_OF_CHANNELS) {
550 		LOG_ERR("Invalid channel %d", channel);
551 		return -EINVAL;
552 	}
553 
554 	if (eMios_Icu_Ip_IndexInChState[config->instance][channel] >=
555 		EMIOS_ICU_IP_NUM_OF_CHANNELS_USED) {
556 		LOG_ERR("Channel %d is not configured for PWM", channel);
557 		return -EINVAL;
558 	}
559 
560 	Emios_Icu_Ip_StopTimestamp(config->instance, channel);
561 
562 	return 0;
563 }
564 #endif
565 
pwm_nxp_s32_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)566 static int pwm_nxp_s32_get_cycles_per_sec(const struct device *dev,
567 					  uint32_t channel, uint64_t *cycles)
568 {
569 	const struct pwm_nxp_s32_config *config = dev->config;
570 	struct pwm_nxp_s32_data *data = dev->data;
571 
572 	uint8_t internal_prescaler, global_prescaler, master_channel;
573 
574 	master_channel = data->ch_data[channel].master_channel;
575 	internal_prescaler = (config->base->CH.UC[master_channel].C2 & eMIOS_C2_UCEXTPRE_MASK) >>
576 			      eMIOS_C2_UCEXTPRE_SHIFT;
577 
578 	/* Clock source for internal prescaler is from either eMIOS or eMIOS / global prescaler */
579 	if (config->base->CH.UC[master_channel].C2 & eMIOS_C2_UCPRECLK_MASK) {
580 		*cycles = data->emios_clk / (internal_prescaler + 1);
581 	} else {
582 		global_prescaler = (config->base->MCR & eMIOS_MCR_GPRE_MASK) >>
583 				    eMIOS_MCR_GPRE_SHIFT;
584 		*cycles = data->emios_clk / ((internal_prescaler + 1) * (global_prescaler + 1));
585 	}
586 
587 	return 0;
588 }
589 
590 #if EMIOS_PWM_IP_USED
pwm_nxp_s32_pulse_gen_init(const struct device * dev)591 static int pwm_nxp_s32_pulse_gen_init(const struct device *dev)
592 {
593 	const struct pwm_nxp_s32_config *config = dev->config;
594 	struct pwm_nxp_s32_data *data = dev->data;
595 
596 	struct pwm_nxp_s32_channel_data *ch_data;
597 	Emios_Pwm_Ip_ChannelConfigType pwm_info;
598 
599 	uint8_t ch_id;
600 	static uint8_t logic_ch;
601 
602 	data->start_pwm_ch = logic_ch;
603 
604 	for (ch_id = 0; ch_id < config->pulse_info->pwm_pulse_channels; ch_id++) {
605 		memcpy(&pwm_info, &config->pulse_info->pwm_info[ch_id],
606 			sizeof(Emios_Pwm_Ip_ChannelConfigType));
607 
608 		/*
609 		 * Let eMIOS channel is in GPIO mode, the actual PWM mode will be
610 		 * configured at the first time pwm_set* is called.
611 		 */
612 		pwm_info.Mode = EMIOS_PWM_IP_MODE_GPO;
613 		eMios_Pwm_Ip_IndexInChState[config->instance][pwm_info.ChannelId] = logic_ch++;
614 		Emios_Pwm_Ip_InitChannel(config->instance, &pwm_info);
615 
616 		ch_data = &data->ch_data[pwm_info.ChannelId];
617 		ch_data->master_channel = EMIOS_PWM_MASTER_CHANNEL(pwm_info.ChannelId,
618 								   pwm_info.Timebase);
619 	}
620 
621 	return 0;
622 }
623 #endif
624 
625 #ifdef CONFIG_PWM_CAPTURE
pwm_nxp_s32_pulse_capture_init(const struct device * dev)626 static int pwm_nxp_s32_pulse_capture_init(const struct device *dev)
627 {
628 	const struct pwm_nxp_s32_config *config = dev->config;
629 	struct pwm_nxp_s32_data *data = dev->data;
630 
631 	struct pwm_nxp_s32_channel_data *ch_data;
632 	const eMios_Icu_Ip_ChannelConfigType *icu_info;
633 
634 	uint8_t ch_id;
635 	static uint8_t logic_ch;
636 
637 	for (ch_id = 0; ch_id < config->icu_cfg->nNumChannels; ch_id++) {
638 		icu_info = &(*config->icu_cfg->pChannelsConfig)[ch_id];
639 		ch_data = &data->ch_data[icu_info->hwChannel];
640 
641 		eMios_Icu_Ip_IndexInChState[config->instance][icu_info->hwChannel] = logic_ch++;
642 		ch_data->master_channel = EMIOS_ICU_MASTER_CHANNEL(icu_info->hwChannel,
643 								   icu_info->CntBus);
644 	}
645 
646 	if (Emios_Icu_Ip_Init(config->instance, config->icu_cfg)) {
647 		return -EINVAL;
648 	}
649 
650 	return 0;
651 }
652 
pwm_nxp_s32_capture_callback(const struct device * dev,uint32_t channel)653 static void pwm_nxp_s32_capture_callback(const struct device *dev, uint32_t channel)
654 {
655 	const struct pwm_nxp_s32_config *config = dev->config;
656 	struct pwm_nxp_s32_data *data = dev->data;
657 
658 	uint32_t period = 0, pulse = 0;
659 
660 	if (data->ch_data[channel].period_capture && !data->ch_data[channel].pulse_capture) {
661 		period = pwm_nxp_s32_capture_calc(data->ch_data[channel].edge_buff[0],
662 						 data->ch_data[channel].edge_buff[1]);
663 	} else {
664 		if (data->ch_data[channel].pulse_capture) {
665 			pulse = pwm_nxp_s32_pulse_calc(data->ch_data[channel].inverted,
666 						       data->ch_data[channel].edge_buff,
667 						       Emios_Icu_Ip_GetInputLevel(config->instance,
668 										  channel));
669 		}
670 
671 		if (data->ch_data[channel].period_capture) {
672 			period = pwm_nxp_s32_capture_calc(data->ch_data[channel].edge_buff[0],
673 							  data->ch_data[channel].edge_buff[2]);
674 		}
675 	}
676 
677 	if (!data->ch_data[channel].continuous) {
678 		Emios_Icu_Ip_StopTimestamp(config->instance, channel);
679 	}
680 
681 	data->ch_data[channel].callback(dev, channel, period, pulse, 0,
682 					data->ch_data[channel].user_data);
683 }
684 #endif
685 
pwm_nxp_s32_init(const struct device * dev)686 static int pwm_nxp_s32_init(const struct device *dev)
687 {
688 	const struct pwm_nxp_s32_config *config = dev->config;
689 	struct pwm_nxp_s32_data *data = dev->data;
690 
691 	int err = 0;
692 
693 	if (!device_is_ready(config->clock_dev)) {
694 		return -ENODEV;
695 	}
696 
697 	if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
698 					&data->emios_clk)) {
699 		return -EINVAL;
700 	}
701 
702 	err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
703 	if (err < 0) {
704 		return err;
705 	}
706 
707 #if EMIOS_PWM_IP_USED
708 	err = pwm_nxp_s32_pulse_gen_init(dev);
709 	if (err < 0) {
710 		return err;
711 	}
712 #endif
713 
714 #ifdef CONFIG_PWM_CAPTURE
715 	err = pwm_nxp_s32_pulse_capture_init(dev);
716 	if (err < 0) {
717 		return err;
718 	}
719 #endif
720 
721 	return err;
722 }
723 
724 static DEVICE_API(pwm, pwm_nxp_s32_driver_api) = {
725 	.set_cycles = pwm_nxp_s32_set_cycles,
726 	.get_cycles_per_sec = pwm_nxp_s32_get_cycles_per_sec,
727 #ifdef CONFIG_PWM_CAPTURE
728 	.configure_capture = pwm_nxp_s32_capture_configure,
729 	.enable_capture = pwm_nxp_s32_capture_enable,
730 	.disable_capture = pwm_nxp_s32_capture_disable,
731 #endif
732 };
733 
734 #define EMIOS_PWM_IS_MODE_OPWFMB(node_id)							\
735 	DT_ENUM_HAS_VALUE(node_id, pwm_mode, OPWFMB)
736 
737 #define EMIOS_PWM_IS_MODE_OPWMCB(node_id)							\
738 	UTIL_OR(DT_ENUM_HAS_VALUE(node_id, pwm_mode, OPWMCB_TRAIL_EDGE),			\
739 		DT_ENUM_HAS_VALUE(node_id, pwm_mode, OPWMCB_LEAD_EDGE))				\
740 
741 #define EMIOS_PWM_IS_MODE_OPWMB(node_id)							\
742 	DT_ENUM_HAS_VALUE(node_id, pwm_mode, OPWMB)
743 
744 #define EMIOS_PWM_IS_MODE_SAIC(node_id)								\
745 	DT_ENUM_HAS_VALUE(node_id, pwm_mode, SAIC)
746 
747 #define EMIOS_PWM_IS_CAPTURE_MODE(node_id)							\
748 	EMIOS_PWM_IS_MODE_SAIC(node_id)
749 
750 #define EMIOS_PWM_LOG(node_id, msg)								\
751 	DT_NODE_PATH(node_id) ": " DT_PROP(node_id, pwm_mode) ": " msg				\
752 
753 #define EMIOS_PWM_VERIFY_MASTER_BUS(node_id)							\
754 	BUILD_ASSERT(BIT(DT_PROP(node_id, channel)) &						\
755 		     DT_PROP_BY_PHANDLE(node_id, master_bus, channel_mask),			\
756 		     EMIOS_PWM_LOG(node_id, "invalid master bus"));
757 
758 #define EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id)						\
759 	BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, input_filter),					\
760 		     EMIOS_PWM_LOG(node_id, "input-filter is not used"));
761 
762 #define EMIOS_PWM_VERIFY_MODE_OPWFMB(node_id)							\
763 	EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id)						\
764 	BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, master_bus),					\
765 		     EMIOS_PWM_LOG(node_id, "master-bus must not be configured"));		\
766 	BUILD_ASSERT(DT_PROP(node_id, dead_time) == 0,						\
767 		     EMIOS_PWM_LOG(node_id, "dead-time is not used"));				\
768 	BUILD_ASSERT(DT_PROP(node_id, phase_shift) == 0,					\
769 		     EMIOS_PWM_LOG(node_id, "phase-shift is not used"));
770 
771 #define EMIOS_PWM_VERIFY_MODE_OPWMCB(node_id)							\
772 	EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id)						\
773 	BUILD_ASSERT(DT_ENUM_HAS_VALUE(DT_PHANDLE(node_id, master_bus),	mode,			\
774 		     MCB_UP_DOWN_COUNTER),							\
775 		     EMIOS_PWM_LOG(node_id, "master-bus must be configured in MCB up-down"));	\
776 	BUILD_ASSERT(DT_PROP(node_id, phase_shift) == 0,					\
777 		     EMIOS_PWM_LOG(node_id, "phase-shift is not used"));			\
778 	BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, prescaler),					\
779 		     EMIOS_PWM_LOG(node_id, "prescaler is not used,"				\
780 		     " driver takes the value from master bus"));				\
781 	BUILD_ASSERT(DT_ENUM_HAS_VALUE(node_id, prescaler_src, PRESCALED_CLOCK),		\
782 		     EMIOS_PWM_LOG(node_id, "prescaler-src is not used,"			\
783 		     " always use prescalered source"));					\
784 
785 #define EMIOS_PWM_VERIFY_MODE_OPWMB(node_id)							\
786 	EMIOS_PWM_PULSE_GEN_COMMON_VERIFY(node_id)						\
787 	BUILD_ASSERT(DT_ENUM_HAS_VALUE(DT_PHANDLE(node_id, master_bus),	mode, MCB_UP_COUNTER),	\
788 		     EMIOS_PWM_LOG(node_id, "master-bus must be configured in MCB up"));	\
789 	BUILD_ASSERT(DT_PROP(node_id, dead_time) == 0,						\
790 		     EMIOS_PWM_LOG(node_id, "dead-time is not used"));				\
791 	BUILD_ASSERT(!DT_NODE_HAS_PROP(node_id, prescaler),					\
792 		     EMIOS_PWM_LOG(node_id, "prescaler is not used"));				\
793 	BUILD_ASSERT(DT_ENUM_HAS_VALUE(node_id, prescaler_src, PRESCALED_CLOCK),		\
794 		     EMIOS_PWM_LOG(node_id, "prescaler-src is not used,"			\
795 		     " always use prescalered source"));					\
796 
797 #define EMIOS_PWM_VERIFY_MODE_SAIC(node_id)							\
798 	IF_ENABLED(DT_NODE_HAS_PROP(node_id, master_bus),					\
799 		  (BUILD_ASSERT(								\
800 		   DT_ENUM_HAS_VALUE(DT_PHANDLE(node_id, master_bus), mode, MCB_UP_COUNTER),	\
801 		   EMIOS_PWM_LOG(node_id, "master-bus must be configured in MCB up"));))	\
802 	IF_ENABLED(UTIL_NOT(DT_NODE_HAS_PROP(node_id, master_bus)),				\
803 		   (BUILD_ASSERT(								\
804 		    BIT(DT_PROP(node_id, channel)) & DT_PROP(DT_GPARENT(node_id), internal_cnt),\
805 		    EMIOS_PWM_LOG(node_id, "master-bus must be chosen,"				\
806 		    " channel do not have has counter"))));					\
807 	IF_ENABLED(UTIL_NOT(DT_NODE_HAS_PROP(node_id, master_bus)),				\
808 		   (BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, prescaler),				\
809 		    EMIOS_PWM_LOG(node_id, "if use internal counter, prescaler must"		\
810 		    " be configured"))));							\
811 	BUILD_ASSERT(DT_ENUM_HAS_VALUE(node_id, prescaler_src, PRESCALED_CLOCK),		\
812 		     EMIOS_PWM_LOG(node_id, "prescaler-src is not used,"			\
813 		     " always use prescalered source"));
814 
815 #define _EMIOS_PWM_VERIFY_CONFIG(node_id)							\
816 	IF_ENABLED(DT_NODE_HAS_PROP(node_id, master_bus),					\
817 		  (EMIOS_PWM_VERIFY_MASTER_BUS(node_id)))					\
818 	IF_ENABLED(EMIOS_PWM_IS_MODE_OPWFMB(node_id),						\
819 		  (EMIOS_PWM_VERIFY_MODE_OPWFMB(node_id)))					\
820 	IF_ENABLED(EMIOS_PWM_IS_MODE_OPWMCB(node_id),						\
821 		  (EMIOS_PWM_VERIFY_MODE_OPWMCB(node_id)))					\
822 	IF_ENABLED(EMIOS_PWM_IS_MODE_OPWMB(node_id),						\
823 		  (EMIOS_PWM_VERIFY_MODE_OPWMB(node_id)))					\
824 	IF_ENABLED(EMIOS_PWM_IS_MODE_SAIC(node_id),						\
825 		   (EMIOS_PWM_VERIFY_MODE_SAIC(node_id)))
826 
827 #if EMIOS_PWM_IP_USED
828 /* Macros used to glue devicetree with RTD's definition */
829 #define EMIOS_PWM_BUS_A			EMIOS_PWM_IP_BUS_A
830 #define EMIOS_PWM_BUS_B			EMIOS_PWM_IP_BUS_BCDE
831 #define EMIOS_PWM_BUS_C			EMIOS_PWM_IP_BUS_BCDE
832 #define EMIOS_PWM_BUS_D			EMIOS_PWM_IP_BUS_BCDE
833 #define EMIOS_PWM_BUS_E			EMIOS_PWM_IP_BUS_BCDE
834 #define EMIOS_PWM_BUS_F			EMIOS_PWM_IP_BUS_F
835 
836 #define EMIOS_PWM_BUS(mode)		DT_CAT(EMIOS_PWM_, mode)
837 #define EMIOS_PWM_MODE(mode)		DT_CAT3(EMIOS_PWM_IP_MODE_, mode, _FLAG)
838 #define EMIOS_PWM_PS_SRC(mode)		DT_CAT(EMIOS_PWM_IP_PS_SRC_, mode)
839 
840 /* Keep minimal configuration used at driver initialization, no PWM signal is produced */
841 #define _EMIOS_PWM_PULSE_GEN_CONFIG(node_id)							\
842 	IF_ENABLED(UTIL_NOT(EMIOS_PWM_IS_CAPTURE_MODE(node_id)),				\
843 	({											\
844 		.ChannelId = DT_PROP(node_id, channel),						\
845 		.Mode      = EMIOS_PWM_MODE(DT_STRING_TOKEN(node_id, pwm_mode)),		\
846 		.InternalPsSrc = EMIOS_PWM_PS_SRC(DT_STRING_TOKEN(node_id, prescaler_src)),	\
847 		.InternalPs = DT_PROP_OR(node_id, prescaler,					\
848 					DT_PROP_BY_PHANDLE(node_id, master_bus, prescaler)) - 1,\
849 		.Timebase = COND_CODE_1(DT_NODE_HAS_PROP(node_id, master_bus),			\
850 			    (EMIOS_PWM_BUS(DT_STRING_TOKEN(					\
851 					  DT_PHANDLE(node_id, master_bus), bus_type))),		\
852 					  (EMIOS_PWM_IP_BUS_INTERNAL)),				\
853 		.PhaseShift = DT_PROP(node_id, phase_shift),					\
854 		.DeadTime   = DT_PROP(node_id, dead_time),					\
855 		.OutputDisableSource = EMIOS_PWM_IP_OUTPUT_DISABLE_NONE,			\
856 		.OutputPolarity = EMIOS_PWM_IP_ACTIVE_LOW,					\
857 		.DebugMode   = DT_PROP(node_id, freeze),					\
858 		.PeriodCount = 0,								\
859 		.DutyCycle   = 0,								\
860 	},))
861 
862 #define EMIOS_PWM_PULSE_GEN_CONFIG(n)								\
863 	const Emios_Pwm_Ip_ChannelConfigType emios_pwm_##n##_init[] = {				\
864 		DT_INST_FOREACH_CHILD_STATUS_OKAY(n, _EMIOS_PWM_PULSE_GEN_CONFIG)		\
865 	};											\
866 	const struct pwm_nxp_s32_pulse_info emios_pwm_##n##_info = {				\
867 		.pwm_pulse_channels = ARRAY_SIZE(emios_pwm_##n##_init),				\
868 		.pwm_info = (Emios_Pwm_Ip_ChannelConfigType *)emios_pwm_##n##_init,		\
869 	};
870 
871 #define EMIOS_PWM_PULSE_GEN_GET_CONFIG(n)							\
872 	.pulse_info = (struct pwm_nxp_s32_pulse_info *)&emios_pwm_##n##_info,
873 #else
874 #define EMIOS_PWM_PULSE_GEN_CONFIG(n)
875 #define EMIOS_PWM_PULSE_GEN_GET_CONFIG(n)
876 #endif
877 
878 #ifdef CONFIG_PWM_CAPTURE
879 /* Macros used to glue devicetree with RTD's definition */
880 #define EMIOS_ICU_BUS_A				EMIOS_ICU_BUS_A
881 #define EMIOS_ICU_BUS_B				EMIOS_ICU_BUS_DIVERSE
882 #define EMIOS_ICU_BUS_C				EMIOS_ICU_BUS_DIVERSE
883 #define EMIOS_ICU_BUS_D				EMIOS_ICU_BUS_DIVERSE
884 #define EMIOS_ICU_BUS_E				EMIOS_ICU_BUS_DIVERSE
885 #define EMIOS_ICU_BUS_F				EMIOS_ICU_BUS_F
886 
887 #define DIGITAL_FILTER_0			EMIOS_DIGITAL_FILTER_BYPASSED
888 #define DIGITAL_FILTER_2			EMIOS_DIGITAL_FILTER_02
889 #define DIGITAL_FILTER_4			EMIOS_DIGITAL_FILTER_04
890 #define DIGITAL_FILTER_8			EMIOS_DIGITAL_FILTER_08
891 #define DIGITAL_FILTER_16			EMIOS_DIGITAL_FILTER_16
892 
893 #define EMIOS_PWM_CAPTURE_FILTER(filter)	DT_CAT(DIGITAL_FILTER_, filter)
894 #define EMIOS_PWM_CAPTURE_MODE(mode)		DT_CAT(EMIOS_ICU_, mode)
895 #define EMIOS_PWM_CAPTURE_BUS(mode)		DT_CAT(EMIOS_ICU_, mode)
896 
897 #define EMIOS_PWM_CAPTURE_CB(n, ch)								\
898 	DT_CAT5(pwm_nxp_s32_, n, _channel_, ch, _capture_callback)
899 
900 #define EMIOS_PWM_CALLBACK_DECLARE(node_id, n)							\
901 	void EMIOS_PWM_CAPTURE_CB(n, DT_PROP(node_id, channel))(void)				\
902 	{											\
903 		pwm_nxp_s32_capture_callback(DEVICE_DT_INST_GET(n), DT_PROP(node_id, channel));	\
904 	}											\
905 
906 #define _EMIOS_PWM_PULSE_CAPTURE_CONFIG(node_id, n)						\
907 	IF_ENABLED(EMIOS_PWM_IS_CAPTURE_MODE(node_id),						\
908 	({											\
909 		.hwChannel = DT_PROP(node_id, channel),						\
910 		.ucMode	   = EMIOS_PWM_CAPTURE_MODE(DT_STRING_TOKEN(node_id, pwm_mode)),	\
911 		.FreezeEn  = DT_PROP(node_id, freeze),						\
912 		.Prescaler = COND_CODE_1(DT_NODE_HAS_PROP(node_id, master_bus),			\
913 					(DT_PROP_BY_PHANDLE(node_id, master_bus, prescaler)),	\
914 					(DT_PROP(node_id, prescaler))) - 1,			\
915 		.CntBus    = COND_CODE_1(DT_NODE_HAS_PROP(node_id, master_bus),			\
916 			     (EMIOS_PWM_CAPTURE_BUS(DT_STRING_TOKEN(				\
917 						    DT_PHANDLE(node_id, master_bus), bus_type))),\
918 			      (EMIOS_ICU_BUS_INTERNAL_COUNTER)),				\
919 		.chMode    = EMIOS_ICU_MODE_TIMESTAMP,						\
920 		.chSubMode = EMIOS_ICU_MODE_WITHOUT_DMA,					\
921 		.measurementMode = EMIOS_ICU_NO_MEASUREMENT,					\
922 		.edgeAlignement  = EMIOS_ICU_BOTH_EDGES,					\
923 		.Filter   = EMIOS_PWM_CAPTURE_FILTER(DT_PROP(node_id, input_filter)),		\
924 		.callback = NULL_PTR,								\
925 		.logicChStateCallback = NULL_PTR,						\
926 		.callbackParams      = 255U,							\
927 		.bWithoutInterrupt   = FALSE,							\
928 		.timestampBufferType = EMIOS_ICU_CIRCULAR_BUFFER,				\
929 		.eMiosChannelNotification = EMIOS_PWM_CAPTURE_CB(n, DT_PROP(node_id, channel)),	\
930 		.eMiosOverflowNotification = NULL_PTR,						\
931 	},))
932 
933 #define EMIOS_PWM_PULSE_CAPTURE_CONFIG(n)							\
934 	DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(n, EMIOS_PWM_CALLBACK_DECLARE, n)		\
935 	const eMios_Icu_Ip_ChannelConfigType emios_pwm_##n##_capture_init[] = {			\
936 		DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(n, _EMIOS_PWM_PULSE_CAPTURE_CONFIG, n)	\
937 	};											\
938 	const eMios_Icu_Ip_ConfigType emios_pwm_##n##_capture_info = {				\
939 		.nNumChannels = ARRAY_SIZE(emios_pwm_##n##_capture_init),			\
940 		.pChannelsConfig = &emios_pwm_##n##_capture_init,				\
941 	};
942 
943 #define EMIOS_PWM_PULSE_CAPTURE_GET_CONFIG(n)							\
944 	.icu_cfg = (eMios_Icu_Ip_ConfigType *)&emios_pwm_##n##_capture_info,
945 #else
946 #define EMIOS_PWM_PULSE_CAPTURE_CONFIG(n)
947 #define EMIOS_PWM_PULSE_CAPTURE_GET_CONFIG(n)
948 #endif
949 
950 #define EMIOS_PWM_VERIFY_CONFIG(n)								\
951 	DT_INST_FOREACH_CHILD_STATUS_OKAY(n, _EMIOS_PWM_VERIFY_CONFIG)
952 
953 #define EMIOS_NXP_S32_INSTANCE_CHECK(idx, node_id)						\
954 	((DT_REG_ADDR(node_id) == IP_EMIOS_##idx##_BASE) ? idx : 0)
955 
956 #define EMIOS_NXP_S32_GET_INSTANCE(node_id)							\
957 	LISTIFY(__DEBRACKET eMIOS_INSTANCE_COUNT, EMIOS_NXP_S32_INSTANCE_CHECK, (|), node_id)
958 
959 #define PWM_NXP_S32_INIT_DEVICE(n)								\
960 	PINCTRL_DT_INST_DEFINE(n);								\
961 	EMIOS_PWM_VERIFY_CONFIG(n)								\
962 	EMIOS_PWM_PULSE_GEN_CONFIG(n)								\
963 	EMIOS_PWM_PULSE_CAPTURE_CONFIG(n)							\
964 	static const struct pwm_nxp_s32_config pwm_nxp_s32_config_##n = {			\
965 		.base = (eMIOS_Type *)DT_REG_ADDR(DT_INST_PARENT(n)),				\
966 		.instance = EMIOS_NXP_S32_GET_INSTANCE(DT_INST_PARENT(n)),			\
967 		.clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(n))),			\
968 		.clock_subsys = (clock_control_subsys_t)DT_CLOCKS_CELL(DT_INST_PARENT(n), name),\
969 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),					\
970 		EMIOS_PWM_PULSE_GEN_GET_CONFIG(n)						\
971 		EMIOS_PWM_PULSE_CAPTURE_GET_CONFIG(n)						\
972 	};											\
973 	static struct pwm_nxp_s32_data pwm_nxp_s32_data_##n;					\
974 	DEVICE_DT_INST_DEFINE(n,								\
975 			&pwm_nxp_s32_init,							\
976 			NULL,									\
977 			&pwm_nxp_s32_data_##n,							\
978 			&pwm_nxp_s32_config_##n,						\
979 			POST_KERNEL,								\
980 			CONFIG_PWM_INIT_PRIORITY,						\
981 			&pwm_nxp_s32_driver_api);
982 
983 DT_INST_FOREACH_STATUS_OKAY(PWM_NXP_S32_INIT_DEVICE)
984