drivers: can: add generic GPIO controlled CAN transceiver driver
Add generic driver for GPIO controlled CAN transceivers. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
parent
754ed399f9
commit
0783b51ee1
5 changed files with 162 additions and 0 deletions
|
@ -16,3 +16,5 @@ zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c)
|
|||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c)
|
||||
|
||||
add_subdirectory(transceiver)
|
||||
|
|
|
@ -102,4 +102,6 @@ source "drivers/can/Kconfig.mcan"
|
|||
source "drivers/can/Kconfig.rcar"
|
||||
source "drivers/can/Kconfig.loopback"
|
||||
|
||||
source "drivers/can/transceiver/Kconfig"
|
||||
|
||||
endif # CAN
|
||||
|
|
6
drivers/can/transceiver/CMakeLists.txt
Normal file
6
drivers/can/transceiver/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Copyright (c) 2022 Vestas Wind Systems A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_property(ALLOW_EMPTY TRUE)
|
||||
zephyr_library_sources_ifdef(CONFIG_CAN_TRANSCEIVER_GPIO can_transceiver_gpio.c)
|
21
drivers/can/transceiver/Kconfig
Normal file
21
drivers/can/transceiver/Kconfig
Normal file
|
@ -0,0 +1,21 @@
|
|||
# CAN transceiver configuration options
|
||||
|
||||
# Copyright (c) 2022 Vestas Wind Systems A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menu "CAN transceiver drivers"
|
||||
|
||||
config CAN_TRANSCEIVER_INIT_PRIORITY
|
||||
int "CAN transceiver driver init priority"
|
||||
default 70
|
||||
help
|
||||
CAN transceiver device driver initialization priority.
|
||||
|
||||
config CAN_TRANSCEIVER_GPIO
|
||||
bool "GPIO controlled CAN transceiver"
|
||||
depends on GPIO
|
||||
default $(dt_compat_enabled,can-transceiver-gpio)
|
||||
help
|
||||
Enable support for GPIO controlled CAN transceivers.
|
||||
|
||||
endmenu
|
131
drivers/can/transceiver/can_transceiver_gpio.c
Normal file
131
drivers/can/transceiver/can_transceiver_gpio.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Vestas Wind Systems A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT can_transceiver_gpio
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/can/transceiver.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(can_transceiver_gpio, CONFIG_CAN_LOG_LEVEL);
|
||||
|
||||
/* Does any devicetree instance have an enable-gpios property? */
|
||||
#define INST_HAS_ENABLE_GPIOS_OR(inst) DT_INST_NODE_HAS_PROP(inst, enable_gpios) ||
|
||||
#define ANY_INST_HAS_ENABLE_GPIOS DT_INST_FOREACH_STATUS_OKAY(INST_HAS_ENABLE_GPIOS_OR) 0
|
||||
|
||||
/* Does any devicetree instance have a standby-gpios property? */
|
||||
#define INST_HAS_STANDBY_GPIOS_OR(inst) DT_INST_NODE_HAS_PROP(inst, standby_gpios) ||
|
||||
#define ANY_INST_HAS_STANDBY_GPIOS DT_INST_FOREACH_STATUS_OKAY(INST_HAS_STANDBY_GPIOS_OR) 0
|
||||
|
||||
struct can_transceiver_gpio_config {
|
||||
#if ANY_INST_HAS_ENABLE_GPIOS
|
||||
struct gpio_dt_spec enable_gpio;
|
||||
#endif /* ANY_INST_HAS_ENABLE_GPIOS */
|
||||
#if ANY_INST_HAS_STANDBY_GPIOS
|
||||
struct gpio_dt_spec standby_gpio;
|
||||
#endif /* ANY_INST_HAS_STANDBY_GPIOS */
|
||||
};
|
||||
|
||||
static int can_transceiver_gpio_set_state(const struct device *dev, bool enabled)
|
||||
{
|
||||
const struct can_transceiver_gpio_config *config = dev->config;
|
||||
int err;
|
||||
|
||||
#if ANY_INST_HAS_ENABLE_GPIOS
|
||||
if (config->enable_gpio.port != NULL) {
|
||||
err = gpio_pin_set_dt(&config->enable_gpio, enabled ? 1 : 0);
|
||||
if (err != 0) {
|
||||
LOG_ERR("failed to set enable GPIO pin (err %d)", err);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
#endif /* ANY_INST_HAS_ENABLE_GPIOS */
|
||||
|
||||
#if ANY_INST_HAS_STANDBY_GPIOS
|
||||
if (config->standby_gpio.port != NULL) {
|
||||
err = gpio_pin_set_dt(&config->standby_gpio, enabled ? 0 : 1);
|
||||
if (err != 0) {
|
||||
LOG_ERR("failed to set standby GPIO pin (err %d)", err);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
#endif /* ANY_INST_HAS_STANDBY_GPIOS */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int can_transceiver_gpio_enable(const struct device *dev)
|
||||
{
|
||||
return can_transceiver_gpio_set_state(dev, true);
|
||||
}
|
||||
|
||||
static int can_transceiver_gpio_disable(const struct device *dev)
|
||||
{
|
||||
return can_transceiver_gpio_set_state(dev, false);
|
||||
}
|
||||
|
||||
static int can_transceiver_gpio_init(const struct device *dev)
|
||||
{
|
||||
const struct can_transceiver_gpio_config *config = dev->config;
|
||||
int err;
|
||||
|
||||
#if ANY_INST_HAS_ENABLE_GPIOS
|
||||
if (config->enable_gpio.port != NULL) {
|
||||
if (!device_is_ready(config->enable_gpio.port)) {
|
||||
LOG_ERR("enable pin GPIO device not ready");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* CAN transceiver is disabled during initialization */
|
||||
err = gpio_pin_configure_dt(&config->enable_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (err != 0) {
|
||||
LOG_ERR("failed to configure enable GPIO pin (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif /* ANY_INST_HAS_ENABLE_GPIOS */
|
||||
|
||||
#if ANY_INST_HAS_STANDBY_GPIOS
|
||||
if (config->standby_gpio.port != NULL) {
|
||||
if (!device_is_ready(config->standby_gpio.port)) {
|
||||
LOG_ERR("standby pin GPIO device not ready");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* CAN transceiver is put in standby during initialization */
|
||||
err = gpio_pin_configure_dt(&config->standby_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
if (err != 0) {
|
||||
LOG_ERR("failed to configure standby GPIO pin (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif /* ANY_INST_HAS_STANDBY_GPIOS */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct can_transceiver_driver_api can_transceiver_gpio_driver_api = {
|
||||
.enable = can_transceiver_gpio_enable,
|
||||
.disable = can_transceiver_gpio_disable,
|
||||
};
|
||||
|
||||
#define CAN_TRANSCEIVER_GPIO_COND(inst, name) \
|
||||
IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, name##_gpios), \
|
||||
(.name##_gpio = GPIO_DT_SPEC_INST_GET(inst, name##_gpios),))
|
||||
|
||||
#define CAN_TRANSCEIVER_GPIO_INIT(inst) \
|
||||
static const struct can_transceiver_gpio_config can_transceiver_gpio_config_##inst = { \
|
||||
CAN_TRANSCEIVER_GPIO_COND(inst, enable) \
|
||||
CAN_TRANSCEIVER_GPIO_COND(inst, standby) \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(inst, &can_transceiver_gpio_init, \
|
||||
NULL, NULL, &can_transceiver_gpio_config_##inst,\
|
||||
POST_KERNEL, CONFIG_CAN_TRANSCEIVER_INIT_PRIORITY, \
|
||||
&can_transceiver_gpio_driver_api); \
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CAN_TRANSCEIVER_GPIO_INIT)
|
Loading…
Add table
Add a link
Reference in a new issue