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