]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/hid/i2c-hid/i2c-hid.c
HID: i2c-hid: Fix suspend/resume when already runtime suspended
[mirror_ubuntu-artful-kernel.git] / drivers / hid / i2c-hid / i2c-hid.c
index a2c6c985b673e08dd9aa6ec79878163fe28f2e61..5b10a5d6e2d176cdbd448451eceaf2c03cf4ed1e 100644 (file)
@@ -1108,13 +1108,30 @@ static int i2c_hid_suspend(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        struct hid_device *hid = ihid->hid;
-       int ret = 0;
+       int ret;
        int wake_status;
 
-       if (hid->driver && hid->driver->suspend)
+       if (hid->driver && hid->driver->suspend) {
+               /*
+                * Wake up the device so that IO issues in
+                * HID driver's suspend code can succeed.
+                */
+               ret = pm_runtime_resume(dev);
+               if (ret < 0)
+                       return ret;
+
                ret = hid->driver->suspend(hid, PMSG_SUSPEND);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (!pm_runtime_suspended(dev)) {
+               /* Save some power */
+               i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+
+               disable_irq(ihid->irq);
+       }
 
-       disable_irq(ihid->irq);
        if (device_may_wakeup(&client->dev)) {
                wake_status = enable_irq_wake(ihid->irq);
                if (!wake_status)
@@ -1124,10 +1141,7 @@ static int i2c_hid_suspend(struct device *dev)
                                wake_status);
        }
 
-       /* Save some power */
-       i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
-
-       return ret;
+       return 0;
 }
 
 static int i2c_hid_resume(struct device *dev)
@@ -1138,11 +1152,6 @@ static int i2c_hid_resume(struct device *dev)
        struct hid_device *hid = ihid->hid;
        int wake_status;
 
-       enable_irq(ihid->irq);
-       ret = i2c_hid_hwreset(client);
-       if (ret)
-               return ret;
-
        if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) {
                wake_status = disable_irq_wake(ihid->irq);
                if (!wake_status)
@@ -1152,6 +1161,16 @@ static int i2c_hid_resume(struct device *dev)
                                wake_status);
        }
 
+       /* We'll resume to full power */
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       enable_irq(ihid->irq);
+       ret = i2c_hid_hwreset(client);
+       if (ret)
+               return ret;
+
        if (hid->driver && hid->driver->reset_resume) {
                ret = hid->driver->reset_resume(hid);
                return ret;