|  | /* | 
|  | * Copyright (c) 2021 Telink Semiconductor | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include "analog.h" | 
|  | #include "clock.h" | 
|  |  | 
|  | #include <device.h> | 
|  | #include <drivers/uart.h> | 
|  | #include <drivers/pinmux.h> | 
|  | #include <dt-bindings/pinctrl/b91-pinctrl.h> | 
|  |  | 
|  |  | 
|  | /* Driver dts compatibility: telink,b91_uart */ | 
|  | #define DT_DRV_COMPAT telink_b91_uart | 
|  |  | 
|  | /* Get UART instance */ | 
|  | #define GET_UART(dev)      ((volatile struct uart_b91_t *) \ | 
|  | ((const struct uart_b91_config *)dev->config)->uart_addr) | 
|  |  | 
|  | /* Get UART configuration */ | 
|  | #define GET_CFG(dev)       ((const struct uart_b91_config *)dev->config) | 
|  |  | 
|  | /* Get instance data */ | 
|  | #define DEV_DATA(dev)      ((struct uart_b91_data *const)dev->data) | 
|  |  | 
|  | /* UART TX buffer count max value */ | 
|  | #define UART_TX_BUF_CNT    ((uint8_t)8u) | 
|  |  | 
|  | /* Parity type */ | 
|  | #define UART_PARITY_NONE   ((uint8_t)0u) | 
|  | #define UART_PARITY_EVEN   ((uint8_t)1u) | 
|  | #define UART_PARITY_ODD    ((uint8_t)2u) | 
|  |  | 
|  | /* Stop bits length */ | 
|  | #define UART_STOP_BIT_1    ((uint8_t)0u) | 
|  | #define UART_STOP_BIT_1P5  BIT(4) | 
|  | #define UART_STOP_BIT_2    BIT(5) | 
|  |  | 
|  |  | 
|  | /* B91 UART registers structure */ | 
|  | struct uart_b91_t { | 
|  | uint8_t data_buf[4]; | 
|  | uint16_t clk_div; | 
|  | uint8_t ctrl0; | 
|  | uint8_t ctrl1; | 
|  | uint8_t ctrl2; | 
|  | uint8_t ctrl3; | 
|  | uint16_t rxtimeout; | 
|  | uint8_t bufcnt; | 
|  | uint8_t status; | 
|  | uint8_t txrx_status; | 
|  | uint8_t state; | 
|  | }; | 
|  |  | 
|  | /* B91 UART data structure */ | 
|  | struct uart_b91_data { | 
|  | uint8_t tx_byte_index; | 
|  | uint8_t rx_byte_index; | 
|  | struct uart_config cfg; | 
|  | #ifdef CONFIG_UART_INTERRUPT_DRIVEN | 
|  | uart_irq_callback_user_data_t callback; | 
|  | void *cb_data; | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | /* B91 UART config structure */ | 
|  | struct uart_b91_config { | 
|  | const uint32_t *pinctrl_list; | 
|  | size_t pinctrl_list_size; | 
|  | uint32_t uart_addr; | 
|  | uint32_t baud_rate; | 
|  | void (*pirq_connect)(void); | 
|  | }; | 
|  |  | 
|  | /* rxtimeout register enums */ | 
|  | enum { | 
|  | UART_ERR_IRQ_MASK = BIT(15), | 
|  | }; | 
|  |  | 
|  | /* ctrl0 register enums */ | 
|  | enum { | 
|  | UART_RX_IRQ_MASK        = BIT(6), | 
|  | UART_TX_IRQ_MASK        = BIT(7), | 
|  | }; | 
|  |  | 
|  | /* ctrl3 register enums */ | 
|  | enum { | 
|  | FLD_UART_RX_IRQ_TRIQ_LEV_OFFSET = 0, | 
|  | FLD_UART_TX_IRQ_TRIQ_LEV_OFFSET = 4, | 
|  | }; | 
|  |  | 
|  | /* bufcnt register enums */ | 
|  | enum { | 
|  | FLD_UART_RX_BUF_CNT_OFFSET      = 0, | 
|  | FLD_UART_TX_BUF_CNT_OFFSET      = 4, | 
|  | }; | 
|  |  | 
|  | /* status register enums */ | 
|  | enum { | 
|  | UART_IRQ_STATUS         = BIT(3), | 
|  | UART_RX_ERR_STATUS      = BIT(7), | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* Get tx fifo count */ | 
|  | static inline uint8_t uart_b91_get_tx_bufcnt(volatile struct uart_b91_t *uart) | 
|  | { | 
|  | return (uart->bufcnt & FLD_UART_TX_BUF_CNT) >> FLD_UART_TX_BUF_CNT_OFFSET; | 
|  | } | 
|  |  | 
|  | /* Get rx fifo count */ | 
|  | static inline uint8_t uart_b91_get_rx_bufcnt(volatile struct uart_b91_t *uart) | 
|  | { | 
|  | return (uart->bufcnt & FLD_UART_RX_BUF_CNT) >> FLD_UART_RX_BUF_CNT_OFFSET; | 
|  | } | 
|  |  | 
|  | /* Check for prime */ | 
|  | static uint8_t uart_b91_is_prime(uint32_t n) | 
|  | { | 
|  | uint32_t i = 5; | 
|  |  | 
|  | if (n <= 3) { | 
|  | return 1; | 
|  | } else if ((n % 2 == 0) || (n % 3 == 0)) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | for (i = 5; i * i < n; i += 6) { | 
|  | if ((n % i == 0) || (n % (i + 2)) == 0) { | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Calculate the best bit width */ | 
|  | static void uart_b91_cal_div_and_bwpc(uint32_t baudrate, uint32_t pclk, | 
|  | uint16_t *divider, uint8_t *bwpc) | 
|  | { | 
|  | uint8_t i = 0, j = 0; | 
|  | uint32_t primeInt = 0; | 
|  | uint8_t primeDec = 0; | 
|  | uint32_t D_intdec[13], D_int[13]; | 
|  | uint8_t D_dec[13]; | 
|  |  | 
|  | primeInt = pclk / baudrate; | 
|  | primeDec = 10 * pclk / baudrate - 10 * primeInt; | 
|  |  | 
|  | if (uart_b91_is_prime(primeInt)) { | 
|  | primeInt += 1; | 
|  | } else if (primeDec > 5) { | 
|  | primeInt += 1; | 
|  | if (uart_b91_is_prime(primeInt)) { | 
|  | primeInt -= 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = 3; i <= 15; i++) { | 
|  | D_intdec[i - 3] = (10 * primeInt) / (i + 1); | 
|  | D_dec[i - 3] = D_intdec[i - 3] - 10 * (D_intdec[i - 3] / 10); | 
|  | D_int[i - 3] = D_intdec[i - 3] / 10; | 
|  | } | 
|  |  | 
|  | /* find the max and min one decimation point */ | 
|  | uint8_t position_min = 0, position_max = 0; | 
|  | uint32_t min = 0xffffffff, max = 0x00; | 
|  |  | 
|  | for (j = 0; j < 13; j++) { | 
|  | if ((D_dec[j] <= min) && (D_int[j] != 0x01)) { | 
|  | min = D_dec[j]; | 
|  | position_min = j; | 
|  | } | 
|  | if (D_dec[j] >= max) { | 
|  | max = D_dec[j]; | 
|  | position_max = j; | 
|  | } | 
|  | } | 
|  |  | 
|  | if ((D_dec[position_min] < 5) && (D_dec[position_max] >= 5)) { | 
|  | if (D_dec[position_min] < (10 - D_dec[position_max])) { | 
|  | *bwpc = position_min + 3; | 
|  | *divider = D_int[position_min] - 1; | 
|  | } else { | 
|  | *bwpc = position_max + 3; | 
|  | *divider = D_int[position_max]; | 
|  | } | 
|  | } else if ((D_dec[position_min] < 5) && (D_dec[position_max] < 5)) { | 
|  | *bwpc = position_min + 3; | 
|  | *divider = D_int[position_min] - 1; | 
|  | } else { | 
|  | *bwpc = position_max + 3; | 
|  | *divider = D_int[position_max]; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Initializes the UART instance */ | 
|  | static void uart_b91_init(volatile struct uart_b91_t *uart, uint16_t divider, | 
|  | uint8_t bwpc, uint8_t parity, uint8_t stop_bit) | 
|  | { | 
|  | /* config clock */ | 
|  | divider = divider | FLD_UART_CLK_DIV_EN; | 
|  | uart->ctrl0 = bwpc; | 
|  | uart->clk_div = divider; | 
|  |  | 
|  | /* config parity */ | 
|  | if (parity) { | 
|  | /* enable parity function */ | 
|  | uart->ctrl1 |= FLD_UART_PARITY_ENABLE; | 
|  |  | 
|  | if (parity == UART_PARITY_EVEN) { | 
|  | /* enable even parity */ | 
|  | uart->ctrl1 &= (~FLD_UART_PARITY_POLARITY); | 
|  | } else if (parity == UART_PARITY_ODD) { | 
|  | /* enable odd parity */ | 
|  | uart->ctrl1 |= FLD_UART_PARITY_POLARITY; | 
|  | } | 
|  | } else { | 
|  | uart->ctrl1 &= (~FLD_UART_PARITY_ENABLE); /* disable parity function */ | 
|  | } | 
|  |  | 
|  | /* stop bit config */ | 
|  | uart->ctrl1 &= (~FLD_UART_STOP_SEL); | 
|  | uart->ctrl1 |= stop_bit; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq handler */ | 
|  | static void uart_b91_irq_handler(const struct device *dev) | 
|  | { | 
|  | #ifndef CONFIG_UART_INTERRUPT_DRIVEN | 
|  | ARG_UNUSED(dev); | 
|  | #else | 
|  | struct uart_b91_data *data = DEV_DATA(dev); | 
|  |  | 
|  | if (data->callback != NULL) { | 
|  | data->callback(dev, data->cb_data); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* API implementation: configure */ | 
|  | static int uart_b91_configure(const struct device *dev, | 
|  | const struct uart_config *cfg) | 
|  | { | 
|  | uint16_t divider; | 
|  | uint8_t bwpc; | 
|  | uint8_t parity; | 
|  | uint8_t stop_bits; | 
|  |  | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | /* check parity */ | 
|  | if (cfg->parity == UART_CFG_PARITY_NONE) { | 
|  | parity = UART_PARITY_NONE; | 
|  | } else if (cfg->parity == UART_CFG_PARITY_ODD) { | 
|  | parity = UART_PARITY_ODD; | 
|  | } else if (cfg->parity == UART_CFG_PARITY_EVEN) { | 
|  | parity = UART_PARITY_EVEN; | 
|  | } else { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | /* check stop bits */ | 
|  | if (cfg->stop_bits == UART_CFG_STOP_BITS_1) { | 
|  | stop_bits = UART_STOP_BIT_1; | 
|  | } else if (cfg->stop_bits == UART_CFG_STOP_BITS_1_5) { | 
|  | stop_bits = UART_STOP_BIT_1P5; | 
|  | } else if (cfg->stop_bits == UART_CFG_STOP_BITS_2) { | 
|  | stop_bits = UART_STOP_BIT_2; | 
|  | } else { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | /* check flow control */ | 
|  | if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | /* UART configure */ | 
|  | uart_b91_cal_div_and_bwpc(cfg->baudrate, sys_clk.pclk * 1000 * 1000, ÷r, &bwpc); | 
|  | uart_b91_init(uart, divider, bwpc, parity, stop_bits); | 
|  |  | 
|  | /* save configuration */ | 
|  | DEV_DATA(dev)->cfg = *cfg; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: config_get */ | 
|  | static int uart_b91_config_get(const struct device *dev, | 
|  | struct uart_config *cfg) | 
|  | { | 
|  | *cfg = DEV_DATA(dev)->cfg; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: driver initialization */ | 
|  | static int uart_b91_driver_init(const struct device *dev) | 
|  | { | 
|  | uint16_t divider = 0u; | 
|  | uint8_t bwpc = 0u; | 
|  | const struct device *pinmux; | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  | const struct uart_b91_config *cfg = GET_CFG(dev); | 
|  |  | 
|  | pinmux = DEVICE_DT_GET(DT_NODELABEL(pinmux)); | 
|  | if (!device_is_ready(pinmux)) { | 
|  | return -ENODEV; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < cfg->pinctrl_list_size; i++) { | 
|  | pinmux_pin_set(pinmux, B91_PINMUX_GET_PIN(cfg->pinctrl_list[i]), | 
|  | B91_PINMUX_GET_FUNC(cfg->pinctrl_list[i])); | 
|  | } | 
|  |  | 
|  | uart_b91_cal_div_and_bwpc(cfg->baud_rate, sys_clk.pclk * 1000 * 1000, ÷r, &bwpc); | 
|  | uart_b91_init(uart, divider, bwpc, UART_PARITY_NONE, UART_STOP_BIT_1); | 
|  |  | 
|  | #ifdef CONFIG_UART_INTERRUPT_DRIVEN | 
|  | cfg->pirq_connect(); | 
|  | #endif | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: poll_out */ | 
|  | static void uart_b91_poll_out(const struct device *dev, uint8_t c) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  | struct uart_b91_data *data = DEV_DATA(dev); | 
|  |  | 
|  | while (uart_b91_get_tx_bufcnt(uart) >= UART_TX_BUF_CNT) { | 
|  | }; | 
|  |  | 
|  | uart->data_buf[data->tx_byte_index] = c; | 
|  | data->tx_byte_index = (data->tx_byte_index + 1) % ARRAY_SIZE(uart->data_buf); | 
|  | } | 
|  |  | 
|  | /* API implementation: poll_in */ | 
|  | static int uart_b91_poll_in(const struct device *dev, unsigned char *c) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  | struct uart_b91_data *data = DEV_DATA(dev); | 
|  |  | 
|  | if (uart_b91_get_rx_bufcnt(uart) == 0) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | *c = uart->data_buf[data->rx_byte_index]; | 
|  | data->rx_byte_index = (data->rx_byte_index + 1) % ARRAY_SIZE(uart->data_buf); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: err_check */ | 
|  | static int uart_b91_err_check(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | return ((uart->status & UART_RX_ERR_STATUS) != 0) ? 1 : 0; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_UART_INTERRUPT_DRIVEN | 
|  |  | 
|  | /* API implementation: fifo_fill */ | 
|  | static int uart_b91_fifo_fill(const struct device *dev, | 
|  | const uint8_t *tx_data, | 
|  | int size) | 
|  | { | 
|  | int i = 0; | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | for (i = 0; i < size; i++) { | 
|  | if (uart_b91_get_rx_bufcnt(uart) != 0) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | uart_b91_poll_out(dev, tx_data[i]); | 
|  | } | 
|  |  | 
|  | return i; | 
|  | } | 
|  |  | 
|  | /* API implementation: fifo_read */ | 
|  | static int uart_b91_fifo_read(const struct device *dev, | 
|  | uint8_t *rx_data, | 
|  | const int size) | 
|  | { | 
|  | int rx_count; | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | for (rx_count = 0; rx_count < size; rx_count++) { | 
|  | if (uart_b91_get_rx_bufcnt(uart) == 0) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | uart_b91_poll_in(dev, &rx_data[rx_count]); | 
|  | } | 
|  |  | 
|  | return rx_count; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_tx_enable */ | 
|  | static void uart_b91_irq_tx_enable(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | uart->ctrl3 = (uart->ctrl3 & (~FLD_UART_TX_IRQ_TRIQ_LEV)) | | 
|  | BIT(FLD_UART_TX_IRQ_TRIQ_LEV_OFFSET); | 
|  | uart->ctrl0 |= UART_TX_IRQ_MASK; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_tx_disable */ | 
|  | static void uart_b91_irq_tx_disable(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | uart->ctrl0 &= ~UART_TX_IRQ_MASK; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_tx_ready */ | 
|  | static int uart_b91_irq_tx_ready(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | return ((uart_b91_get_tx_bufcnt(uart) < UART_TX_BUF_CNT) && | 
|  | ((uart->ctrl0 & UART_TX_IRQ_MASK) != 0)) ? 1 : 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_tx_complete */ | 
|  | static int uart_b91_irq_tx_complete(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | return (uart_b91_get_tx_bufcnt(uart) == 0) ? 1 : 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_rx_enable */ | 
|  | static void uart_b91_irq_rx_enable(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | uart->ctrl3 = (uart->ctrl3 & (~FLD_UART_RX_IRQ_TRIQ_LEV)) | | 
|  | BIT(FLD_UART_RX_IRQ_TRIQ_LEV_OFFSET); | 
|  | uart->ctrl0 |= UART_RX_IRQ_MASK; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_rx_disable */ | 
|  | static void uart_b91_irq_rx_disable(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | uart->ctrl0 &= ~UART_RX_IRQ_MASK; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_rx_ready */ | 
|  | static int uart_b91_irq_rx_ready(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | return (uart_b91_get_rx_bufcnt(uart) > 0) ? 1 : 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_err_enable */ | 
|  | static void uart_b91_irq_err_enable(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | uart->rxtimeout |= UART_ERR_IRQ_MASK; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_err_disable*/ | 
|  | static void uart_b91_irq_err_disable(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | uart->rxtimeout &= ~UART_ERR_IRQ_MASK; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_is_pending */ | 
|  | static int uart_b91_irq_is_pending(const struct device *dev) | 
|  | { | 
|  | volatile struct uart_b91_t *uart = GET_UART(dev); | 
|  |  | 
|  | return ((uart->status & UART_IRQ_STATUS) != 0) ? 1 : 0; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_update */ | 
|  | static int uart_b91_irq_update(const struct device *dev) | 
|  | { | 
|  | ARG_UNUSED(dev); | 
|  |  | 
|  | /* nothing to be done */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* API implementation: irq_callback_set */ | 
|  | static void uart_b91_irq_callback_set(const struct device *dev, | 
|  | uart_irq_callback_user_data_t cb, | 
|  | void *cb_data) | 
|  | { | 
|  | struct uart_b91_data *data = DEV_DATA(dev); | 
|  |  | 
|  | data->callback = cb; | 
|  | data->cb_data = cb_data; | 
|  | } | 
|  |  | 
|  | #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ | 
|  |  | 
|  | static const struct uart_driver_api uart_b91_driver_api = { | 
|  | .poll_in = uart_b91_poll_in, | 
|  | .poll_out = uart_b91_poll_out, | 
|  | .err_check = uart_b91_err_check, | 
|  | .configure = uart_b91_configure, | 
|  | .config_get = uart_b91_config_get, | 
|  | #ifdef CONFIG_UART_INTERRUPT_DRIVEN | 
|  | .fifo_fill = uart_b91_fifo_fill, | 
|  | .fifo_read = uart_b91_fifo_read, | 
|  | .irq_tx_enable = uart_b91_irq_tx_enable, | 
|  | .irq_tx_disable = uart_b91_irq_tx_disable, | 
|  | .irq_tx_ready = uart_b91_irq_tx_ready, | 
|  | .irq_tx_complete = uart_b91_irq_tx_complete, | 
|  | .irq_rx_enable = uart_b91_irq_rx_enable, | 
|  | .irq_rx_disable = uart_b91_irq_rx_disable, | 
|  | .irq_rx_ready = uart_b91_irq_rx_ready, | 
|  | .irq_err_enable = uart_b91_irq_err_enable, | 
|  | .irq_err_disable = uart_b91_irq_err_disable, | 
|  | .irq_is_pending = uart_b91_irq_is_pending, | 
|  | .irq_update = uart_b91_irq_update, | 
|  | .irq_callback_set = uart_b91_irq_callback_set, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  |  | 
|  | #define UART_B91_INIT(n)							    \ | 
|  | \ | 
|  | static void uart_b91_irq_connect_##n(void);				    \ | 
|  | \ | 
|  | static const uint32_t uart_pins_##n[] =					    \ | 
|  | B91_PINMUX_DT_INST_GET_ARRAY(n, 0);				    \ | 
|  | \ | 
|  | static const struct uart_b91_config uart_b91_cfg_##n =			    \ | 
|  | {									    \ | 
|  | .uart_addr = DT_INST_REG_ADDR(n),				    \ | 
|  | .baud_rate = DT_INST_PROP(n, current_speed),			    \ | 
|  | .pinctrl_list_size = ARRAY_SIZE(uart_pins_##n),			    \ | 
|  | .pinctrl_list = uart_pins_##n,					    \ | 
|  | .pirq_connect = uart_b91_irq_connect_##n			    \ | 
|  | };									    \ | 
|  | \ | 
|  | static struct uart_b91_data uart_b91_data_##n;				    \ | 
|  | \ | 
|  | DEVICE_DT_INST_DEFINE(n, uart_b91_driver_init,				    \ | 
|  | NULL,						    \ | 
|  | &uart_b91_data_##n,				    \ | 
|  | &uart_b91_cfg_##n,				    \ | 
|  | PRE_KERNEL_1,					    \ | 
|  | CONFIG_SERIAL_INIT_PRIORITY,			    \ | 
|  | (void *)&uart_b91_driver_api);			    \ | 
|  | \ | 
|  | static void uart_b91_irq_connect_##n(void)				    \ | 
|  | {									    \ | 
|  | IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),		    \ | 
|  | uart_b91_irq_handler,				    \ | 
|  | DEVICE_DT_INST_GET(n), 0);				    \ | 
|  | \ | 
|  | riscv_plic_irq_enable(DT_INST_IRQN(n));				    \ | 
|  | riscv_plic_set_priority(DT_INST_IRQN(n), DT_INST_IRQ(n, priority)); \ | 
|  | } | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(UART_B91_INIT) |