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