[PATCH v5 2/8] serial: max310x: assert the transceiver during a break
From: Tapio Reijonen
Date: Tue Sep 29 2026 - 05:39:50 EST
The chip's auto-RTS (MODE1.TRNSCVCTRL) asserts the RS485 transceiver
only while FIFO data is shifting out, and a break is not FIFO data: on
an RS485 port a requested break sets the TX break bit but the
transceiver is never enabled, so the break never reaches the wire.
Break-led protocols cannot work at all.
Disable auto-RTS for the break duration and drive RTS manually via the
LCR RTS bit, then restore auto-RTS when the break ends. Track the break
in tx_break and leave MODE1 alone in the rs485-config worker while it
is set - a TIOCSRS485 arriving mid-break would otherwise re-enable
auto-RTS on top of the manual RTS and release the transceiver before
the break ends; break_ctl() restores auto-RTS from the then-current
configuration when the break completes. The worker runs under
port->mutex - break_ctl() and set_termios() already do - so the
tx_break test and the MODE1 write cannot straddle a break starting or
ending, and startup() clears tx_break alongside the latched TXBREAK
bit, since a port can be closed with a break still asserted.
Fixes: 55367c620aed ("serial: max310x: Add support for RS-485 mode")
Signed-off-by: Tapio Reijonen <tapio.reijonen@xxxxxxxxxxx>
---
drivers/tty/serial/max310x.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 4c1e10e0765f45a51e0c74ca965588f39872efd5..693decd04de104051b07357973364bd587ab3d91 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -298,6 +298,7 @@ struct max310x_one {
struct work_struct md_work;
struct work_struct rs_work;
struct regmap *regmap;
+ bool tx_break; /* break_ctl() owns the transceiver */
u8 rx_buf[MAX310X_FIFO_SIZE];
};
@@ -682,6 +683,12 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
}
+static void max310x_rts_ctl(struct uart_port *port, bool rts_state)
+{
+ max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_RTS_BIT,
+ rts_state ? MAX310X_LCR_RTS_BIT : 0);
+}
+
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
{
struct max310x_one *one = to_max310x_port(port);
@@ -929,9 +936,27 @@ static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void max310x_break_ctl(struct uart_port *port, int break_state)
{
+ struct max310x_one *one = to_max310x_port(port);
+
+ one->tx_break = break_state;
+
max310x_port_update(port, MAX310X_LCR_REG,
MAX310X_LCR_TXBREAK_BIT,
break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
+
+ if (!(port->rs485.flags & SER_RS485_ENABLED))
+ return;
+
+ /*
+ * The chip's auto-RTS asserts the transceiver only while FIFO data is
+ * shifting out, and a break is not FIFO data. Disable auto-RTS for the
+ * break duration and drive RTS manually so the break reaches the wire;
+ * restore auto-RTS when the break ends.
+ */
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT,
+ break_state ? 0 : MAX310X_MODE1_TRNSCVCTRL_BIT);
+ max310x_rts_ctl(port, break_state);
}
static void max310x_set_termios(struct uart_port *port,
@@ -1055,6 +1080,13 @@ static void max310x_rs_proc(struct work_struct *ws)
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
unsigned int delay, mode1 = 0, mode2 = 0;
+ /*
+ * Serialize against break_ctl() and set_termios(), which run under
+ * port->mutex: the tx_break test below and the MODE1 write must not
+ * straddle a break starting or ending.
+ */
+ guard(mutex)(&one->port.state->port.mutex);
+
delay = (one->port.rs485.delay_rts_before_send << 4) |
one->port.rs485.delay_rts_after_send;
max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
@@ -1066,8 +1098,14 @@ static void max310x_rs_proc(struct work_struct *ws)
mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
}
- max310x_port_update(&one->port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
+ /*
+ * A break owns the transceiver: break_ctl() disabled auto-RTS and
+ * drives RTS manually, and restores it when the break ends. Leave
+ * MODE1 alone meanwhile or the break goes undriven mid-way.
+ */
+ if (!one->tx_break)
+ max310x_port_update(&one->port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
max310x_port_update(&one->port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT, mode2);
}
@@ -1090,6 +1128,7 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios
static int max310x_startup(struct uart_port *port)
{
+ struct max310x_one *one = to_max310x_port(port);
unsigned int val;
max310x_power(port, 1);
@@ -1099,6 +1138,7 @@ static int max310x_startup(struct uart_port *port)
* closed with a break still asserted, and set_termios() no longer
* rewrites it.
*/
+ one->tx_break = false;
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TXBREAK_BIT, 0);
/* Configure MODE1 register */
--
2.47.3