[PATCH v7 5/9] serial: max310x: stop the transmitter before powering down in shutdown
From: Tapio Reijonen
Date: Mon Oct 05 2026 - 09:22:24 EST
max310x_shutdown() powers the port down regardless of what the
transmitter is doing. The power-off stops the UART clock mid-character,
truncating the final frame, and on the auto-RTS path it freezes the
RTS output at its current level: a close() with data still queued
leaves the RS485 transceiver asserted until the next open, which also
emits the interrupted character corrupted.
Waiting for the data to drain is no better: the tty layer's
wait-until-sent is bounded by closing_wait, configurable to none, and
a hangup arrives with no wait at all, so draining a full FIFO blocks
close() in uninterruptible sleep for seconds at low baud rates - and
forever when CTS flow control blocks the FIFO.
Instead, set MODE1 TxDisabl: the character in flight completes and the
transmitter ceases with TX_ at idle. Give that character one character
time (the chip has no transmitter-idle status), then reset the FIFOs
so the auto-RTS engine sees the transmitter empty and releases RTS
within the configured after-send hold; wait that hold plus one bit
time before powering off. Abandoned data was explicitly not waited
for, and startup() resets the FIFOs and TxDisabl on open anyway.
Measured on a MAX14830: a truncating close() at 50 baud takes 0.23 s,
RTS releases one character plus the hold after the last stop bit on
both polarities, and the reopen corruption is gone.
Fixes: f65444187a66 ("serial: New serial driver MAX310X")
Signed-off-by: Tapio Reijonen <tapio.reijonen@xxxxxxxxxxx>
---
drivers/tty/serial/max310x.c | 44 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 2456a2af891f5296cfec833d6406916073d2865f..e08e506360d72a3ef4c0ebdca2e60d864973f909 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -302,6 +302,7 @@ struct max310x_one {
struct work_struct md_work;
struct work_struct rs_work;
struct regmap *regmap;
+ unsigned int char_time_us;
unsigned int baud;
bool tx_break; /* break_ctl() owns the transceiver */
@@ -1012,6 +1013,7 @@ static void max310x_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
+ unsigned int frame_bits = tty_get_frame_size(termios->c_cflag);
unsigned int lcr = 0, flow = 0;
int baud;
@@ -1124,10 +1126,13 @@ static void max310x_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
/*
- * Cache the new baud rate and reprogram the RS485 RTS delays, whose
- * millisecond-to-bit-time conversion depends on it.
+ * Cache the new baud rate and the time it takes to clock out one
+ * character before reprogramming the RS485 RTS delays: the
+ * millisecond-to-bit-time conversion divides by the baud rate.
*/
to_max310x_port(port)->baud = baud;
+ to_max310x_port(port)->char_time_us =
+ DIV_ROUND_UP(USEC_PER_SEC * frame_bits, baud);
max310x_set_rts_ctl_params(to_max310x_port(port));
}
@@ -1184,9 +1189,10 @@ static int max310x_startup(struct uart_port *port)
one->tx_break = false;
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TXBREAK_BIT, 0);
- /* Configure MODE1 register */
+ /* Configure MODE1: re-enable the transmitter shutdown() stopped */
max310x_port_update(port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
+ MAX310X_MODE1_TRNSCVCTRL_BIT |
+ MAX310X_MODE1_TXDIS_BIT, 0);
/* Configure MODE2 register & Reset FIFOs*/
val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;
@@ -1223,9 +1229,39 @@ static int max310x_startup(struct uart_port *port)
static void max310x_shutdown(struct uart_port *port)
{
+ struct max310x_one *one = to_max310x_port(port);
+
/* Disable all interrupts */
max310x_port_write(port, MAX310X_IRQEN_REG, 0);
+ /*
+ * Stop the transmitter: the character in flight completes, data
+ * still queued is abandoned (the next startup() resets the FIFOs).
+ */
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TXDIS_BIT, MAX310X_MODE1_TXDIS_BIT);
+
+ /*
+ * Let the character in flight finish (the chip has no
+ * transmitter-idle status), then empty the FIFO: auto-RTS releases
+ * only once the transmitter is empty, and the power-off below
+ * would freeze an asserted pin until the next open.
+ */
+ fsleep(one->char_time_us);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT,
+ MAX310X_MODE2_FIFORST_BIT);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT, 0);
+ if (port->rs485.flags & SER_RS485_ENABLED && one->baud) {
+ unsigned int hold = DIV_ROUND_UP(one->baud *
+ port->rs485.delay_rts_after_send,
+ MSEC_PER_SEC);
+
+ fsleep(max(DIV_ROUND_UP((hold + 1) * USEC_PER_SEC,
+ one->baud), 100U));
+ }
+
max310x_power(port, 0);
}
--
2.47.3