Skip to content

Commit f7120f1

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: Nachiketa Kumar <[email protected]> Signed-off-by: Antonio Tessarolo <[email protected]> Signed-off-by: Sergey Grigorovich <[email protected]>
1 parent ad845fd commit f7120f1

File tree

16 files changed

+469
-137
lines changed

16 files changed

+469
-137
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

+110-57
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2018 Diego Sueiro <[email protected]>
3+
* Copyright (c) 2022 Antonio Tessarolo <[email protected]>
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -23,8 +24,10 @@
2324
#include <zephyr/drivers/pinctrl.h>
2425
#include <zephyr/irq.h>
2526

26-
#define UART_STRUCT(dev) \
27-
((UART_Type *)((const struct imx_uart_config *const)(dev)->config)->base)
27+
#define UART_STRUCT(dev) ((UART_Type *)((const struct imx_uart_config *const)(dev)->config)->base)
28+
29+
/* FIFO real size is 32 but irq may rise when there are 2 bytes in the queue */
30+
#define UART_FIFO_SIZE 30u
2831

2932
struct imx_uart_config {
3033
UART_Type *base;
@@ -33,16 +36,27 @@ struct imx_uart_config {
3336
const struct pinctrl_dev_config *pincfg;
3437
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
3538
void (*irq_config_func)(const struct device *dev);
39+
bool rs485_enabled;
40+
bool rs485_de_active_low;
41+
uint32_t rs485_de_timeout;
3642
#endif
3743
};
3844

3945
struct imx_uart_data {
4046
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
4147
uart_irq_callback_user_data_t callback;
4248
void *cb_data;
49+
struct k_timer rs485_timer;
4350
#endif
4451
};
4552

53+
static void rs485_de_time_expire_callback(struct k_timer *timer)
54+
{
55+
UART_Type *uart = k_timer_user_data_get(timer);
56+
57+
UART_SetIntCmd(uart, uartIntTxReady, true);
58+
}
59+
4660
/**
4761
* @brief Initialize UART channel
4862
*
@@ -57,6 +71,7 @@ static int uart_imx_init(const struct device *dev)
5771
{
5872
UART_Type *uart = UART_STRUCT(dev);
5973
const struct imx_uart_config *config = dev->config;
74+
struct imx_uart_data *data = dev->data;
6075
unsigned int old_level;
6176
int err;
6277

@@ -93,6 +108,12 @@ static int uart_imx_init(const struct device *dev)
93108
config->irq_config_func(dev);
94109
#endif
95110

111+
if (config->rs485_enabled) {
112+
UART_SetCtsPinLevel(uart, !config->rs485_de_active_low);
113+
k_timer_init(&data->rs485_timer, rs485_de_time_expire_callback, NULL);
114+
k_timer_user_data_set(&data->rs485_timer, uart);
115+
}
116+
96117
/* Set UART modem mode */
97118
UART_SetModemMode(uart, config->modem_mode);
98119

@@ -137,11 +158,12 @@ static int uart_imx_fifo_fill(const struct device *dev,
137158
UART_Type *uart = UART_STRUCT(dev);
138159
unsigned int num_tx = 0U;
139160

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++;
161+
if (UART_GetStatusFlag(uart, uartStatusTxReady)) {
162+
while (((size - num_tx) > 0) && (num_tx < UART_FIFO_SIZE)) {
163+
/* Send a character */
164+
UART_Putchar(uart, tx_data[num_tx]);
165+
num_tx++;
166+
}
145167
}
146168

147169
return (int)num_tx;
@@ -169,13 +191,30 @@ static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data,
169191
static void uart_imx_irq_tx_enable(const struct device *dev)
170192
{
171193
UART_Type *uart = UART_STRUCT(dev);
194+
const struct imx_uart_config *config = dev->config;
195+
struct imx_uart_data *data = dev->data;
172196

173-
UART_SetIntCmd(uart, uartIntTxReady, true);
197+
if (config->rs485_enabled) {
198+
UART_SetCtsPinLevel(uart, config->rs485_de_active_low);
199+
if (config->rs485_de_timeout) {
200+
k_timer_start(&data->rs485_timer, K_USEC(config->rs485_de_timeout),
201+
K_NO_WAIT);
202+
} else {
203+
UART_SetIntCmd(uart, uartIntTxReady, true);
204+
}
205+
} else {
206+
UART_SetIntCmd(uart, uartIntTxReady, true);
207+
}
174208
}
175209

176210
static void uart_imx_irq_tx_disable(const struct device *dev)
177211
{
178212
UART_Type *uart = UART_STRUCT(dev);
213+
const struct imx_uart_config *config = dev->config;
214+
215+
if (config->rs485_enabled) {
216+
UART_SetIntCmd(uart, uartIntTxComplete, true);
217+
}
179218

180219
UART_SetIntCmd(uart, uartIntTxReady, false);
181220
}
@@ -187,9 +226,27 @@ static int uart_imx_irq_tx_ready(const struct device *dev)
187226
return UART_GetStatusFlag(uart, uartStatusTxReady);
188227
}
189228

229+
static int uart_imx_irq_tx_complete(const struct device *dev)
230+
{
231+
UART_Type *uart = UART_STRUCT(dev);
232+
const struct imx_uart_config *config = dev->config;
233+
bool complete = UART_GetStatusFlag(uart, uartStatusTxComplete);
234+
235+
if (config->rs485_enabled && complete) {
236+
UART_SetIntCmd(uart, uartIntTxComplete, false);
237+
}
238+
239+
return complete;
240+
}
241+
190242
static void uart_imx_irq_rx_enable(const struct device *dev)
191243
{
192244
UART_Type *uart = UART_STRUCT(dev);
245+
const struct imx_uart_config *config = dev->config;
246+
247+
if (config->rs485_enabled) {
248+
UART_SetCtsPinLevel(uart, !config->rs485_de_active_low);
249+
}
193250

194251
UART_SetIntCmd(uart, uartIntRxReady, true);
195252
}
@@ -272,68 +329,64 @@ static DEVICE_API(uart, uart_imx_driver_api) = {
272329
.poll_out = uart_imx_poll_out,
273330

274331
#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,
332+
.fifo_fill = uart_imx_fifo_fill,
333+
.fifo_read = uart_imx_fifo_read,
334+
.irq_tx_enable = uart_imx_irq_tx_enable,
335+
.irq_tx_disable = uart_imx_irq_tx_disable,
336+
.irq_tx_ready = uart_imx_irq_tx_ready,
337+
.irq_tx_complete = uart_imx_irq_tx_complete,
338+
.irq_rx_enable = uart_imx_irq_rx_enable,
339+
.irq_rx_disable = uart_imx_irq_rx_disable,
340+
.irq_rx_ready = uart_imx_irq_rx_ready,
341+
.irq_err_enable = uart_imx_irq_err_enable,
342+
.irq_err_disable = uart_imx_irq_err_disable,
343+
.irq_is_pending = uart_imx_irq_is_pending,
344+
.irq_update = uart_imx_irq_update,
287345
.irq_callback_set = uart_imx_irq_callback_set,
288346
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
289347

290348
};
291349

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-
}
350+
#define UART_IMX_DECLARE_CFG(n, IRQ_FUNC_INIT) \
351+
static const struct imx_uart_config imx_uart_##n##_config = { \
352+
.base = (UART_Type *)DT_INST_REG_ADDR(n), \
353+
.baud_rate = DT_INST_PROP(n, current_speed), \
354+
.modem_mode = DT_INST_PROP(n, modem_mode), \
355+
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
356+
IRQ_FUNC_INIT}
300357

