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