There is a bug in the current GPIO code for ftdi_sio: it failed to take USB autosuspend into account. If the device is in autosuspend, calls to usb_control_msg() fail with -EHOSTUNREACH. Because the standard value for autosuspend timeout is usually 2-5 seconds, this made it almost impossible to use the GPIOs on machines that have USB autosuspend enabled. This patch fixes the issue by acquiring a PM lock on the device for the duration of the USB transfers. Tested on an FT231X device. Signed-off-by: Karoly Pados <pados@xxxxxxxx> --- Please consider backporting to 4.20.x, otherwise the GPIO driver is not really usable for anybody with USB autosuspend enabled (eg. many laptops), at least not without manual configuration. drivers/usb/serial/ftdi_sio.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1ab2a6191013..01813dce37f2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1783,6 +1783,13 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) int result; u16 val; + result = usb_autopm_get_interface(port->serial->interface); + if (result) { + dev_err(&port->serial->interface->dev, + "Failed to wake device from autosuspend.\n"); + return result; + } + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1795,6 +1802,8 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) val, result); } + usb_autopm_put_interface(port->serial->interface); + return result; } @@ -1846,9 +1855,18 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) unsigned char *buf; int result; + result = usb_autopm_get_interface(port->serial->interface); + if (result) { + dev_err(&port->serial->interface->dev, + "Failed to wake device from autosuspend.\n"); + return result; + } + buf = kmalloc(1, GFP_KERNEL); - if (!buf) + if (!buf) { + usb_autopm_put_interface(port->serial->interface); return -ENOMEM; + } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -1863,6 +1881,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) } kfree(buf); + usb_autopm_put_interface(port->serial->interface); return result; } -- 2.20.1