drivers: serial: ns16550: Add support for Async APIs

Added support for async APIs for ns16550. This will be
enabled by kconfig CONFIG_UART_ASYNC_API.

Signed-off-by: Anisetti Avinash Krishna <anisetti.avinash.krishna@intel.com>
This commit is contained in:
Anisetti Avinash Krishna 2023-04-04 15:14:34 +05:30 committed by Fabio Baltieri
parent 3d5de8920b
commit 2d03aaf99f
2 changed files with 576 additions and 1 deletions

View file

@ -6,6 +6,7 @@ menuconfig UART_NS16550
depends on DT_HAS_NS16550_ENABLED
select SERIAL_HAS_DRIVER
select SERIAL_SUPPORT_INTERRUPT
select SERIAL_SUPPORT_ASYNC
help
This option enables the NS16550 serial driver.
This driver can be used for the serial hardware

View file

@ -66,6 +66,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
#define REG_MDC 0x04 /* Modem control reg. */
#define REG_LSR 0x05 /* Line status reg. */
#define REG_MSR 0x06 /* Modem status reg. */
#define REG_SCR 0x07 /* Scratchpad. */
#define REG_DLF 0xC0 /* Divisor Latch Fraction */
#define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */
@ -142,6 +143,18 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
*/
#define FCR_FIFO_64 0x20 /* Enable 64 bytes FIFO */
/* FIFO Depth. */
#if defined(CONFIG_UART_NS16550_VARIANT_NS16750)
#define UART_FIFO_DEPTH (64)
#elif defined(CONFIG_UART_NS16550_VARIANT_NS16950)
#define UART_FIFO_DEPTH (128)
#else
#define UART_FIFO_DEPTH (16)
#endif
/* FIFO Half Depth. */
#define UART_FIFO_HALF_DEPTH (UART_FIFO_DEPTH / 2)
/* constants for line control register */
#define LCR_CS5 0x00 /* 5 bits data size */
@ -177,6 +190,18 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
#define LSR_THRE 0x20 /* transmit holding register empty */
#define LSR_TEMT 0x40 /* transmitter empty */
/* Transfer Error */
#define UART_PASS 0 /* Transfer completed */
#define UART_ERROR_CANCELED -ECANCELED /* Operation was canceled */
#define UART_DRIVER_ERROR -ENOTSUP /* Unsupported error */
/* Transfer Status */
#define UART_TRANSFER_SUCCESS 0 /* Transfer success */
#define UART_TRANSFER_FAILED -EPERM /* Transfer failed */
/* SCR bit to indicate updated status for LSR. */
#define UART_SCR_STATUS_UPDATE BIT(0)
/* constants for modem status register */
#define MSR_DCTS 0x01 /* cts change */
@ -199,11 +224,44 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
#define MDC(dev) (get_port(dev) + REG_MDC * reg_interval(dev))
#define LSR(dev) (get_port(dev) + REG_LSR * reg_interval(dev))
#define MSR(dev) (get_port(dev) + REG_MSR * reg_interval(dev))
#define SCR(dev) (get_port(dev) + REG_SCR * reg_interval(dev))
#define DLF(dev) (get_port(dev) + REG_DLF)
#define PCP(dev) (get_port(dev) + REG_PCP)
#define IIRC(dev) (((struct uart_ns16550_dev_data *)(dev)->data)->iir_cache)
#if CONFIG_UART_ASYNC_API
/* Macro to get tx semamphore */
#define GET_TX_SEM(dev) \
(((const struct uart_ns16550_device_config *) \
dev->config)->tx_sem)
/* Macro to get rx sempahore */
#define GET_RX_SEM(dev) \
(((const struct uart_ns16550_device_config *) \
dev->config)->rx_sem)
/**
* UART asynchronous transfer structure.
*/
struct uart_ns16550_transfer_t {
uint8_t *data; /**< Pre-allocated write or read buffer. */
uint32_t data_len; /**< Number of bytes to transfer. */
/** Transfer callback
*
* @param[in] data Callback user data.
* @param[in] UART_PASS on success,negative value for possible
* errors.
* @param[in] status UART module status.To be interpreted with
* intel_uart_status_t for different error bits.
* @param[in] len Length of the UART transfer if successful, 0
* otherwise.
*/
void (*callback)(void *data, int error, uint32_t status, uint32_t len);
void *callback_data; /**< Callback identifier. */
};
#endif /* CONFIG_UART_ASYNC_API */
/* device config */
struct uart_ns16550_device_config {
union {
@ -226,6 +284,12 @@ struct uart_ns16550_device_config {
#if defined(CONFIG_PINCTRL)
const struct pinctrl_dev_config *pincfg;
#endif
#ifdef CONFIG_UART_ASYNC_API
struct k_sem *tx_sem;
struct k_sem *rx_sem;
#endif
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
bool io_map;
#endif
@ -251,8 +315,21 @@ struct uart_ns16550_dev_data {
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM)
bool tx_stream_on;
#endif
#ifdef CONFIG_UART_ASYNC_API
struct uart_event evt;
uart_callback_t async_cb;
void *async_user_data;
struct uart_ns16550_transfer_t *rx_transfer;
struct uart_ns16550_transfer_t *tx_transfer;
uint32_t write_pos;
uint32_t read_pos;
#endif
};
static void ns16550_outbyte(const struct uart_ns16550_device_config *cfg,
uintptr_t port, uint8_t val)
{
@ -434,7 +511,7 @@ static int uart_ns16550_configure(const struct device *dev,
}
clock_control_get_rate(dev_cfg->clock_dev, dev_cfg->clock_subsys,
&pclk);
&pclk);
}
set_baud_rate(dev, cfg->baudrate, pclk);
@ -993,6 +1070,221 @@ static void uart_ns16550_irq_callback_set(const struct device *dev,
k_spin_unlock(&dev_data->lock, key);
}
#ifdef CONFIG_UART_ASYNC_API
static bool is_async_write_complete(const struct device *dev)
{
struct uart_ns16550_dev_data * const dev_data = dev->data;
struct uart_ns16550_transfer_t *transfer = dev_data->tx_transfer;
return dev_data->write_pos >= transfer->data_len;
}
static bool is_async_read_complete(const struct device *dev)
{
struct uart_ns16550_dev_data * const dev_data = dev->data;
struct uart_ns16550_transfer_t *transfer = dev_data->rx_transfer;
return dev_data->read_pos >= transfer->data_len;
}
static void ns16550_write_transfer(const struct device *dev,
struct uart_ns16550_transfer_t *write_transfer)
{
struct uart_ns16550_dev_data * const dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
int count;
if (!write_transfer) {
return;
}
if (is_async_write_complete(dev)) {
ns16550_outbyte(dev_cfg, IER(dev),
ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE));
/*
* At this point the FIFOs are empty, but the shift
* register still is transmitting the last 8 bits.
* So if we were to read LSR, it would say the device
* is still busy.
* Use the SCR Bit 0 to indicate an irq tx is complete.
*/
ns16550_outbyte(dev_cfg, SCR(dev), ns16550_inbyte(dev_cfg, SCR(dev))
| UART_SCR_STATUS_UPDATE);
if (write_transfer->callback) {
write_transfer->callback(write_transfer->callback_data,
UART_PASS, UART_TRANSFER_SUCCESS,
dev_data->write_pos);
write_transfer->callback = NULL;
}
return;
}
/*
* If we are starting the transfer then the TX FIFO is empty.
* In that case we set 'count' variable to UART_FIFO_DEPTH
* in order to take advantage of the whole FIFO capacity.
*/
count = (dev_data->write_pos == 0)
? UART_FIFO_DEPTH
: UART_FIFO_HALF_DEPTH;
while (count-- && !is_async_write_complete(dev)) {
ns16550_outbyte(dev_cfg, THR(dev),
write_transfer->data[dev_data->write_pos++]);
}
/*
* Change the threshold level to trigger an interrupt when the
* TX buffer is empty.
*/
if (is_async_write_complete(dev)) {
ns16550_outbyte(dev_cfg, FCR(dev), ns16550_inbyte(dev_cfg, FCR(dev)) |
(ns16550_inbyte(dev_cfg, IER(dev)) | IER_TBE));
}
}
static void ns16550_read_transfer(const struct device *dev,
struct uart_ns16550_transfer_t *read_transfer)
{
struct uart_ns16550_dev_data * const dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
int lsr;
if (!read_transfer) {
return;
}
/*
* Copy data from RX FIFO to xfer buffer as long as the xfer
* has not completed and we have data in the RX FIFO.
*/
while (!is_async_read_complete(dev)) {
lsr = ns16550_inbyte(dev_cfg, LSR(dev));
/*
* A break condition may cause a line status
* interrupt to follow very closely after a
* char timeout interrupt, but reading the lsr
* effectively clears the pending interrupts so
* we issue here the callback
* instead, otherwise we would miss it.
* NOTE: Returned len is 0 for now, this might
* change in the future.
*/
if (lsr & LSR_EOB_MASK) {
ns16550_outbyte(dev_cfg, IER(dev),
ns16550_inbyte(dev_cfg, IER(dev)) &
~(IER_RXRDY | IER_LSR));
if (read_transfer->callback) {
read_transfer->callback(read_transfer
->callback_data,
UART_DRIVER_ERROR,
lsr & LSR_EOB_MASK, 0);
read_transfer->callback = NULL;
}
return;
}
if (lsr & LSR_RXRDY) {
read_transfer->data[dev_data->read_pos++] =
ns16550_inbyte(dev_cfg, THR(dev));
} else {
/* No more data in the RX FIFO. */
break;
}
}
if (is_async_read_complete(dev)) {
/*
* Disable both 'Receiver Data Available' and
* 'Receiver Line Status' interrupts.
*/
ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) &
~(IER_RXRDY | IER_LSR));
if (read_transfer->callback) {
read_transfer->callback(read_transfer->callback_data,
UART_PASS, UART_TRANSFER_SUCCESS,
dev_data->read_pos);
read_transfer->callback = NULL;
}
}
}
static void ns16550_line_status(const struct device *dev, uint32_t line_status,
struct uart_ns16550_transfer_t *read_transfer)
{
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
if (!line_status) {
return;
}
if (read_transfer) {
ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) &
~(IER_RXRDY | IER_LSR));
if (read_transfer->callback) {
/*
* Return the number of bytes read
* a zero as a line status error
* was detected.
*/
read_transfer->callback(read_transfer->callback_data,
UART_DRIVER_ERROR,
line_status, 0);
read_transfer->callback = NULL;
}
}
}
static void uart_ns16550_callback(const struct device *dev)
{
struct uart_ns16550_dev_data * const dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
struct uart_ns16550_transfer_t *write_transfer = dev_data->tx_transfer;
struct uart_ns16550_transfer_t *read_transfer = dev_data->rx_transfer;
uint8_t interrupt_id = ns16550_inbyte(dev_cfg, IIR(dev)) & IIR_MASK;
uint32_t line_status;
/*
* Interrupt ID priority levels (from highest to lowest):
* 1: IIR_LS
* 2: IIR_RBRF and IIR_CH
* 3: IIR_THRE
*/
switch (interrupt_id) {
/* Spurious interrupt */
case IIR_NIP:
break;
case IIR_LS:
line_status = ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_EOB_MASK;
ns16550_line_status(dev, line_status, read_transfer);
break;
case IIR_CH:
case IIR_RBRF:
ns16550_read_transfer(dev, read_transfer);
break;
case IIR_THRE:
ns16550_write_transfer(dev, write_transfer);
break;
default:
/* Unhandled interrupt occurred,disable uart interrupts.
* and report error.
*/
if (read_transfer && read_transfer->callback) {
ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) &
~(IER_RXRDY | IER_LSR));
read_transfer->callback(read_transfer->callback_data,
UART_DRIVER_ERROR,
UART_TRANSFER_FAILED, 0);
read_transfer->callback = NULL;
}
if (write_transfer && write_transfer->callback) {
ns16550_outbyte(dev_cfg, IER(dev),
ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE));
write_transfer->callback(write_transfer->callback_data,
UART_DRIVER_ERROR,
UART_TRANSFER_FAILED, 0);
write_transfer->callback = NULL;
}
}
}
#endif /* CONFIG_UART_ASYNC_API */
/**
* @brief Interrupt service routine.
*
@ -1006,6 +1298,10 @@ static void uart_ns16550_isr(const struct device *dev)
if (dev_data->cb) {
dev_data->cb(dev, dev_data->cb_data);
#ifdef CONFIG_UART_ASYNC_API
} else {
uart_ns16550_callback(dev);
#endif
}
#ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT
@ -1109,6 +1405,247 @@ static int uart_ns16550_drv_cmd(const struct device *dev, uint32_t cmd,
#endif /* CONFIG_UART_NS16550_DRV_CMD */
#ifdef CONFIG_UART_ASYNC_API
static uint32_t uart_ns16550_decode_line_err(uint32_t line_err)
{
uint32_t zephyr_line_err = 0;
if (line_err & LSR_OE) {
zephyr_line_err = UART_ERROR_OVERRUN;
}
if (line_err & LSR_PE) {
zephyr_line_err = UART_ERROR_PARITY;
}
if (line_err & LSR_FE) {
zephyr_line_err = UART_ERROR_FRAMING;
}
if (line_err & LSR_BI) {
zephyr_line_err = UART_BREAK;
}
return zephyr_line_err;
}
static void uart_ns16550_irq_tx_common_cb(void *data, int err, uint32_t status,
uint32_t len)
{
const struct device *dev = data;
struct uart_ns16550_dev_data *dev_data = dev->data;
if (dev_data->async_cb) {
dev_data->async_user_data = (void *)(uintptr_t)
uart_ns16550_decode_line_err(status);
dev_data->async_cb(dev, &dev_data->evt, dev_data->async_user_data);
}
k_sem_give(GET_TX_SEM(dev));
}
static void uart_ns16550_irq_rx_common_cb(void *data, int err, uint32_t status,
uint32_t len)
{
const struct device *dev = data;
struct uart_ns16550_dev_data *dev_data = dev->data;
if (dev_data->async_cb) {
dev_data->async_user_data = (void *)(uintptr_t)
uart_ns16550_decode_line_err(status);
dev_data->async_cb(dev, &dev_data->evt, dev_data->async_user_data);
}
k_sem_give(GET_RX_SEM(dev));
}
static int uart_ns16550_async_callback_set(const struct device *dev,
uart_callback_t cb,
void *user_data)
{
struct uart_ns16550_dev_data *dev_data = dev->data;
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
dev_data->async_cb = cb;
dev_data->async_user_data = user_data;
k_spin_unlock(&dev_data->lock, key);
return 0;
}
static int uart_ns16550_write_buffer_async(const struct device *dev,
const uint8_t *tx_buf,
size_t tx_buf_size, int32_t timeout)
{
struct uart_ns16550_dev_data *dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
int ret;
__ASSERT(tx_buf != NULL, "");
__ASSERT(tx_buf_size != 0, "");
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
if (k_sem_take(GET_TX_SEM(dev), K_NO_WAIT)) {
ret = -EBUSY;
goto out;
}
if (dev_data->async_cb) {
dev_data->evt.type = UART_TX_DONE;
}
dev_data->tx_transfer->data = (uint8_t *)tx_buf;
dev_data->tx_transfer->data_len = tx_buf_size;
dev_data->tx_transfer->callback = uart_ns16550_irq_tx_common_cb;
dev_data->tx_transfer->callback_data = (void *)dev;
dev_data->write_pos = 0;
/* Set threshold. */
ns16550_outbyte(dev_cfg, FCR(dev), (FCR_FIFO | FCR_FIFO_8));
/* Enable TX holding reg empty interrupt. */
ns16550_outbyte(dev_cfg, IER(dev), (ns16550_inbyte(dev_cfg, IER(dev)) | IER_TBE));
ret = 0;
out:
k_spin_unlock(&dev_data->lock, key);
return ret;
}
static int uart_ns16550_write_abort_async(const struct device *dev)
{
struct uart_ns16550_dev_data *dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
struct uart_ns16550_transfer_t *transfer = dev_data->tx_transfer;
int ret;
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
if (dev_data->async_cb) {
dev_data->evt.type = UART_TX_ABORTED;
}
/* No ongoing write transaction to be terminated. */
if (transfer == NULL) {
ret = -EIO;
goto out;
}
/* Disable TX holding reg empty interrupt. */
ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE));
if (transfer) {
if (transfer->callback) {
transfer->callback(transfer->callback_data,
UART_ERROR_CANCELED,
UART_TRANSFER_FAILED,
dev_data->write_pos);
}
dev_data->tx_transfer->callback = NULL;
dev_data->write_pos = 0;
}
ret = 0;
out:
k_spin_unlock(&dev_data->lock, key);
return ret;
}
static int uart_ns16550_read_buffer_async(const struct device *dev,
uint8_t *rx_buf,
size_t rx_buf_size,
int32_t timeout)
{
__ASSERT(rx_buf != NULL, "");
__ASSERT(rx_buf_size != 0, "");
struct uart_ns16550_dev_data *dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
int ret;
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
if (k_sem_take(GET_RX_SEM(dev), K_NO_WAIT)) {
ret = -EBUSY;
goto out;
}
if (dev_data->async_cb) {
dev_data->evt.type = UART_RX_RDY;
}
dev_data->rx_transfer->data = rx_buf;
dev_data->rx_transfer->data_len = rx_buf_size;
dev_data->rx_transfer->callback = uart_ns16550_irq_rx_common_cb;
dev_data->rx_transfer->callback_data = (void *)dev;
dev_data->read_pos = 0;
/* Set threshold. */
ns16550_outbyte(dev_cfg, FCR(dev), (FCR_FIFO | FCR_FIFO_8));
/*
* Enable both 'Receiver Data Available' and 'Receiver
* Line Status' interrupts.
*/
ns16550_outbyte(dev_cfg, IER(dev),
(ns16550_inbyte(dev_cfg, IER(dev)) | IER_RXRDY | IER_LSR));
ret = 0;
out:
k_spin_unlock(&dev_data->lock, key);
return ret;
}
static int uart_ns16550_read_disable_async(const struct device *dev)
{
struct uart_ns16550_dev_data *dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
struct uart_ns16550_transfer_t *transfer = dev_data->rx_transfer;
int ret;
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
if (dev_data->async_cb) {
dev_data->evt.type = UART_RX_DISABLED;
}
/* No ongoing read transaction to be terminated. */
if (transfer == NULL) {
ret = -EIO;
goto out;
}
/*
* Disable both 'Receiver Data Available' and 'Receiver Line Status'
* interrupts.
*/
ns16550_outbyte(dev_cfg, IER(dev),
ns16550_inbyte(dev_cfg, IER(dev)) & ~(IER_RXRDY | IER_LSR));
if (transfer) {
if (transfer->callback) {
transfer->callback(transfer->callback_data,
UART_ERROR_CANCELED,
UART_TRANSFER_FAILED,
dev_data->read_pos);
transfer->callback = NULL;
}
dev_data->read_pos = 0;
}
ret = 0;
out:
k_spin_unlock(&dev_data->lock, key);
return ret;
}
static int uart_ns16550_read_buf_rsp(const struct device *dev, uint8_t *buf,
size_t len)
{
ARG_UNUSED(dev);
ARG_UNUSED(buf);
ARG_UNUSED(len);
return -ENOTSUP;
}
#endif /* CONFIG_UART_ASYNC_API */
static const struct uart_driver_api uart_ns16550_driver_api = {
.poll_in = uart_ns16550_poll_in,
@ -1137,6 +1674,15 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
#endif
#ifdef CONFIG_UART_ASYNC_API
.callback_set = uart_ns16550_async_callback_set,
.tx = uart_ns16550_write_buffer_async,
.tx_abort = uart_ns16550_write_abort_async,
.rx_enable = uart_ns16550_read_buffer_async,
.rx_disable = uart_ns16550_read_disable_async,
.rx_buf_rsp = uart_ns16550_read_buf_rsp,
#endif
#ifdef CONFIG_UART_NS16550_LINE_CTRL
.line_ctrl_set = uart_ns16550_line_ctrl_set,
#endif
@ -1258,10 +1804,36 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
#define NS16550_BOOT_PRIO(n) \
_CONCAT(DEV_BOOT_PRIO, DT_INST_ON_BUS(n, pcie))(n)
#ifdef CONFIG_UART_ASYNC_API
#define DEV_ASYNC_DECLARE(n) \
static K_SEM_DEFINE(uart_##n##_tx_sem, 1, 1); \
static K_SEM_DEFINE(uart_##n##_rx_sem, 1, 1); \
static struct uart_ns16550_transfer_t tx_##n; \
static struct uart_ns16550_transfer_t rx_##n;
#else
#define DEV_ASYNC_DECLARE(n)
#endif
#ifdef CONFIG_UART_ASYNC_API
#define DEV_CONFIG_ASYNC_INIT(n) \
.tx_sem = &uart_##n##_tx_sem, \
.rx_sem = &uart_##n##_rx_sem,
#else
#define DEV_CONFIG_ASYNC_INIT(n)
#endif
#ifdef CONFIG_UART_ASYNC_API
#define DEV_DATA_ASYNC_INIT(n) \
.tx_transfer = &tx_##n, \
.rx_transfer = &rx_##n,
#else
#define DEV_DATA_ASYNC_INIT(n)
#endif
#define UART_NS16550_DEVICE_INIT(n) \
UART_NS16550_IRQ_FUNC_DECLARE(n); \
DEV_PCIE_DECLARE(n); \
DEV_ASYNC_DECLARE(n); \
IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \
(PINCTRL_DT_INST_DEFINE(n))); \
static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \
@ -1280,6 +1852,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
DEV_CONFIG_IRQ_FUNC_INIT(n) \
DEV_CONFIG_PCP_INIT(n) \
.reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \
DEV_CONFIG_ASYNC_INIT(n) \
DEV_CONFIG_PCIE_INIT(n) \
IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \
(.pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)),)) \
@ -1291,6 +1864,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
.uart_config.data_bits = UART_CFG_DATA_BITS_8, \
.uart_config.flow_ctrl = DEV_DATA_FLOW_CTRL(n), \
DEV_DATA_DLF_INIT(n) \
DEV_DATA_ASYNC_INIT(n) \
}; \
DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \
&uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \