ad1450510a
Refactors all of the serial drivers to use a shared driver class initialization priority configuration, CONFIG_SERIAL_INIT_PRIORITY, to allow configuring serial drivers separately from other devices. This is similar to other driver classes like I2C and SPI. The default is set to CONFIG_KERNEL_INIT_PRIORITY_DEVICE to preserve the existing default initialization priority for most drivers. The one exception is uart_lpc11u6x.c which previously used CONFIG_KERNEL_INIT_PRIORITY_OBJECTS. This change was motivated by an issue on the frdm_k64f board where the serial driver was incorrectly initialized before the clock control driver. Signed-off-by: Maureen Helm <maureen.helm@intel.com>
1013 lines
28 KiB
C
1013 lines
28 KiB
C
/*
|
|
* Copyright (c) 2020, Seagate Technology LLC
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#define DT_DRV_COMPAT nxp_lpc11u6x_uart
|
|
|
|
#include <arch/arm/aarch32/cortex_m/cmsis.h>
|
|
|
|
#include <drivers/uart.h>
|
|
#include <drivers/pinmux.h>
|
|
#include <drivers/clock_control.h>
|
|
|
|
#include "uart_lpc11u6x.h"
|
|
|
|
#define DEV_CFG(dev) ((dev)->config)
|
|
#define DEV_DATA(dev) ((dev)->data)
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart0), okay)
|
|
static int lpc11u6x_uart0_poll_in(const struct device *dev, unsigned char *c)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
if (!(cfg->uart0->lsr & LPC11U6X_UART0_LSR_RDR)) {
|
|
return -1;
|
|
}
|
|
*c = cfg->uart0->rbr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_poll_out(const struct device *dev, unsigned char c)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
while (!(cfg->uart0->lsr & LPC11U6X_UART0_LSR_THRE)) {
|
|
}
|
|
cfg->uart0->thr = c;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_err_check(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
uint32_t lsr;
|
|
int ret = 0;
|
|
|
|
lsr = cfg->uart0->lsr;
|
|
if (lsr & LPC11U6X_UART0_LSR_OE) {
|
|
ret |= UART_ERROR_OVERRUN;
|
|
}
|
|
if (lsr & LPC11U6X_UART0_LSR_PE) {
|
|
ret |= UART_ERROR_PARITY;
|
|
}
|
|
if (lsr & LPC11U6X_UART0_LSR_FE) {
|
|
ret |= UART_ERROR_FRAMING;
|
|
}
|
|
if (lsr & LPC11U6X_UART0_LSR_BI) {
|
|
ret |= UART_BREAK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_write_divisor(struct lpc11u6x_uart0_regs *uart0,
|
|
uint32_t div)
|
|
{
|
|
/* Enable access to dll & dlm registers */
|
|
uart0->lcr |= LPC11U6X_UART0_LCR_DLAB;
|
|
uart0->dll = div & 0xFF;
|
|
uart0->dlm = (div >> 8) & 0xFF;
|
|
uart0->lcr &= ~LPC11U6X_UART0_LCR_DLAB;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_write_fdr(struct lpc11u6x_uart0_regs *uart0,
|
|
uint32_t div, uint32_t mul)
|
|
{
|
|
uart0->fdr = (div & 0xF) | ((mul & 0xF) << 4);
|
|
}
|
|
|
|
static void lpc11u6x_uart0_config_baudrate(const struct device *clk_drv,
|
|
const struct lpc11u6x_uart0_config *cfg,
|
|
uint32_t baudrate)
|
|
{
|
|
uint32_t div = 1, mul, dl;
|
|
uint32_t pclk;
|
|
|
|
/* Compute values for fractional baud rate generator. We need to have
|
|
* a clock that is as close as possible to a multiple of
|
|
* LPC11U6X_UART0_CLK so that we can have every baudrate that is
|
|
* a multiple of 9600
|
|
*/
|
|
clock_control_get_rate(clk_drv, (clock_control_subsys_t) cfg->clkid,
|
|
&pclk);
|
|
mul = pclk / (pclk % LPC11U6X_UART0_CLK);
|
|
|
|
dl = pclk / (16 * baudrate + 16 * baudrate / mul);
|
|
|
|
/* Configure clock divisor and fractional baudrate generator */
|
|
lpc11u6x_uart0_write_divisor(cfg->uart0, dl);
|
|
lpc11u6x_uart0_write_fdr(cfg->uart0, div, mul);
|
|
}
|
|
|
|
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
static int lpc11u6x_uart0_configure(const struct device *dev,
|
|
const struct uart_config *cfg)
|
|
{
|
|
const struct lpc11u6x_uart0_config *dev_cfg = DEV_CFG(dev);
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
const struct device *clk_dev;
|
|
uint32_t flags = 0;
|
|
|
|
/* Check that the baudrate is a multiple of 9600 */
|
|
if (cfg->baudrate % 9600) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
switch (cfg->parity) {
|
|
case UART_CFG_PARITY_NONE:
|
|
break;
|
|
case UART_CFG_PARITY_ODD:
|
|
flags |= LPC11U6X_UART0_LCR_PARTIY_ENABLE |
|
|
LPC11U6X_UART0_LCR_PARTIY_ODD;
|
|
break;
|
|
case UART_CFG_PARITY_EVEN:
|
|
flags |= LPC11U6X_UART0_LCR_PARTIY_ENABLE |
|
|
LPC11U6X_UART0_LCR_PARTIY_EVEN;
|
|
break;
|
|
case UART_CFG_PARITY_MARK:
|
|
__fallthrough;
|
|
case UART_CFG_PARITY_SPACE:
|
|
return -ENOTSUP;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (cfg->stop_bits) {
|
|
case UART_CFG_STOP_BITS_0_5:
|
|
return -ENOTSUP;
|
|
case UART_CFG_STOP_BITS_1:
|
|
flags |= LPC11U6X_UART0_LCR_STOP_1BIT;
|
|
break;
|
|
case UART_CFG_STOP_BITS_1_5:
|
|
return -ENOTSUP;
|
|
case UART_CFG_STOP_BITS_2:
|
|
flags |= LPC11U6X_UART0_LCR_STOP_2BIT;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (cfg->data_bits) {
|
|
case UART_CFG_DATA_BITS_5:
|
|
flags |= LPC11U6X_UART0_LCR_WLS_5BITS;
|
|
break;
|
|
case UART_CFG_DATA_BITS_6:
|
|
flags |= LPC11U6X_UART0_LCR_WLS_6BITS;
|
|
break;
|
|
case UART_CFG_DATA_BITS_7:
|
|
flags |= LPC11U6X_UART0_LCR_WLS_7BITS;
|
|
break;
|
|
case UART_CFG_DATA_BITS_8:
|
|
flags |= LPC11U6X_UART0_LCR_WLS_8BITS;
|
|
break;
|
|
case UART_CFG_DATA_BITS_9:
|
|
return -ENOTSUP;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
clk_dev = device_get_binding(dev_cfg->clock_drv_name);
|
|
if (!clk_dev) {
|
|
return -EINVAL;
|
|
}
|
|
lpc11u6x_uart0_config_baudrate(clk_dev, dev_cfg, cfg->baudrate);
|
|
dev_cfg->uart0->lcr = flags;
|
|
|
|
data->baudrate = cfg->baudrate;
|
|
data->stop_bits = cfg->stop_bits;
|
|
data->data_bits = cfg->data_bits;
|
|
data->flow_ctrl = cfg->flow_ctrl;
|
|
data->parity = cfg->parity;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_config_get(const struct device *dev,
|
|
struct uart_config *cfg)
|
|
{
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
|
|
cfg->baudrate = data->baudrate;
|
|
cfg->parity = data->parity;
|
|
cfg->stop_bits = data->stop_bits;
|
|
cfg->data_bits = data->data_bits;
|
|
cfg->flow_ctrl = data->flow_ctrl;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
static int lpc11u6x_uart0_fifo_fill(const struct device *dev,
|
|
const uint8_t *data,
|
|
const int size)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
int nr_sent = 0;
|
|
|
|
while (nr_sent < size && (cfg->uart0->lsr & LPC11U6X_UART0_LSR_THRE)) {
|
|
cfg->uart0->thr = data[nr_sent++];
|
|
}
|
|
|
|
return nr_sent;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_fifo_read(const struct device *dev, uint8_t *data,
|
|
const int size)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
int nr_rx = 0;
|
|
|
|
while (nr_rx < size && (cfg->uart0->lsr & LPC11U6X_UART0_LSR_RDR)) {
|
|
data[nr_rx++] = cfg->uart0->rbr;
|
|
}
|
|
|
|
return nr_rx;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_tx_enable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->uart0->ier = (cfg->uart0->ier & LPC11U6X_UART0_IER_MASK) |
|
|
LPC11U6X_UART0_IER_THREINTEN;
|
|
|
|
/* Due to hardware limitations, first TX interrupt is not triggered when
|
|
* enabling it in the IER register. We have to trigger it.
|
|
*/
|
|
NVIC_SetPendingIRQ(DT_INST_IRQN(0));
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_tx_disable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->uart0->ier = (cfg->uart0->ier & LPC11U6X_UART0_IER_MASK) &
|
|
~LPC11U6X_UART0_IER_THREINTEN;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_irq_tx_complete(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
return (cfg->uart0->lsr & LPC11U6X_UART0_LSR_TEMT) != 0;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_irq_tx_ready(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
return (cfg->uart0->lsr & LPC11U6X_UART0_LSR_THRE) &&
|
|
(cfg->uart0->ier & LPC11U6X_UART0_IER_THREINTEN);
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_rx_enable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->uart0->ier = (cfg->uart0->ier & LPC11U6X_UART0_IER_MASK) |
|
|
LPC11U6X_UART0_IER_RBRINTEN;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_rx_disable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->uart0->ier = (cfg->uart0->ier & LPC11U6X_UART0_IER_MASK) &
|
|
~LPC11U6X_UART0_IER_RBRINTEN;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_irq_rx_ready(const struct device *dev)
|
|
{
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
|
|
return (LPC11U6X_UART0_IIR_INTID(data->cached_iir) ==
|
|
LPC11U6X_UART0_IIR_INTID_RDA) ||
|
|
(LPC11U6X_UART0_IIR_INTID(data->cached_iir) ==
|
|
LPC11U6X_UART0_IIR_INTID_CTI);
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_err_enable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->uart0->ier = (cfg->uart0->ier & LPC11U6X_UART0_IER_MASK) |
|
|
LPC11U6X_UART0_IER_RLSINTEN;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_err_disable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->uart0->ier = (cfg->uart0->ier & LPC11U6X_UART0_IER_MASK) &
|
|
~LPC11U6X_UART0_IER_RLSINTEN;
|
|
}
|
|
|
|
static int lpc11u6x_uart0_irq_is_pending(const struct device *dev)
|
|
{
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
|
|
return !(data->cached_iir & LPC11U6X_UART0_IIR_STATUS);
|
|
}
|
|
|
|
static int lpc11u6x_uart0_irq_update(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
|
|
data->cached_iir = cfg->uart0->iir;
|
|
return 1;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_irq_callback_set(const struct device *dev,
|
|
uart_irq_callback_user_data_t cb,
|
|
void *user_data)
|
|
{
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
|
|
data->cb = cb;
|
|
data->cb_data = user_data;
|
|
}
|
|
|
|
static void lpc11u6x_uart0_isr(const struct device *dev)
|
|
{
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
|
|
if (data->cb) {
|
|
data->cb(dev, data->cb_data);
|
|
}
|
|
}
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
|
|
static int lpc11u6x_uart0_init(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uart0_config *cfg = DEV_CFG(dev);
|
|
struct lpc11u6x_uart0_data *data = DEV_DATA(dev);
|
|
const struct device *clk_drv, *rx_pinmux_drv, *tx_pinmux_drv;
|
|
|
|
/* Configure RX and TX pin via the pinmux driver */
|
|
rx_pinmux_drv = device_get_binding(cfg->rx_pinmux_drv_name);
|
|
if (!rx_pinmux_drv) {
|
|
return -EINVAL;
|
|
}
|
|
pinmux_pin_set(rx_pinmux_drv, cfg->rx_pin, cfg->rx_func);
|
|
|
|
tx_pinmux_drv = device_get_binding(cfg->tx_pinmux_drv_name);
|
|
if (!tx_pinmux_drv) {
|
|
return -EINVAL;
|
|
}
|
|
pinmux_pin_set(tx_pinmux_drv, cfg->tx_pin, cfg->tx_func);
|
|
|
|
/* Call clock driver to initialize uart0 clock */
|
|
clk_drv = device_get_binding(cfg->clock_drv_name);
|
|
if (!clk_drv) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
clock_control_on(clk_drv, (clock_control_subsys_t) cfg->clkid);
|
|
|
|
/* Configure baudrate, parity and stop bits */
|
|
lpc11u6x_uart0_config_baudrate(clk_drv, cfg, cfg->baudrate);
|
|
|
|
cfg->uart0->lcr |= LPC11U6X_UART0_LCR_WLS_8BITS; /* 8N1 */
|
|
|
|
data->baudrate = cfg->baudrate;
|
|
data->parity = UART_CFG_PARITY_NONE;
|
|
data->stop_bits = UART_CFG_STOP_BITS_1;
|
|
data->data_bits = UART_CFG_DATA_BITS_8;
|
|
data->flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
|
|
|
|
/* Configure FIFO */
|
|
cfg->uart0->fcr = LPC11U6X_UART0_FCR_FIFO_EN;
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
cfg->irq_config_func(dev);
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
static void lpc11u6x_uart0_isr_config(const struct device *dev);
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
|
|
static const struct lpc11u6x_uart0_config uart0_config = {
|
|
.uart0 = (struct lpc11u6x_uart0_regs *)
|
|
DT_REG_ADDR(DT_NODELABEL(uart0)),
|
|
.clock_drv_name = DT_LABEL(DT_PHANDLE(DT_NODELABEL(uart0), clocks)),
|
|
.rx_pinmux_drv_name =
|
|
DT_LABEL(DT_PHANDLE_BY_NAME(DT_NODELABEL(uart0), pinmuxs, rxd)),
|
|
.tx_pinmux_drv_name =
|
|
DT_LABEL(DT_PHANDLE_BY_NAME(DT_NODELABEL(uart0), pinmuxs, txd)),
|
|
.clkid = DT_PHA_BY_IDX(DT_NODELABEL(uart0), clocks, 0, clkid),
|
|
.rx_pin = DT_PHA_BY_NAME(DT_NODELABEL(uart0), pinmuxs, rxd, pin),
|
|
.rx_func = DT_PHA_BY_NAME(DT_NODELABEL(uart0), pinmuxs, rxd, function),
|
|
.tx_pin = DT_PHA_BY_NAME(DT_NODELABEL(uart0), pinmuxs, txd, pin),
|
|
.tx_func = DT_PHA_BY_NAME(DT_NODELABEL(uart0), pinmuxs, txd, function),
|
|
.baudrate = DT_PROP(DT_NODELABEL(uart0), current_speed),
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
.irq_config_func = lpc11u6x_uart0_isr_config,
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
};
|
|
|
|
static const struct uart_driver_api uart0_api = {
|
|
.poll_in = lpc11u6x_uart0_poll_in,
|
|
.poll_out = lpc11u6x_uart0_poll_out,
|
|
.err_check = lpc11u6x_uart0_err_check,
|
|
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
.configure = lpc11u6x_uart0_configure,
|
|
.config_get = lpc11u6x_uart0_config_get,
|
|
#endif
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
.fifo_fill = lpc11u6x_uart0_fifo_fill,
|
|
.fifo_read = lpc11u6x_uart0_fifo_read,
|
|
.irq_tx_enable = lpc11u6x_uart0_irq_tx_enable,
|
|
.irq_tx_disable = lpc11u6x_uart0_irq_tx_disable,
|
|
.irq_tx_ready = lpc11u6x_uart0_irq_tx_ready,
|
|
.irq_tx_complete = lpc11u6x_uart0_irq_tx_complete,
|
|
.irq_rx_enable = lpc11u6x_uart0_irq_rx_enable,
|
|
.irq_rx_disable = lpc11u6x_uart0_irq_rx_disable,
|
|
.irq_rx_ready = lpc11u6x_uart0_irq_rx_ready,
|
|
.irq_err_enable = lpc11u6x_uart0_irq_err_enable,
|
|
.irq_err_disable = lpc11u6x_uart0_irq_err_disable,
|
|
.irq_is_pending = lpc11u6x_uart0_irq_is_pending,
|
|
.irq_update = lpc11u6x_uart0_irq_update,
|
|
.irq_callback_set = lpc11u6x_uart0_irq_callback_set,
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
};
|
|
|
|
static struct lpc11u6x_uart0_data uart0_data;
|
|
|
|
DEVICE_DT_DEFINE(DT_NODELABEL(uart0),
|
|
&lpc11u6x_uart0_init,
|
|
NULL,
|
|
&uart0_data, &uart0_config,
|
|
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,
|
|
&uart0_api);
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
static void lpc11u6x_uart0_isr_config(const struct device *dev)
|
|
{
|
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(uart0)),
|
|
DT_IRQ(DT_NODELABEL(uart0), priority),
|
|
lpc11u6x_uart0_isr, DEVICE_DT_GET(DT_NODELABEL(uart0)), 0);
|
|
|
|
irq_enable(DT_IRQN(DT_NODELABEL(uart0)));
|
|
}
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart0), okay) */
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay)
|
|
|
|
static int lpc11u6x_uartx_poll_in(const struct device *dev, unsigned char *c)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
if (!(cfg->base->stat & LPC11U6X_UARTX_STAT_RXRDY)) {
|
|
return -1;
|
|
}
|
|
*c = cfg->base->rx_dat;
|
|
return 0;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_poll_out(const struct device *dev, unsigned char c)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
while (!(cfg->base->stat & LPC11U6X_UARTX_STAT_TXRDY)) {
|
|
}
|
|
cfg->base->tx_dat = c;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_err_check(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
int ret = 0;
|
|
|
|
if (cfg->base->stat & LPC11U6X_UARTX_STAT_OVERRUNINT) {
|
|
ret |= UART_ERROR_OVERRUN;
|
|
}
|
|
if (cfg->base->stat & LPC11U6X_UARTX_STAT_FRAMERRINT) {
|
|
ret |= UART_ERROR_FRAMING;
|
|
}
|
|
if (cfg->base->stat & LPC11U6X_UARTX_STAT_PARITYERRINT) {
|
|
ret |= UART_ERROR_PARITY;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_config_baud(const struct lpc11u6x_uartx_config *cfg,
|
|
const struct device *clk_drv,
|
|
uint32_t baudrate)
|
|
{
|
|
uint32_t clk_rate;
|
|
uint32_t div;
|
|
|
|
clock_control_get_rate(clk_drv, (clock_control_subsys_t) cfg->clkid,
|
|
&clk_rate);
|
|
|
|
div = clk_rate / (16 * baudrate);
|
|
if (div != 0) {
|
|
div -= 1;
|
|
}
|
|
cfg->base->brg = div & LPC11U6X_UARTX_BRG_MASK;
|
|
}
|
|
|
|
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
static int lpc11u6x_uartx_configure(const struct device *dev,
|
|
const struct uart_config *cfg)
|
|
{
|
|
const struct lpc11u6x_uartx_config *dev_cfg = DEV_CFG(dev);
|
|
struct lpc11u6x_uartx_data *data = DEV_DATA(dev);
|
|
const struct device *clk_dev;
|
|
uint32_t flags = 0;
|
|
|
|
/* We only support baudrates that are multiple of 9600 */
|
|
if (cfg->baudrate % 9600) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
switch (cfg->parity) {
|
|
case UART_CFG_PARITY_NONE:
|
|
flags |= LPC11U6X_UARTX_CFG_PARITY_NONE;
|
|
break;
|
|
case UART_CFG_PARITY_ODD:
|
|
flags |= LPC11U6X_UARTX_CFG_PARITY_ODD;
|
|
break;
|
|
case UART_CFG_PARITY_EVEN:
|
|
flags |= LPC11U6X_UARTX_CFG_PARITY_EVEN;
|
|
break;
|
|
case UART_CFG_PARITY_MARK:
|
|
__fallthrough;
|
|
case UART_CFG_PARITY_SPACE:
|
|
return -ENOTSUP;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (cfg->stop_bits) {
|
|
case UART_CFG_STOP_BITS_0_5:
|
|
return -ENOTSUP;
|
|
case UART_CFG_STOP_BITS_1:
|
|
flags |= LPC11U6X_UARTX_CFG_STOP_1BIT;
|
|
break;
|
|
case UART_CFG_STOP_BITS_1_5:
|
|
return -ENOTSUP;
|
|
case UART_CFG_STOP_BITS_2:
|
|
flags |= LPC11U6X_UARTX_CFG_STOP_2BIT;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (cfg->data_bits) {
|
|
case UART_CFG_DATA_BITS_5:
|
|
__fallthrough;
|
|
case UART_CFG_DATA_BITS_6:
|
|
return -ENOTSUP;
|
|
case UART_CFG_DATA_BITS_7:
|
|
flags |= LPC11U6X_UARTX_CFG_DATALEN_7BIT;
|
|
break;
|
|
case UART_CFG_DATA_BITS_8:
|
|
flags |= LPC11U6X_UARTX_CFG_DATALEN_8BIT;
|
|
break;
|
|
case UART_CFG_DATA_BITS_9:
|
|
flags |= LPC11U6X_UARTX_CFG_DATALEN_9BIT;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
clk_dev = device_get_binding(dev_cfg->clock_drv_name);
|
|
if (!clk_dev) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Disable UART */
|
|
dev_cfg->base->cfg = 0;
|
|
|
|
/* Update baudrate */
|
|
lpc11u6x_uartx_config_baud(dev_cfg, clk_dev, cfg->baudrate);
|
|
|
|
/* Set parity, data bits, stop bits and re-enable UART interface */
|
|
dev_cfg->base->cfg = flags | LPC11U6X_UARTX_CFG_ENABLE;
|
|
|
|
data->baudrate = cfg->baudrate;
|
|
data->parity = cfg->parity;
|
|
data->stop_bits = cfg->stop_bits;
|
|
data->data_bits = cfg->data_bits;
|
|
data->flow_ctrl = cfg->flow_ctrl;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_config_get(const struct device *dev,
|
|
struct uart_config *cfg)
|
|
{
|
|
const struct lpc11u6x_uartx_data *data = DEV_DATA(dev);
|
|
|
|
cfg->baudrate = data->baudrate;
|
|
cfg->parity = data->parity;
|
|
cfg->stop_bits = data->stop_bits;
|
|
cfg->data_bits = data->data_bits;
|
|
cfg->flow_ctrl = data->flow_ctrl;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
static int lpc11u6x_uartx_fifo_fill(const struct device *dev,
|
|
const uint8_t *data,
|
|
int size)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
int tx_size = 0;
|
|
|
|
while (tx_size < size &&
|
|
(cfg->base->stat & LPC11U6X_UARTX_STAT_TXRDY)) {
|
|
cfg->base->tx_dat = data[tx_size++];
|
|
}
|
|
return tx_size;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_fifo_read(const struct device *dev, uint8_t *data,
|
|
int size)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
int rx_size = 0;
|
|
|
|
while (rx_size < size &&
|
|
(cfg->base->stat & LPC11U6X_UARTX_STAT_RXRDY)) {
|
|
data[rx_size++] = cfg->base->rx_dat;
|
|
}
|
|
return rx_size;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_tx_enable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->base->int_en_set = (cfg->base->int_en_set &
|
|
LPC11U6X_UARTX_INT_EN_SET_MASK) |
|
|
LPC11U6X_UARTX_INT_EN_SET_TXRDYEN;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_tx_disable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->base->int_en_clr = LPC11U6X_UARTX_INT_EN_CLR_TXRDYCLR;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_irq_tx_ready(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
return (cfg->base->stat & LPC11U6X_UARTX_STAT_TXRDY) &&
|
|
(cfg->base->int_en_set & LPC11U6X_UARTX_INT_EN_SET_TXRDYEN);
|
|
}
|
|
|
|
static int lpc11u6x_uartx_irq_tx_complete(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
return (cfg->base->stat & LPC11U6X_UARTX_STAT_TXIDLE) != 0;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_rx_enable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->base->int_en_set = (cfg->base->int_en_set &
|
|
LPC11U6X_UARTX_INT_EN_SET_MASK) |
|
|
LPC11U6X_UARTX_INT_EN_SET_RXRDYEN;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_rx_disable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->base->int_en_clr = LPC11U6X_UARTX_INT_EN_CLR_RXRDYCLR;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_irq_rx_ready(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
return (cfg->base->stat & LPC11U6X_UARTX_STAT_RXRDY) &&
|
|
(cfg->base->int_en_set & LPC11U6X_UARTX_INT_EN_SET_RXRDYEN);
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_err_enable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->base->int_en_set = (cfg->base->int_en_set &
|
|
LPC11U6X_UARTX_INT_EN_SET_MASK) |
|
|
(LPC11U6X_UARTX_INT_EN_SET_RXRDYEN |
|
|
LPC11U6X_UARTX_INT_EN_SET_FRAMERREN |
|
|
LPC11U6X_UARTX_INT_EN_SET_PARITYERREN);
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_err_disable(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
cfg->base->int_en_clr = LPC11U6X_UARTX_INT_EN_CLR_OVERRUNCLR |
|
|
LPC11U6X_UARTX_INT_EN_CLR_FRAMERRCLR |
|
|
LPC11U6X_UARTX_INT_EN_CLR_PARITYERRCLR;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_irq_is_pending(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
|
|
if ((cfg->base->stat & LPC11U6X_UARTX_STAT_RXRDY) &&
|
|
(cfg->base->int_stat & LPC11U6X_UARTX_INT_STAT_RXRDY)) {
|
|
return 1;
|
|
}
|
|
if ((cfg->base->stat & LPC11U6X_UARTX_STAT_TXRDY) &&
|
|
cfg->base->int_stat & LPC11U6X_UARTX_INT_STAT_TXRDY) {
|
|
return 1;
|
|
}
|
|
if (cfg->base->stat & (LPC11U6X_UARTX_STAT_OVERRUNINT |
|
|
LPC11U6X_UARTX_STAT_FRAMERRINT |
|
|
LPC11U6X_UARTX_STAT_PARITYERRINT)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int lpc11u6x_uartx_irq_update(const struct device *dev)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_irq_callback_set(const struct device *dev,
|
|
uart_irq_callback_user_data_t cb,
|
|
void *user_data)
|
|
{
|
|
struct lpc11u6x_uartx_data *data = DEV_DATA(dev);
|
|
|
|
data->cb = cb;
|
|
data->cb_data = user_data;
|
|
}
|
|
|
|
static void lpc11u6x_uartx_isr(const struct device *dev)
|
|
{
|
|
struct lpc11u6x_uartx_data *data = DEV_DATA(dev);
|
|
|
|
if (data->cb) {
|
|
data->cb(dev, data->cb_data);
|
|
}
|
|
}
|
|
|
|
static void lpc11u6x_uartx_shared_isr(const void *arg)
|
|
{
|
|
struct lpc11u6x_uartx_shared_irq *shared_irq =
|
|
(struct lpc11u6x_uartx_shared_irq *)arg;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(shared_irq->devices); i++) {
|
|
if (shared_irq->devices[i]) {
|
|
lpc11u6x_uartx_isr(shared_irq->devices[i]);
|
|
}
|
|
}
|
|
}
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
|
|
static int lpc11u6x_uartx_init(const struct device *dev)
|
|
{
|
|
const struct lpc11u6x_uartx_config *cfg = DEV_CFG(dev);
|
|
struct lpc11u6x_uartx_data *data = DEV_DATA(dev);
|
|
const struct device *clk_drv, *rx_pinmux_drv, *tx_pinmux_drv;
|
|
|
|
/* Configure RX and TX pin via the pinmux driver */
|
|
rx_pinmux_drv = device_get_binding(cfg->rx_pinmux_drv_name);
|
|
if (!rx_pinmux_drv) {
|
|
return -EINVAL;
|
|
}
|
|
pinmux_pin_set(rx_pinmux_drv, cfg->rx_pin, cfg->rx_func);
|
|
|
|
tx_pinmux_drv = device_get_binding(cfg->tx_pinmux_drv_name);
|
|
if (!tx_pinmux_drv) {
|
|
return -EINVAL;
|
|
}
|
|
pinmux_pin_set(tx_pinmux_drv, cfg->tx_pin, cfg->tx_func);
|
|
|
|
/* Call clock driver to initialize uart0 clock */
|
|
clk_drv = device_get_binding(cfg->clock_drv_name);
|
|
if (!clk_drv) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
clock_control_on(clk_drv, (clock_control_subsys_t) cfg->clkid);
|
|
|
|
/* Configure baudrate, parity and stop bits */
|
|
lpc11u6x_uartx_config_baud(cfg, clk_drv, cfg->baudrate);
|
|
cfg->base->cfg = LPC11U6X_UARTX_CFG_DATALEN_8BIT; /* 8N1 */
|
|
|
|
data->baudrate = cfg->baudrate;
|
|
data->parity = UART_CFG_PARITY_NONE;
|
|
data->stop_bits = UART_CFG_STOP_BITS_1;
|
|
data->data_bits = UART_CFG_DATA_BITS_8;
|
|
data->flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
|
|
|
|
/* Enable UART */
|
|
cfg->base->cfg = (cfg->base->cfg & LPC11U6X_UARTX_CFG_MASK) |
|
|
LPC11U6X_UARTX_CFG_ENABLE;
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay)
|
|
lpc11u6x_uartx_isr_config_1(dev);
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) ||
|
|
* DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay)
|
|
*/
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay)
|
|
lpc11u6x_uartx_isr_config_2(dev);
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) ||
|
|
* DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay)
|
|
*/
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
return 0;
|
|
}
|
|
|
|
static const struct uart_driver_api uartx_api = {
|
|
.poll_in = lpc11u6x_uartx_poll_in,
|
|
.poll_out = lpc11u6x_uartx_poll_out,
|
|
.err_check = lpc11u6x_uartx_err_check,
|
|
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
.configure = lpc11u6x_uartx_configure,
|
|
.config_get = lpc11u6x_uartx_config_get,
|
|
#endif
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
.fifo_fill = lpc11u6x_uartx_fifo_fill,
|
|
.fifo_read = lpc11u6x_uartx_fifo_read,
|
|
.irq_tx_enable = lpc11u6x_uartx_irq_tx_enable,
|
|
.irq_tx_disable = lpc11u6x_uartx_irq_tx_disable,
|
|
.irq_tx_ready = lpc11u6x_uartx_irq_tx_ready,
|
|
.irq_tx_complete = lpc11u6x_uartx_irq_tx_complete,
|
|
.irq_rx_enable = lpc11u6x_uartx_irq_rx_enable,
|
|
.irq_rx_disable = lpc11u6x_uartx_irq_rx_disable,
|
|
.irq_rx_ready = lpc11u6x_uartx_irq_rx_ready,
|
|
.irq_err_enable = lpc11u6x_uartx_irq_err_enable,
|
|
.irq_err_disable = lpc11u6x_uartx_irq_err_disable,
|
|
.irq_is_pending = lpc11u6x_uartx_irq_is_pending,
|
|
.irq_update = lpc11u6x_uartx_irq_update,
|
|
.irq_callback_set = lpc11u6x_uartx_irq_callback_set,
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
};
|
|
|
|
|
|
#define LPC11U6X_UARTX_INIT(idx) \
|
|
\
|
|
static const struct lpc11u6x_uartx_config uart_cfg_##idx = { \
|
|
.base = (struct lpc11u6x_uartx_regs *) \
|
|
DT_REG_ADDR(DT_NODELABEL(uart##idx)), \
|
|
.clock_drv_name = \
|
|
DT_LABEL(DT_PHANDLE(DT_NODELABEL(uart##idx), clocks)), \
|
|
.rx_pinmux_drv_name = \
|
|
DT_LABEL(DT_PHANDLE_BY_NAME(DT_NODELABEL(uart##idx), pinmuxs, rxd)), \
|
|
.tx_pinmux_drv_name = \
|
|
DT_LABEL(DT_PHANDLE_BY_NAME(DT_NODELABEL(uart##idx), pinmuxs, txd)), \
|
|
.clkid = DT_PHA_BY_IDX(DT_NODELABEL(uart##idx), clocks, 0, clkid), \
|
|
.rx_pin = DT_PHA_BY_NAME(DT_NODELABEL(uart##idx), pinmuxs, rxd, pin), \
|
|
.rx_func = DT_PHA_BY_NAME(DT_NODELABEL(uart##idx), \
|
|
pinmuxs, rxd, function), \
|
|
.rx_func = DT_PHA_BY_NAME(DT_NODELABEL(uart##idx), pinmuxs, \
|
|
rxd, function), \
|
|
.tx_pin = DT_PHA_BY_NAME(DT_NODELABEL(uart##idx), pinmuxs, txd, pin), \
|
|
.tx_func = DT_PHA_BY_NAME(DT_NODELABEL(uart##idx), pinmuxs, \
|
|
txd, function), \
|
|
.baudrate = DT_PROP(DT_NODELABEL(uart##idx), current_speed), \
|
|
}; \
|
|
\
|
|
static struct lpc11u6x_uartx_data uart_data_##idx; \
|
|
\
|
|
DEVICE_DT_DEFINE(DT_NODELABEL(uart##idx), \
|
|
&lpc11u6x_uartx_init, NULL, \
|
|
&uart_data_##idx, &uart_cfg_##idx, \
|
|
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
|
|
&uartx_api)
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay)
|
|
LPC11U6X_UARTX_INIT(1);
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) */
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay)
|
|
LPC11U6X_UARTX_INIT(2);
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) */
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay)
|
|
LPC11U6X_UARTX_INIT(3);
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay) */
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay)
|
|
LPC11U6X_UARTX_INIT(4);
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay) */
|
|
|
|
#if CONFIG_UART_INTERRUPT_DRIVEN && \
|
|
(DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay))
|
|
|
|
struct lpc11u6x_uartx_shared_irq lpc11u6x_uartx_shared_irq_info_1 = {
|
|
.devices = {
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay)
|
|
DEVICE_DT_GET(DT_NODELABEL(uart1)),
|
|
#else
|
|
NULL,
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) */
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay)
|
|
DEVICE_DT_GET(DT_NODELABEL(uart4)),
|
|
#else
|
|
NULL,
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay) */
|
|
},
|
|
};
|
|
|
|
static void lpc11u6x_uartx_isr_config_1(const struct device *dev)
|
|
{
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay)
|
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(uart1)),
|
|
DT_IRQ(DT_NODELABEL(uart1), priority),
|
|
lpc11u6x_uartx_shared_isr,
|
|
&lpc11u6x_uartx_shared_irq_info_1,
|
|
0);
|
|
irq_enable(DT_IRQN(DT_NODELABEL(uart1)));
|
|
#else
|
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(uart4)),
|
|
DT_IRQ(DT_NODELABEL(uart4), priority),
|
|
lpc11u6x_uartx_shared_isr,
|
|
&lpc11u6x_uartx_shared_irq_info_1,
|
|
0);
|
|
irq_enable(DT_IRQN(DT_NODELABEL(uart4)));
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) */
|
|
}
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN &&
|
|
* (DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) ||
|
|
* DT_NODE_HAS_STATUS(DT_NODELABEL(uart4), okay))
|
|
*/
|
|
|
|
#if CONFIG_UART_INTERRUPT_DRIVEN && \
|
|
(DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) || \
|
|
DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay))
|
|
struct lpc11u6x_uartx_shared_irq lpc11u6x_uartx_shared_irq_info_2 = {
|
|
.devices = {
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay)
|
|
DEVICE_DT_GET(DT_NODELABEL(uart2)),
|
|
#else
|
|
NULL,
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) */
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay)
|
|
DEVICE_DT_GET(DT_NODELABEL(uart3)),
|
|
#else
|
|
NULL,
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay) */
|
|
},
|
|
};
|
|
|
|
static void lpc11u6x_uartx_isr_config_2(const struct device *dev)
|
|
{
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay)
|
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(uart2)),
|
|
DT_IRQ(DT_NODELABEL(uart2), priority),
|
|
lpc11u6x_uartx_shared_isr,
|
|
&lpc11u6x_uartx_shared_irq_info_2,
|
|
0);
|
|
irq_enable(DT_IRQN(DT_NODELABEL(uart2)));
|
|
#else
|
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(uart3)),
|
|
DT_IRQ(DT_NODELABEL(uart3), priority),
|
|
lpc11u6x_uartx_shared_isr,
|
|
&lpc11u6x_uartx_shared_irq_info_2,
|
|
0);
|
|
irq_enable(DT_IRQN(DT_NODELABEL(uart3)));
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) */
|
|
}
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN &&
|
|
* (DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) ||
|
|
* DT_NODE_HAS_STATUS(DT_NODELABEL(uart3), okay))
|
|
*/
|
|
#endif /* DT_NODE_EXISTS(DT_NODELABEL(uart1) ||
|
|
* DT_NODE_EXISTS(DT_NODELABEL(uart2) ||
|
|
* DT_NODE_EXISTS(DT_NODELABEL(uart3) ||
|
|
* DT_NODE_EXISTS(DT_NODELABEL(uart4)
|
|
*/
|