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