summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c73
1 files changed, 30 insertions, 43 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 2735cd585af0..ca2a4ccb9abf 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -426,12 +426,23 @@ set_pwr_exit:
return ret;
}
-static int i2c_hid_execute_reset(struct i2c_hid *ihid)
+static int i2c_hid_hwreset(struct i2c_hid *ihid)
{
size_t length = 0;
int ret;
- i2c_hid_dbg(ihid, "resetting...\n");
+ i2c_hid_dbg(ihid, "%s\n", __func__);
+
+ /*
+ * This prevents sending feature reports while the device is
+ * being reset. Otherwise we may lose the reset complete
+ * interrupt.
+ */
+ mutex_lock(&ihid->reset_lock);
+
+ ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
+ if (ret)
+ goto err_unlock;
/* Prepare reset command. Command register goes first. */
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
@@ -444,59 +455,35 @@ static int i2c_hid_execute_reset(struct i2c_hid *ihid)
ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
if (ret) {
- dev_err(&ihid->client->dev, "failed to reset device.\n");
- goto out;
+ dev_err(&ihid->client->dev,
+ "failed to reset device: %d\n", ret);
+ goto err_clear_reset;
}
+ i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
+
if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
msleep(100);
- goto out;
- }
-
- i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
- if (!wait_event_timeout(ihid->wait,
- !test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
- msecs_to_jiffies(5000))) {
+ clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+ } else if (!wait_event_timeout(ihid->wait,
+ !test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
+ msecs_to_jiffies(5000))) {
ret = -ENODATA;
- goto out;
+ goto err_clear_reset;
}
i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
-out:
- clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
- return ret;
-}
-
-static int i2c_hid_hwreset(struct i2c_hid *ihid)
-{
- int ret;
-
- i2c_hid_dbg(ihid, "%s\n", __func__);
-
- /*
- * This prevents sending feature reports while the device is
- * being reset. Otherwise we may lose the reset complete
- * interrupt.
- */
- mutex_lock(&ihid->reset_lock);
-
- ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
- if (ret)
- goto out_unlock;
-
- ret = i2c_hid_execute_reset(ihid);
- if (ret) {
- dev_err(&ihid->client->dev,
- "failed to reset device: %d\n", ret);
- i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
- goto out_unlock;
- }
-
/* At least some SIS devices need this after reset */
if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
-out_unlock:
+ mutex_unlock(&ihid->reset_lock);
+ return ret;
+
+err_clear_reset:
+ clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+ i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
+err_unlock:
mutex_unlock(&ihid->reset_lock);
return ret;
}