211 lines
4.9 KiB
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)
|