]> git.itanic.dy.fi Git - linux-stable/commitdiff
HID: i2c-hid: Split i2c_hid_hwreset() in start() and finish() functions
authorHans de Goede <hdegoede@redhat.com>
Sat, 2 Dec 2023 22:46:09 +0000 (23:46 +0100)
committerJiri Kosina <jkosina@suse.com>
Wed, 6 Dec 2023 10:48:40 +0000 (11:48 +0100)
Split i2c_hid_hwreset() into:

i2c_hid_start_hwreset() which sends the PWR_ON and reset commands; and
i2c_hid_finish_hwreset() which actually waits for the reset to complete.

This is a preparation patch for removing the need for
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave
more like Windows.

No functional changes intended.

Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
drivers/hid/i2c-hid/i2c-hid-core.c

index ca2a4ccb9abfed5e6346f82722d419fd8887a161..21d65ca328666fa8fae9f27dd8acfdd41882c32c 100644 (file)
@@ -426,7 +426,7 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)
        return ret;
 }
 
-static int i2c_hid_hwreset(struct i2c_hid *ihid)
+static int i2c_hid_start_hwreset(struct i2c_hid *ihid)
 {
        size_t length = 0;
        int ret;
@@ -438,11 +438,11 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid)
         * being reset. Otherwise we may lose the reset complete
         * interrupt.
         */
-       mutex_lock(&ihid->reset_lock);
+       lockdep_assert_held(&ihid->reset_lock);
 
        ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
        if (ret)
-               goto err_unlock;
+               return ret;
 
        /* Prepare reset command. Command register goes first. */
        *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
@@ -460,6 +460,18 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid)
                goto err_clear_reset;
        }
 
+       return 0;
+
+err_clear_reset:
+       clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+       i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
+       return ret;
+}
+
+static int i2c_hid_finish_hwreset(struct i2c_hid *ihid)
+{
+       int ret = 0;
+
        i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
 
        if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
@@ -477,14 +489,11 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid)
        if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
                ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
 
-       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;
 }
 
@@ -731,7 +740,11 @@ static int i2c_hid_parse(struct hid_device *hid)
        }
 
        do {
-               ret = i2c_hid_hwreset(ihid);
+               mutex_lock(&ihid->reset_lock);
+               ret = i2c_hid_start_hwreset(ihid);
+               if (ret == 0)
+                       ret = i2c_hid_finish_hwreset(ihid);
+               mutex_unlock(&ihid->reset_lock);
                if (ret)
                        msleep(1000);
        } while (tries-- > 0 && ret);
@@ -974,10 +987,15 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)
         * However some ALPS touchpads generate IRQ storm without reset, so
         * let's still reset them here.
         */
-       if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
-               ret = i2c_hid_hwreset(ihid);
-       else
+       if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) {
+               mutex_lock(&ihid->reset_lock);
+               ret = i2c_hid_start_hwreset(ihid);
+               if (ret == 0)
+                       ret = i2c_hid_finish_hwreset(ihid);
+               mutex_unlock(&ihid->reset_lock);
+       } else {
                ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
+       }
 
        if (ret)
                return ret;