drivers: can: loopback: convert the CAN loopback driver to dts

Convert the CAN loopback driver from being configured via Kconfig to
multi-instance configured via devicetree.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
Henrik Brix Andersen 2021-12-16 15:23:05 +01:00 committed by Maureen Helm
commit 99a310b29b
12 changed files with 94 additions and 127 deletions

View file

@ -88,6 +88,8 @@ Zephyr includes the following emulators:
* eSPI emulator driver, which does the same for eSPI. The emulator is being * eSPI emulator driver, which does the same for eSPI. The emulator is being
developed to support more functionalities. developed to support more functionalities.
* CAN loopback driver
A GPIO emulator is planned but is not yet complete. A GPIO emulator is planned but is not yet complete.
Samples Samples

View file

@ -3,19 +3,16 @@
# Copyright (c) 2019 Alexander Wachter # Copyright (c) 2019 Alexander Wachter
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
DT_COMPAT_ZEPHYR_CAN_LOOPBACK := zephyr,can-loopback
config CAN_LOOPBACK config CAN_LOOPBACK
bool "Loopback CAN driver" bool "Emulated CAN loopback driver"
default $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_CAN_LOOPBACK))
help help
This is a dummy driver that can only loopback messages. This is an emulated driver that can only loopback messages.
if CAN_LOOPBACK if CAN_LOOPBACK
config CAN_LOOPBACK_DEV_NAME
string "CAN loopback device name"
default "CAN_LOOPBACK"
help
"Device name for the loopback device"
config CAN_MAX_FILTER config CAN_MAX_FILTER
int "Maximum number of concurrent active filters" int "Maximum number of concurrent active filters"
default 16 default 16

View file

