|
@@ -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;
|