Skip to content

Commit dcc2cb5

Browse files
committed
uart: Rework support for RS485 APIs
Add support for configuring and enabling RS485 signaling by use software method of pin control. Signed-off-by: Sergey Grigorovich <[email protected]> Signed-off-by: Nachiketa Kumar <[email protected]> Signed-off-by: Antonio Tessarolo <[email protected]> Signed-off-by: Sergey Grigorovich <[email protected]>
1 parent c47926e commit dcc2cb5

File tree

16 files changed

+486
-144
lines changed

16 files changed

+486
-144
lines changed

drivers/serial/Kconfig

+6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ config UART_USE_RUNTIME_CONFIGURE
6363
Say y if unsure. Disable this to reduce footprint for
6464
applications that do not require runtime UART configuration.
6565

66+
config SERIAL_SUPPORT_RS485
67+
bool
68+
help
69+
This is an option to be enabled by individual serial driver
70+
to signal that the driver and hardware supports RS485.
71+
6672
config UART_ASYNC_API
6773
bool "Asynchronous UART API"
6874
depends on SERIAL_SUPPORT_ASYNC

drivers/serial/Kconfig.imx

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ config UART_IMX
1010
select PINCTRL
1111
select SERIAL_HAS_DRIVER
1212
select SERIAL_SUPPORT_INTERRUPT
13+
select SERIAL_SUPPORT_RS485
14+
depends on HAS_IMX_HAL
1315
help
1416
This option enables the UART driver for NXP i.MX7
1517
family processors.

drivers/serial/Kconfig.stm32

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ config UART_STM32
88
default y
99
depends on DT_HAS_ST_STM32_UART_ENABLED
1010
select SERIAL_HAS_DRIVER
11+
select SERIAL_SUPPORT_RS485
1112
select SERIAL_SUPPORT_INTERRUPT
1213
# the ASYNC implementation requires a DMA controller
1314
select SERIAL_SUPPORT_ASYNC \

drivers/serial/uart_imx.c

+111-57
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/*
22
* Copyright (c) 2018 Diego Sueiro <[email protected]>
3+
* Copyright (c) 2022 Antonio Tessarolo <[email protected]>
4+
* Copyright (c) 2025 Sergey Grigorovich <[email protected]>
35
*
46
* SPDX-License-Identifier: Apache-2.0
57
*/
@@ -23,8 +25,10 @@
2325
#include <zephyr/drivers/pinctrl.h>
2426
#include <zephyr/irq.h>
2527

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
2832

2933
struct imx_uart_config {
3034
UART_Type *base;
@@ -33,16 +37,27 @@ struct imx_uart_config {
3337
const struct pinctrl_dev_config *pincfg;
3438
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
3539
void (*irq_config_func)(const struct device *dev);
40+
bool rs485_enabled;
41+
bool rs485_de_active_low;
42+
uint32_t rs485_de_timeout;
3643
#endif
3744
};
3845

3946
struct imx_uart_data {
4047
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
4148
uart_irq_callback_user_data_t callback;
4249
void *cb_data;
50+
struct k_timer rs485_timer;
4351
#endif
4452
};
4553

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+
4661
/**
4762
* @brief Initialize UART channel
4863
*
@@ -57,6 +72,7 @@ static int uart_imx_init(const struct device *dev)
5772
{
5873
UART_Type *uart = UART_STRUCT(dev);
5974
const struct imx_uart_config *config = dev->config;
75+
struct imx_uart_data *data = dev->data;
6076
unsigned int old_level;
6177
int err;
6278

@@ -93,6 +109,12 @@ static int uart_imx_init(const struct device *dev)
93109
config->irq_config_func(dev);
94110
#endif
95111

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+
96118
/* Set UART modem mode */
97119
UART_SetModemMode(uart, config->modem_mode);
98120

@@ -137,11 +159,12 @@ static int uart_imx_fifo_fill(const struct device *dev,
137159
UART_Type *uart = UART_STRUCT(dev);
138160
unsigned int num_tx = 0U;
139161

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+
}
145168
}
146169

147170
return (int)num_tx;
@@ -169,13 +192,30 @@ static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data,
169192
static void uart_imx_irq_tx_enable(const struct device *dev)
170193
{
171194
UART_Type *uart = UART_STRUCT(dev);
195+
const struct imx_uart_config *config = dev->config;
196+
struct imx_uart_data *data = dev->data;
172197

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+
}
174209
}
175210

176211
static void uart_imx_irq_tx_disable(const struct device *dev)
177212
{
178213
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+
}
179219

180220
UART_SetIntCmd(uart, uartIntTxReady, false);
181221
}
@@ -187,9 +227,27 @@ static int uart_imx_irq_tx_ready(const struct device *dev)
187227
return UART_GetStatusFlag(uart, uartStatusTxReady);
188228
}
189229

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+
190243
static void uart_imx_irq_rx_enable(const struct device *dev)
191244
{
192245
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+
}
193251

194252
UART_SetIntCmd(uart, uartIntRxReady, true);
195253
}
@@ -272,68 +330,64 @@ static DEVICE_API(uart, uart_imx_driver_api) = {
272330
.poll_out = uart_imx_poll_out,
273331

274332
#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,
287346
.irq_callback_set = uart_imx_irq_callback_set,
288347
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
289348

290349
};
291350

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}
300358

301359
#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)); \
310366
}
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))
315372
#else
316373
#define UART_IMX_CONFIG_FUNC(n)
317374
#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)
320376
#endif
321377

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+
\
337391
UART_IMX_INIT_CFG(n);
338392

339393
DT_INST_FOREACH_STATUS_OKAY(UART_IMX_INIT)

0 commit comments

Comments
 (0)