Current GPIO code in cp210x fails to take USB autosuspend into account,
making it practically impossible to use GPIOs with autosuspend enabled
without user configuration. Fix this like for ftdi_sio in a previous patch.
Tested on a CP2102N.

Signed-off-by: Karoly Pados <pa...@pados.hu>
---
Changelog:
- v2: Restrict new autopm calls to GPIO paths.
      Always check result of usb_autopm_get.
      Rebased to current usb_serial upstream.

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

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fac7a4547523..f7aaecad6e21 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1370,8 +1370,13 @@ static int cp210x_gpio_get(struct gpio_chip *gc, 
unsigned int gpio)
        if (priv->partnum == CP210X_PARTNUM_CP2105)
                req_type = REQTYPE_INTERFACE_TO_HOST;
 
+       result = usb_autopm_get_interface(serial->interface);
+       if (result)
+               return result;
+
        result = cp210x_read_vendor_block(serial, req_type,
                                          CP210X_READ_LATCH, &buf, sizeof(buf));
+       usb_autopm_put_interface(serial->interface);
        if (result < 0)
                return result;
 
@@ -1392,6 +1397,10 @@ static void cp210x_gpio_set(struct gpio_chip *gc, 
unsigned int gpio, int value)
 
        buf.mask = BIT(gpio);
 
+       result = usb_autopm_get_interface(serial->interface);
+       if (result)
+               goto out;
+
        if (priv->partnum == CP210X_PARTNUM_CP2105) {
                result = cp210x_write_vendor_block(serial,
                                                   REQTYPE_HOST_TO_INTERFACE,
@@ -1399,7 +1408,6 @@ static void cp210x_gpio_set(struct gpio_chip *gc, 
unsigned int gpio, int value)
                                                   sizeof(buf));
        } else {
                u16 wIndex = buf.state << 8 | buf.mask;
-
                result = usb_control_msg(serial->dev,
                                         usb_sndctrlpipe(serial->dev, 0),
                                         CP210X_VENDOR_SPECIFIC,
@@ -1409,6 +1417,9 @@ static void cp210x_gpio_set(struct gpio_chip *gc, 
unsigned int gpio, int value)
                                         NULL, 0, USB_CTRL_SET_TIMEOUT);
        }
 
+       usb_autopm_put_interface(serial->interface);
+
+out:
        if (result < 0) {
                dev_err(&serial->interface->dev, "failed to set GPIO value: 
%d\n",
                                result);
-- 
2.20.1

Reply via email to