1 /*
2 * Copyright (c) 2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @brief UART driver for Intel FPGA UART Core IP
9 * Reference : Embedded Peripherals IP User Guide (22.3 and above): 55.
10 * Lightweight UART Core
11 */
12
13 #define DT_DRV_COMPAT intel_lw_uart
14 #include <zephyr/kernel.h>
15 #include <zephyr/drivers/uart.h>
16
17 #include <zephyr/drivers/serial/uart_intel_lw.h>
18
19 /* register offsets */
20 #define INTEL_LW_UART_OFFSET (0x4)
21
22 #define INTEL_LW_UART_RXDATA_REG_OFFSET (0 * INTEL_LW_UART_OFFSET)
23 #define INTEL_LW_UART_TXDATA_REG_OFFSET (1 * INTEL_LW_UART_OFFSET)
24 #define INTEL_LW_UART_STATUS_REG_OFFSET (2 * INTEL_LW_UART_OFFSET)
25 #define INTEL_LW_UART_CONTROL_REG_OFFSET (3 * INTEL_LW_UART_OFFSET)
26 #define INTEL_LW_UART_DIVISOR_REG_OFFSET (4 * INTEL_LW_UART_OFFSET)
27 #define INTEL_LW_UART_EOP_REG_OFFSET (5 * INTEL_LW_UART_OFFSET)
28
29 /*status register mask */
30 #define INTEL_LW_UART_STATUS_PE_MSK (0x1)
31 #define INTEL_LW_UART_STATUS_FE_MSK (0x2)
32 #define INTEL_LW_UART_STATUS_BRK_MSK (0x4)
33 #define INTEL_LW_UART_STATUS_ROE_MSK (0x8)
34 #define INTEL_LW_UART_STATUS_TOE_MSK (0x10)
35 #define INTEL_LW_UART_STATUS_TMT_MSK (0x20)
36 #define INTEL_LW_UART_STATUS_TRDY_MSK (0x40)
37 #define INTEL_LW_UART_STATUS_RRDY_MSK (0x80)
38 #define INTEL_LW_UART_STATUS_DCTS_MSK (0x400)
39 #define INTEL_LW_UART_STATUS_CTS_MSK (0x800)
40 #define INTEL_LW_UART_STATUS_E_MSK (0x100)
41 #define INTEL_LW_UART_STATUS_EOP_MSK (0x1000)
42
43 /* control register mask */
44 #define INTEL_LW_UART_CONTROL_TMT_MSK (0x20)
45 #define INTEL_LW_UART_CONTROL_TRDY_MSK (0x40)
46 #define INTEL_LW_UART_CONTROL_RRDY_MSK (0x80)
47 #define INTEL_LW_UART_CONTROL_E_MSK (0x100)
48 #define INTEL_LW_UART_CONTROL_TRBK_MSK (0x200)
49 #define INTEL_LW_UART_CONTROL_DCTS_MSK (0x400)
50 #define INTEL_LW_UART_CONTROL_RTS_MSK (0x800)
51 #define INTEL_LW_UART_CONTROL_EOP_MSK (0x1000)
52
53 /* defined values */
54 #define UART_INTEL_LW_NO_ERROR (0u)
55 #define INTEL_LW_UART_CLEAR_STATUS_VAL (0u)
56 #define INTEL_LW_UART_PENDING_MASK (INTEL_LW_UART_STATUS_RRDY_MSK | \
57 INTEL_LW_UART_STATUS_TRDY_MSK | INTEL_LW_UART_STATUS_E_MSK \
58 | INTEL_LW_UART_STATUS_EOP_MSK)
59
60 /***********************/
61 /* configuration flags */
62 /*
63 * The value INTEL_LW_UART_FB is a value set in the devices flag field to
64 * indicate that the device has a fixed baud rate; i.e. if this flag is set
65 * software can not control the baud rate of the device.
66 */
67 #define INTEL_LW_UART_FB 0x1
68
69 /*
70 * The value INTEL_LW_UART_FC is a value set in the device flag field to
71 * indicate the device is using flow control, i.e. the driver must
72 * throttle on transmit if the nCTS pin is low.
73 */
74 #define INTEL_LW_UART_FC 0x2
75
76 /* end of configuration flags */
77 /******************************/
78
79 /* device data */
80 struct uart_intel_lw_device_data {
81 struct uart_config uart_cfg; /* stores uart config from device tree*/
82 struct k_spinlock lock;
83 uint32_t status_act; /* stores value of status register. */
84 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
85 uart_irq_callback_user_data_t cb; /**< Callback function pointer */
86 void *cb_data; /**< Callback function arg */
87 #ifdef CONFIG_UART_INTEL_LW_EOP
88 uint8_t set_eop_cb;
89 uart_irq_callback_user_data_t cb_eop; /**< Callback function pointer */
90 void *cb_data_eop; /**< Callback function arg */
91 #endif /* CONFIG_UART_INTEL_LW_EOP */
92 uint32_t control_val; /* stores value to set control register. */
93 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
94 };
95
96 /*
97 * device config:
98 * stores data that cannot be changed during run time.
99 */
100 struct uart_intel_lw_device_config {
101 mm_reg_t base;
102 uint32_t flags; /* refer to configuration flags */
103 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
104 uart_irq_config_func_t irq_config_func;
105 unsigned int irq_num;
106 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
107 };
108
109 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
110 /**
111 * function prototypes
112 */
113 static int uart_intel_lw_irq_update(const struct device *dev);
114 static int uart_intel_lw_irq_tx_ready(const struct device *dev);
115 static int uart_intel_lw_irq_rx_ready(const struct device *dev);
116 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
117
118 /**
119 * @brief Poll the device for input.
120 *
121 * This is a non-blocking function.
122 *
123 * This driver supports interrupt driven api.
124 * Polling for data under normal operation, might cause unexpected behaviour.
125 * If users wish to poll in for data, please ensure that the data is not retrieved
126 * in interrupt.
127 *
128 * If UART_LINE_CTRL is enabled, please do not disable the hardware
129 * interrupt for this uart device, as the flow control is handled in uart_intel_lw_dcts_isr.
130 *
131 * @param dev UART device instance
132 * @param p_char Pointer to character
133 *
134 * @return 0 if a character arrived, -1 if input buffer is empty.
135 * -EINVAL if p_char is null pointer
136 */
uart_intel_lw_poll_in(const struct device * dev,unsigned char * p_char)137 static int uart_intel_lw_poll_in(const struct device *dev, unsigned char *p_char)
138 {
139 const struct uart_intel_lw_device_config *config = dev->config;
140 struct uart_intel_lw_device_data *data = dev->data;
141 int ret_val = -1;
142 uint32_t status;
143
144 /* generate fatal error if CONFIG_ASSERT is enabled. */
145 __ASSERT(p_char != NULL, "p_char is null pointer!");
146
147 /* Stop, if p_char is null pointer */
148 if (p_char == NULL) {
149 return -EINVAL;
150 }
151
152 k_spinlock_key_t key = k_spin_lock(&data->lock);
153
154 /* check if received character is ready.*/
155 status = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
156 if (status & INTEL_LW_UART_STATUS_RRDY_MSK) {
157 /* got a character */
158 *p_char = sys_read32(config->base + INTEL_LW_UART_RXDATA_REG_OFFSET);
159 ret_val = 0;
160 }
161
162 k_spin_unlock(&data->lock, key);
163
164 return ret_val;
165 }
166
167 /**
168 * @brief Output a character in polled mode.
169 *
170 * This function will block until transmitter is ready.
171 * Then, a character will be transmitted.
172 *
173 * This driver supports interrupt driven api.
174 * Polling for data under normal operation, might cause unexpected behaviour.
175 * If users wish to poll out data, please ensure that the data is not transmitted
176 * in interrupt.
177 *
178 * If UART_LINE_CTRL is enabled and users wish to poll out only 1 character,
179 * please enable UART_INTEL_LW_AUTO_LINE_CTRL_POLL. Please note that this might
180 * be inefficient, in case of polling out several characters. Instead of using
181 * UART_INTEL_LW_AUTO_LINE_CTRL_POLL, please consider using the api: uart_drv_cmd
182 * with CMD_POLL_ASSERT_RTS before polling out. Then use CMD_POLL_DEASSERT_RTS to
183 * resume normal operation after all characters are polled out.
184 *
185 * Please do not set CMD_TRBK_EN, when polling out data.
186 *
187 * @param dev UART device instance
188 * @param c Character to send
189 */
uart_intel_lw_poll_out(const struct device * dev,unsigned char c)190 static void uart_intel_lw_poll_out(const struct device *dev, unsigned char c)
191 {
192 const struct uart_intel_lw_device_config *config = dev->config;
193 struct uart_intel_lw_device_data *data = dev->data;
194 uint32_t status;
195 bool tx_is_free = false;
196 bool poll_out_done = false;
197 k_spinlock_key_t key;
198
199 /* wait until uart is free to transmit.*/
200 do {
201 key = k_spin_lock(&data->lock);
202
203 if (tx_is_free == false) {
204 status = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
205
206 /* wait until there is space in fifo. */
207 if (status & INTEL_LW_UART_STATUS_TRDY_MSK) {
208 #ifdef CONFIG_UART_INTEL_LW_AUTO_LINE_CTRL_POLL
209 data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK;
210 sys_write32(data->control_val, config->base
211 + INTEL_LW_UART_CONTROL_REG_OFFSET);
212 #endif
213 sys_write32(c, config->base + INTEL_LW_UART_TXDATA_REG_OFFSET);
214 tx_is_free = true;
215 }
216 } else {
217 status = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
218
219 /* wait until fifo data is shifted out. */
220 if (status & INTEL_LW_UART_STATUS_TMT_MSK) {
221 #ifdef CONFIG_UART_INTEL_LW_AUTO_LINE_CTRL_POLL
222 data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK;
223 sys_write32(data->control_val, config->base
224 + INTEL_LW_UART_CONTROL_REG_OFFSET);
225 #endif
226 poll_out_done = true;
227 }
228 }
229
230 k_spin_unlock(&data->lock, key);
231 } while (!poll_out_done);
232 }
233
234 /**
235 * @brief Initialise an instance of the driver
236 *
237 * This function initialise the interrupt configuration for the driver.
238 *
239 * @param dev UART device instance
240 *
241 * @return 0 to indicate success.
242 */
uart_intel_lw_init(const struct device * dev)243 static int uart_intel_lw_init(const struct device *dev)
244 {
245 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
246 struct uart_intel_lw_device_data *data = dev->data;
247 const struct uart_intel_lw_device_config *config = dev->config;
248 /* clear status to ensure, that interrupts are not triggered due to old status. */
249 sys_write32(INTEL_LW_UART_CLEAR_STATUS_VAL, config->base
250 + INTEL_LW_UART_STATUS_REG_OFFSET);
251
252 /*
253 * Enable hardware interrupt.
254 * The corresponding csr from IP still needs to be set,
255 * so that the IP generates interrupt signal.
256 */
257 config->irq_config_func(dev);
258
259 #ifdef CONFIG_UART_LINE_CTRL
260 /* Enable DCTS interrupt. */
261 data->control_val = INTEL_LW_UART_CONTROL_DCTS_MSK;
262 #endif /* CONFIG_UART_LINE_CTRL */
263
264 sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET);
265
266 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
267
268 return 0;
269 }
270
271 /**
272 * @brief Check if an error was received
273 * If error is received, it will be mapped to uart_rx_stop_reason.
274 * This function should be called after irq_update.
275 * If interrupt driven API is not enabled,
276 * this function will read and clear the status register.
277 *
278 * @param dev UART device struct
279 *
280 * @return UART_ERROR_OVERRUN, UART_ERROR_PARITY, UART_ERROR_FRAMING,
281 * UART_BREAK if an error was detected, 0 otherwise.
282 */
uart_intel_lw_err_check(const struct device * dev)283 static int uart_intel_lw_err_check(const struct device *dev)
284 {
285 struct uart_intel_lw_device_data *data = dev->data;
286 int err = UART_INTEL_LW_NO_ERROR;
287
288 #ifndef CONFIG_UART_INTERRUPT_DRIVEN
289 const struct uart_intel_lw_device_config *config = dev->config;
290 k_spinlock_key_t key = k_spin_lock(&data->lock);
291
292 data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
293 #endif
294
295 if (data->status_act & INTEL_LW_UART_STATUS_E_MSK) {
296 if (data->status_act & INTEL_LW_UART_STATUS_PE_MSK) {
297 err |= UART_ERROR_PARITY;
298 }
299
300 if (data->status_act & INTEL_LW_UART_STATUS_FE_MSK) {
301 err |= UART_ERROR_FRAMING;
302 }
303
304 if (data->status_act & INTEL_LW_UART_STATUS_BRK_MSK) {
305 err |= UART_BREAK;
306 }
307
308 if (data->status_act & INTEL_LW_UART_STATUS_ROE_MSK) {
309 err |= UART_ERROR_OVERRUN;
310 }
311 }
312
313 #ifndef CONFIG_UART_INTERRUPT_DRIVEN
314 /* clear status */
315 sys_write32(INTEL_LW_UART_CLEAR_STATUS_VAL, config->base
316 + INTEL_LW_UART_STATUS_REG_OFFSET);
317 k_spin_unlock(&data->lock, key);
318 #endif
319
320 return err;
321 }
322
323 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
324 /***
325 * @brief helper function to check, if the configuration is support.
326 * The only parameter that can be changed during runtime is the baudrate.
327 *
328 * @param cfg_stored The original configuration.
329 * @param cfg_in The input configuration.
330 * @return true if parameter other than baudrate remains the same. otherwise, false.
331 */
uart_intel_lw_check_configuration(const struct uart_config * cfg_stored,const struct uart_config * cfg_in)332 static bool uart_intel_lw_check_configuration(const struct uart_config *cfg_stored,
333 const struct uart_config *cfg_in)
334 {
335 bool ret_val = false;
336
337 if ((cfg_stored->parity == cfg_in->parity)
338 && (cfg_stored->stop_bits == cfg_in->stop_bits)
339 && (cfg_stored->data_bits == cfg_in->data_bits)
340 && (cfg_stored->flow_ctrl == cfg_in->flow_ctrl)) {
341 ret_val = true;
342 }
343
344 return ret_val;
345 }
346
347 /**
348 * @brief Set UART configuration using data from *cfg_in.
349 *
350 * @param dev UART Device struct
351 * @param cfg_in The input configuration.
352 *
353 * @return 0 if success, -ENOTSUP, if input from cfg_in is not configurable.
354 * -EINVAL if cfg_in is null pointer
355 */
uart_intel_lw_configure(const struct device * dev,const struct uart_config * cfg_in)356 static int uart_intel_lw_configure(const struct device *dev,
357 const struct uart_config *cfg_in)
358 {
359 const struct uart_intel_lw_device_config *config = dev->config;
360 struct uart_intel_lw_device_data * const data = dev->data;
361 struct uart_config * const cfg_stored = &data->uart_cfg;
362 uint32_t divisor_val;
363 int ret_val;
364
365 /* generate fatal error if CONFIG_ASSERT is enabled. */
366 __ASSERT(cfg_in != NULL, "cfg_in is null pointer!");
367
368 /* Stop, if cfg_in is null pointer */
369 if (cfg_in == NULL) {
370 return -EINVAL;
371 }
372
373 /* check if configuration is supported. */
374 if (uart_intel_lw_check_configuration(cfg_stored, cfg_in)
375 && !(config->flags & INTEL_LW_UART_FB)) {
376 /* parameter is valid, just return ok if baudrate is the same. */
377 if (cfg_stored->baudrate != cfg_in->baudrate) {
378 /* calculate and set baudrate. */
379 divisor_val = (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC/cfg_in->baudrate) - 1;
380 sys_write32(divisor_val, config->base + INTEL_LW_UART_DIVISOR_REG_OFFSET);
381
382 /* update stored data. */
383 cfg_stored->baudrate = cfg_in->baudrate;
384 }
385
386 ret_val = 0;
387 } else {
388 /* return not supported */
389 ret_val = -ENOTSUP;
390 }
391
392 return ret_val;
393 }
394 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
395
396 /**
397 * @brief Get UART configuration and stores in *cfg_out.
398 *
399 * @param dev UART Device struct
400 * @param cfg_out The output configuration.
401 *
402 * @return 0 if success.
403 * -EINVAL if cfg_out is null pointer
404 */
uart_intel_lw_config_get(const struct device * dev,struct uart_config * cfg_out)405 static int uart_intel_lw_config_get(const struct device *dev,
406 struct uart_config *cfg_out)
407 {
408 const struct uart_intel_lw_device_data *data = dev->data;
409
410 /* generate fatal error if CONFIG_ASSERT is enabled. */
411 __ASSERT(cfg_out != NULL, "cfg_out is null pointer!");
412
413 /* Stop, if cfg_out is null pointer */
414 if (cfg_out == NULL) {
415 return -EINVAL;
416 }
417
418 *cfg_out = data->uart_cfg;
419 return 0;
420 }
421
422 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
423 /**
424 * @brief Fill FIFO with data
425 * This function is expected to be called from UART interrupt handler (ISR),
426 * if uart_irq_tx_ready() returns true. This function does not block!
427 *
428 * @param dev UART device struct
429 * @param tx_data Data to transmit
430 * @param size Number of bytes to send
431 *
432 * @return Number of bytes sent
433 */
uart_intel_lw_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)434 static int uart_intel_lw_fifo_fill(const struct device *dev,
435 const uint8_t *tx_data,
436 int size)
437 {
438 const struct uart_intel_lw_device_config *config = dev->config;
439 struct uart_intel_lw_device_data *data = dev->data;
440 int ret_val = 0;
441 k_spinlock_key_t key;
442
443 /* generate fatal error if CONFIG_ASSERT is enabled. */
444 __ASSERT(tx_data != NULL, "tx_data is null pointer!");
445
446 /* Stop, if tx_data is null pointer */
447 if (tx_data == NULL) {
448 return 0;
449 }
450
451 /* Stop, if transmit break is set */
452 if (data->control_val & INTEL_LW_UART_CONTROL_TRBK_MSK) {
453 return 0;
454 }
455
456 do {
457 if (data->status_act & INTEL_LW_UART_STATUS_TRDY_MSK) {
458 key = k_spin_lock(&data->lock);
459 sys_write32(tx_data[ret_val++], config->base
460 + INTEL_LW_UART_TXDATA_REG_OFFSET);
461 data->status_act = sys_read32(config->base
462 + INTEL_LW_UART_STATUS_REG_OFFSET);
463 k_spin_unlock(&data->lock, key);
464 } else {
465 /* stop because tx fifo is full! */
466 break;
467 }
468 } while ((size - ret_val) > 0);
469
470 return ret_val;
471 }
472
473 /**
474 * @brief Read data from FIFO
475 * This function is expected to be called from UART interrupt handler (ISR),
476 * if uart_irq_rx_ready() returns true.
477 *
478 * @param dev UART device struct
479 * @param rx_data Data container
480 * @param size Container size
481 *
482 * @return Number of bytes read
483 */
uart_intel_lw_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)484 static int uart_intel_lw_fifo_read(const struct device *dev, uint8_t *rx_data,
485 const int size)
486 {
487 const struct uart_intel_lw_device_config *config = dev->config;
488 struct uart_intel_lw_device_data *data = dev->data;
489 int ret_val = 0;
490 k_spinlock_key_t key;
491
492 /* generate fatal error if CONFIG_ASSERT is enabled. */
493 __ASSERT(rx_data != NULL, "rx_data is null pointer!");
494
495 /* Stop, if rx_data is null pointer */
496 if (rx_data == NULL) {
497 return 0;
498 }
499
500 do {
501 if (data->status_act & INTEL_LW_UART_STATUS_RRDY_MSK) {
502 key = k_spin_lock(&data->lock);
503 rx_data[ret_val++] = sys_read32(config->base +
504 INTEL_LW_UART_RXDATA_REG_OFFSET);
505 data->status_act = sys_read32(config->base
506 + INTEL_LW_UART_STATUS_REG_OFFSET);
507
508 k_spin_unlock(&data->lock, key);
509 } else {
510 break;
511 }
512 } while ((size - ret_val) > 0);
513
514 return ret_val;
515 }
516
517 /**
518 * @brief Enable TX interrupt
519 *
520 * @param dev UART device struct
521 */
uart_intel_lw_irq_tx_enable(const struct device * dev)522 static void uart_intel_lw_irq_tx_enable(const struct device *dev)
523 {
524 struct uart_intel_lw_device_data *data = dev->data;
525 const struct uart_intel_lw_device_config *config = dev->config;
526
527 k_spinlock_key_t key = k_spin_lock(&data->lock);
528
529 data->control_val |= INTEL_LW_UART_CONTROL_TRDY_MSK;
530
531 #ifdef CONFIG_UART_LINE_CTRL
532 /* also enable RTS, if flow control is enabled. */
533 data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK;
534 #endif
535
536 sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET);
537
538 k_spin_unlock(&data->lock, key);
539 }
540
541 /**
542 * @brief Disable TX interrupt
543 *
544 * @param dev UART device struct
545 */
uart_intel_lw_irq_tx_disable(const struct device * dev)546 static void uart_intel_lw_irq_tx_disable(const struct device *dev)
547 {
548 struct uart_intel_lw_device_data *data = dev->data;
549 const struct uart_intel_lw_device_config *config = dev->config;
550
551 k_spinlock_key_t key = k_spin_lock(&data->lock);
552
553 data->control_val &= ~INTEL_LW_UART_CONTROL_TRDY_MSK;
554
555 #ifdef CONFIG_UART_LINE_CTRL
556 /* also disable RTS, if flow control is enabled. */
557 data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK;
558 #endif
559
560 sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET);
561
562 k_spin_unlock(&data->lock, key);
563 }
564
565 /**
566 * @brief Check if UART TX buffer can accept a new char.
567 *
568 * @param dev UART device struct
569 *
570 * @return 1 if TX interrupt is enabled and at least one char can be written to UART.
571 * 0 if device is not ready to write a new byte.
572 */
uart_intel_lw_irq_tx_ready(const struct device * dev)573 static int uart_intel_lw_irq_tx_ready(const struct device *dev)
574 {
575 struct uart_intel_lw_device_data *data = dev->data;
576 int ret_val = 0;
577
578 k_spinlock_key_t key = k_spin_lock(&data->lock);
579
580 /* if TX interrupt is enabled */
581 if (data->control_val & INTEL_LW_UART_CONTROL_TRDY_MSK) {
582 /* IP core does not have fifo. Wait until tx data is completely shifted. */
583 if (data->status_act & INTEL_LW_UART_STATUS_TMT_MSK) {
584 ret_val = 1;
585 }
586 }
587
588 #ifdef CONFIG_UART_LINE_CTRL
589 /* if flow control is enabled, set tx not ready, if CTS is low. */
590 if ((data->status_act & INTEL_LW_UART_STATUS_CTS_MSK) == 0) {
591 ret_val = 0;
592 }
593
594 #endif /* CONFIG_UART_LINE_CTRL */
595
596 k_spin_unlock(&data->lock, key);
597
598 return ret_val;
599 }
600
601 /**
602 * @brief Check if nothing remains to be transmitted
603 *
604 * @param dev UART device struct
605 *
606 * @return 1 if nothing remains to be transmitted, 0 otherwise
607 */
uart_intel_lw_irq_tx_complete(const struct device * dev)608 static int uart_intel_lw_irq_tx_complete(const struct device *dev)
609 {
610 struct uart_intel_lw_device_data *data = dev->data;
611 int ret_val = 0;
612
613 k_spinlock_key_t key = k_spin_lock(&data->lock);
614
615 if (data->status_act & INTEL_LW_UART_STATUS_TMT_MSK) {
616 ret_val = 1;
617 }
618
619 k_spin_unlock(&data->lock, key);
620
621 return ret_val;
622 }
623
624 /**
625 * @brief Enable RX interrupt in
626 *
627 * @param dev UART device struct
628 */
uart_intel_lw_irq_rx_enable(const struct device * dev)629 static void uart_intel_lw_irq_rx_enable(const struct device *dev)
630 {
631 struct uart_intel_lw_device_data *data = dev->data;
632 const struct uart_intel_lw_device_config *config = dev->config;
633
634 k_spinlock_key_t key = k_spin_lock(&data->lock);
635
636 data->control_val |= INTEL_LW_UART_CONTROL_RRDY_MSK;
637 sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET);
638
639 k_spin_unlock(&data->lock, key);
640 }
641
642 /**
643 * @brief Disable RX interrupt
644 *
645 * @param dev UART device struct
646 */
uart_intel_lw_irq_rx_disable(const struct device * dev)647 static void uart_intel_lw_irq_rx_disable(const struct device *dev)
648 {
649 struct uart_intel_lw_device_data *data = dev->data;
650 const struct uart_intel_lw_device_config *config = dev->config;
651
652 k_spinlock_key_t key = k_spin_lock(&data->lock);
653
654 data->control_val &= ~INTEL_LW_UART_CONTROL_RRDY_MSK;
655 sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET);
656
657 k_spin_unlock(&data->lock, key);
658 }
659
660 /**
661 * @brief Check if Rx IRQ has been raised
662 *
663 * @param dev UART device struct
664 *
665 * @return 1 if an IRQ is ready, 0 otherwise
666 */
uart_intel_lw_irq_rx_ready(const struct device * dev)667 static int uart_intel_lw_irq_rx_ready(const struct device *dev)
668 {
669 struct uart_intel_lw_device_data *data = dev->data;
670 int ret_val = 0;
671
672 k_spinlock_key_t key = k_spin_lock(&data->lock);
673
674 /* if RX interrupt is enabled */
675 if (data->control_val & INTEL_LW_UART_CONTROL_RRDY_MSK) {
676 /* check for space in rx data register */
677 if (data->status_act & INTEL_LW_UART_STATUS_RRDY_MSK) {
678 ret_val = 1;
679 }
680 }
681
682 k_spin_unlock(&data->lock, key);
683
684 return ret_val;
685 }
686
687 /**
688 * @brief This function will cache the status register.
689 *
690 * @param dev UART device struct
691 *
692 * @return 1 for success.
693 */
uart_intel_lw_irq_update(const struct device * dev)694 static int uart_intel_lw_irq_update(const struct device *dev)
695 {
696 struct uart_intel_lw_device_data *data = dev->data;
697 const struct uart_intel_lw_device_config *config = dev->config;
698
699 k_spinlock_key_t key = k_spin_lock(&data->lock);
700
701 data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
702
703 k_spin_unlock(&data->lock, key);
704
705 return 1;
706 }
707
708 /**
709 * @brief Check if any IRQ is pending
710 *
711 * @param dev UART device struct
712 *
713 * @return 1 if an IRQ is pending, 0 otherwise
714 */
uart_intel_lw_irq_is_pending(const struct device * dev)715 static int uart_intel_lw_irq_is_pending(const struct device *dev)
716 {
717 struct uart_intel_lw_device_data *data = dev->data;
718 int ret_val = 0;
719
720 k_spinlock_key_t key = k_spin_lock(&data->lock);
721
722 if (data->status_act & data->control_val & INTEL_LW_UART_PENDING_MASK) {
723 ret_val = 1;
724 }
725
726 k_spin_unlock(&data->lock, key);
727
728 return ret_val;
729 }
730
731 /**
732 * @brief Set the callback function pointer for IRQ.
733 *
734 * @param dev UART device struct
735 * @param cb Callback function pointer.
736 * @param cb_data Data to pass to callback function.
737 */
uart_intel_lw_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)738 static void uart_intel_lw_irq_callback_set(const struct device *dev,
739 uart_irq_callback_user_data_t cb,
740 void *cb_data)
741 {
742 struct uart_intel_lw_device_data *data = dev->data;
743
744 k_spinlock_key_t key = k_spin_lock(&data->lock);
745
746 #ifdef CONFIG_UART_INTEL_LW_EOP
747 if (data->set_eop_cb) {
748 data->cb_eop = cb;
749 data->cb_data_eop = cb_data;
750 data->set_eop_cb = 0;
751 } else {
752 data->cb = cb;
753 data->cb_data = cb_data;
754 }
755 #else
756 data->cb = cb;
757 data->cb_data = cb_data;
758 #endif /* CONFIG_UART_INTEL_LW_EOP */
759
760 k_spin_unlock(&data->lock, key);
761 }
762
763 #ifdef CONFIG_UART_LINE_CTRL
764 /**
765 * @brief DCTS Interrupt service routine.
766 *
767 * Handles assertion and deassettion of CTS/RTS stignal
768 *
769 * @param dev Pointer to UART device struct
770 */
uart_intel_lw_dcts_isr(const struct device * dev)771 static void uart_intel_lw_dcts_isr(const struct device *dev)
772 {
773 struct uart_intel_lw_device_data *data = dev->data;
774 const struct uart_intel_lw_device_config *config = dev->config;
775
776 k_spinlock_key_t key = k_spin_lock(&data->lock);
777
778 /* Assume that user follows zephyr requirement and update status in their call back. */
779 if (data->status_act & INTEL_LW_UART_STATUS_CTS_MSK) {
780
781 /* Assert RTS to inform other UART. */
782 data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK;
783 sys_write32(data->control_val, config->base
784 + INTEL_LW_UART_CONTROL_REG_OFFSET);
785 } else {
786 /* other UART deasserts RTS */
787 if (data->status_act & INTEL_LW_UART_STATUS_TMT_MSK) {
788 /* only deasserts if not transmitting. */
789 data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK;
790 sys_write32(data->control_val, config->base
791 + INTEL_LW_UART_CONTROL_REG_OFFSET);
792 }
793 }
794
795 k_spin_unlock(&data->lock, key);
796 }
797 #endif /* CONFIG_UART_LINE_CTRL */
798
799 /**
800 * @brief Interrupt service routine.
801 *
802 * This simply calls the callback function, if one exists.
803 *
804 * @param dev Pointer to UART device struct
805 *
806 */
uart_intel_lw_isr(const struct device * dev)807 static void uart_intel_lw_isr(const struct device *dev)
808 {
809 struct uart_intel_lw_device_data *data = dev->data;
810 const struct uart_intel_lw_device_config *config = dev->config;
811
812 uart_irq_callback_user_data_t callback = data->cb;
813
814 if (callback) {
815 callback(dev, data->cb_data);
816 }
817
818 /* Post ISR */
819 #if CONFIG_UART_INTEL_LW_EOP
820 data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
821 if (data->status_act & INTEL_LW_UART_STATUS_EOP_MSK) {
822 callback = data->cb_eop;
823 if (callback) {
824 callback(dev, data->cb_data_eop);
825 }
826 }
827 #endif /* CONFIG_UART_INTEL_LW_EOP */
828
829 #ifdef CONFIG_UART_LINE_CTRL
830 data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET);
831 /* handles RTS/CTS signal */
832 if (data->status_act & INTEL_LW_UART_STATUS_DCTS_MSK) {
833 uart_intel_lw_dcts_isr(dev);
834 }
835 #endif
836
837 /* clear status after all interrupts are handled. */
838 sys_write32(INTEL_LW_UART_CLEAR_STATUS_VAL, config->base
839 + INTEL_LW_UART_STATUS_REG_OFFSET);
840 }
841
842 #ifdef CONFIG_UART_DRV_CMD
843 /**
844 * @brief Send extra command to driver
845 *
846 * @param dev UART device struct
847 * @param cmd Command to driver
848 * @param p Parameter to the command
849 *
850 * @return 0 if successful, failed otherwise
851 */
uart_intel_lw_drv_cmd(const struct device * dev,uint32_t cmd,uint32_t p)852 static int uart_intel_lw_drv_cmd(const struct device *dev, uint32_t cmd,
853 uint32_t p)
854 {
855 struct uart_intel_lw_device_data *data = dev->data;
856 const struct uart_intel_lw_device_config *config = dev->config;
857
858 int ret_val = -ENOTSUP;
859 k_spinlock_key_t key = k_spin_lock(&data->lock);
860
861 switch (cmd) {
862 #if CONFIG_UART_INTEL_LW_EOP
863 case CMD_ENABLE_EOP:
864 /* enable EOP interrupt */
865 data->control_val |= INTEL_LW_UART_CONTROL_EOP_MSK;
866 sys_write32(data->control_val, config->base
867 + INTEL_LW_UART_CONTROL_REG_OFFSET);
868
869 /* set EOP character */
870 sys_write32((uint8_t) p, config->base + INTEL_LW_UART_EOP_REG_OFFSET);
871
872 /* after this, user needs to call uart_irq_callback_set
873 * to set data->cb_eop and data->cb_data_eop!
874 */
875 data->set_eop_cb = 1;
876 ret_val = 0;
877 break;
878
879 case CMD_DISABLE_EOP:
880 /* disable EOP interrupt */
881 data->control_val &= ~INTEL_LW_UART_CONTROL_EOP_MSK;
882 sys_write32(data->control_val, config->base
883 + INTEL_LW_UART_CONTROL_REG_OFFSET);
884
885 /* clear call back */
886 data->cb_eop = NULL;
887 data->cb_data_eop = NULL;
888 ret_val = 0;
889 break;
890 #endif /* CONFIG_UART_INTEL_LW_EOP */
891
892 case CMD_TRBK_EN:
893 /* enable transmit break */
894 data->control_val |= INTEL_LW_UART_CONTROL_TRBK_MSK;
895 sys_write32(data->control_val, config->base
896 + INTEL_LW_UART_CONTROL_REG_OFFSET);
897 ret_val = 0;
898 break;
899
900 case CMD_TRBK_DIS:
901 /* disable transmit break */
902 data->control_val &= ~INTEL_LW_UART_CONTROL_TRBK_MSK;
903 sys_write32(data->control_val, config->base
904 + INTEL_LW_UART_CONTROL_REG_OFFSET);
905 ret_val = 0;
906 break;
907
908 case CMD_POLL_ASSERT_RTS:
909 /* assert RTS */
910 data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK;
911 sys_write32(data->control_val, config->base
912 + INTEL_LW_UART_CONTROL_REG_OFFSET);
913 ret_val = 0;
914 break;
915
916 case CMD_POLL_DEASSERT_RTS:
917 /* deassert RTS */
918 data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK;
919 sys_write32(data->control_val, config->base
920 + INTEL_LW_UART_CONTROL_REG_OFFSET);
921 ret_val = 0;
922 break;
923
924 default:
925 ret_val = -ENOTSUP;
926 break;
927 };
928
929 k_spin_unlock(&data->lock, key);
930
931 return ret_val;
932 }
933
934 #endif /* CONFIG_UART_DRV_CMD */
935
936 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
937
938 static DEVICE_API(uart, uart_intel_lw_driver_api) = {
939 .poll_in = uart_intel_lw_poll_in,
940 .poll_out = uart_intel_lw_poll_out,
941 .err_check = uart_intel_lw_err_check,
942 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
943 .configure = uart_intel_lw_configure,
944 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
945 .config_get = uart_intel_lw_config_get,
946
947 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
948 .fifo_fill = uart_intel_lw_fifo_fill,
949 .fifo_read = uart_intel_lw_fifo_read,
950 .irq_tx_enable = uart_intel_lw_irq_tx_enable,
951 .irq_tx_disable = uart_intel_lw_irq_tx_disable,
952 .irq_tx_ready = uart_intel_lw_irq_tx_ready,
953 .irq_tx_complete = uart_intel_lw_irq_tx_complete,
954 .irq_rx_enable = uart_intel_lw_irq_rx_enable,
955 .irq_rx_disable = uart_intel_lw_irq_rx_disable,
956 .irq_rx_ready = uart_intel_lw_irq_rx_ready,
957 .irq_is_pending = uart_intel_lw_irq_is_pending,
958 .irq_update = uart_intel_lw_irq_update,
959 .irq_callback_set = uart_intel_lw_irq_callback_set,
960 #endif
961
962 #ifdef CONFIG_UART_DRV_CMD
963 .drv_cmd = uart_intel_lw_drv_cmd,
964 #endif
965 };
966
967 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
968
969 #define UART_INTEL_LW_IRQ_CONFIG_FUNC(n) \
970 static void uart_intel_lw_irq_config_func_##n(const struct device *dev) \
971 { \
972 IRQ_CONNECT(DT_INST_IRQN(n), \
973 DT_INST_IRQ(n, priority), \
974 uart_intel_lw_isr, \
975 DEVICE_DT_INST_GET(n), 0); \
976 \
977 irq_enable(DT_INST_IRQN(n)); \
978 }
979
980 #define UART_INTEL_LW_IRQ_CONFIG_INIT(n) \
981 .irq_config_func = uart_intel_lw_irq_config_func_##n, \
982 .irq_num = DT_INST_IRQN(n),
983
984 #else
985
986 #define UART_INTEL_LW_IRQ_CONFIG_FUNC(n)
987 #define UART_INTEL_LW_IRQ_CONFIG_INIT(n)
988
989 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
990
991 #define UART_INTEL_LW_DEVICE_INIT(n) \
992 UART_INTEL_LW_IRQ_CONFIG_FUNC(n) \
993 static struct uart_intel_lw_device_data uart_intel_lw_dev_data_##n = { \
994 .uart_cfg = \
995 { \
996 .baudrate = DT_INST_PROP(n, current_speed), \
997 .parity = DT_INST_ENUM_IDX_OR(n, parity, \
998 UART_CFG_PARITY_NONE), \
999 .stop_bits = DT_INST_ENUM_IDX_OR(n, stop_bits, \
1000 UART_CFG_STOP_BITS_1), \
1001 .data_bits = DT_INST_ENUM_IDX_OR(n, data_bits, \
1002 UART_CFG_DATA_BITS_8), \
1003 .flow_ctrl = DT_INST_PROP(n, hw_flow_control) ? \
1004 UART_CFG_FLOW_CTRL_RTS_CTS : \
1005 UART_CFG_FLOW_CTRL_NONE, \
1006 }, \
1007 }; \
1008 \
1009 static const struct uart_intel_lw_device_config uart_intel_lw_dev_cfg_##n = { \
1010 .base = DT_INST_REG_ADDR(n), \
1011 .flags = ((DT_INST_PROP(n, fixed_baudrate)?INTEL_LW_UART_FB:0) \
1012 |(DT_INST_PROP(n, hw_flow_control)?INTEL_LW_UART_FC:0)),\
1013 UART_INTEL_LW_IRQ_CONFIG_INIT(n) \
1014 }; \
1015 \
1016 DEVICE_DT_INST_DEFINE(n, \
1017 uart_intel_lw_init, \
1018 NULL, \
1019 &uart_intel_lw_dev_data_##n, \
1020 &uart_intel_lw_dev_cfg_##n, \
1021 PRE_KERNEL_1, \
1022 CONFIG_SERIAL_INIT_PRIORITY, \
1023 &uart_intel_lw_driver_api);
1024
1025 DT_INST_FOREACH_STATUS_OKAY(UART_INTEL_LW_DEVICE_INIT)
1026