pci1xxxx uart supports rs485 mode of operation in the hardware with auto-direction control with configurable delay for releasing RTS after the transmission. This patch adds support for the rs485 mode. Signed-off-by: Kumaravel Thiagarajan <kumaravel.thiagarajan@xxxxxxxxxxxxx> --- Changes in v2: - move pci1xxxx_rs485_config to a separate patch with pci1xxxx_rs485_supported. --- drivers/tty/serial/8250/8250_pci1xxxx.c | 57 +++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index 41a4b94f52b4..999e5a284266 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -137,6 +137,61 @@ static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud, writel((quot << 8) | frac, (port->membase + CLK_DIVISOR_REG)); } +static const struct serial_rs485 pci1xxxx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + .delay_rts_after_send = 1, + /* Delay RTS before send is not supported */ +}; + +static int pci1xxxx_rs485_config(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + u32 clock_div = readl(port->membase + CLK_DIVISOR_REG); + u8 delay_in_baud_periods = 0; + u32 baud_period_in_ns = 0; + u8 data = 0; + + /* pci1xxxx's uart hardware supports only RTS delay after + * Tx and in units of bit times to a maximum of 15 + */ + + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + memset(rs485->padding, 0, sizeof(rs485->padding)); + + data = ADCL_CFG_EN | ADCL_CFG_PIN_SEL; + + if (!(rs485->flags & SER_RS485_RTS_ON_SEND)) { + data |= ADCL_CFG_POL_SEL; + rs485->flags |= SER_RS485_RTS_AFTER_SEND; + } else { + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + } + + if (rs485->delay_rts_after_send) { + baud_period_in_ns = ((clock_div >> 8) * 16); + delay_in_baud_periods = (rs485->delay_rts_after_send * 1000000) / + baud_period_in_ns; + if (delay_in_baud_periods > 0xF) + delay_in_baud_periods = 0xF; + data |= delay_in_baud_periods << 8; + rs485->delay_rts_after_send = (baud_period_in_ns * delay_in_baud_periods) / + 1000000; + rs485->delay_rts_before_send = 0; + } + } else { + memset(rs485, 0, sizeof(*rs485)); + } + + writeb(data, (port->membase + ADCL_CFG_REG)); + port->rs485 = *rs485; + + return 0; +} + static int pci1xxxx_get_num_ports(struct pci_dev *dev) { int nr_ports = 1; @@ -217,6 +272,8 @@ static int pci1xxxx_setup(struct pci1xxxx_8250 *priv, port->port.set_termios = serial8250_do_set_termios; port->port.get_divisor = pci1xxxx_get_divisor; port->port.set_divisor = pci1xxxx_set_divisor; + port->port.rs485_config = pci1xxxx_rs485_config; + port->port.rs485_supported = pci1xxxx_rs485_supported; ret = pci1xxxx_setup_port(priv, port, offset); if (ret < 0) return ret; -- 2.25.1