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