Skip to content

Commit d2080d2

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 73a3438 commit d2080d2

File tree

17 files changed

+178453
-519
lines changed

17 files changed

+178453
-519
lines changed

_test_plan_partial.json

+177,754
Large diffs are not rendered by default.

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
@@ -9,6 +9,8 @@ config UART_IMX
99
depends on DT_HAS_NXP_IMX_UART_ENABLED
1010
select SERIAL_HAS_DRIVER
1111
select SERIAL_SUPPORT_INTERRUPT
12+
select SERIAL_SUPPORT_RS485
13+
depends on HAS_IMX_HAL
1214
help
1315
This option enables the UART driver for NXP i.MX7
1416
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

+124-78
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,28 +71,27 @@ 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

6378
/* disable interrupts */
6479
old_level = irq_lock();
6580

6681
/* Setup UART init structure */
67-
uart_init_config_t initConfig = {
68-
.baudRate = config->baud_rate,
69-
.wordLength = uartWordLength8Bits,
70-
.stopBitNum = uartStopBitNumOne,
71-
.parity = uartParityDisable,
72-
.direction = uartDirectionTxRx
73-
};
82+
uart_init_config_t initConfig = {.baudRate = config->baud_rate,
83+
.wordLength = uartWordLength8Bits,
84+
.stopBitNum = uartStopBitNumOne,
85+
.parity = uartParityDisable,
86+
.direction = uartDirectionTxRx};
7487

7588
err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
7689
if (err) {
7790
return err;
7891
}
7992

8093
/* Get current module clock frequency */
81-
initConfig.clockRate = get_uart_clock_freq(uart);
94+
initConfig.clockRate = get_uart_clock_freq(uart);
8295

8396
UART_Init(uart, &initConfig);
8497

@@ -93,6 +106,12 @@ static int uart_imx_init(const struct device *dev)
93106
config->irq_config_func(dev);
94107
#endif
95108

109+
if (config->rs485_enabled) {
110+
UART_SetCtsPinLevel(uart, !config->rs485_de_active_low);
111+
k_timer_init(&data->rs485_timer, rs485_de_time_expire_callback, NULL);
112+
k_timer_user_data_set(&data->rs485_timer, uart);
113+
}
114+
96115
/* Set UART modem mode */
97116
UART_SetModemMode(uart, config->modem_mode);
98117

@@ -130,31 +149,28 @@ static int uart_imx_poll_in(const struct device *dev, unsigned char *c)
130149

131150
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
132151

133-
static int uart_imx_fifo_fill(const struct device *dev,
134-
const uint8_t *tx_data,
135-
int size)
152+
static int uart_imx_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
136153
{
137154
UART_Type *uart = UART_STRUCT(dev);
138155
unsigned int num_tx = 0U;
139156

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++;
157+
if (UART_GetStatusFlag(uart, uartStatusTxReady)) {
158+
while (((size - num_tx) > 0) && (num_tx < UART_FIFO_SIZE)) {
159+
/* Send a character */
160+
UART_Putchar(uart, tx_data[num_tx]);
161+
num_tx++;
162+
}
145163
}
146164

147165
return (int)num_tx;
148166
}
149167

150-
static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data,
151-
const int size)
168+
static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
152169
{
153170
UART_Type *uart = UART_STRUCT(dev);
154171
unsigned int num_rx = 0U;
155172

156-
while (((size - num_rx) > 0) &&
157-
UART_GetStatusFlag(uart, uartStatusRxReady)) {
173+
while (((size - num_rx) > 0) && UART_GetStatusFlag(uart, uartStatusRxReady)) {
158174
/* Receive a character */
159175
rx_data[num_rx++] = UART_Getchar(uart);
160176
}
@@ -163,19 +179,36 @@ static int uart_imx_fifo_read(const struct device *dev, uint8_t *rx_data,
163179
UART_ClearStatusFlag(uart, uartStatusRxOverrun);
164180
}
165181

166-
return num_rx;
182+
return (int)num_rx;
167183
}
168184

169185
static void uart_imx_irq_tx_enable(const struct device *dev)
170186
{
171187
UART_Type *uart = UART_STRUCT(dev);
188+
const struct imx_uart_config *config = dev->config;
189+
struct imx_uart_data *data = dev->data;
172190

173-
UART_SetIntCmd(uart, uartIntTxReady, true);
191+
if (config->rs485_enabled) {
192+
UART_SetCtsPinLevel(uart, config->rs485_de_active_low);
193+
if (config->rs485_de_timeout) {
194+
k_timer_start(&data->rs485_timer, K_USEC(config->rs485_de_timeout),
195+
K_NO_WAIT);
196+
} else {
197+
UART_SetIntCmd(uart, uartIntTxReady, true);
198+
}
199+
} else {
200+
UART_SetIntCmd(uart, uartIntTxReady, true);
201+
}
174202
}
175203

176204
static void uart_imx_irq_tx_disable(const struct device *dev)
177205
{
178206
UART_Type *uart = UART_STRUCT(dev);
207+
const struct imx_uart_config *config = dev->config;
208+
209+
if (config->rs485_enabled) {
210+
UART_SetIntCmd(uart, uartIntTxComplete, true);
211+
}
179212

180213
UART_SetIntCmd(uart, uartIntTxReady, false);
181214
}
@@ -187,9 +220,27 @@ static int uart_imx_irq_tx_ready(const struct device *dev)
187220
return UART_GetStatusFlag(uart, uartStatusTxReady);
188221
}
189222

