diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 979bef9bfb6b..32f0a4273abb 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -505,6 +505,60 @@ struct cp210x_gpio_write {
 	u8	state;
 } __packed;
 
+/*
+ * Number of CP2108 USB interfaces, port-blocks and GPIO port-block index,
+ * where port-blocks are the internal pins containers of the chip.
+ */
+#define CP2108_IFACE_CNT		4
+#define CP2108_PB_CNT			5
+#define CP2108_GPIO_PB_IDX		1
+
+/*
+ * CP2108 default pins state. There are five port-blocks (PB). Each one is with
+ * it' specific pins-set: Port 0 - UART 0 and 1, Port 1 - GPIOs, Port 2 - chip
+ * suspend and a part of UART 2 pins, Port 3 and 4 - UART 2 and 3 pins
+ * (for details see USB Express SDK sources or SDK-based smt application
+ * accessible here https://github.com/fancer/smt-cp210x).
+ */
+struct cp2108_state {
+	__le16	mode[CP2108_PB_CNT];	/* 0 - Open-Drain, 1 - Push-Pull */
+	__le16	low_power[CP2108_PB_CNT];
+	__le16	latch[CP2108_PB_CNT];	/* 0 - Logic Low, 1 - Logic High */
+} __packed;
+
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 73 bytes.
+ * Reset/Suspend latches describe default states after reset/suspend of the
+ * pins. The rest are responsible for alternate functions settings of the
+ * chip pins (see USB Express SDK sources or SDK-based smt application
+ * https://github.com/fancer/smt-cp210x for details).
+ */
+struct cp2108_config {
+	struct cp2108_state reset_latch;
+	struct cp2108_state suspend_latch;
+	u8	ip_delay[CP2108_IFACE_CNT];
+	u8	enhanced_fxn[CP2108_IFACE_CNT];
+	u8	enhanced_fxn_dev;
+	u8	ext_clock_freq[CP2108_IFACE_CNT];
+} __packed;
+
+/* CP2108 port alternate functions fields. */
+#define CP2108_GPIO_TXLED_MODE		BIT(0)
+#define CP2108_GPIO_RXLED_MODE		BIT(1)
+#define CP2108_GPIO_RS485_MODE		BIT(2)
+#define CP2108_GPIO_RS485_LOGIC		BIT(3)
+#define CP2108_GPIO_CLOCK_MODE		BIT(4)
+#define CP2108_DYNAMIC_SUSPEND_MODE	BIT(5)
+
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x4 bytes
+ * to CP2108 controller.
+ */
+struct cp2108_gpio_write {
+	__le16	mask;
+	__le16	state;
+};
+
 /*
  * Helper to get interface number when we only have struct usb_serial.
  */
@@ -1366,10 +1420,13 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 	struct usb_serial *serial = gpiochip_get_data(gc);
 	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
 	u8 req_type = REQTYPE_DEVICE_TO_HOST;
+	int bufsize = 1;
 	int result;
-	u8 buf;
+	u16 buf;
 
-	if (priv->partnum == CP210X_PARTNUM_CP2105)
+	if (priv->partnum == CP210X_PARTNUM_CP2108)
+		bufsize = 2;
+	else if (priv->partnum == CP210X_PARTNUM_CP2105)
 		req_type = REQTYPE_INTERFACE_TO_HOST;
 
 	result = usb_autopm_get_interface(serial->interface);
@@ -1377,39 +1434,62 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 		return result;
 
 	result = cp210x_read_vendor_block(serial, req_type,
-					  CP210X_READ_LATCH, &buf, sizeof(buf));
+					  CP210X_READ_LATCH, &buf, bufsize);
 	usb_autopm_put_interface(serial->interface);
 	if (result < 0)
 		return result;
 
