Re: [PATCH] HID: i2c-hid: Resolve touchpad issues on Dell systems during S4

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sep 11 2025, Mario Limonciello wrote:
> On 9/11/25 8:49 AM, Benjamin Tissoires wrote:
> > Hi Mario,
> > 
> > On Sep 09 2025, Mario Limonciello (AMD) wrote:
> > > 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.
> > 
> > In the downstream Red Hat bug it was mentioned that the kernel
> > configuration had an impact though. But as I understand it now that I'm
> > re-reading it for the 4th time:
> > - on stock fedora kernel (i2c-hid in initramfs): works
> > - on stock RHEL kernel (i2c-hid in initramfs): bug but config issue
> > - on vanilla kernel without i2c-hid in initramfs: bug fixed by that
> > 		patch
> > - on vanilla kernel with i2c-hid in initramfs: works
> 
> The detail you're missing here for #4 is vanilla kernel *with Fedora kernel
> config* not with a defconfig.  A defconfig kernel I don't expect enables all
> the config options needed for this hardware.
> 
> I've reproduced it with my own kernel config as well which is not the Fedora
> or RHEL kernel config but rather a narrowed down config of options that I
> normally use for testing.
> 
> > 
> > So that patch is needed no matter the config bug we have there and it
> > will also fix that config bug. Am I correct?
> 
> Yes there are certainly circumstances it is needed if i2c-hid isn't present
> in the kernel used to restore the hibernation image.
> 
> > 
> > > 
> > > 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.
> > 
> > I'm a little bit hesitant to include this patch without proper testing.
> > Did you run this through a wider range of laptops than just the
> > problematic one?
> 
> I have been including it in my (local) development and testing tree ever
> since I made it about a month ago so I've thrown it at a random assortment
> of hardware I boot that on.  I have also been doing S4 testing explicitly
> because of checking that I didn't break S4 with by S4 at S5 series [1].
> 
> That hardware is all biased to be AMD hardware though.

Alright, thanks for the precision.

I'll run on my intel based laptop a few tests then and will include this
upstream.

Cheers,
Benjamin

> 
> [1] https://lore.kernel.org/linux-usb/20250909191619.2580169-1-superm1@xxxxxxxxxx/
> > 
> > Other than that, patch looks good to me, but I would have liked to have
> > another opinion on it.
> > 
> > Cheers,
> > Benjamin
> > 
> > > 
> > > Signed-off-by: Mario Limonciello (AMD) <superm1@xxxxxxxxxx>
> > > ---
> > >   drivers/hid/i2c-hid/i2c-hid-acpi.c |  8 ++++++++
> > >   drivers/hid/i2c-hid/i2c-hid-core.c | 28 +++++++++++++++++++++++++++-
> > >   drivers/hid/i2c-hid/i2c-hid.h      |  2 ++
> > >   3 files changed, 37 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c
> > > index 1b49243adb16a..abd700a101f46 100644
> > > --- a/drivers/hid/i2c-hid/i2c-hid-acpi.c
> > > +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c
> > > @@ -76,6 +76,13 @@ static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi)
> > >   	return hid_descriptor_address;
> > >   }
> > > +static void i2c_hid_acpi_restore_sequence(struct i2chid_ops *ops)
> > > +{
> > > +	struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops);
> > > +
> > > +	i2c_hid_acpi_get_descriptor(ihid_acpi);
> > > +}
> > > +
> > >   static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops)
> > >   {
> > >   	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)
> > >   	ihid_acpi->adev = ACPI_COMPANION(dev);
> > >   	ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail;
> > > +	ihid_acpi->ops.restore_sequence = i2c_hid_acpi_restore_sequence;
> > >   	ret = i2c_hid_acpi_get_descriptor(ihid_acpi);
> > >   	if (ret < 0)
> > > diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
> > > index d3912e3f2f13a..3257aa87be898 100644
> > > --- a/drivers/hid/i2c-hid/i2c-hid-core.c
> > > +++ b/drivers/hid/i2c-hid/i2c-hid-core.c
> > > @@ -961,6 +961,14 @@ static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid)
> > >   	ihid->ops->shutdown_tail(ihid->ops);
> > >   }
> > > +static void i2c_hid_core_restore_sequence(struct i2c_hid *ihid)
> > > +{
> > > +	if (!ihid->ops->restore_sequence)
> > > +		return;
> > > +
> > > +	ihid->ops->restore_sequence(ihid->ops);
> > > +}
> > > +
> > >   static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff)
> > >   {
> > >   	struct i2c_client *client = ihid->client;
> > > @@ -1360,8 +1368,26 @@ static int i2c_hid_core_pm_resume(struct device *dev)
> > >   	return i2c_hid_core_resume(ihid);
> > >   }
> > > +static int i2c_hid_core_pm_restore(struct device *dev)
> > > +{
> > > +	struct i2c_client *client = to_i2c_client(dev);
> > > +	struct i2c_hid *ihid = i2c_get_clientdata(client);
> > > +
> > > +	if (ihid->is_panel_follower)
> > > +		return 0;
> > > +
> > > +	i2c_hid_core_restore_sequence(ihid);
> > > +
> > > +	return i2c_hid_core_resume(ihid);
> > > +}
> > > +
> > >   const struct dev_pm_ops i2c_hid_core_pm = {
> > > -	SYSTEM_SLEEP_PM_OPS(i2c_hid_core_pm_suspend, i2c_hid_core_pm_resume)
> > > +	.suspend = pm_sleep_ptr(i2c_hid_core_pm_suspend),
> > > +	.resume = pm_sleep_ptr(i2c_hid_core_pm_resume),
> > > +	.freeze = pm_sleep_ptr(i2c_hid_core_pm_suspend),
> > > +	.thaw = pm_sleep_ptr(i2c_hid_core_pm_resume),
> > > +	.poweroff = pm_sleep_ptr(i2c_hid_core_pm_suspend),
> > > +	.restore = pm_sleep_ptr(i2c_hid_core_pm_restore),
> > >   };
> > >   EXPORT_SYMBOL_GPL(i2c_hid_core_pm);
> > > diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
> > > index 2c7b66d5caa0f..1724a435c783a 100644
> > > --- a/drivers/hid/i2c-hid/i2c-hid.h
> > > +++ b/drivers/hid/i2c-hid/i2c-hid.h
> > > @@ -27,11 +27,13 @@ static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
> > >    * @power_up: do sequencing to power up the device.
> > >    * @power_down: do sequencing to power down the device.
> > >    * @shutdown_tail: called at the end of shutdown.
> > > + * @restore_sequence: hibernation restore sequence.
> > >    */
> > >   struct i2chid_ops {
> > >   	int (*power_up)(struct i2chid_ops *ops);
> > >   	void (*power_down)(struct i2chid_ops *ops);
> > >   	void (*shutdown_tail)(struct i2chid_ops *ops);
> > > +	void (*restore_sequence)(struct i2chid_ops *ops);
> > >   };
> > >   int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
> > > -- 
> > > 2.43.0
> > > 
> 




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux