diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 871cdccf3a5f..39fc14af6185 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2029,6 +2029,22 @@ static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr,
 	return 0;
 }
 
+static int ftdi_write_eeprom(struct usb_serial_port *port, u8 addr, u16 data)
+{
+	struct usb_device *udev = port->serial->dev;
+	int rv;
+
+	rv = usb_control_msg(udev,
+			     usb_sndctrlpipe(udev, 0),
+			     FTDI_SIO_WRITE_EEPROM_REQUEST,
+			     FTDI_SIO_WRITE_EEPROM_REQUEST_TYPE,
+			     data, addr,
+			     NULL, 0, WDR_TIMEOUT);
+	if (rv < 0)
+		dev_err(&port->dev, "Unable to write EEPROM: %i\n", rv);
+	return rv;
+}
+
 static int ftdi_gpio_init_ft232h(struct usb_serial_port *port)
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -2234,10 +2250,100 @@ static int ftdi_sio_probe(struct usb_serial *serial,
 	return 0;
 }
 
+static u16 ftdi_checksum(u16 *data, int n)
+{
+	u16 checksum;
+	int i;
+
+	checksum = 0xaaaa;
+	for (i = 0; i < n - 1; i++) {
+		checksum ^= be16_to_cpu(data[i]);
+		checksum = (checksum << 1) | (checksum >> 15);
+	}
+
+	return cpu_to_be16(checksum);
+}
+
+static int ftdi_repair_brick(struct usb_serial_port *port)
+{
+	struct ftdi_private *priv = usb_get_serial_port_data(port);
+	int orig_latency;
+	int rv;
+	u16 *eeprom_data;
+	u16 checksum;
+	int eeprom_size;
+	int result;
+
+	switch (priv->chip_type) {
+	case FT232RL:
+		eeprom_size = 0x40;
+		break;
+	default:
+		/* Unsupported for brick repair */
+		return 0;
+	}
+
+	/* Latency timer needs to be 0x77 to unlock EEPROM programming */
+	if (priv->latency != 0x77) {
+		orig_latency = priv->latency;
+		priv->latency = 0x77;
+		rv = write_latency_timer(port);
+		priv->latency = orig_latency;
+		if (rv < 0)
+			return -EIO;
+	}
+
+	eeprom_data = kmalloc(eeprom_size * 2, GFP_KERNEL);
+	if (!eeprom_data)
+		return -ENOMEM;
+
+	/* Read in EEPROM */
+	result = ftdi_read_eeprom(port->serial, eeprom_data, 0x00, eeprom_size * 2);
+	if (result < 0)
+		goto end_repair_brick;
+
+	/* Verify EEPROM is valid */
+	checksum = ftdi_checksum(eeprom_data, eeprom_size);
+	if (checksum != eeprom_data[eeprom_size - 1])
+		goto end_repair_brick;
+
+	/* FTDI driver checksum preimage attack targets address 62 */
+	if (eeprom_data[62] == 0)
+		goto end_repair_brick;
+
+	/* Attempt to restore Product ID to 0x6001 */
+	eeprom_data[2] = FTDI_8U232AM_PID;
+
+	/* Clear preimage attack target address */
+	eeprom_data[62] = 0;
+
+	/* Calculate and verify new checksum */
+	checksum = ftdi_checksum(eeprom_data, eeprom_size);
+	if (checksum != eeprom_data[eeprom_size - 1])
+		goto end_repair_brick;
+
+	/* Restore EEPROM PID to original pre-brick state */
+	if (ftdi_write_eeprom(port, 2, eeprom_data[2]) < 0)
+		goto end_repair_brick;
+
+	/* Restore EEPROM preimage target address to original pre-brick state */
+	if (ftdi_write_eeprom(port, 62, eeprom_data[62]) < 0)
+		goto end_repair_brick;
+
+	dev_info(&port->dev, "Successfully repaired eeprom bricked by FTDI's malicious Windows driver.\n");
+
+end_repair_brick:
+	kfree(eeprom_data);
+
+	return result;
+}
+
 static int ftdi_sio_port_probe(struct usb_serial_port *port)
 {
 	struct ftdi_private *priv;
 	const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
+	u16 vendor_id;
+	u16 product_id;
 	int result;
 
 	priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
@@ -2255,6 +2361,12 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
 	ftdi_set_max_packet_size(port);
 	if (read_latency_timer(port) < 0)
 		priv->latency = 16;
+	vendor_id = le16_to_cpu(port->serial->dev->descriptor.idVendor);
+	product_id = le16_to_cpu(port->serial->dev->descriptor.idProduct);
+	if (vendor_id == FTDI_VID &&
+		product_id == FTDI_BRICK_PID &&
+		priv->chip_type == FT232RL)
+		ftdi_repair_brick(port);
 	write_latency_timer(port);
 	create_sysfs_attrs(port);
 
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index be1641e0408b..40c6c4372a34 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -39,6 +39,7 @@
 #define FTDI_SIO_SET_BITMODE		0x0b /* Set bitbang mode */
 #define FTDI_SIO_READ_PINS		0x0c /* Read immediate value of pins */
 #define FTDI_SIO_READ_EEPROM		0x90 /* Read EEPROM */
+#define FTDI_SIO_WRITE_EEPROM		0x91 /* Write EEPROM */
 
 /* Interface indices for FT2232, FT2232H and FT4232H devices */
 #define INTERFACE_A		1
@@ -457,6 +458,9 @@ enum ftdi_sio_baudrate {
 #define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
 #define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
 
+#define FTDI_SIO_WRITE_EEPROM_REQUEST_TYPE 0x40
+#define FTDI_SIO_WRITE_EEPROM_REQUEST FTDI_SIO_WRITE_EEPROM
+
 #define FTDI_FTX_CBUS_MUX_GPIO		0x8
 #define FTDI_FT232R_CBUS_MUX_GPIO	0xa
 
