Skip to content

Commit

Permalink
tty: serial: imx: Fix broken RS485
Browse files Browse the repository at this point in the history
When about to transmit the function imx_uart_start_tx is called and in
some RS485 configurations this function will call imx_uart_stop_rx. The
problem is that imx_uart_stop_rx will enable loopback in order to
release the RS485 bus, but when loopback is enabled transmitted data
will just be looped to RX.

This patch fixes the above problem by not enabling loopback when about
to transmit.

This driver now works well when used for RS485 half duplex master
configurations.

Fixes: 79d0224 ("tty: serial: imx: Handle RS485 DE signal active high")
Cc: stable <stable@kernel.org>
Signed-off-by: Rickard x Andersson <rickaran@axis.com>
Tested-by: Christoph Niedermaier <cniedermaier@dh-electronics.com>
Link: https://lore.kernel.org/r/20240221115304.509811-1-rickaran@axis.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Rickard x Andersson authored and Greg Kroah-Hartman committed Mar 2, 2024
1 parent d206a76 commit 672448c
Showing 1 changed file with 18 additions and 4 deletions.
22 changes: 18 additions & 4 deletions drivers/tty/serial/imx.c
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,7 @@ static void imx_uart_stop_tx(struct uart_port *port)
}
}

/* called with port.lock taken and irqs off */
static void imx_uart_stop_rx(struct uart_port *port)
static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback)
{
struct imx_port *sport = (struct imx_port *)port;
u32 ucr1, ucr2, ucr4, uts;
Expand All @@ -485,7 +484,7 @@ static void imx_uart_stop_rx(struct uart_port *port)
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
if (port->rs485.flags & SER_RS485_ENABLED &&
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
sport->have_rtscts && !sport->have_rtsgpio) {
sport->have_rtscts && !sport->have_rtsgpio && loopback) {
uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
uts |= UTS_LOOP;
imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
Expand All @@ -497,6 +496,16 @@ static void imx_uart_stop_rx(struct uart_port *port)
imx_uart_writel(sport, ucr2, UCR2);
}

/* called with port.lock taken and irqs off */
static void imx_uart_stop_rx(struct uart_port *port)
{
/*
* Stop RX and enable loopback in order to make sure RS485 bus
* is not blocked. Se comment in imx_uart_probe().
*/
imx_uart_stop_rx_with_loopback_ctrl(port, true);
}

/* called with port.lock taken and irqs off */
static void imx_uart_enable_ms(struct uart_port *port)
{
Expand Down Expand Up @@ -682,9 +691,14 @@ static void imx_uart_start_tx(struct uart_port *port)
imx_uart_rts_inactive(sport, &ucr2);
imx_uart_writel(sport, ucr2, UCR2);

/*
* Since we are about to transmit we can not stop RX
* with loopback enabled because that will make our
* transmitted data being just looped to RX.
*/
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) &&
!port->rs485_rx_during_tx_gpio)
imx_uart_stop_rx(port);
imx_uart_stop_rx_with_loopback_ctrl(port, false);

sport->tx_state = WAIT_AFTER_RTS;

Expand Down

0 comments on commit 672448c

Please sign in to comment.