1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2023 Nuvoton Technology Corporation.
5 */
6
7 #define DT_DRV_COMPAT nuvoton_numaker_uart
8
9 #include <string.h>
10 #include <zephyr/drivers/uart.h>
11 #include <zephyr/drivers/reset.h>
12 #include <zephyr/irq.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/drivers/clock_control.h>
15 #include <zephyr/drivers/clock_control/clock_control_numaker.h>
16 #include <zephyr/drivers/pinctrl.h>
17 #include <NuMicro.h>
18
19 LOG_MODULE_REGISTER(numaker_uart, LOG_LEVEL_ERR);
20
21 struct uart_numaker_config {
22 UART_T *uart;
23 const struct reset_dt_spec reset;
24 uint32_t clk_modidx;
25 uint32_t clk_src;
26 uint32_t clk_div;
27 const struct device *clk_dev;
28 uint32_t irq_n;
29 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
30 void (*irq_config_func)(const struct device *dev);
31 #endif
32 const struct pinctrl_dev_config *pincfg;
33 };
34
35 struct uart_numaker_data {
36 const struct device *clock;
37 struct uart_config ucfg;
38 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
39 uart_irq_callback_user_data_t user_cb;
40 void *user_data;
41 #endif
42 };
43
uart_numaker_poll_in(const struct device * dev,unsigned char * c)44 static int uart_numaker_poll_in(const struct device *dev, unsigned char *c)
45 {
46 const struct uart_numaker_config *config = dev->config;
47 uint32_t count;
48
49 count = UART_Read(config->uart, c, 1);
50 if (!count) {
51 return -1;
52 }
53
54 return 0;
55 }
56
uart_numaker_poll_out(const struct device * dev,unsigned char c)57 static void uart_numaker_poll_out(const struct device *dev, unsigned char c)
58 {
59 const struct uart_numaker_config *config = dev->config;
60
61 UART_Write(config->uart, &c, 1);
62 }
63
uart_numaker_err_check(const struct device * dev)64 static int uart_numaker_err_check(const struct device *dev)
65 {
66 const struct uart_numaker_config *config = dev->config;
67 UART_T *uart = config->uart;
68 uint32_t flags = uart->FIFOSTS;
69 int err = 0;
70
71 if (flags & UART_FIFOSTS_RXOVIF_Msk) {
72 err |= UART_ERROR_OVERRUN;
73 }
74
75 if (flags & UART_FIFOSTS_PEF_Msk) {
76 err |= UART_ERROR_PARITY;
77 }
78
79 if (flags & UART_FIFOSTS_FEF_Msk) {
80 err |= UART_ERROR_FRAMING;
81 }
82
83 if (flags & UART_FIFOSTS_BIF_Msk) {
84 err |= UART_BREAK;
85 }
86
87 if (flags & (UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk | UART_FIFOSTS_PEF_Msk |
88 UART_FIFOSTS_RXOVIF_Msk)) {
89 uart->FIFOSTS = (UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk |
90 UART_FIFOSTS_PEF_Msk | UART_FIFOSTS_RXOVIF_Msk);
91 }
92 return err;
93 }
94
uart_numaker_convert_stopbit(enum uart_config_stop_bits sb)95 static inline int32_t uart_numaker_convert_stopbit(enum uart_config_stop_bits sb)
96 {
97 switch (sb) {
98 case UART_CFG_STOP_BITS_1:
99 return UART_STOP_BIT_1;
100 case UART_CFG_STOP_BITS_1_5:
101 return UART_STOP_BIT_1_5;
102 case UART_CFG_STOP_BITS_2:
103 return UART_STOP_BIT_2;
104 default:
105 return -ENOTSUP;
106 }
107 };
108
uart_numaker_convert_datalen(enum uart_config_data_bits db)109 static inline int32_t uart_numaker_convert_datalen(enum uart_config_data_bits db)
110 {
111 switch (db) {
112 case UART_CFG_DATA_BITS_5:
113 return UART_WORD_LEN_5;
114 case UART_CFG_DATA_BITS_6:
115 return UART_WORD_LEN_6;
116 case UART_CFG_DATA_BITS_7:
117 return UART_WORD_LEN_7;
118 case UART_CFG_DATA_BITS_8:
119 return UART_WORD_LEN_8;
120 default:
121 return -ENOTSUP;
122 }
123 }
124
uart_numaker_convert_parity(enum uart_config_parity parity)125 static inline uint32_t uart_numaker_convert_parity(enum uart_config_parity parity)
126 {
127 switch (parity) {
128 case UART_CFG_PARITY_ODD:
129 return UART_PARITY_ODD;
130 case UART_CFG_PARITY_EVEN:
131 return UART_PARITY_EVEN;
132 case UART_CFG_PARITY_MARK:
133 return UART_PARITY_MARK;
134 case UART_CFG_PARITY_SPACE:
135 return UART_PARITY_SPACE;
136 case UART_CFG_PARITY_NONE:
137 default:
138 return UART_PARITY_NONE;
139 }
140 }
141
142 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
uart_numaker_configure(const struct device * dev,const struct uart_config * cfg)143 static int uart_numaker_configure(const struct device *dev, const struct uart_config *cfg)
144 {
145 const struct uart_numaker_config *config = dev->config;
146 struct uart_numaker_data *pData = dev->data;
147 int32_t databits, stopbits;
148 uint32_t parity;
149
150 databits = uart_numaker_convert_datalen(cfg->data_bits);
151 if (databits < 0) {
152 return databits;
153 }
154
155 stopbits = uart_numaker_convert_stopbit(cfg->stop_bits);
156 if (stopbits < 0) {
157 return stopbits;
158 }
159
160 if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE) {
161 UART_DisableFlowCtrl(config->uart);
162 } else if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) {
163 UART_EnableFlowCtrl(config->uart);
164 } else {
165 return -ENOTSUP;
166 }
167
168 parity = uart_numaker_convert_parity(cfg->parity);
169
170 UART_SetLineConfig(config->uart, cfg->baudrate, databits, parity, stopbits);
171
172 memcpy(&pData->ucfg, cfg, sizeof(*cfg));
173
174 return 0;
175 }
176
uart_numaker_config_get(const struct device * dev,struct uart_config * cfg)177 static int uart_numaker_config_get(const struct device *dev, struct uart_config *cfg)
178 {
179 struct uart_numaker_data *pData = dev->data;
180
181 memcpy(cfg, &pData->ucfg, sizeof(*cfg));
182
183 return 0;
184 }
185 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
186
uart_numaker_init(const struct device * dev)187 static int uart_numaker_init(const struct device *dev)
188 {
189 const struct uart_numaker_config *config = dev->config;
190 struct uart_numaker_data *pData = dev->data;
191 int err = 0;
192
193 SYS_UnlockReg();
194
195 struct numaker_scc_subsys scc_subsys;
196
197 memset(&scc_subsys, 0x00, sizeof(scc_subsys));
198 scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC;
199 scc_subsys.pcc.clk_modidx = config->clk_modidx;
200 scc_subsys.pcc.clk_src = config->clk_src;
201 scc_subsys.pcc.clk_div = config->clk_div;
202
203 /* Equivalent to CLK_EnableModuleClock(clk_modidx) */
204 err = clock_control_on(config->clk_dev, (clock_control_subsys_t)&scc_subsys);
205 if (err != 0) {
206 goto move_exit;
207 }
208 /* Equivalent to CLK_SetModuleClock(clk_modidx, clk_src, clk_div) */
209 err = clock_control_configure(config->clk_dev, (clock_control_subsys_t)&scc_subsys, NULL);
210 if (err != 0) {
211 goto move_exit;
212 }
213
214 /*
215 * Set pinctrl for UART0 RXD and TXD
216 * Set multi-function pins for UART0 RXD and TXD
217 */
218 err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
219 if (err != 0) {
220 goto move_exit;
221 }
222
223 /* Same as BSP's SYS_ResetModule(id_rst) */
224 if (!device_is_ready(config->reset.dev)) {
225 LOG_ERR("reset controller not ready");
226 return -ENODEV;
227 }
228
229 /* Reset UART to default state */
230 reset_line_toggle_dt(&config->reset);
231
232 UART_Open(config->uart, pData->ucfg.baudrate);
233
234 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
235 config->irq_config_func(dev);
236 #endif
237
238 move_exit:
239 SYS_LockReg();
240 return err;
241 }
242
243 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_numaker_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)244 static int uart_numaker_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
245 {
246 const struct uart_numaker_config *config = dev->config;
247 UART_T *uart = config->uart;
248 int tx_bytes = 0;
249
250 /* Check TX FIFO not full, then fill */
251 while (((size - tx_bytes) > 0) && (!(uart->FIFOSTS & UART_FIFOSTS_TXFULL_Msk))) {
252 /* Fill one byte into TX FIFO */
253 uart->DAT = tx_data[tx_bytes++];
254 }
255
256 return tx_bytes;
257 }
258
uart_numaker_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)259 static int uart_numaker_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
260 {
261 const struct uart_numaker_config *config = dev->config;
262 UART_T *uart = config->uart;
263 int rx_bytes = 0;
264
265 /* Check RX FIFO not empty, then read */
266 while (((size - rx_bytes) > 0) && (!(uart->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk))) {
267 /* Read one byte from UART RX FIFO */
268 rx_data[rx_bytes++] = (uint8_t)uart->DAT;
269 }
270
271 return rx_bytes;
272 }
273
uart_numaker_irq_tx_enable(const struct device * dev)274 static void uart_numaker_irq_tx_enable(const struct device *dev)
275 {
276 const struct uart_numaker_config *config = dev->config;
277 UART_T *uart = config->uart;
278
279 UART_EnableInt(uart, UART_INTEN_THREIEN_Msk);
280 }
281
uart_numaker_irq_tx_disable(const struct device * dev)282 static void uart_numaker_irq_tx_disable(const struct device *dev)
283 {
284 const struct uart_numaker_config *config = dev->config;
285 UART_T *uart = config->uart;
286
287 UART_DisableInt(uart, UART_INTEN_THREIEN_Msk);
288 }
289
uart_numaker_irq_tx_ready(const struct device * dev)290 static int uart_numaker_irq_tx_ready(const struct device *dev)
291 {
292 const struct uart_numaker_config *config = dev->config;
293 UART_T *uart = config->uart;
294
295 return ((!UART_IS_TX_FULL(uart)) && (uart->INTEN & UART_INTEN_THREIEN_Msk));
296 }
297
uart_numaker_irq_tx_complete(const struct device * dev)298 static int uart_numaker_irq_tx_complete(const struct device *dev)
299 {
300 const struct uart_numaker_config *config = dev->config;
301 UART_T *uart = config->uart;
302
303 return (uart->INTSTS & UART_INTSTS_THREINT_Msk);
304 }
305
uart_numaker_irq_rx_enable(const struct device * dev)306 static void uart_numaker_irq_rx_enable(const struct device *dev)
307 {
308 const struct uart_numaker_config *config = dev->config;
309 UART_T *uart = config->uart;
310
311 UART_EnableInt(uart, UART_INTEN_RDAIEN_Msk);
312 }
313
uart_numaker_irq_rx_disable(const struct device * dev)314 static void uart_numaker_irq_rx_disable(const struct device *dev)
315 {
316 const struct uart_numaker_config *config = dev->config;
317 UART_T *uart = config->uart;
318
319 UART_DisableInt(uart, UART_INTEN_RDAIEN_Msk);
320 }
321
uart_numaker_irq_rx_ready(const struct device * dev)322 static int uart_numaker_irq_rx_ready(const struct device *dev)
323 {
324 const struct uart_numaker_config *config = dev->config;
325 UART_T *uart = config->uart;
326
327 return ((!UART_GET_RX_EMPTY(uart)) && (uart->INTEN & UART_INTEN_RDAIEN_Msk));
328 }
329
uart_numaker_irq_err_enable(const struct device * dev)330 static void uart_numaker_irq_err_enable(const struct device *dev)
331 {
332 const struct uart_numaker_config *config = dev->config;
333 UART_T *uart = config->uart;
334
335 UART_EnableInt(uart, UART_INTEN_BUFERRIEN_Msk | UART_INTEN_SWBEIEN_Msk);
336 }
337
uart_numaker_irq_err_disable(const struct device * dev)338 static void uart_numaker_irq_err_disable(const struct device *dev)
339 {
340 const struct uart_numaker_config *config = dev->config;
341 UART_T *uart = config->uart;
342
343 UART_DisableInt(uart, UART_INTEN_BUFERRIEN_Msk | UART_INTEN_SWBEIEN_Msk);
344 }
345
uart_numaker_irq_is_pending(const struct device * dev)346 static int uart_numaker_irq_is_pending(const struct device *dev)
347 {
348
349 return (uart_numaker_irq_tx_ready(dev) || (uart_numaker_irq_rx_ready(dev)));
350 }
351
uart_numaker_irq_update(const struct device * dev)352 static int uart_numaker_irq_update(const struct device *dev)
353 {
354 ARG_UNUSED(dev);
355
356 /* nothing to be done */
357 return 1;
358 }
359
uart_numaker_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)360 static void uart_numaker_irq_callback_set(const struct device *dev,
361 uart_irq_callback_user_data_t cb, void *cb_data)
362 {
363 struct uart_numaker_data *pData = dev->data;
364
365 pData->user_cb = cb;
366 pData->user_data = cb_data;
367 }
368
uart_numaker_isr(const struct device * dev)369 static void uart_numaker_isr(const struct device *dev)
370 {
371 struct uart_numaker_data *pData = dev->data;
372
373 if (pData->user_cb) {
374 pData->user_cb(dev, pData->user_data);
375 }
376 }
377
378 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
379
380 static const struct uart_driver_api uart_numaker_driver_api = {
381 .poll_in = uart_numaker_poll_in,
382 .poll_out = uart_numaker_poll_out,
383 .err_check = uart_numaker_err_check,
384 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
385 .configure = uart_numaker_configure,
386 .config_get = uart_numaker_config_get,
387 #endif
388 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
389 .fifo_fill = uart_numaker_fifo_fill,
390 .fifo_read = uart_numaker_fifo_read,
391 .irq_tx_enable = uart_numaker_irq_tx_enable,
392 .irq_tx_disable = uart_numaker_irq_tx_disable,
393 .irq_tx_ready = uart_numaker_irq_tx_ready,
394 .irq_tx_complete = uart_numaker_irq_tx_complete,
395 .irq_rx_enable = uart_numaker_irq_rx_enable,
396 .irq_rx_disable = uart_numaker_irq_rx_disable,
397 .irq_rx_ready = uart_numaker_irq_rx_ready,
398 .irq_err_enable = uart_numaker_irq_err_enable,
399 .irq_err_disable = uart_numaker_irq_err_disable,
400 .irq_is_pending = uart_numaker_irq_is_pending,
401 .irq_update = uart_numaker_irq_update,
402 .irq_callback_set = uart_numaker_irq_callback_set,
403 #endif
404 };
405
406 #define CLOCK_CTRL_INIT(n) .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(n))),
407
408 #define PINCTRL_DEFINE(n) PINCTRL_DT_INST_DEFINE(n);
409 #define PINCTRL_INIT(n) .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),
410
411 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
412 #define NUMAKER_UART_IRQ_CONFIG_FUNC(n) \
413 static void uart_numaker_irq_config_##n(const struct device *dev) \
414 { \
415 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_numaker_isr, \
416 DEVICE_DT_INST_GET(n), 0); \
417 irq_enable(DT_INST_IRQN(n)); \
418 }
419 #define IRQ_FUNC_INIT(n) .irq_config_func = uart_numaker_irq_config_##n
420 #else
421 #define NUMAKER_UART_IRQ_CONFIG_FUNC(n)
422 #define IRQ_FUNC_INIT(n)
423 #endif
424
425 #define NUMAKER_UART_INIT(inst) \
426 PINCTRL_DEFINE(inst) \
427 NUMAKER_UART_IRQ_CONFIG_FUNC(inst) \
428 \
429 static const struct uart_numaker_config uart_numaker_cfg_##inst = { \
430 .uart = (UART_T *)DT_INST_REG_ADDR(inst), \
431 .reset = RESET_DT_SPEC_INST_GET(inst), \
432 .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \
433 .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \
434 .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \
435 CLOCK_CTRL_INIT(inst).irq_n = DT_INST_IRQN(inst), \
436 PINCTRL_INIT(inst) IRQ_FUNC_INIT(inst)}; \
437 \
438 static struct uart_numaker_data uart_numaker_data_##inst = { \
439 .ucfg = \
440 { \
441 .baudrate = DT_INST_PROP(inst, current_speed), \
442 }, \
443 }; \
444 \
445 DEVICE_DT_INST_DEFINE(inst, uart_numaker_init, NULL, &uart_numaker_data_##inst, \
446 &uart_numaker_cfg_##inst, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
447 &uart_numaker_driver_api);
448
449 DT_INST_FOREACH_STATUS_OKAY(NUMAKER_UART_INIT)
450