Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

908 lines
25 KiB

/*
* Copyright (c) 2024 Texas Instruments Incorporated
* Copyright (c) 2024 BayLibre, SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_cc23x0_uart
#include <zephyr/device.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/irq.h>
#include <errno.h>
#include <driverlib/uart.h>
#include <driverlib/clkctl.h>
#include <inc/hw_memmap.h>
#ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
#define UART_CC23_REG_GET(base, offset) ((base) + (offset))
/*
* For each DMA channel, burst transfer and single transfer request signals
* are not mutually exclusive, and both can be asserted at the same time.
* For example, when there is more data than the watermark level in the
* TX (or RX) FIFO, the burst transfer request and the single transfer
* requests are asserted.
* When a burst request is detected, the DMA controller transfers the number
* of items that is the lesser of the arbitration size or the number of items
* remaining in the transfer. Therefore, the arbitration size must be the same
* as the number of data items that the peripheral can accommodate when making
* a burst request. Since UART, which uses a mix of single or burst requests,
* can generate a burst request based on the FIFO trigger level (1/2 full),
* the burst length is set to half the FIFO size.
*/
#define UART_CC23_BURST_LEN 4
#endif
struct uart_cc23x0_config {
uint32_t reg;
uint32_t sys_clk_freq;
const struct pinctrl_dev_config *pcfg;
#ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
const struct device *dma_dev;
uint8_t dma_channel_tx;
uint8_t dma_trigsrc_tx;
uint8_t dma_channel_rx;
uint8_t dma_trigsrc_rx;
#endif
};
struct uart_cc23x0_data {
struct uart_config uart_config;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_irq_callback_user_data_t callback;
void *user_data;
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
const struct device *dev;
uart_callback_t async_callback;
void *async_user_data;
struct k_work_delayable tx_timeout_work;
const uint8_t *tx_buf;
size_t tx_len;
uint8_t *rx_buf;
size_t rx_len;
size_t rx_processed_len;
uint8_t *rx_next_buf;
size_t rx_next_len;
#endif /* CONFIG_UART_CC23X0_DMA_DRIVEN */
};
static int uart_cc23x0_poll_in(const struct device *dev, unsigned char *c)
{
const struct uart_cc23x0_config *config = dev->config;
if (!UARTCharAvailable(config->reg)) {
return -1;
}
*c = UARTGetCharNonBlocking(config->reg);
return 0;
}
static void uart_cc23x0_poll_out(const struct device *dev, unsigned char c)
{
const struct uart_cc23x0_config *config = dev->config;
UARTPutChar(config->reg, c);
}
static int uart_cc23x0_err_check(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
uint32_t flags = UARTGetRxError(config->reg);
int error = 0;
error |= (flags & UART_RXERROR_FRAMING) ? UART_ERROR_FRAMING : 0;
error |= (flags & UART_RXERROR_PARITY) ? UART_ERROR_PARITY : 0;
error |= (flags & UART_RXERROR_BREAK) ? UART_BREAK : 0;
error |= (flags & UART_RXERROR_OVERRUN) ? UART_ERROR_OVERRUN : 0;
UARTClearRxError(config->reg);
return error;
}
static int uart_cc23x0_configure(const struct device *dev, const struct uart_config *cfg)
{
const struct uart_cc23x0_config *config = dev->config;
struct uart_cc23x0_data *data = dev->data;
uint32_t line_ctrl = 0;
bool flow_ctrl;
switch (cfg->parity) {
case UART_CFG_PARITY_NONE:
line_ctrl |= UART_CONFIG_PAR_NONE;
break;
case UART_CFG_PARITY_ODD:
line_ctrl |= UART_CONFIG_PAR_ODD;
break;
case UART_CFG_PARITY_EVEN:
line_ctrl |= UART_CONFIG_PAR_EVEN;
break;
case UART_CFG_PARITY_MARK:
line_ctrl |= UART_CONFIG_PAR_ONE;
break;
case UART_CFG_PARITY_SPACE:
line_ctrl |= UART_CONFIG_PAR_ZERO;
break;
default:
return -EINVAL;
}
switch (cfg->stop_bits) {
case UART_CFG_STOP_BITS_1:
line_ctrl |= UART_CONFIG_STOP_ONE;
break;
case UART_CFG_STOP_BITS_2:
line_ctrl |= UART_CONFIG_STOP_TWO;
break;
case UART_CFG_STOP_BITS_0_5:
case UART_CFG_STOP_BITS_1_5:
return -ENOTSUP;
default:
return -EINVAL;
}
switch (cfg->data_bits) {
case UART_CFG_DATA_BITS_5:
line_ctrl |= UART_CONFIG_WLEN_5;
break;
case UART_CFG_DATA_BITS_6:
line_ctrl |= UART_CONFIG_WLEN_6;
break;
case UART_CFG_DATA_BITS_7:
line_ctrl |= UART_CONFIG_WLEN_7;
break;
case UART_CFG_DATA_BITS_8:
line_ctrl |= UART_CONFIG_WLEN_8;
break;
default:
return -EINVAL;
}
switch (cfg->flow_ctrl) {
case UART_CFG_FLOW_CTRL_NONE:
flow_ctrl = false;
break;
case UART_CFG_FLOW_CTRL_RTS_CTS:
flow_ctrl = true;
break;
case UART_CFG_FLOW_CTRL_DTR_DSR:
return -ENOTSUP;
default:
return -EINVAL;
}
/* Disables UART before setting control registers */
UARTConfigSetExpClk(config->reg, config->sys_clk_freq, cfg->baudrate, line_ctrl);
if (flow_ctrl) {
UARTEnableCTS(config->reg);
UARTEnableRTS(config->reg);
} else {
UARTDisableCTS(config->reg);
UARTDisableRTS(config->reg);
}
/* Re-enable UART */
UARTEnable(config->reg);
/* Make use of the FIFO to reduce chances of data being lost */
UARTEnableFifo(config->reg);
data->uart_config = *cfg;
return 0;
}
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
static int uart_cc23x0_config_get(const struct device *dev, struct uart_config *cfg)
{
const struct uart_cc23x0_data *data = dev->data;
*cfg = data->uart_config;
return 0;
}
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static int uart_cc23x0_fifo_fill(const struct device *dev, const uint8_t *buf, int len)
{
const struct uart_cc23x0_config *config = dev->config;
int n = 0;
while (n < len) {
if (!UARTSpaceAvailable(config->reg)) {
break;
}
UARTPutCharNonBlocking(config->reg, buf[n]);
n++;
}
return n;
}
static int uart_cc23x0_fifo_read(const struct device *dev, uint8_t *buf, const int len)
{
const struct uart_cc23x0_config *config = dev->config;
int c, n;
n = 0;
while (n < len) {
if (!UARTCharAvailable(config->reg)) {
break;
}
c = UARTGetCharNonBlocking(config->reg);
buf[n++] = c;
}
return n;
}
static void uart_cc23x0_irq_tx_enable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
UARTEnableInt(config->reg, UART_INT_TX);
}
static void uart_cc23x0_irq_tx_disable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
UARTDisableInt(config->reg, UART_INT_TX);
}
static int uart_cc23x0_irq_tx_ready(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
return UARTSpaceAvailable(config->reg) ? 1 : 0;
}
static void uart_cc23x0_irq_rx_enable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
/* Trigger the ISR on both RX and Receive Timeout. This is to allow
* the use of the hardware FIFOs for more efficient operation
*/
UARTEnableInt(config->reg, UART_INT_RX | UART_INT_RT);
}
static void uart_cc23x0_irq_rx_disable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
UARTDisableInt(config->reg, UART_INT_RX | UART_INT_RT);
}
static int uart_cc23x0_irq_tx_complete(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
return UARTBusy(config->reg) ? 0 : 1;
}
static int uart_cc23x0_irq_rx_ready(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
return UARTCharAvailable(config->reg) ? 1 : 0;
}
static void uart_cc23x0_irq_err_enable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
return UARTEnableInt(config->reg, UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);
}
static void uart_cc23x0_irq_err_disable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
return UARTDisableInt(config->reg, UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);
}
static int uart_cc23x0_irq_is_pending(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
/* Read masked interrupt status */
uint32_t status = UARTIntStatus(config->reg, true);
return status ? 1 : 0;
}
static int uart_cc23x0_irq_update(const struct device *dev)
{
ARG_UNUSED(dev);
return 1;
}
static void uart_cc23x0_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
void *user_data)
{
struct uart_cc23x0_data *data = dev->data;
data->callback = cb;
data->user_data = user_data;
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#if CONFIG_UART_CC23X0_DMA_DRIVEN
static int uart_cc23x0_async_callback_set(const struct device *dev, uart_callback_t callback,
void *user_data)
{
struct uart_cc23x0_data *data = dev->data;
#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
data->async_callback = NULL;
data->async_user_data = NULL;
#else
data->async_callback = callback;
data->async_user_data = user_data;
#endif
return 0;
}
static int uart_cc23x0_async_tx(const struct device *dev, const uint8_t *buf, size_t len,
int32_t timeout)
{
const struct uart_cc23x0_config *config = dev->config;
struct uart_cc23x0_data *data = dev->data;
unsigned int key;
int ret;
struct dma_block_config block_cfg_tx = {
.source_address = (uint32_t)buf,
.dest_address = UART_CC23_REG_GET(config->reg, UART_O_DR),
.source_addr_adj = DMA_ADDR_ADJ_INCREMENT,
.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE,
.block_size = len,
};
struct dma_config dma_cfg_tx = {
.dma_slot = config->dma_trigsrc_tx,
.channel_direction = MEMORY_TO_PERIPHERAL,
.block_count = 1,
.head_block = &block_cfg_tx,
.source_data_size = 1,
.dest_data_size = 1,
.source_burst_length = UART_CC23_BURST_LEN,
.dma_callback = NULL,
.user_data = NULL,
};
key = irq_lock();
if (data->tx_len) {
irq_unlock(key);
return -EBUSY;
}
data->tx_buf = buf;
data->tx_len = len;
irq_unlock(key);
ret = dma_config(config->dma_dev, config->dma_channel_tx, &dma_cfg_tx);
if (ret) {
return ret;
}
/* Disable DMA trigger */
UARTDisableDMA(config->reg, UART_DMA_TX);
/* Schedule timeout work */
if (timeout != SYS_FOREVER_US) {
k_work_reschedule(&data->tx_timeout_work, K_USEC(timeout));
}
/* Start DMA channel */
ret = dma_start(config->dma_dev, config->dma_channel_tx);
if (ret) {
return ret;
}
/* Enable DMA trigger to start the transfer */
UARTEnableDMA(config->reg, UART_DMA_TX);
return 0;
}
static int uart_cc23x0_tx_halt(struct uart_cc23x0_data *data)
{
const struct uart_cc23x0_config *config = data->dev->config;
struct dma_status status;
struct uart_event evt;
size_t total_len;
unsigned int key;
key = irq_lock();
total_len = data->tx_len;
evt.type = UART_TX_ABORTED;
evt.data.tx.buf = data->tx_buf;
evt.data.tx.len = 0;
data->tx_buf = NULL;
data->tx_len = 0;
dma_stop(config->dma_dev, config->dma_channel_tx);
irq_unlock(key);
if (dma_get_status(config->dma_dev, config->dma_channel_tx, &status) == 0) {
evt.data.tx.len = total_len - status.pending_length;
}
if (total_len) {
if (data->async_callback) {
data->async_callback(data->dev, &evt, data->async_user_data);
}
} else {
return -EINVAL;
}
return 0;
}
static void uart_cc23x0_async_tx_timeout(struct k_work *work)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
struct uart_cc23x0_data *data = CONTAINER_OF(dwork, struct uart_cc23x0_data,
tx_timeout_work);
uart_cc23x0_tx_halt(data);
}
static int uart_cc23x0_async_tx_abort(const struct device *dev)
{
struct uart_cc23x0_data *data = dev->data;
k_work_cancel_delayable(&data->tx_timeout_work);
return uart_cc23x0_tx_halt(data);
}
static int uart_cc23x0_async_rx_enable(const struct device *dev, uint8_t *buf, size_t len,
int32_t timeout)
{
const struct uart_cc23x0_config *config = dev->config;
struct uart_cc23x0_data *data = dev->data;
struct uart_event evt;
unsigned int key;
int ret;
struct dma_block_config block_cfg_rx = {
.source_address = UART_CC23_REG_GET(config->reg, UART_O_DR),
.dest_address = (uint32_t)buf,
.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE,
.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT,
.block_size = len,
};
struct dma_config dma_cfg_rx = {
.dma_slot = config->dma_trigsrc_rx,
.channel_direction = PERIPHERAL_TO_MEMORY,
.block_count = 1,
.head_block = &block_cfg_rx,
.source_data_size = 1,
.dest_data_size = 1,
.source_burst_length = UART_CC23_BURST_LEN,
.dma_callback = NULL,
.user_data = NULL,
};
if (timeout != SYS_FOREVER_US) {
return -ENOTSUP;
}
key = irq_lock();
if (data->rx_len) {
ret = -EBUSY;
goto unlock;
}
ret = dma_config(config->dma_dev, config->dma_channel_rx, &dma_cfg_rx);
if (ret) {
goto unlock;
}
/* Disable DMA trigger */
UARTDisableDMA(config->reg, UART_DMA_RX);
/* Start DMA channel */
ret = dma_start(config->dma_dev, config->dma_channel_rx);
if (ret) {
goto unlock;
}
/* Enable DMA trigger to start the transfer */
UARTEnableDMA(config->reg, UART_DMA_RX);
data->rx_buf = buf;
data->rx_len = len;
data->rx_processed_len = 0;
/* Request next buffer */
if (data->async_callback) {
evt.type = UART_RX_BUF_REQUEST;
data->async_callback(dev, &evt, data->async_user_data);
}
unlock:
irq_unlock(key);
return ret;
}
static int uart_cc23x0_async_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len)
{
struct uart_cc23x0_data *data = dev->data;
unsigned int key;
int ret = 0;
key = irq_lock();
if (data->rx_len == 0) {
ret = -EACCES;
goto unlock;
}
if (data->rx_next_len) {
ret = -EBUSY;
goto unlock;
}
data->rx_next_buf = buf;
data->rx_next_len = len;
unlock:
irq_unlock(key);
return ret;
}
static void uart_cc23x0_notify_rx_processed(struct uart_cc23x0_data *data,
size_t processed)
{
struct uart_event evt;
if (!data->async_callback || data->rx_processed_len == processed) {
return;
}
evt.type = UART_RX_RDY;
evt.data.rx.buf = data->rx_buf;
evt.data.rx.offset = data->rx_processed_len;
evt.data.rx.len = processed - data->rx_processed_len;
data->rx_processed_len = processed;
data->async_callback(data->dev, &evt, data->async_user_data);
}
static int uart_cc23x0_async_rx_disable(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
struct uart_cc23x0_data *data = dev->data;
struct dma_status status;
struct uart_event evt;
size_t rx_processed;
unsigned int key;
int ret = 0;
key = irq_lock();
if (data->rx_len == 0) {
ret = -EINVAL;
goto unlock;
}
dma_stop(config->dma_dev, config->dma_channel_rx);
if (dma_get_status(config->dma_dev, config->dma_channel_rx, &status) == 0 &&
status.pending_length) {
rx_processed = data->rx_len - status.pending_length;
uart_cc23x0_notify_rx_processed(data, rx_processed);
}
if (data->async_callback) {
evt.type = UART_RX_BUF_RELEASED;
evt.data.rx_buf.buf = data->rx_buf;
data->async_callback(dev, &evt, data->async_user_data);
}
data->rx_buf = NULL;
data->rx_len = 0;
if (data->rx_next_len) {
if (data->async_callback) {
evt.type = UART_RX_BUF_RELEASED;
evt.data.rx_buf.buf = data->rx_next_buf;
data->async_callback(dev, &evt, data->async_user_data);
}
data->rx_next_buf = NULL;
data->rx_next_len = 0;
}
if (data->async_callback) {
evt.type = UART_RX_DISABLED;
data->async_callback(dev, &evt, data->async_user_data);
}
unlock:
irq_unlock(key);
return ret;
}
#endif /* CONFIG_UART_CC23X0_DMA_DRIVEN */
#if CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_CC23X0_DMA_DRIVEN
static void uart_cc23x0_isr(const struct device *dev)
{
struct uart_cc23x0_data *data = dev->data;
#if CONFIG_UART_CC23X0_DMA_DRIVEN
const struct uart_cc23x0_config *config = dev->config;
struct uart_event evt;
unsigned int key;
uint32_t int_status = UARTIntStatus(config->reg, true);
#endif
#if CONFIG_UART_INTERRUPT_DRIVEN
if (data->callback) {
data->callback(dev, data->user_data);
}
#endif
#if CONFIG_UART_CC23X0_DMA_DRIVEN
/*
* When a peripheral channel is used (which is the case here for UART),
* the DMA transfer completion is signaled on the peripheral's interrupt only.
* It is not signaled on the DMA dedicated interrupt.
*/
if (int_status & UART_INT_TXDMADONE) {
k_work_cancel_delayable(&data->tx_timeout_work);
key = irq_lock();
if (data->tx_len && data->async_callback) {
evt.type = UART_TX_DONE;
evt.data.tx.buf = data->tx_buf;
evt.data.tx.len = data->tx_len;
data->async_callback(dev, &evt, data->async_user_data);
}
data->tx_buf = NULL;
data->tx_len = 0;
irq_unlock(key);
UARTClearInt(config->reg, UART_INT_TXDMADONE);
}
if (int_status & UART_INT_RXDMADONE) {
key = irq_lock();
uart_cc23x0_notify_rx_processed(data, data->rx_len);
if (data->async_callback) {
evt.type = UART_RX_BUF_RELEASED;
evt.data.rx.buf = data->rx_buf;
data->async_callback(dev, &evt, data->async_user_data);
}
if (data->rx_next_len == 0) {
/* If no next buffer, end the transfer */
data->rx_buf = NULL;
data->rx_len = 0;
if (data->async_callback) {
evt.type = UART_RX_DISABLED;
data->async_callback(dev, &evt, data->async_user_data);
}
} else {
/* Otherwise, load next buffer and start the transfer */
data->rx_buf = data->rx_next_buf;
data->rx_len = data->rx_next_len;
data->rx_next_buf = NULL;
data->rx_next_len = 0;
data->rx_processed_len = 0;
dma_reload(config->dma_dev, config->dma_channel_rx,
(uint32_t)UART_CC23_REG_GET(config->reg, UART_O_DR),
(uint32_t)data->rx_buf, data->rx_len);
dma_start(config->dma_dev, config->dma_channel_rx);
/* Request a new buffer */
if (data->async_callback) {
evt.type = UART_RX_BUF_REQUEST;
data->async_callback(dev, &evt, data->async_user_data);
}
}
irq_unlock(key);
UARTClearInt(config->reg, UART_INT_RXDMADONE);
}
#endif
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_CC23X0_DMA_DRIVEN */
static DEVICE_API(uart, uart_cc23x0_driver_api) = {
.poll_in = uart_cc23x0_poll_in,
.poll_out = uart_cc23x0_poll_out,
.err_check = uart_cc23x0_err_check,
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
.configure = uart_cc23x0_configure,
.config_get = uart_cc23x0_config_get,
#endif
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = uart_cc23x0_fifo_fill,
.fifo_read = uart_cc23x0_fifo_read,
.irq_tx_enable = uart_cc23x0_irq_tx_enable,
.irq_tx_disable = uart_cc23x0_irq_tx_disable,
.irq_tx_ready = uart_cc23x0_irq_tx_ready,
.irq_rx_enable = uart_cc23x0_irq_rx_enable,
.irq_rx_disable = uart_cc23x0_irq_rx_disable,
.irq_tx_complete = uart_cc23x0_irq_tx_complete,
.irq_rx_ready = uart_cc23x0_irq_rx_ready,
.irq_err_enable = uart_cc23x0_irq_err_enable,
.irq_err_disable = uart_cc23x0_irq_err_disable,
.irq_is_pending = uart_cc23x0_irq_is_pending,
.irq_update = uart_cc23x0_irq_update,
.irq_callback_set = uart_cc23x0_irq_callback_set,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#if CONFIG_UART_CC23X0_DMA_DRIVEN
.callback_set = uart_cc23x0_async_callback_set,
.tx = uart_cc23x0_async_tx,
.tx_abort = uart_cc23x0_async_tx_abort,
.rx_enable = uart_cc23x0_async_rx_enable,
.rx_buf_rsp = uart_cc23x0_async_rx_buf_rsp,
.rx_disable = uart_cc23x0_async_rx_disable,
#endif /* CONFIG_UART_CC23X0_DMA_DRIVEN */
};
#if CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_CC23X0_DMA_DRIVEN
#define UART_CC23X0_IRQ_CFG(n) \
const struct uart_cc23x0_config *config = dev->config; \
\
do { \
UARTClearInt(config->reg, UART_INT_RX); \
UARTClearInt(config->reg, UART_INT_RT); \
\
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_cc23x0_isr, \
DEVICE_DT_INST_GET(n), 0); \
irq_enable(DT_INST_IRQN(n)); \
} while (false)
#else
#define UART_CC23X0_IRQ_CFG(n)
#endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_CC23X0_DMA_DRIVEN */
#if CONFIG_UART_INTERRUPT_DRIVEN
#define UART_CC23X0_INT_FIELDS .callback = NULL, .user_data = NULL,
#else
#define UART_CC23X0_INT_FIELDS
#endif
#ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
#define UART_CC23X0_DMA_INIT(n) \
.dma_dev = DEVICE_DT_GET(TI_CC23X0_DT_INST_DMA_CTLR(n, tx)), \
.dma_channel_tx = TI_CC23X0_DT_INST_DMA_CHANNEL(n, tx), \
.dma_trigsrc_tx = TI_CC23X0_DT_INST_DMA_TRIGSRC(n, tx), \
.dma_channel_rx = TI_CC23X0_DT_INST_DMA_CHANNEL(n, rx), \
.dma_trigsrc_rx = TI_CC23X0_DT_INST_DMA_TRIGSRC(n, rx),
#else
#define UART_CC23X0_DMA_INIT(n)
#endif
static int uart_cc23x0_init_common(const struct device *dev)
{
const struct uart_cc23x0_config *config = dev->config;
struct uart_cc23x0_data *data = dev->data;
int ret;
CLKCTLEnable(CLKCTL_BASE, CLKCTL_UART0);
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
#ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
if (!device_is_ready(config->dma_dev)) {
return -ENODEV;
}
UARTEnableInt(config->reg, UART_INT_TXDMADONE | UART_INT_RXDMADONE);
k_work_init_delayable(&data->tx_timeout_work, uart_cc23x0_async_tx_timeout);
data->dev = dev;
#endif
/* Configure and enable UART */
return uart_cc23x0_configure(dev, &data->uart_config);
}
#define UART_CC23X0_DEVICE_DEFINE(n) \
\
DEVICE_DT_INST_DEFINE(n, uart_cc23x0_init_##n, NULL, &uart_cc23x0_data_##n, \
&uart_cc23x0_config_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
&uart_cc23x0_driver_api)
#define UART_CC23X0_INIT_FUNC(n) \
static int uart_cc23x0_init_##n(const struct device *dev) \
{ \
int ret; \
\
ret = uart_cc23x0_init_common(dev); \
if (ret < 0) { \
return ret; \
} \
\
/* Enable interrupts */ \
UART_CC23X0_IRQ_CFG(n); \
\
return ret; \
}
#define UART_CC23X0_INIT(n) \
PINCTRL_DT_INST_DEFINE(n); \
UART_CC23X0_INIT_FUNC(n); \
\
static struct uart_cc23x0_config uart_cc23x0_config_##n = { \
.reg = DT_INST_REG_ADDR(n), \
.sys_clk_freq = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
UART_CC23X0_DMA_INIT(n) \
}; \
\
static struct uart_cc23x0_data uart_cc23x0_data_##n = { \
.uart_config = \
{ \
.baudrate = DT_INST_PROP(n, current_speed), \
.parity = DT_INST_ENUM_IDX(n, parity), \
.stop_bits = DT_INST_ENUM_IDX(n, stop_bits), \
.data_bits = DT_INST_ENUM_IDX(n, data_bits), \
.flow_ctrl = DT_INST_PROP(n, hw_flow_control), \
}, \
UART_CC23X0_INT_FIELDS \
}; \
UART_CC23X0_DEVICE_DEFINE(n);
DT_INST_FOREACH_STATUS_OKAY(UART_CC23X0_INIT)