diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index e6b0a55f0cfb..9854bb2406e3 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -146,6 +146,7 @@ struct qcom_geni_serial_port { int wakeup_irq; bool rx_tx_swap; bool cts_rts_swap; + bool manual_flow; struct qcom_geni_private_data private_data; const struct qcom_geni_device_data *dev_data; @@ -250,7 +251,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, if (mctrl & TIOCM_LOOP) port->loopback = RX_TX_CTS_RTS_SORTED; - if (!(mctrl & TIOCM_RTS) && !uport->suspended) + if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); } @@ -1401,11 +1402,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, else stop_bit_len = TX_STOP_BIT_LEN_1; - /* flow control, clear the CTS_MASK bit if using flow control. */ - if (termios->c_cflag & CRTSCTS) + /* Configure flow control based on CRTSCTS flag. + * When CRTSCTS is set, use HW/auto flow control mode, where HW + * controls the RTS/CTS pin based FIFO state. + * When CRTSCTS is clear, the CTS pin value is ignored for TX + * path and RTS pin can be set/cleared using registers, for RX + * path. + */ + + if (termios->c_cflag & CRTSCTS) { tx_trans_cfg &= ~UART_CTS_MASK; - else + port->manual_flow = false; + } else { tx_trans_cfg |= UART_CTS_MASK; + port->manual_flow = true; + } if (baud) { uart_update_timeout(uport, termios->c_cflag, baud);