drivers: can: mcux: flexcan: add FlexCAN CANFD variant support
Add support for CAN-FD capable variants of the FlexCAN IP core. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
parent
764d00ce18
commit
95b8bf3121
2 changed files with 574 additions and 58 deletions
|
@ -4,22 +4,33 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config CAN_MCUX_FLEXCAN
|
||||
bool "MCUX FlexCAN driver"
|
||||
bool "NXP FlexCAN driver"
|
||||
default y
|
||||
depends on DT_HAS_NXP_FLEXCAN_ENABLED
|
||||
depends on CLOCK_CONTROL
|
||||
help
|
||||
Enable support for the NXP MCUX FlexCAN driver.
|
||||
Enable support for the NXP FlexCAN driver.
|
||||
|
||||
if CAN_MCUX_FLEXCAN
|
||||
|
||||
config CAN_MCUX_FLEXCAN_FD
|
||||
bool # hidden
|
||||
default y
|
||||
depends on DT_HAS_NXP_FLEXCAN_FD_ENABLED && CAN_FD_MODE
|
||||
help
|
||||
Enable support for CAN-FD capable NXP FlexCAN devices.
|
||||
|
||||
config CAN_MAX_FILTER
|
||||
int "Maximum number of concurrent active RX filters"
|
||||
depends on CAN_MCUX_FLEXCAN
|
||||
default 5
|
||||
range 1 15 if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_KINETIS_K6X
|
||||
range 1 13 if SOC_SERIES_IMX_RT && CAN_MCUX_FLEXCAN_FD
|
||||
range 1 63 if SOC_SERIES_IMX_RT
|
||||
help
|
||||
Defines maximum number of concurrent active RX filters
|
||||
|
||||
endif # CAN_MCUX_FLEXCAN
|
||||
|
||||
config CAN_MCUX_MCAN
|
||||
bool "MCUX MCAN driver"
|
||||
default y
|
||||
|
|
|
@ -4,8 +4,12 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Base driver compatible */
|
||||
#define DT_DRV_COMPAT nxp_flexcan
|
||||
|
||||
/* CAN-FD extension compatible */
|
||||
#define FLEXCAN_FD_DRV_COMPAT nxp_flexcan_fd
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/drivers/can.h>
|
||||
|
@ -89,6 +93,15 @@ struct mcux_flexcan_config {
|
|||
uint32_t prop_seg;
|
||||
uint32_t phase_seg1;
|
||||
uint32_t phase_seg2;
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
bool flexcan_fd;
|
||||
uint32_t bitrate_data;
|
||||
uint32_t sample_point_data;
|
||||
uint32_t sjw_data;
|
||||
uint32_t prop_seg_data;
|
||||
uint32_t phase_seg1_data;
|
||||
uint32_t phase_seg2_data;
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
void (*irq_config_func)(const struct device *dev);
|
||||
void (*irq_enable_func)(void);
|
||||
void (*irq_disable_func)(void);
|
||||
|
@ -96,18 +109,25 @@ struct mcux_flexcan_config {
|
|||
uint32_t max_bitrate;
|
||||
#ifdef CONFIG_PINCTRL
|
||||
const struct pinctrl_dev_config *pincfg;
|
||||
#endif
|
||||
#endif /* CONFIG_PINCTRL */
|
||||
};
|
||||
|
||||
struct mcux_flexcan_rx_callback {
|
||||
flexcan_rx_mb_config_t mb_config;
|
||||
flexcan_frame_t frame;
|
||||
union {
|
||||
flexcan_frame_t classic;
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
flexcan_fd_frame_t fd;
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
} frame;
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
bool fdf;
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
can_rx_callback_t function;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct mcux_flexcan_tx_callback {
|
||||
flexcan_frame_t frame;
|
||||
can_tx_callback_t function;
|
||||
void *arg;
|
||||
};
|
||||
|
@ -128,6 +148,10 @@ struct mcux_flexcan_data {
|
|||
can_state_change_callback_t state_change_cb;
|
||||
void *state_change_cb_data;
|
||||
struct can_timing timing;
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
struct can_timing timing_data;
|
||||
bool fd_mode;
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
bool started;
|
||||
};
|
||||
|
||||
|
@ -176,15 +200,97 @@ static int mcux_flexcan_set_timing(const struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
static int mcux_flexcan_set_timing_data(const struct device *dev,
|
||||
const struct can_timing *timing_data)
|
||||
{
|
||||
struct mcux_flexcan_data *data = dev->data;
|
||||
uint8_t sjw_backup = data->timing_data.sjw;
|
||||
|
||||
if (!timing_data) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data->started) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
data->timing_data = *timing_data;
|
||||
if (timing_data->sjw == CAN_SJW_NO_CHANGE) {
|
||||
data->timing_data.sjw = sjw_backup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
static int mcux_flexcan_get_capabilities(const struct device *dev, can_mode_t *cap)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
__maybe_unused const struct mcux_flexcan_config *config = dev->config;
|
||||
|
||||
*cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_3_SAMPLES;
|
||||
|
||||
if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), config->flexcan_fd)) {
|
||||
*cap |= CAN_MODE_FD;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc)
|
||||
{
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
struct mcux_flexcan_data *data = dev->data;
|
||||
flexcan_mb_transfer_t xfer;
|
||||
status_t status;
|
||||
|
||||
__ASSERT_NO_MSG(alloc >= 0 && alloc < ARRAY_SIZE(data->rx_cbs));
|
||||
|
||||
xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc);
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
xfer.framefd = &data->rx_cbs[alloc].frame.fd;
|
||||
FLEXCAN_SetFDRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc),
|
||||
&data->rx_cbs[alloc].mb_config, true);
|
||||
status = FLEXCAN_TransferFDReceiveNonBlocking(config->base, &data->handle, &xfer);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
xfer.frame = &data->rx_cbs[alloc].frame.classic;
|
||||
FLEXCAN_SetRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc),
|
||||
&data->rx_cbs[alloc].mb_config, true);
|
||||
status = FLEXCAN_TransferReceiveNonBlocking(config->base, &data->handle, &xfer);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void mcux_flexcan_mb_stop(const struct device *dev, int alloc)
|
||||
{
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
struct mcux_flexcan_data *data = dev->data;
|
||||
|
||||
__ASSERT_NO_MSG(alloc >= 0 && alloc < ARRAY_SIZE(data->rx_cbs));
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
FLEXCAN_TransferFDAbortReceive(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_RXMB_IDX(alloc));
|
||||
FLEXCAN_SetFDRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc),
|
||||
NULL, false);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
FLEXCAN_TransferAbortReceive(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_RXMB_IDX(alloc));
|
||||
FLEXCAN_SetRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc),
|
||||
NULL, false);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
}
|
||||
|
||||
static int mcux_flexcan_start(const struct device *dev)
|
||||
{
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
|
@ -208,6 +314,30 @@ static int mcux_flexcan_start(const struct device *dev)
|
|||
CAN_STATS_RESET(dev);
|
||||
config->base->ECR &= ~(CAN_ECR_TXERRCNT_MASK | CAN_ECR_RXERRCNT_MASK);
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
status_t status;
|
||||
int alloc;
|
||||
|
||||
if (config->flexcan_fd) {
|
||||
/* Re-add all RX filters using current mode */
|
||||
k_mutex_lock(&data->rx_mutex, K_FOREVER);
|
||||
|
||||
for (alloc = RX_START_IDX; alloc < MCUX_FLEXCAN_MAX_RX; alloc++) {
|
||||
if (atomic_test_bit(data->rx_allocs, alloc)) {
|
||||
status = mcux_flexcan_mb_start(dev, alloc);
|
||||
if (status != kStatus_Success) {
|
||||
LOG_ERR("Failed to re-add rx filter id %d (err = %d)",
|
||||
alloc, status);
|
||||
k_mutex_unlock(&data->rx_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->rx_mutex);
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
/* Delay this until start since setting the timing automatically exits freeze mode */
|
||||
timing.preDivider = data->timing.prescaler - 1U;
|
||||
timing.rJumpwidth = data->timing.sjw - 1U;
|
||||
|
@ -216,6 +346,17 @@ static int mcux_flexcan_start(const struct device *dev)
|
|||
timing.propSeg = data->timing.prop_seg - 1U;
|
||||
FLEXCAN_SetTimingConfig(config->base, &timing);
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (config->flexcan_fd) {
|
||||
timing.fpreDivider = data->timing_data.prescaler - 1U;
|
||||
timing.frJumpwidth = data->timing_data.sjw - 1U;
|
||||
timing.fphaseSeg1 = data->timing_data.phase_seg1 - 1U;
|
||||
timing.fphaseSeg2 = data->timing_data.phase_seg2 - 1U;
|
||||
timing.fpropSeg = data->timing_data.prop_seg;
|
||||
FLEXCAN_SetFDTimingConfig(config->base, &timing);
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
data->started = true;
|
||||
|
||||
return 0;
|
||||
|
@ -242,8 +383,17 @@ static int mcux_flexcan_stop(const struct device *dev)
|
|||
arg = data->tx_cbs[alloc].arg;
|
||||
|
||||
if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
FLEXCAN_TransferFDAbortSend(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_TXMB_IDX(alloc));
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
FLEXCAN_TransferAbortSend(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_TXMB_IDX(alloc));
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
function(dev, -ENETDOWN, arg);
|
||||
k_sem_give(&data->tx_allocs_sem);
|
||||
|
@ -252,6 +402,22 @@ static int mcux_flexcan_stop(const struct device *dev)
|
|||
|
||||
FLEXCAN_EnterFreezeMode(config->base);
|
||||
|
||||
if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), config->flexcan_fd)) {
|
||||
/*
|
||||
* Remove all RX filters and re-add them in start() since the mode may change
|
||||
* between stop()/start().
|
||||
*/
|
||||
k_mutex_lock(&data->rx_mutex, K_FOREVER);
|
||||
|
||||
for (alloc = RX_START_IDX; alloc < MCUX_FLEXCAN_MAX_RX; alloc++) {
|
||||
if (atomic_test_bit(data->rx_allocs, alloc)) {
|
||||
mcux_flexcan_mb_stop(dev, alloc);
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->rx_mutex);
|
||||
}
|
||||
|
||||
if (config->phy != NULL) {
|
||||
err = can_transceiver_disable(config->phy);
|
||||
if (err != 0) {
|
||||
|
@ -265,6 +431,7 @@ static int mcux_flexcan_stop(const struct device *dev)
|
|||
|
||||
static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode)
|
||||
{
|
||||
can_mode_t supported = CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY;
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
struct mcux_flexcan_data *data = dev->data;
|
||||
uint32_t ctrl1;
|
||||
|
@ -274,11 +441,20 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_3_SAMPLES)) != 0) {
|
||||
if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), config->flexcan_fd)) {
|
||||
supported |= CAN_MODE_FD;
|
||||
}
|
||||
|
||||
if ((mode & ~(supported)) != 0) {
|
||||
LOG_ERR("unsupported mode: 0x%08x", mode);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((mode & CAN_MODE_FD) != 0 && (mode & CAN_MODE_3_SAMPLES) != 0) {
|
||||
LOG_ERR("triple samling is not supported in CAN-FD mode");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ctrl1 = config->base->CTRL1;
|
||||
mcr = config->base->MCR;
|
||||
|
||||
|
@ -308,6 +484,27 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode)
|
|||
ctrl1 &= ~(CAN_CTRL1_SMP_MASK);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (config->flexcan_fd) {
|
||||
if ((mode & CAN_MODE_FD) != 0) {
|
||||
/* Enable CAN-FD mode */
|
||||
mcr |= CAN_MCR_FDEN_MASK;
|
||||
data->fd_mode = true;
|
||||
|
||||
/* Transceiver Delay Compensation must be disabled in loopback mode */
|
||||
if ((mode & CAN_MODE_LOOPBACK) != 0) {
|
||||
config->base->FDCTRL &= ~(CAN_FDCTRL_TDCEN_MASK);
|
||||
} else {
|
||||
config->base->FDCTRL |= CAN_FDCTRL_TDCEN_MASK;
|
||||
}
|
||||
} else {
|
||||
/* Disable CAN-FD mode */
|
||||
mcr &= ~(CAN_MCR_FDEN_MASK);
|
||||
data->fd_mode = false;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
config->base->CTRL1 = ctrl1;
|
||||
config->base->MCR = mcr;
|
||||
|
||||
|
@ -362,6 +559,82 @@ static void mcux_flexcan_to_can_frame(const flexcan_frame_t *src,
|
|||
#endif /* CAN_RX_TIMESTAMP */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
static void mcux_flexcan_fd_from_can_frame(const struct can_frame *src,
|
||||
flexcan_fd_frame_t *dest)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
|
||||
if ((src->flags & CAN_FRAME_IDE) != 0) {
|
||||
dest->format = kFLEXCAN_FrameFormatExtend;
|
||||
dest->id = FLEXCAN_ID_EXT(src->id);
|
||||
} else {
|
||||
dest->format = kFLEXCAN_FrameFormatStandard;
|
||||
dest->id = FLEXCAN_ID_STD(src->id);
|
||||
}
|
||||
|
||||
if ((src->flags & CAN_FRAME_RTR) != 0) {
|
||||
dest->type = kFLEXCAN_FrameTypeRemote;
|
||||
} else {
|
||||
dest->type = kFLEXCAN_FrameTypeData;
|
||||
}
|
||||
|
||||
if ((src->flags & CAN_FRAME_FDF) != 0) {
|
||||
dest->edl = 1;
|
||||
}
|
||||
|
||||
if ((src->flags & CAN_FRAME_BRS) != 0) {
|
||||
dest->brs = 1;
|
||||
}
|
||||
|
||||
dest->length = src->dlc;
|
||||
for (i = 0; i < ARRAY_SIZE(dest->dataWord); i++) {
|
||||
dest->dataWord[i] = sys_cpu_to_be32(src->data_32[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void mcux_flexcan_fd_to_can_frame(const flexcan_fd_frame_t *src,
|
||||
struct can_frame *dest)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
|
||||
if (src->format == kFLEXCAN_FrameFormatStandard) {
|
||||
dest->id = FLEXCAN_ID_TO_CAN_ID_STD(src->id);
|
||||
} else {
|
||||
dest->flags |= CAN_FRAME_IDE;
|
||||
dest->id = FLEXCAN_ID_TO_CAN_ID_EXT(src->id);
|
||||
}
|
||||
|
||||
if (src->type == kFLEXCAN_FrameTypeRemote) {
|
||||
dest->flags |= CAN_FRAME_RTR;
|
||||
}
|
||||
|
||||
if (src->edl != 0) {
|
||||
dest->flags |= CAN_FRAME_FDF;
|
||||
}
|
||||
|
||||
if (src->brs != 0) {
|
||||
dest->flags |= CAN_FRAME_BRS;
|
||||
}
|
||||
|
||||
if (src->esi != 0) {
|
||||
dest->flags |= CAN_FRAME_ESI;
|
||||
}
|
||||
|
||||
dest->dlc = src->length;
|
||||
for (i = 0; i < ARRAY_SIZE(dest->data_32); i++) {
|
||||
dest->data_32[i] = sys_be32_to_cpu(src->dataWord[i]);
|
||||
}
|
||||
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
||||
dest->timestamp = src->timestamp;
|
||||
#endif /* CAN_RX_TIMESTAMP */
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
static void mcux_flexcan_can_filter_to_mbconfig(const struct can_filter *src,
|
||||
flexcan_rx_mb_config_t *dest,
|
||||
uint32_t *mask)
|
||||
|
@ -430,20 +703,33 @@ static int mcux_flexcan_send(const struct device *dev,
|
|||
struct mcux_flexcan_data *data = dev->data;
|
||||
flexcan_mb_transfer_t xfer;
|
||||
enum can_state state;
|
||||
status_t status;
|
||||
status_t status = kStatus_Fail;
|
||||
uint8_t max_dlc = CAN_MAX_DLC;
|
||||
int alloc;
|
||||
|
||||
__ASSERT_NO_MSG(callback != NULL);
|
||||
|
||||
if (frame->dlc > CAN_MAX_DLC) {
|
||||
LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC);
|
||||
return -EINVAL;
|
||||
if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), data->fd_mode)) {
|
||||
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR |
|
||||
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) {
|
||||
max_dlc = CANFD_MAX_DLC;
|
||||
}
|
||||
} else {
|
||||
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0) {
|
||||
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->dlc > max_dlc) {
|
||||
LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, max_dlc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!data->started) {
|
||||
return -ENETDOWN;
|
||||
|
@ -465,16 +751,41 @@ static int mcux_flexcan_send(const struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
mcux_flexcan_from_can_frame(frame, &data->tx_cbs[alloc].frame);
|
||||
data->tx_cbs[alloc].function = callback;
|
||||
data->tx_cbs[alloc].arg = user_data;
|
||||
xfer.frame = &data->tx_cbs[alloc].frame;
|
||||
xfer.mbIdx = ALLOC_IDX_TO_TXMB_IDX(alloc);
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
FLEXCAN_SetFDTxMbConfig(config->base, xfer.mbIdx, true);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
FLEXCAN_SetTxMbConfig(config->base, xfer.mbIdx, true);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
k_mutex_lock(&data->tx_mutex, K_FOREVER);
|
||||
config->irq_disable_func();
|
||||
status = FLEXCAN_TransferSendNonBlocking(config->base, &data->handle,
|
||||
&xfer);
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
flexcan_fd_frame_t flexcan_frame;
|
||||
|
||||
mcux_flexcan_fd_from_can_frame(frame, &flexcan_frame);
|
||||
xfer.framefd = &flexcan_frame;
|
||||
status = FLEXCAN_TransferFDSendNonBlocking(config->base, &data->handle, &xfer);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
flexcan_frame_t flexcan_frame;
|
||||
|
||||
mcux_flexcan_from_can_frame(frame, &flexcan_frame);
|
||||
xfer.frame = &flexcan_frame;
|
||||
status = FLEXCAN_TransferSendNonBlocking(config->base, &data->handle, &xfer);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
config->irq_enable_func();
|
||||
k_mutex_unlock(&data->tx_mutex);
|
||||
if (status != kStatus_Success) {
|
||||
|
@ -489,9 +800,9 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
|
|||
void *user_data,
|
||||
const struct can_filter *filter)
|
||||
{
|
||||
uint8_t supported = CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR;
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
struct mcux_flexcan_data *data = dev->data;
|
||||
flexcan_mb_transfer_t xfer;
|
||||
status_t status;
|
||||
uint32_t mask;
|
||||
int alloc = -ENOSPC;
|
||||
|
@ -499,7 +810,11 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
|
|||
|
||||
__ASSERT_NO_MSG(callback);
|
||||
|
||||
if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) {
|
||||
if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), config->flexcan_fd)) {
|
||||
supported |= CAN_FILTER_FDF;
|
||||
}
|
||||
|
||||
if ((filter->flags & ~(supported)) != 0) {
|
||||
LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
@ -524,25 +839,32 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev,
|
|||
data->rx_cbs[alloc].arg = user_data;
|
||||
data->rx_cbs[alloc].function = callback;
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
/* FDF filtering not supported in hardware, must be handled in driver */
|
||||
data->rx_cbs[alloc].fdf = (filter->flags & CAN_FILTER_FDF) != 0;
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
/* The indidual RX mask registers can only be written in freeze mode */
|
||||
FLEXCAN_EnterFreezeMode(config->base);
|
||||
config->base->RXIMR[ALLOC_IDX_TO_RXMB_IDX(alloc)] = mask;
|
||||
|
||||
if (data->started) {
|
||||
FLEXCAN_ExitFreezeMode(config->base);
|
||||
}
|
||||
|
||||
FLEXCAN_SetRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc),
|
||||
&data->rx_cbs[alloc].mb_config, true);
|
||||
|
||||
xfer.frame = &data->rx_cbs[alloc].frame;
|
||||
xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc);
|
||||
status = FLEXCAN_TransferReceiveNonBlocking(config->base, &data->handle,
|
||||
&xfer);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
/* Defer starting FlexCAN-FD MBs unless started */
|
||||
if (!config->flexcan_fd || data->started) {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
status = mcux_flexcan_mb_start(dev, alloc);
|
||||
if (status != kStatus_Success) {
|
||||
LOG_ERR("Failed to start rx for filter id %d (err = %d)",
|
||||
alloc, status);
|
||||
alloc = -ENOSPC;
|
||||
}
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
unlock:
|
||||
k_mutex_unlock(&data->rx_mutex);
|
||||
|
@ -602,7 +924,6 @@ static int mcux_flexcan_recover(const struct device *dev, k_timeout_t timeout)
|
|||
|
||||
static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_id)
|
||||
{
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
struct mcux_flexcan_data *data = dev->data;
|
||||
|
||||
if (filter_id >= MCUX_FLEXCAN_MAX_RX) {
|
||||
|
@ -614,11 +935,17 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i
|
|||
k_mutex_lock(&data->rx_mutex, K_FOREVER);
|
||||
|
||||
if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
|
||||
FLEXCAN_TransferAbortReceive(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_RXMB_IDX(filter_id));
|
||||
FLEXCAN_SetRxMbConfig(config->base,
|
||||
ALLOC_IDX_TO_RXMB_IDX(filter_id), NULL,
|
||||
false);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
const struct mcux_flexcan_config *config = dev->config;
|
||||
|
||||
/* Stop FlexCAN-FD MBs unless already in stopped mode */
|
||||
if (!config->flexcan_fd || data->started) {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
mcux_flexcan_mb_stop(dev, filter_id);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
data->rx_cbs[filter_id].function = NULL;
|
||||
data->rx_cbs[filter_id].arg = NULL;
|
||||
} else {
|
||||
|
@ -682,8 +1009,17 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev,
|
|||
arg = data->tx_cbs[alloc].arg;
|
||||
|
||||
if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) {
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
FLEXCAN_TransferFDAbortSend(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_TXMB_IDX(alloc));
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
FLEXCAN_TransferAbortSend(config->base, &data->handle,
|
||||
ALLOC_IDX_TO_TXMB_IDX(alloc));
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
function(dev, -ENETUNREACH, arg);
|
||||
k_sem_give(&data->tx_allocs_sem);
|
||||
|
@ -720,7 +1056,7 @@ static inline void mcux_flexcan_transfer_rx_idle(const struct device *dev,
|
|||
can_rx_callback_t function;
|
||||
flexcan_mb_transfer_t xfer;
|
||||
struct can_frame frame;
|
||||
status_t status;
|
||||
status_t status = kStatus_Fail;
|
||||
void *arg;
|
||||
int alloc;
|
||||
|
||||
|
@ -729,15 +1065,40 @@ static inline void mcux_flexcan_transfer_rx_idle(const struct device *dev,
|
|||
arg = data->rx_cbs[alloc].arg;
|
||||
|
||||
if (atomic_test_bit(data->rx_allocs, alloc)) {
|
||||
mcux_flexcan_to_can_frame(&data->rx_cbs[alloc].frame, &frame);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
mcux_flexcan_fd_to_can_frame(&data->rx_cbs[alloc].frame.fd, &frame);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
mcux_flexcan_to_can_frame(&data->rx_cbs[alloc].frame.classic, &frame);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
|
||||
if (!!(frame.flags & CAN_FRAME_FDF) == data->rx_cbs[alloc].fdf) {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
function(dev, &frame, arg);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
/* Setup RX message buffer to receive next message */
|
||||
xfer.frame = &data->rx_cbs[alloc].frame;
|
||||
xfer.mbIdx = mb;
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
xfer.framefd = &data->rx_cbs[alloc].frame.fd;
|
||||
status = FLEXCAN_TransferFDReceiveNonBlocking(config->base,
|
||||
&data->handle,
|
||||
&xfer);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
xfer.frame = &data->rx_cbs[alloc].frame.classic;
|
||||
status = FLEXCAN_TransferReceiveNonBlocking(config->base,
|
||||
&data->handle,
|
||||
&xfer);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
LOG_ERR("Failed to restart rx for filter id %d "
|
||||
"(err = %d)", alloc, status);
|
||||
|
@ -768,7 +1129,15 @@ static FLEXCAN_CALLBACK(mcux_flexcan_transfer_callback)
|
|||
mcux_flexcan_transfer_error_status(data->dev, status_flags);
|
||||
break;
|
||||
case kStatus_FLEXCAN_TxSwitchToRx:
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (data->fd_mode) {
|
||||
FLEXCAN_TransferFDAbortReceive(config->base, &data->handle, mb);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
FLEXCAN_TransferAbortReceive(config->base, &data->handle, mb);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
__fallthrough;
|
||||
case kStatus_FLEXCAN_TxIdle:
|
||||
mcux_flexcan_transfer_tx_idle(data->dev, mb);
|
||||
|
@ -843,6 +1212,32 @@ static int mcux_flexcan_init(const struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (config->flexcan_fd) {
|
||||
data->timing_data.sjw = config->sjw_data;
|
||||
if (config->sample_point_data && USE_SP_ALGO) {
|
||||
err = can_calc_timing_data(dev, &data->timing_data, config->bitrate_data,
|
||||
config->sample_point_data);
|
||||
if (err == -EINVAL) {
|
||||
LOG_ERR("Can't find timing for given param");
|
||||
return -EIO;
|
||||
}
|
||||
LOG_DBG("Presc: %d, Seg1S1: %d, Seg2: %d",
|
||||
data->timing_data.prescaler, data->timing_data.phase_seg1,
|
||||
data->timing_data.phase_seg2);
|
||||
LOG_DBG("Sample-point err : %d", err);
|
||||
} else {
|
||||
data->timing_data.prop_seg = config->prop_seg;
|
||||
data->timing_data.phase_seg1 = config->phase_seg1;
|
||||
data->timing_data.phase_seg2 = config->phase_seg2;
|
||||
err = can_calc_prescaler(dev, &data->timing_data, config->bitrate_data);
|
||||
if (err) {
|
||||
LOG_WRN("Bitrate error: %d", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
|
||||
if (err != 0) {
|
||||
|
@ -863,9 +1258,19 @@ static int mcux_flexcan_init(const struct device *dev)
|
|||
flexcan_config.baudRate = clock_freq /
|
||||
(1U + data->timing.prop_seg + data->timing.phase_seg1 +
|
||||
data->timing.phase_seg2) / data->timing.prescaler;
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (config->flexcan_fd) {
|
||||
flexcan_config.baudRateFD = clock_freq /
|
||||
(1U + data->timing_data.prop_seg + data->timing_data.phase_seg1 +
|
||||
data->timing_data.phase_seg2) / data->timing_data.prescaler;
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
flexcan_config.enableIndividMask = true;
|
||||
flexcan_config.enableLoopBack = false;
|
||||
flexcan_config.disableSelfReception = true;
|
||||
/* Initialize in listen-only mode since FLEXCAN_{FD}Init() exits freeze mode */
|
||||
flexcan_config.enableListenOnlyMode = true;
|
||||
|
||||
flexcan_config.timingConfig.rJumpwidth = data->timing.sjw - 1U;
|
||||
|
@ -873,8 +1278,21 @@ static int mcux_flexcan_init(const struct device *dev)
|
|||
flexcan_config.timingConfig.phaseSeg1 = data->timing.phase_seg1 - 1U;
|
||||
flexcan_config.timingConfig.phaseSeg2 = data->timing.phase_seg2 - 1U;
|
||||
|
||||
/* Initialize in listen-only mode since FLEXCAN_Init() exits freeze mode */
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
if (config->flexcan_fd) {
|
||||
flexcan_config.timingConfig.frJumpwidth = data->timing_data.sjw - 1U;
|
||||
flexcan_config.timingConfig.fpropSeg = data->timing_data.prop_seg;
|
||||
flexcan_config.timingConfig.fphaseSeg1 = data->timing_data.phase_seg1 - 1U;
|
||||
flexcan_config.timingConfig.fphaseSeg2 = data->timing_data.phase_seg2 - 1U;
|
||||
|
||||
FLEXCAN_FDInit(config->base, &flexcan_config, clock_freq, kFLEXCAN_64BperMB, true);
|
||||
} else {
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
FLEXCAN_Init(config->base, &flexcan_config, clock_freq);
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
}
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
FLEXCAN_TransferCreateHandle(config->base, &data->handle,
|
||||
mcux_flexcan_transfer_callback, data);
|
||||
|
||||
|
@ -894,7 +1312,7 @@ static int mcux_flexcan_init(const struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct can_driver_api mcux_flexcan_driver_api = {
|
||||
__maybe_unused static const struct can_driver_api mcux_flexcan_driver_api = {
|
||||
.get_capabilities = mcux_flexcan_get_capabilities,
|
||||
.start = mcux_flexcan_start,
|
||||
.stop = mcux_flexcan_stop,
|
||||
|
@ -917,8 +1335,8 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
|
|||
*
|
||||
* Note that the values here are the "physical" timing limits, whereas
|
||||
* the register field limits are physical values minus 1 (which is
|
||||
* handled by the flexcan_config_t field assignments elsewhere in this
|
||||
* driver).
|
||||
* handled by the flexcan_timing_config_t field assignments elsewhere
|
||||
* in this driver).
|
||||
*/
|
||||
.timing_min = {
|
||||
.sjw = 0x01,
|
||||
|
@ -936,6 +1354,67 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
static const struct can_driver_api mcux_flexcan_fd_driver_api = {
|
||||
.get_capabilities = mcux_flexcan_get_capabilities,
|
||||
.start = mcux_flexcan_start,
|
||||
.stop = mcux_flexcan_stop,
|
||||
.set_mode = mcux_flexcan_set_mode,
|
||||
.set_timing = mcux_flexcan_set_timing,
|
||||
.set_timing_data = mcux_flexcan_set_timing_data,
|
||||
.send = mcux_flexcan_send,
|
||||
.add_rx_filter = mcux_flexcan_add_rx_filter,
|
||||
.remove_rx_filter = mcux_flexcan_remove_rx_filter,
|
||||
.get_state = mcux_flexcan_get_state,
|
||||
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
||||
.recover = mcux_flexcan_recover,
|
||||
#endif
|
||||
.set_state_change_callback = mcux_flexcan_set_state_change_callback,
|
||||
.get_core_clock = mcux_flexcan_get_core_clock,
|
||||
.get_max_filters = mcux_flexcan_get_max_filters,
|
||||
.get_max_bitrate = mcux_flexcan_get_max_bitrate,
|
||||
/*
|
||||
* FlexCAN FD timing limits are specified in the "CAN Bit Timing
|
||||
* Register (CBT)" and "CAN FD Bit Timing Register" field description
|
||||
* tables in the SoC reference manual.
|
||||
*
|
||||
* Note that the values here are the "physical" timing limits, whereas
|
||||
* the register field limits are physical values minus 1 (which is
|
||||
* handled by the flexcan_timing_config_t field assignments elsewhere
|
||||
* in this driver). The exception to this are the prop_seg values for
|
||||
* the data phase, which correspond to the allowed register values.
|
||||
*/
|
||||
.timing_min = {
|
||||
.sjw = 0x01,
|
||||
.prop_seg = 0x01,
|
||||
.phase_seg1 = 0x01,
|
||||
.phase_seg2 = 0x02,
|
||||
.prescaler = 0x01
|
||||
},
|
||||
.timing_max = {
|
||||
.sjw = 0x20,
|
||||
.prop_seg = 0x40,
|
||||
.phase_seg1 = 0x20,
|
||||
.phase_seg2 = 0x20,
|
||||
.prescaler = 0x400
|
||||
},
|
||||
.timing_data_min = {
|
||||
.sjw = 0x01,
|
||||
.prop_seg = 0x01,
|
||||
.phase_seg1 = 0x01,
|
||||
.phase_seg2 = 0x02,
|
||||
.prescaler = 0x01
|
||||
},
|
||||
.timing_data_max = {
|
||||
.sjw = 0x08,
|
||||
.prop_seg = 0x1f,
|
||||
.phase_seg1 = 0x08,
|
||||
.phase_seg2 = 0x08,
|
||||
.prescaler = 0x400
|
||||
},
|
||||
};
|
||||
#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
#define FLEXCAN_IRQ_BY_IDX(node_id, prop, idx, cell) \
|
||||
DT_IRQ_BY_NAME(node_id, \
|
||||
DT_STRING_TOKEN_BY_IDX(node_id, prop, idx), cell)
|
||||
|
@ -963,6 +1442,22 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
|
|||
#define FLEXCAN_PINCTRL_INIT(id)
|
||||
#endif /* CONFIG_PINCTRL */
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
#define FLEXCAN_MAX_BITRATE(id) \
|
||||
COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \
|
||||
(8000000), (1000000))
|
||||
#else /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
#define FLEXCAN_MAX_BITRATE(id) 1000000
|
||||
#endif /* !CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD
|
||||
#define FLEXCAN_DRIVER_API(id) \
|
||||
COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \
|
||||
(mcux_flexcan_fd_driver_api), \
|
||||
(mcux_flexcan_driver_api))
|
||||
#else /* CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
#define FLEXCAN_DRIVER_API(id) mcux_flexcan_driver_api
|
||||
#endif /* !CONFIG_CAN_MCUX_FLEXCAN_FD */
|
||||
|
||||
#define FLEXCAN_DEVICE_INIT_MCUX(id) \
|
||||
FLEXCAN_PINCTRL_DEFINE(id) \
|
||||
|
@ -983,11 +1478,21 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
|
|||
.phase_seg1 = DT_INST_PROP_OR(id, phase_seg1, 0), \
|
||||
.phase_seg2 = DT_INST_PROP_OR(id, phase_seg2, 0), \
|
||||
.sample_point = DT_INST_PROP_OR(id, sample_point, 0), \
|
||||
IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \
|
||||
.flexcan_fd = DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \
|
||||
.bitrate_data = DT_INST_PROP_OR(id, bus_speed_data, 0), \
|
||||
.sjw_data = DT_INST_PROP_OR(id, sjw_data, 0), \
|
||||
.prop_seg_data = DT_INST_PROP_OR(id, prop_seg_data, 0), \
|
||||
.phase_seg1_data = DT_INST_PROP_OR(id, phase_seg1_data, 0), \
|
||||
.phase_seg2_data = DT_INST_PROP_OR(id, phase_seg2_data, 0), \
|
||||
.sample_point_data = DT_INST_PROP_OR(id, sample_point_data, 0), \
|
||||
)) \
|
||||
.irq_config_func = mcux_flexcan_irq_config_##id, \
|
||||
.irq_enable_func = mcux_flexcan_irq_enable_##id, \
|
||||
.irq_disable_func = mcux_flexcan_irq_disable_##id, \
|
||||
.phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(id, phys)),\
|
||||
.max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(id, 1000000), \
|
||||
.max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(id, \
|
||||
FLEXCAN_MAX_BITRATE(id)), \
|
||||
FLEXCAN_PINCTRL_INIT(id) \
|
||||
}; \
|
||||
\
|
||||
|
@ -997,7 +1502,7 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
|
|||
NULL, &mcux_flexcan_data_##id, \
|
||||
&mcux_flexcan_config_##id, \
|
||||
POST_KERNEL, CONFIG_CAN_INIT_PRIORITY,\
|
||||
&mcux_flexcan_driver_api); \
|
||||
&FLEXCAN_DRIVER_API(id)); \
|
||||
\
|
||||
static void mcux_flexcan_irq_config_##id(const struct device *dev) \
|
||||
{ \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue