zephyr/drivers/serial/uart_numicro.c

211 lines
4.9 KiB
C

/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Linumiz
* Author: Saravanan Sekar <saravanan@linumiz.com>
*/
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/uart.h>
#include <NuMicro.h>
#include <string.h>
#define DT_DRV_COMPAT nuvoton_numicro_uart
struct uart_numicro_config {
UART_T *uart;
uint32_t id_rst;
uint32_t id_clk;
const struct pinctrl_dev_config *pincfg;
};
struct uart_numicro_data {
const struct device *clock;
struct uart_config ucfg;
};
static int uart_numicro_poll_in(const struct device *dev, unsigned char *c)
{
const struct uart_numicro_config *config = dev->config;
if ((config->uart->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0) {
return -1;
}
*c = (uint8_t)config->uart->DAT;
return 0;
}
static void uart_numicro_poll_out(const struct device *dev, unsigned char c)
{
const struct uart_numicro_config *config = dev->config;
UART_Write(config->uart, &c, 1);
}
static int uart_numicro_err_check(const 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;
}
}
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
static int uart_numicro_configure(const struct device *dev,
const struct uart_config *cfg)
{
const struct uart_numicro_config *config = dev->config;
struct uart_numicro_data *ddata = dev->data;
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(config->uart);
} else if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) {
UART_EnableFlowCtrl(config->uart);
} else {
return -ENOTSUP;
}
parity = uart_numicro_convert_parity(cfg->parity);
UART_SetLineConfig(config->uart, cfg->baudrate, databits, parity,
stopbits);
memcpy(&ddata->ucfg, cfg, sizeof(*cfg));
return 0;
}
static int uart_numicro_config_get(const struct device *dev,
struct uart_config *cfg)
{
struct uart_numicro_data *ddata = dev->data;
memcpy(cfg, &ddata->ucfg, sizeof(*cfg));
return 0;
}
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
static int uart_numicro_init(const struct device *dev)
{
const struct uart_numicro_config *config = dev->config;
struct uart_numicro_data *ddata = dev->data;
int err;
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));
SYS_LockReg();
err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
if (err != 0) {
return err;
}
UART_Open(config->uart, 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,
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
.configure = uart_numicro_configure,
.config_get = uart_numicro_config_get,
#endif
};
#define NUMICRO_INIT(index) \
PINCTRL_DT_INST_DEFINE(index); \
\
static const struct uart_numicro_config uart_numicro_cfg_##index = { \
.uart = (UART_T *)DT_INST_REG_ADDR(index), \
.id_rst = UART##index##_RST, \
.id_clk = UART##index##_MODULE, \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
}; \
\
static struct uart_numicro_data uart_numicro_data_##index = { \
.ucfg = { \
.baudrate = DT_INST_PROP(index, current_speed), \
}, \
}; \
\
DEVICE_DT_INST_DEFINE(index, \
uart_numicro_init, \
NULL, \
&uart_numicro_data_##index, \
&uart_numicro_cfg_##index, \
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
&uart_numicro_driver_api);
DT_INST_FOREACH_STATUS_OKAY(NUMICRO_INIT)