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)