1 /*
2 * Copyright (c) 2023 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/uart.h>
10 #include <zephyr/pm/device.h>
11 #include "sedi_driver_uart.h"
12
13 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
14 static void uart_sedi_isr(void *arg);
15 static void uart_sedi_cb(struct device *port);
16 #endif
17
18 #define DT_DRV_COMPAT intel_sedi_uart
19
20 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
21 /* UART IRQ handler declaration. */
22 #define UART_IRQ_HANDLER_DECL(n) \
23 static void irq_config_uart_##n(const struct device *dev)
24
25 /* Setting configuration function. */
26 #define UART_CONFIG_IRQ_HANDLER_SET(n) \
27 .uart_irq_config_func = irq_config_uart_##n
28 #define UART_IRQ_HANDLER_DEFINE(n) \
29 static void irq_config_uart_##n(const struct device *dev) \
30 { \
31 ARG_UNUSED(dev); \
32 IRQ_CONNECT(DT_INST_IRQN(n), \
33 DT_INST_IRQ(n, priority), uart_sedi_isr, \
34 DEVICE_DT_GET(DT_NODELABEL(uart##n)), \
35 DT_INST_IRQ(n, sense)); \
36 irq_enable(DT_INST_IRQN(n)); \
37 }
38 #else /*CONFIG_UART_INTERRUPT_DRIVEN */
39 #define UART_IRQ_HANDLER_DECL(n)
40 #define UART_CONFIG_IRQ_HANDLER_SET(n) (0)
41
42 #define UART_IRQ_HANDLER_DEFINE(n)
43 #endif /* !CONFIG_UART_INTERRUPT_DRIVEN */
44
45 /* Device init macro for UART instance. As multiple uart instances follow a
46 * similar definition of data structures differing only in the instance
47 * number.This macro makes adding instances simpler.
48 */
49 #define UART_SEDI_DEVICE_INIT(n) \
50 UART_IRQ_HANDLER_DECL(n); \
51 static K_MUTEX_DEFINE(uart_##n##_mutex); \
52 static K_SEM_DEFINE(uart_##n##_tx_sem, 1, 1); \
53 static K_SEM_DEFINE(uart_##n##_rx_sem, 1, 1); \
54 static K_SEM_DEFINE(uart_##n##_sync_read_sem, 0, 1); \
55 static const struct uart_sedi_config_info config_info_##n = { \
56 DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \
57 .instance = DT_INST_PROP(n, peripheral_id), \
58 .baud_rate = DT_INST_PROP(n, current_speed), \
59 .hw_fc = DT_INST_PROP(n, hw_flow_control), \
60 .line_ctrl = SEDI_UART_LC_8N1, \
61 .mutex = &uart_##n##_mutex, \
62 UART_CONFIG_IRQ_HANDLER_SET(n) \
63 }; \
64 \
65 static struct uart_sedi_drv_data drv_data_##n; \
66 PM_DEVICE_DT_DEFINE(DT_NODELABEL(uart##n), \
67 uart_sedi_pm_action); \
68 DEVICE_DT_DEFINE(DT_NODELABEL(uart##n), \
69 &uart_sedi_init, \
70 PM_DEVICE_DT_GET(DT_NODELABEL(uart##n)), \
71 &drv_data_##n, &config_info_##n, \
72 PRE_KERNEL_1, \
73 CONFIG_SERIAL_INIT_PRIORITY, &api); \
74 UART_IRQ_HANDLER_DEFINE(n)
75
76
77
78 /* Convenient macro to get the controller instance. */
79 #define GET_CONTROLLER_INSTANCE(dev) \
80 (((const struct uart_sedi_config_info *) \
81 dev->config)->instance)
82
83 #define GET_MUTEX(dev) \
84 (((const struct uart_sedi_config_info *) \
85 dev->config)->mutex)
86
87 struct uart_sedi_config_info {
88 DEVICE_MMIO_ROM;
89 /* Specifies the uart instance for configuration. */
90 sedi_uart_t instance;
91
92 /* Specifies the baudrate for the uart instance. */
93 uint32_t baud_rate;
94
95 /* Specifies the port line control settings */
96 sedi_uart_lc_t line_ctrl;
97
98 struct k_mutex *mutex;
99
100 /* Enable / disable hardware flow control for UART. */
101 bool hw_fc;
102
103 /* UART irq configuration function when supporting interrupt
104 * mode.
105 */
106 uart_irq_config_func_t uart_irq_config_func;
107 };
108
109
110 static int uart_sedi_init(const struct device *dev);
111
112 struct uart_sedi_drv_data {
113 DEVICE_MMIO_RAM;
114 uart_irq_callback_user_data_t user_cb;
115 void *unsol_rx_usr_cb_param;
116 uint32_t sync_rx_len;
117 uint32_t sync_rx_status;
118 void *user_data;
119 void *usr_rx_buff;
120 uint32_t usr_rx_size;
121 uint8_t iir_cache;
122 uint8_t busy_count;
123 };
124
125 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_busy_set(const struct device * dev)126 static void uart_busy_set(const struct device *dev)
127 {
128
129 struct uart_sedi_drv_data *context = dev->data;
130
131 context->busy_count++;
132
133 if (context->busy_count == 1) {
134 pm_device_busy_set(dev);
135 }
136 }
137
uart_busy_clear(const struct device * dev)138 static void uart_busy_clear(const struct device *dev)
139 {
140
141 struct uart_sedi_drv_data *context = dev->data;
142
143 context->busy_count--;
144
145 if (context->busy_count == 0) {
146 pm_device_busy_clear(dev);
147 }
148 }
149 #endif
150
151 #ifdef CONFIG_PM_DEVICE
152
153 #ifndef CONFIG_UART_CONSOLE
154
uart_suspend_device(const struct device * dev)155 static int uart_suspend_device(const struct device *dev)
156 {
157 const struct uart_sedi_config_info *config = dev->config;
158
159 if (pm_device_is_busy(dev)) {
160 return -EBUSY;
161 }
162
163 int ret = sedi_uart_set_power(config->instance, SEDI_POWER_SUSPEND);
164
165 if (ret != SEDI_DRIVER_OK) {
166 return -EIO;
167 }
168
169 return 0;
170 }
171
uart_resume_device_from_suspend(const struct device * dev)172 static int uart_resume_device_from_suspend(const struct device *dev)
173 {
174 const struct uart_sedi_config_info *config = dev->config;
175 int ret;
176
177 ret = sedi_uart_set_power(config->instance, SEDI_POWER_FULL);
178 if (ret != SEDI_DRIVER_OK) {
179 return -EIO;
180 }
181
182 return 0;
183 }
184
uart_sedi_pm_action(const struct device * dev,enum pm_device_action action)185 static int uart_sedi_pm_action(const struct device *dev,
186 enum pm_device_action action)
187 {
188 int ret = 0;
189
190 switch (action) {
191 case PM_DEVICE_ACTION_SUSPEND:
192 ret = uart_suspend_device(dev);
193 break;
194 case PM_DEVICE_ACTION_RESUME:
195 ret = uart_resume_device_from_suspend(dev);
196 break;
197
198 default:
199 ret = -ENOTSUP;
200 }
201 return ret;
202 }
203
204 #else
205
uart_sedi_pm_action(const struct device * dev,enum pm_device_action action)206 static int uart_sedi_pm_action(const struct device *dev,
207 enum pm_device_action action)
208 {
209 /* do nothing if using UART print log to avoid clock gating
210 * pm driver already handled power management for uart.
211 */
212 return 0;
213 }
214
215 #endif /* CONFIG_UART_CONSOLE */
216
217 #endif /* CONFIG_PM_DEVICE */
218
uart_sedi_poll_in(const struct device * dev,unsigned char * data)219 static int uart_sedi_poll_in(const struct device *dev, unsigned char *data)
220 {
221 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
222 uint32_t status;
223 int ret = 0;
224
225 sedi_uart_get_status(instance, (uint32_t *) &status);
226
227 /* In order to check if there is any data to read from UART
228 * controller we should check if the SEDI_UART_RX_BUSY bit from
229 * 'status' is not set. This bit is set only if there is any
230 * pending character to read.
231 */
232 if (!(status & SEDI_UART_RX_BUSY)) {
233 ret = -1;
234 } else {
235 if (sedi_uart_read(instance, data, (uint32_t *)&status)) {
236 ret = -1;
237 }
238 }
239 return ret;
240 }
241
uart_sedi_poll_out(const struct device * dev,unsigned char data)242 static void uart_sedi_poll_out(const struct device *dev,
243 unsigned char data)
244 {
245 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
246
247 sedi_uart_write(instance, data);
248 }
249
250 #ifdef CONFIG_UART_LINE_CTRL
get_xfer_error(int bsp_err)251 static int get_xfer_error(int bsp_err)
252 {
253 int err;
254
255 switch (bsp_err) {
256 case SEDI_DRIVER_OK:
257 err = 0;
258 break;
259 case SEDI_USART_ERROR_CANCELED:
260 err = -ECANCELED;
261 break;
262 case SEDI_DRIVER_ERROR:
263 err = -EIO;
264 break;
265 case SEDI_DRIVER_ERROR_PARAMETER:
266 err = -EINVAL;
267 break;
268 case SEDI_DRIVER_ERROR_UNSUPPORTED:
269 err = -ENOTSUP;
270 break;
271 default:
272 err = -EFAULT;
273 }
274 return err;
275 }
276 #endif /* CONFIG_UART_LINE_CTRL */
277
uart_sedi_err_check(const struct device * dev)278 static int uart_sedi_err_check(const struct device *dev)
279 {
280 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
281 uint32_t status;
282 int ret_status = 0;
283
284 sedi_uart_get_status(instance, (uint32_t *const)&status);
285 if (status & SEDI_UART_RX_OE) {
286 ret_status = UART_ERROR_OVERRUN;
287 }
288
289 if (status & SEDI_UART_RX_PE) {
290 ret_status = UART_ERROR_PARITY;
291 }
292
293 if (status & SEDI_UART_RX_FE) {
294 ret_status = UART_ERROR_FRAMING;
295 }
296
297 if (status & SEDI_UART_RX_BI) {
298 ret_status = UART_BREAK;
299 }
300
301 return ret_status;
302 }
303
304
305 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
306
uart_sedi_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)307 static int uart_sedi_fifo_fill(const struct device *dev, const uint8_t *tx_data,
308 int size)
309 {
310 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
311
312 return sedi_uart_fifo_fill(instance, tx_data, size);
313 }
314
uart_sedi_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)315 static int uart_sedi_fifo_read(const struct device *dev, uint8_t *rx_data,
316 const int size)
317 {
318 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
319
320 return sedi_uart_fifo_read(instance, rx_data, size);
321 }
322
uart_sedi_irq_tx_enable(const struct device * dev)323 static void uart_sedi_irq_tx_enable(const struct device *dev)
324 {
325 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
326
327 sedi_uart_irq_tx_enable(instance);
328 }
329
uart_sedi_irq_tx_disable(const struct device * dev)330 static void uart_sedi_irq_tx_disable(const struct device *dev)
331 {
332 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
333
334 sedi_uart_irq_tx_disable(instance);
335 }
336
uart_sedi_irq_tx_ready(const struct device * dev)337 static int uart_sedi_irq_tx_ready(const struct device *dev)
338 {
339 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
340
341 return sedi_uart_irq_tx_ready(instance);
342 }
343
uart_sedi_irq_tx_complete(const struct device * dev)344 static int uart_sedi_irq_tx_complete(const struct device *dev)
345 {
346 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
347
348 return sedi_uart_is_tx_complete(instance);
349 }
350
uart_sedi_irq_rx_enable(const struct device * dev)351 static void uart_sedi_irq_rx_enable(const struct device *dev)
352 {
353 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
354
355 uart_busy_set(dev);
356 sedi_uart_irq_rx_enable(instance);
357 }
358
uart_sedi_irq_rx_disable(const struct device * dev)359 static void uart_sedi_irq_rx_disable(const struct device *dev)
360 {
361 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
362
363 sedi_uart_irq_rx_disable(instance);
364 uart_busy_clear(dev);
365 }
366
uart_sedi_irq_rx_ready(const struct device * dev)367 static int uart_sedi_irq_rx_ready(const struct device *dev)
368 {
369 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
370
371 return sedi_uart_is_irq_rx_ready(instance);
372 }
373
uart_sedi_irq_err_enable(const struct device * dev)374 static void uart_sedi_irq_err_enable(const struct device *dev)
375 {
376 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
377
378 sedi_uart_irq_err_enable(instance);
379 }
380
uart_sedi_irq_err_disable(const struct device * dev)381 static void uart_sedi_irq_err_disable(const struct device *dev)
382 {
383 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
384
385 sedi_uart_irq_err_disable(instance);
386 }
387
uart_sedi_irq_is_pending(const struct device * dev)388 static int uart_sedi_irq_is_pending(const struct device *dev)
389 {
390
391 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
392
393 return sedi_uart_is_irq_pending(instance);
394 }
395
uart_sedi_irq_update(const struct device * dev)396 static int uart_sedi_irq_update(const struct device *dev)
397 {
398 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
399
400 sedi_uart_update_irq_cache(instance);
401 return 1;
402 }
403
uart_sedi_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * user_data)404 static void uart_sedi_irq_callback_set(const struct device *dev,
405 uart_irq_callback_user_data_t cb,
406 void *user_data)
407 {
408 struct uart_sedi_drv_data *drv_data = dev->data;
409
410 drv_data->user_cb = cb;
411 drv_data->user_data = user_data;
412
413 }
414
uart_sedi_isr(void * arg)415 static void uart_sedi_isr(void *arg)
416 {
417 struct device *dev = arg;
418 struct uart_sedi_drv_data *drv_data = dev->data;
419
420 if (drv_data->user_cb) {
421 drv_data->user_cb(dev, drv_data->user_data);
422 } else {
423 uart_sedi_cb(dev);
424 }
425 }
426
427 /* Called from generic callback of zephyr , set by set_cb. */
uart_sedi_cb(struct device * port)428 static void uart_sedi_cb(struct device *port)
429 {
430 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(port);
431
432 sedi_uart_isr_handler(instance);
433 }
434
435 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
436
437 #ifdef CONFIG_UART_LINE_CTRL
uart_sedi_line_ctrl_set(struct device * dev,uint32_t ctrl,uint32_t val)438 static int uart_sedi_line_ctrl_set(struct device *dev,
439 uint32_t ctrl, uint32_t val)
440 {
441 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
442 sedi_uart_config_t cfg;
443 uint32_t mask;
444 int ret;
445
446 k_mutex_lock(GET_MUTEX(dev), K_FOREVER);
447 switch (ctrl) {
448 case UART_LINE_CTRL_BAUD_RATE:
449 sedi_uart_get_config(instance, &cfg);
450 cfg.baud_rate = val;
451 ret = sedi_uart_set_config(instance, &cfg);
452 break;
453
454 default:
455 ret = -ENODEV;
456 }
457 k_mutex_unlock(GET_MUTEX(dev));
458 ret = get_xfer_error(ret);
459 return ret;
460 }
461
uart_sedi_line_ctrl_get(struct device * dev,uint32_t ctrl,uint32_t * val)462 static int uart_sedi_line_ctrl_get(struct device *dev,
463 uint32_t ctrl, uint32_t *val)
464 {
465 sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev);
466 sedi_uart_config_t cfg;
467 uint32_t mask;
468 int ret;
469
470 k_mutex_lock(GET_MUTEX(dev), K_FOREVER);
471 switch (ctrl) {
472 case UART_LINE_CTRL_BAUD_RATE:
473 ret = sedi_uart_get_config(instance, &cfg);
474 *val = cfg.baud_rate;
475 break;
476
477 case UART_LINE_CTRL_LOOPBACK:
478 ret = sedi_uart_get_loopback_mode(instance, (uint32_t *)val);
479 break;
480
481 case UART_LINE_CTRL_AFCE:
482 ret = sedi_uart_get_config(instance, &cfg);
483 *val = cfg.hw_fc;
484 break;
485
486 case UART_LINE_CTRL_LINE_STATUS_REPORT_MASK:
487 mask = 0;
488 *val = 0;
489 ret = sedi_get_ln_status_report_mask(instance,
490 (uint32_t *)&mask);
491 *val |= ((mask & SEDI_UART_RX_OE) ? UART_ERROR_OVERRUN : 0);
492 *val |= ((mask & SEDI_UART_RX_PE) ? UART_ERROR_PARITY : 0);
493 *val |= ((mask & SEDI_UART_RX_FE) ? UART_ERROR_FRAMING : 0);
494 *val |= ((mask & SEDI_UART_RX_BI) ? UART_BREAK : 0);
495 break;
496
497 case UART_LINE_CTRL_RTS:
498 ret = sedi_uart_read_rts(instance, (uint32_t *)val);
499 break;
500
501 case UART_LINE_CTRL_CTS:
502 ret = sedi_uart_read_cts(instance, (uint32_t *)val);
503 break;
504
505
506 default:
507 ret = -ENODEV;
508 }
509 k_mutex_unlock(GET_MUTEX(dev));
510 ret = get_xfer_error(ret);
511 return ret;
512 }
513
514 #endif /* CONFIG_UART_LINE_CTRL */
515
516 static DEVICE_API(uart, api) = {
517 .poll_in = uart_sedi_poll_in,
518 .poll_out = uart_sedi_poll_out,
519 .err_check = uart_sedi_err_check,
520 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
521 .fifo_fill = uart_sedi_fifo_fill,
522 .fifo_read = uart_sedi_fifo_read,
523 .irq_tx_enable = uart_sedi_irq_tx_enable,
524 .irq_tx_disable = uart_sedi_irq_tx_disable,
525 .irq_tx_ready = uart_sedi_irq_tx_ready,
526 .irq_tx_complete = uart_sedi_irq_tx_complete,
527 .irq_rx_enable = uart_sedi_irq_rx_enable,
528 .irq_rx_disable = uart_sedi_irq_rx_disable,
529 .irq_rx_ready = uart_sedi_irq_rx_ready,
530 .irq_err_enable = uart_sedi_irq_err_enable,
531 .irq_err_disable = uart_sedi_irq_err_disable,
532 .irq_is_pending = uart_sedi_irq_is_pending,
533 .irq_update = uart_sedi_irq_update,
534 .irq_callback_set = uart_sedi_irq_callback_set,
535 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
536 #ifdef CONFIG_UART_LINE_CTRL
537 .line_ctrl_set = uart_sedi_line_ctrl_set,
538 .line_ctrl_get = uart_sedi_line_ctrl_get,
539 #endif /* CONFIG_UART_LINE_CTRL */
540
541 };
542
uart_sedi_init(const struct device * dev)543 static int uart_sedi_init(const struct device *dev)
544 {
545
546 const struct uart_sedi_config_info *config = dev->config;
547 sedi_uart_config_t cfg;
548
549 DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
550 sedi_uart_init(config->instance, (void *)DEVICE_MMIO_GET(dev));
551
552 cfg.line_control = config->line_ctrl;
553 cfg.baud_rate = config->baud_rate;
554 cfg.hw_fc = config->hw_fc;
555
556 /* Setting to full power and enabling clk. */
557 sedi_uart_set_power(config->instance, SEDI_POWER_FULL);
558
559 sedi_uart_set_config(config->instance, &cfg);
560
561 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
562 config->uart_irq_config_func(dev);
563 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
564
565 return 0;
566 }
567
568 DT_INST_FOREACH_STATUS_OKAY(UART_SEDI_DEVICE_INIT)
569