301358
#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)); \
359+
#define UART_IMX_CONFIG_FUNC(n) \
360+
static void irq_config_func_##n(const struct device *dev) \
361+
{ \
362+
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_imx_isr, \
363+
DEVICE_DT_INST_GET(n), 0); \
364+
irq_enable(DT_INST_IRQN(n)); \
310365
}
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))
366+
#define UART_IMX_IRQ_CFG_FUNC_INIT(n) \
367+
.irq_config_func = irq_config_func_##n, .rs485_enabled = DT_INST_PROP(n, rs485_enabled), \
368+
.rs485_de_active_low = DT_INST_PROP(n, rs485_de_active_low), \
369+
.rs485_de_timeout = DT_INST_PROP(n, rs485_assertion_time_de_us),
370+
#define UART_IMX_INIT_CFG(n) UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT(n))
315371
#else
316372
#define UART_IMX_CONFIG_FUNC(n)
317373
#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)
374+
#define UART_IMX_INIT_CFG(n) UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT)
320375
#endif
321376

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-
\
377+
#define UART_IMX_INIT(n) \
378+
static struct imx_uart_data imx_uart_##n##_data; \
379+
\
380+
static const struct imx_uart_config imx_uart_##n##_config; \
381+
\
382+
PINCTRL_DT_INST_DEFINE(n); \
383+
\
384+
DEVICE_DT_INST_DEFINE(n, uart_imx_init, NULL, &imx_uart_##n##_data, \
385+
&imx_uart_##n##_config, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
386+
&uart_imx_driver_api); \
387+
\
388+
UART_IMX_CONFIG_FUNC(n) \
389+
\
337390
UART_IMX_INIT_CFG(n);
338391

339392
DT_INST_FOREACH_STATUS_OKAY(UART_IMX_INIT)

0 commit comments

Comments
 (0)