@ -1,31 +1,45 @@
/* /*
* Copyright (c) 2021 Vestas Wind Systems A/S
* Copyright (c) 2018 Alexander Wachter * Copyright (c) 2018 Alexander Wachter
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <string.h> #define DT_DRV_COMPAT zephyr_can_loopback
#include <kernel.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <drivers/can.h> #include <drivers/can.h>
#include "can_loopback.h" #include <kernel.h>
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_DECLARE(can_driver, CONFIG_CAN_LOG_LEVEL);
K_KERNEL_STACK_DEFINE(tx_thread_stack, LOG_MODULE_REGISTER(can_loopback, CONFIG_CAN_LOG_LEVEL);
CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE);
struct k_thread tx_thread_data;
struct can_looppback_frame { struct can_loopback_frame {
struct zcan_frame frame; struct zcan_frame frame;
can_tx_callback_t cb; can_tx_callback_t cb;
void *cb_arg; void *cb_arg;
struct k_sem *tx_compl; struct k_sem *tx_compl;
}; };
K_MSGQ_DEFINE(tx_msgq, sizeof(struct can_looppback_frame), struct can_loopback_filter {
CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE, 4); can_rx_callback_t rx_cb;
void *cb_arg;
struct zcan_filter filter;
};
struct can_loopback_data {
struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER];
struct k_mutex mtx;
bool loopback;
struct k_msgq tx_msgq;
char msgq_buffer[CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE * sizeof(struct can_loopback_frame)];
struct k_thread tx_thread_data;
K_KERNEL_STACK_MEMBER(tx_thread_stack,
CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE);
};
static void dispatch_frame(const struct zcan_frame *frame, static void dispatch_frame(const struct zcan_frame *frame,
struct can_loopback_filter *filter) struct can_loopback_filter *filter)
@ -52,12 +66,12 @@ void tx_thread(void *data_arg, void *arg2, void *arg3)
{ {
ARG_UNUSED(arg2); ARG_UNUSED(arg2);
ARG_UNUSED(arg3); ARG_UNUSED(arg3);
struct can_looppback_frame frame; struct can_loopback_frame frame;
struct can_loopback_filter *filter; struct can_loopback_filter *filter;
struct can_loopback_data *data = (struct can_loopback_data *)data_arg; struct can_loopback_data *data = (struct can_loopback_data *)data_arg;
while (1) { while (1) {
k_msgq_get(&tx_msgq, &frame, K_FOREVER); k_msgq_get(&data->tx_msgq, &frame, K_FOREVER);
k_mutex_lock(&data->mtx, K_FOREVER); k_mutex_lock(&data->mtx, K_FOREVER);
for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) { for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) {
@ -83,9 +97,9 @@ int can_loopback_send(const struct device *dev,
k_timeout_t timeout, can_tx_callback_t callback, k_timeout_t timeout, can_tx_callback_t callback,
void *user_data) void *user_data)
{ {
struct can_loopback_data *data = DEV_DATA(dev); struct can_loopback_data *data = dev->data;
int ret; int ret;
struct can_looppback_frame loopback_frame; struct can_loopback_frame loopback_frame;
struct k_sem tx_sem; struct k_sem tx_sem;
LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s", LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s",
@ -112,7 +126,7 @@ int can_loopback_send(const struct device *dev,
k_sem_init(&tx_sem, 0, 1); k_sem_init(&tx_sem, 0, 1);
} }
ret = k_msgq_put(&tx_msgq, &loopback_frame, timeout); ret = k_msgq_put(&data->tx_msgq, &loopback_frame, timeout);
if (!callback) { if (!callback) {
k_sem_take(&tx_sem, K_FOREVER); k_sem_take(&tx_sem, K_FOREVER);
@ -137,7 +151,7 @@ int can_loopback_attach_isr(const struct device *dev, can_rx_callback_t isr,
void *cb_arg, void *cb_arg,
const struct zcan_filter *filter) const struct zcan_filter *filter)
{ {
struct can_loopback_data *data = DEV_DATA(dev); struct can_loopback_data *data = dev->data;
struct can_loopback_filter *loopback_filter; struct can_loopback_filter *loopback_filter;
int filter_id; int filter_id;
@ -173,7 +187,7 @@ int can_loopback_attach_isr(const struct device *dev, can_rx_callback_t isr,
void can_loopback_detach(const struct device *dev, int filter_id) void can_loopback_detach(const struct device *dev, int filter_id)
{ {
struct can_loopback_data *data = DEV_DATA(dev); struct can_loopback_data *data = dev->data;
LOG_DBG("Detach filter ID: %d", filter_id); LOG_DBG("Detach filter ID: %d", filter_id);
k_mutex_lock(&data->mtx, K_FOREVER); k_mutex_lock(&data->mtx, K_FOREVER);
@ -183,7 +197,7 @@ void can_loopback_detach(const struct device *dev, int filter_id)
int can_loopback_set_mode(const struct device *dev, enum can_mode mode) int can_loopback_set_mode(const struct device *dev, enum can_mode mode)
{ {
struct can_loopback_data *data = DEV_DATA(dev); struct can_loopback_data *data = dev->data;
data->loopback = mode == CAN_LOOPBACK_MODE ? 1 : 0; data->loopback = mode == CAN_LOOPBACK_MODE ? 1 : 0;
return 0; return 0;
@ -243,7 +257,7 @@ int can_loopback_get_max_filters(const struct device *dev, enum can_ide id_type)
return CONFIG_CAN_MAX_FILTER; return CONFIG_CAN_MAX_FILTER;
} }
static const struct can_driver_api can_api_funcs = { static const struct can_driver_api can_loopback_driver_api = {
.set_mode = can_loopback_set_mode, .set_mode = can_loopback_set_mode,
.set_timing = can_loopback_set_timing, .set_timing = can_loopback_set_timing,
.send = can_loopback_send, .send = can_loopback_send,
@ -274,7 +288,7 @@ static const struct can_driver_api can_api_funcs = {
static int can_loopback_init(const struct device *dev) static int can_loopback_init(const struct device *dev)
{ {
struct can_loopback_data *data = DEV_DATA(dev); struct can_loopback_data *data = dev->data;
k_tid_t tx_tid; k_tid_t tx_tid;
k_mutex_init(&data->mtx); k_mutex_init(&data->mtx);
@ -283,8 +297,11 @@ static int can_loopback_init(const struct device *dev)
data->filters[i].rx_cb = NULL; data->filters[i].rx_cb = NULL;
} }
tx_tid = k_thread_create(&tx_thread_data, tx_thread_stack, k_msgq_init(&data->tx_msgq, data->msgq_buffer, sizeof(struct can_loopback_frame),
K_KERNEL_STACK_SIZEOF(tx_thread_stack), CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE);
tx_tid = k_thread_create(&data->tx_thread_data, data->tx_thread_stack,
K_KERNEL_STACK_SIZEOF(data->tx_thread_stack),
tx_thread, data, NULL, NULL, tx_thread, data, NULL, NULL,
CONFIG_CAN_LOOPBACK_TX_THREAD_PRIORITY, CONFIG_CAN_LOOPBACK_TX_THREAD_PRIORITY,
0, K_NO_WAIT); 0, K_NO_WAIT);
@ -298,46 +315,50 @@ static int can_loopback_init(const struct device *dev)
return 0; return 0;
} }
static struct can_loopback_data can_loopback_dev_data_1; #define CAN_LOOPBACK_INIT(inst) \
static struct can_loopback_data can_loopback_dev_data_##inst; \
DEVICE_DEFINE(can_loopback_1, CONFIG_CAN_LOOPBACK_DEV_NAME, \
&can_loopback_init, NULL, DEVICE_DT_INST_DEFINE(inst, &can_loopback_init, NULL, \
&can_loopback_dev_data_1, NULL, &can_loopback_dev_data_##inst, NULL, \
POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \
&can_api_funcs); &can_loopback_driver_api);
DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT)
#if defined(CONFIG_NET_SOCKETS_CAN) #if defined(CONFIG_NET_SOCKETS_CAN)
#include "socket_can_generic.h" #include "socket_can_generic.h"
static struct socket_can_context socket_can_context_1; #define CAN_LOOPBACK_SOCKET_CAN(inst) \
static struct socket_can_context socket_can_context_##inst; \
\
static int socket_can_init_##inst(const struct device *dev) \
{ \
const struct device *can_dev = DEVICE_DT_INST_GET(inst); \
struct socket_can_context *socket_context = dev->data; \
\
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", \
dev, dev->name, can_dev, can_dev->name); \
\
socket_context->can_dev = can_dev; \
socket_context->msgq = &socket_can_msgq; \
\
socket_context->rx_tid = \
k_thread_create(&socket_context->rx_thread_data, \
rx_thread_stack, \
K_KERNEL_STACK_SIZEOF(rx_thread_stack), \
rx_thread, socket_context, NULL, NULL, \
RX_THREAD_PRIORITY, 0, K_NO_WAIT); \
\
return 0; \
} \
\
NET_DEVICE_INIT(socket_can_loopback_##inst, SOCKET_CAN_NAME_##inst, \
socket_can_init_##inst, NULL, \
&socket_can_context_##inst, NULL, \
CONFIG_CAN_INIT_PRIORITY, &socket_can_api, \
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), \
CAN_MTU);
static int socket_can_init_1(const struct device *dev) DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_SOCKET_CAN)
{
const struct device *can_dev = DEVICE_GET(can_loopback_1);
struct socket_can_context *socket_context = dev->data;
LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)",
dev, dev->name, can_dev, can_dev->name);
socket_context->can_dev = can_dev;
socket_context->msgq = &socket_can_msgq;
socket_context->rx_tid =
k_thread_create(&socket_context->rx_thread_data,
rx_thread_stack,
K_KERNEL_STACK_SIZEOF(rx_thread_stack),
rx_thread, socket_context, NULL, NULL,
RX_THREAD_PRIORITY, 0, K_NO_WAIT);
return 0;
}
NET_DEVICE_INIT(socket_can_loopback_1, SOCKET_CAN_NAME_1, socket_can_init_1,
NULL, &socket_can_context_1, NULL,
CONFIG_CAN_INIT_PRIORITY,
&socket_can_api,
CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);
#endif /* CONFIG_NET_SOCKETS_CAN */ #endif /* CONFIG_NET_SOCKETS_CAN */

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2019 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#ifndef ZEPHYR_DRIVERS_CAN_LOOPBACK_CAN_H_
#define ZEPHYR_DRIVERS_CAN_LOOPBACK_CAN_H_
#include <drivers/can.h>
#define DEV_DATA(dev) ((struct can_loopback_data *const)(dev)->data)
#define DEV_CFG(dev) \
((const struct can_loopback_config *const)(dev)->config)
struct can_loopback_filter {
can_rx_callback_t rx_cb;
void *cb_arg;
struct zcan_filter filter;
};
struct can_loopback_data {
struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER];
struct k_mutex mtx;
bool loopback;
};
struct can_loopback_config {
};
#endif /*ZEPHYR_DRIVERS_CAN_LOOPBACK_CAN_H_*/

