diff --git a/CODEOWNERS b/CODEOWNERS index 3f92ec9229..e4b59b61fa 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -218,6 +218,7 @@ /drivers/serial/Kconfig.xlnx @wjliang /drivers/serial/uart_xlnx_ps.c @wjliang /drivers/serial/*xmc4xxx* @parthitce +/drivers/serial/*nuvoton* @ssekar15 /drivers/net/ @jukkar @tbursztyka /drivers/ptp_clock/ @jukkar /drivers/pwm/*rv32m1* @henrikbrixandersen diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 69e1b04bcb..7d59acf31b 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -19,6 +19,7 @@ zephyr_library_sources_if_kconfig(uart_msp432p4xx.c) zephyr_library_sources_ifdef(CONFIG_NRF_UART_PERIPHERAL uart_nrfx_uart.c) zephyr_library_sources_ifdef(CONFIG_NRF_UARTE_PERIPHERAL uart_nrfx_uarte.c) zephyr_library_sources_if_kconfig(uart_nsim.c) +zephyr_library_sources_if_kconfig(uart_nuvoton.c) zephyr_library_sources_if_kconfig(uart_sam.c) zephyr_library_sources_if_kconfig(usart_sam.c) zephyr_library_sources_if_kconfig(uart_stellaris.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 7b9fe57ffd..918a24c905 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -110,6 +110,8 @@ source "drivers/serial/Kconfig.leuart_gecko" source "drivers/serial/Kconfig.msp432p4xx" +source "drivers/serial/Kconfig.nuvoton" + source "drivers/serial/Kconfig.sam0" source "drivers/serial/Kconfig.psoc6" diff --git a/drivers/serial/Kconfig.nuvoton b/drivers/serial/Kconfig.nuvoton new file mode 100644 index 0000000000..655695c36e --- /dev/null +++ b/drivers/serial/Kconfig.nuvoton @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# NUVOTON UART configuration +# +# Copyright (c) 2020 Linumiz +# Author: Saravanan Sekar + +config UART_NUVOTON + bool "NUVOTON MCU serial driver" + select SERIAL_HAS_DRIVER + select HAS_NUMICRO_UART + depends on SOC_FAMILY_NUMICRO + help + This option enables the UART driver for Nuvoton Numicro + family of processors. + Say y to use serial port on Nuvoton MCU. diff --git a/drivers/serial/uart_nuvoton.c b/drivers/serial/uart_nuvoton.c new file mode 100644 index 0000000000..7cc57ee3b6 --- /dev/null +++ b/drivers/serial/uart_nuvoton.c @@ -0,0 +1,207 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2020 Linumiz + * Author: Saravanan Sekar + */ + +#include +#include +#include + +#define DT_DRV_COMPAT nuvoton_numicro_uart + +/* Device data structure */ +#define DEV_CFG(dev) \ + ((const struct uart_numicro_config * const)(dev)->config_info) + +#define DRV_DATA(dev) \ + ((struct uart_numicro_data * const)(dev)->driver_data) + +#define UART_STRUCT(dev) \ + ((UART_T *)(DEV_CFG(dev))->devcfg.base) + +struct uart_numicro_config { + struct uart_device_config devcfg; + uint32_t id_rst; + uint32_t id_clk; +}; + +struct uart_numicro_data { + struct device *clock; + struct uart_config ucfg; +}; + +static int uart_numicro_poll_in(struct device *dev, unsigned char *c) +{ + uint32_t count; + + count = UART_Read(UART_STRUCT(dev), c, 1); + if (!count) { + return -1; + } + + return 0; +} + +static void uart_numicro_poll_out(struct device *dev, unsigned char c) +{ + UART_Write(UART_STRUCT(dev), &c, 1); +} + +static int uart_numicro_err_check(struct device *dev) +{ + return 0; +} + +static inline int32_t uart_numicro_convert_stopbit(enum uart_config_stop_bits sb) +{ + switch (sb) { + case UART_CFG_STOP_BITS_1: + return UART_STOP_BIT_1; + case UART_CFG_STOP_BITS_1_5: + return UART_STOP_BIT_1_5; + case UART_CFG_STOP_BITS_2: + return UART_STOP_BIT_2; + default: + return -ENOTSUP; + } +}; + +static inline int32_t uart_numicro_convert_datalen(enum uart_config_data_bits db) +{ + switch (db) { + case UART_CFG_DATA_BITS_5: + return UART_WORD_LEN_5; + case UART_CFG_DATA_BITS_6: + return UART_WORD_LEN_6; + case UART_CFG_DATA_BITS_7: + return UART_WORD_LEN_7; + case UART_CFG_DATA_BITS_8: + return UART_WORD_LEN_8; + default: + return -ENOTSUP; + } +} + +static inline uint32_t uart_numicro_convert_parity(enum uart_config_parity parity) +{ + switch (parity) { + case UART_CFG_PARITY_ODD: + return UART_PARITY_ODD; + case UART_CFG_PARITY_EVEN: + return UART_PARITY_EVEN; + case UART_CFG_PARITY_MARK: + return UART_PARITY_MARK; + case UART_CFG_PARITY_SPACE: + return UART_PARITY_SPACE; + case UART_CFG_PARITY_NONE: + default: + return UART_PARITY_NONE; + } +} + +static int uart_numicro_configure(struct device *dev, + const struct uart_config *cfg) +{ + struct uart_numicro_data *ddata = DRV_DATA(dev); + int32_t databits, stopbits; + uint32_t parity; + + databits = uart_numicro_convert_datalen(cfg->data_bits); + if (databits < 0) { + return databits; + } + + stopbits = uart_numicro_convert_stopbit(cfg->stop_bits); + if (stopbits < 0) { + return stopbits; + } + + if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE) { + UART_DisableFlowCtrl(UART_STRUCT(dev)); + } else if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) { + UART_EnableFlowCtrl(UART_STRUCT(dev)); + } else { + return -ENOTSUP; + } + + parity = uart_numicro_convert_parity(cfg->parity); + + UART_SetLineConfig(UART_STRUCT(dev), cfg->baudrate, databits, + parity, stopbits); + + memcpy(&ddata->ucfg, cfg, sizeof(*cfg)); + + return 0; +} + +static int uart_numicro_config_get(struct device *dev, struct uart_config *cfg) +{ + struct uart_numicro_data *ddata = DRV_DATA(dev); + + memcpy(cfg, &ddata->ucfg, sizeof(*cfg)); + + return 0; +} + +static int uart_numicro_init(struct device *dev) +{ + const struct uart_numicro_config *config = DEV_CFG(dev); + struct uart_numicro_data *ddata = DRV_DATA(dev); + + SYS_ResetModule(config->id_rst); + + SYS_UnlockReg(); + + /* Enable UART module clock */ + CLK_EnableModuleClock(config->id_clk); + + /* Select UART0 clock source is PLL */ + CLK_SetModuleClock(config->id_clk, CLK_CLKSEL1_UART0SEL_PLL, + CLK_CLKDIV0_UART0(0)); + + /* Set pinctrl for UART0 RXD and TXD */ + SYS->GPB_MFPH &= ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk); + SYS->GPB_MFPH |= (SYS_GPB_MFPH_PB12MFP_UART0_RXD | + SYS_GPB_MFPH_PB13MFP_UART0_TXD); + + SYS_LockReg(); + + UART_Open(UART_STRUCT(dev), ddata->ucfg.baudrate); + + return 0; +} + +static const struct uart_driver_api uart_numicro_driver_api = { + .poll_in = uart_numicro_poll_in, + .poll_out = uart_numicro_poll_out, + .err_check = uart_numicro_err_check, + .configure = uart_numicro_configure, + .config_get = uart_numicro_config_get, +}; + +#define NUMICRO_INIT(index) \ + \ +static const struct uart_numicro_config uart_numicro_cfg_##index = { \ + .devcfg = { \ + .base = (uint8_t *)DT_INST_REG_ADDR(index), \ + }, \ + .id_rst = UART##index##_RST, \ + .id_clk = UART##index##_MODULE, \ +}; \ + \ +static struct uart_numicro_data uart_numicro_data_##index = { \ + .ucfg = { \ + .baudrate = DT_INST_PROP(index, current_speed), \ + }, \ +}; \ + \ +DEVICE_AND_API_INIT(uart_numicro_##index, DT_INST_LABEL(index), \ + &uart_numicro_init, \ + &uart_numicro_data_##index, \ + &uart_numicro_cfg_##index, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_numicro_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NUMICRO_INIT) diff --git a/dts/bindings/serial/nuvoton,numicro-uart.yaml b/dts/bindings/serial/nuvoton,numicro-uart.yaml new file mode 100644 index 0000000000..7592206029 --- /dev/null +++ b/dts/bindings/serial/nuvoton,numicro-uart.yaml @@ -0,0 +1,9 @@ +description: NUVOTON NUMICRO FAMILY UART + +compatible: "nuvoton,numicro-uart" + +include: uart-controller.yaml + +properties: + reg: + required: true