2022-11-30 02:47:14 +01:00
|
|
|
/*
|
2024-01-12 11:54:05 +01:00
|
|
|
* Copyright 2022-2024 NXP
|
2022-11-30 02:47:14 +01:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include <zephyr/sys/atomic.h>
|
|
|
|
#include <zephyr/drivers/can.h>
|
|
|
|
#include <zephyr/drivers/can/transceiver.h>
|
2023-09-18 07:30:49 +02:00
|
|
|
#include <zephyr/drivers/clock_control.h>
|
2022-11-30 02:47:14 +01:00
|
|
|
#include <zephyr/device.h>
|
|
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
#include <zephyr/irq.h>
|
|
|
|
|
|
|
|
#include <CanEXCEL_Ip_HwAccess.h>
|
|
|
|
#include <CanEXCEL_Ip_Irq.h>
|
|
|
|
|
|
|
|
#define DT_DRV_COMPAT nxp_s32_canxl
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert from RX message buffer index to allocated filter ID and
|
|
|
|
* vice versa.
|
|
|
|
*/
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
#define RX_MBIDX_TO_ALLOC_IDX(x) (x)
|
|
|
|
#define ALLOC_IDX_TO_RXMB_IDX(x) (x)
|
|
|
|
#else
|
2022-11-30 02:47:14 +01:00
|
|
|
#define RX_MBIDX_TO_ALLOC_IDX(x) (x - CONFIG_CAN_NXP_S32_MAX_TX)
|
|
|
|
#define ALLOC_IDX_TO_RXMB_IDX(x) (x + CONFIG_CAN_NXP_S32_MAX_TX)
|
2024-01-12 11:54:05 +01:00
|
|
|
#endif
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert from TX message buffer index to allocated TX ID and vice
|
|
|
|
* versa.
|
|
|
|
*/
|
|
|
|
#define TX_MBIDX_TO_ALLOC_IDX(x) (x)
|
|
|
|
#define ALLOC_IDX_TO_TXMB_IDX(x) (x)
|
|
|
|
|
|
|
|
#define CAN_NXP_S32_TIMEOUT_MS 1
|
|
|
|
#define CAN_NXP_S32_MAX_BITRATE 8000000
|
|
|
|
#define CAN_NXP_S32_DATA_LENGTH 64
|
|
|
|
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
/* RX FIFO depth is fixed to the maximum value */
|
|
|
|
#define CAN_NXP_S32_RX_FIFO_DEPTH 32
|
|
|
|
/* RX FIFO water mark equal 1 that allows the interrupt is generated after 1 message received */
|
|
|
|
#define CAN_NXP_S32_RX_FIFO_WATERMARK 1
|
|
|
|
#endif
|
|
|
|
|
2024-01-23 08:04:57 +01:00
|
|
|
#if defined(CONFIG_CAN_FD_MODE) && defined(CONFIG_CAN_NXP_S32_RX_FIFO)
|
|
|
|
#define CAN_NXP_S32_FD_MODE 1
|
|
|
|
#endif
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL);
|
|
|
|
|
|
|
|
struct can_nxp_s32_config {
|
2024-01-17 19:53:56 +01:00
|
|
|
const struct can_driver_config common;
|
2022-11-30 02:47:14 +01:00
|
|
|
CANXL_SIC_Type *base_sic;
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
CANXL_RXFIFO_Type * base_rx_fifo;
|
|
|
|
CANXL_RXFIFO_CONTROL_Type *base_rx_fifo_ctrl;
|
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
uint8 instance;
|
2023-09-18 07:30:49 +02:00
|
|
|
const struct device *clock_dev;
|
|
|
|
clock_control_subsys_t clock_subsys;
|
2022-11-30 02:47:14 +01:00
|
|
|
const struct pinctrl_dev_config *pin_cfg;
|
|
|
|
Canexcel_Ip_ConfigType *can_cfg;
|
|
|
|
void (*irq_config_func)(void);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct can_nxp_s32_tx_callback {
|
|
|
|
Canexcel_Ip_DataInfoType tx_info;
|
|
|
|
can_tx_callback_t function;
|
|
|
|
void *arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct can_nxp_s32_rx_callback {
|
|
|
|
struct can_filter filter;
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifndef CONFIG_CAN_NXP_S32_RX_FIFO
|
2022-11-30 02:47:14 +01:00
|
|
|
Canexcel_Ip_DataInfoType rx_info;
|
2024-01-12 11:54:05 +01:00
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
can_rx_callback_t function;
|
|
|
|
void *arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct can_nxp_s32_data {
|
2024-01-17 19:53:56 +01:00
|
|
|
struct can_driver_data common;
|
2022-11-30 02:47:14 +01:00
|
|
|
Canexcel_Ip_StateType *can_state;
|
|
|
|
|
|
|
|
ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_NXP_S32_MAX_RX);
|
|
|
|
struct k_mutex rx_mutex;
|
|
|
|
struct can_nxp_s32_rx_callback rx_cbs[CONFIG_CAN_NXP_S32_MAX_RX];
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifndef CONFIG_CAN_NXP_S32_RX_FIFO
|
2022-11-30 02:47:14 +01:00
|
|
|
Canexcel_RxFdMsg *rx_msg;
|
2024-01-12 11:54:05 +01:00
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
ATOMIC_DEFINE(tx_allocs, CONFIG_CAN_NXP_S32_MAX_TX);
|
|
|
|
struct k_sem tx_allocs_sem;
|
|
|
|
struct k_mutex tx_mutex;
|
|
|
|
struct can_nxp_s32_tx_callback tx_cbs[CONFIG_CAN_NXP_S32_MAX_TX];
|
|
|
|
Canexcel_TxFdMsgType *tx_msg;
|
|
|
|
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
Canexcel_Ip_RxFifoFilterID_ADDR * rx_fifo_filter;
|
|
|
|
Canexcel_RxFdMsg *rx_fifo;
|
|
|
|
#endif
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
struct can_timing timing;
|
2024-01-23 08:04:57 +01:00
|
|
|
#ifdef CAN_NXP_S32_FD_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
struct can_timing timing_data;
|
|
|
|
#endif
|
|
|
|
enum can_state state;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *cap)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
|
|
|
*cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY;
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) {
|
|
|
|
*cap |= CAN_MODE_MANUAL_RECOVERY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CAN_NXP_S32_FD_MODE)) {
|
|
|
|
*cap |= CAN_MODE_FD;
|
|
|
|
}
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
static void can_nxp_s32_config_rx_fifo_filter(const struct device *dev, int filter_id)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
|
|
|
|
/* Lock the RxFIFO by System by reading register */
|
|
|
|
(void)config->base_rx_fifo_ctrl->RXFSYSLOCK;
|
|
|
|
|
|
|
|
CanXL_ConfigIDFilter(config->base_rx_fifo,
|
|
|
|
&data->rx_fifo_filter[filter_id], filter_id);
|
|
|
|
|
|
|
|
if ((config->base_rx_fifo_ctrl->RXFCSTA & CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK)
|
|
|
|
== CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK) {
|
|
|
|
/* Clear the sys lock to enable transfers */
|
|
|
|
config->base_rx_fifo_ctrl->RXFSYSLOCK =
|
|
|
|
CANXL_RXFIFO_CONTROL_RXFSYSLOCK_SYSLOCK_MASK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the RxFiFO filter matched with the received RxFIFO message queue */
|
|
|
|
static inline int can_nxp_s32_get_rx_fifo_filter(struct can_nxp_s32_data *data)
|
|
|
|
{
|
|
|
|
int alloc = -ENOSPC;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
for (int filter_id = 0; filter_id < CONFIG_CAN_NXP_S32_MAX_RX; filter_id++) {
|
|
|
|
mask = data->rx_fifo_filter[filter_id].idAddrFilterL;
|
|
|
|
|
|
|
|
if (mask == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((data->rx_fifo[0].Header.Id & mask) ==
|
|
|
|
(data->rx_fifo_filter[filter_id].idAddrFilterH & mask)) {
|
|
|
|
alloc = filter_id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return alloc;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
static int can_nxp_s32_start(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
int err;
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (config->common.phy != NULL) {
|
2024-01-24 14:09:31 +01:00
|
|
|
err = can_transceiver_enable(config->common.phy, data->common.mode);
|
2022-11-30 02:47:14 +01:00
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to enable CAN transceiver (err %d)", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
data->common.started = true;
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_stop(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
can_tx_callback_t function;
|
|
|
|
void *arg;
|
|
|
|
int alloc;
|
|
|
|
int err;
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (!data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
data->common.started = false;
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
/* Abort any pending TX frames before entering freeze mode */
|
|
|
|
for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) {
|
|
|
|
function = data->tx_cbs[alloc].function;
|
|
|
|
arg = data->tx_cbs[alloc].arg;
|
|
|
|
|
|
|
|
if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
|
2024-03-01 08:43:49 +01:00
|
|
|
if (Canexcel_Ip_DeactivateMD(config->instance,
|
2022-11-30 02:47:14 +01:00
|
|
|
ALLOC_IDX_TO_TXMB_IDX(alloc))) {
|
|
|
|
LOG_ERR("Can't abort message !");
|
|
|
|
};
|
|
|
|
|
|
|
|
function(dev, -ENETDOWN, arg);
|
|
|
|
k_sem_give(&data->tx_allocs_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (config->common.phy != NULL) {
|
|
|
|
err = can_transceiver_disable(config->common.phy);
|
2022-11-30 02:47:14 +01:00
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to disable CAN transceiver (err %d)", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode)
|
|
|
|
{
|
2024-02-14 22:38:34 +01:00
|
|
|
can_mode_t supported = CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY;
|
2022-11-30 02:47:14 +01:00
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
Canexcel_Ip_ModesType can_nxp_s32_mode = CAN_MODE_NORMAL;
|
|
|
|
bool canfd = false;
|
|
|
|
bool brs = false;
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
2024-02-14 22:38:34 +01:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) {
|
|
|
|
supported |= CAN_MODE_MANUAL_RECOVERY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CAN_NXP_S32_FD_MODE)) {
|
|
|
|
supported |= CAN_MODE_FD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mode & ~(supported)) != 0) {
|
2022-11-30 02:47:14 +01:00
|
|
|
LOG_ERR("unsupported mode: 0x%08x", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mode & (CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY))
|
|
|
|
== (CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY)) {
|
|
|
|
LOG_ERR("unsupported mode loopback and "
|
|
|
|
"mode listen-only at the same time: 0x%08x", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
canfd = !!(mode & CAN_MODE_FD);
|
|
|
|
brs = canfd;
|
|
|
|
|
|
|
|
if (mode & CAN_MODE_LISTENONLY) {
|
|
|
|
can_nxp_s32_mode = CANEXCEL_LISTEN_ONLY_MODE;
|
|
|
|
} else if (mode & CAN_MODE_LOOPBACK) {
|
|
|
|
can_nxp_s32_mode = CANEXCEL_LOOPBACK_MODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Canexcel_Ip_EnterFreezeMode(config->instance);
|
|
|
|
|
|
|
|
CanXL_SetFDEnabled(config->base_sic, canfd, brs);
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) {
|
|
|
|
Canexcel_Ip_StatusType status;
|
|
|
|
uint32_t options = 0U;
|
|
|
|
|
|
|
|
if ((mode & CAN_MODE_MANUAL_RECOVERY) == 0U) {
|
|
|
|
options = CANXL_IP_BUSOFF_RECOVERY_U32;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = CanXL_ConfigCtrlOptions(config->base_sic, options);
|
|
|
|
if (status != CANEXCEL_STATUS_SUCCESS) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
CanXL_SetOperationMode(config->base_sic, can_nxp_s32_mode);
|
|
|
|
|
|
|
|
Canexcel_Ip_ExitFreezeMode(config->instance);
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
data->common.mode = mode;
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_get_core_clock(const struct device *dev, uint32_t *rate)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
|
|
|
|
__ASSERT_NO_MSG(rate != NULL);
|
|
|
|
|
2023-09-18 07:30:49 +02:00
|
|
|
return clock_control_get_rate(config->clock_dev, config->clock_subsys, rate);
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_get_max_filters(const struct device *dev, bool ide)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(ide);
|
|
|
|
|
|
|
|
return CONFIG_CAN_NXP_S32_MAX_RX;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_get_state(const struct device *dev, enum can_state *state,
|
|
|
|
struct can_bus_err_cnt *err_cnt)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
uint32_t sys_status = config->base_sic->SYSS;
|
|
|
|
|
|
|
|
if (state) {
|
2024-01-17 19:53:56 +01:00
|
|
|
if (!data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
*state = CAN_STATE_STOPPED;
|
|
|
|
} else {
|
|
|
|
if (sys_status & CANXL_SIC_SYSS_CBOFF_MASK) {
|
|
|
|
*state = CAN_STATE_BUS_OFF;
|
|
|
|
} else if (sys_status & CANXL_SIC_SYSS_CPASERR_MASK) {
|
|
|
|
*state = CAN_STATE_ERROR_PASSIVE;
|
|
|
|
} else if (sys_status & (CANXL_SIC_SYSS_CRXWRN_MASK
|
|
|
|
| CANXL_SIC_SYSS_CTXWRN_MASK)) {
|
|
|
|
*state = CAN_STATE_ERROR_WARNING;
|
|
|
|
} else {
|
|
|
|
*state = CAN_STATE_ERROR_ACTIVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err_cnt) {
|
|
|
|
/* NXP S32 CANXL HAL is not supported error counter */
|
|
|
|
err_cnt->tx_err_cnt = 0;
|
|
|
|
err_cnt->rx_err_cnt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void can_nxp_s32_set_state_change_callback(const struct device *dev,
|
|
|
|
can_state_change_callback_t callback,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
data->common.state_change_cb = callback;
|
|
|
|
data->common.state_change_cb_user_data = user_data;
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
#ifdef CONFIG_CAN_MANUAL_RECOVERY_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
static int can_nxp_s32_recover(const struct device *dev, k_timeout_t timeout)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
enum can_state state;
|
|
|
|
uint64_t start_time;
|
|
|
|
int ret = 0;
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (!data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if ((data->common.mode & CAN_MODE_MANUAL_RECOVERY) == 0U) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
can_nxp_s32_get_state(dev, &state, NULL);
|
|
|
|
if (state != CAN_STATE_BUS_OFF) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
start_time = k_uptime_ticks();
|
|
|
|
config->base_sic->BCFG1 &= (~CANXL_SIC_BCFG1_ABRDIS_MASK);
|
|
|
|
|
|
|
|
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
|
|
|
can_nxp_s32_get_state(dev, &state, NULL);
|
|
|
|
|
|
|
|
while (state == CAN_STATE_BUS_OFF) {
|
|
|
|
if (!K_TIMEOUT_EQ(timeout, K_FOREVER) &&
|
|
|
|
k_uptime_ticks() - start_time >= timeout.ticks) {
|
|
|
|
ret = -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
can_nxp_s32_get_state(dev, &state, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
config->base_sic->BCFG1 |= CANXL_SIC_BCFG1_ABRDIS_MASK;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2024-02-14 22:38:34 +01:00
|
|
|
#endif /* CONFIG_CAN_MANUAL_RECOVERY_MODE */
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
static void can_nxp_s32_remove_rx_filter(const struct device *dev, int filter_id)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
int mb_indx = ALLOC_IDX_TO_RXMB_IDX(filter_id);
|
|
|
|
|
2023-10-24 22:16:11 +02:00
|
|
|
if (filter_id < 0 || filter_id >= CONFIG_CAN_NXP_S32_MAX_RX) {
|
|
|
|
LOG_ERR("filter ID %d out of bounds", filter_id);
|
|
|
|
return;
|
|
|
|
}
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
k_mutex_lock(&data->rx_mutex, K_FOREVER);
|
|
|
|
|
|
|
|
if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
data->rx_fifo_filter[mb_indx].idAddrFilterL = 0;
|
|
|
|
data->rx_fifo_filter[mb_indx].idAddrFilterH = 0;
|
|
|
|
|
|
|
|
Canexcel_Ip_EnterFreezeMode(config->instance);
|
|
|
|
|
|
|
|
can_nxp_s32_config_rx_fifo_filter(dev, mb_indx);
|
|
|
|
|
|
|
|
Canexcel_Ip_ExitFreezeMode(config->instance);
|
|
|
|
#else
|
2024-03-01 08:43:49 +01:00
|
|
|
if (Canexcel_Ip_DeactivateMD(config->instance, mb_indx)) {
|
2022-11-30 02:47:14 +01:00
|
|
|
LOG_ERR("Can't abort message !");
|
|
|
|
};
|
2024-01-12 11:54:05 +01:00
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
data->rx_cbs[filter_id].function = NULL;
|
|
|
|
data->rx_cbs[filter_id].arg = NULL;
|
|
|
|
data->rx_cbs[filter_id].filter = (struct can_filter){0};
|
|
|
|
} else {
|
|
|
|
LOG_WRN("Filter ID %d already detached", filter_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
k_mutex_unlock(&data->rx_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_add_rx_filter(const struct device *dev,
|
|
|
|
can_rx_callback_t callback,
|
|
|
|
void *user_data,
|
|
|
|
const struct can_filter *filter)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
int alloc = -ENOSPC;
|
|
|
|
int mb_indx;
|
|
|
|
uint32_t mask;
|
|
|
|
|
2023-12-15 13:36:18 +01:00
|
|
|
if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) {
|
2022-11-30 02:47:14 +01:00
|
|
|
LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
k_mutex_lock(&data->rx_mutex, K_FOREVER);
|
|
|
|
|
|
|
|
/* Find and allocate RX message buffer */
|
|
|
|
for (int i = 0; i < CONFIG_CAN_NXP_S32_MAX_RX; i++) {
|
|
|
|
if (!atomic_test_and_set_bit(data->rx_allocs, i)) {
|
|
|
|
alloc = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alloc == -ENOSPC) {
|
|
|
|
LOG_ERR("No free filter bank found");
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->rx_cbs[alloc].function = callback;
|
|
|
|
data->rx_cbs[alloc].arg = user_data;
|
|
|
|
data->rx_cbs[alloc].filter = *filter;
|
|
|
|
|
|
|
|
/* Set Rx Mb individual mask for */
|
|
|
|
mb_indx = ALLOC_IDX_TO_RXMB_IDX(alloc);
|
|
|
|
if (!!(filter->flags & CAN_FILTER_IDE)) {
|
2024-01-12 11:54:05 +01:00
|
|
|
mask = filter->mask & CANXL_IP_ID_EXT_MASK;
|
2022-11-30 02:47:14 +01:00
|
|
|
} else {
|
2024-01-12 11:54:05 +01:00
|
|
|
mask = (filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK;
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
|
2023-12-15 13:36:18 +01:00
|
|
|
#ifndef CONFIG_CAN_ACCEPT_RTR
|
|
|
|
mask |= CANXL_MSG_DESCRIPTORS_MDFLT1FD_RTRMSK_MASK;
|
|
|
|
#endif /* !CONFIG_CAN_ACCEPT_RTR */
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
Canexcel_Ip_EnterFreezeMode(config->instance);
|
|
|
|
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
uint32_t filter_id;
|
|
|
|
|
|
|
|
if (!!(filter->flags & CAN_FILTER_IDE)) {
|
|
|
|
filter_id = filter->id & CANXL_IP_ID_EXT_MASK;
|
|
|
|
} else {
|
|
|
|
filter_id = (filter->id << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->rx_fifo_filter[mb_indx].filterType = CANEXCEL_IP_RX_FIFO_MASK_FILTER;
|
|
|
|
data->rx_fifo_filter[mb_indx].idAddrFilterL = mask;
|
|
|
|
data->rx_fifo_filter[mb_indx].idAddrFilterH = filter_id;
|
|
|
|
|
|
|
|
can_nxp_s32_config_rx_fifo_filter(dev, mb_indx);
|
|
|
|
#else
|
|
|
|
data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) {
|
2023-11-10 14:17:56 +01:00
|
|
|
.frame = CANEXCEL_CLASIC_FRAME,
|
2024-01-12 11:54:05 +01:00
|
|
|
.idType = !!(filter->flags & CAN_FILTER_IDE) ?
|
|
|
|
CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD,
|
|
|
|
.dataLength = CAN_NXP_S32_DATA_LENGTH,
|
|
|
|
};
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
Canexcel_Ip_SetRxIndividualMask(config->instance, mb_indx,
|
|
|
|
data->rx_cbs[alloc].rx_info.frame, mask);
|
|
|
|
|
|
|
|
Canexcel_Ip_ConfigRx(config->instance, mb_indx, filter->id,
|
|
|
|
&data->rx_cbs[alloc].rx_info);
|
|
|
|
|
|
|
|
Canexcel_Ip_ReceiveFD(config->instance, mb_indx, &data->rx_msg[alloc], FALSE);
|
2024-01-12 11:54:05 +01:00
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
Canexcel_Ip_ExitFreezeMode(config->instance);
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->rx_mutex);
|
|
|
|
|
|
|
|
return alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_send(const struct device *dev,
|
|
|
|
const struct can_frame *frame,
|
|
|
|
k_timeout_t timeout,
|
|
|
|
can_tx_callback_t callback, void *user_data)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
uint8_t data_length = can_dlc_to_bytes(frame->dlc);
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
Canexcel_Ip_StatusType status;
|
|
|
|
enum can_state state;
|
|
|
|
int alloc, mb_indx;
|
|
|
|
|
2024-01-23 08:04:57 +01:00
|
|
|
#ifdef CAN_NXP_S32_FD_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) {
|
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((frame->flags & CAN_FRAME_FDF) != 0 &&
|
|
|
|
(config->base_sic->BCFG2 & CANXL_SIC_BCFG2_FDEN_MASK) == 0) {
|
2023-10-31 10:09:38 +01:00
|
|
|
LOG_ERR("CAN FD format not supported in non-FD mode");
|
2022-11-30 02:47:14 +01:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((frame->flags & CAN_FRAME_BRS) != 0 &&
|
|
|
|
~(config->base_sic->BCFG1 & CANXL_SIC_BCFG1_FDRSDIS_MASK) == 0) {
|
2023-10-31 10:09:38 +01:00
|
|
|
LOG_ERR("CAN FD BRS not supported in non-FD mode");
|
2022-11-30 02:47:14 +01:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if ((frame->flags & ~CAN_FRAME_IDE) != 0) {
|
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (data_length > sizeof(frame->data)) {
|
|
|
|
LOG_ERR("data length (%d) > max frame data length (%d)",
|
|
|
|
data_length, sizeof(frame->data));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((frame->flags & CAN_FRAME_FDF) == 0) {
|
|
|
|
if (frame->dlc > CAN_MAX_DLC) {
|
|
|
|
LOG_ERR("DLC of %d for non-FD format frame", frame->dlc);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2024-01-23 08:04:57 +01:00
|
|
|
#ifdef CAN_NXP_S32_FD_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
} else {
|
|
|
|
if (frame->dlc > CANFD_MAX_DLC) {
|
2023-10-31 10:09:38 +01:00
|
|
|
LOG_ERR("DLC of %d for CAN FD format frame", frame->dlc);
|
2022-11-30 02:47:14 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (!data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
can_nxp_s32_get_state(dev, &state, NULL);
|
|
|
|
if (state == CAN_STATE_BUS_OFF) {
|
|
|
|
LOG_ERR("Transmit failed, bus-off");
|
|
|
|
return -ENETUNREACH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k_sem_take(&data->tx_allocs_sem, timeout) != 0) {
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) {
|
|
|
|
if (!atomic_test_and_set_bit(data->tx_allocs, alloc)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data->tx_cbs[alloc].function = callback;
|
|
|
|
data->tx_cbs[alloc].arg = user_data;
|
|
|
|
mb_indx = ALLOC_IDX_TO_TXMB_IDX(alloc);
|
|
|
|
data->tx_cbs[alloc].tx_info = (Canexcel_Ip_DataInfoType) {
|
|
|
|
.frame = !!(frame->flags & CAN_FRAME_FDF) ?
|
|
|
|
CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME,
|
|
|
|
.enable_brs = !!(frame->flags & CAN_FRAME_BRS) ? TRUE : FALSE,
|
|
|
|
.idType = !!(frame->flags & CAN_FRAME_IDE) ?
|
|
|
|
CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD,
|
|
|
|
.priority = 0,
|
|
|
|
.fd_padding = 0,
|
|
|
|
.dataLength = data_length,
|
|
|
|
.is_polling = FALSE
|
|
|
|
};
|
|
|
|
|
|
|
|
LOG_DBG("%s: Sending %d bytes Tx Mb %d, "
|
|
|
|
"Tx Id: 0x%x, "
|
|
|
|
"Id type: %s %s %s %s",
|
|
|
|
dev->name, data_length,
|
|
|
|
mb_indx, frame->id,
|
|
|
|
!!(frame->flags & CAN_FRAME_IDE) ?
|
|
|
|
"extended" : "standard",
|
|
|
|
!!(frame->flags & CAN_FRAME_RTR) ? "RTR" : "",
|
|
|
|
!!(frame->flags & CAN_FRAME_FDF) ? "FD frame" : "",
|
|
|
|
!!(frame->flags & CAN_FRAME_BRS) ? "BRS" : "");
|
|
|
|
|
|
|
|
k_mutex_lock(&data->tx_mutex, K_FOREVER);
|
|
|
|
/* Send MB Interrupt */
|
|
|
|
status = Canexcel_Ip_SendFDMsg(config->instance, mb_indx, &data->tx_cbs[alloc].tx_info,
|
|
|
|
frame->id, (uint8_t *)&frame->data, &data->tx_msg[alloc]);
|
|
|
|
k_mutex_unlock(&data->tx_mutex);
|
|
|
|
|
|
|
|
if (status != CANEXCEL_STATUS_SUCCESS) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nxp_s32_zcan_timing_to_canxl_timing(const struct can_timing *timing,
|
|
|
|
Canexcel_Ip_TimeSegmentType *canxl_timing)
|
|
|
|
{
|
|
|
|
LOG_DBG("propSeg: %d, phase_seg1: %d, phase_seg2: %d, prescaler: %d, sjw: %d",
|
|
|
|
timing->prop_seg, timing->phase_seg1, timing->phase_seg2,
|
|
|
|
timing->prescaler, timing->sjw);
|
|
|
|
|
|
|
|
canxl_timing->propSeg = timing->prop_seg - 1U;
|
|
|
|
canxl_timing->phaseSeg1 = timing->phase_seg1 - 1U;
|
|
|
|
canxl_timing->phaseSeg2 = timing->phase_seg2 - 1U;
|
|
|
|
canxl_timing->preDivider = timing->prescaler - 1U;
|
|
|
|
canxl_timing->rJumpwidth = timing->sjw - 1U;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_set_timing(const struct device *dev,
|
|
|
|
const struct can_timing *timing)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
Canexcel_Ip_TimeSegmentType can_time_segment = {0};
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
nxp_s32_zcan_timing_to_canxl_timing(timing, &can_time_segment);
|
|
|
|
|
|
|
|
/* Set timing for CAN instance*/
|
|
|
|
CanXL_SetBaudRate(config->base_sic, &can_time_segment);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-23 08:04:57 +01:00
|
|
|
#ifdef CAN_NXP_S32_FD_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
static int can_nxp_s32_set_timing_data(const struct device *dev,
|
|
|
|
const struct can_timing *timing_data)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
Canexcel_Ip_TimeSegmentType can_fd_time_segment = {0};
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (data->common.started) {
|
2022-11-30 02:47:14 +01:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
nxp_s32_zcan_timing_to_canxl_timing(timing_data, &can_fd_time_segment);
|
|
|
|
|
|
|
|
/* Set timing for CAN FD instance*/
|
|
|
|
CanXL_SetFDBaudRate(config->base_sic, &can_fd_time_segment);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void can_nxp_s32_err_callback(const struct device *dev,
|
|
|
|
Canexcel_Ip_EventType eventType,
|
|
|
|
uint32 u32SysStatus,
|
|
|
|
const Canexcel_Ip_StateType *canexcelState)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
enum can_state state;
|
|
|
|
struct can_bus_err_cnt err_cnt;
|
2024-01-17 19:53:56 +01:00
|
|
|
void *cb_data = data->common.state_change_cb_user_data;
|
2022-11-30 02:47:14 +01:00
|
|
|
can_tx_callback_t function;
|
|
|
|
int alloc;
|
|
|
|
void *arg;
|
|
|
|
|
|
|
|
switch (eventType) {
|
|
|
|
case CANEXCEL_EVENT_TX_WARNING:
|
|
|
|
LOG_DBG("Tx Warning (error 0x%x)", u32SysStatus);
|
|
|
|
break;
|
|
|
|
case CANEXCEL_EVENT_RX_WARNING:
|
|
|
|
LOG_DBG("Rx Warning (error 0x%x)", u32SysStatus);
|
|
|
|
break;
|
|
|
|
case CANEXCEL_EVENT_BUSOFF:
|
|
|
|
LOG_DBG("Bus Off (error 0x%x)", u32SysStatus);
|
|
|
|
break;
|
|
|
|
case CANEXCEL_EVENT_ERROR:
|
|
|
|
LOG_DBG("Error Format Frames (error 0x%x)", u32SysStatus);
|
|
|
|
break;
|
|
|
|
case CANEXCEL_EVENT_ERROR_FD:
|
|
|
|
LOG_DBG("Error Data Phase (error 0x%x)", u32SysStatus);
|
|
|
|
break;
|
|
|
|
case CANEXCEL_EVENT_PASSIVE:
|
|
|
|
LOG_DBG("Error Passive (error 0x%x)", u32SysStatus);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
can_nxp_s32_get_state(dev, &state, &err_cnt);
|
|
|
|
if (data->state != state) {
|
|
|
|
data->state = state;
|
2024-01-17 19:53:56 +01:00
|
|
|
if (data->common.state_change_cb) {
|
|
|
|
data->common.state_change_cb(dev, state, err_cnt, cb_data);
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == CAN_STATE_BUS_OFF) {
|
|
|
|
/* Abort any pending TX frames in case of bus-off */
|
|
|
|
for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) {
|
|
|
|
/* Copy callback function and argument before clearing bit */
|
|
|
|
function = data->tx_cbs[alloc].function;
|
|
|
|
arg = data->tx_cbs[alloc].arg;
|
|
|
|
|
|
|
|
if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
|
2024-03-01 08:43:49 +01:00
|
|
|
if (Canexcel_Ip_DeactivateMD(config->instance,
|
2022-11-30 02:47:14 +01:00
|
|
|
ALLOC_IDX_TO_TXMB_IDX(alloc))) {
|
|
|
|
LOG_ERR("Can't abort message !");
|
|
|
|
};
|
|
|
|
|
|
|
|
function(dev, -ENETUNREACH, arg);
|
|
|
|
k_sem_give(&data->tx_allocs_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nxp_s32_msg_data_to_zcan_frame(Canexcel_RxFdMsg msg_data,
|
|
|
|
struct can_frame *frame)
|
|
|
|
{
|
2023-10-11 13:33:29 +02:00
|
|
|
memset(frame, 0, sizeof(*frame));
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
if (!!(msg_data.Header.Id & CANXL_TX_HEADER_IDE_MASK)) {
|
|
|
|
frame->flags |= CAN_FRAME_IDE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!!(frame->flags & CAN_FRAME_IDE)) {
|
|
|
|
frame->id = (msg_data.Header.Id & CANXL_IP_ID_EXT_MASK);
|
|
|
|
} else {
|
|
|
|
frame->id = ((msg_data.Header.Id & CANXL_IP_ID_STD_MASK)
|
|
|
|
>> CANXL_IP_ID_STD_SHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
frame->dlc = (msg_data.Header.Control & CANXL_TX_HEADER_DLC_MASK)
|
|
|
|
>> CANXL_TX_HEADER_DLC_SHIFT;
|
|
|
|
|
|
|
|
if (!!(msg_data.Header.Control & CANXL_TX_HEADER_FDF_MASK)) {
|
|
|
|
frame->flags |= CAN_FRAME_FDF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!!(msg_data.Header.Control & CANXL_TX_HEADER_BRS_MASK)) {
|
|
|
|
frame->flags |= CAN_FRAME_BRS;
|
|
|
|
}
|
|
|
|
|
2023-10-11 13:33:29 +02:00
|
|
|
if (!!(msg_data.Header.Id & CANXL_TX_HEADER_RTR_MASK)) {
|
|
|
|
frame->flags |= CAN_FRAME_RTR;
|
|
|
|
} else {
|
|
|
|
memcpy(frame->data, msg_data.data, can_dlc_to_bytes(frame->dlc));
|
|
|
|
}
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
|
|
|
frame->timestamp = msg_data.timeStampL;
|
|
|
|
#endif /* CAN_RX_TIMESTAMP */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void can_nxp_s32_ctrl_callback(const struct device *dev,
|
|
|
|
Canexcel_Ip_EventType eventType, uint32 buffidx,
|
|
|
|
const Canexcel_Ip_StateType *canexcelState)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
struct can_frame frame = {0};
|
|
|
|
can_tx_callback_t tx_func;
|
|
|
|
can_rx_callback_t rx_func;
|
|
|
|
int alloc;
|
|
|
|
|
|
|
|
if (eventType == CANEXCEL_EVENT_TX_COMPLETE) {
|
|
|
|
alloc = TX_MBIDX_TO_ALLOC_IDX(buffidx);
|
|
|
|
tx_func = data->tx_cbs[alloc].function;
|
|
|
|
LOG_DBG("%s: Sent Tx Mb %d", dev->name, buffidx);
|
|
|
|
if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
|
|
|
|
tx_func(dev, 0, data->tx_cbs[alloc].arg);
|
|
|
|
k_sem_give(&data->tx_allocs_sem);
|
|
|
|
}
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
} else if (eventType == CANEXCEL_EVENT_RXFIFO_COMPLETE) {
|
|
|
|
alloc = can_nxp_s32_get_rx_fifo_filter(data);
|
|
|
|
|
|
|
|
if (alloc != -ENOSPC) {
|
|
|
|
rx_func = data->rx_cbs[alloc].function;
|
|
|
|
if (atomic_test_bit(data->rx_allocs, alloc)) {
|
|
|
|
nxp_s32_msg_data_to_zcan_frame(data->rx_fifo[0], &frame);
|
|
|
|
|
|
|
|
LOG_DBG("%s: Received %d bytes Rx FiFo %d, "
|
|
|
|
"Rx Id: 0x%x, "
|
|
|
|
"Id type: %s %s %s %s",
|
|
|
|
dev->name, can_dlc_to_bytes(frame.dlc),
|
|
|
|
alloc, frame.id,
|
|
|
|
!!(frame.flags & CAN_FRAME_IDE) ?
|
|
|
|
"extended" : "standard",
|
|
|
|
!!(frame.flags & CAN_FRAME_RTR) ? "RTR" : "",
|
|
|
|
!!(frame.flags & CAN_FRAME_FDF) ? "FD frame" : "",
|
|
|
|
!!(frame.flags & CAN_FRAME_BRS) ? "BRS" : "");
|
|
|
|
|
|
|
|
rx_func(dev, &frame, data->rx_cbs[alloc].arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pop 1 (= RXFSYSPOP + 1) received RxFIFO message queue */
|
|
|
|
config->base_rx_fifo_ctrl->RXFSYSPOP = 0;
|
|
|
|
#else
|
2022-11-30 02:47:14 +01:00
|
|
|
} else if (eventType == CANEXCEL_EVENT_RX_COMPLETE) {
|
|
|
|
alloc = RX_MBIDX_TO_ALLOC_IDX(buffidx);
|
|
|
|
rx_func = data->rx_cbs[alloc].function;
|
|
|
|
if (atomic_test_bit(data->rx_allocs, alloc)) {
|
|
|
|
nxp_s32_msg_data_to_zcan_frame(data->rx_msg[alloc], &frame);
|
|
|
|
|
|
|
|
LOG_DBG("%s: Received %d bytes Rx Mb %d, "
|
|
|
|
"Rx Id: 0x%x, "
|
|
|
|
"Id type: %s %s %s %s",
|
|
|
|
dev->name, can_dlc_to_bytes(frame.dlc),
|
|
|
|
buffidx, frame.id,
|
|
|
|
!!(frame.flags & CAN_FRAME_IDE) ?
|
|
|
|
"extended" : "standard",
|
|
|
|
!!(frame.flags & CAN_FRAME_RTR) ? "RTR" : "",
|
|
|
|
!!(frame.flags & CAN_FRAME_FDF) ? "FD frame" : "",
|
|
|
|
!!(frame.flags & CAN_FRAME_BRS) ? "BRS" : "");
|
|
|
|
|
|
|
|
rx_func(dev, &frame, data->rx_cbs[alloc].arg);
|
|
|
|
|
2024-01-12 11:54:05 +01:00
|
|
|
if (Canexcel_Ip_ReceiveFD(config->instance, buffidx,
|
|
|
|
&data->rx_msg[alloc], FALSE) != CANEXCEL_STATUS_SUCCESS) {
|
2022-11-30 02:47:14 +01:00
|
|
|
LOG_ERR("MB %d is not ready for receiving next message", buffidx);
|
|
|
|
}
|
|
|
|
}
|
2024-01-12 11:54:05 +01:00
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_nxp_s32_init(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
struct can_nxp_s32_data *data = dev->data;
|
|
|
|
int err;
|
|
|
|
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
|
|
|
Canexcel_Ip_TimeStampConf_Type time_stamp = {
|
|
|
|
.ts64bit = FALSE, /* Time stamp size is 32 bits */
|
|
|
|
.capture = CANEXCEL_TIMESTAMPCAPTURE_END,
|
|
|
|
.src = CANTBS_TIMESURCE_BUS1
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
if (config->common.phy != NULL) {
|
|
|
|
if (!device_is_ready(config->common.phy)) {
|
2022-11-30 02:47:14 +01:00
|
|
|
LOG_ERR("CAN transceiver not ready");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-18 07:30:49 +02:00
|
|
|
if (!device_is_ready(config->clock_dev)) {
|
|
|
|
LOG_ERR("Clock control device not ready");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = clock_control_on(config->clock_dev, config->clock_subsys);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to enable clock");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
k_mutex_init(&data->rx_mutex);
|
|
|
|
k_mutex_init(&data->tx_mutex);
|
|
|
|
k_sem_init(&data->tx_allocs_sem, CONFIG_CAN_NXP_S32_MAX_TX, CONFIG_CAN_NXP_S32_MAX_TX);
|
|
|
|
|
|
|
|
err = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT);
|
|
|
|
if (err < 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable CANXL HW */
|
|
|
|
IP_MC_RGM->PRST_0[0].PRST_0 &=
|
|
|
|
~(MC_RGM_PRST_0_PERIPH_16_RST_MASK | MC_RGM_PRST_0_PERIPH_24_RST_MASK);
|
|
|
|
|
2024-02-07 17:35:21 +01:00
|
|
|
err = can_calc_timing(dev, &data->timing, config->common.bus_speed,
|
|
|
|
config->common.sample_point);
|
|
|
|
if (err == -EINVAL) {
|
|
|
|
LOG_ERR("Can't find timing for given param");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err > 0) {
|
|
|
|
LOG_WRN("Sample-point error : %d", err);
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
LOG_DBG("Setting CAN bitrate %d:", config->common.bus_speed);
|
2022-11-30 02:47:14 +01:00
|
|
|
nxp_s32_zcan_timing_to_canxl_timing(&data->timing, &config->can_cfg->bitrate);
|
|
|
|
|
2024-01-23 08:04:57 +01:00
|
|
|
#ifdef CAN_NXP_S32_FD_MODE
|
2024-02-07 17:35:21 +01:00
|
|
|
err = can_calc_timing_data(dev, &data->timing_data, config->common.bus_speed_data,
|
|
|
|
config->common.sample_point_data);
|
|
|
|
if (err == -EINVAL) {
|
|
|
|
LOG_ERR("Can't find timing data for given param");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err > 0) {
|
|
|
|
LOG_WRN("Sample-point-data err : %d", err);
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
|
2024-01-17 19:53:56 +01:00
|
|
|
LOG_DBG("Setting CAN FD bitrate %d:", config->common.bus_speed_data);
|
2022-11-30 02:47:14 +01:00
|
|
|
nxp_s32_zcan_timing_to_canxl_timing(&data->timing_data, &config->can_cfg->Fd_bitrate);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Initialize CAN structure */
|
|
|
|
Canexcel_Ip_Init(config->instance, config->can_cfg, data->can_state);
|
|
|
|
|
|
|
|
/* Configure time stamp */
|
|
|
|
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
|
|
|
Canexcel_Ip_ConfigTimeStamp(config->instance, &time_stamp);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Enable Interrupt */
|
|
|
|
Canexcel_Ip_EnableInterrupts(config->instance);
|
|
|
|
|
|
|
|
/* Enable Error Interrupt */
|
|
|
|
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_RX_WARNING, TRUE);
|
|
|
|
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_TX_WARNING, TRUE);
|
|
|
|
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_ERR, TRUE);
|
|
|
|
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_BUSOFF, TRUE);
|
|
|
|
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_PASIVE_ERR, TRUE);
|
2024-01-12 11:54:05 +01:00
|
|
|
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
|
|
|
|
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_RXFIFO_OVER, TRUE);
|
|
|
|
|
|
|
|
/* Configure number of ID acceptance filters*/
|
|
|
|
config->base_rx_fifo->AFCFG =
|
|
|
|
CANXL_RXFIFO_AFCFG_ACPTID(CONFIG_CAN_NXP_S32_MAX_RX - 1);
|
|
|
|
#endif
|
2022-11-30 02:47:14 +01:00
|
|
|
|
|
|
|
config->irq_config_func();
|
|
|
|
|
|
|
|
can_nxp_s32_get_state(dev, &data->state, NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-11-09 11:36:17 +01:00
|
|
|
static void can_nxp_s32_isr_rx_tx(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
|
|
|
|
Canexcel_Ip_RxTxIRQHandler(config->instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void can_nxp_s32_isr_error(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_nxp_s32_config *config = dev->config;
|
|
|
|
|
|
|
|
Canexcel_Ip_ErrIRQHandler(config->instance);
|
|
|
|
}
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
static const struct can_driver_api can_nxp_s32_driver_api = {
|
|
|
|
.get_capabilities = can_nxp_s32_get_capabilities,
|
|
|
|
.start = can_nxp_s32_start,
|
|
|
|
.stop = can_nxp_s32_stop,
|
|
|
|
.set_mode = can_nxp_s32_set_mode,
|
|
|
|
.set_timing = can_nxp_s32_set_timing,
|
|
|
|
.send = can_nxp_s32_send,
|
|
|
|
.add_rx_filter = can_nxp_s32_add_rx_filter,
|
|
|
|
.remove_rx_filter = can_nxp_s32_remove_rx_filter,
|
|
|
|
.get_state = can_nxp_s32_get_state,
|
2024-02-14 22:38:34 +01:00
|
|
|
#ifdef CONFIG_CAN_MANUAL_RECOVERY_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
.recover = can_nxp_s32_recover,
|
2024-02-14 22:38:34 +01:00
|
|
|
#endif /* CONFIG_CAN_MANUAL_RECOVERY_MODE */
|
2022-11-30 02:47:14 +01:00
|
|
|
.set_state_change_callback = can_nxp_s32_set_state_change_callback,
|
|
|
|
.get_core_clock = can_nxp_s32_get_core_clock,
|
|
|
|
.get_max_filters = can_nxp_s32_get_max_filters,
|
|
|
|
.timing_min = {
|
|
|
|
.sjw = 0x01,
|
|
|
|
.prop_seg = 0x01,
|
|
|
|
.phase_seg1 = 0x01,
|
|
|
|
.phase_seg2 = 0x02,
|
|
|
|
.prescaler = 0x01
|
|
|
|
},
|
|
|
|
.timing_max = {
|
|
|
|
.sjw = 0x04,
|
|
|
|
.prop_seg = 0x08,
|
|
|
|
.phase_seg1 = 0x08,
|
|
|
|
.phase_seg2 = 0x08,
|
|
|
|
.prescaler = 0x100
|
|
|
|
},
|
2024-01-23 08:04:57 +01:00
|
|
|
#ifdef CAN_NXP_S32_FD_MODE
|
2022-11-30 02:47:14 +01:00
|
|
|
.set_timing_data = can_nxp_s32_set_timing_data,
|
|
|
|
.timing_data_min = {
|
|
|
|
.sjw = 0x01,
|
|
|
|
.prop_seg = 0x01,
|
|
|
|
.phase_seg1 = 0x01,
|
|
|
|
.phase_seg2 = 0x02,
|
|
|
|
.prescaler = 0x01
|
|
|
|
},
|
|
|
|
.timing_data_max = {
|
|
|
|
.sjw = 0x04,
|
|
|
|
.prop_seg = 0x08,
|
|
|
|
.phase_seg1 = 0x08,
|
|
|
|
.phase_seg2 = 0x08,
|
|
|
|
.prescaler = 0x100
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2023-11-09 11:36:17 +01:00
|
|
|
#define _CAN_NXP_S32_IRQ_CONFIG(node_id, prop, idx) \
|
2022-11-30 02:47:14 +01:00
|
|
|
do { \
|
|
|
|
IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \
|
|
|
|
DT_IRQ_BY_IDX(node_id, idx, priority), \
|
2023-11-09 11:36:17 +01:00
|
|
|
UTIL_CAT(can_nxp_s32_isr_, \
|
2022-11-30 02:47:14 +01:00
|
|
|
DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)), \
|
2023-11-09 11:36:17 +01:00
|
|
|
DEVICE_DT_GET(node_id), \
|
2022-11-30 02:47:14 +01:00
|
|
|
DT_IRQ_BY_IDX(node_id, idx, flags)); \
|
|
|
|
irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
#define CAN_NXP_S32_IRQ_CONFIG(n) \
|
|
|
|
static void can_irq_config_##n(void) \
|
|
|
|
{ \
|
2023-11-09 11:36:17 +01:00
|
|
|
DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, _CAN_NXP_S32_IRQ_CONFIG); \
|
2022-11-30 02:47:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#define CAN_NXP_S32_ERR_CALLBACK(n) \
|
|
|
|
void nxp_s32_can_##n##_err_callback(uint8 instance, Canexcel_Ip_EventType eventType,\
|
|
|
|
uint32 u32SysStatus, const Canexcel_Ip_StateType *canexcelState) \
|
|
|
|
{ \
|
2023-11-09 11:36:17 +01:00
|
|
|
const struct device *dev = DEVICE_DT_INST_GET(n); \
|
2022-11-30 02:47:14 +01:00
|
|
|
can_nxp_s32_err_callback(dev, eventType, u32SysStatus, canexcelState); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CAN_NXP_S32_CTRL_CALLBACK(n) \
|
|
|
|
void nxp_s32_can_##n##_ctrl_callback(uint8 instance, Canexcel_Ip_EventType eventType,\
|
|
|
|
uint32 buffIdx, const Canexcel_Ip_StateType *canexcelState) \
|
|
|
|
{ \
|
2023-11-09 11:36:17 +01:00
|
|
|
const struct device *dev = DEVICE_DT_INST_GET(n); \
|
2022-11-30 02:47:14 +01:00
|
|
|
can_nxp_s32_ctrl_callback(dev, eventType, buffIdx, canexcelState); \
|
|
|
|
}
|
|
|
|
|
2024-01-23 08:04:57 +01:00
|
|
|
#if defined(CAN_NXP_S32_FD_MODE)
|
2022-11-30 02:47:14 +01:00
|
|
|
#define CAN_NXP_S32_BRS 1
|
|
|
|
#else
|
|
|
|
#define CAN_NXP_S32_BRS 0
|
|
|
|
#endif
|
|
|
|
|
2023-11-09 11:36:17 +01:00
|
|
|
#define CAN_NXP_S32_HW_INSTANCE_CHECK(i, n) \
|
|
|
|
((DT_INST_REG_ADDR(n) == IP_CANXL_##i##__SIC_BASE) ? i : 0)
|
|
|
|
|
|
|
|
#define CAN_NXP_S32_HW_INSTANCE(n) \
|
|
|
|
LISTIFY(__DEBRACKET CANXL_SIC_INSTANCE_COUNT, CAN_NXP_S32_HW_INSTANCE_CHECK, (|), n)
|
|
|
|
|
2022-11-30 02:47:14 +01:00
|
|
|
#define CAN_NXP_S32_INIT_DEVICE(n) \
|
|
|
|
CAN_NXP_S32_CTRL_CALLBACK(n) \
|
|
|
|
CAN_NXP_S32_ERR_CALLBACK(n) \
|
|
|
|
CAN_NXP_S32_IRQ_CONFIG(n) \
|
2023-11-09 11:36:17 +01:00
|
|
|
PINCTRL_DT_INST_DEFINE(n); \
|
2024-01-12 11:54:05 +01:00
|
|
|
\
|
|
|
|
__nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \
|
|
|
|
__nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \
|
|
|
|
IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
|
|
|
|
(__nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \
|
|
|
|
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
|
|
|
|
(__nocache Canexcel_RxFdMsg rx_fifo_##n[CAN_NXP_S32_RX_FIFO_DEPTH]; \
|
|
|
|
static Canexcel_Ip_RxFifoFilterID_ADDR \
|
|
|
|
rx_fifo_filter##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \
|
2022-11-30 02:47:14 +01:00
|
|
|
Canexcel_Ip_ConfigType can_nxp_s32_default_config##n = { \
|
2024-01-12 11:54:05 +01:00
|
|
|
.rx_mbdesc = (uint8)IS_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO) ? \
|
|
|
|
0 : CONFIG_CAN_NXP_S32_MAX_RX, \
|
2022-11-30 02:47:14 +01:00
|
|
|
.tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \
|
|
|
|
.CanxlMode = CANEXCEL_LISTEN_ONLY_MODE, \
|
2024-01-23 08:04:57 +01:00
|
|
|
.fd_enable = (boolean)IS_ENABLED(CAN_NXP_S32_FD_MODE), \
|
2022-11-30 02:47:14 +01:00
|
|
|
.bitRateSwitch = (boolean)CAN_NXP_S32_BRS, \
|
2024-02-14 22:38:34 +01:00
|
|
|
.ctrlOptions = CANXL_IP_BUSOFF_RECOVERY_U32, \
|
2022-11-30 02:47:14 +01:00
|
|
|
.Callback = nxp_s32_can_##n##_ctrl_callback, \
|
2024-01-12 11:54:05 +01:00
|
|
|
.ErrorCallback = nxp_s32_can_##n##_err_callback, \
|
|
|
|
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
|
|
|
|
(.is_rx_fifo_needed = (boolean)TRUE, \
|
|
|
|
.pRxFifoConfig = { \
|
|
|
|
.Rx_Fifo_Depth = CAN_NXP_S32_RX_FIFO_DEPTH, \
|
|
|
|
.Rx_Fifo_Watermark = CAN_NXP_S32_RX_FIFO_WATERMARK, \
|
|
|
|
.Rx_Fifo_Msg_Size = CAN_NXP_S32_DATA_LENGTH, \
|
|
|
|
.Rx_Fifo_KeepLast = (boolean)FALSE, \
|
|
|
|
.isPolling = (boolean)FALSE, \
|
|
|
|
.MsgBuffersPtr = (uint32 *)rx_fifo_##n, \
|
|
|
|
},)) \
|
2022-11-30 02:47:14 +01:00
|
|
|
}; \
|
|
|
|
static struct can_nxp_s32_data can_nxp_s32_data_##n = { \
|
|
|
|
.can_state = (Canexcel_Ip_StateType *)&can_nxp_s32_state##n, \
|
|
|
|
.tx_msg = tx_msg##n, \
|
2024-01-12 11:54:05 +01:00
|
|
|
IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
|
|
|
|
(.rx_msg = rx_msg_##n,)) \
|
|
|
|
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
|
|
|
|
(.rx_fifo = rx_fifo_##n, \
|
|
|
|
.rx_fifo_filter = \
|
|
|
|
(Canexcel_Ip_RxFifoFilterID_ADDR *)&rx_fifo_filter##n,))\
|
2022-11-30 02:47:14 +01:00
|
|
|
}; \
|
|
|
|
static struct can_nxp_s32_config can_nxp_s32_config_##n = { \
|
2024-02-26 22:34:59 +01:00
|
|
|
.common = CAN_DT_DRIVER_CONFIG_INST_GET(n, 0, CAN_NXP_S32_MAX_BITRATE), \
|
2023-11-09 11:36:17 +01:00
|
|
|
.base_sic = (CANXL_SIC_Type *)DT_INST_REG_ADDR_BY_NAME(n, sic), \
|
2024-01-12 11:54:05 +01:00
|
|
|
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
|
|
|
|
(.base_rx_fifo = (CANXL_RXFIFO_Type *) \
|
|
|
|
DT_INST_REG_ADDR_BY_NAME(n, rx_fifo), \
|
|
|
|
.base_rx_fifo_ctrl = (CANXL_RXFIFO_CONTROL_Type *) \
|
|
|
|
DT_INST_REG_ADDR_BY_NAME(n, rx_fifo_ctrl),)) \
|
2023-11-09 11:36:17 +01:00
|
|
|
.instance = CAN_NXP_S32_HW_INSTANCE(n), \
|
|
|
|
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
|
2023-09-18 07:30:49 +02:00
|
|
|
.clock_subsys = (clock_control_subsys_t) \
|
2023-11-09 11:36:17 +01:00
|
|
|
DT_INST_CLOCKS_CELL(n, name), \
|
|
|
|
.pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
2022-11-30 02:47:14 +01:00
|
|
|
.can_cfg = (Canexcel_Ip_ConfigType *)&can_nxp_s32_default_config##n, \
|
|
|
|
.irq_config_func = can_irq_config_##n \
|
|
|
|
}; \
|
|
|
|
static int can_nxp_s32_##n##_init(const struct device *dev) \
|
|
|
|
{ \
|
|
|
|
return can_nxp_s32_init(dev); \
|
|
|
|
} \
|
2023-11-09 11:36:17 +01:00
|
|
|
CAN_DEVICE_DT_INST_DEFINE(n, \
|
|
|
|
can_nxp_s32_##n##_init, \
|
|
|
|
NULL, \
|
|
|
|
&can_nxp_s32_data_##n, \
|
|
|
|
&can_nxp_s32_config_##n, \
|
|
|
|
POST_KERNEL, \
|
|
|
|
CONFIG_CAN_INIT_PRIORITY, \
|
|
|
|
&can_nxp_s32_driver_api);
|
|
|
|
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(CAN_NXP_S32_INIT_DEVICE)
|