blob: 9908e5362babc6fdfd13dac663b7179dd2ed771c [file] [log] [blame]
/*
* Copyright (c) 2025 Joel Guittet
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT zephyr_uart_bitbang
#define LOG_LEVEL CONFIG_UART_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(uart_bitbang);
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/sys/sys_io.h>
#include <zephyr/drivers/counter.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/kernel.h>
enum uart_bitbang_state {
UART_BITBANG_IDLE,
UART_BITBANG_START_BIT,
UART_BITBANG_DATA,
UART_BITBANG_PARITY,
UART_BITBANG_STOP_BIT_1,
UART_BITBANG_STOP_BIT_2,
UART_BITBANG_COMPLETE,
};
struct uart_bitbang_config {
/* GPIOs */
struct gpio_dt_spec tx_gpio;
struct gpio_dt_spec rx_gpio;
struct gpio_dt_spec de_gpio;
/* Counters */
const struct device *tx_counter;
const struct device *rx_counter;
/* UART config */
struct uart_config *uart_cfg;
/* MSB first */
bool msb;
};
struct uart_bitbang_data {
/* Configuration */
struct uart_bitbang_config *config;
/* Error flags */
int err;
/* Tx state */
enum uart_bitbang_state tx_state;
/* Tx bit index */
int tx_index;
/* Tx data */
uint16_t *tx_data;
/* Tx parity */
int tx_parity;
/* Tx counter config */
struct counter_top_cfg tx_counter_cfg;
/* Tx ring buffer */
struct ring_buf *tx_ringbuf;
/* Rx state */
enum uart_bitbang_state rx_state;
/* Rx bit index */
int rx_index;
/* Rx data */
uint16_t rx_data;
/* Rx parity */
int rx_parity;
/* Rx counter config */
struct counter_top_cfg rx_counter_cfg;
/* Rx callback data */
struct gpio_callback rx_gpio_cb_data;
/* Rx ring buffer */
struct ring_buf *rx_ringbuf;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
/* Interrupt flags */
#define UART_BITBANG_IRQ_TC (1 << 0)
#define UART_BITBANG_IRQ_RXNE (1 << 1)
#define UART_BITBANG_IRQ_PE (1 << 2)
int irq;
/* User callback and data */
uart_irq_callback_user_data_t user_cb;
void *user_data;
#endif
};
static int uart_bitbang_init(const struct device *dev);
static inline uint8_t uart_bitbang_data_bits_to_len(uint8_t data_bits)
{
switch (data_bits) {
case UART_CFG_DATA_BITS_5:
return 5;
case UART_CFG_DATA_BITS_6:
return 6;
case UART_CFG_DATA_BITS_7:
return 7;
case UART_CFG_DATA_BITS_8:
return 8;
case UART_CFG_DATA_BITS_9:
return 9;
}
return 0;
}
static int uart_bitbang_compute_parity(const struct device *dev, uint16_t data_u16)
{
const struct uart_bitbang_config *config = dev->config;
uint8_t len = uart_bitbang_data_bits_to_len(config->uart_cfg->data_bits);
int parity = 0, index;
if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) {
for (index = 0; index < len; index++) {
const int shift = config->msb ? (len - 1 - index) : index;
const int d = (data_u16 >> shift) & 0x1;
parity += d;
}
if (config->uart_cfg->parity == UART_CFG_PARITY_ODD) {
parity = (parity % 2) ? 0 : 1;
} else if (config->uart_cfg->parity == UART_CFG_PARITY_EVEN) {
parity = (parity % 2) ? 1 : 0;
} else if (config->uart_cfg->parity == UART_CFG_PARITY_MARK) {
parity = 1;
} else if (config->uart_cfg->parity == UART_CFG_PARITY_SPACE) {
parity = 0;
}
}
return parity;
}
/*
* To perform reception of data, a counter interrupt is used for each bit to be read.
* This interrupt uses a state machine and gets the rx gpio depending of the current state.
*/
static void uart_bitbang_rx_counter_top_interrupt(const struct device *dev, void *user_data)
{
const struct device *uart_dev = (struct device *)user_data;
const struct uart_bitbang_config *config = uart_dev->config;
struct uart_bitbang_data *data = uart_dev->data;
uint8_t len = uart_bitbang_data_bits_to_len(config->uart_cfg->data_bits);
int rc;
/* Rx state machine */
if (data->rx_state == UART_BITBANG_DATA) {
/* Compute rx data depending of the bit index */
const int shift = config->msb ? (len - 1 - data->rx_index) : data->rx_index;
data->rx_data |= ((gpio_pin_get_dt(&config->rx_gpio) & 0x1) << shift);
data->rx_index++;
if (data->rx_index == len) {
if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) {
data->rx_state = UART_BITBANG_PARITY;
} else {
data->rx_state = UART_BITBANG_COMPLETE;
}
}
} else if (data->rx_state == UART_BITBANG_PARITY) {
/* Read parity bit value */
data->rx_parity = gpio_pin_get_dt(&config->rx_gpio);
data->rx_state = UART_BITBANG_COMPLETE;
}
/* Intentional fall-through */
if (data->rx_state == UART_BITBANG_COMPLETE) {
/* Stop rx counter */
counter_stop(config->rx_counter);
data->rx_state = UART_BITBANG_IDLE;
/* Enable rx gpio interrupt */
rc = gpio_pin_interrupt_configure_dt(&config->rx_gpio, GPIO_INT_EDGE_FALLING);
if (rc < 0) {
LOG_ERR("Couldn't configure rx pin (%d)", rc);
}
/* Check parity */
if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) {
if (data->rx_parity !=
uart_bitbang_compute_parity(uart_dev, data->rx_data)) {
/* Indicate parity error */
data->err |= UART_ERROR_PARITY;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
if ((data->user_cb) && (data->irq & UART_BITBANG_IRQ_PE)) {
data->user_cb(dev, data->user_data);
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
return;
}
}
/* Push data received to rx ring buffer */
ring_buf_put(data->rx_ringbuf, (const uint8_t *)&data->rx_data, sizeof(uint16_t));
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
if ((data->user_cb) && (data->irq & UART_BITBANG_IRQ_RXNE)) {
data->user_cb(dev, data->user_data);
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}
}
static void uart_bitbang_rx_callback(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
struct uart_bitbang_data *data =
CONTAINER_OF(cb, struct uart_bitbang_data, rx_gpio_cb_data);
struct uart_bitbang_config *config = data->config;
(void)pins;
int rc;
/* Start bit detected, start reception of data */
data->rx_data = 0;
data->rx_index = 0;
data->rx_state = UART_BITBANG_DATA;
counter_reset(config->rx_counter);
counter_start(config->rx_counter);
/* Disable rx gpio interrupt */
rc = gpio_pin_interrupt_configure_dt(&config->rx_gpio, GPIO_INT_DISABLE);
if (rc < 0) {
LOG_ERR("Couldn't configure rx pin (%d)", rc);
}
}
static int uart_bitbang_poll_in_u16(const struct device *dev, uint16_t *in_u16)
{
struct uart_bitbang_data *data = dev->data;
uint32_t s = ring_buf_get(data->rx_ringbuf, (uint8_t *)in_u16, sizeof(uint16_t));
return (s == sizeof(uint16_t)) ? 0 : -1;
}
static int uart_bitbang_poll_in(const struct device *dev, unsigned char *c)
{
uint16_t in_u16;
int rc;
rc = uart_bitbang_poll_in_u16(dev, &in_u16);
*c = (unsigned char)(in_u16 & 0xFF);
return rc;
}
/*
* To perform transmission of data, a counter interrupt is used for each bit to be transmitted.
* This interrupt uses a state machine and sets the tx gpio depending of the current state.
*/
static void uart_bitbang_tx_counter_top_interrupt(const struct device *dev, void *user_data)
{
const struct device *uart_dev = (struct device *)user_data;
const struct uart_bitbang_config *config = uart_dev->config;
struct uart_bitbang_data *data = uart_dev->data;
uint8_t len = uart_bitbang_data_bits_to_len(config->uart_cfg->data_bits);
uint32_t size;
/* Tx state machine */
switch (data->tx_state) {
case UART_BITBANG_IDLE:
/* Claim the next data */
size = ring_buf_get_claim(data->tx_ringbuf, (uint8_t **)&data->tx_data,
sizeof(uint16_t));
if (size == sizeof(uint16_t)) {
/* Start next transmission */
data->tx_index = 0;
data->tx_parity = uart_bitbang_compute_parity(uart_dev, *data->tx_data);
data->tx_state = UART_BITBANG_START_BIT;
/* Assert RS485 driver enable pin */
if ((config->uart_cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485) &&
(config->de_gpio.port != NULL)) {
gpio_pin_set_dt(&config->de_gpio, 1);
}
} else {
/* End of the transmission, stop tx counter */
counter_stop(config->tx_counter);
/* Release RS485 driver enable pin */
if ((config->uart_cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485) &&
(config->de_gpio.port != NULL)) {
gpio_pin_set_dt(&config->de_gpio, 0);
}
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
if ((data->user_cb) && (data->irq & UART_BITBANG_IRQ_TC)) {
data->user_cb(dev, data->user_data);
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}
break;
case UART_BITBANG_START_BIT:
/* Set start bit value */
gpio_pin_set_dt(&config->tx_gpio, 0);
/* Prepare transmission of data */
data->tx_state = UART_BITBANG_DATA;
break;
case UART_BITBANG_DATA:
/* Set tx gpio depending of the bit index */
const int shift = config->msb ? (len - 1 - data->tx_index) : data->tx_index;
const int d = (*data->tx_data >> shift) & 0x1;
gpio_pin_set_dt(&config->tx_gpio, d);
data->tx_index++;
if (data->tx_index == len) {
if (config->uart_cfg->parity != UART_CFG_PARITY_NONE) {
data->tx_state = UART_BITBANG_PARITY;
} else {
data->tx_state = UART_BITBANG_STOP_BIT_1;
}
}
break;
case UART_BITBANG_PARITY:
/* Set parity bit value */
gpio_pin_set_dt(&config->tx_gpio, data->tx_parity);
data->tx_state = UART_BITBANG_STOP_BIT_1;
break;
case UART_BITBANG_STOP_BIT_1:
/* Set stop bit value */
gpio_pin_set_dt(&config->tx_gpio, 1);
if (config->uart_cfg->stop_bits > UART_CFG_STOP_BITS_1) {
data->tx_state = UART_BITBANG_STOP_BIT_2;
} else {
data->tx_state = UART_BITBANG_COMPLETE;
}
break;
case UART_BITBANG_STOP_BIT_2:
/* Wait one more bit in case 1.5 or 2 stop bits */
data->tx_state = UART_BITBANG_COMPLETE;
break;
case UART_BITBANG_COMPLETE:
/* Terminate current transfer */
ring_buf_get_finish(data->tx_ringbuf, sizeof(uint16_t));
data->tx_state = UART_BITBANG_IDLE;
break;
}
}
static void uart_bitbang_poll_out_u16(const struct device *dev, uint16_t out_u16)
{
const struct uart_bitbang_config *config = dev->config;
struct uart_bitbang_data *data = dev->data;
/* Transmit data */
if (config->tx_gpio.port != NULL) {
/* Push data to send to tx ring buffer */
ring_buf_put(data->tx_ringbuf, (const uint8_t *)&out_u16, sizeof(uint16_t));
/* Start tx counter if not already started */
counter_reset(config->tx_counter);
counter_start(config->tx_counter);
}
}
static void uart_bitbang_poll_out(const struct device *dev, unsigned char c)
{
uart_bitbang_poll_out_u16(dev, (uint16_t)c);
}
/*
* Handler used when tx and rx counters are the same instance (half-duplex communications).
* The tx or rx handler is called depending on the device state (rx state not idle indicating the
* reception of data).
*/
static void uart_bitbang_tx_rx_counter_top_interrupt(const struct device *dev, void *user_data)
{
const struct device *uart_dev = (struct device *)user_data;
struct uart_bitbang_data *data = uart_dev->data;
if (data->rx_state != UART_BITBANG_IDLE) {
uart_bitbang_rx_counter_top_interrupt(dev, user_data);
} else {
uart_bitbang_tx_counter_top_interrupt(dev, user_data);
}
}
static int uart_bitbang_err_check(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
int err;
/* Check for errors, then clear them */
err = data->err;
data->err = 0;
return err;
}
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
static int uart_bitbang_configure(const struct device *dev, const struct uart_config *cfg)
{
const struct uart_bitbang_config *config = dev->config;
/* Copy configuration */
memcpy(config->uart_cfg, cfg, sizeof(struct uart_config));
/* Reinitialize device */
return uart_bitbang_init(dev);
};
static int uart_bitbang_config_get(const struct device *dev, struct uart_config *cfg)
{
const struct uart_bitbang_config *config = dev->config;
/* Copy configuration */
memcpy(cfg, config->uart_cfg, sizeof(struct uart_config));
return 0;
}
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static int uart_bitbang_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
{
int index = 0;
while (size - index > 0) {
uart_bitbang_poll_out(dev, tx_data[index]);
index++;
}
return index;
}
#ifdef CONFIG_UART_WIDE_DATA
static int uart_bitbang_fifo_fill_u16(const struct device *dev, const uint16_t *tx_data, int size)
{
int index = 0;
while (size - index > 0) {
uart_bitbang_poll_out_u16(dev, tx_data[index]);
index++;
}
return index;
}
#endif /* CONFIG_UART_WIDE_DATA */
static int uart_bitbang_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
{
int index = 0;
while (size - index > 0) {
if (uart_bitbang_poll_in(dev, &rx_data[index]) < 0) {
break;
}
index++;
}
return index;
}
#ifdef CONFIG_UART_WIDE_DATA
static int uart_bitbang_fifo_read_u16(const struct device *dev, uint16_t *rx_data, const int size)
{
int index = 0;
while (size - index > 0) {
if (uart_bitbang_poll_in_u16(dev, &rx_data[index]) < 0) {
break;
}
index++;
}
return index;
}
#endif /* CONFIG_UART_WIDE_DATA */
static void uart_bitbang_irq_tx_enable(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
/* Enable Transmission Complete interrupt */
data->irq |= UART_BITBANG_IRQ_TC;
}
static void uart_bitbang_irq_tx_disable(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
/* Disable Transmission Complete interrupt */
data->irq &= ~UART_BITBANG_IRQ_TC;
}
static int uart_bitbang_irq_tx_ready(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
return (int)(ring_buf_space_get(data->tx_ringbuf) / sizeof(uint16_t));
}
static void uart_bitbang_irq_rx_enable(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
/* Enable Receive data register Not Empty interrupt */
data->irq |= UART_BITBANG_IRQ_RXNE;
}
static void uart_bitbang_irq_rx_disable(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
/* Disable Receive data register Not Empty interrupt */
data->irq &= ~UART_BITBANG_IRQ_RXNE;
}
static int uart_bitbang_irq_tx_complete(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
return ring_buf_is_empty(data->tx_ringbuf) ? 1 : 0;
}
static int uart_bitbang_irq_rx_ready(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
return (ring_buf_size_get(data->rx_ringbuf) > 0) ? 1 : 0;
}
static void uart_bitbang_irq_err_enable(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
/* Enable Parity Error interrupt */
data->irq |= UART_BITBANG_IRQ_PE;
}
static void uart_bitbang_irq_err_disable(const struct device *dev)
{
struct uart_bitbang_data *data = dev->data;
/* Disable Parity Error interrupt */
data->irq &= ~UART_BITBANG_IRQ_PE;
}
static int uart_bitbang_irq_is_pending(const struct device *dev)
{
return 0;
}
static int uart_bitbang_irq_update(const struct device *dev)
{
return 1;
}
static void uart_bitbang_irq_callback_set(const struct device *dev,
uart_irq_callback_user_data_t cb, void *cb_data)
{
struct uart_bitbang_data *data = dev->data;
data->user_cb = cb;
data->user_data = cb_data;
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static DEVICE_API(uart, uart_bitbang_api) = {
.poll_in = uart_bitbang_poll_in,
.poll_out = uart_bitbang_poll_out,
#ifdef CONFIG_UART_WIDE_DATA
.poll_in_u16 = uart_bitbang_poll_in_u16,
.poll_out_u16 = uart_bitbang_poll_out_u16,
#endif /* CONFIG_UART_WIDE_DATA */
.err_check = uart_bitbang_err_check,
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
.configure = uart_bitbang_configure,
.config_get = uart_bitbang_config_get,
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = uart_bitbang_fifo_fill,
#ifdef CONFIG_UART_WIDE_DATA
.fifo_fill_u16 = uart_bitbang_fifo_fill_u16,
#endif /* CONFIG_UART_WIDE_DATA */
.fifo_read = uart_bitbang_fifo_read,
#ifdef CONFIG_UART_WIDE_DATA
.fifo_read_u16 = uart_bitbang_fifo_read_u16,
#endif /* CONFIG_UART_WIDE_DATA */
.irq_tx_enable = uart_bitbang_irq_tx_enable,
.irq_tx_disable = uart_bitbang_irq_tx_disable,
.irq_tx_ready = uart_bitbang_irq_tx_ready,
.irq_rx_enable = uart_bitbang_irq_rx_enable,
.irq_rx_disable = uart_bitbang_irq_rx_disable,
.irq_tx_complete = uart_bitbang_irq_tx_complete,
.irq_rx_ready = uart_bitbang_irq_rx_ready,
.irq_err_enable = uart_bitbang_irq_err_enable,
.irq_err_disable = uart_bitbang_irq_err_disable,
.irq_is_pending = uart_bitbang_irq_is_pending,
.irq_update = uart_bitbang_irq_update,
.irq_callback_set = uart_bitbang_irq_callback_set,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
};
static int uart_bitbang_init(const struct device *dev)
{
const struct uart_bitbang_config *config = dev->config;
struct uart_bitbang_data *data = dev->data;
int rc;
/* Initialize tx state */
data->tx_state = UART_BITBANG_IDLE;
/*
* Setup tx counter so that the counter interrupts for each bit to be generated
* A state machine in the interrupt handler permits to generate the uart signal
*/
if (config->tx_gpio.port != NULL) {
if (config->tx_counter == NULL) {
LOG_ERR("Couldn't configure tx counter");
return -ENODEV;
} else if (config->tx_counter != config->rx_counter) {
if (!device_is_ready(config->tx_counter)) {
LOG_ERR("Couldn't configure tx counter");
return -ENODEV;
}
data->tx_counter_cfg.callback = uart_bitbang_tx_counter_top_interrupt;
data->tx_counter_cfg.ticks = counter_get_frequency(config->tx_counter) /
config->uart_cfg->baudrate;
data->tx_counter_cfg.user_data = (void *)dev;
data->tx_counter_cfg.flags = 0;
rc = counter_set_top_value(config->tx_counter, &data->tx_counter_cfg);
if (rc < 0) {
LOG_ERR("Couldn't configure tx counter (%d)", rc);
return rc;
}
}
}
/* Initialize rx state */
data->rx_state = UART_BITBANG_IDLE;
/*
* Setup rx counter so that the counter interrupts for each bit to be read
* A state machine in the interrupt handler permits to capture the uart signal
*/
if (config->rx_gpio.port != NULL) {
if (config->rx_counter == NULL) {
LOG_ERR("Couldn't configure rx counter");
return -ENODEV;
} else if (config->rx_counter != config->tx_counter) {
if (!device_is_ready(config->rx_counter)) {
LOG_ERR("Couldn't configure rx counter");
return -ENODEV;
}
data->rx_counter_cfg.callback = uart_bitbang_rx_counter_top_interrupt;
data->rx_counter_cfg.ticks = counter_get_frequency(config->rx_counter) /
config->uart_cfg->baudrate;
data->rx_counter_cfg.user_data = (void *)dev;
data->rx_counter_cfg.flags = 0;
rc = counter_set_top_value(config->rx_counter, &data->rx_counter_cfg);
if (rc < 0) {
LOG_ERR("Couldn't configure rx counter (%d)", rc);
return rc;
}
}
}
/*
* Setup tx/rx counter in case it is the same instance so that the counter interrupts for
* each bit to be generated or read
* The interrupt handler calls the tx or rx counter handler depending on the device state
*/
if (((config->tx_gpio.port != NULL) || (config->rx_gpio.port != NULL)) &&
(config->tx_counter != NULL) && (config->tx_counter == config->rx_counter)) {
if (!device_is_ready(config->tx_counter)) {
LOG_ERR("Couldn't configure tx/rx counter");
return -ENODEV;
}
data->tx_counter_cfg.callback = uart_bitbang_tx_rx_counter_top_interrupt;
data->tx_counter_cfg.ticks =
counter_get_frequency(config->tx_counter) / config->uart_cfg->baudrate;
data->tx_counter_cfg.user_data = (void *)dev;
data->tx_counter_cfg.flags = 0;
rc = counter_set_top_value(config->tx_counter, &data->tx_counter_cfg);
if (rc < 0) {
LOG_ERR("Couldn't configure tx/rx counter (%d)", rc);
return rc;
}
}
/* Setup tx gpio if it is defined */
if (config->tx_gpio.port != NULL) {
if (!gpio_is_ready_dt(&config->tx_gpio)) {
LOG_ERR("GPIO port for tx pin is not ready");
return -ENODEV;
}
rc = gpio_pin_configure_dt(&config->tx_gpio, GPIO_OUTPUT_INACTIVE);
if (rc < 0) {
LOG_ERR("Couldn't configure tx pin (%d)", rc);
return rc;
}
rc = gpio_pin_set_dt(&config->tx_gpio, 1);
if (rc < 0) {
LOG_ERR("Couldn't set tx pin (%d)", rc);
return rc;
}
}
/* Setup rx gpio if it is defined */
if (config->rx_gpio.port != NULL) {
if (!gpio_is_ready_dt(&config->rx_gpio)) {
LOG_ERR("GPIO port for rx pin is not ready");
return -ENODEV;
}
rc = gpio_pin_configure_dt(&config->rx_gpio, GPIO_INPUT);
if (rc < 0) {
LOG_ERR("Couldn't configure rx pin (%d)", rc);
return rc;
}
rc = gpio_pin_interrupt_configure_dt(&config->rx_gpio, GPIO_INT_EDGE_FALLING);
if (rc < 0) {
LOG_ERR("Couldn't configure rx pin (%d)", rc);
return rc;
}
gpio_init_callback(&data->rx_gpio_cb_data, uart_bitbang_rx_callback,
BIT(config->rx_gpio.pin));
rc = gpio_add_callback_dt(&config->rx_gpio, &data->rx_gpio_cb_data);
if (rc < 0) {
LOG_ERR("Couldn't configure rx callback (%d)", rc);
return rc;
}
}
/* Setup RS485 driver enable gpio if it is defined */
if ((config->uart_cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485) &&
(config->de_gpio.port != NULL)) {
if (!gpio_is_ready_dt(&config->de_gpio)) {
LOG_ERR("GPIO port for driver enable pin is not ready");
return -ENODEV;
}
rc = gpio_pin_configure_dt(&config->de_gpio, GPIO_OUTPUT_INACTIVE);
if (rc < 0) {
LOG_ERR("Couldn't configure driver enable pin (%d)", rc);
return rc;
}
rc = gpio_pin_set_dt(&config->de_gpio, 0);
if (rc < 0) {
LOG_ERR("Couldn't set driver enable pin (%d)", rc);
return rc;
}
}
return 0;
}
#define UART_BITBANG_INIT(index) \
static struct uart_config uart_cfg_##index = { \
.baudrate = DT_INST_PROP(index, current_speed), \
.parity = DT_INST_ENUM_IDX(index, parity), \
.stop_bits = DT_INST_ENUM_IDX(index, stop_bits), \
.data_bits = DT_INST_ENUM_IDX(index, data_bits), \
.flow_ctrl = DT_INST_PROP(index, hw_flow_control) ? UART_CFG_FLOW_CTRL_RTS_CTS \
: DT_INST_PROP(index, hw_rs485_flow_control) \
? UART_CFG_FLOW_CTRL_RS485 \
: UART_CFG_FLOW_CTRL_NONE, \
}; \
static struct uart_bitbang_config uart_bitbang_config_##index = { \
.tx_gpio = GPIO_DT_SPEC_INST_GET_OR(index, tx_gpios, {0}), \
.rx_gpio = GPIO_DT_SPEC_INST_GET_OR(index, rx_gpios, {0}), \
.de_gpio = GPIO_DT_SPEC_INST_GET_OR(index, de_gpios, {0}), \
.tx_counter = DEVICE_DT_GET_OR_NULL( \
DT_CHILD(DT_INST_PHANDLE(index, tx_timer), counter)), \
.rx_counter = DEVICE_DT_GET_OR_NULL( \
DT_CHILD(DT_INST_PHANDLE(index, rx_timer), counter)), \
.uart_cfg = &uart_cfg_##index, \
.msb = DT_INST_PROP_OR(index, msb, false), \
}; \
RING_BUF_DECLARE(uart_bitbang_tx_ringbuf##index, DT_INST_PROP(index, tx_fifo_size)); \
RING_BUF_DECLARE(uart_bitbang_rx_ringbuf##index, DT_INST_PROP(index, rx_fifo_size)); \
static struct uart_bitbang_data uart_bitbang_data_##index = { \
.config = &uart_bitbang_config_##index, \
.tx_ringbuf = &uart_bitbang_tx_ringbuf##index, \
.rx_ringbuf = &uart_bitbang_rx_ringbuf##index, \
}; \
DEVICE_DT_INST_DEFINE(index, uart_bitbang_init, PM_DEVICE_DT_INST_GET(index), \
&uart_bitbang_data_##index, &uart_bitbang_config_##index, \
POST_KERNEL, CONFIG_SERIAL_INIT_PRIORITY, &uart_bitbang_api);
DT_INST_FOREACH_STATUS_OKAY(UART_BITBANG_INIT)