210 lines
4.8 KiB
C
210 lines
4.8 KiB
C
/*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Copyright (c) 2020 Linumiz
|
|
* Author: Saravanan Sekar <saravanan@linumiz.com>
|
|
*/
|
|
|
|
#include <drivers/uart.h>
|
|
#include <NuMicro.h>
|
|
#include <string.h>
|
|
|
|
#define DT_DRV_COMPAT nuvoton_numicro_uart
|
|
|
|
/* Device data structure */
|
|
#define DEV_CFG(dev) \
|
|
((const struct uart_numicro_config * const)(dev)->config)
|
|
|
|
#define DRV_DATA(dev) \
|
|
((struct uart_numicro_data * const)(dev)->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 {
|
|
const struct device *clock;
|
|
struct uart_config ucfg;
|
|
};
|
|
|
|
static int uart_numicro_poll_in(const 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(const struct device *dev, unsigned char c)
|
|
{
|
|
UART_Write(UART_STRUCT(dev), &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;
|
|
}
|
|
}
|
|
|
|
static int uart_numicro_configure(const 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(const 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(const 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_DT_INST_DEFINE(index, \
|
|
&uart_numicro_init, \
|
|
device_pm_control_nop, \
|
|
&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)
|