1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2020 Linumiz
5 * Author: Saravanan Sekar <saravanan@linumiz.com>
6 */
7
8 #include <zephyr/drivers/pinctrl.h>
9 #include <zephyr/drivers/uart.h>
10 #include <NuMicro.h>
11 #include <string.h>
12
13 #define DT_DRV_COMPAT nuvoton_numicro_uart
14
15 struct uart_numicro_config {
16 UART_T *uart;
17 uint32_t id_rst;
18 uint32_t id_clk;
19 const struct pinctrl_dev_config *pincfg;
20 };
21
22 struct uart_numicro_data {
23 const struct device *clock;
24 struct uart_config ucfg;
25 };
26
uart_numicro_poll_in(const struct device * dev,unsigned char * c)27 static int uart_numicro_poll_in(const struct device *dev, unsigned char *c)
28 {
29 const struct uart_numicro_config *config = dev->config;
30
31 if ((config->uart->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0) {
32 return -1;
33 }
34
35 *c = (uint8_t)config->uart->DAT;
36
37 return 0;
38 }
39
uart_numicro_poll_out(const struct device * dev,unsigned char c)40 static void uart_numicro_poll_out(const struct device *dev, unsigned char c)
41 {
42 const struct uart_numicro_config *config = dev->config;
43
44 UART_Write(config->uart, &c, 1);
45 }
46
uart_numicro_err_check(const struct device * dev)47 static int uart_numicro_err_check(const struct device *dev)
48 {
49 return 0;
50 }
51
uart_numicro_convert_stopbit(enum uart_config_stop_bits sb)52 static inline int32_t uart_numicro_convert_stopbit(enum uart_config_stop_bits sb)
53 {
54 switch (sb) {
55 case UART_CFG_STOP_BITS_1:
56 return UART_STOP_BIT_1;
57 case UART_CFG_STOP_BITS_1_5:
58 return UART_STOP_BIT_1_5;
59 case UART_CFG_STOP_BITS_2:
60 return UART_STOP_BIT_2;
61 default:
62 return -ENOTSUP;
63 }
64 };
65
uart_numicro_convert_datalen(enum uart_config_data_bits db)66 static inline int32_t uart_numicro_convert_datalen(enum uart_config_data_bits db)
67 {
68 switch (db) {
69 case UART_CFG_DATA_BITS_5:
70 return UART_WORD_LEN_5;
71 case UART_CFG_DATA_BITS_6:
72 return UART_WORD_LEN_6;
73 case UART_CFG_DATA_BITS_7:
74 return UART_WORD_LEN_7;
75 case UART_CFG_DATA_BITS_8:
76 return UART_WORD_LEN_8;
77 default:
78 return -ENOTSUP;
79 }
80 }
81
uart_numicro_convert_parity(enum uart_config_parity parity)82 static inline uint32_t uart_numicro_convert_parity(enum uart_config_parity parity)
83 {
84 switch (parity) {
85 case UART_CFG_PARITY_ODD:
86 return UART_PARITY_ODD;
87 case UART_CFG_PARITY_EVEN:
88 return UART_PARITY_EVEN;
89 case UART_CFG_PARITY_MARK:
90 return UART_PARITY_MARK;
91 case UART_CFG_PARITY_SPACE:
92 return UART_PARITY_SPACE;
93 case UART_CFG_PARITY_NONE:
94 default:
95 return UART_PARITY_NONE;
96 }
97 }
98
99 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
uart_numicro_configure(const struct device * dev,const struct uart_config * cfg)100 static int uart_numicro_configure(const struct device *dev,
101 const struct uart_config *cfg)
102 {
103 const struct uart_numicro_config *config = dev->config;
104 struct uart_numicro_data *ddata = dev->data;
105 int32_t databits, stopbits;
106 uint32_t parity;
107
108 databits = uart_numicro_convert_datalen(cfg->data_bits);
109 if (databits < 0) {
110 return databits;
111 }
112
113 stopbits = uart_numicro_convert_stopbit(cfg->stop_bits);
114 if (stopbits < 0) {
115 return stopbits;
116 }
117
118 if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE) {
119 UART_DisableFlowCtrl(config->uart);
120 } else if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) {
121 UART_EnableFlowCtrl(config->uart);
122 } else {
123 return -ENOTSUP;
124 }
125
126 parity = uart_numicro_convert_parity(cfg->parity);
127
128 UART_SetLineConfig(config->uart, cfg->baudrate, databits, parity,
129 stopbits);
130
131 memcpy(&ddata->ucfg, cfg, sizeof(*cfg));
132
133 return 0;
134 }
135
uart_numicro_config_get(const struct device * dev,struct uart_config * cfg)136 static int uart_numicro_config_get(const struct device *dev,
137 struct uart_config *cfg)
138 {
139 struct uart_numicro_data *ddata = dev->data;
140
141 memcpy(cfg, &ddata->ucfg, sizeof(*cfg));
142
143 return 0;
144 }
145 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
146
uart_numicro_init(const struct device * dev)147 static int uart_numicro_init(const struct device *dev)
148 {
149 const struct uart_numicro_config *config = dev->config;
150 struct uart_numicro_data *ddata = dev->data;
151 int err;
152
153 SYS_ResetModule(config->id_rst);
154
155 SYS_UnlockReg();
156
157 /* Enable UART module clock */
158 CLK_EnableModuleClock(config->id_clk);
159
160 /* Select UART0 clock source is PLL */
161 CLK_SetModuleClock(config->id_clk, CLK_CLKSEL1_UART0SEL_PLL,
162 CLK_CLKDIV0_UART0(0));
163
164 SYS_LockReg();
165
166 err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
167 if (err != 0) {
168 return err;
169 }
170
171 UART_Open(config->uart, ddata->ucfg.baudrate);
172
173 return 0;
174 }
175
176 static DEVICE_API(uart, uart_numicro_driver_api) = {
177 .poll_in = uart_numicro_poll_in,
178 .poll_out = uart_numicro_poll_out,
179 .err_check = uart_numicro_err_check,
180 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
181 .configure = uart_numicro_configure,
182 .config_get = uart_numicro_config_get,
183 #endif
184 };
185
186 #define NUMICRO_INIT(index) \
187 PINCTRL_DT_INST_DEFINE(index); \
188 \
189 static const struct uart_numicro_config uart_numicro_cfg_##index = { \
190 .uart = (UART_T *)DT_INST_REG_ADDR(index), \
191 .id_rst = UART##index##_RST, \
192 .id_clk = UART##index##_MODULE, \
193 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
194 }; \
195 \
196 static struct uart_numicro_data uart_numicro_data_##index = { \
197 .ucfg = { \
198 .baudrate = DT_INST_PROP(index, current_speed), \
199 }, \
200 }; \
201 \
202 DEVICE_DT_INST_DEFINE(index, \
203 uart_numicro_init, \
204 NULL, \
205 &uart_numicro_data_##index, \
206 &uart_numicro_cfg_##index, \
207 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
208 &uart_numicro_driver_api);
209
210 DT_INST_FOREACH_STATUS_OKAY(NUMICRO_INIT)
211