From 7784d6aee59a142505072b3fbea97932b2fd1fa0 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Thu, 8 Oct 2026 09:48:27 +0000 Subject: [PATCH] serial: max310x: fix RS485 delays being programmed as bit-times The HDPIXDELAY register counts the RTS setup and hold delays in bit-times, four bits per direction, but the driver has been writing the struct serial_rs485 delay_rts_before_send/delay_rts_after_send values into it unconverted - and the uapi expresses those in milliseconds. A requested 9 ms setup delay is programmed as 9 bit-times, which at 9600 baud is 0.94 ms, roughly a tenth of what userspace asked for; the error grows with the baud rate. Cache the baud rate in set_termios() and convert the delays to bit-times at the current rate, rounding up so the delay on the wire is never shorter than requested, and capping at the 15 bit-times the 4-bit field can hold. The conversion lives in max310x_set_rts_ctl_params(); set_termios() now calls it as well, since the conversion depends on the baud rate. The delays a 4-bit bit-time field can represent still fall well short of the milliseconds the uapi can express; requests beyond 15 bit-times are capped, and the -ERANGE rejection of values above 15 ms remains in place for now. Fixes: 55367c620aed ("serial: max310x: Add support for RS-485 mode") Assisted-by: Claude:claude-fable-5 Signed-off-by: Tapio Reijonen Link: https://patch.msgid.link/20261008-max310x-rs485-sw-delay-v8-4-6ba881f81e1f@vaisala.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 40 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index bf2dcf63be88..c57d6dde7fe3 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -163,6 +163,10 @@ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ #define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ +/* HDPIXDELAY accessor macros */ +#define MAX310X_HDPIXDELAY_SETUP(val) (((val) & 0x0f) << 4) +#define MAX310X_HDPIXDELAY_HOLD(val) ((val) & 0x0f) + /* Flow control trigger level register masks */ #define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */ #define MAX310X_FLOWLVL_RES_MASK GENMASK(7, 4) /* Flow control resume level */ @@ -296,6 +300,7 @@ struct max310x_one { struct work_struct md_work; struct work_struct rs_work; struct regmap *regmap; + unsigned int baud; bool tx_break; /* break_ctl() owns the transceiver */ u8 rx_buf[MAX310X_FIFO_SIZE]; @@ -933,23 +938,33 @@ static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl) } /* - * Program the chip's RS485 RTS timing (HDPIXDELAY) and the auto - * transceiver control (MODE1) from the current configuration. The - * rs485-config worker, startup() and break_ctl()'s break-off restore - * each carried their own copy of this sequence. + * Program the chip's RS485 RTS timing. The HDPIXDELAY setup and hold fields + * count bit-times, four bits per direction, while the uapi expresses the + * delays in milliseconds: convert at the current baud rate, rounding up, and + * cap at the field maximum. */ static void max310x_set_rts_ctl_params(struct max310x_one *one) { + const unsigned int max_bit_dly = 15; struct uart_port *port = &one->port; - unsigned int delay; + unsigned int setup = 0, hold = 0; u8 mode1 = 0; - delay = (clamp(port->rs485.delay_rts_before_send, 0U, 15U) << 4) | - clamp(port->rs485.delay_rts_after_send, 0U, 15U); - max310x_port_write(port, MAX310X_HDPIXDELAY_REG, delay); + if (port->rs485.flags & SER_RS485_ENABLED) { + /* Convert milliseconds to bit-times, rounding up. */ + setup = DIV_ROUND_UP(one->baud * port->rs485.delay_rts_before_send, + MSEC_PER_SEC); + hold = DIV_ROUND_UP(one->baud * port->rs485.delay_rts_after_send, + MSEC_PER_SEC); + setup = min(setup, max_bit_dly); + hold = min(hold, max_bit_dly); - if (port->rs485.flags & SER_RS485_ENABLED) mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT; + } + + max310x_port_write(port, MAX310X_HDPIXDELAY_REG, + MAX310X_HDPIXDELAY_SETUP(setup) | + MAX310X_HDPIXDELAY_HOLD(hold)); /* * A break owns the transceiver: break_ctl() disabled auto-RTS and @@ -1105,6 +1120,13 @@ static void max310x_set_termios(struct uart_port *port, /* Update timeout according to new baud rate */ 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. + */ + to_max310x_port(port)->baud = baud; + max310x_set_rts_ctl_params(to_max310x_port(port)); } static void max310x_rs_proc(struct work_struct *ws)