Skip to content

Commit

Permalink
drivers: can: transceiver: termination gpio
Browse files Browse the repository at this point in the history
The functionality for termination gpio is used on
some boards like ST's b-g431b-esc1 motor controller board.
This feature is also supported by SocketCAN in linux.

Signed-off-by: Alexander Kozhinov <ak.alexander.kozhinov@gmail.com>
  • Loading branch information
KozhinovAlexander committed Dec 27, 2024
1 parent fc25679 commit 502e76c
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 1 deletion.
40 changes: 39 additions & 1 deletion drivers/can/transceiver/can_transceiver_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@ LOG_MODULE_REGISTER(can_transceiver_gpio, CONFIG_CAN_LOG_LEVEL);
#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

/* Does any devicetree instance have a term-gpios property? */
#define INST_HAS_TERM_GPIOS_OR(inst) DT_INST_NODE_HAS_PROP(inst, termination_gpios) ||
#define ANY_INST_HAS_TERM_GPIOS DT_INST_FOREACH_STATUS_OKAY(INST_HAS_TERM_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 */
#if ANY_INST_HAS_TERM_GPIOS
struct gpio_dt_spec termination_gpio;
#endif /* ANY_INST_HAS_TERM_GPIOS */
};

static int can_transceiver_gpio_set_state(const struct device *dev, bool enabled)
Expand Down Expand Up @@ -110,9 +117,37 @@ static int can_transceiver_gpio_init(const struct device *dev)
return 0;
}

static int can_transceiver_gpio_set_termination(const struct device *dev,
bool enabled)

Check warning on line 121 in drivers/can/transceiver/can_transceiver_gpio.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LONG_LINE

drivers/can/transceiver/can_transceiver_gpio.c:121 line length of 109 exceeds 100 columns
{
#if ANY_INST_HAS_TERM_GPIOS
if (config->termination_gpio.port != NULL) {
err = gpio_pin_set_dt(&config->termination_gpio, enabled ? 0 : 1);
if (err != 0) {
LOG_ERR("failed to set termination GPIO pin (err %d)", err);
return -EIO;
}
}
#endif /* ANY_INST_HAS_TERM_GPIOS */

return 0;
}

static int can_transceiver_gpio_termination_enable(const struct device *dev)
{
return can_transceiver_gpio_set_termination(dev, true);
}

static int can_transceiver_gpio_termination_disable(const struct device *dev)
{
return can_transceiver_gpio_set_termination(dev, false);
}

static DEVICE_API(can_transceiver, can_transceiver_gpio_driver_api) = {
.enable = can_transceiver_gpio_enable,
.disable = can_transceiver_gpio_disable,
.termination_enable = can_transceiver_gpio_termination_enable,
.termination_disable = can_transceiver_gpio_termination_disable,
};

#define CAN_TRANSCEIVER_GPIO_COND(inst, name) \
Expand All @@ -121,13 +156,16 @@ static DEVICE_API(can_transceiver, can_transceiver_gpio_driver_api) = {

#define CAN_TRANSCEIVER_GPIO_INIT(inst) \
BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, enable_gpios) || \
DT_INST_NODE_HAS_PROP(inst, standby_gpios), \
DT_INST_NODE_HAS_PROP(inst, standby_gpios), \
DT_INST_NODE_HAS_PROP(inst, termination_gpios), \
"Missing GPIO property on " \
DT_NODE_FULL_NAME(DT_DRV_INST(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) \
CAN_TRANSCEIVER_GPIO_COND(inst, termination_enable) \
CAN_TRANSCEIVER_GPIO_COND(inst, termination_disable) \
}; \
\
DEVICE_DT_INST_DEFINE(inst, &can_transceiver_gpio_init, \
Expand Down
6 changes: 6 additions & 0 deletions dts/bindings/phy/can-transceiver-gpio.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ properties:
GPIO to use to put the CAN transceiver into standby. This GPIO is driven
inactive when the CAN transceiver is enabled and active when the CAN
transceiver is disabled.
termination-gpios:
type: phandle-array
description: |
GPIO to use to enable/disable the CAN transceiver termination resistor.
This GPIO will be not changed during CAN transceiver initialzation phase.
48 changes: 48 additions & 0 deletions include/zephyr/drivers/can/transceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,23 @@ typedef int (*can_transceiver_enable_t)(const struct device *dev, can_mode_t mod
*/
typedef int (*can_transceiver_disable_t)(const struct device *dev);

/**
* @brief Callback API upon enabling CAN transceiver termination
* See @a can_transceiver_termination_enable() for argument description
*/
typedef int (*can_transceiver_termination_enable_t)(const struct device *dev);

/**
* @brief Callback API upon disabling CAN transceiver termination
* See @a can_transceiver_termination_disable() for argument description
*/
typedef int (*can_transceiver_termination_disable_t)(const struct device *dev);

__subsystem struct can_transceiver_driver_api {
can_transceiver_enable_t enable;
can_transceiver_disable_t disable;
can_transceiver_termination_enable_t termination_enable;
can_transceiver_termination_disable_t termination_disable;
};

/** @endcond */
Expand Down Expand Up @@ -87,6 +101,40 @@ static inline int can_transceiver_disable(const struct device *dev)
return DEVICE_API_GET(can_transceiver, dev)->disable(dev);
}

/**
* @brief Enable CAN transceiver termination
*
* Enable CAN transceiver termination by puttig 120ohm between CAN_H and CAN_L.
*
* @note The CAN transceiver is controlled by the CAN controller driver and
* should not normally be controlled by the application.
*
* @param dev Pointer to the device structure for the driver instance.
* @retval 0 If successful.
* @retval -EIO General input/output error, failed to enable device.
*/
static inline int can_transceiver_termination_enable(const struct device *dev)
{
return DEVICE_API_GET(can_transceiver, dev)->termination_enable(dev);
}

/**
* @brief Disable CAN transceiver termination
*
* Disable CAN transceiver termination by puttig 120ohm between CAN_H and CAN_L.
*
* @note The CAN transceiver is controlled by the CAN controller driver and
* should not normally be controlled by the application.
*
* @param dev Pointer to the device structure for the driver instance.
* @retval 0 If successful.
* @retval -EIO General input/output error, failed to enable device.
*/
static inline int can_transceiver_termination_disable(const struct device *dev)
{
return DEVICE_API_GET(can_transceiver, dev)->termination_disable(dev);
}

/**
* @}
*/
Expand Down

0 comments on commit 502e76c

Please sign in to comment.