Skip to content

Commit 7c4363d

Browse files
committed
Merge tag 'usb-serial-5.13-rc6' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-linus
Johan writes: USB-serial fixes for 5.13-rc6 Here are two fixes for the cp210x driver. The first fixes a regression with early revisions of the CP2102N which specifically broke some ESP32 development boards. The second makes sure that the pin configuration is detected properly also for the CP2102N QFN20 package. Both have been in linux-next over night and with no reported issues. * tag 'usb-serial-5.13-rc6' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: USB: serial: cp210x: fix CP2102N-A01 modem control USB: serial: cp210x: fix alternate function for CP2102N QFN20
2 parents abd0628 + 63a8eef commit 7c4363d

File tree

1 file changed

+78
-6
lines changed

1 file changed

+78
-6
lines changed

drivers/usb/serial/cp210x.c

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,11 @@ struct cp210x_serial_private {
252252
u8 gpio_input;
253253
#endif
254254
u8 partnum;
255+
u32 fw_version;
255256
speed_t min_speed;
256257
speed_t max_speed;
257258
bool use_actual_rate;
259+
bool no_flow_control;
258260
};
259261

260262
enum cp210x_event_state {
@@ -398,6 +400,7 @@ struct cp210x_special_chars {
398400

399401
/* CP210X_VENDOR_SPECIFIC values */
400402
#define CP210X_READ_2NCONFIG 0x000E
403+
#define CP210X_GET_FW_VER_2N 0x0010
401404
#define CP210X_READ_LATCH 0x00C2
402405
#define CP210X_GET_PARTNUM 0x370B
403406
#define CP210X_GET_PORTCONFIG 0x370C
@@ -537,6 +540,12 @@ struct cp210x_single_port_config {
537540
#define CP210X_2NCONFIG_GPIO_RSTLATCH_IDX 587
538541
#define CP210X_2NCONFIG_GPIO_CONTROL_IDX 600
539542

543+
/* CP2102N QFN20 port configuration values */
544+
#define CP2102N_QFN20_GPIO2_TXLED_MODE BIT(2)
545+
#define CP2102N_QFN20_GPIO3_RXLED_MODE BIT(3)
546+
#define CP2102N_QFN20_GPIO1_RS485_MODE BIT(4)
547+
#define CP2102N_QFN20_GPIO0_CLK_MODE BIT(6)
548+
540549
/* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
541550
struct cp210x_gpio_write {
542551
u8 mask;
@@ -1122,13 +1131,23 @@ static bool cp210x_termios_change(const struct ktermios *a, const struct ktermio
11221131
static void cp210x_set_flow_control(struct tty_struct *tty,
11231132
struct usb_serial_port *port, struct ktermios *old_termios)
11241133
{
1134+
struct cp210x_serial_private *priv = usb_get_serial_data(port->serial);
11251135
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
11261136
struct cp210x_special_chars chars;
11271137
struct cp210x_flow_ctl flow_ctl;
11281138
u32 flow_repl;
11291139
u32 ctl_hs;
11301140
int ret;
11311141

1142+
/*
1143+
* Some CP2102N interpret ulXonLimit as ulFlowReplace (erratum
1144+
* CP2102N_E104). Report back that flow control is not supported.
1145+
*/
1146+
if (priv->no_flow_control) {
1147+
tty->termios.c_cflag &= ~CRTSCTS;
1148+
tty->termios.c_iflag &= ~(IXON | IXOFF);
1149+
}
1150+
11321151
if (old_termios &&
11331152
C_CRTSCTS(tty) == (old_termios->c_cflag & CRTSCTS) &&
11341153
I_IXON(tty) == (old_termios->c_iflag & IXON) &&
@@ -1185,19 +1204,20 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
11851204
port_priv->crtscts = false;
11861205
}
11871206

1188-
if (I_IXOFF(tty))
1207+
if (I_IXOFF(tty)) {
11891208
flow_repl |= CP210X_SERIAL_AUTO_RECEIVE;
1190-
else
1209+
1210+
flow_ctl.ulXonLimit = cpu_to_le32(128);
1211+
flow_ctl.ulXoffLimit = cpu_to_le32(128);
1212+
} else {
11911213
flow_repl &= ~CP210X_SERIAL_AUTO_RECEIVE;
1214+
}
11921215

11931216
if (I_IXON(tty))
11941217
flow_repl |= CP210X_SERIAL_AUTO_TRANSMIT;
11951218
else
11961219
flow_repl &= ~CP210X_SERIAL_AUTO_TRANSMIT;
11971220

1198-
flow_ctl.ulXonLimit = cpu_to_le32(128);
1199-
flow_ctl.ulXoffLimit = cpu_to_le32(128);
1200-
12011221
dev_dbg(&port->dev, "%s - ctrl = 0x%02x, flow = 0x%02x\n", __func__,
12021222
ctl_hs, flow_repl);
12031223

@@ -1733,7 +1753,19 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial)
17331753
priv->gpio_pushpull = (gpio_pushpull >> 3) & 0x0f;
17341754

17351755
/* 0 indicates GPIO mode, 1 is alternate function */
1736-
priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f;
1756+
if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN20) {
1757+
/* QFN20 is special... */
1758+
if (gpio_ctrl & CP2102N_QFN20_GPIO0_CLK_MODE) /* GPIO 0 */
1759+
priv->gpio_altfunc |= BIT(0);
1760+
if (gpio_ctrl & CP2102N_QFN20_GPIO1_RS485_MODE) /* GPIO 1 */
1761+
priv->gpio_altfunc |= BIT(1);
1762+
if (gpio_ctrl & CP2102N_QFN20_GPIO2_TXLED_MODE) /* GPIO 2 */
1763+
priv->gpio_altfunc |= BIT(2);
1764+
if (gpio_ctrl & CP2102N_QFN20_GPIO3_RXLED_MODE) /* GPIO 3 */
1765+
priv->gpio_altfunc |= BIT(3);
1766+
} else {
1767+
priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f;
1768+
}
17371769

17381770
if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) {
17391771
/*
@@ -1908,6 +1940,45 @@ static void cp210x_init_max_speed(struct usb_serial *serial)
19081940
priv->use_actual_rate = use_actual_rate;
19091941
}
19101942

1943+
static int cp210x_get_fw_version(struct usb_serial *serial, u16 value)
1944+
{
1945+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1946+
u8 ver[3];
1947+
int ret;
1948+
1949+
ret = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST, value,
1950+
ver, sizeof(ver));
1951+
if (ret)
1952+
return ret;
1953+
1954+
dev_dbg(&serial->interface->dev, "%s - %d.%d.%d\n", __func__,
1955+
ver[0], ver[1], ver[2]);
1956+
1957+
priv->fw_version = ver[0] << 16 | ver[1] << 8 | ver[2];
1958+
1959+
return 0;
1960+
}
1961+
1962+
static void cp210x_determine_quirks(struct usb_serial *serial)
1963+
{
1964+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1965+
int ret;
1966+
1967+
switch (priv->partnum) {
1968+
case CP210X_PARTNUM_CP2102N_QFN28:
1969+
case CP210X_PARTNUM_CP2102N_QFN24:
1970+
case CP210X_PARTNUM_CP2102N_QFN20:
1971+
ret = cp210x_get_fw_version(serial, CP210X_GET_FW_VER_2N);
1972+
if (ret)
1973+
break;
1974+
if (priv->fw_version <= 0x10004)
1975+
priv->no_flow_control = true;
1976+
break;
1977+
default:
1978+
break;
1979+
}
1980+
}
1981+
19111982
static int cp210x_attach(struct usb_serial *serial)
19121983
{
19131984
int result;
@@ -1928,6 +1999,7 @@ static int cp210x_attach(struct usb_serial *serial)
19281999

19292000
usb_set_serial_data(serial, priv);
19302001

2002+
cp210x_determine_quirks(serial);
19312003
cp210x_init_max_speed(serial);
19322004

19332005
result = cp210x_gpio_init(serial);

0 commit comments

Comments
 (0)