1 /*
2  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or
3  * an affiliate of Cypress Semiconductor Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @brief UART driver for Infineon CAT1 MCU family.
10  *
11  * Note:
12  * - Uart ASYNC functionality is not implemented in current
13  *   version of Uart CAT1 driver.
14  */
15 
16 #define DT_DRV_COMPAT infineon_cat1_uart
17 
18 #include <zephyr/drivers/uart.h>
19 #include <zephyr/drivers/pinctrl.h>
20 #include <cyhal_uart.h>
21 #include <cyhal_utils_impl.h>
22 #include <cyhal_scb_common.h>
23 
24 /* Data structure */
25 struct ifx_cat1_uart_data {
26 	cyhal_uart_t obj;                               /* UART CYHAL object */
27 	struct uart_config cfg;
28 	cyhal_resource_inst_t hw_resource;
29 	cyhal_clock_t clock;
30 
31 #if CONFIG_UART_INTERRUPT_DRIVEN
32 	uart_irq_callback_user_data_t irq_cb;           /* Interrupt Callback */
33 	void *irq_cb_data;                              /* Interrupt Callback Arg */
34 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
35 };
36 
37 /* Device config structure */
38 struct ifx_cat1_uart_config {
39 	const struct pinctrl_dev_config *pcfg;
40 	CySCB_Type *reg_addr;
41 	struct uart_config dt_cfg;
42 	uint8_t irq_priority;
43 };
44 
45 /* Default Counter configuration structure */
46 static const cy_stc_scb_uart_config_t _cyhal_uart_default_config = {
47 	.uartMode = CY_SCB_UART_STANDARD,
48 	.enableMutliProcessorMode = false,
49 	.smartCardRetryOnNack = false,
50 	.irdaInvertRx = false,
51 	.irdaEnableLowPowerReceiver = false,
52 	.oversample = 12,
53 	.enableMsbFirst = false,
54 	.dataWidth = 8UL,
55 	.parity = CY_SCB_UART_PARITY_NONE,
56 	.stopBits = CY_SCB_UART_STOP_BITS_1,
57 	.enableInputFilter = false,
58 	.breakWidth = 11UL,
59 	.dropOnFrameError = false,
60 	.dropOnParityError = false,
61 
62 	.receiverAddress = 0x0UL,
63 	.receiverAddressMask = 0x0UL,
64 	.acceptAddrInFifo = false,
65 
66 	.enableCts = false,
67 	.ctsPolarity = CY_SCB_UART_ACTIVE_LOW,
68 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
69 	.rtsRxFifoLevel = 20UL,
70 #elif defined(COMPONENT_CAT2)
71 	.rtsRxFifoLevel = 3UL,
72 #endif
73 	.rtsPolarity = CY_SCB_UART_ACTIVE_LOW,
74 
75 	/* Level triggers when at least one element is in FIFO */
76 	.rxFifoTriggerLevel = 0UL,
77 	.rxFifoIntEnableMask = 0x0UL,
78 
79 	/* Level triggers when half-fifo is half empty */
80 	.txFifoTriggerLevel = (CY_SCB_FIFO_SIZE / 2 - 1),
81 	.txFifoIntEnableMask = 0x0UL
82 };
83 
84 /* Helper API */
_convert_uart_parity_z_to_cyhal(enum uart_config_parity parity)85 static cyhal_uart_parity_t _convert_uart_parity_z_to_cyhal(enum uart_config_parity parity)
86 {
87 	cyhal_uart_parity_t cyhal_parity;
88 
89 	switch (parity) {
90 	case UART_CFG_PARITY_NONE:
91 		cyhal_parity = CYHAL_UART_PARITY_NONE;
92 		break;
93 	case UART_CFG_PARITY_ODD:
94 		cyhal_parity = CYHAL_UART_PARITY_ODD;
95 		break;
96 	case UART_CFG_PARITY_EVEN:
97 		cyhal_parity = CYHAL_UART_PARITY_EVEN;
98 		break;
99 	default:
100 		cyhal_parity = CYHAL_UART_PARITY_NONE;
101 	}
102 	return cyhal_parity;
103 }
104 
_convert_uart_stop_bits_z_to_cyhal(enum uart_config_stop_bits stop_bits)105 static uint32_t _convert_uart_stop_bits_z_to_cyhal(enum uart_config_stop_bits stop_bits)
106 {
107 	uint32_t cyhal_stop_bits;
108 
109 	switch (stop_bits) {
110 	case UART_CFG_STOP_BITS_1:
111 		cyhal_stop_bits = 1u;
112 		break;
113 
114 	case UART_CFG_STOP_BITS_2:
115 		cyhal_stop_bits = 2u;
116 		break;
117 	default:
118 		cyhal_stop_bits = 1u;
119 	}
120 	return cyhal_stop_bits;
121 }
122 
_convert_uart_data_bits_z_to_cyhal(enum uart_config_data_bits data_bits)123 static uint32_t _convert_uart_data_bits_z_to_cyhal(enum uart_config_data_bits data_bits)
124 {
125 	uint32_t cyhal_data_bits;
126 
127 	switch (data_bits) {
128 	case UART_CFG_DATA_BITS_5:
129 		cyhal_data_bits = 1u;
130 		break;
131 
132 	case UART_CFG_DATA_BITS_6:
133 		cyhal_data_bits = 6u;
134 		break;
135 
136 	case UART_CFG_DATA_BITS_7:
137 		cyhal_data_bits = 7u;
138 		break;
139 
140 	case UART_CFG_DATA_BITS_8:
141 		cyhal_data_bits = 8u;
142 		break;
143 
144 	case UART_CFG_DATA_BITS_9:
145 		cyhal_data_bits = 9u;
146 		break;
147 
148 	default:
149 		cyhal_data_bits = 1u;
150 	}
151 	return cyhal_data_bits;
152 }
153 
_get_hw_block_num(CySCB_Type * reg_addr)154 static int32_t _get_hw_block_num(CySCB_Type *reg_addr)
155 {
156 	uint32_t i;
157 
158 	for (i = 0u; i < _SCB_ARRAY_SIZE; i++) {
159 		if (_CYHAL_SCB_BASE_ADDRESSES[i] == reg_addr) {
160 			return i;
161 		}
162 	}
163 
164 	return -1;
165 }
166 
ifx_cat1_uart_poll_in(const struct device * dev,unsigned char * c)167 static int ifx_cat1_uart_poll_in(const struct device *dev, unsigned char *c)
168 {
169 	cy_rslt_t rec;
170 	struct ifx_cat1_uart_data *data = dev->data;
171 
172 	rec = cyhal_uart_getc(&data->obj, c, 0u);
173 
174 	return ((rec == CY_SCB_UART_RX_NO_DATA) ? -1 : 0);
175 }
176 
ifx_cat1_uart_poll_out(const struct device * dev,unsigned char c)177 static void ifx_cat1_uart_poll_out(const struct device *dev, unsigned char c)
178 {
179 	struct ifx_cat1_uart_data *data = dev->data;
180 
181 	(void) cyhal_uart_putc(&data->obj, (uint32_t)c);
182 }
183 
ifx_cat1_uart_err_check(const struct device * dev)184 static int ifx_cat1_uart_err_check(const struct device *dev)
185 {
186 	struct ifx_cat1_uart_data *data = dev->data;
187 	uint32_t status = Cy_SCB_UART_GetRxFifoStatus(data->obj.base);
188 	int errors = 0;
189 
190 	if (status & CY_SCB_UART_RX_OVERFLOW) {
191 		errors |= UART_ERROR_OVERRUN;
192 	}
193 
194 	if (status & CY_SCB_UART_RX_ERR_PARITY) {
195 		errors |= UART_ERROR_PARITY;
196 	}
197 
198 	if (status & CY_SCB_UART_RX_ERR_FRAME) {
199 		errors |= UART_ERROR_FRAMING;
200 	}
201 
202 	return errors;
203 }
204 
ifx_cat1_uart_configure(const struct device * dev,const struct uart_config * cfg)205 static int ifx_cat1_uart_configure(const struct device *dev,
206 				   const struct uart_config *cfg)
207 {
208 	__ASSERT_NO_MSG(cfg != NULL);
209 
210 	cy_rslt_t result;
211 	struct ifx_cat1_uart_data *data = dev->data;
212 
213 	cyhal_uart_cfg_t uart_cfg = {
214 		.data_bits = _convert_uart_data_bits_z_to_cyhal(cfg->data_bits),
215 		.stop_bits = _convert_uart_stop_bits_z_to_cyhal(cfg->stop_bits),
216 		.parity = _convert_uart_parity_z_to_cyhal(cfg->parity)
217 	};
218 
219 	/* Store Uart Zephyr configuration (uart config) into data structure */
220 	data->cfg = *cfg;
221 
222 	/* Configure parity, data and stop bits */
223 	result = cyhal_uart_configure(&data->obj, &uart_cfg);
224 
225 	/* Configure the baud rate */
226 	if (result == CY_RSLT_SUCCESS) {
227 		result = cyhal_uart_set_baud(&data->obj, cfg->baudrate, NULL);
228 	}
229 
230 	/* Set RTS/CTS flow control pins as NC so cyhal will skip initialization */
231 	data->obj.pin_cts = NC;
232 	data->obj.pin_rts = NC;
233 
234 	/* Enable RTS/CTS flow control */
235 	if ((result == CY_RSLT_SUCCESS) && cfg->flow_ctrl) {
236 		Cy_SCB_UART_EnableCts(data->obj.base);
237 	}
238 
239 	return (result == CY_RSLT_SUCCESS) ? 0 : -ENOTSUP;
240 };
241 
ifx_cat1_uart_config_get(const struct device * dev,struct uart_config * cfg)242 static int ifx_cat1_uart_config_get(const struct device *dev,
243 				    struct uart_config *cfg)
244 {
245 	ARG_UNUSED(dev);
246 
247 	struct ifx_cat1_uart_data *const data = dev->data;
248 
249 	if (cfg == NULL) {
250 		return -EINVAL;
251 	}
252 
253 	*cfg = data->cfg;
254 	return 0;
255 }
256 
257 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
258 
259 /* Uart event callback for Interrupt driven mode */
_uart_event_callback_irq_mode(void * arg,cyhal_uart_event_t event)260 static void _uart_event_callback_irq_mode(void *arg, cyhal_uart_event_t event)
261 {
262 	ARG_UNUSED(event);
263 
264 	const struct device *dev = (const struct device *) arg;
265 	struct ifx_cat1_uart_data *const data = dev->data;
266 
267 	if (data->irq_cb != NULL) {
268 		data->irq_cb(dev, data->irq_cb_data);
269 	}
270 }
271 
272 /* Fill FIFO with data */
ifx_cat1_uart_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)273 static int ifx_cat1_uart_fifo_fill(const struct device *dev,
274 				   const uint8_t *tx_data, int size)
275 {
276 	struct ifx_cat1_uart_data *const data = dev->data;
277 	size_t _size = (size_t) size;
278 
279 	(void)cyhal_uart_write(&data->obj, (uint8_t *) tx_data,  &_size);
280 	return (int) _size;
281 }
282 
283 /* Read data from FIFO */
ifx_cat1_uart_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)284 static int ifx_cat1_uart_fifo_read(const struct device *dev,
285 				   uint8_t *rx_data, const int size)
286 {
287 	struct ifx_cat1_uart_data *const data = dev->data;
288 	size_t _size = (size_t) size;
289 
290 	(void)cyhal_uart_read(&data->obj, rx_data, &_size);
291 	return (int) _size;
292 }
293 
294 /* Enable TX interrupt */
ifx_cat1_uart_irq_tx_enable(const struct device * dev)295 static void ifx_cat1_uart_irq_tx_enable(const struct device *dev)
296 {
297 	struct ifx_cat1_uart_data *const data = dev->data;
298 	const struct ifx_cat1_uart_config *const config = dev->config;
299 
300 	cyhal_uart_enable_event(&data->obj,
301 				(cyhal_uart_event_t) CYHAL_UART_IRQ_TX_EMPTY,
302 				config->irq_priority, 1);
303 }
304 
305 /* Disable TX interrupt */
ifx_cat1_uart_irq_tx_disable(const struct device * dev)306 static void ifx_cat1_uart_irq_tx_disable(const struct device *dev)
307 {
308 	struct ifx_cat1_uart_data *const data = dev->data;
309 	const struct ifx_cat1_uart_config *const config = dev->config;
310 
311 	cyhal_uart_enable_event(&data->obj,
312 				(cyhal_uart_event_t) CYHAL_UART_IRQ_TX_EMPTY,
313 				config->irq_priority, 0);
314 }
315 
316 /* Check if UART TX buffer can accept a new char */
ifx_cat1_uart_irq_tx_ready(const struct device * dev)317 static int ifx_cat1_uart_irq_tx_ready(const struct device *dev)
318 {
319 	struct ifx_cat1_uart_data *const data = dev->data;
320 	uint32_t mask = Cy_SCB_GetTxInterruptStatusMasked(data->obj.base);
321 
322 	return (((mask & (CY_SCB_UART_TX_NOT_FULL | SCB_INTR_TX_EMPTY_Msk)) != 0u) ? 1 : 0);
323 }
324 
325 /* Check if UART TX block finished transmission */
ifx_cat1_uart_irq_tx_complete(const struct device * dev)326 static int ifx_cat1_uart_irq_tx_complete(const struct device *dev)
327 {
328 	struct ifx_cat1_uart_data *const data = dev->data;
329 
330 	return (int) !(cyhal_uart_is_tx_active(&data->obj));
331 }
332 
333 /* Enable RX interrupt */
ifx_cat1_uart_irq_rx_enable(const struct device * dev)334 static void ifx_cat1_uart_irq_rx_enable(const struct device *dev)
335 {
336 	struct ifx_cat1_uart_data *const data = dev->data;
337 	const struct ifx_cat1_uart_config *const config = dev->config;
338 
339 	cyhal_uart_enable_event(&data->obj,
340 				(cyhal_uart_event_t) CYHAL_UART_IRQ_RX_NOT_EMPTY,
341 				config->irq_priority, 1);
342 }
343 
344 /* Disable TX interrupt */
ifx_cat1_uart_irq_rx_disable(const struct device * dev)345 static void ifx_cat1_uart_irq_rx_disable(const struct device *dev)
346 {
347 	struct ifx_cat1_uart_data *const data = dev->data;
348 	const struct ifx_cat1_uart_config *const config = dev->config;
349 
350 	cyhal_uart_enable_event(&data->obj,
351 				(cyhal_uart_event_t) CYHAL_UART_IRQ_RX_NOT_EMPTY,
352 				config->irq_priority, 0);
353 }
354 
355 /* Check if UART RX buffer has a received char */
ifx_cat1_uart_irq_rx_ready(const struct device * dev)356 static int ifx_cat1_uart_irq_rx_ready(const struct device *dev)
357 {
358 	struct ifx_cat1_uart_data *const data = dev->data;
359 
360 	return cyhal_uart_readable(&data->obj) ? 1 : 0;
361 }
362 
363 /* Enable Error interrupts */
ifx_cat1_uart_irq_err_enable(const struct device * dev)364 static void ifx_cat1_uart_irq_err_enable(const struct device *dev)
365 {
366 	struct ifx_cat1_uart_data *const data = dev->data;
367 	const struct ifx_cat1_uart_config *const config = dev->config;
368 
369 	cyhal_uart_enable_event(&data->obj, (cyhal_uart_event_t)
370 				(CYHAL_UART_IRQ_TX_ERROR | CYHAL_UART_IRQ_RX_ERROR),
371 				config->irq_priority, 1);
372 }
373 
374 /* Disable Error interrupts */
ifx_cat1_uart_irq_err_disable(const struct device * dev)375 static void ifx_cat1_uart_irq_err_disable(const struct device *dev)
376 {
377 	struct ifx_cat1_uart_data *const data = dev->data;
378 	const struct ifx_cat1_uart_config *const config = dev->config;
379 
380 	cyhal_uart_enable_event(&data->obj, (cyhal_uart_event_t)
381 				(CYHAL_UART_IRQ_TX_ERROR | CYHAL_UART_IRQ_RX_ERROR),
382 				config->irq_priority, 0);
383 }
384 
385 /* Check if any IRQs is pending */
ifx_cat1_uart_irq_is_pending(const struct device * dev)386 static int ifx_cat1_uart_irq_is_pending(const struct device *dev)
387 {
388 	struct ifx_cat1_uart_data *const data = dev->data;
389 	uint32_t intcause = Cy_SCB_GetInterruptCause(data->obj.base);
390 
391 	return (int) (intcause & (CY_SCB_TX_INTR | CY_SCB_RX_INTR));
392 }
393 
394 /* Start processing interrupts in ISR.
395  * This function should be called the first thing in the ISR. Calling
396  * uart_irq_rx_ready(), uart_irq_tx_ready(), uart_irq_tx_complete()
397  * allowed only after this.
398  */
ifx_cat1_uart_irq_update(const struct device * dev)399 static int ifx_cat1_uart_irq_update(const struct device *dev)
400 {
401 	struct ifx_cat1_uart_data *const data = dev->data;
402 	int status = 1;
403 
404 	if (((ifx_cat1_uart_irq_is_pending(dev) & CY_SCB_RX_INTR) != 0u) &&
405 	    (Cy_SCB_UART_GetNumInRxFifo(data->obj.base) == 0u)) {
406 		status = 0;
407 	}
408 
409 	return status;
410 }
411 
ifx_cat1_uart_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)412 static void ifx_cat1_uart_irq_callback_set(const struct device *dev,
413 					   uart_irq_callback_user_data_t cb,
414 					   void *cb_data)
415 {
416 	struct ifx_cat1_uart_data *data = dev->data;
417 	cyhal_uart_t *uart_obj = &data->obj;
418 
419 	/* Store user callback info */
420 	data->irq_cb = cb;
421 	data->irq_cb_data = cb_data;
422 
423 	/* Register a uart general callback handler  */
424 	cyhal_uart_register_callback(uart_obj, _uart_event_callback_irq_mode, (void *) dev);
425 }
426 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
427 
428 
ifx_cat1_uart_init(const struct device * dev)429 static int ifx_cat1_uart_init(const struct device *dev)
430 {
431 	struct ifx_cat1_uart_data *const data = dev->data;
432 	const struct ifx_cat1_uart_config *const config = dev->config;
433 	cy_rslt_t result;
434 	int ret;
435 
436 	cyhal_uart_configurator_t uart_init_cfg = {
437 		.resource = &data->hw_resource,
438 		.config = &_cyhal_uart_default_config,
439 		.clock = &data->clock,
440 		.gpios = {
441 			.pin_tx  = NC,
442 			.pin_rts = NC,
443 			.pin_cts = NC,
444 		},
445 	};
446 
447 	/* Dedicate SCB HW resource */
448 	data->hw_resource.type = CYHAL_RSC_SCB;
449 	data->hw_resource.block_num = _get_hw_block_num(config->reg_addr);
450 
451 	/* Configure dt provided device signals when available */
452 	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
453 	if (ret < 0) {
454 		return ret;
455 	}
456 
457 	/* Allocates clock for selected IP block */
458 	result = _cyhal_utils_allocate_clock(&data->clock, &data->hw_resource,
459 					     CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
460 	if (result != CY_RSLT_SUCCESS) {
461 		return -ENOTSUP;
462 	}
463 
464 	/* Assigns a programmable divider to a selected IP block */
465 	en_clk_dst_t clk_idx = _cyhal_scb_get_clock_index(uart_init_cfg.resource->block_num);
466 
467 	result = _cyhal_utils_peri_pclk_assign_divider(clk_idx, uart_init_cfg.clock);
468 	if (result != CY_RSLT_SUCCESS) {
469 		return -ENOTSUP;
470 	}
471 
472 	/* Initialize the UART peripheral */
473 	result = cyhal_uart_init_cfg(&data->obj, &uart_init_cfg);
474 	if (result != CY_RSLT_SUCCESS) {
475 		return -ENOTSUP;
476 	}
477 
478 	/* Perform initial Uart configuration */
479 	data->obj.is_clock_owned = true;
480 	ret = ifx_cat1_uart_configure(dev, &config->dt_cfg);
481 
482 	return ret;
483 }
484 
485 static DEVICE_API(uart, ifx_cat1_uart_driver_api) = {
486 	.poll_in = ifx_cat1_uart_poll_in,
487 	.poll_out = ifx_cat1_uart_poll_out,
488 	.err_check = ifx_cat1_uart_err_check,
489 
490 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
491 	.configure = ifx_cat1_uart_configure,
492 	.config_get = ifx_cat1_uart_config_get,
493 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
494 
495 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
496 	.fifo_fill = ifx_cat1_uart_fifo_fill,
497 	.fifo_read = ifx_cat1_uart_fifo_read,
498 	.irq_tx_enable = ifx_cat1_uart_irq_tx_enable,
499 	.irq_tx_disable = ifx_cat1_uart_irq_tx_disable,
500 	.irq_tx_ready = ifx_cat1_uart_irq_tx_ready,
501 	.irq_rx_enable = ifx_cat1_uart_irq_rx_enable,
502 	.irq_rx_disable = ifx_cat1_uart_irq_rx_disable,
503 	.irq_tx_complete = ifx_cat1_uart_irq_tx_complete,
504 	.irq_rx_ready = ifx_cat1_uart_irq_rx_ready,
505 	.irq_err_enable = ifx_cat1_uart_irq_err_enable,
506 	.irq_err_disable = ifx_cat1_uart_irq_err_disable,
507 	.irq_is_pending = ifx_cat1_uart_irq_is_pending,
508 	.irq_update = ifx_cat1_uart_irq_update,
509 	.irq_callback_set = ifx_cat1_uart_irq_callback_set,
510 #endif    /* CONFIG_UART_INTERRUPT_DRIVEN */
511 };
512 
513 #define INFINEON_CAT1_UART_INIT(n)							     \
514 	PINCTRL_DT_INST_DEFINE(n);							     \
515 	static struct ifx_cat1_uart_data ifx_cat1_uart##n##_data;			     \
516 											     \
517 	static struct ifx_cat1_uart_config ifx_cat1_uart##n##_cfg = {			     \
518 		.dt_cfg.baudrate = DT_INST_PROP(n, current_speed),			     \
519 		.dt_cfg.parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE),	     \
520 		.dt_cfg.stop_bits = DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \
521 		.dt_cfg.data_bits = DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \
522 		.dt_cfg.flow_ctrl = DT_INST_PROP(n, hw_flow_control),			     \
523 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),				     \
524 		.reg_addr = (CySCB_Type *)DT_INST_REG_ADDR(n),				     \
525 		.irq_priority = DT_INST_IRQ(n, priority)				     \
526 	};										     \
527 											     \
528 	DEVICE_DT_INST_DEFINE(n,							     \
529 			      ifx_cat1_uart_init, NULL,					     \
530 			      &ifx_cat1_uart##n##_data,					     \
531 			      &ifx_cat1_uart##n##_cfg, PRE_KERNEL_1,			     \
532 			      CONFIG_SERIAL_INIT_PRIORITY,				     \
533 			      &ifx_cat1_uart_driver_api);
534 
535 DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_UART_INIT)
536