1
1
/*
2
2
* Copyright (c) 2018 Diego Sueiro <[email protected] >
3
+ * Copyright (c) 2022 Antonio Tessarolo <[email protected] >
4
+ * Copyright (c) 2025 Sergey Grigorovich <[email protected] >
3
5
*
4
6
* SPDX-License-Identifier: Apache-2.0
5
7
*/
23
25
#include <zephyr/drivers/pinctrl.h>
24
26
#include <zephyr/irq.h>
25
27
26
- #define UART_STRUCT (dev ) \
27
- ((UART_Type *)((const struct imx_uart_config *const)(dev)->config)->base)
28
+ #define UART_STRUCT (dev ) ((UART_Type *)((const struct imx_uart_config *const)(dev)->config)->base)
29
+
30
+ /* FIFO real size is 32 but irq may rise when there are 2 bytes in the queue */
31
+ #define UART_FIFO_SIZE 30u
28
32
29
33
struct imx_uart_config {
30
34
UART_Type * base ;
@@ -33,16 +37,27 @@ struct imx_uart_config {
33
37
const struct pinctrl_dev_config * pincfg ;
34
38
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
35
39
void (* irq_config_func )(const struct device * dev );
40
+ bool rs485_enabled ;
41
+ bool rs485_de_active_low ;
42
+ uint32_t rs485_de_timeout ;
36
43
#endif
37
44
};
38
45
39
46
struct imx_uart_data {
40
47
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
41
48
uart_irq_callback_user_data_t callback ;
42
49
void * cb_data ;
50
+ struct k_timer rs485_timer ;
43
51
#endif
44
52
};
45
53
54
+ static void rs485_de_time_expire_callback (struct k_timer * timer )
55
+ {
56
+ UART_Type * uart = k_timer_user_data_get (timer );
57
+
58
+ UART_SetIntCmd (uart , uartIntTxReady , true);
59
+ }
60
+
46
61
/**
47
62
* @brief Initialize UART channel
48
63
*
@@ -57,6 +72,7 @@ static int uart_imx_init(const struct device *dev)
57
72
{
58
73
UART_Type * uart = UART_STRUCT (dev );
59
74
const struct imx_uart_config * config = dev -> config ;
75
+ struct imx_uart_data * data = dev -> data ;
60
76
unsigned int old_level ;
61
77
int err ;
62
78
@@ -93,6 +109,12 @@ static int uart_imx_init(const struct device *dev)
93
109
config -> irq_config_func (dev );
94
110
#endif
95
111
112
+ if (config -> rs485_enabled ) {
113
+ UART_SetCtsPinLevel (uart , !config -> rs485_de_active_low );
114
+ k_timer_init (& data -> rs485_timer , rs485_de_time_expire_callback , NULL );
115
+ k_timer_user_data_set (& data -> rs485_timer , uart );
116
+ }
117
+
96
118
/* Set UART modem mode */
97
119
UART_SetModemMode (uart , config -> modem_mode );
98
120
@@ -137,11 +159,12 @@ static int uart_imx_fifo_fill(const struct device *dev,
137
159
UART_Type * uart = UART_STRUCT (dev );
138
160
unsigned int num_tx = 0U ;
139
161
140
- while (((size - num_tx ) > 0 ) &&
141
- UART_GetStatusFlag (uart , uartStatusTxReady )) {
142
- /* Send a character */
143
- UART_Putchar (uart , tx_data [num_tx ]);
144
- num_tx ++ ;
162
+ if (UART_GetStatusFlag (uart , uartStatusTxReady )) {
163
+ while (((size - num_tx ) > 0 ) && (num_tx < UART_FIFO_SIZE )) {
164
+ /* Send a character */
165
+ UART_Putchar (uart , tx_data [num_tx ]);
166
+ num_tx ++ ;
167
+ }
145
168
}
146
169
147
170
return (int )num_tx ;
@@ -169,13 +192,30 @@ static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data,
169
192
static void uart_imx_irq_tx_enable (const struct device * dev )
170
193
{
171
194
UART_Type * uart = UART_STRUCT (dev );
195
+ const struct imx_uart_config * config = dev -> config ;
196
+ struct imx_uart_data * data = dev -> data ;
172
197
173
- UART_SetIntCmd (uart , uartIntTxReady , true);
198
+ if (config -> rs485_enabled ) {
199
+ UART_SetCtsPinLevel (uart , config -> rs485_de_active_low );
200
+ if (config -> rs485_de_timeout ) {
201
+ k_timer_start (& data -> rs485_timer , K_USEC (config -> rs485_de_timeout ),
202
+ K_NO_WAIT );
203
+ } else {
204
+ UART_SetIntCmd (uart , uartIntTxReady , true);
205
+ }
206
+ } else {
207
+ UART_SetIntCmd (uart , uartIntTxReady , true);
208
+ }
174
209
}
175
210
176
211
static void uart_imx_irq_tx_disable (const struct device * dev )
177
212
{
178
213
UART_Type * uart = UART_STRUCT (dev );
214
+ const struct imx_uart_config * config = dev -> config ;
215
+
216
+ if (config -> rs485_enabled ) {
217
+ UART_SetIntCmd (uart , uartIntTxComplete , true);
218
+ }
179
219
180
220
UART_SetIntCmd (uart , uartIntTxReady , false);
181
221
}
@@ -187,9 +227,27 @@ static int uart_imx_irq_tx_ready(const struct device *dev)
187
227
return UART_GetStatusFlag (uart , uartStatusTxReady );
188
228
}
189
229
230
+ static int uart_imx_irq_tx_complete (const struct device * dev )
231
+ {
232
+ UART_Type * uart = UART_STRUCT (dev );
233
+ const struct imx_uart_config * config = dev -> config ;
234
+ bool complete = UART_GetStatusFlag (uart , uartStatusTxComplete );
235
+
236
+ if (config -> rs485_enabled && complete ) {
237
+ UART_SetIntCmd (uart , uartIntTxComplete , false);
238
+ }
239
+
240
+ return complete ;
241
+ }
242
+
190
243
static void uart_imx_irq_rx_enable (const struct device * dev )
191
244
{
192
245
UART_Type * uart = UART_STRUCT (dev );
246
+ const struct imx_uart_config * config = dev -> config ;
247
+
248
+ if (config -> rs485_enabled ) {
249
+ UART_SetCtsPinLevel (uart , !config -> rs485_de_active_low );
250
+ }
193
251
194
252
UART_SetIntCmd (uart , uartIntRxReady , true);
195
253
}
@@ -272,68 +330,64 @@ static DEVICE_API(uart, uart_imx_driver_api) = {
272
330
.poll_out = uart_imx_poll_out ,
273
331
274
332
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
275
- .fifo_fill = uart_imx_fifo_fill ,
276
- .fifo_read = uart_imx_fifo_read ,
277
- .irq_tx_enable = uart_imx_irq_tx_enable ,
278
- .irq_tx_disable = uart_imx_irq_tx_disable ,
279
- .irq_tx_ready = uart_imx_irq_tx_ready ,
280
- .irq_rx_enable = uart_imx_irq_rx_enable ,
281
- .irq_rx_disable = uart_imx_irq_rx_disable ,
282
- .irq_rx_ready = uart_imx_irq_rx_ready ,
283
- .irq_err_enable = uart_imx_irq_err_enable ,
284
- .irq_err_disable = uart_imx_irq_err_disable ,
285
- .irq_is_pending = uart_imx_irq_is_pending ,
286
- .irq_update = uart_imx_irq_update ,
333
+ .fifo_fill = uart_imx_fifo_fill ,
334
+ .fifo_read = uart_imx_fifo_read ,
335
+ .irq_tx_enable = uart_imx_irq_tx_enable ,
336
+ .irq_tx_disable = uart_imx_irq_tx_disable ,
337
+ .irq_tx_ready = uart_imx_irq_tx_ready ,
338
+ .irq_tx_complete = uart_imx_irq_tx_complete ,
339
+ .irq_rx_enable = uart_imx_irq_rx_enable ,
340
+ .irq_rx_disable = uart_imx_irq_rx_disable ,
341
+ .irq_rx_ready = uart_imx_irq_rx_ready ,
342
+ .irq_err_enable = uart_imx_irq_err_enable ,
343
+ .irq_err_disable = uart_imx_irq_err_disable ,
344
+ .irq_is_pending = uart_imx_irq_is_pending ,
345
+ .irq_update = uart_imx_irq_update ,
287
346
.irq_callback_set = uart_imx_irq_callback_set ,
288
347
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
289
348
290
349
};
291
350
292
- #define UART_IMX_DECLARE_CFG (n , IRQ_FUNC_INIT ) \
293
- static const struct imx_uart_config imx_uart_##n##_config = { \
294
- .base = (UART_Type *) DT_INST_REG_ADDR(n), \
295
- .baud_rate = DT_INST_PROP(n, current_speed), \
296
- .modem_mode = DT_INST_PROP(n, modem_mode), \
297
- .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
298
- IRQ_FUNC_INIT \
299
- }
351
+ #define UART_IMX_DECLARE_CFG (n , IRQ_FUNC_INIT ) \
352
+ static const struct imx_uart_config imx_uart_##n##_config = { \
353
+ .base = (UART_Type *)DT_INST_REG_ADDR(n), \
354
+ .baud_rate = DT_INST_PROP(n, current_speed), \
355
+ .modem_mode = DT_INST_PROP(n, modem_mode), \
356
+ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
357
+ IRQ_FUNC_INIT}
300
358
301
359
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
302
- #define UART_IMX_CONFIG_FUNC (n ) \
303
- static void irq_config_func_##n(const struct device *dev) \
304
- { \
305
- IRQ_CONNECT(DT_INST_IRQN(n), \
306
- DT_INST_IRQ(n, priority), \
307
- uart_imx_isr, \
308
- DEVICE_DT_INST_GET(n), 0); \
309
- irq_enable(DT_INST_IRQN(n)); \
360
+ #define UART_IMX_CONFIG_FUNC (n ) \
361
+ static void irq_config_func_##n(const struct device *dev) \
362
+ { \
363
+ IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_imx_isr, \
364
+ DEVICE_DT_INST_GET(n), 0); \
365
+ irq_enable(DT_INST_IRQN(n)); \
310
366
}
311
- #define UART_IMX_IRQ_CFG_FUNC_INIT (n ) \
312
- .irq_config_func = irq_config_func_##n
313
- #define UART_IMX_INIT_CFG (n ) \
314
- UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT(n))
367
+ #define UART_IMX_IRQ_CFG_FUNC_INIT (n ) \
368
+ .irq_config_func = irq_config_func_##n, .rs485_enabled = DT_INST_PROP(n, rs485_enabled), \
369
+ .rs485_de_active_low = DT_INST_PROP(n, rs485_de_active_low), \
370
+ .rs485_de_timeout = DT_INST_PROP(n, rs485_assertion_time_de_us),
371
+ #define UART_IMX_INIT_CFG (n ) UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT(n))
315
372
#else
316
373
#define UART_IMX_CONFIG_FUNC (n )
317
374
#define UART_IMX_IRQ_CFG_FUNC_INIT
318
- #define UART_IMX_INIT_CFG (n ) \
319
- UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT)
375
+ #define UART_IMX_INIT_CFG (n ) UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT)
320
376
#endif
321
377
322
- #define UART_IMX_INIT (n ) \
323
- static struct imx_uart_data imx_uart_##n##_data; \
324
- \
325
- static const struct imx_uart_config imx_uart_##n##_config; \
326
- \
327
- PINCTRL_DT_INST_DEFINE(n); \
328
- \
329
- DEVICE_DT_INST_DEFINE(n, uart_imx_init, NULL, \
330
- &imx_uart_##n##_data, &imx_uart_##n##_config, \
331
- PRE_KERNEL_1, \
332
- CONFIG_SERIAL_INIT_PRIORITY, \
333
- &uart_imx_driver_api); \
334
- \
335
- UART_IMX_CONFIG_FUNC(n) \
336
- \
378
+ #define UART_IMX_INIT (n ) \
379
+ static struct imx_uart_data imx_uart_##n##_data; \
380
+ \
381
+ static const struct imx_uart_config imx_uart_##n##_config; \
382
+ \
383
+ PINCTRL_DT_INST_DEFINE(n); \
384
+ \
385
+ DEVICE_DT_INST_DEFINE(n, uart_imx_init, NULL, &imx_uart_##n##_data, \
386
+ &imx_uart_##n##_config, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
387
+ &uart_imx_driver_api); \
388
+ \
389
+ UART_IMX_CONFIG_FUNC(n) \
390
+ \
337
391
UART_IMX_INIT_CFG(n);
338
392
339
393
DT_INST_FOREACH_STATUS_OKAY (UART_IMX_INIT )
0 commit comments