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