From: Philippe Schenker <philippe.schenker@xxxxxxxxxxx> Sent: Wednesday, October 16, 2019 11:19 PM > This commits adds RS485 support for LPUART hardware that uses 32-bit > registers. These are typically found in i.MX8 processors. > > Signed-off-by: Philippe Schenker <philippe.schenker@xxxxxxxxxxx> Reviewed-by: Fugang Duan <fugang.duan@xxxxxxx> > > --- > > drivers/tty/serial/fsl_lpuart.c | 65 ++++++++++++++++++++++++++++++++- > 1 file changed, 63 insertions(+), 2 deletions(-) > > diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index > 346b4a070ce9..22df5f8f48b6 100644 > --- a/drivers/tty/serial/fsl_lpuart.c > +++ b/drivers/tty/serial/fsl_lpuart.c > @@ -1280,6 +1280,57 @@ static int lpuart_config_rs485(struct uart_port > *port, > return 0; > } > > +static int lpuart32_config_rs485(struct uart_port *port, > + struct serial_rs485 *rs485) { > + struct lpuart_port *sport = container_of(port, > + struct lpuart_port, port); > + > + unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) > + & ~(UARTMODEM_TXRTSPOL | > UARTMODEM_TXRTSE); > + lpuart32_write(&sport->port, modem, UARTMODIR); > + > + /* clear unsupported configurations */ > + rs485->delay_rts_before_send = 0; > + rs485->delay_rts_after_send = 0; > + rs485->flags &= ~SER_RS485_RX_DURING_TX; > + > + if (rs485->flags & SER_RS485_ENABLED) { > + /* Enable auto RS-485 RTS mode */ > + modem |= UARTMODEM_TXRTSE; > + > + /* > + * RTS needs to be logic HIGH either during transer _or_ > after > + * transfer, other variants are not supported by the > hardware. > + */ > + > + if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | > + SER_RS485_RTS_AFTER_SEND))) > + rs485->flags |= SER_RS485_RTS_ON_SEND; > + > + if (rs485->flags & SER_RS485_RTS_ON_SEND && > + rs485->flags & > SER_RS485_RTS_AFTER_SEND) > + rs485->flags &= > ~SER_RS485_RTS_AFTER_SEND; > + > + /* > + * The hardware defaults to RTS logic HIGH while > transfer. > + * Switch polarity in case RTS shall be logic HIGH > + * after transfer. > + * Note: UART is assumed to be active high. > + */ > + if (rs485->flags & SER_RS485_RTS_ON_SEND) > + modem &= ~UARTMODEM_TXRTSPOL; > + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) > + modem |= UARTMODEM_TXRTSPOL; > + } > + > + /* Store the new configuration */ > + sport->port.rs485 = *rs485; > + > + lpuart32_write(&sport->port, modem, UARTMODIR); > + return 0; > +} > + > static unsigned int lpuart_get_mctrl(struct uart_port *port) { > unsigned int temp = 0; > @@ -1878,6 +1929,13 @@ lpuart32_set_termios(struct uart_port *port, > struct ktermios *termios, > ctrl |= UARTCTRL_M; > } > > + /* > + * When auto RS-485 RTS mode is enabled, > + * hardware flow control need to be disabled. > + */ > + if (sport->port.rs485.flags & SER_RS485_ENABLED) > + termios->c_cflag &= ~CRTSCTS; > + > if (termios->c_cflag & CRTSCTS) { > modem |= (UARTMODIR_RXRTSE | > UARTMODIR_TXCTSE); > } else { > @@ -2405,7 +2463,10 @@ static int lpuart_probe(struct platform_device > *pdev) > sport->port.ops = &lpuart_pops; > sport->port.flags = UPF_BOOT_AUTOCONF; > > - sport->port.rs485_config = lpuart_config_rs485; > + if (lpuart_is_32(sport)) > + sport->port.rs485_config = lpuart32_config_rs485; > + else > + sport->port.rs485_config = lpuart_config_rs485; > > sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); > if (IS_ERR(sport->ipg_clk)) { > @@ -2459,7 +2520,7 @@ static int lpuart_probe(struct platform_device > *pdev) > sport->port.rs485.delay_rts_after_send) > dev_err(&pdev->dev, "driver doesn't support RTS > delays\n"); > > - lpuart_config_rs485(&sport->port, &sport->port.rs485); > + sport->port.rs485_config(&sport->port, &sport->port.rs485); > > sport->dma_tx_chan = > dma_request_slave_channel(sport->port.dev, "tx"); > if (!sport->dma_tx_chan) > -- > 2.23.0