diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index fc8df9a3ad8650..3d36afca283371 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_ITE_IT8XXX2 uart_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_UART_LITEX uart_litex.c) zephyr_library_sources_ifdef(CONFIG_UART_LPC11U6X uart_lpc11u6x.c) zephyr_library_sources_ifdef(CONFIG_UART_MAX32 uart_max32.c) +zephyr_library_sources_ifdef(CONFIG_UART_MCHP_MEC5 uart_mchp_mec5.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX uart_mcux.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX_FLEXCOMM uart_mcux_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX_IUART uart_mcux_iuart.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index baf3f7e4121e79..4ede34ed99a8ad 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -187,6 +187,7 @@ rsource "Kconfig.mcux_flexcomm" rsource "Kconfig.mcux_iuart" rsource "Kconfig.mcux_lpsci" rsource "Kconfig.mcux_lpuart" +rsource "Kconfig.mec5" rsource "Kconfig.miv" rsource "Kconfig.msp432p4xx" rsource "Kconfig.native_posix" diff --git a/drivers/serial/Kconfig.mec5 b/drivers/serial/Kconfig.mec5 new file mode 100644 index 00000000000000..6c46bf9b9c601d --- /dev/null +++ b/drivers/serial/Kconfig.mec5 @@ -0,0 +1,27 @@ +# Microchip MEC5 UART + +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config UART_MCHP_MEC5 + bool "Microchip MEC5 family ns16550 compatible UART driver" + default y + depends on DT_HAS_MICROCHIP_MEC5_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + This option enables the UART driver for Microchip MEC5 + family processors. + +if UART_MCHP_MEC5 + +config UART_MCHP_MEC5_LINE_CTRL + bool "Serial Line Control for Apps" + depends on UART_LINE_CTRL + help + This enables the API for apps to control the serial line, + such as CTS and RTS. + + Says n if not sure. + +endif # UART_MCHP_MEC5 diff --git a/drivers/serial/uart_mchp_mec5.c b/drivers/serial/uart_mchp_mec5.c new file mode 100644 index 00000000000000..947a5c3375f73e --- /dev/null +++ b/drivers/serial/uart_mchp_mec5.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Microchip MEC5 ns16550 compatible UART Serial Driver + */ + +#define DT_DRV_COMPAT microchip_mec5_uart + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(uart_mec5, CONFIG_UART_LOG_LEVEL); + +/* MEC5 HAL */ +#include +#include +#include + +#define UART_MEC_DFLT_CLK_FREQ 1843200u +#define UART_MEC_DEVCFG_FLAG_RX_FIFO_TRIG_POS 0 +#define UART_MEC_DEVCFG_FLAG_RX_FIFO_TRIG_MSK 0x3u +#define UART_MEC_DEVCFG_FLAG_FIFO_DIS_POS 4 +#define UART_MEC_DEVCFG_FLAG_USE_EXTCLK_POS 5 + +struct uart_mec5_devcfg { + struct mec_uart_regs *regs; + const struct pinctrl_dev_config *pcfg; + uint32_t clock_freq; + uint32_t flags; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + void (*irq_config_func)(const struct device *dev); +#endif +}; + +struct uart_mec5_dev_data { + const struct device *dev; + struct uart_config current_config; + struct uart_config ucfg; + struct k_spinlock lock; + enum mec_uart_ipend ipend; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t cb; /* Callback function pointer */ + void *cb_data; /* Callback function arg */ + uint32_t flags; + uint8_t rx_enabled; + uint8_t tx_enabled; +#endif +}; + +static const uint8_t mec5_xlat_word_len[4] = { + MEC_UART_WORD_LEN_5, + MEC_UART_WORD_LEN_6, + MEC_UART_WORD_LEN_7, + MEC_UART_WORD_LEN_8, +}; + +static const uint8_t mec5_xlat_stop_bits[4] = { + MEC_UART_STOP_BITS_1, + MEC_UART_STOP_BITS_1, + MEC_UART_STOP_BITS_2, + MEC_UART_STOP_BITS_2, +}; + +static const uint8_t mec5_xlat_parity[5] = { + (uint8_t)(MEC5_UART_CFG_PARITY_NONE >> MEC5_UART_CFG_PARITY_POS), + (uint8_t)(MEC5_UART_CFG_PARITY_ODD >> MEC5_UART_CFG_PARITY_POS), + (uint8_t)(MEC5_UART_CFG_PARITY_EVEN >> MEC5_UART_CFG_PARITY_POS), + (uint8_t)(MEC5_UART_CFG_PARITY_MARK >> MEC5_UART_CFG_PARITY_POS), + (uint8_t)(MEC5_UART_CFG_PARITY_SPACE >> MEC5_UART_CFG_PARITY_POS), +}; + +static int uart_mec5_xlat_cfg(const struct uart_config *cfg, uint32_t *cfg_word) +{ + uint32_t temp; + + if (!cfg || !cfg_word) { + return -EINVAL; + } + + *cfg_word = 0u; + + if (cfg->data_bits > UART_CFG_DATA_BITS_8) { + return -EINVAL; + } + temp = mec5_xlat_word_len[cfg->data_bits]; + *cfg_word |= ((temp << MEC5_UART_CFG_WORD_LEN_POS) & MEC5_UART_CFG_WORD_LEN_MSK); + + if (cfg->stop_bits > UART_CFG_STOP_BITS_2) { + return -EINVAL; + } + temp = mec5_xlat_stop_bits[cfg->stop_bits]; + *cfg_word |= ((temp << MEC5_UART_CFG_STOP_BITS_POS) & MEC5_UART_CFG_STOP_BITS_MSK); + + if (cfg->parity > UART_CFG_PARITY_SPACE) { + return -EINVAL; + } + temp = mec5_xlat_parity[cfg->parity]; + *cfg_word |= ((temp << MEC5_UART_CFG_PARITY_POS) & MEC5_UART_CFG_PARITY_MSK); + + return 0; +} + +/* Configure UART TX and RX FIFOs based on device tree. + * Both FIFOs are fixed 16-byte. + * RX FIFO has a configurable interrupt trigger level of 1, 4, 8, or 14 bytes. + */ +static uint32_t uart_mec5_fifo_config(uint32_t mcfg, uint32_t cfg_flags) +{ + uint32_t new_mcfg = mcfg; + uint32_t temp = 0; + + if (!(cfg_flags & BIT(UART_MEC_DEVCFG_FLAG_FIFO_DIS_POS))) { + new_mcfg |= BIT(MEC5_UART_CFG_FIFO_EN_POS); + temp = (cfg_flags & UART_MEC_DEVCFG_FLAG_RX_FIFO_TRIG_MSK) >> + UART_MEC_DEVCFG_FLAG_RX_FIFO_TRIG_POS; + switch (temp) { + case 0: + new_mcfg |= MEC5_UART_CFG_RX_FIFO_TRIG_LVL_1; + break; + case 1: + new_mcfg |= MEC5_UART_CFG_RX_FIFO_TRIG_LVL_4; + break; + case 2: + new_mcfg |= MEC5_UART_CFG_RX_FIFO_TRIG_LVL_8; + break; + default: + new_mcfg |= MEC5_UART_CFG_RX_FIFO_TRIG_LVL_14; + break; + } + } + + return new_mcfg; +} + +static int config_mec5_uart(const struct device *dev, const struct uart_config *cfg) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + struct uart_mec5_dev_data *const data = dev->data; + int ret = 0; + uint32_t mcfg = 0, extclk = 0; + + data->ipend = MEC_UART_IPEND_NONE; + + ret = uart_mec5_xlat_cfg(cfg, &mcfg); + if (ret) { + return ret; + } + + mcfg = uart_mec5_fifo_config(mcfg, devcfg->flags); + mcfg |= BIT(MEC5_UART_CFG_GIRQ_EN_POS); + + if (devcfg->flags & BIT(UART_MEC_DEVCFG_FLAG_USE_EXTCLK_POS)) { + extclk = devcfg->clock_freq; + } + + ret = mec_hal_uart_init(regs, cfg->baudrate, mcfg, extclk); + if (ret != MEC_RET_OK) { + return -EIO; + } + + memcpy(&data->ucfg, cfg, sizeof(struct uart_config)); + + return ret; +}; + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +/* run-time driver configuration API */ +static int uart_mec5_configure(const struct device *dev, const struct uart_config *cfg) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct uart_mec5_dev_data *const data = dev->data; + int ret = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + LOG_ERR("MEC5 UART pinctrl error (%d)", ret); + } + + ret = config_mec5_uart(dev, cfg); + if (ret) { + LOG_ERR("MEC5 UART config error (%d)", ret); + return ret; + } + + data->current_config = *cfg; + + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int uart_mec5_config_get(const struct device *dev, struct uart_config *cfg) +{ + struct uart_mec5_dev_data *const data = dev->data; + + if (!cfg) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + *cfg = data->current_config; + + k_spin_unlock(&data->lock, key); + + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +/* Called by kernel during driver initialization phase */ +static int uart_mec5_init(const struct device *dev) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct uart_mec5_dev_data *data = dev->data; + int ret = 0; + + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + LOG_ERR("MEC5 UART init pinctrl error (%d)", ret); + return ret; + } + + ret = config_mec5_uart(dev, &data->ucfg); + if (ret != 0) { + return -EIO; + } + + return ret; +} + +/* + * Poll the UART for input. + * return 0 is a byte arrived else -1 if no data. + */ +static int uart_mec5_poll_in(const struct device *dev, unsigned char *cptr) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + ret = mec_hal_uart_rx_byte(regs, (uint8_t *)cptr); + if (ret == MEC_RET_ERR_NO_DATA) { + k_spin_unlock(&data->lock, key); + return -1; + } + + k_spin_unlock(&data->lock, key); + + return 0; +} + +/* Block until UART can accept data byte. */ +static void uart_mec5_poll_out(const struct device *dev, unsigned char out_data) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + do { + ret = mec_hal_uart_tx_byte(regs, (uint8_t)out_data); + } while (ret == MEC_RET_ERR_BUSY); + + k_spin_unlock(&data->lock, key); +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static inline void irq_tx_enable(const struct device *dev) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + mec_hal_uart_intr_mask(regs, MEC_UART_IEN_FLAG_ETHREI, MEC_UART_IEN_FLAG_ETHREI); + + k_spin_unlock(&data->lock, key); +} + +static inline void irq_tx_disable(const struct device *dev) +{ + const struct uart_mec5_devcfg *devcfg = dev->config; + struct uart_mec5_dev_data *data = dev->data; + struct mec_uart_regs *const regs = devcfg->regs; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + mec_hal_uart_intr_mask(regs, MEC_UART_IEN_FLAG_ETHREI, 0); + + k_spin_unlock(&data->lock, key); +} + +static inline void irq_rx_enable(const struct device *dev) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct uart_mec5_dev_data *data = dev->data; + struct mec_uart_regs *const regs = devcfg->regs; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + mec_hal_uart_intr_mask(regs, MEC_UART_IEN_FLAG_ERDAI, MEC_UART_IEN_FLAG_ERDAI); + + k_spin_unlock(&data->lock, key); +} + +static inline void irq_rx_disable(const struct device *dev) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct uart_mec5_dev_data *data = dev->data; + struct mec_uart_regs *const regs = devcfg->regs; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + mec_hal_uart_intr_mask(regs, MEC_UART_IEN_FLAG_ERDAI, 0); + + k_spin_unlock(&data->lock, key); +} + +static int uart_mec5_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct uart_mec5_dev_data *data = dev->data; + struct mec_uart_regs *const regs = devcfg->regs; + int num_tx = 0, ret = 0; + + if (len < 0) { + return 0; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + while (num_tx < len) { + ret = mec_hal_uart_tx_byte(regs, tx_data[num_tx]); + if (ret == MEC_RET_ERR_BUSY) { + break; + } + num_tx++; + } + + if (data->tx_enabled) { + irq_tx_enable(dev); + } + + k_spin_unlock(&data->lock, key); + + return num_tx; +} + +static int uart_mec5_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct uart_mec5_dev_data *data = dev->data; + struct mec_uart_regs *const regs = devcfg->regs; + int num_rx = 0, ret = 0; + + if (size < 0) { + return 0; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + uint8_t *pdata = rx_data; + + while (num_rx < size) { + ret = mec_hal_uart_rx_byte(regs, pdata); + if (ret != MEC_RET_OK) { + break; + } + pdata++; + num_rx++; + } + + if (data->rx_enabled) { + irq_rx_enable(dev); + } + + k_spin_unlock(&data->lock, key); + + return num_rx; +} + +static void uart_mec5_irq_tx_enable(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->tx_enabled = 1; + irq_tx_enable(dev); + + k_spin_unlock(&data->lock, key); +} + +static void uart_mec5_irq_tx_disable(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_tx_disable(dev); + data->tx_enabled = 0; + + k_spin_unlock(&data->lock, key); +} + +static int uart_mec5_irq_tx_ready(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (data->ipend == MEC_UART_IPEND_TX) { + ret = 1; + } + + k_spin_unlock(&data->lock, key); + + return ret; +} + +static void uart_mec5_irq_rx_enable(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->rx_enabled = 1; + irq_rx_enable(dev); + + k_spin_unlock(&data->lock, key); +} + +static void uart_mec5_irq_rx_disable(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_rx_disable(dev); + data->rx_enabled = 0; + + k_spin_unlock(&data->lock, key); +} + +/* check if UART TX shift register is empty. Empty TX shift register indicates + * the UART does not need clocks and can be put into a low power state. + * return 1 nothing remains to be transmitted, 0 otherwise. + */ +static int uart_mec5_irq_tx_complete(const struct device *dev) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = mec_hal_uart_is_tx_empty(regs); + + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int uart_mec5_irq_rx_ready(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + int ret = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (data->ipend == MEC_UART_IPEND_RX_DATA) { + ret = 1; + } + + k_spin_unlock(&data->lock, key); + + return ret; +} + +static void irq_error_enable(const struct device *dev, uint8_t enable) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + uint8_t msk = 0; + + if (enable) { + msk = MEC_UART_IEN_FLAG_ELSI; + } + + mec_hal_uart_intr_mask(regs, MEC_UART_IEN_FLAG_ELSI, msk); +} + +/* + * Enable received line status interrupt active when one or more of the following errors + * occur: overrun, parity, framing, or break. + */ +static void uart_mec5_irq_err_enable(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_error_enable(dev, 1u); + + k_spin_unlock(&data->lock, key); +} + +static void uart_mec5_irq_err_disable(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_error_enable(dev, 0); + + k_spin_unlock(&data->lock, key); +} + +static int uart_mec5_irq_is_pending(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (data->ipend != MEC_UART_IPEND_NONE) { + ret = 1; + } + + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int uart_mec5_irq_update(const struct device *dev) +{ + const struct uart_mec5_devcfg *const devcfg = dev->config; + struct mec_uart_regs *const regs = devcfg->regs; + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->ipend = MEC_UART_IPEND_NONE; + mec_hal_uart_pending_status(regs, &data->ipend); + + switch (data->ipend) { + case MEC_UART_IPEND_NONE: + break; + case MEC_UART_IPEND_TX: + irq_tx_disable(dev); + break; + case MEC_UART_IPEND_RX_DATA: + irq_rx_disable(dev); + break; + case MEC_UART_IPEND_RX_ERR: + irq_error_enable(dev, 0); + break; + case MEC_UART_IPEND_MODEM: + __fallthrough; /* fall through */ + default: + k_panic(); + break; + } + + k_spin_unlock(&data->lock, key); + + return 1; +} + +static void uart_mec5_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct uart_mec5_dev_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->cb = cb; + data->cb_data = cb_data; + + k_spin_unlock(&data->lock, key); +} + +static void uart_mec5_isr(const struct device *dev) +{ + struct uart_mec5_dev_data *data = dev->data; + + if (data->cb) { + data->cb(dev, data->cb_data); + } +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api uart_mec5_driver_api = { + .poll_in = uart_mec5_poll_in, + .poll_out = uart_mec5_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_mec5_configure, + .config_get = uart_mec5_config_get, +#endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_mec5_fifo_fill, + .fifo_read = uart_mec5_fifo_read, + .irq_tx_enable = uart_mec5_irq_tx_enable, + .irq_tx_disable = uart_mec5_irq_tx_disable, + .irq_tx_ready = uart_mec5_irq_tx_ready, + .irq_rx_enable = uart_mec5_irq_rx_enable, + .irq_rx_disable = uart_mec5_irq_rx_disable, + .irq_tx_complete = uart_mec5_irq_tx_complete, + .irq_rx_ready = uart_mec5_irq_rx_ready, + .irq_err_enable = uart_mec5_irq_err_enable, + .irq_err_disable = uart_mec5_irq_err_disable, + .irq_is_pending = uart_mec5_irq_is_pending, + .irq_update = uart_mec5_irq_update, + .irq_callback_set = uart_mec5_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define UART_MEC5_CONFIGURE(n) \ + do { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_mec5_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } while (0) +#else +#define UART_MEC5_CONFIGURE(n) +#endif + +#define UART_MEC5_DCFG_FLAGS(i) \ + ((DT_INST_ENUM_IDX_OR(i, rx_fifo_trig, 2) & 0x3u) | \ + ((DT_INST_PROP_OR(i, fifo_mode_disable, 0) & 0x1u) << 4) | \ + ((DT_INST_PROP_OR(i, use_extclk, 0) & 0x1u) << 5)) + +#define DEV_DATA_FLOW_CTRL(n) DT_INST_PROP_OR(n, hw_flow_control, UART_CFG_FLOW_CTRL_NONE) + +#define UART_MEC5_DEVICE(i) \ + PINCTRL_DT_INST_DEFINE(i); \ + static const struct uart_mec5_devcfg uart_mec5_##i##_devcfg = { \ + .regs = (struct mec_uart_regs *)DT_INST_REG_ADDR(i), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \ + .clock_freq = DT_INST_PROP_OR(i, clock_frequency, UART_MEC_DFLT_CLK_FREQ), \ + .flags = UART_MEC5_DCFG_FLAGS(i), \ + }; \ + static struct uart_mec5_dev_data uart_mec5_##i##_dev_data = { \ + .ucfg.baudrate = DT_INST_PROP_OR(i, current_speed, 0), \ + .ucfg.parity = UART_CFG_PARITY_NONE, \ + .ucfg.stop_bits = UART_CFG_STOP_BITS_1, \ + .ucfg.data_bits = UART_CFG_DATA_BITS_8, \ + .ucfg.flow_ctrl = DEV_DATA_FLOW_CTRL(i), \ + }; \ + static int uart_mec5_##i##_init(const struct device *dev) \ + { \ + UART_MEC5_CONFIGURE(i); \ + return uart_mec5_init(dev); \ + } \ + DEVICE_DT_INST_DEFINE(i, uart_mec5_##i##_init, NULL, &uart_mec5_##i##_dev_data, \ + &uart_mec5_##i##_devcfg, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_mec5_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(UART_MEC5_DEVICE) diff --git a/dts/bindings/serial/microchip,mec5-uart.yaml b/dts/bindings/serial/microchip,mec5-uart.yaml new file mode 100644 index 00000000000000..d37c196d046bc8 --- /dev/null +++ b/dts/bindings/serial/microchip,mec5-uart.yaml @@ -0,0 +1,55 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Microchip MEC5 UART + +compatible: "microchip,mec5-uart" + +include: [uart-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + fifo-mode-disable: + type: boolean + description: | + Disable 16550 FIFO mode. Both 16-byte TX and RX FIFOs will be + disabled. UART will revert to a one byte holding register for + TX and RX. + + rx-fifo-trig: + type: string + default: "8" + description: | + RX FIFO byte count trigger limit. When the number of received bytes + reaches this level the UART will signal an interrupt if enabled. + enum: + - "1" + - "4" + - "8" + - "14" + + use-extclk: + type: boolean + description: | + Optional source of an external UART clock. If present the + driver will use this pin as the UART input clock source. + The pin should have a 1.8432 MHz clock waveform for normal + UART BAUD rates or 48 MHz for high speed BAUD rates. + Refer to data sheet for the pin(s) available as external UART + clock input. The pin should be added to the default PINCTRL list. + Example using external 1.8432MHz clock on MEC5 external UART clock pin. + + clock-frequency = <1843200>; + pinctrl-0 = < &uart1_tx_gpio170 &uart1_tx_gpio171 &uart_clk_gpio025>; + pinctrl-names = "default";