You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
4.8 KiB
205 lines
4.8 KiB
/* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
* |
|
* Copyright (c) 2020 Linumiz |
|
* Author: Saravanan Sekar <saravanan@linumiz.com> |
|
*/ |
|
|
|
#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; |
|
}; |
|
|
|
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; |
|
uint32_t count; |
|
|
|
count = UART_Read(config->uart, c, 1); |
|
if (!count) { |
|
return -1; |
|
} |
|
|
|
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; |
|
|
|
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(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) \ |
|
\ |
|
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, \ |
|
}; \ |
|
\ |
|
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)
|
|
|