From: Brant Merryman <brant.merry...@silabs.com>

commit c7614ff9b73a1e6fb2b1b51396da132ed22fecdb upstream.

CP210x hardware disables auto-RTS but leaves auto-CTS when in hardware
flow control mode and UART on cp210x hardware is disabled. When
re-opening the port, if auto-CTS is enabled on the cp210x, then auto-RTS
must be re-enabled in the driver.

Signed-off-by: Brant Merryman <brant.merry...@silabs.com>
Co-developed-by: Phu Luu <phu....@silabs.com>
Signed-off-by: Phu Luu <phu....@silabs.com>
Link: https://lore.kernel.org/r/eccf8e73-91f3-4080-be17-1714bc881...@silabs.com
[ johan: fix up tags and problem description ]
Fixes: 39a66b8d22a3 ("[PATCH] USB: CP2101 Add support for flow control")
Cc: stable <sta...@vger.kernel.org>     # 2.6.12
Signed-off-by: Johan Hovold <jo...@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/usb/serial/cp210x.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -765,6 +765,7 @@ static void cp210x_get_termios_port(stru
        u32 baud;
        u16 bits;
        u32 ctl_hs;
+       u32 flow_repl;
 
        cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud);
 
@@ -865,6 +866,22 @@ static void cp210x_get_termios_port(stru
        ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
        if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) {
                dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
+               /*
+                * When the port is closed, the CP210x hardware disables
+                * auto-RTS and RTS is deasserted but it leaves auto-CTS when
+                * in hardware flow control mode. When re-opening the port, if
+                * auto-CTS is enabled on the cp210x, then auto-RTS must be
+                * re-enabled in the driver.
+                */
+               flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
+               flow_repl &= ~CP210X_SERIAL_RTS_MASK;
+               flow_repl |= 
CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
+               flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
+               cp210x_write_reg_block(port,
+                               CP210X_SET_FLOW,
+                               &flow_ctl,
+                               sizeof(flow_ctl));
+
                cflag |= CRTSCTS;
        } else {
                dev_dbg(dev, "%s - flow control = NONE\n", __func__);


Reply via email to