1 /*
2 * Copyright 2022-2023 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/atomic.h>
9 #include <zephyr/drivers/can.h>
10 #include <zephyr/drivers/can/transceiver.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/pinctrl.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/irq.h>
16
17 #include <CanEXCEL_Ip_HwAccess.h>
18 #include <CanEXCEL_Ip_Irq.h>
19
20 #define DT_DRV_COMPAT nxp_s32_canxl
21
22 /*
23 * Convert from RX message buffer index to allocated filter ID and
24 * vice versa.
25 */
26 #define RX_MBIDX_TO_ALLOC_IDX(x) (x - CONFIG_CAN_NXP_S32_MAX_TX)
27 #define ALLOC_IDX_TO_RXMB_IDX(x) (x + CONFIG_CAN_NXP_S32_MAX_TX)
28
29 /*
30 * Convert from TX message buffer index to allocated TX ID and vice
31 * versa.
32 */
33 #define TX_MBIDX_TO_ALLOC_IDX(x) (x)
34 #define ALLOC_IDX_TO_TXMB_IDX(x) (x)
35
36 #define CAN_NXP_S32_TIMEOUT_MS 1
37 #define CAN_NXP_S32_MAX_BITRATE 8000000
38 #define CAN_NXP_S32_DATA_LENGTH 64
39
40 LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL);
41
42 #define SP_AND_TIMING_NOT_SET(inst) \
43 (!DT_INST_NODE_HAS_PROP(inst, sample_point) && \
44 !(DT_INST_NODE_HAS_PROP(inst, prop_seg) && \
45 DT_INST_NODE_HAS_PROP(inst, phase_seg1) && \
46 DT_INST_NODE_HAS_PROP(inst, phase_seg2))) ||
47
48 #if DT_INST_FOREACH_STATUS_OKAY(SP_AND_TIMING_NOT_SET) 0
49 #error You must either set a sampling-point or timings (phase-seg* and prop-seg)
50 #endif
51
52 #ifdef CONFIG_CAN_FD_MODE
53
54 #define SP_AND_TIMING_DATA_NOT_SET(inst) \
55 (!DT_INST_NODE_HAS_PROP(inst, sample_point_data) && \
56 !(DT_INST_NODE_HAS_PROP(inst, prop_seg_data) && \
57 DT_INST_NODE_HAS_PROP(inst, phase_seg1_data) && \
58 DT_INST_NODE_HAS_PROP(inst, phase_seg2_data))) ||
59
60 #if DT_INST_FOREACH_STATUS_OKAY(SP_AND_TIMING_DATA_NOT_SET) 0
61 #error You must either set a sampling-point-data or timings (phase-seg-data* and prop-seg-data)
62 #endif
63 #endif
64
65 struct can_nxp_s32_config {
66 CANXL_SIC_Type *base_sic;
67 CANXL_GRP_CONTROL_Type *base_grp_ctrl;
68 CANXL_DSC_CONTROL_Type *base_dsc_ctrl;
69 uint8 instance;
70 const struct device *clock_dev;
71 clock_control_subsys_t clock_subsys;
72 uint32_t bitrate;
73 uint32_t sample_point;
74 uint32_t sjw;
75 uint32_t prop_seg;
76 uint32_t phase_seg1;
77 uint32_t phase_seg2;
78 #ifdef CONFIG_CAN_FD_MODE
79 uint32_t bitrate_data;
80 uint32_t sample_point_data;
81 uint32_t sjw_data;
82 uint32_t prop_seg_data;
83 uint32_t phase_seg1_data;
84 uint32_t phase_seg2_data;
85 #endif
86 uint32_t max_bitrate;
87 const struct device *phy;
88 const struct pinctrl_dev_config *pin_cfg;
89 Canexcel_Ip_ConfigType *can_cfg;
90 void (*irq_config_func)(void);
91 };
92
93 struct can_nxp_s32_tx_callback {
94 Canexcel_Ip_DataInfoType tx_info;
95 can_tx_callback_t function;
96 void *arg;
97 };
98
99 struct can_nxp_s32_rx_callback {
100 struct can_filter filter;
101 Canexcel_Ip_DataInfoType rx_info;
102 can_rx_callback_t function;
103 void *arg;
104 };
105
106 struct can_nxp_s32_data {
107 Canexcel_Ip_StateType *can_state;
108
109 ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_NXP_S32_MAX_RX);
110 struct k_mutex rx_mutex;
111 struct can_nxp_s32_rx_callback rx_cbs[CONFIG_CAN_NXP_S32_MAX_RX];
112 Canexcel_RxFdMsg *rx_msg;
113
114 ATOMIC_DEFINE(tx_allocs, CONFIG_CAN_NXP_S32_MAX_TX);
115 struct k_sem tx_allocs_sem;
116 struct k_mutex tx_mutex;
117 struct can_nxp_s32_tx_callback tx_cbs[CONFIG_CAN_NXP_S32_MAX_TX];
118 Canexcel_TxFdMsgType *tx_msg;
119
120 struct can_timing timing;
121 #ifdef CONFIG_CAN_FD_MODE
122 struct can_timing timing_data;
123 #endif
124 enum can_state state;
125 can_state_change_callback_t state_change_cb;
126 void *state_change_cb_data;
127 bool started;
128 };
129
can_nxp_s32_get_capabilities(const struct device * dev,can_mode_t * cap)130 static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *cap)
131 {
132 ARG_UNUSED(dev);
133
134 *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY;
135
136 #if CONFIG_CAN_FD_MODE
137 *cap |= CAN_MODE_FD;
138 #endif
139
140 return 0;
141 }
142
can_nxp_s32_start(const struct device * dev)143 static int can_nxp_s32_start(const struct device *dev)
144 {
145 const struct can_nxp_s32_config *config = dev->config;
146 struct can_nxp_s32_data *data = dev->data;
147 int err;
148
149 if (data->started) {
150 return -EALREADY;
151 }
152
153 if (config->phy != NULL) {
154 err = can_transceiver_enable(config->phy);
155 if (err != 0) {
156 LOG_ERR("failed to enable CAN transceiver (err %d)", err);
157 return err;
158 }
159 }
160
161 data->started = true;
162
163 return 0;
164 }
165
can_nxp_s32_abort_msg(const struct can_nxp_s32_config * config,int mb_idx)166 static int can_nxp_s32_abort_msg(const struct can_nxp_s32_config *config, int mb_idx)
167 {
168 uint32_t time_start = 0;
169 int ret = 0;
170
171 Canexcel_Ip_EnterFreezeMode(config->instance);
172
173 CanXL_ClearMsgBuffIntCmd(config->base_grp_ctrl, mb_idx);
174 CanXL_ClearMsgDescIntStatusFlag(config->base_grp_ctrl, mb_idx);
175
176 time_start = k_uptime_get();
177 /* Set system lock Status */
178 (void)config->base_dsc_ctrl->DSCMBCTRLAR[mb_idx].SYSLOCK.DCSYSLOCK;
179 while (CanXL_GetDescControlStatus(config->base_dsc_ctrl, mb_idx)
180 == CANEXCEL_DESCNTSTATUS_LOCKED_HW) {
181 if (k_uptime_get() - time_start >= CAN_NXP_S32_TIMEOUT_MS) {
182 ret = CANEXCEL_STATUS_TIMEOUT;
183 break;
184 }
185 }
186
187 /* Inactive descriptor */
188 config->base_dsc_ctrl->DSCMBCTRLAR[mb_idx].ACT.DCACT = 0;
189
190 Canexcel_Ip_ExitFreezeMode(config->instance);
191
192 return ret;
193 }
194
can_nxp_s32_stop(const struct device * dev)195 static int can_nxp_s32_stop(const struct device *dev)
196 {
197 const struct can_nxp_s32_config *config = dev->config;
198 struct can_nxp_s32_data *data = dev->data;
199 can_tx_callback_t function;
200 void *arg;
201 int alloc;
202 int err;
203
204 if (!data->started) {
205 return -EALREADY;
206 }
207
208 data->started = false;
209
210 /* Abort any pending TX frames before entering freeze mode */
211 for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) {
212 function = data->tx_cbs[alloc].function;
213 arg = data->tx_cbs[alloc].arg;
214
215 if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
216 if (can_nxp_s32_abort_msg(config,
217 ALLOC_IDX_TO_TXMB_IDX(alloc))) {
218 LOG_ERR("Can't abort message !");
219 };
220
221 function(dev, -ENETDOWN, arg);
222 k_sem_give(&data->tx_allocs_sem);
223 }
224 }
225
226 if (config->phy != NULL) {
227 err = can_transceiver_disable(config->phy);
228 if (err != 0) {
229 LOG_ERR("failed to disable CAN transceiver (err %d)", err);
230 return err;
231 }
232 }
233
234 return 0;
235 }
236
237
can_nxp_s32_set_mode(const struct device * dev,can_mode_t mode)238 static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode)
239 {
240 const struct can_nxp_s32_config *config = dev->config;
241 struct can_nxp_s32_data *data = dev->data;
242 Canexcel_Ip_ModesType can_nxp_s32_mode = CAN_MODE_NORMAL;
243 bool canfd = false;
244 bool brs = false;
245
246 if (data->started) {
247 return -EBUSY;
248 }
249 #ifdef CONFIG_CAN_FD_MODE
250 if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_FD)) != 0) {
251 #else
252 if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY)) != 0) {
253 #endif
254 LOG_ERR("unsupported mode: 0x%08x", mode);
255 return -ENOTSUP;
256 }
257
258 if ((mode & (CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY))
259 == (CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY)) {
260 LOG_ERR("unsupported mode loopback and "
261 "mode listen-only at the same time: 0x%08x", mode);
262 return -ENOTSUP;
263 }
264
265 canfd = !!(mode & CAN_MODE_FD);
266 brs = canfd;
267
268 if (mode & CAN_MODE_LISTENONLY) {
269 can_nxp_s32_mode = CANEXCEL_LISTEN_ONLY_MODE;
270 } else if (mode & CAN_MODE_LOOPBACK) {
271 can_nxp_s32_mode = CANEXCEL_LOOPBACK_MODE;
272 }
273
274 Canexcel_Ip_EnterFreezeMode(config->instance);
275
276 CanXL_SetFDEnabled(config->base_sic, canfd, brs);
277
278 CanXL_SetOperationMode(config->base_sic, can_nxp_s32_mode);
279
280 Canexcel_Ip_ExitFreezeMode(config->instance);
281
282 return 0;
283 }
284
285 static int can_nxp_s32_get_core_clock(const struct device *dev, uint32_t *rate)
286 {
287 const struct can_nxp_s32_config *config = dev->config;
288
289 __ASSERT_NO_MSG(rate != NULL);
290
291 return clock_control_get_rate(config->clock_dev, config->clock_subsys, rate);
292 }
293
294 static int can_nxp_s32_get_max_filters(const struct device *dev, bool ide)
295 {
296 ARG_UNUSED(ide);
297
298 return CONFIG_CAN_NXP_S32_MAX_RX;
299 }
300
301 static int can_nxp_s32_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate)
302 {
303 const struct can_nxp_s32_config *config = dev->config;
304
305 *max_bitrate = config->max_bitrate;
306
307 return 0;
308 }
309
310 static int can_nxp_s32_get_state(const struct device *dev, enum can_state *state,
311 struct can_bus_err_cnt *err_cnt)
312 {
313 const struct can_nxp_s32_config *config = dev->config;
314 struct can_nxp_s32_data *data = dev->data;
315 uint32_t sys_status = config->base_sic->SYSS;
316
317 if (state) {
318 if (!data->started) {
319 *state = CAN_STATE_STOPPED;
320 } else {
321 if (sys_status & CANXL_SIC_SYSS_CBOFF_MASK) {
322 *state = CAN_STATE_BUS_OFF;
323 } else if (sys_status & CANXL_SIC_SYSS_CPASERR_MASK) {
324 *state = CAN_STATE_ERROR_PASSIVE;
325 } else if (sys_status & (CANXL_SIC_SYSS_CRXWRN_MASK
326 | CANXL_SIC_SYSS_CTXWRN_MASK)) {
327 *state = CAN_STATE_ERROR_WARNING;
328 } else {
329 *state = CAN_STATE_ERROR_ACTIVE;
330 }
331 }
332 }
333
334 if (err_cnt) {
335 /* NXP S32 CANXL HAL is not supported error counter */
336 err_cnt->tx_err_cnt = 0;
337 err_cnt->rx_err_cnt = 0;
338 }
339
340 return 0;
341 }
342
343 static void can_nxp_s32_set_state_change_callback(const struct device *dev,
344 can_state_change_callback_t callback,
345 void *user_data)
346 {
347 struct can_nxp_s32_data *data = dev->data;
348
349 data->state_change_cb = callback;
350 data->state_change_cb_data = user_data;
351 }
352
353 #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
354 static int can_nxp_s32_recover(const struct device *dev, k_timeout_t timeout)
355 {
356 const struct can_nxp_s32_config *config = dev->config;
357 struct can_nxp_s32_data *data = dev->data;
358 enum can_state state;
359 uint64_t start_time;
360 int ret = 0;
361
362 if (!data->started) {
363 return -ENETDOWN;
364 }
365
366 can_nxp_s32_get_state(dev, &state, NULL);
367 if (state != CAN_STATE_BUS_OFF) {
368 return 0;
369 }
370
371 start_time = k_uptime_ticks();
372 config->base_sic->BCFG1 &= (~CANXL_SIC_BCFG1_ABRDIS_MASK);
373
374 if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
375 can_nxp_s32_get_state(dev, &state, NULL);
376
377 while (state == CAN_STATE_BUS_OFF) {
378 if (!K_TIMEOUT_EQ(timeout, K_FOREVER) &&
379 k_uptime_ticks() - start_time >= timeout.ticks) {
380 ret = -EAGAIN;
381 }
382
383 can_nxp_s32_get_state(dev, &state, NULL);
384 }
385 }
386
387 config->base_sic->BCFG1 |= CANXL_SIC_BCFG1_ABRDIS_MASK;
388
389 return ret;
390 }
391 #endif
392
393 static void can_nxp_s32_remove_rx_filter(const struct device *dev, int filter_id)
394 {
395 const struct can_nxp_s32_config *config = dev->config;
396 struct can_nxp_s32_data *data = dev->data;
397 int mb_indx = ALLOC_IDX_TO_RXMB_IDX(filter_id);
398
399 __ASSERT_NO_MSG(filter_id >= 0 && filter_id < CONFIG_CAN_NXP_S32_MAX_RX);
400
401 k_mutex_lock(&data->rx_mutex, K_FOREVER);
402
403 if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
404 if (can_nxp_s32_abort_msg(config, mb_indx)) {
405 LOG_ERR("Can't abort message !");
406 };
407
408 data->rx_cbs[filter_id].function = NULL;
409 data->rx_cbs[filter_id].arg = NULL;
410 data->rx_cbs[filter_id].filter = (struct can_filter){0};
411 } else {
412 LOG_WRN("Filter ID %d already detached", filter_id);
413 }
414
415 k_mutex_unlock(&data->rx_mutex);
416 }
417
418 static int can_nxp_s32_add_rx_filter(const struct device *dev,
419 can_rx_callback_t callback,
420 void *user_data,
421 const struct can_filter *filter)
422 {
423 const struct can_nxp_s32_config *config = dev->config;
424 struct can_nxp_s32_data *data = dev->data;
425 int alloc = -ENOSPC;
426 int mb_indx;
427 uint32_t mask;
428
429 __ASSERT_NO_MSG(callback != NULL);
430 #if defined(CONFIG_CAN_FD_MODE)
431 if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_FDF)) != 0) {
432 #else
433 if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA)) != 0) {
434 #endif
435 LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags);
436 return -ENOTSUP;
437 }
438
439 k_mutex_lock(&data->rx_mutex, K_FOREVER);
440
441 /* Find and allocate RX message buffer */
442 for (int i = 0; i < CONFIG_CAN_NXP_S32_MAX_RX; i++) {
443 if (!atomic_test_and_set_bit(data->rx_allocs, i)) {
444 alloc = i;
445 break;
446 }
447 }
448
449 if (alloc == -ENOSPC) {
450 LOG_ERR("No free filter bank found");
451 goto unlock;
452 }
453
454 data->rx_cbs[alloc].function = callback;
455 data->rx_cbs[alloc].arg = user_data;
456 data->rx_cbs[alloc].filter = *filter;
457
458 data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) {
459 .frame = !!(filter->flags & CAN_FILTER_FDF) ?
460 CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME,
461 .idType = !!(filter->flags & CAN_FILTER_IDE) ?
462 CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD,
463 .dataLength = CAN_NXP_S32_DATA_LENGTH,
464 };
465
466 /* Set Rx Mb individual mask for */
467 mb_indx = ALLOC_IDX_TO_RXMB_IDX(alloc);
468 if (!!(filter->flags & CAN_FILTER_IDE)) {
469 mask = (filter->mask & CANXL_IP_ID_EXT_MASK);
470 } else {
471 mask = ((filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK);
472 }
473
474 Canexcel_Ip_EnterFreezeMode(config->instance);
475
476 Canexcel_Ip_SetRxIndividualMask(config->instance, mb_indx,
477 data->rx_cbs[alloc].rx_info.frame, mask);
478
479 Canexcel_Ip_ConfigRx(config->instance, mb_indx, filter->id,
480 &data->rx_cbs[alloc].rx_info);
481
482 Canexcel_Ip_ReceiveFD(config->instance, mb_indx, &data->rx_msg[alloc], FALSE);
483
484 Canexcel_Ip_ExitFreezeMode(config->instance);
485
486 unlock:
487 k_mutex_unlock(&data->rx_mutex);
488
489 return alloc;
490 }
491
492 static int can_nxp_s32_send(const struct device *dev,
493 const struct can_frame *frame,
494 k_timeout_t timeout,
495 can_tx_callback_t callback, void *user_data)
496 {
497 const struct can_nxp_s32_config *config = dev->config;
498 uint8_t data_length = can_dlc_to_bytes(frame->dlc);
499 struct can_nxp_s32_data *data = dev->data;
500 Canexcel_Ip_StatusType status;
501 enum can_state state;
502 int alloc, mb_indx;
503
504 __ASSERT_NO_MSG(callback != NULL);
505
506 #ifdef CONFIG_CAN_FD_MODE
507 if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) {
508 LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
509 return -ENOTSUP;
510 }
511
512 if ((frame->flags & CAN_FRAME_FDF) != 0 &&
513 (config->base_sic->BCFG2 & CANXL_SIC_BCFG2_FDEN_MASK) == 0) {
514 LOG_ERR("CAN-FD format not supported in non-FD mode");
515 return -ENOTSUP;
516 }
517
518 if ((frame->flags & CAN_FRAME_BRS) != 0 &&
519 ~(config->base_sic->BCFG1 & CANXL_SIC_BCFG1_FDRSDIS_MASK) == 0) {
520 LOG_ERR("CAN-FD BRS not supported in non-FD mode");
521 return -ENOTSUP;
522 }
523 #else
524 if ((frame->flags & ~CAN_FRAME_IDE) != 0) {
525 LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
526 return -ENOTSUP;
527 }
528 #endif
529
530 if (data_length > sizeof(frame->data)) {
531 LOG_ERR("data length (%d) > max frame data length (%d)",
532 data_length, sizeof(frame->data));
533 return -EINVAL;
534 }
535
536 if ((frame->flags & CAN_FRAME_FDF) == 0) {
537 if (frame->dlc > CAN_MAX_DLC) {
538 LOG_ERR("DLC of %d for non-FD format frame", frame->dlc);
539 return -EINVAL;
540 }
541 #ifdef CONFIG_CAN_FD_MODE
542 } else {
543 if (frame->dlc > CANFD_MAX_DLC) {
544 LOG_ERR("DLC of %d for CAN-FD format frame", frame->dlc);
545 return -EINVAL;
546 }
547 #endif
548 }
549
550 if (!data->started) {
551 return -ENETDOWN;
552 }
553
554 can_nxp_s32_get_state(dev, &state, NULL);
555 if (state == CAN_STATE_BUS_OFF) {
556 LOG_ERR("Transmit failed, bus-off");
557 return -ENETUNREACH;
558 }
559
560 if (k_sem_take(&data->tx_allocs_sem, timeout) != 0) {
561 return -EAGAIN;
562 }
563
564 for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) {
565 if (!atomic_test_and_set_bit(data->tx_allocs, alloc)) {
566 break;
567 }
568 }
569
570 data->tx_cbs[alloc].function = callback;
571 data->tx_cbs[alloc].arg = user_data;
572 mb_indx = ALLOC_IDX_TO_TXMB_IDX(alloc);
573 data->tx_cbs[alloc].tx_info = (Canexcel_Ip_DataInfoType) {
574 .frame = !!(frame->flags & CAN_FRAME_FDF) ?
575 CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME,
576 .enable_brs = !!(frame->flags & CAN_FRAME_BRS) ? TRUE : FALSE,
577 .idType = !!(frame->flags & CAN_FRAME_IDE) ?
578 CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD,
579 .priority = 0,
580 .fd_padding = 0,
581 .dataLength = data_length,
582 .is_polling = FALSE
583 };
584
585 LOG_DBG("%s: Sending %d bytes Tx Mb %d, "
586 "Tx Id: 0x%x, "
587 "Id type: %s %s %s %s",
588 dev->name, data_length,
589 mb_indx, frame->id,
590 !!(frame->flags & CAN_FRAME_IDE) ?
591 "extended" : "standard",
592 !!(frame->flags & CAN_FRAME_RTR) ? "RTR" : "",
593 !!(frame->flags & CAN_FRAME_FDF) ? "FD frame" : "",
594 !!(frame->flags & CAN_FRAME_BRS) ? "BRS" : "");
595
596 k_mutex_lock(&data->tx_mutex, K_FOREVER);
597 /* Send MB Interrupt */
598 status = Canexcel_Ip_SendFDMsg(config->instance, mb_indx, &data->tx_cbs[alloc].tx_info,
599 frame->id, (uint8_t *)&frame->data, &data->tx_msg[alloc]);
600 k_mutex_unlock(&data->tx_mutex);
601
602 if (status != CANEXCEL_STATUS_SUCCESS) {
603 return -EIO;
604 }
605
606 return 0;
607 }
608
609 static void nxp_s32_zcan_timing_to_canxl_timing(const struct can_timing *timing,
610 Canexcel_Ip_TimeSegmentType *canxl_timing)
611 {
612 LOG_DBG("propSeg: %d, phase_seg1: %d, phase_seg2: %d, prescaler: %d, sjw: %d",
613 timing->prop_seg, timing->phase_seg1, timing->phase_seg2,
614 timing->prescaler, timing->sjw);
615
616 canxl_timing->propSeg = timing->prop_seg - 1U;
617 canxl_timing->phaseSeg1 = timing->phase_seg1 - 1U;
618 canxl_timing->phaseSeg2 = timing->phase_seg2 - 1U;
619 canxl_timing->preDivider = timing->prescaler - 1U;
620 canxl_timing->rJumpwidth = timing->sjw - 1U;
621 }
622
623 static int can_nxp_s32_set_timing(const struct device *dev,
624 const struct can_timing *timing)
625 {
626 const struct can_nxp_s32_config *config = dev->config;
627 struct can_nxp_s32_data *data = dev->data;
628 Canexcel_Ip_TimeSegmentType can_time_segment = {0};
629
630 if (data->started) {
631 return -EBUSY;
632 }
633
634 nxp_s32_zcan_timing_to_canxl_timing(timing, &can_time_segment);
635
636 /* Set timing for CAN instance*/
637 CanXL_SetBaudRate(config->base_sic, &can_time_segment);
638
639 return 0;
640 }
641
642 #ifdef CONFIG_CAN_FD_MODE
643 static int can_nxp_s32_set_timing_data(const struct device *dev,
644 const struct can_timing *timing_data)
645 {
646 const struct can_nxp_s32_config *config = dev->config;
647 struct can_nxp_s32_data *data = dev->data;
648 Canexcel_Ip_TimeSegmentType can_fd_time_segment = {0};
649
650 if (data->started) {
651 return -EBUSY;
652 }
653
654 nxp_s32_zcan_timing_to_canxl_timing(timing_data, &can_fd_time_segment);
655
656 /* Set timing for CAN FD instance*/
657 CanXL_SetFDBaudRate(config->base_sic, &can_fd_time_segment);
658
659 return 0;
660 }
661 #endif
662
663 static void can_nxp_s32_err_callback(const struct device *dev,
664 Canexcel_Ip_EventType eventType,
665 uint32 u32SysStatus,
666 const Canexcel_Ip_StateType *canexcelState)
667 {
668 const struct can_nxp_s32_config *config = dev->config;
669 struct can_nxp_s32_data *data = dev->data;
670 enum can_state state;
671 struct can_bus_err_cnt err_cnt;
672 void *cb_data = data->state_change_cb_data;
673 can_tx_callback_t function;
674 int alloc;
675 void *arg;
676
677 switch (eventType) {
678 case CANEXCEL_EVENT_TX_WARNING:
679 LOG_DBG("Tx Warning (error 0x%x)", u32SysStatus);
680 break;
681 case CANEXCEL_EVENT_RX_WARNING:
682 LOG_DBG("Rx Warning (error 0x%x)", u32SysStatus);
683 break;
684 case CANEXCEL_EVENT_BUSOFF:
685 LOG_DBG("Bus Off (error 0x%x)", u32SysStatus);
686 break;
687 case CANEXCEL_EVENT_ERROR:
688 LOG_DBG("Error Format Frames (error 0x%x)", u32SysStatus);
689 break;
690 case CANEXCEL_EVENT_ERROR_FD:
691 LOG_DBG("Error Data Phase (error 0x%x)", u32SysStatus);
692 break;
693 case CANEXCEL_EVENT_PASSIVE:
694 LOG_DBG("Error Passive (error 0x%x)", u32SysStatus);
695 break;
696 default:
697 break;
698 }
699
700 can_nxp_s32_get_state(dev, &state, &err_cnt);
701 if (data->state != state) {
702 data->state = state;
703 if (data->state_change_cb) {
704 data->state_change_cb(dev, state, err_cnt, cb_data);
705 }
706 }
707
708 if (state == CAN_STATE_BUS_OFF) {
709 /* Abort any pending TX frames in case of bus-off */
710 for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) {
711 /* Copy callback function and argument before clearing bit */
712 function = data->tx_cbs[alloc].function;
713 arg = data->tx_cbs[alloc].arg;
714
715 if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
716 if (can_nxp_s32_abort_msg(config,
717 ALLOC_IDX_TO_TXMB_IDX(alloc))) {
718 LOG_ERR("Can't abort message !");
719 };
720
721 function(dev, -ENETUNREACH, arg);
722 k_sem_give(&data->tx_allocs_sem);
723 }
724 }
725 }
726 }
727
728 static void nxp_s32_msg_data_to_zcan_frame(Canexcel_RxFdMsg msg_data,
729 struct can_frame *frame)
730 {
731 memset(frame, 0, sizeof(*frame));
732
733 if (!!(msg_data.Header.Id & CANXL_TX_HEADER_IDE_MASK)) {
734 frame->flags |= CAN_FRAME_IDE;
735 }
736
737 if (!!(frame->flags & CAN_FRAME_IDE)) {
738 frame->id = (msg_data.Header.Id & CANXL_IP_ID_EXT_MASK);
739 } else {
740 frame->id = ((msg_data.Header.Id & CANXL_IP_ID_STD_MASK)
741 >> CANXL_IP_ID_STD_SHIFT);
742 }
743
744 frame->dlc = (msg_data.Header.Control & CANXL_TX_HEADER_DLC_MASK)
745 >> CANXL_TX_HEADER_DLC_SHIFT;
746
747 if (!!(msg_data.Header.Control & CANXL_TX_HEADER_FDF_MASK)) {
748 frame->flags |= CAN_FRAME_FDF;
749 }
750
751 if (!!(msg_data.Header.Control & CANXL_TX_HEADER_BRS_MASK)) {
752 frame->flags |= CAN_FRAME_BRS;
753 }
754
755 if (!!(msg_data.Header.Id & CANXL_TX_HEADER_RTR_MASK)) {
756 frame->flags |= CAN_FRAME_RTR;
757 } else {
758 memcpy(frame->data, msg_data.data, can_dlc_to_bytes(frame->dlc));
759 }
760
761 #ifdef CONFIG_CAN_RX_TIMESTAMP
762 frame->timestamp = msg_data.timeStampL;
763 #endif /* CAN_RX_TIMESTAMP */
764 }
765
766 static void can_nxp_s32_ctrl_callback(const struct device *dev,
767 Canexcel_Ip_EventType eventType, uint32 buffidx,
768 const Canexcel_Ip_StateType *canexcelState)
769 {
770 const struct can_nxp_s32_config *config = dev->config;
771 struct can_nxp_s32_data *data = dev->data;
772 struct can_frame frame = {0};
773 can_tx_callback_t tx_func;
774 can_rx_callback_t rx_func;
775 Canexcel_Ip_StatusType status;
776 int alloc;
777
778 if (eventType == CANEXCEL_EVENT_TX_COMPLETE) {
779 alloc = TX_MBIDX_TO_ALLOC_IDX(buffidx);
780 tx_func = data->tx_cbs[alloc].function;
781 LOG_DBG("%s: Sent Tx Mb %d", dev->name, buffidx);
782 if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
783 tx_func(dev, 0, data->tx_cbs[alloc].arg);
784 k_sem_give(&data->tx_allocs_sem);
785 }
786 } else if (eventType == CANEXCEL_EVENT_RX_COMPLETE) {
787 alloc = RX_MBIDX_TO_ALLOC_IDX(buffidx);
788 rx_func = data->rx_cbs[alloc].function;
789 if (atomic_test_bit(data->rx_allocs, alloc)) {
790 nxp_s32_msg_data_to_zcan_frame(data->rx_msg[alloc], &frame);
791
792 LOG_DBG("%s: Received %d bytes Rx Mb %d, "
793 "Rx Id: 0x%x, "
794 "Id type: %s %s %s %s",
795 dev->name, can_dlc_to_bytes(frame.dlc),
796 buffidx, frame.id,
797 !!(frame.flags & CAN_FRAME_IDE) ?
798 "extended" : "standard",
799 !!(frame.flags & CAN_FRAME_RTR) ? "RTR" : "",
800 !!(frame.flags & CAN_FRAME_FDF) ? "FD frame" : "",
801 !!(frame.flags & CAN_FRAME_BRS) ? "BRS" : "");
802
803 rx_func(dev, &frame, data->rx_cbs[alloc].arg);
804
805 status = Canexcel_Ip_ReceiveFD(config->instance, buffidx,
806 &data->rx_msg[alloc], FALSE);
807 if (status != CANEXCEL_STATUS_SUCCESS) {
808 LOG_ERR("MB %d is not ready for receiving next message", buffidx);
809 }
810 }
811 }
812 }
813
814 static int can_nxp_s32_init(const struct device *dev)
815 {
816 const struct can_nxp_s32_config *config = dev->config;
817 struct can_nxp_s32_data *data = dev->data;
818 int err;
819 #ifdef CONFIG_CAN_RX_TIMESTAMP
820 Canexcel_Ip_TimeStampConf_Type time_stamp = {
821 .ts64bit = FALSE, /* Time stamp size is 32 bits */
822 .capture = CANEXCEL_TIMESTAMPCAPTURE_END,
823 .src = CANTBS_TIMESURCE_BUS1
824 };
825 #endif
826
827 if (config->phy != NULL) {
828 if (!device_is_ready(config->phy)) {
829 LOG_ERR("CAN transceiver not ready");
830 return -ENODEV;
831 }
832 }
833
834 if (!device_is_ready(config->clock_dev)) {
835 LOG_ERR("Clock control device not ready");
836 return -ENODEV;
837 }
838
839 err = clock_control_on(config->clock_dev, config->clock_subsys);
840 if (err) {
841 LOG_ERR("Failed to enable clock");
842 return err;
843 }
844
845 k_mutex_init(&data->rx_mutex);
846 k_mutex_init(&data->tx_mutex);
847 k_sem_init(&data->tx_allocs_sem, CONFIG_CAN_NXP_S32_MAX_TX, CONFIG_CAN_NXP_S32_MAX_TX);
848
849 err = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT);
850 if (err < 0) {
851 return err;
852 }
853
854 /* Enable CANXL HW */
855 IP_MC_RGM->PRST_0[0].PRST_0 &=
856 ~(MC_RGM_PRST_0_PERIPH_16_RST_MASK | MC_RGM_PRST_0_PERIPH_24_RST_MASK);
857
858 data->timing.sjw = config->sjw;
859 if (config->sample_point) {
860 err = can_calc_timing(dev, &data->timing, config->bitrate,
861 config->sample_point);
862 if (err == -EINVAL) {
863 LOG_ERR("Can't find timing for given param");
864 return -EIO;
865 }
866 if (err > 0) {
867 LOG_WRN("Sample-point error : %d", err);
868 }
869 } else {
870 data->timing.prop_seg = config->prop_seg;
871 data->timing.phase_seg1 = config->phase_seg1;
872 data->timing.phase_seg2 = config->phase_seg2;
873 err = can_calc_prescaler(dev, &data->timing, config->bitrate);
874 if (err) {
875 LOG_WRN("Bitrate error: %d", err);
876 }
877 }
878
879 LOG_DBG("Setting CAN bitrate %d:", config->bitrate);
880 nxp_s32_zcan_timing_to_canxl_timing(&data->timing, &config->can_cfg->bitrate);
881
882 #ifdef CONFIG_CAN_FD_MODE
883 data->timing_data.sjw = config->sjw_data;
884 if (config->sample_point_data) {
885 err = can_calc_timing_data(dev, &data->timing_data, config->bitrate_data,
886 config->sample_point_data);
887 if (err == -EINVAL) {
888 LOG_ERR("Can't find timing data for given param");
889 return -EIO;
890 }
891 if (err > 0) {
892 LOG_WRN("Sample-point-data err : %d", err);
893 }
894 } else {
895 data->timing_data.prop_seg = config->prop_seg_data;
896 data->timing_data.phase_seg1 = config->phase_seg1_data;
897 data->timing_data.phase_seg2 = config->phase_seg2_data;
898 err = can_calc_prescaler(dev, &data->timing_data, config->bitrate_data);
899 if (err) {
900 LOG_WRN("Bitrate data error: %d", err);
901 }
902 }
903
904 LOG_DBG("Setting CAN-FD bitrate %d:", config->bitrate_data);
905 nxp_s32_zcan_timing_to_canxl_timing(&data->timing_data, &config->can_cfg->Fd_bitrate);
906 #endif
907
908 /* Initialize CAN structure */
909 Canexcel_Ip_Init(config->instance, config->can_cfg, data->can_state);
910
911 /* Configure time stamp */
912 #ifdef CONFIG_CAN_RX_TIMESTAMP
913 Canexcel_Ip_ConfigTimeStamp(config->instance, &time_stamp);
914 #endif
915
916 /* Enable Interrupt */
917 Canexcel_Ip_EnableInterrupts(config->instance);
918
919 /* Enable Error Interrupt */
920 CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_RX_WARNING, TRUE);
921 CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_TX_WARNING, TRUE);
922 CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_ERR, TRUE);
923 CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_BUSOFF, TRUE);
924 CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_PASIVE_ERR, TRUE);
925
926 config->irq_config_func();
927
928 can_nxp_s32_get_state(dev, &data->state, NULL);
929
930 return 0;
931 }
932
933 static const struct can_driver_api can_nxp_s32_driver_api = {
934 .get_capabilities = can_nxp_s32_get_capabilities,
935 .start = can_nxp_s32_start,
936 .stop = can_nxp_s32_stop,
937 .set_mode = can_nxp_s32_set_mode,
938 .set_timing = can_nxp_s32_set_timing,
939 .send = can_nxp_s32_send,
940 .add_rx_filter = can_nxp_s32_add_rx_filter,
941 .remove_rx_filter = can_nxp_s32_remove_rx_filter,
942 .get_state = can_nxp_s32_get_state,
943 #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
944 .recover = can_nxp_s32_recover,
945 #endif
946 .set_state_change_callback = can_nxp_s32_set_state_change_callback,
947 .get_core_clock = can_nxp_s32_get_core_clock,
948 .get_max_filters = can_nxp_s32_get_max_filters,
949 .get_max_bitrate = can_nxp_s32_get_max_bitrate,
950 .timing_min = {
951 .sjw = 0x01,
952 .prop_seg = 0x01,
953 .phase_seg1 = 0x01,
954 .phase_seg2 = 0x02,
955 .prescaler = 0x01
956 },
957 .timing_max = {
958 .sjw = 0x04,
959 .prop_seg = 0x08,
960 .phase_seg1 = 0x08,
961 .phase_seg2 = 0x08,
962 .prescaler = 0x100
963 },
964 #ifdef CONFIG_CAN_FD_MODE
965 .set_timing_data = can_nxp_s32_set_timing_data,
966 .timing_data_min = {
967 .sjw = 0x01,
968 .prop_seg = 0x01,
969 .phase_seg1 = 0x01,
970 .phase_seg2 = 0x02,
971 .prescaler = 0x01
972 },
973 .timing_data_max = {
974 .sjw = 0x04,
975 .prop_seg = 0x08,
976 .phase_seg1 = 0x08,
977 .phase_seg2 = 0x08,
978 .prescaler = 0x100
979 }
980 #endif
981 };
982
983 #define CAN_NXP_S32_NODE(n) DT_NODELABEL(can##n)
984
985 #define CAN_NXP_S32_IRQ_HANDLER(n, irq_name) DT_CAT5(CANXL, n, _, irq_name, Handler)
986
987 #define _CAN_NXP_S32_IRQ_CONFIG(node_id, prop, idx, n) \
988 do { \
989 extern void (CAN_NXP_S32_IRQ_HANDLER(n, \
990 DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)))(void); \
991 IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \
992 DT_IRQ_BY_IDX(node_id, idx, priority), \
993 CAN_NXP_S32_IRQ_HANDLER(n, \
994 DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)), \
995 NULL, \
996 DT_IRQ_BY_IDX(node_id, idx, flags)); \
997 irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \
998 } while (false);
999
1000 #define CAN_NXP_S32_IRQ_CONFIG(n) \
1001 static void can_irq_config_##n(void) \
1002 { \
1003 DT_FOREACH_PROP_ELEM_VARGS(CAN_NXP_S32_NODE(n), interrupt_names, \
1004 _CAN_NXP_S32_IRQ_CONFIG, n); \
1005 }
1006
1007 #define CAN_NXP_S32_ERR_CALLBACK(n) \
1008 void nxp_s32_can_##n##_err_callback(uint8 instance, Canexcel_Ip_EventType eventType,\
1009 uint32 u32SysStatus, const Canexcel_Ip_StateType *canexcelState) \
1010 { \
1011 const struct device *dev = DEVICE_DT_GET(CAN_NXP_S32_NODE(n)); \
1012 can_nxp_s32_err_callback(dev, eventType, u32SysStatus, canexcelState); \
1013 }
1014
1015 #define CAN_NXP_S32_CTRL_CALLBACK(n) \
1016 void nxp_s32_can_##n##_ctrl_callback(uint8 instance, Canexcel_Ip_EventType eventType,\
1017 uint32 buffIdx, const Canexcel_Ip_StateType *canexcelState) \
1018 { \
1019 const struct device *dev = DEVICE_DT_GET(CAN_NXP_S32_NODE(n)); \
1020 can_nxp_s32_ctrl_callback(dev, eventType, buffIdx, canexcelState); \
1021 }
1022
1023 #if defined(CONFIG_CAN_FD_MODE)
1024 #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) \
1025 .bitrate_data = DT_PROP(CAN_NXP_S32_NODE(n), bus_speed_data), \
1026 .sjw_data = DT_PROP(CAN_NXP_S32_NODE(n), sjw_data), \
1027 .prop_seg_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), prop_seg_data, 0), \
1028 .phase_seg1_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg1_data, 0), \
1029 .phase_seg2_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg2_data, 0), \
1030 .sample_point_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), sample_point_data, 0),
1031 #define CAN_NXP_S32_FD_MODE 1
1032 #define CAN_NXP_S32_BRS 1
1033 #else
1034 #define CAN_NXP_S32_TIMING_DATA_CONFIG(n)
1035 #define CAN_NXP_S32_FD_MODE 0
1036 #define CAN_NXP_S32_BRS 0
1037 #endif
1038
1039 #ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
1040 #define CAN_NXP_S32_CTRL_OPTIONS CANXL_IP_BUSOFF_RECOVERY_U32
1041 #else
1042 #define CAN_NXP_S32_CTRL_OPTIONS 0
1043 #endif
1044
1045 #define CAN_NXP_S32_INIT_DEVICE(n) \
1046 CAN_NXP_S32_CTRL_CALLBACK(n) \
1047 CAN_NXP_S32_ERR_CALLBACK(n) \
1048 CAN_NXP_S32_IRQ_CONFIG(n) \
1049 PINCTRL_DT_DEFINE(CAN_NXP_S32_NODE(n)); \
1050 Canexcel_Ip_ConfigType can_nxp_s32_default_config##n = { \
1051 .rx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_RX, \
1052 .tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \
1053 .CanxlMode = CANEXCEL_LISTEN_ONLY_MODE, \
1054 .fd_enable = (boolean)CAN_NXP_S32_FD_MODE, \
1055 .bitRateSwitch = (boolean)CAN_NXP_S32_BRS, \
1056 .ctrlOptions = (uint32)CAN_NXP_S32_CTRL_OPTIONS, \
1057 .Callback = nxp_s32_can_##n##_ctrl_callback, \
1058 .ErrorCallback = nxp_s32_can_##n##_err_callback \
1059 }; \
1060 __nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \
1061 __nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \
1062 __nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX]; \
1063 static struct can_nxp_s32_data can_nxp_s32_data_##n = { \
1064 .can_state = (Canexcel_Ip_StateType *)&can_nxp_s32_state##n, \
1065 .tx_msg = tx_msg##n, \
1066 .rx_msg = rx_msg_##n, \
1067 }; \
1068 static struct can_nxp_s32_config can_nxp_s32_config_##n = { \
1069 .base_sic = (CANXL_SIC_Type *) \
1070 DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), sic), \
1071 .base_grp_ctrl = (CANXL_GRP_CONTROL_Type *) \
1072 DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), grp_ctrl), \
1073 .base_dsc_ctrl = (CANXL_DSC_CONTROL_Type *) \
1074 DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), dsc_ctrl), \
1075 .instance = n, \
1076 .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(CAN_NXP_S32_NODE(n))), \
1077 .clock_subsys = (clock_control_subsys_t) \
1078 DT_CLOCKS_CELL(CAN_NXP_S32_NODE(n), name), \
1079 .bitrate = DT_PROP(CAN_NXP_S32_NODE(n), bus_speed), \
1080 .sjw = DT_PROP(CAN_NXP_S32_NODE(n), sjw), \
1081 .prop_seg = DT_PROP_OR(CAN_NXP_S32_NODE(n), prop_seg, 0), \
1082 .phase_seg1 = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg1, 0), \
1083 .phase_seg2 = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg2, 0), \
1084 .sample_point = DT_PROP_OR(CAN_NXP_S32_NODE(n), sample_point, 0), \
1085 CAN_NXP_S32_TIMING_DATA_CONFIG(n) \
1086 .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(CAN_NXP_S32_NODE(n), \
1087 CAN_NXP_S32_MAX_BITRATE), \
1088 .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(CAN_NXP_S32_NODE(n), phys)), \
1089 .pin_cfg = PINCTRL_DT_DEV_CONFIG_GET(CAN_NXP_S32_NODE(n)), \
1090 .can_cfg = (Canexcel_Ip_ConfigType *)&can_nxp_s32_default_config##n, \
1091 .irq_config_func = can_irq_config_##n \
1092 }; \
1093 static int can_nxp_s32_##n##_init(const struct device *dev) \
1094 { \
1095 return can_nxp_s32_init(dev); \
1096 } \
1097 CAN_DEVICE_DT_DEFINE(CAN_NXP_S32_NODE(n), \
1098 can_nxp_s32_##n##_init, \
1099 NULL, \
1100 &can_nxp_s32_data_##n, \
1101 &can_nxp_s32_config_##n, \
1102 POST_KERNEL, \
1103 CONFIG_CAN_INIT_PRIORITY, \
1104 &can_nxp_s32_driver_api);
1105
1106 #if DT_NODE_HAS_STATUS(CAN_NXP_S32_NODE(0), okay)
1107 CAN_NXP_S32_INIT_DEVICE(0)
1108 #endif
1109
1110 #if DT_NODE_HAS_STATUS(CAN_NXP_S32_NODE(1), okay)
1111 CAN_NXP_S32_INIT_DEVICE(1)
1112 #endif
1113