Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | /*
* 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
#define UART_STRUCT(dev) \
((UART_T *) \
((const struct uart_numicro_config * const)(dev)->config)->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;
}
}
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
static int uart_numicro_configure(const struct device *dev,
const struct uart_config *cfg)
{
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(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 = 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(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,
#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 = { \
.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, \
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)
|