1 /*
2 * Copyright (c) 2024, Yishai Jaffe
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT silabs_eusart_uart
8
9 #include <errno.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/drivers/clock_control/clock_control_silabs.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/drivers/uart.h>
14 #include <zephyr/irq.h>
15 #include <zephyr/pm/device.h>
16 #include <em_eusart.h>
17
18 struct uart_silabs_eusart_config {
19 EUSART_TypeDef *eusart;
20 const struct pinctrl_dev_config *pcfg;
21 const struct device *clock_dev;
22 const struct silabs_clock_control_cmu_config clock_cfg;
23 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
24 void (*irq_config_func)(const struct device *dev);
25 #endif
26 };
27
28 struct uart_silabs_eusart_data {
29 struct uart_config uart_cfg;
30 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
31 uart_irq_callback_user_data_t callback;
32 void *cb_data;
33 #endif
34 };
35
uart_silabs_eusart_poll_in(const struct device * dev,unsigned char * c)36 static int uart_silabs_eusart_poll_in(const struct device *dev, unsigned char *c)
37 {
38 const struct uart_silabs_eusart_config *config = dev->config;
39
40 if (EUSART_StatusGet(config->eusart) & EUSART_STATUS_RXFL) {
41 *c = EUSART_Rx(config->eusart);
42 return 0;
43 }
44
45 return -1;
46 }
47
uart_silabs_eusart_poll_out(const struct device * dev,unsigned char c)48 static void uart_silabs_eusart_poll_out(const struct device *dev, unsigned char c)
49 {
50 const struct uart_silabs_eusart_config *config = dev->config;
51
52 /* EUSART_Tx function already waits for the transmit buffer being empty
53 * and waits for the bus to be free to transmit.
54 */
55 EUSART_Tx(config->eusart, c);
56 }
57
uart_silabs_eusart_err_check(const struct device * dev)58 static int uart_silabs_eusart_err_check(const struct device *dev)
59 {
60 const struct uart_silabs_eusart_config *config = dev->config;
61 uint32_t flags = EUSART_IntGet(config->eusart);
62 int err = 0;
63
64 if (flags & EUSART_IF_RXOF) {
65 err |= UART_ERROR_OVERRUN;
66 }
67
68 if (flags & EUSART_IF_PERR) {
69 err |= UART_ERROR_PARITY;
70 }
71
72 if (flags & EUSART_IF_FERR) {
73 err |= UART_ERROR_FRAMING;
74 }
75
76 EUSART_IntClear(config->eusart, EUSART_IF_RXOF | EUSART_IF_PERR | EUSART_IF_FERR);
77
78 return err;
79 }
80
81 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_silabs_eusart_fifo_fill(const struct device * dev,const uint8_t * tx_data,int len)82 static int uart_silabs_eusart_fifo_fill(const struct device *dev,
83 const uint8_t *tx_data,
84 int len)
85 {
86 const struct uart_silabs_eusart_config *config = dev->config;
87 int num_tx = 0;
88
89 while ((len - num_tx > 0) &&
90 (EUSART_StatusGet(config->eusart) & EUSART_STATUS_TXFL)) {
91
92 config->eusart->TXDATA = (uint32_t)tx_data[num_tx++];
93 }
94
95 if (!(EUSART_StatusGet(config->eusart) & EUSART_STATUS_TXFL)) {
96 EUSART_IntClear(config->eusart, EUSART_IF_TXFL);
97 }
98
99 return num_tx;
100 }
101
uart_silabs_eusart_fifo_read(const struct device * dev,uint8_t * rx_data,const int len)102 static int uart_silabs_eusart_fifo_read(const struct device *dev, uint8_t *rx_data,
103 const int len)
104 {
105 const struct uart_silabs_eusart_config *config = dev->config;
106 int num_rx = 0;
107
108 while ((len - num_rx > 0) &&
109 (EUSART_StatusGet(config->eusart) & EUSART_STATUS_RXFL)) {
110 rx_data[num_rx++] = (uint8_t)config->eusart->RXDATA;
111 }
112
113 if (!(EUSART_StatusGet(config->eusart) & EUSART_STATUS_RXFL)) {
114 EUSART_IntClear(config->eusart, EUSART_IF_RXFL);
115 }
116
117 return num_rx;
118 }
119
uart_silabs_eusart_irq_tx_enable(const struct device * dev)120 static void uart_silabs_eusart_irq_tx_enable(const struct device *dev)
121 {
122 const struct uart_silabs_eusart_config *config = dev->config;
123
124 EUSART_IntClear(config->eusart, EUSART_IEN_TXFL | EUSART_IEN_TXC);
125 EUSART_IntEnable(config->eusart, EUSART_IEN_TXFL | EUSART_IEN_TXC);
126 }
127
uart_silabs_eusart_irq_tx_disable(const struct device * dev)128 static void uart_silabs_eusart_irq_tx_disable(const struct device *dev)
129 {
130 const struct uart_silabs_eusart_config *config = dev->config;
131
132 EUSART_IntDisable(config->eusart, EUSART_IEN_TXFL | EUSART_IEN_TXC);
133 EUSART_IntClear(config->eusart, EUSART_IEN_TXFL | EUSART_IEN_TXC);
134 }
135
uart_silabs_eusart_irq_tx_complete(const struct device * dev)136 static int uart_silabs_eusart_irq_tx_complete(const struct device *dev)
137 {
138 const struct uart_silabs_eusart_config *config = dev->config;
139 uint32_t flags = EUSART_IntGet(config->eusart);
140
141 EUSART_IntClear(config->eusart, EUSART_IF_TXC);
142
143 return (flags & EUSART_IF_TXC) != 0;
144 }
145
uart_silabs_eusart_irq_tx_ready(const struct device * dev)146 static int uart_silabs_eusart_irq_tx_ready(const struct device *dev)
147 {
148 const struct uart_silabs_eusart_config *config = dev->config;
149
150 return (config->eusart->IEN & EUSART_IEN_TXFL)
151 && (EUSART_IntGet(config->eusart) & EUSART_IF_TXFL);
152 }
153
uart_silabs_eusart_irq_rx_enable(const struct device * dev)154 static void uart_silabs_eusart_irq_rx_enable(const struct device *dev)
155 {
156 const struct uart_silabs_eusart_config *config = dev->config;
157
158 EUSART_IntClear(config->eusart, EUSART_IEN_RXFL);
159 EUSART_IntEnable(config->eusart, EUSART_IEN_RXFL);
160 }
161
uart_silabs_eusart_irq_rx_disable(const struct device * dev)162 static void uart_silabs_eusart_irq_rx_disable(const struct device *dev)
163 {
164 const struct uart_silabs_eusart_config *config = dev->config;
165
166 EUSART_IntDisable(config->eusart, EUSART_IEN_RXFL);
167 EUSART_IntClear(config->eusart, EUSART_IEN_RXFL);
168 }
169
uart_silabs_eusart_irq_rx_ready(const struct device * dev)170 static int uart_silabs_eusart_irq_rx_ready(const struct device *dev)
171 {
172 const struct uart_silabs_eusart_config *config = dev->config;
173
174 return (config->eusart->IEN & EUSART_IEN_RXFL)
175 && (EUSART_IntGet(config->eusart) & EUSART_IF_RXFL);
176 }
177
uart_silabs_eusart_irq_err_enable(const struct device * dev)178 static void uart_silabs_eusart_irq_err_enable(const struct device *dev)
179 {
180 const struct uart_silabs_eusart_config *config = dev->config;
181
182 EUSART_IntClear(config->eusart, EUSART_IF_RXOF | EUSART_IF_PERR | EUSART_IF_FERR);
183 EUSART_IntEnable(config->eusart, EUSART_IF_RXOF | EUSART_IF_PERR | EUSART_IF_FERR);
184 }
185
uart_silabs_eusart_irq_err_disable(const struct device * dev)186 static void uart_silabs_eusart_irq_err_disable(const struct device *dev)
187 {
188 const struct uart_silabs_eusart_config *config = dev->config;
189
190 EUSART_IntDisable(config->eusart, EUSART_IF_RXOF | EUSART_IF_PERR | EUSART_IF_FERR);
191 EUSART_IntClear(config->eusart, EUSART_IF_RXOF | EUSART_IF_PERR | EUSART_IF_FERR);
192 }
193
uart_silabs_eusart_irq_is_pending(const struct device * dev)194 static int uart_silabs_eusart_irq_is_pending(const struct device *dev)
195 {
196 return uart_silabs_eusart_irq_tx_ready(dev) || uart_silabs_eusart_irq_rx_ready(dev);
197 }
198
uart_silabs_eusart_irq_update(const struct device * dev)199 static int uart_silabs_eusart_irq_update(const struct device *dev)
200 {
201 return 1;
202 }
203
uart_silabs_eusart_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)204 static void uart_silabs_eusart_irq_callback_set(const struct device *dev,
205 uart_irq_callback_user_data_t cb,
206 void *cb_data)
207 {
208 struct uart_silabs_eusart_data *data = dev->data;
209
210 data->callback = cb;
211 data->cb_data = cb_data;
212 }
213
uart_silabs_eusart_isr(const struct device * dev)214 static void uart_silabs_eusart_isr(const struct device *dev)
215 {
216 struct uart_silabs_eusart_data *data = dev->data;
217
218 if (data->callback) {
219 data->callback(dev, data->cb_data);
220 }
221 }
222 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
223
uart_silabs_eusart_cfg2ll_parity(enum uart_config_parity parity)224 static inline EUSART_Parity_TypeDef uart_silabs_eusart_cfg2ll_parity(
225 enum uart_config_parity parity)
226 {
227 switch (parity) {
228 case UART_CFG_PARITY_ODD:
229 return eusartOddParity;
230 case UART_CFG_PARITY_EVEN:
231 return eusartEvenParity;
232 case UART_CFG_PARITY_NONE:
233 default:
234 return eusartNoParity;
235 }
236 }
237
uart_silabs_eusart_ll2cfg_parity(EUSART_Parity_TypeDef parity)238 static inline enum uart_config_parity uart_silabs_eusart_ll2cfg_parity(
239 EUSART_Parity_TypeDef parity)
240 {
241 switch (parity) {
242 case eusartOddParity:
243 return UART_CFG_PARITY_ODD;
244 case eusartEvenParity:
245 return UART_CFG_PARITY_EVEN;
246 case eusartNoParity:
247 default:
248 return UART_CFG_PARITY_NONE;
249 }
250 }
251
uart_silabs_eusart_cfg2ll_stopbits(enum uart_config_stop_bits sb)252 static inline EUSART_Stopbits_TypeDef uart_silabs_eusart_cfg2ll_stopbits(
253 enum uart_config_stop_bits sb)
254 {
255 switch (sb) {
256 case UART_CFG_STOP_BITS_0_5:
257 return eusartStopbits0p5;
258 case UART_CFG_STOP_BITS_1:
259 return eusartStopbits1;
260 case UART_CFG_STOP_BITS_2:
261 return eusartStopbits2;
262 case UART_CFG_STOP_BITS_1_5:
263 return eusartStopbits1p5;
264 default:
265 return eusartStopbits1;
266 }
267 }
268
uart_silabs_eusart_ll2cfg_stopbits(EUSART_Stopbits_TypeDef sb)269 static inline enum uart_config_stop_bits uart_silabs_eusart_ll2cfg_stopbits(
270 EUSART_Stopbits_TypeDef sb)
271 {
272 switch (sb) {
273 case eusartStopbits0p5:
274 return UART_CFG_STOP_BITS_0_5;
275 case eusartStopbits1:
276 return UART_CFG_STOP_BITS_1;
277 case eusartStopbits1p5:
278 return UART_CFG_STOP_BITS_1_5;
279 case eusartStopbits2:
280 return UART_CFG_STOP_BITS_2;
281 default:
282 return UART_CFG_STOP_BITS_1;
283 }
284 }
285
uart_silabs_eusart_cfg2ll_databits(enum uart_config_data_bits db,enum uart_config_parity p)286 static inline EUSART_Databits_TypeDef uart_silabs_eusart_cfg2ll_databits(
287 enum uart_config_data_bits db, enum uart_config_parity p)
288 {
289 switch (db) {
290 case UART_CFG_DATA_BITS_7:
291 if (p == UART_CFG_PARITY_NONE) {
292 return eusartDataBits7;
293 } else {
294 return eusartDataBits8;
295 }
296 case UART_CFG_DATA_BITS_9:
297 return eusartDataBits9;
298 case UART_CFG_DATA_BITS_8:
299 default:
300 if (p == UART_CFG_PARITY_NONE) {
301 return eusartDataBits8;
302 } else {
303 return eusartDataBits9;
304 }
305 return eusartDataBits8;
306 }
307 }
308
uart_silabs_eusart_ll2cfg_databits(EUSART_Databits_TypeDef db,EUSART_Parity_TypeDef p)309 static inline enum uart_config_data_bits uart_silabs_eusart_ll2cfg_databits(
310 EUSART_Databits_TypeDef db, EUSART_Parity_TypeDef p)
311 {
312 switch (db) {
313 case eusartDataBits7:
314 if (p == eusartNoParity) {
315 return UART_CFG_DATA_BITS_7;
316 } else {
317 return UART_CFG_DATA_BITS_6;
318 }
319 case eusartDataBits9:
320 if (p == eusartNoParity) {
321 return UART_CFG_DATA_BITS_9;
322 } else {
323 return UART_CFG_DATA_BITS_8;
324 }
325 case eusartDataBits8:
326 default:
327 if (p == eusartNoParity) {
328 return UART_CFG_DATA_BITS_8;
329 } else {
330 return UART_CFG_DATA_BITS_7;
331 }
332 }
333 }
334
335 /**
336 * @brief Get LL hardware flow control define from
337 * Zephyr hardware flow control option.
338 * @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS and UART_CFG_FLOW_CTRL_RS485.
339 * @param fc: Zephyr hardware flow control option.
340 * @retval eusartHwFlowControlCtsAndRts, or eusartHwFlowControlNone.
341 */
uart_silabs_eusart_cfg2ll_hwctrl(enum uart_config_flow_control fc)342 static inline EUSART_HwFlowControl_TypeDef uart_silabs_eusart_cfg2ll_hwctrl(
343 enum uart_config_flow_control fc)
344 {
345 if (fc == UART_CFG_FLOW_CTRL_RTS_CTS) {
346 return eusartHwFlowControlCtsAndRts;
347 }
348
349 return eusartHwFlowControlNone;
350 }
351
352 /**
353 * @brief Get Zephyr hardware flow control option from
354 * LL hardware flow control define.
355 * @note Supports only eusartHwFlowControlCtsAndRts.
356 * @param fc: LL hardware flow control definition.
357 * @retval UART_CFG_FLOW_CTRL_RTS_CTS, or UART_CFG_FLOW_CTRL_NONE.
358 */
uart_silabs_eusart_ll2cfg_hwctrl(EUSART_HwFlowControl_TypeDef fc)359 static inline enum uart_config_flow_control uart_silabs_eusart_ll2cfg_hwctrl(
360 EUSART_HwFlowControl_TypeDef fc)
361 {
362 if (fc == eusartHwFlowControlCtsAndRts) {
363 return UART_CFG_FLOW_CTRL_RTS_CTS;
364 }
365
366 return UART_CFG_FLOW_CTRL_NONE;
367 }
368
369 /**
370 * @brief Main initializer for UART
371 *
372 * @param dev UART device to be initialized
373 * @return int 0
374 */
uart_silabs_eusart_init(const struct device * dev)375 static int uart_silabs_eusart_init(const struct device *dev)
376 {
377 int err;
378 const struct uart_silabs_eusart_config *config = dev->config;
379 struct uart_silabs_eusart_data *data = dev->data;
380 struct uart_config *uart_cfg = &data->uart_cfg;
381
382 EUSART_UartInit_TypeDef eusartInit = EUSART_UART_INIT_DEFAULT_HF;
383 EUSART_AdvancedInit_TypeDef advancedSettings = EUSART_ADVANCED_INIT_DEFAULT;
384
385 /* The peripheral and gpio clock are already enabled from soc and gpio
386 * driver
387 */
388 /* Enable EUSART clock */
389 err = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->clock_cfg);
390 if (err < 0) {
391 return err;
392 }
393
394 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
395 if (err < 0) {
396 return err;
397 }
398
399 /* Init EUSART */
400 eusartInit.baudrate = uart_cfg->baudrate;
401 eusartInit.parity = uart_silabs_eusart_cfg2ll_parity(uart_cfg->parity);
402 eusartInit.stopbits = uart_silabs_eusart_cfg2ll_stopbits(uart_cfg->stop_bits);
403 eusartInit.databits = uart_silabs_eusart_cfg2ll_databits(uart_cfg->data_bits,
404 uart_cfg->parity);
405 advancedSettings.hwFlowControl = uart_silabs_eusart_cfg2ll_hwctrl(uart_cfg->flow_ctrl);
406 eusartInit.advancedSettings = &advancedSettings;
407
408 EUSART_UartInitHf(config->eusart, &eusartInit);
409
410 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
411 config->irq_config_func(dev);
412 #endif
413
414 return 0;
415 }
416
417 #ifdef CONFIG_PM_DEVICE
uart_silabs_eusart_pm_action(const struct device * dev,enum pm_device_action action)418 static int uart_silabs_eusart_pm_action(const struct device *dev, enum pm_device_action action)
419 {
420 __maybe_unused const struct uart_silabs_eusart_config *config = dev->config;
421
422 switch (action) {
423 case PM_DEVICE_ACTION_SUSPEND:
424 #ifdef EUSART_STATUS_TXIDLE
425 /* Wait for TX FIFO to flush before suspending */
426 while (!(EUSART_StatusGet(config->eusart) & EUSART_STATUS_TXIDLE)) {
427 }
428 #endif
429 break;
430
431 case PM_DEVICE_ACTION_RESUME:
432 break;
433
434 default:
435 return -ENOTSUP;
436 }
437
438 return 0;
439 }
440 #endif
441
442 static DEVICE_API(uart, uart_silabs_eusart_driver_api) = {
443 .poll_in = uart_silabs_eusart_poll_in,
444 .poll_out = uart_silabs_eusart_poll_out,
445 .err_check = uart_silabs_eusart_err_check,
446 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
447 .fifo_fill = uart_silabs_eusart_fifo_fill,
448 .fifo_read = uart_silabs_eusart_fifo_read,
449 .irq_tx_enable = uart_silabs_eusart_irq_tx_enable,
450 .irq_tx_disable = uart_silabs_eusart_irq_tx_disable,
451 .irq_tx_complete = uart_silabs_eusart_irq_tx_complete,
452 .irq_tx_ready = uart_silabs_eusart_irq_tx_ready,
453 .irq_rx_enable = uart_silabs_eusart_irq_rx_enable,
454 .irq_rx_disable = uart_silabs_eusart_irq_rx_disable,
455 .irq_rx_ready = uart_silabs_eusart_irq_rx_ready,
456 .irq_err_enable = uart_silabs_eusart_irq_err_enable,
457 .irq_err_disable = uart_silabs_eusart_irq_err_disable,
458 .irq_is_pending = uart_silabs_eusart_irq_is_pending,
459 .irq_update = uart_silabs_eusart_irq_update,
460 .irq_callback_set = uart_silabs_eusart_irq_callback_set,
461 #endif
462 };
463
464 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
465 #define UART_IRQ_HANDLER_FUNC(idx) \
466 .irq_config_func = uart_silabs_eusart_config_func_##idx,
467 #define UART_IRQ_HANDLER(idx) \
468 static void uart_silabs_eusart_config_func_##idx(const struct device *dev) \
469 { \
470 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, rx, irq), \
471 DT_INST_IRQ_BY_NAME(idx, rx, priority), \
472 uart_silabs_eusart_isr, DEVICE_DT_INST_GET(idx), 0); \
473 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, tx, irq), \
474 DT_INST_IRQ_BY_NAME(idx, tx, priority), \
475 uart_silabs_eusart_isr, DEVICE_DT_INST_GET(idx), 0); \
476 \
477 irq_enable(DT_INST_IRQ_BY_NAME(idx, rx, irq)); \
478 irq_enable(DT_INST_IRQ_BY_NAME(idx, tx, irq)); \
479 }
480 #else
481 #define UART_IRQ_HANDLER_FUNC(idx)
482 #define UART_IRQ_HANDLER(idx)
483 #endif
484
485 #define UART_INIT(idx) \
486 UART_IRQ_HANDLER(idx) \
487 \
488 PINCTRL_DT_INST_DEFINE(idx); \
489 \
490 static const struct uart_silabs_eusart_config uart_silabs_eusart_cfg_##idx = { \
491 .eusart = (EUSART_TypeDef *)DT_INST_REG_ADDR(idx), \
492 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
493 .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \
494 .clock_cfg = SILABS_DT_INST_CLOCK_CFG(idx), \
495 UART_IRQ_HANDLER_FUNC(idx) \
496 }; \
497 \
498 static struct uart_silabs_eusart_data uart_silabs_eusart_data_##idx = { \
499 .uart_cfg = { \
500 .baudrate = DT_INST_PROP(idx, current_speed), \
501 .parity = DT_INST_ENUM_IDX(idx, parity), \
502 .stop_bits = DT_INST_ENUM_IDX(idx, stop_bits), \
503 .data_bits = DT_INST_ENUM_IDX(idx, data_bits), \
504 .flow_ctrl = DT_INST_PROP(idx, hw_flow_control) \
505 ? UART_CFG_FLOW_CTRL_RTS_CTS \
506 : UART_CFG_FLOW_CTRL_NONE, \
507 }, \
508 }; \
509 \
510 PM_DEVICE_DT_INST_DEFINE(idx, uart_silabs_eusart_pm_action); \
511 \
512 DEVICE_DT_INST_DEFINE(idx, uart_silabs_eusart_init, PM_DEVICE_DT_INST_GET(idx), \
513 &uart_silabs_eusart_data_##idx, \
514 &uart_silabs_eusart_cfg_##idx, PRE_KERNEL_1, \
515 CONFIG_SERIAL_INIT_PRIORITY, \
516 &uart_silabs_eusart_driver_api);
517
518 DT_INST_FOREACH_STATUS_OKAY(UART_INIT)
519