View file

@ -0,0 +1,8 @@
# Copyright (c) 2021 Vestas Wind Systems A/S
# SPDX-License-Identifier: Apache-2.0
description: Zephyr emulated CAN loopback controller
compatible: "zephyr,can-loopback"
include: can-controller.yaml

View file

@ -44,12 +44,7 @@
#define TEST_CAN_EXT_MASK_ID_2 0x1555556A #define TEST_CAN_EXT_MASK_ID_2 0x1555556A
#define TEST_CAN_EXT_MASK 0x1FFFFFF0 #define TEST_CAN_EXT_MASK 0x1FFFFFF0
#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME)
#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME
#else
#define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus))
#endif
CAN_DEFINE_MSGQ(can_msgq, 5); CAN_DEFINE_MSGQ(can_msgq, 5);
struct k_sem rx_isr_sem; struct k_sem rx_isr_sem;

View file

@ -28,12 +28,7 @@
#define TEST_CAN_STD_ID_1 0x555 #define TEST_CAN_STD_ID_1 0x555
#define TEST_CAN_STD_ID_2 0x556 #define TEST_CAN_STD_ID_2 0x556
#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME)
#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME
#else
#define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus))
#endif
CAN_DEFINE_MSGQ(can_msgq, 5); CAN_DEFINE_MSGQ(can_msgq, 5);
struct k_sem rx_isr_sem; struct k_sem rx_isr_sem;

