Skip to content

Commit 6e124e5

Browse files
Tomasz Mońgregkh
authored andcommitted
sc16is7xx: Set AUTOCTS and AUTORTS bits
Let serial core know that the chip automatically handles RTS/CTS signal. This elimines completely unnecessary I2C/SPI bus traffic. Cease reading from RX FIFO (by disabling RDI interrupt) when throttled. Eventually the FIFO will fill up and the device will drive RTS output inactive. Unthrottle by enabling back RDI interrupt. Indirectly controlling RTS via RX FIFO state seems to be the only option because RTS bit is ignored when hardware flow control is enabled. Signed-off-by: Tomasz Moń <tomasz.mon@camlingroup.com> Link: https://lore.kernel.org/r/20220301060332.2561851-4-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 21144ba commit 6e124e5

1 file changed

Lines changed: 30 additions & 1 deletion

File tree

drivers/tty/serial/sc16is7xx.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,29 @@ static void sc16is7xx_start_tx(struct uart_port *port)
957957
kthread_queue_work(&s->kworker, &one->tx_work);
958958
}
959959

960+
static void sc16is7xx_throttle(struct uart_port *port)
961+
{
962+
unsigned long flags;
963+
964+
/*
965+
* Hardware flow control is enabled and thus the device ignores RTS
966+
* value set in MCR register. Stop reading data from RX FIFO so the
967+
* AutoRTS feature will de-activate RTS output.
968+
*/
969+
spin_lock_irqsave(&port->lock, flags);
970+
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
971+
spin_unlock_irqrestore(&port->lock, flags);
972+
}
973+
974+
static void sc16is7xx_unthrottle(struct uart_port *port)
975+
{
976+
unsigned long flags;
977+
978+
spin_lock_irqsave(&port->lock, flags);
979+
sc16is7xx_ier_set(port, SC16IS7XX_IER_RDI_BIT);
980+
spin_unlock_irqrestore(&port->lock, flags);
981+
}
982+
960983
static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
961984
{
962985
unsigned int lsr;
@@ -1062,9 +1085,13 @@ static void sc16is7xx_set_termios(struct uart_port *port,
10621085
regcache_cache_bypass(s->regmap, true);
10631086
sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
10641087
sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
1065-
if (termios->c_cflag & CRTSCTS)
1088+
1089+
port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
1090+
if (termios->c_cflag & CRTSCTS) {
10661091
flow |= SC16IS7XX_EFR_AUTOCTS_BIT |
10671092
SC16IS7XX_EFR_AUTORTS_BIT;
1093+
port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
1094+
}
10681095
if (termios->c_iflag & IXON)
10691096
flow |= SC16IS7XX_EFR_SWFLOW3_BIT;
10701097
if (termios->c_iflag & IXOFF)
@@ -1270,6 +1297,8 @@ static const struct uart_ops sc16is7xx_ops = {
12701297
.get_mctrl = sc16is7xx_get_mctrl,
12711298
.stop_tx = sc16is7xx_stop_tx,
12721299
.start_tx = sc16is7xx_start_tx,
1300+
.throttle = sc16is7xx_throttle,
1301+
.unthrottle = sc16is7xx_unthrottle,
12731302
.stop_rx = sc16is7xx_stop_rx,
12741303
.enable_ms = sc16is7xx_enable_ms,
12751304
.break_ctl = sc16is7xx_break_ctl,

0 commit comments

Comments
 (0)