Skip to content

Commit

Permalink
HID: i2c-hid: Split i2c_hid_hwreset() in start() and finish() functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans de Goede authored and Jiri Kosina committed Dec 6, 2023
1 parent f023605 commit 96d3098
Showing 1 changed file with 28 additions and 10 deletions.
38 changes: 28 additions & 10 deletions drivers/hid/i2c-hid/i2c-hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 96d3098

Please sign in to comment.