View file

@ -1,3 +0,0 @@
CONFIG_CAN=y
CONFIG_ZTEST=y
CONFIG_CAN_LOOPBACK=y

View file

@ -22,11 +22,7 @@
* @} * @}
*/ */
#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME)
#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME
#else
#define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus))
#endif
const struct device *can_dev; const struct device *can_dev;

View file

@ -2,7 +2,3 @@ tests:
drivers.can.timing: drivers.can.timing:
tags: driver can tags: driver can
depends_on: can depends_on: can
drivers.can.timing_loopback:
tags: driver can
platform_allow: native_posix
extra_args: CONF_FILE="prj_loopback.conf"

View file

@ -49,11 +49,7 @@
#define BS_TIMEOUT_UPPER_MS 1100 #define BS_TIMEOUT_UPPER_MS 1100
#define BS_TIMEOUT_LOWER_MS 1000 #define BS_TIMEOUT_LOWER_MS 1000
#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME)
#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME
#else
#define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus))
#endif
/* /*
* @addtogroup t_can * @addtogroup t_can

View file

@ -12,11 +12,7 @@
#define NUMBER_OF_REPETITIONS 5 #define NUMBER_OF_REPETITIONS 5
#define DATA_SIZE_SF 7 #define DATA_SIZE_SF 7
#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME)
#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME
#else
#define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus))
#endif
/* /*
* @addtogroup t_can * @addtogroup t_can