1 /*
2  * Copyright 2022-2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_s32_linflexd
8 
9 #include <soc.h>
10 #include <zephyr/irq.h>
11 #include <zephyr/drivers/uart.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/drivers/clock_control.h>
14 
15 #include <Linflexd_Uart_Ip.h>
16 #include <Linflexd_Uart_Ip_Irq.h>
17 #include "uart_nxp_s32_linflexd.h"
18 
uart_nxp_s32_err_check(const struct device * dev)19 static int uart_nxp_s32_err_check(const struct device *dev)
20 {
21 	const struct uart_nxp_s32_config *config = dev->config;
22 	Linflexd_Uart_Ip_StatusType status;
23 	int err = 0;
24 
25 	status = Linflexd_Uart_Ip_GetReceiveStatus(config->instance, NULL);
26 
27 	if (status == LINFLEXD_UART_IP_STATUS_RX_OVERRUN) {
28 		err |= UART_ERROR_OVERRUN;
29 	}
30 
31 	if (status == LINFLEXD_UART_IP_STATUS_PARITY_ERROR) {
32 		err |= UART_ERROR_PARITY;
33 	}
34 
35 	if (status == LINFLEXD_UART_IP_STATUS_FRAMING_ERROR) {
36 		err |= UART_ERROR_FRAMING;
37 	}
38 
39 	return err;
40 }
41 
uart_nxp_s32_poll_out(const struct device * dev,unsigned char c)42 static void uart_nxp_s32_poll_out(const struct device *dev, unsigned char c)
43 {
44 	const struct uart_nxp_s32_config *config = dev->config;
45 	uint32_t linflexd_ier;
46 	uint8_t key;
47 
48 	key = irq_lock();
49 
50 	/* Save enabled Linflexd's interrupts */
51 	linflexd_ier = sys_read32(POINTER_TO_UINT(&config->base->LINIER));
52 
53 	Linflexd_Uart_Ip_SyncSend(config->instance, &c, 1,
54 				  CONFIG_UART_NXP_S32_POLL_OUT_TIMEOUT);
55 
56 	/* Restore Linflexd's interrupts */
57 	sys_write32(linflexd_ier, POINTER_TO_UINT(&config->base->LINIER));
58 
59 	irq_unlock(key);
60 }
61 
uart_nxp_s32_poll_in(const struct device * dev,unsigned char * c)62 static int uart_nxp_s32_poll_in(const struct device *dev, unsigned char *c)
63 {
64 	const struct uart_nxp_s32_config *config = dev->config;
65 	Linflexd_Uart_Ip_StatusType status;
66 	uint32_t linflexd_ier;
67 	int ret;
68 
69 	status = LINFLEXD_UART_IP_STATUS_SUCCESS;
70 
71 	/* Save enabled Linflexd's interrupts */
72 	linflexd_ier = sys_read32(POINTER_TO_UINT(&config->base->LINIER));
73 
74 	/* Retrieves data with poll method */
75 	status = Linflexd_Uart_Ip_SyncReceive(config->instance, c, 1,
76 					      CONFIG_UART_NXP_S32_POLL_IN_TIMEOUT);
77 
78 	/* Restore Linflexd's interrupts */
79 	sys_write32(linflexd_ier, POINTER_TO_UINT(&config->base->LINIER));
80 
81 	if (status == LINFLEXD_UART_IP_STATUS_SUCCESS) {
82 		ret = 0;
83 	} else if (status == LINFLEXD_UART_IP_STATUS_TIMEOUT) {
84 		ret = -1;
85 	} else {
86 		ret = -EBUSY;
87 	}
88 
89 	return ret;
90 }
91 
92 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
93 
uart_nxp_s32_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)94 static int uart_nxp_s32_fifo_fill(const struct device *dev, const uint8_t *tx_data,
95 				  int size)
96 {
97 	const struct uart_nxp_s32_config *config = dev->config;
98 	struct uart_nxp_s32_data *data = dev->data;
99 	struct uart_nxp_s32_int *int_data = &(data->int_data);
100 
101 	if (int_data->tx_fifo_busy) {
102 		return 0;
103 	}
104 
105 	int_data->tx_fifo_busy = true;
106 
107 	Linflexd_Uart_Ip_AsyncSend(config->instance, tx_data, 1);
108 
109 	return 1;
110 }
111 
uart_nxp_s32_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)112 static int uart_nxp_s32_fifo_read(const struct device *dev, uint8_t *rx_data,
113 				  const int size)
114 {
115 	const struct uart_nxp_s32_config *config = dev->config;
116 	struct uart_nxp_s32_data *data = dev->data;
117 	struct uart_nxp_s32_int *int_data = &(data->int_data);
118 
119 	if (int_data->rx_fifo_busy) {
120 		return 0;
121 	}
122 
123 	*rx_data = int_data->rx_fifo_data;
124 	int_data->rx_fifo_busy = true;
125 
126 	Linflexd_Uart_Ip_SetRxBuffer(config->instance, &(int_data->rx_fifo_data), 1);
127 
128 	return 1;
129 }
130 
uart_nxp_s32_irq_tx_enable(const struct device * dev)131 static void uart_nxp_s32_irq_tx_enable(const struct device *dev)
132 {
133 
134 	struct uart_nxp_s32_data *data = dev->data;
135 	struct uart_nxp_s32_int *int_data = &(data->int_data);
136 	uint8_t key;
137 
138 	int_data->irq_tx_enable = true;
139 
140 	key = irq_lock();
141 
142 	/* Callback is called in order to transmit the data */
143 	if (!int_data->tx_fifo_busy) {
144 
145 		if (data->callback) {
146 			data->callback(dev, data->cb_data);
147 		}
148 	}
149 
150 	irq_unlock(key);
151 }
152 
uart_nxp_s32_irq_tx_disable(const struct device * dev)153 static void uart_nxp_s32_irq_tx_disable(const struct device *dev)
154 {
155 	const struct uart_nxp_s32_config *config = dev->config;
156 	struct uart_nxp_s32_data *data = dev->data;
157 	struct uart_nxp_s32_int *int_data = &(data->int_data);
158 
159 	int_data->irq_tx_enable = false;
160 	int_data->tx_fifo_busy  = false;
161 
162 	Linflexd_Uart_Ip_AbortSendingData(config->instance);
163 }
164 
uart_nxp_s32_irq_tx_ready(const struct device * dev)165 static int uart_nxp_s32_irq_tx_ready(const struct device *dev)
166 {
167 	struct uart_nxp_s32_data *data = dev->data;
168 	struct uart_nxp_s32_int *int_data = &(data->int_data);
169 
170 	return !int_data->tx_fifo_busy && int_data->irq_tx_enable;
171 }
172 
uart_nxp_s32_irq_rx_enable(const struct device * dev)173 static void uart_nxp_s32_irq_rx_enable(const struct device *dev)
174 {
175 	const struct uart_nxp_s32_config *config = dev->config;
176 	struct uart_nxp_s32_data *data = dev->data;
177 	struct uart_nxp_s32_int *int_data = &(data->int_data);
178 
179 	int_data->irq_rx_enable = true;
180 
181 	Linflexd_Uart_Ip_AsyncReceive(config->instance, &(int_data->rx_fifo_data), 1);
182 }
183 
uart_nxp_s32_irq_rx_disable(const struct device * dev)184 static void uart_nxp_s32_irq_rx_disable(const struct device *dev)
185 {
186 	const struct uart_nxp_s32_config *config = dev->config;
187 	struct uart_nxp_s32_data *data = dev->data;
188 	struct uart_nxp_s32_int *int_data = &(data->int_data);
189 
190 	int_data->irq_rx_enable = false;
191 	int_data->rx_fifo_busy = false;
192 
193 	Linflexd_Uart_Ip_AbortReceivingData(config->instance);
194 }
195 
uart_nxp_s32_irq_rx_ready(const struct device * dev)196 static int uart_nxp_s32_irq_rx_ready(const struct device *dev)
197 {
198 	struct uart_nxp_s32_data *data = dev->data;
199 	struct uart_nxp_s32_int *int_data = &(data->int_data);
200 
201 	return !int_data->rx_fifo_busy && int_data->irq_rx_enable;
202 }
203 
uart_nxp_s32_irq_err_enable(const struct device * dev)204 static void uart_nxp_s32_irq_err_enable(const struct device *dev)
205 {
206 	const struct uart_nxp_s32_config *config = dev->config;
207 	uint32_t linflexd_ier;
208 
209 	linflexd_ier = sys_read32(POINTER_TO_UINT(&config->base->LINIER));
210 
211 	/* Enable frame error interrupt and buffer overrun error interrupt */
212 	linflexd_ier |= (LINFLEXD_LINIER_FEIE_MASK | LINFLEXD_LINIER_BOIE_MASK);
213 
214 	sys_write32(linflexd_ier, POINTER_TO_UINT(&config->base->LINIER));
215 }
216 
uart_nxp_s32_irq_err_disable(const struct device * dev)217 static void uart_nxp_s32_irq_err_disable(const struct device *dev)
218 {
219 	const struct uart_nxp_s32_config *config = dev->config;
220 	uint32_t linflexd_ier;
221 
222 	linflexd_ier = sys_read32(POINTER_TO_UINT(&config->base->LINIER));
223 
224 	/* Disable frame error interrupt and buffer overrun error interrupt */
225 	linflexd_ier &= ~(LINFLEXD_LINIER_FEIE_MASK | LINFLEXD_LINIER_BOIE_MASK);
226 
227 	sys_write32(linflexd_ier, POINTER_TO_UINT(&config->base->LINIER));
228 }
229 
uart_nxp_s32_irq_is_pending(const struct device * dev)230 static int uart_nxp_s32_irq_is_pending(const struct device *dev)
231 {
232 	return (uart_nxp_s32_irq_tx_ready(dev)) || (uart_nxp_s32_irq_rx_ready(dev));
233 }
234 
uart_nxp_s32_irq_update(const struct device * dev)235 static int uart_nxp_s32_irq_update(const struct device *dev)
236 {
237 	return 1;
238 }
239 
uart_nxp_s32_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)240 static void uart_nxp_s32_irq_callback_set(const struct device *dev,
241 				      uart_irq_callback_user_data_t cb,
242 				      void *cb_data)
243 {
244 	struct uart_nxp_s32_data *data = dev->data;
245 
246 	data->callback = cb;
247 	data->cb_data = cb_data;
248 }
249 
uart_nxp_s32_isr(const struct device * dev)250 void uart_nxp_s32_isr(const struct device *dev)
251 {
252 	const struct uart_nxp_s32_config *config = dev->config;
253 
254 	Linflexd_Uart_Ip_IRQHandler(config->instance);
255 }
256 
uart_nxp_s32_event_handler(const uint8 instance,Linflexd_Uart_Ip_EventType event,const void * user_data)257 static void uart_nxp_s32_event_handler(const uint8 instance,
258 				       Linflexd_Uart_Ip_EventType event,
259 				       const void *user_data)
260 {
261 	const struct device *dev = (const struct device *)user_data;
262 	const struct uart_nxp_s32_config *config = dev->config;
263 	struct uart_nxp_s32_data *data = dev->data;
264 	struct uart_nxp_s32_int *int_data = &(data->int_data);
265 	Linflexd_Uart_Ip_StatusType status;
266 
267 	if (event == LINFLEXD_UART_IP_EVENT_END_TRANSFER) {
268 		/*
269 		 * Check the previous UART transmit has	finished
270 		 * because Rx may also trigger this event
271 		 */
272 		status = Linflexd_Uart_Ip_GetTransmitStatus(config->instance, NULL);
273 		if (status != LINFLEXD_UART_IP_STATUS_BUSY) {
274 			int_data->tx_fifo_busy = false;
275 			if (data->callback) {
276 				data->callback(dev, data->cb_data);
277 			}
278 		}
279 	} else if (event == LINFLEXD_UART_IP_EVENT_RX_FULL) {
280 		int_data->rx_fifo_busy = false;
281 		if (data->callback) {
282 			data->callback(dev, data->cb_data);
283 		}
284 	} else if (event == LINFLEXD_UART_IP_EVENT_ERROR) {
285 		if (data->callback) {
286 			data->callback(dev, data->cb_data);
287 		}
288 	} else {
289 		/* Other events are not used */
290 	}
291 }
292 
293 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
294 
uart_nxp_s32_init(const struct device * dev)295 static int uart_nxp_s32_init(const struct device *dev)
296 {
297 	const struct uart_nxp_s32_config *config = dev->config;
298 	int err;
299 	uint32_t clock_rate;
300 	Linflexd_Uart_Ip_StatusType status;
301 
302 	err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
303 	if (err < 0) {
304 		return err;
305 	}
306 
307 	if (!device_is_ready(config->clock_dev)) {
308 		return -ENODEV;
309 	}
310 
311 	err = clock_control_on(config->clock_dev, config->clock_subsys);
312 	if (err) {
313 		return err;
314 	}
315 
316 	err = clock_control_get_rate(config->clock_dev, config->clock_subsys, &clock_rate);
317 	if (err) {
318 		return err;
319 	}
320 
321 	Linflexd_Uart_Ip_Init(config->instance, &config->hw_cfg);
322 
323 	status = Linflexd_Uart_Ip_SetBaudrate(config->instance, config->hw_cfg.BaudRate,
324 					      clock_rate);
325 	if (status != LINFLEXD_UART_IP_STATUS_SUCCESS) {
326 		return -EIO;
327 	}
328 
329 	return 0;
330 }
331 
332 static DEVICE_API(uart, uart_nxp_s32_driver_api) = {
333 	.poll_in	  = uart_nxp_s32_poll_in,
334 	.poll_out	  = uart_nxp_s32_poll_out,
335 	.err_check	  = uart_nxp_s32_err_check,
336 
337 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
338 	.fifo_fill	  = uart_nxp_s32_fifo_fill,
339 	.fifo_read	  = uart_nxp_s32_fifo_read,
340 	.irq_tx_enable	  = uart_nxp_s32_irq_tx_enable,
341 	.irq_tx_disable   = uart_nxp_s32_irq_tx_disable,
342 	.irq_tx_ready	  = uart_nxp_s32_irq_tx_ready,
343 	.irq_rx_enable	  = uart_nxp_s32_irq_rx_enable,
344 	.irq_rx_disable   = uart_nxp_s32_irq_rx_disable,
345 	.irq_rx_ready	  = uart_nxp_s32_irq_rx_ready,
346 	.irq_err_enable   = uart_nxp_s32_irq_err_enable,
347 	.irq_err_disable  = uart_nxp_s32_irq_err_disable,
348 	.irq_is_pending   = uart_nxp_s32_irq_is_pending,
349 	.irq_update	  = uart_nxp_s32_irq_update,
350 	.irq_callback_set = uart_nxp_s32_irq_callback_set,
351 #endif	/* CONFIG_UART_INTERRUPT_DRIVEN */
352 
353 };
354 
355 #define UART_NXP_S32_HW_INSTANCE_CHECK(i, n) \
356 	((DT_INST_REG_ADDR(n) == IP_LINFLEX_##i##_BASE) ? i : 0)
357 
358 #define UART_NXP_S32_HW_INSTANCE(n) \
359 	LISTIFY(__DEBRACKET LINFLEXD_INSTANCE_COUNT, UART_NXP_S32_HW_INSTANCE_CHECK, (|), n)
360 
361 #define UART_NXP_S32_INTERRUPT_DEFINE(n)					\
362 	do {									\
363 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),		\
364 			uart_nxp_s32_isr, DEVICE_DT_INST_GET(n),		\
365 			DT_INST_IRQ(n, flags));					\
366 		irq_enable(DT_INST_IRQN(n));					\
367 	} while (0)
368 
369 #define UART_NXP_S32_HW_CONFIG(n)						\
370 	{									\
371 		.BaudRate = DT_INST_PROP(n, current_speed),			\
372 		.BaudRateMantissa = 26U,					\
373 		.BaudRateDivisor = 16U,						\
374 		.BaudRateFractionalDivisor = 1U,				\
375 		.ParityCheck = DT_INST_ENUM_IDX(n, parity) ==			\
376 				UART_CFG_PARITY_NONE ? false : true,		\
377 		.ParityType = DT_INST_ENUM_IDX(n, parity) ==			\
378 					UART_CFG_PARITY_ODD ?			\
379 				LINFLEXD_UART_IP_PARITY_ODD :			\
380 				(DT_INST_ENUM_IDX(n, parity) ==			\
381 						UART_CFG_PARITY_EVEN ?		\
382 					LINFLEXD_UART_IP_PARITY_ONE :		\
383 					(DT_INST_ENUM_IDX(n, parity) ==		\
384 							UART_CFG_PARITY_MARK ?	\
385 						LINFLEXD_UART_IP_PARITY_EVEN :	\
386 						LINFLEXD_UART_IP_PARITY_ZERO)),	\
387 		.StopBitsCount = DT_INST_ENUM_IDX(n, stop_bits) ==		\
388 						UART_CFG_STOP_BITS_1 ?		\
389 					LINFLEXD_UART_IP_ONE_STOP_BIT :		\
390 					LINFLEXD_UART_IP_TWO_STOP_BIT,		\
391 		.WordLength = DT_INST_ENUM_IDX(n, data_bits) ==			\
392 						UART_CFG_DATA_BITS_7 ?		\
393 					LINFLEXD_UART_IP_7_BITS	:		\
394 					LINFLEXD_UART_IP_8_BITS,		\
395 		.TransferType = LINFLEXD_UART_IP_USING_INTERRUPTS,		\
396 		.StateStruct = &Linflexd_Uart_Ip_apStateStructure[n],		\
397 		IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, (			\
398 			.Callback = uart_nxp_s32_event_handler,			\
399 			.CallbackParam = (void *)DEVICE_DT_INST_GET(n),		\
400 		))								\
401 	}
402 
403 #define UART_NXP_S32_INIT_DEVICE(n)						\
404 	BUILD_ASSERT(DT_INST_ENUM_IDX(n, stop_bits) == UART_CFG_STOP_BITS_1 ||	\
405 		DT_INST_ENUM_IDX(n, stop_bits) == UART_CFG_STOP_BITS_2,		\
406 		"Node " DT_NODE_PATH(DT_DRV_INST(n))				\
407 		" has unsupported stop bits configuration");			\
408 	BUILD_ASSERT(DT_INST_ENUM_IDX(n, data_bits) == UART_CFG_DATA_BITS_7 ||	\
409 		DT_INST_ENUM_IDX(n, data_bits) == UART_CFG_DATA_BITS_8,		\
410 		"Node " DT_NODE_PATH(DT_DRV_INST(n))				\
411 		" has unsupported data bits configuration");			\
412 	BUILD_ASSERT(DT_INST_PROP(n, hw_flow_control) == UART_CFG_FLOW_CTRL_NONE,\
413 		"Node " DT_NODE_PATH(DT_DRV_INST(n))				\
414 		" has unsupported flow control configuration");			\
415 	PINCTRL_DT_INST_DEFINE(n);						\
416 	IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN,				\
417 		(static struct uart_nxp_s32_data uart_nxp_s32_data_##n;))	\
418 	static const struct uart_nxp_s32_config uart_nxp_s32_config_##n = {	\
419 		.instance = UART_NXP_S32_HW_INSTANCE(n),			\
420 		.base = (LINFLEXD_Type *)DT_INST_REG_ADDR(n),			\
421 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),			\
422 		.hw_cfg = UART_NXP_S32_HW_CONFIG(n),				\
423 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),		\
424 		.clock_subsys = (clock_control_subsys_t)			\
425 				DT_INST_CLOCKS_CELL(n, name),			\
426 	};									\
427 	static int uart_nxp_s32_init_##n(const struct device *dev)		\
428 	{									\
429 		IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN,			\
430 			(UART_NXP_S32_INTERRUPT_DEFINE(n);))			\
431 										\
432 		return uart_nxp_s32_init(dev);					\
433 	}									\
434 	DEVICE_DT_INST_DEFINE(n,						\
435 			uart_nxp_s32_init_##n,					\
436 			NULL,							\
437 			COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN,		\
438 				   (&uart_nxp_s32_data_##n), (NULL)),		\
439 			&uart_nxp_s32_config_##n,				\
440 			PRE_KERNEL_1,						\
441 			CONFIG_SERIAL_INIT_PRIORITY,				\
442 			&uart_nxp_s32_driver_api);
443 
444 DT_INST_FOREACH_STATUS_OKAY(UART_NXP_S32_INIT_DEVICE)
445