Skip to content

Commit 7d62beb

Browse files
superm1Benjamin Tissoires
authored andcommitted
HID: i2c-hid: Resolve touchpad issues on Dell systems during S4
Dell systems utilize an EC-based touchpad emulation when the ACPI touchpad _DSM is not invoked. This emulation acts as a secondary master on the I2C bus, designed for scenarios where the I2C touchpad driver is absent, such as in BIOS menus. Typically, loading the i2c-hid module triggers the _DSM at initialization, disabling the EC-based emulation. However, if the i2c-hid module is missing from the boot kernel used for hibernation snapshot restoration, the _DSM remains uncalled, resulting in dual masters on the I2C bus and subsequent arbitration errors. This issue arises when i2c-hid resides in the rootfs instead of the kernel or initramfs. To address this, switch from using the SYSTEM_SLEEP_PM_OPS() macro to dedicated callbacks, introducing a specific callback for restoring the S4 image. This callback ensures the _DSM is invoked. Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
1 parent 02d6eee commit 7d62beb

3 files changed

Lines changed: 37 additions & 1 deletion

File tree

drivers/hid/i2c-hid/i2c-hid-acpi.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi)
7676
return hid_descriptor_address;
7777
}
7878

79+
static void i2c_hid_acpi_restore_sequence(struct i2chid_ops *ops)
80+
{
81+
struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops);
82+
83+
i2c_hid_acpi_get_descriptor(ihid_acpi);
84+
}
85+
7986
static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops)
8087
{
8188
struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops);
@@ -96,6 +103,7 @@ static int i2c_hid_acpi_probe(struct i2c_client *client)
96103

97104
ihid_acpi->adev = ACPI_COMPANION(dev);
98105
ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail;
106+
ihid_acpi->ops.restore_sequence = i2c_hid_acpi_restore_sequence;
99107

100108
ret = i2c_hid_acpi_get_descriptor(ihid_acpi);
101109
if (ret < 0)

drivers/hid/i2c-hid/i2c-hid-core.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,14 @@ static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid)
961961
ihid->ops->shutdown_tail(ihid->ops);
962962
}
963963

964+
static void i2c_hid_core_restore_sequence(struct i2c_hid *ihid)
965+
{
966+
if (!ihid->ops->restore_sequence)
967+
return;
968+
969+
ihid->ops->restore_sequence(ihid->ops);
970+
}
971+
964972
static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff)
965973
{
966974
struct i2c_client *client = ihid->client;
@@ -1360,8 +1368,26 @@ static int i2c_hid_core_pm_resume(struct device *dev)
13601368
return i2c_hid_core_resume(ihid);
13611369
}
13621370

1371+
static int i2c_hid_core_pm_restore(struct device *dev)
1372+
{
1373+
struct i2c_client *client = to_i2c_client(dev);
1374+
struct i2c_hid *ihid = i2c_get_clientdata(client);
1375+
1376+
if (ihid->is_panel_follower)
1377+
return 0;
1378+
1379+
i2c_hid_core_restore_sequence(ihid);
1380+
1381+
return i2c_hid_core_resume(ihid);
1382+
}
1383+
13631384
const struct dev_pm_ops i2c_hid_core_pm = {
1364-
SYSTEM_SLEEP_PM_OPS(i2c_hid_core_pm_suspend, i2c_hid_core_pm_resume)
1385+
.suspend = pm_sleep_ptr(i2c_hid_core_pm_suspend),
1386+
.resume = pm_sleep_ptr(i2c_hid_core_pm_resume),
1387+
.freeze = pm_sleep_ptr(i2c_hid_core_pm_suspend),
1388+
.thaw = pm_sleep_ptr(i2c_hid_core_pm_resume),
1389+
.poweroff = pm_sleep_ptr(i2c_hid_core_pm_suspend),
1390+
.restore = pm_sleep_ptr(i2c_hid_core_pm_restore),
13651391
};
13661392
EXPORT_SYMBOL_GPL(i2c_hid_core_pm);
13671393

drivers/hid/i2c-hid/i2c-hid.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
2727
* @power_up: do sequencing to power up the device.
2828
* @power_down: do sequencing to power down the device.
2929
* @shutdown_tail: called at the end of shutdown.
30+
* @restore_sequence: hibernation restore sequence.
3031
*/
3132
struct i2chid_ops {
3233
int (*power_up)(struct i2chid_ops *ops);
3334
void (*power_down)(struct i2chid_ops *ops);
3435
void (*shutdown_tail)(struct i2chid_ops *ops);
36+
void (*restore_sequence)(struct i2chid_ops *ops);
3537
};
3638

3739
int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,

0 commit comments

Comments
 (0)