223+
static int uart_imx_irq_tx_complete(const struct device *dev)
224+
{
225+
UART_Type *uart = UART_STRUCT(dev);
226+
const struct imx_uart_config *config = dev->config;
227+
bool complete = UART_GetStatusFlag(uart, uartStatusTxComplete);
228+
229+
if (config->rs485_enabled && complete) {
230+
UART_SetIntCmd(uart, uartIntTxComplete, false);
231+
}
232+
233+
return complete;
234+
}
235+
190236
static void uart_imx_irq_rx_enable(const struct device *dev)
191237
{
192238
UART_Type *uart = UART_STRUCT(dev);
239+
const struct imx_uart_config *config = dev->config;
240+
241+
if (config->rs485_enabled) {
242+
UART_SetCtsPinLevel(uart, !config->rs485_de_active_low);
243+
}
193244

194245
UART_SetIntCmd(uart, uartIntRxReady, true);
195246
}
@@ -229,16 +280,15 @@ static int uart_imx_irq_is_pending(const struct device *dev)
229280
UART_Type *uart = UART_STRUCT(dev);
230281

231282
return UART_GetStatusFlag(uart, uartStatusRxReady) ||
232-
UART_GetStatusFlag(uart, uartStatusTxReady);
283+
UART_GetStatusFlag(uart, uartStatusTxReady);
233284
}
234285

235286
static int uart_imx_irq_update(const struct device *dev)
236287
{
237288
return 1;
238289
}
239290

240-
static void uart_imx_irq_callback_set(const struct device *dev,
241-
uart_irq_callback_user_data_t cb,
291+
static void uart_imx_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
242292
void *cb_data)
243293
{
244294
struct imx_uart_data *data = dev->data;
@@ -268,72 +318,68 @@ void uart_imx_isr(const struct device *dev)
268318
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
269319

270320
static const struct uart_driver_api uart_imx_driver_api = {
271-
.poll_in = uart_imx_poll_in,
321+
.poll_in = uart_imx_poll_in,
272322
.poll_out = uart_imx_poll_out,
273323

274324
#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,
325+
.fifo_fill = uart_imx_fifo_fill,
326+
.fifo_read = uart_imx_fifo_read,
327+
.irq_tx_enable = uart_imx_irq_tx_enable,
328+
.irq_tx_disable = uart_imx_irq_tx_disable,
329+
.irq_tx_ready = uart_imx_irq_tx_ready,
330+
.irq_tx_complete = uart_imx_irq_tx_complete,
331+
.irq_rx_enable = uart_imx_irq_rx_enable,
332+
.irq_rx_disable = uart_imx_irq_rx_disable,
333+
.irq_rx_ready = uart_imx_irq_rx_ready,
334+
.irq_err_enable = uart_imx_irq_err_enable,
335+
.irq_err_disable = uart_imx_irq_err_disable,
336+
.irq_is_pending = uart_imx_irq_is_pending,
337+
.irq_update = uart_imx_irq_update,
287338
.irq_callback_set = uart_imx_irq_callback_set,
288-
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
339+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
289340

290341
};
291342

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-
}
343+
#define UART_IMX_DECLARE_CFG(n, IRQ_FUNC_INIT) \
344+
static const struct imx_uart_config imx_uart_##n##_config = { \
345+
.base = (UART_Type *)DT_INST_REG_ADDR(n), \
346+
.baud_rate = DT_INST_PROP(n, current_speed), \
347+
.modem_mode = DT_INST_PROP(n, modem_mode), \
348+
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
349+
IRQ_FUNC_INIT}
300350

301351
#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)); \
352+
#define UART_IMX_CONFIG_FUNC(n) \
353+
static void irq_config_func_##n(const struct device *dev) \
354+
{ \
355+
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_imx_isr, \
356+
DEVICE_DT_INST_GET(n), 0); \
357+
irq_enable(DT_INST_IRQN(n)); \
310358
}
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))
359+
#define UART_IMX_IRQ_CFG_FUNC_INIT(n) \
360+
.irq_config_func = irq_config_func_##n, .rs485_enabled = DT_INST_PROP(n, rs485_enabled), \
361+
.rs485_de_active_low = DT_INST_PROP(n, rs485_de_active_low), \
362+
.rs485_de_timeout = DT_INST_PROP(n, rs485_assertion_time_de_us),
363+
#define UART_IMX_INIT_CFG(n) UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT(n))
315364
#else
316365
#define UART_IMX_CONFIG_FUNC(n)
317366
#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)
367+
#define UART_IMX_INIT_CFG(n) UART_IMX_DECLARE_CFG(n, UART_IMX_IRQ_CFG_FUNC_INIT)
320368
#endif
321369

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-
\
370+
#define UART_IMX_INIT(n) \
371+
static struct imx_uart_data imx_uart_##n##_data; \
372+
\
373+
static const struct imx_uart_config imx_uart_##n##_config; \
374+
\
375+
PINCTRL_DT_INST_DEFINE(n); \
376+
\
377+
DEVICE_DT_INST_DEFINE(n, uart_imx_init, NULL, &imx_uart_##n##_data, \
378+
&imx_uart_##n##_config, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
379+
&uart_imx_driver_api); \
380+
\
381+
UART_IMX_CONFIG_FUNC(n) \
382+
\
337383
UART_IMX_INIT_CFG(n);
338384

339385
DT_INST_FOREACH_STATUS_OKAY(UART_IMX_INIT)

0 commit comments

Comments
 (0)