From b407b5697ffdb100cbfeaa835b18ccd8d0048e57 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 18 Jul 2022 13:23:17 +0200 Subject: [PATCH] drivers: can: loopback: add CAN-FD loopback support Add support for CAN-FD frames in the CAN loopback driver. Signed-off-by: Henrik Brix Andersen --- drivers/can/Kconfig.loopback | 1 + drivers/can/can_loopback.c | 59 +++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/drivers/can/Kconfig.loopback b/drivers/can/Kconfig.loopback index 5e21b092e7d..4149d8fa7e0 100644 --- a/drivers/can/Kconfig.loopback +++ b/drivers/can/Kconfig.loopback @@ -7,6 +7,7 @@ DT_COMPAT_ZEPHYR_CAN_LOOPBACK := zephyr,can-loopback config CAN_LOOPBACK bool "Emulated CAN loopback driver" + select CAN_HAS_CANFD default $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_CAN_LOOPBACK)) help This is an emulated driver that can only loopback messages. diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index eb3d1b59d9a..9a142f60c76 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -96,9 +96,10 @@ static int can_loopback_send(const struct device *dev, void *user_data) { struct can_loopback_data *data = dev->data; - int ret; struct can_loopback_frame loopback_frame; + uint8_t max_dlc = CAN_MAX_DLC; struct k_sem tx_sem; + int ret; LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s", frame->dlc, dev->name, frame->id, @@ -106,8 +107,14 @@ static int can_loopback_send(const struct device *dev, "standard" : "extended", frame->rtr == CAN_DATAFRAME ? "" : ", RTR frame"); - if (frame->dlc > CAN_MAX_DLC) { - LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); +#ifdef CONFIG_CAN_FD_MODE + if (frame->fd != 0) { + max_dlc = CANFD_MAX_DLC; + } +#endif /* CONFIG_CAN_FD_MODE */ + + if (frame->dlc > max_dlc) { + LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, max_dlc); return -EINVAL; } @@ -198,6 +205,10 @@ static int can_loopback_get_capabilities(const struct device *dev, can_mode_t *c *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK; +#if CONFIG_CAN_FD_MODE + *cap |= CAN_MODE_FD; +#endif /* CONFIG_CAN_FD_MODE */ + return 0; } @@ -205,6 +216,18 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) { struct can_loopback_data *data = dev->data; +#ifdef CONFIG_CAN_FD_MODE + if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { + LOG_ERR("unsupported mode: 0x%08x", mode); + return -ENOTSUP; + } +#else + if ((mode & ~(CAN_MODE_LOOPBACK)) != 0) { + LOG_ERR("unsupported mode: 0x%08x", mode); + return -ENOTSUP; + } +#endif /* CONFIG_CAN_FD_MODE */ + data->loopback = (mode & CAN_MODE_LOOPBACK) != 0 ? 1 : 0; return 0; } @@ -218,6 +241,17 @@ static int can_loopback_set_timing(const struct device *dev, return 0; } +#ifdef CONFIG_CAN_FD_MODE +static int can_loopback_set_timing_data(const struct device *dev, + const struct can_timing *timing) +{ + ARG_UNUSED(dev); + ARG_UNUSED(timing); + + return 0; +} +#endif /* CONFIG_CAN_FD_MODE */ + static int can_loopback_get_state(const struct device *dev, enum can_state *state, struct can_bus_err_cnt *err_cnt) { @@ -295,7 +329,24 @@ static const struct can_driver_api can_loopback_driver_api = { .phase_seg1 = 0x0F, .phase_seg2 = 0x0F, .prescaler = 0xFFFF - } + }, +#ifdef CONFIG_CAN_FD_MODE + .set_timing_data = can_loopback_set_timing_data, + .timing_data_min = { + .sjw = 0x1, + .prop_seg = 0x01, + .phase_seg1 = 0x01, + .phase_seg2 = 0x01, + .prescaler = 0x01 + }, + .timing_data_max = { + .sjw = 0x0F, + .prop_seg = 0x0F, + .phase_seg1 = 0x0F, + .phase_seg2 = 0x0F, + .prescaler = 0xFFFF + }, +#endif /* CONFIG_CAN_FD_MODE */ }; static int can_loopback_init(const struct device *dev)