-	return !!(buf & BIT(gpio));
+	if (priv->partnum == CP210X_PARTNUM_CP2108) {
+		u8 intf_num = cp210x_interface_num(serial);
+
+		gpio += intf_num * 4;
+	}
+
+	return !!(le16_to_cpu(buf) & BIT(gpio));
 }
 
 static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
 {
 	struct usb_serial *serial = gpiochip_get_data(gc);
 	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
-	struct cp210x_gpio_write buf;
 	int result;
 
-	if (value == 1)
-		buf.state = BIT(gpio);
-	else
-		buf.state = 0;
-
-	buf.mask = BIT(gpio);
-
 	result = usb_autopm_get_interface(serial->interface);
 	if (result)
 		goto out;
 
-	if (priv->partnum == CP210X_PARTNUM_CP2105) {
+	if (priv->partnum == CP210X_PARTNUM_CP2108) {
+		u8 intf_num = cp210x_interface_num(serial);
+		struct cp2108_gpio_write buf;
+
+		buf.mask = cpu_to_le16(BIT(intf_num * 4 + gpio));
+		if (value == 1)
+			buf.state = buf.mask;
+		else
+			buf.state = 0;
+
+		result = cp210x_write_vendor_block(serial,
+						   REQTYPE_HOST_TO_DEVICE,
+						   CP210X_WRITE_LATCH, &buf,
+						   sizeof(buf));
+	} else if (priv->partnum == CP210X_PARTNUM_CP2105) {
+		struct cp210x_gpio_write buf;
+
+		buf.mask = BIT(gpio);
+		if (value == 1)
+			buf.state = buf.mask;
+		else
+			buf.state = 0;
+
 		result = cp210x_write_vendor_block(serial,
 						   REQTYPE_HOST_TO_INTERFACE,
 						   CP210X_WRITE_LATCH, &buf,
 						   sizeof(buf));
 	} else {
-		u16 wIndex = buf.state << 8 | buf.mask;
+		u16 wIndex = BIT(gpio);
+
+		if (value == 1)
+			wIndex |= (BIT(gpio) << 8);
 
 		result = usb_control_msg(serial->dev,
 					 usb_sndctrlpipe(serial->dev, 0),
@@ -1489,6 +1569,73 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
 	return -ENOTSUPP;
 }
 
+/*
+ * CP2108 got 16 GPIOs, each of which can be configured either as input, or
+ * as open-drain with weak pulling up to VIO or as push-pull with strong
+ * pulling up to VIO. Similar to the rest of devices the open-drain mode
+ * with latch set high is treated as input mode. All GPIOs are equally
+ * distributed between four interfaces. Thanks to the mask-state based
+ * write-latch control message we don't need to worry about possible races.
+ */
+static int cp2108_gpioconf_init(struct usb_serial *serial)
+{
+	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+	struct cp2108_config config;
+	u16 mode, latch;
+	u8 intf_num;
+	int result;
+
+	result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
+					  CP210X_GET_PORTCONFIG, &config,
+					  sizeof(config));
+	if (result < 0)
+		return result;
+
+	/*
+	 * There are four interfaces with four GPIOs manually distributed for
+	 * each of them. Here we parse the device config data to comply with
+	 * the driver interface. Note that the mode (push-pull, open-drain,
+	 * etc) can be changed only after reset, which causes the driver
+	 * reloading anyway. So we can safely read the config just once at the
+	 * device attachment procedure.
+	 */
+	intf_num = cp210x_interface_num(serial);
+	if (intf_num >= CP2108_IFACE_CNT)
+		return -ENODEV;
+	mode = le16_to_cpu(config.reset_latch.mode[CP2108_GPIO_PB_IDX]);
+	latch = le16_to_cpu(config.reset_latch.latch[CP2108_GPIO_PB_IDX]);
+
+	priv->gpio_altfunc = config.enhanced_fxn[intf_num];
+	priv->gpio_pushpull = (mode >> (intf_num * 4)) & 0x0f;
+	priv->gpio_input = (latch >> (intf_num * 4)) & 0x0f;
+	priv->gc.ngpio = 4;
+
+	/*
+	 * Each GPIO[i*4 + x] can have an alternative function enabled
+	 * (x = 0 - UART i TX toggle, x = 1 - UART i RX toggle, x = 2 - UART i
+	 * RS485 mode and x = 3  - clock output i), in which case the GPIO
+	 * functionality isn't available. If it is switched on we deny the GPIO
+	 * requests. GPIO alternative functions state resides the
+	 * enhanced_fxn[i] bitfield, where each bit linearly corresponds to
+	 * the specific GPIO, except GPIO[3] - clock output function, which
+	 * alas is placed at fourth bit, while the third bit is busy with RS485
+	 * logic mode flag. In order to make the generic cp210x GPIO request
+	 * method being suitable for cp2108, lets copy the GPIO[4] clock
+	 * alternative function state bit to the GPIO[3] RS485 logic mode bit.
+	 */
+	priv->gpio_altfunc &= ~CP2108_GPIO_RS485_LOGIC;
+	if (priv->gpio_altfunc & CP2108_GPIO_CLOCK_MODE)
+		priv->gpio_altfunc |= CP2108_GPIO_RS485_LOGIC;
+
+	/*
+	 * Open-drain mode in combination with a high latch value is used
+	 * to emulate the GPIO input pin.
+	 */
+	priv->gpio_input &= ~priv->gpio_pushpull;
+
+	return 0;
+}
+
 /*
  * This function is for configuring GPIO using shared pins, where other signals
  * are made unavailable by configuring the use of GPIO. This is believed to be
@@ -1713,6 +1860,9 @@ static int cp210x_gpio_init(struct usb_serial *serial)
 	case CP210X_PARTNUM_CP2105:
 		result = cp2105_gpioconf_init(serial);
 		break;
+	case CP210X_PARTNUM_CP2108:
+		result = cp2108_gpioconf_init(serial);
+		break;
 	case CP210X_PARTNUM_CP2102N_QFN28:
 	case CP210X_PARTNUM_CP2102N_QFN24:
 	case CP210X_PARTNUM_CP2102N_QFN20:
