Skip to content

Commit 03895cf

Browse files
bhuvanchandradvgregkh
authored andcommitted
tty: serial: fsl_lpuart: Add support for RS-485
Enable Vybrid's build-in support for RS-485 auto RTS for controlling line direction of RS-485 transceiver driver. Enable RS485 feature by either using ioctrl 'TIOCSRS485' or enable it in the device tree by setting 'linux,rs485-enabled-at-boot-time' property. Signed-off-by: Bhuvanchandra DV <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c05efd6 commit 03895cf

File tree

1 file changed

+72
-6
lines changed

1 file changed

+72
-6
lines changed

drivers/tty/serial/fsl_lpuart.c

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,52 @@ static void lpuart_dma_rx_free(struct uart_port *port)
917917
sport->dma_rx_cookie = -EINVAL;
918918
}
919919

920+
static int lpuart_config_rs485(struct uart_port *port,
921+
struct serial_rs485 *rs485)
922+
{
923+
struct lpuart_port *sport = container_of(port,
924+
struct lpuart_port, port);
925+
926+
u8 modem = readb(sport->port.membase + UARTMODEM) &
927+
~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
928+
writeb(modem, sport->port.membase + UARTMODEM);
929+
930+
if (rs485->flags & SER_RS485_ENABLED) {
931+
/* Enable auto RS-485 RTS mode */
932+
modem |= UARTMODEM_TXRTSE;
933+
934+
/*
935+
* RTS needs to be logic HIGH either during transer _or_ after
936+
* transfer, other variants are not supported by the hardware.
937+
*/
938+
939+
if (!(rs485->flags & (SER_RS485_RTS_ON_SEND |
940+
SER_RS485_RTS_AFTER_SEND)))
941+
rs485->flags |= SER_RS485_RTS_ON_SEND;
942+
943+
if (rs485->flags & SER_RS485_RTS_ON_SEND &&
944+
rs485->flags & SER_RS485_RTS_AFTER_SEND)
945+
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
946+
947+
/*
948+
* The hardware defaults to RTS logic HIGH while transfer.
949+
* Switch polarity in case RTS shall be logic HIGH
950+
* after transfer.
951+
* Note: UART is assumed to be active high.
952+
*/
953+
if (rs485->flags & SER_RS485_RTS_ON_SEND)
954+
modem &= ~UARTMODEM_TXRTSPOL;
955+
else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
956+
modem |= UARTMODEM_TXRTSPOL;
957+
}
958+
959+
/* Store the new configuration */
960+
sport->port.rs485 = *rs485;
961+
962+
writeb(modem, sport->port.membase + UARTMODEM);
963+
return 0;
964+
}
965+
920966
static unsigned int lpuart_get_mctrl(struct uart_port *port)
921967
{
922968
unsigned int temp = 0;
@@ -950,17 +996,22 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
950996
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
951997
{
952998
unsigned char temp;
999+
struct lpuart_port *sport = container_of(port,
1000+
struct lpuart_port, port);
9531001

954-
temp = readb(port->membase + UARTMODEM) &
1002+
/* Make sure RXRTSE bit is not set when RS485 is enabled */
1003+
if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) {
1004+
temp = readb(sport->port.membase + UARTMODEM) &
9551005
~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
9561006

957-
if (mctrl & TIOCM_RTS)
958-
temp |= UARTMODEM_RXRTSE;
1007+
if (mctrl & TIOCM_RTS)
1008+
temp |= UARTMODEM_RXRTSE;
9591009

960-
if (mctrl & TIOCM_CTS)
961-
temp |= UARTMODEM_TXCTSE;
1010+
if (mctrl & TIOCM_CTS)
1011+
temp |= UARTMODEM_TXCTSE;
9621012

963-
writeb(temp, port->membase + UARTMODEM);
1013+
writeb(temp, port->membase + UARTMODEM);
1014+
}
9641015
}
9651016

9661017
static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -1256,6 +1307,13 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
12561307
cr1 |= UARTCR1_M;
12571308
}
12581309

1310+
/*
1311+
* When auto RS-485 RTS mode is enabled,
1312+
* hardware flow control need to be disabled.
1313+
*/
1314+
if (sport->port.rs485.flags & SER_RS485_ENABLED)
1315+
termios->c_cflag &= ~CRTSCTS;
1316+
12591317
if (termios->c_cflag & CRTSCTS) {
12601318
modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
12611319
} else {
@@ -1870,6 +1928,8 @@ static int lpuart_probe(struct platform_device *pdev)
18701928
sport->port.ops = &lpuart_pops;
18711929
sport->port.flags = UPF_BOOT_AUTOCONF;
18721930

1931+
sport->port.rs485_config = lpuart_config_rs485;
1932+
18731933
sport->clk = devm_clk_get(&pdev->dev, "ipg");
18741934
if (IS_ERR(sport->clk)) {
18751935
ret = PTR_ERR(sport->clk);
@@ -1910,6 +1970,12 @@ static int lpuart_probe(struct platform_device *pdev)
19101970
dev_info(sport->port.dev, "DMA rx channel request failed, "
19111971
"operating without rx DMA\n");
19121972

1973+
if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) {
1974+
sport->port.rs485.flags |= SER_RS485_ENABLED;
1975+
sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND;
1976+
writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM);
1977+
}
1978+
19131979
return 0;
19141980
}
19151981

0 commit comments

Comments
 (0)