diff mbox series

[1/1] Force ELAN06FA touchpad I2C bus freq to 100KHz

Message ID 20250103051657.211966-2-rha051117@gmail.com
State New
Headers show
Series Force I2C bus freq to 100KHz for ELAN06FA touchpad | expand

Commit Message

R Ha Jan. 3, 2025, 5:16 a.m. UTC
Some devices do not define valid bus frequencies for the ELAN06FA
touchpad in their ACPI table, and some controllers run them at
400KHz by default. The 06FA touchpad exhibits excessive smoothing
behaviors when run at 400KHz, so force the bus frequency to 100KHz.

Signed-off-by: Randolph Ha <rha051117@gmail.com>
---
 drivers/i2c/i2c-core-acpi.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

Comments

R Ha Jan. 3, 2025, 11:46 p.m. UTC | #1
Hello,

Thanks for reading my patch!

On Fri, Jan 3, 2025 at 3:33 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> What are those "some devices" and "some controllers"?

The "Some Devices" are the Lenovo V15 G4 IRU, which I use, and
potentially the Lenovo V15 G4 AMN and Lenovo Ideapad Slim 3 15IAH8 as
well (based on issue reports from other users [1]).
The "Some Controllers" are the Designware I2C controller.

Sorry for not putting this in the commit message; I had tried to
follow the comments for the quirk I copied in Commit 7574c0db2e68c
("i2c: acpi: Force bus speed to 400KHz if a Silead touchscreen is
present"), which left them out.

On Fri, Jan 3, 2025 at 3:33 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> Can you add the ACPI table snippet here too for reference?

I believe this is the correct snippet in my ACPI table (Again, V15 G4
IRU). Tried to edit it down as much as I could, hopefully this tells
everything. Please let me know how I should attach a longer snippet or
the full ACPI table if needed.
Scope (_SB.PC00.I2C1)
{
    [...]
    Device (TPD0)
    {
        [...]
        CreateWordField (SBFB, \_SB.PC00.I2C1.TPD0._Y53._ADR, BADR)
// _ADR: Address
        CreateDWordField (SBFB, \_SB.PC00.I2C1.TPD0._Y53._SPE, SPED)
// _SPE: Speed
        CreateWordField (SBFG, 0x17, INT1)
        CreateDWordField (SBFI, \_SB.PC00.I2C1.TPD0._Y54._INT, INT2)
// _INT: Interrupts
        Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            If ((OSYS < 0x07DC))
            {
                SRXO (0x09080011, One)
            }

            INT1 = GNUM (0x09080011)
            INT2 = INUM (0x09080011)
            If ((TPTY == One))
            {
                _HID = "ELAN06FA"
                _SUB = "ELAN0001"
                BADR = 0x15
                HID2 = One
                Return (Zero)
            }
            [...]
        }

        Name (_HID, "XXXX0000")  // _HID: Hardware ID
        Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */)  //
_CID: Compatible ID
        Name (_SUB, "XXXX0000")  // _SUB: Subsystem ID
        Name (_S0W, 0x03)  // _S0W: S0 Device Wake State
        Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
        {
            If ((Arg0 == HIDG))
            {
                Return (HIDD (Arg0, Arg1, Arg2, Arg3, HID2))
            }

            If ((Arg0 == TP7G))
            {
                Return (TP7D (Arg0, Arg1, Arg2, Arg3, SBFB, SBFG))
            }

            Return (Buffer (One)
            {
                 0x00                                             // .
            })
        }
        [...]
        Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
        {
            If ((OSYS < 0x07DC))
            {
                Return (SBFI) /* \_SB_.PC00.I2C1.TPD0.SBFI */
            }

            If ((TPDM == Zero))
            {
                Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFG))
            }

            Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFI))
        }
        [...]
    }
}

For comparison, the properties for a device that I think did set a
proper speed was like this:
If ((TPNP == 0xD64D))
{
    _HID = "GTCH7503"
    HID2 = One
    BADR = 0x10
    SPED = 0x000F4240
    Return (Zero)
}

[1]: https://bbs.archlinux.org/viewtopic.php?id=297092
diff mbox series

Patch

diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 14ae0cfc325e..b10f52e12fe8 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -355,6 +355,18 @@  static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = {
 	{}
 };
 
+static const struct acpi_device_id i2c_acpi_force_100khz_device_ids[] = {
+	/*
+	 * When a 400KHz freq is used on this model of ELAN touchpad instead
+	 * of 100Khz, excessive smoothing (similar to when there is noise in
+	 * the signal) is intermittently applied. As some devices' ACPI
+	 * tables do not specify the 100KHz frequency requirement, it is
+	 * necessary to force the speed to 100KHz.
+	 */
+	{ "ELAN06FA", 0 },
+	{}
+};
+
 static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
 					   void *data, void **return_value)
 {
@@ -373,6 +385,9 @@  static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
 	if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0)
 		lookup->force_speed = I2C_MAX_FAST_MODE_FREQ;
 
+	if (acpi_match_device_ids(adev, i2c_acpi_force_100khz_device_ids) == 0)
+		lookup->force_speed = I2C_MAX_STANDARD_MODE_FREQ;
+
 	return AE_OK;
 }