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