diff mbox series

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

Message ID 20250103051657.211966-2-rha051117@gmail.com (mailing list archive)
State Superseded, archived
Headers show
Series Force I2C bus freq to 100KHz for ELAN06FA touchpad | expand

Commit Message

Randolph 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

Mika Westerberg Jan. 3, 2025, 9:33 a.m. UTC | #1
Hi,

On Thu, Jan 02, 2025 at 11:16:52PM -0600, Randolph Ha wrote:
> 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.

What are those "some devices" and "some controllers"?

Can you add the ACPI table snippet here too for reference?

> Signed-off-by: Randolph Ha <rha051117@gmail.com>
> ---
>  drivers/i2c/i2c-core-acpi.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> 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;
>  }
>  
> -- 
> 2.47.1
Randolph Ha Jan. 3, 2025, 11:46 p.m. UTC | #2
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
Mika Westerberg Jan. 5, 2025, 8:33 a.m. UTC | #3
On Fri, Jan 03, 2025 at 05:46:27PM -0600, R Ha wrote:
> 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.

In general it is good to follow the existing changelogs but in this case I
would prefer to add the details of the system in question (so we know what
systems the quirk is applied to).

> 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.

Okay thanks for sharing. I don't see the "SPED" beeing assigned in the
below snipped though. I would expect this works in Windows? Have you
checked if it uses 100 kHz or 400kHz there?

> 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
Randolph Ha Jan. 6, 2025, 9 a.m. UTC | #4
On Sun, Jan 5, 2025 at 2:34 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> In general it is good to follow the existing changelogs but in this case I
> would prefer to add the details of the system in question (so we know what
> systems the quirk is applied to).

Alright, I sent an updated patch with a commit message that specifies
the devices affected.

On Sun, Jan 5, 2025 at 2:34 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> Okay thanks for sharing. I don't see the "SPED" beeing assigned in the
> below snipped though.

I believe "SPED" is left unassigned. There are two reasons for this.
1. I could not find a place where it was assigned in the ACPI table
(in the snippet, every line with the word "SPED" was already
included).
2. In the file drivers/i2c/busses/i2c-designware-common.c, the code in
the function "i2c_dw_adjust_bus_speed" falls through to the "else"
case.

For (2), here is the relevant function where the control flow falls to
the "else" case. I found this by adding a print-debugging statement
after the last "else" statement.
static void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev)
{
    u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev);
    struct i2c_timings *t = &dev->timings;

    /*
     * Find bus speed from the "clock-frequency" device property, ACPI
     * or by using fast mode if neither is set.
     */
    if (acpi_speed && t->bus_freq_hz)
        t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed);
    else if (acpi_speed || t->bus_freq_hz)
        t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
    else
        t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
}

Actually, after some further investigation, I found that I missed a
few lines in my previous snippet. Specifically the line concerning the
method "I2CSerialBusV2".
Here is the full snippet pasted below since I don't want to miss
anything else, I'm sorry for the length but want to make sure
everything is included.
Scope (_SB.PC00.I2C1)
{
    Name (I2CN, Zero)
    Name (I2CX, Zero)
    Name (I2CI, One)
    Method (_INI, 0, NotSerialized)  // _INI: Initialize
    {
        I2CN = SDS1 /* \SDS1 */
        I2CX = One
    }

    Device (TPD0)
    {
        Name (HID2, Zero)
        Name (SBFB, ResourceTemplate ()
        {
            I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
                AddressingMode7Bit, "\\_SB.PC00.I2C1",
                0x00, ResourceConsumer, _Y53, Exclusive,
                )
        })
        Name (SBFG, ResourceTemplate ()
        {
            GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
                "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                )
                {   // Pin list
                    0x0000
                }
        })
        Name (SBFI, ResourceTemplate ()
        {
            Interrupt (ResourceConsumer, Level, ActiveLow,
ExclusiveAndWake, ,, _Y54)
            {
                0x00000000,
            }
        })
        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)
            }

            If ((TPTY == 0x02))
            {
                _HID = "SYNA2BA6"
                _SUB = "SYNA0001"
                BADR = 0x2C
                HID2 = 0x20
                Return (Zero)
            }

            If ((TPTY == 0x04))
            {
                _HID = "CRQ1080"
                _SUB = "CRQ0001"
                BADR = 0x2C
                HID2 = 0x20
                Return (Zero)
            }

            If ((TPTY == 0x05))
            {
                _HID = "FTCS0038"
                _SUB = "FTCS0001"
                BADR = 0x38
                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 (_STA, 0, NotSerialized)  // _STA: Status
        {
            If ((TPTY == Zero))
            {
                Return (Zero)
            }
            Else
            {
                Return (0x0F)
            }
        }

        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))
        }

        Method (TPRD, 0, Serialized)
        {
            Return (^^^LPCB.EC0.ECTP) /* \_SB_.PC00.LPCB.EC0_.ECTP */
        }

        Method (TPWR, 1, Serialized)
        {
            ^^^LPCB.EC0.ECTP = Arg0
        }
    }
}
Randolph Ha Jan. 6, 2025, 9:08 a.m. UTC | #5
On Sun, Jan 5, 2025 at 2:34 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> I would expect this works in Windows? Have you
> checked if it uses 100 kHz or 400kHz there?

The touchpad does work in Windows. I couldn't find a way to check the
frequency there. I think that I need to do some more investigation
into how I can find the "proper" frequency, though if anyone has any
tips I would appreciate them greatly.

In Windows, my touchpad does not have a vendor-provided driver, but
uses the default I2C HID driver provided by Microsoft.
Actually, my touchpad is registered as two devices: An "I2C HID
Device" using the default "HIDI2C.inf" driver, and an "HID-compliant
touch pad", using the default "input.inf" driver. Both were provided
by Microsoft, so it appears there is no vendor-specific firmware here.

I initially assumed that the driver would default to 100KHz (as being
the lowest speed defined in
drivers/i2c/busses/i2c-designware-common.c), but after reading
Microsoft's documentation for I2C HID devices it appears that they
recommend 400KHz or more [1].
After reading this, I tried forcing the speed to 1MHz in the kernel,
which surprisingly also alleviated the laggy behavior. So it appears
that the speed can be either 100KHz or 1MHz, but I think that in
Windows it should be whatever the "default" defined by the Windows
driver is.

I tried finding the I2C frequency using the steps defined in the
Microsoft guide to tracing I2C HID events using Logman [2], and this
was (what I believe to be) the relevant snippet for setting up the I2C
device, though it does not appear there is anything related to the
controller frequency:
[1]0004.0140::01/06/2025-02:34:21.359
[hidi2c][WDFDEVICE:0x000018796F20AFD8] Received WDFREQUEST
0x000018797575D918 (IOCTL_HID_READ_REPORT) on WDFQUEUE
0x000018796F20AC08
[1]0004.0140::01/06/2025-02:34:21.368
[hidi2c][WDFDEVICE:0x000018796F20AFD8] Error retrieving read
WDFREQUEST 0x0000000000000000 from ReportQueue on interrupt
status:0x8000001a(STATUS_NO_MORE_ENTRIES)
[3]0004.3184::01/06/2025-02:34:21.369
[hidi2c][WDFDEVICE:0x000018796F20AFD8] D0Exit to target state D4
[0]0004.3184::01/06/2025-02:34:21.369
[hidi2c][WDFDEVICE:0x000018796F20AFD8] Power command (opcode:0x801)
sent to device register 0x5
[0]0004.3184::01/06/2025-02:34:21.369
[hidi2c][WDFDEVICE:0x000018796F20AFD8] Successfully put device into
sleep power state
[0]0004.3184::01/06/2025-02:34:21.369
[hidi2c][WDFDEVICE:0x000018796F20AFD8] Deinitialized device HID state
[0]0004.3184::01/06/2025-02:34:21.369
[hidi2c][WDFDEVICE:0x000018796F20AFD8] WdfObjectDelete closed and
deleted SpbIoTarget
[1]0004.0150::01/06/2025-02:34:23.172 [hidi2c]Created WDF driver
object:0xFFFFE78696EE0E30
[3]0004.0150::01/06/2025-02:34:23.180
[hidi2c][WDFDEVICE:0x00001879716173C8] Created new device
[1]0004.2364::01/06/2025-02:34:23.183
[hidi2c][WDFDEVICE:0x00001879716173C8] I2C resource found at index 0
with connection id: 0x1
[1]0004.2364::01/06/2025-02:34:23.183
[hidi2c][WDFDEVICE:0x00001879716173C8] Interrupt resource found at
index 1
[1]0004.2364::01/06/2025-02:34:23.183
[hidi2c][WDFDEVICE:0x00001879716173C8] Created Spb IO Target and
resources
[1]0004.2364::01/06/2025-02:34:23.184
[hidi2c][WDFDEVICE:0x00001879716173C8] Found supported DSM function:1
[1]0004.2364::01/06/2025-02:34:23.184
[hidi2c][WDFDEVICE:0x00001879716173C8] HID Descriptor register address
0x1 retrieved from ACPI
[1]0004.2364::01/06/2025-02:34:23.184
[hidi2c][WDFDEVICE:0x00001879716173C8] D0Entry from from previous
state D4
[1]0004.2364::01/06/2025-02:34:23.185
[hidi2c][WDFDEVICE:0x00001879716173C8] HID descriptor retrieved from
register 0x1 : LEN 30 VER 0x100 VID 0x4f3 PID 0x32b9 VER 0x4 RDL 679
RDA 0x2 IRA 0x3 IRML 31 ORA 0x4 ORML 0 CRA 0x5 DRA 0x6
[1]0004.2364::01/06/2025-02:34:23.185
[hidi2c][WDFDEVICE:0x00001879716173C8] Initialized device HID state
[3]0004.2364::01/06/2025-02:34:23.185
[hidi2c][WDFDEVICE:0x00001879716173C8] Power command (opcode:0x800)
sent to device register 0x5
[3]0004.2364::01/06/2025-02:34:23.185
[hidi2c][WDFDEVICE:0x00001879716173C8] Successfully put device into on
power state
[3]0004.2364::01/06/2025-02:34:23.185
[hidi2c][WDFDEVICE:0x00001879716173C8] WdfIoQueueRetrieveNextRequest
failed to find idle notification request in IdleQueue WDFQUEUE
0x000018796F1CCFD8 status:0x8000001a(STATUS_NO_MORE_ENTRIES)
[1]0004.2364::01/06/2025-02:34:23.186
[hidi2c][WDFDEVICE:0x00001879716173C8] Failed querying registry value
for DoNotWaitForResetResponsestatus:0xc0000034(STATUS_OBJECT_NAME_NOT_FOUND)
[1]0004.2364::01/06/2025-02:34:23.186
[hidi2c][WDFDEVICE:0x00001879716173C8] Starting timer for reset
response - IO queue stopped
[1]0004.2364::01/06/2025-02:34:23.186
[hidi2c][WDFDEVICE:0x00001879716173C8] Reset command sent to device
register 0x5
[0]0004.0140::01/06/2025-02:34:23.188
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_GET_DEVICE_DESCRIPTOR) on WDFQUEUE
0x000018796258EA28
[0]0004.0140::01/06/2025-02:34:23.188
[hidi2c][WDFDEVICE:0x00001879716173C8] Returning device descriptor to
hidclass, report descriptor length 679
[0]0004.0140::01/06/2025-02:34:23.188
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_GET_DEVICE_DESCRIPTOR) with
STATUS_SUCCESS
[0]0004.0140::01/06/2025-02:34:23.188
[hidi2c][WDFDEVICE:0x00001879716173C8] Received reset response -
starting IO queue
[3]0004.0150::01/06/2025-02:34:23.189
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_GET_DEVICE_ATTRIBUTES) on WDFQUEUE
0x000018796258EA28
[3]0004.0150::01/06/2025-02:34:23.189
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_GET_DEVICE_ATTRIBUTES) with
STATUS_SUCCESS
[3]0004.0150::01/06/2025-02:34:23.189
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_GET_REPORT_DESCRIPTOR) on WDFQUEUE
0x000018796258EA28
[3]0004.0150::01/06/2025-02:34:23.209
[hidi2c][WDFDEVICE:0x00001879716173C8] Report descriptor of length 679
retrieved from register 0x2
[3]0004.0150::01/06/2025-02:34:23.209
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_GET_REPORT_DESCRIPTOR) with
STATUS_SUCCESS
[3]0004.0150::01/06/2025-02:34:23.209
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC4C48 (IOCTL_HID_READ_REPORT) on WDFQUEUE
0x000018796258EA28
[3]0004.0150::01/06/2025-02:34:23.209
[hidi2c][WDFDEVICE:0x00001879716173C8] Received first ping pong read -
enabling interrupt processing
[3]0004.0150::01/06/2025-02:34:23.209
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC48C8 (IOCTL_HID_READ_REPORT) on WDFQUEUE
0x000018796258EA28
[2]0790.0A3C::01/06/2025-02:34:23.225
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_GET_STRING) on WDFQUEUE
0x000018796258EA28
[2]0790.0A3C::01/06/2025-02:34:23.225
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_GET_STRING) with STATUS_SUCCESS
[2]0790.0A3C::01/06/2025-02:34:23.225
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_GET_FEATURE) on WDFQUEUE
0x000018796258EA28
[0]0790.0A3C::01/06/2025-02:34:23.233
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_GET_FEATURE) with STATUS_SUCCESS
[0]0790.0A3C::01/06/2025-02:34:23.234
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_GET_FEATURE) on WDFQUEUE
0x000018796258EA28
[2]0790.0A3C::01/06/2025-02:34:23.242
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_GET_FEATURE) with STATUS_SUCCESS
[2]0790.0A3C::01/06/2025-02:34:23.242
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC5A48 (IOCTL_HID_DEVICERESET_NOTIFICATION) on WDFQUEUE
0x000018796258EA28
[2]0790.0A3C::01/06/2025-02:34:23.242
[hidi2c][WDFDEVICE:0x00001879716173C8] Pended device reset
notification WDFREQUEST 0x0000187962CC5A48 to WDFQUEUE
0x0000187967F9EB08
[8]0004.020C::01/06/2025-02:34:23.243
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC3208 (IOCTL_HID_SET_FEATURE) on WDFQUEUE
0x000018796258EA28
[0]0004.0300::01/06/2025-02:34:23.243
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC1608 (IOCTL_HID_SET_FEATURE) on WDFQUEUE
0x000018796258EA28
[2]0004.020C::01/06/2025-02:34:23.244
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC3208 (IOCTL_HID_SET_FEATURE) with STATUS_SUCCESS
[2]0004.0300::01/06/2025-02:34:23.244
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC1608 (IOCTL_HID_SET_FEATURE) with STATUS_SUCCESS
[2]0790.0A3C::01/06/2025-02:34:23.247
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC1608 (IOCTL_HID_SET_FEATURE) on WDFQUEUE
0x000018796258EA28
[8]0004.0300::01/06/2025-02:34:23.247
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC3208 (IOCTL_HID_SET_FEATURE) on WDFQUEUE
0x000018796258EA28
[9]0004.020C::01/06/2025-02:34:23.247
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC0F08 (IOCTL_HID_SET_FEATURE) on WDFQUEUE
0x000018796258EA28
[2]0790.0A3C::01/06/2025-02:34:23.247
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC1608 (IOCTL_HID_SET_FEATURE) with STATUS_SUCCESS
[2]0004.0300::01/06/2025-02:34:23.248
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC3208 (IOCTL_HID_SET_FEATURE) with STATUS_SUCCESS
[2]0004.020C::01/06/2025-02:34:23.248
[hidi2c][WDFDEVICE:0x00001879716173C8] Completing WDFREQUEST
0x0000187962CC0F08 (IOCTL_HID_SET_FEATURE) with STATUS_SUCCESS
[3]0004.0140::01/06/2025-02:34:23.267
[hidi2c][WDFDEVICE:0x00001879716173C8] Received WDFREQUEST
0x0000187962CC0F08 (IOCTL_HID_READ_REPORT) on WDFQUEUE
0x000018796258EA28

[1]: https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchpad-device-bus-connectivity#acpi-table-entries
[2]: https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/event-tracing#using-logmanexe
Mika Westerberg Jan. 7, 2025, 7:27 a.m. UTC | #6
Hi,

On Mon, Jan 06, 2025 at 03:00:53AM -0600, R Ha wrote:
> On Sun, Jan 5, 2025 at 2:34 AM Mika Westerberg
> <mika.westerberg@linux.intel.com> wrote:
> > In general it is good to follow the existing changelogs but in this case I
> > would prefer to add the details of the system in question (so we know what
> > systems the quirk is applied to).
> 
> Alright, I sent an updated patch with a commit message that specifies
> the devices affected.
> 
> On Sun, Jan 5, 2025 at 2:34 AM Mika Westerberg
> <mika.westerberg@linux.intel.com> wrote:
> > Okay thanks for sharing. I don't see the "SPED" beeing assigned in the
> > below snipped though.
> 
> I believe "SPED" is left unassigned. There are two reasons for this.
> 1. I could not find a place where it was assigned in the ACPI table
> (in the snippet, every line with the word "SPED" was already
> included).
> 2. In the file drivers/i2c/busses/i2c-designware-common.c, the code in
> the function "i2c_dw_adjust_bus_speed" falls through to the "else"
> case.
> 
> For (2), here is the relevant function where the control flow falls to
> the "else" case. I found this by adding a print-debugging statement
> after the last "else" statement.
> static void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev)
> {
>     u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev);
>     struct i2c_timings *t = &dev->timings;
> 
>     /*
>      * Find bus speed from the "clock-frequency" device property, ACPI
>      * or by using fast mode if neither is set.
>      */
>     if (acpi_speed && t->bus_freq_hz)
>         t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed);
>     else if (acpi_speed || t->bus_freq_hz)
>         t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
>     else
>         t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
> }
> 
> Actually, after some further investigation, I found that I missed a
> few lines in my previous snippet. Specifically the line concerning the
> method "I2CSerialBusV2".
> Here is the full snippet pasted below since I don't want to miss
> anything else, I'm sorry for the length but want to make sure
> everything is included.

Thanks! Okay the speed set in the I2CSerialBusV2 resource is 400kHZ but
there is one more variable in this equation: \\_SB.PC00.I2C1 that's the I2C
controller itself. DW I2C has some timing related methods (HCNT/LCNT) that
may affect this so I wonder if you can share that one too?

> Scope (_SB.PC00.I2C1)
> {
>     Name (I2CN, Zero)
>     Name (I2CX, Zero)
>     Name (I2CI, One)
>     Method (_INI, 0, NotSerialized)  // _INI: Initialize
>     {
>         I2CN = SDS1 /* \SDS1 */
>         I2CX = One
>     }
> 
>     Device (TPD0)
>     {
>         Name (HID2, Zero)
>         Name (SBFB, ResourceTemplate ()
>         {
>             I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
>                 AddressingMode7Bit, "\\_SB.PC00.I2C1",
>                 0x00, ResourceConsumer, _Y53, Exclusive,
>                 )
>         })
Randolph Ha Jan. 7, 2025, 12:16 p.m. UTC | #7
Hi,

Thanks for clarifying the speed. Seems like this bug is different than
I thought.

In my ACPI table there were no references to HCNT or LCNT
specifically. I'm not sure if this is normal.

In addition, I noticed that there were debug messages in dmesg
relating to the HCNT and LCNT.
I'm not sure if they'll be useful, but here they are (taken from an
unmodified kernel):
[    3.543648] i2c i2c-14: Successfully instantiated SPD at 0x50
[    3.543790] Standard Mode HCNT:LCNT = 552:652
[    3.543794] Fast Mode HCNT:LCNT = 100:200

Here's what I have found with the string "\\_SB.PC00.I2C1" in my ACPI table:
#1
Scope (_SB)
{
    Device (PEPD)
    {
        Name (_HID, "INT33A1" /* Intel Power Engine */)  // _HID: Hardware ID
        Name (_CID, EisaId ("PNP0D80") /* Windows-compatible System
Power Management Controller */)  // _CID: Compatible ID
        Name (_UID, One)  // _UID: Unique ID
        Name (LBUF, Buffer (0xC0){})
        Name (PPD0, Package (0x03)
        {
            "\\_SB.PC00.SAT0",
            Zero,
            Package (0x02)
            {
                Zero,
                Package (0x03)
                {
                    0xFF,
                    Zero,
                    0x81
                }
            }
        })
        Name (PPD3, Package (0x03)
        {
            "\\_SB.PC00.SAT0",
            Zero,
            Package (0x02)
            {
                Zero,
                Package (0x02)
                {
                    0xFF,
                    0x03
                }
            }
        })
        Name (WWD3, Package (0x03)
        {
            "\\_SB.PC00.RP04",
            Zero,
            Package (0x02)
            {
                Zero,
                Package (0x02)
                {
                    0xFF,
                    0x03
                }
            }
        })
        Name (PKD0, Package (0x02)
        {
            Zero,
            Package (0x03)
            {
                0xFF,
                Zero,
                0x81
            }
        })
        Name (PKD3, Package (0x02)
        {
            Zero,
            Package (0x02)
            {
                0xFF,
                0x03
            }
        })
        Name (DEVY, Package (0x77)
        {
            [...]
            Package (0x03)
            {
                "\\_SB.PC00.I2C0",
                One,
                Package (0x02)
                {
                    Zero,
                    Package (0x02)
                    {
                        0xFF,
                        0x03
                    }
                }
            },

            Package (0x03)
            {
                "\\_SB.PC00.I2C1",
                One,
                Package (0x02)
                {
                    Zero,
                    Package (0x02)
                    {
                        0xFF,
                        0x03
                    }
                }
            },

            Package (0x03)
            {
                "\\_SB.PC00.XHCI",
                One,
                Package (0x02)
                {
                    Zero,
                    Package (0x02)
                    {
                        0xFF,
                        0x03
                    }
                }
            },

            Package (0x03)
            {
                "\\_SB.PC00.HDAS",
                One,
                Package (0x02)
                {
                    Zero,
                    Package (0x03)
                    {
                        0xFF,
                        Zero,
                        0x81
                    }
                }
            },
            [...The rest are similar, only changinng the strings]
        })
    }
}

#2 (seems related to another device)
Scope (_SB.PC00.I2C1)
{
    Device (PA06)
    {
        Name (_HID, "MCHP1930")  // _HID: Hardware ID
        Name (_UID, "I2C1&PA06")  // _UID: Unique ID
        Name (_S0W, 0x03)  // _S0W: S0 Device Wake State
        Method (_STA, 0, Serialized)  // _STA: Status
        {
            If (POME)
            {
                Switch (ToInteger (PLID))
                {
                    Case (Package (0x01)
                        {
                            0x0C
                        }

)
                    {
                        Return (0x0F)
                    }
                    Default
                    {
                        Return (Zero)
                    }

                }
            }

            Return (Zero)
        }

        Method (_CRS, 0, Serialized)  // _CRS: Current Resource Settings
        {
            Name (RBUF, ResourceTemplate ()
            {
                I2cSerialBusV2 (0x0000, ControllerInitiated, 0x00061A80,
                    AddressingMode7Bit, "\\_SB.PC00.I2C1",
                    0x00, ResourceConsumer, _Y3A, Exclusive,
                    )
            })
            CreateWordField (RBUF, \_SB.PC00.I2C1.PA06._CRS._Y3A._ADR,
BADR)  // _ADR: Address
            Switch (ToInteger (PLID))
            {
                Case (Package (0x01)
                    {
                        0x0C
                    }

)
                {
                    BADR = 0x17
                }
                Default
                {
                    BADR = Zero
                }

            }

            Return (RBUF) /* \_SB_.PC00.I2C1.PA06._CRS.RBUF */
        }

        Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
        {
            If ((Arg0 != ToUUID
("033771e0-1705-47b4-9535-d1bbe14d9a09") /* Unknown UUID */))
            {
                Return (Buffer (One)
                {
                     0x00                                             // .
                })
            }

            Switch (ToInteger (Arg2))
            {
                Case (Zero)
                {
                    Switch (ToInteger (Arg1))
                    {
                        Case (Zero)
                        {
                            Return (Buffer (One)
                            {
                                 0x03
           // .
                            })
                        }
                        Case (One)
                        {
                            Return (Buffer (One)
                            {
                                 0x7F
           // .
                            })
                        }

                    }

                    Break
                }
                Case (One)
                {
                    Name (PKG1, Package (0x02)
                    {
                        Package (0x08)
                        {
                            "",
                            Zero,
                            "",
                            Zero,
                            "",
                            Zero,
                            "",
                            Zero
                        },

                        Package (0x08)
                        {
                            "",
                            Zero,
                            "VBAT_IN_ELPMIC",
                            0x32,
                            "V3P3DX_EDP",
                            0x0A,
                            "VCC_EDP_BKLT",
                            0x32
                        }
                    })
                    Switch (ToInteger (PLID))
                    {
                        Case (Package (0x01)
                            {
                                0x0C
                            }

)
                        {
                            Return (DerefOf (PKG1 [One]))
                        }
                        Default
                        {
                            Return (DerefOf (PKG1 [Zero]))
                        }

                    }
                }
                Case (0x02)
                {
                    If ((Arg1 < One))
                    {
                        Break
                    }

                    Name (PKG2, Package (0x02)
                    {
                        Package (0x04)
                        {
                            Zero,
                            Zero,
                            Zero,
                            Zero
                        },

                        Package (0x04)
                        {
                            Zero,
                            0xC350,
                            0x2710,
                            0xC350
                        }
                    })
                    Switch (ToInteger (PLID))
                    {
                        Case (Package (0x01)
                            {
                                0x0C
                            }

)
                        {
                            Return (DerefOf (PKG2 [One]))
                        }
                        Default
                        {
                            Return (DerefOf (PKG2 [Zero]))
                        }

                    }
                }
                Case (0x03)
                {
                    If ((Arg1 < One))
                    {
                        Break
                    }

                    Name (BUF3, Package (0x01)
                    {
                        0x0F
                    })
                    Return (BUF3) /* \_SB_.PC00.I2C1.PA06._DSM.BUF3 */
                }
                Case (0x04)
                {
                    If ((Arg1 < One))
                    {
                        Break
                    }

                    Name (BUF4, Package (0x01)
                    {
                        Zero
                    })
                    Return (BUF4) /* \_SB_.PC00.I2C1.PA06._DSM.BUF4 */
                }
                Case (0x05)
                {
                    If ((Arg1 < One))
                    {
                        Break
                    }

                    Name (BUF5, Package (0x02)
                    {
                        0x0400,
                        0x08
                    })
                    Return (BUF5) /* \_SB_.PC00.I2C1.PA06._DSM.BUF5 */
                }
                Case (0x06)
                {
                    If ((Arg1 < One))
                    {
                        Break
                    }

                    Name (BUF6, Package (0x01)
                    {
                        0x0384
                    })
                    Return (BUF6) /* \_SB_.PC00.I2C1.PA06._DSM.BUF6 */
                }

            }

            Return (Buffer (One)
            {
                 0x00                                             // .
            })
        }
    }
}

#3 (also seems related to another device)
ElseIf ((I2SB == One))
{
    Scope (_SB.PC00.I2C1)
    {
        Device (HDAC)
        {
            Name (_HID, "INT00000")  // _HID: Hardware ID
            Name (_DDN, "Intel(R) Smart Sound Technology Audio Codec")
 // _DDN: DOS Device Name
            Name (_UID, One)  // _UID: Unique ID
            Name (CADR, Zero)
            Name (CDIS, Zero)
            Method (_INI, 0, NotSerialized)  // _INI: Initialize
            {
                If ((I2SC == One))
                {
                    _HID = "INT34C2"
                    _CID = "INT34C2"
                    CADR = 0x1C
                }
                ElseIf ((I2SC == 0x02))
                {
                    _HID = "10EC1308"
                    _CID = "10EC1308"
                    CADR = 0x10
                }
                ElseIf ((I2SC == 0x03))
                {
                    _HID = "ESSX8326"
                    _CID = "ESSX8326"
                    _DDN = "ESSX Codec Controller 8326 "
                }
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                If ((I2SC == 0x03))
                {
                    Name (SBFB, ResourceTemplate ()
                    {
                        I2cSerialBusV2 (0x0018, ControllerInitiated, 0x00061A80,
                            AddressingMode7Bit, "\\_SB.PC00.I2C0",
                            0x00, ResourceConsumer, , Exclusive,
                            )
                        I2cSerialBusV2 (0x0009, ControllerInitiated, 0x00061A80,
                            AddressingMode7Bit, "\\_SB.PC00.I2C0",
                            0x00, ResourceConsumer, , Exclusive,
                            )
                    })
                    Name (PBUF, ResourceTemplate ()
                    {
                        GpioIo (Exclusive, PullDefault, 0x0000,
0x0000, IoRestrictionOutputOnly,
                            "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                            )
                            {   // Pin list
                                0x0000
                            }
                    })
                    Name (SBFG, ResourceTemplate ()
                    {
                        GpioInt (Edge, ActiveBoth, ExclusiveAndWake,
PullNone, 0x0000,
                            "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                            )
                            {   // Pin list
                                0x0000
                            }
                    })
                    CreateWordField (PBUF, 0x17, PWRP)
                    PWRP = GNUM (0x09030006)
                    CreateWordField (SBFG, 0x17, INTP)
                    INTP = GNUM (0x09030007)
                    Return (ConcatenateResTemplate (SBFB,
ConcatenateResTemplate (PBUF, SBFG)))
                }
                Else
                {
                    Return (ConcatenateResTemplate (IICB (CADR, I2SB),
INTB (I2SI, Zero, Zero)))
                }
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If (((I2SC != Zero) && (CDIS != One)))
                {
                    Return (0x0F)
                }

                If ((CDIS == One))
                {
                    Return (0x0D)
                }

                Return (Zero)
            }

            Method (_SRS, 1, Serialized)  // _SRS: Set Resource Settings
            {
                CDIS = Zero
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                CDIS = One
            }

            Method (_DSM, 4, NotSerialized)  // _DSM: Device-Specific Method
            {
                If ((Arg0 == Buffer (0x10)
                        {
                            /* 0000 */  0x04, 0x0C, 0x80, 0xA9, 0x16,
0xE0, 0x3E, 0x34,  // ......>4
                            /* 0008 */  0x41, 0xF4, 0x6B, 0xCC, 0xE7,
0x0F, 0x43, 0x32   // A.k...C2
                        }))
                {
                    If ((Arg2 == Zero))
                    {
                        Return (0x55)
                    }

                    [...Rest are similar to above, for values of Arg2
from 0 to DF]
                }

                Return (0xFF)
            }
        }
    }
}
Mika Westerberg Jan. 8, 2025, 5:51 a.m. UTC | #8
Hi,

On Tue, Jan 07, 2025 at 06:16:09AM -0600, R Ha wrote:
> Hi,
> 
> Thanks for clarifying the speed. Seems like this bug is different than
> I thought.
> 
> In my ACPI table there were no references to HCNT or LCNT
> specifically. I'm not sure if this is normal.
> 
> In addition, I noticed that there were debug messages in dmesg
> relating to the HCNT and LCNT.
> I'm not sure if they'll be useful, but here they are (taken from an
> unmodified kernel):
> [    3.543648] i2c i2c-14: Successfully instantiated SPD at 0x50
> [    3.543790] Standard Mode HCNT:LCNT = 552:652
> [    3.543794] Fast Mode HCNT:LCNT = 100:200

I'm adding Jarkko who is expert in the designware I2C maybe he has some
ideas. IIRC we expect the HCNT/LCNT values to be passed from ACPI tables to
the driver.

@Jarkko, it seems that standard I2C HID touchpad does not work properly
with the 400 kHz as passed in I2CSerialBusV2() resource but it works with
either 100 kHz and 1 MHz. It also works fine in Windows. To me it sounds
like that we may have wrong/missing HCNT/LCNT values?

> Here's what I have found with the string "\\_SB.PC00.I2C1" in my ACPI table:
> #1

There should be Device() node for that too. The ones you listed are just
child devices connected to that bus.

> Scope (_SB)
> {
>     Device (PEPD)
>     {
>         Name (_HID, "INT33A1" /* Intel Power Engine */)  // _HID: Hardware ID
>         Name (_CID, EisaId ("PNP0D80") /* Windows-compatible System
> Power Management Controller */)  // _CID: Compatible ID
>         Name (_UID, One)  // _UID: Unique ID
>         Name (LBUF, Buffer (0xC0){})
>         Name (PPD0, Package (0x03)
>         {
>             "\\_SB.PC00.SAT0",
>             Zero,
>             Package (0x02)
>             {
>                 Zero,
>                 Package (0x03)
>                 {
>                     0xFF,
>                     Zero,
>                     0x81
>                 }
>             }
>         })
>         Name (PPD3, Package (0x03)
>         {
>             "\\_SB.PC00.SAT0",
>             Zero,
>             Package (0x02)
>             {
>                 Zero,
>                 Package (0x02)
>                 {
>                     0xFF,
>                     0x03
>                 }
>             }
>         })
>         Name (WWD3, Package (0x03)
>         {
>             "\\_SB.PC00.RP04",
>             Zero,
>             Package (0x02)
>             {
>                 Zero,
>                 Package (0x02)
>                 {
>                     0xFF,
>                     0x03
>                 }
>             }
>         })
>         Name (PKD0, Package (0x02)
>         {
>             Zero,
>             Package (0x03)
>             {
>                 0xFF,
>                 Zero,
>                 0x81
>             }
>         })
>         Name (PKD3, Package (0x02)
>         {
>             Zero,
>             Package (0x02)
>             {
>                 0xFF,
>                 0x03
>             }
>         })
>         Name (DEVY, Package (0x77)
>         {
>             [...]
>             Package (0x03)
>             {
>                 "\\_SB.PC00.I2C0",
>                 One,
>                 Package (0x02)
>                 {
>                     Zero,
>                     Package (0x02)
>                     {
>                         0xFF,
>                         0x03
>                     }
>                 }
>             },
> 
>             Package (0x03)
>             {
>                 "\\_SB.PC00.I2C1",
>                 One,
>                 Package (0x02)
>                 {
>                     Zero,
>                     Package (0x02)
>                     {
>                         0xFF,
>                         0x03
>                     }
>                 }
>             },
> 
>             Package (0x03)
>             {
>                 "\\_SB.PC00.XHCI",
>                 One,
>                 Package (0x02)
>                 {
>                     Zero,
>                     Package (0x02)
>                     {
>                         0xFF,
>                         0x03
>                     }
>                 }
>             },
> 
>             Package (0x03)
>             {
>                 "\\_SB.PC00.HDAS",
>                 One,
>                 Package (0x02)
>                 {
>                     Zero,
>                     Package (0x03)
>                     {
>                         0xFF,
>                         Zero,
>                         0x81
>                     }
>                 }
>             },
>             [...The rest are similar, only changinng the strings]
>         })
>     }
> }
> 
> #2 (seems related to another device)
> Scope (_SB.PC00.I2C1)
> {
>     Device (PA06)
>     {
>         Name (_HID, "MCHP1930")  // _HID: Hardware ID
>         Name (_UID, "I2C1&PA06")  // _UID: Unique ID
>         Name (_S0W, 0x03)  // _S0W: S0 Device Wake State
>         Method (_STA, 0, Serialized)  // _STA: Status
>         {
>             If (POME)
>             {
>                 Switch (ToInteger (PLID))
>                 {
>                     Case (Package (0x01)
>                         {
>                             0x0C
>                         }
> 
> )
>                     {
>                         Return (0x0F)
>                     }
>                     Default
>                     {
>                         Return (Zero)
>                     }
> 
>                 }
>             }
> 
>             Return (Zero)
>         }
> 
>         Method (_CRS, 0, Serialized)  // _CRS: Current Resource Settings
>         {
>             Name (RBUF, ResourceTemplate ()
>             {
>                 I2cSerialBusV2 (0x0000, ControllerInitiated, 0x00061A80,
>                     AddressingMode7Bit, "\\_SB.PC00.I2C1",
>                     0x00, ResourceConsumer, _Y3A, Exclusive,
>                     )
>             })
>             CreateWordField (RBUF, \_SB.PC00.I2C1.PA06._CRS._Y3A._ADR,
> BADR)  // _ADR: Address
>             Switch (ToInteger (PLID))
>             {
>                 Case (Package (0x01)
>                     {
>                         0x0C
>                     }
> 
> )
>                 {
>                     BADR = 0x17
>                 }
>                 Default
>                 {
>                     BADR = Zero
>                 }
> 
>             }
> 
>             Return (RBUF) /* \_SB_.PC00.I2C1.PA06._CRS.RBUF */
>         }
> 
>         Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
>         {
>             If ((Arg0 != ToUUID
> ("033771e0-1705-47b4-9535-d1bbe14d9a09") /* Unknown UUID */))
>             {
>                 Return (Buffer (One)
>                 {
>                      0x00                                             // .
>                 })
>             }
> 
>             Switch (ToInteger (Arg2))
>             {
>                 Case (Zero)
>                 {
>                     Switch (ToInteger (Arg1))
>                     {
>                         Case (Zero)
>                         {
>                             Return (Buffer (One)
>                             {
>                                  0x03
>            // .
>                             })
>                         }
>                         Case (One)
>                         {
>                             Return (Buffer (One)
>                             {
>                                  0x7F
>            // .
>                             })
>                         }
> 
>                     }
> 
>                     Break
>                 }
>                 Case (One)
>                 {
>                     Name (PKG1, Package (0x02)
>                     {
>                         Package (0x08)
>                         {
>                             "",
>                             Zero,
>                             "",
>                             Zero,
>                             "",
>                             Zero,
>                             "",
>                             Zero
>                         },
> 
>                         Package (0x08)
>                         {
>                             "",
>                             Zero,
>                             "VBAT_IN_ELPMIC",
>                             0x32,
>                             "V3P3DX_EDP",
>                             0x0A,
>                             "VCC_EDP_BKLT",
>                             0x32
>                         }
>                     })
>                     Switch (ToInteger (PLID))
>                     {
>                         Case (Package (0x01)
>                             {
>                                 0x0C
>                             }
> 
> )
>                         {
>                             Return (DerefOf (PKG1 [One]))
>                         }
>                         Default
>                         {
>                             Return (DerefOf (PKG1 [Zero]))
>                         }
> 
>                     }
>                 }
>                 Case (0x02)
>                 {
>                     If ((Arg1 < One))
>                     {
>                         Break
>                     }
> 
>                     Name (PKG2, Package (0x02)
>                     {
>                         Package (0x04)
>                         {
>                             Zero,
>                             Zero,
>                             Zero,
>                             Zero
>                         },
> 
>                         Package (0x04)
>                         {
>                             Zero,
>                             0xC350,
>                             0x2710,
>                             0xC350
>                         }
>                     })
>                     Switch (ToInteger (PLID))
>                     {
>                         Case (Package (0x01)
>                             {
>                                 0x0C
>                             }
> 
> )
>                         {
>                             Return (DerefOf (PKG2 [One]))
>                         }
>                         Default
>                         {
>                             Return (DerefOf (PKG2 [Zero]))
>                         }
> 
>                     }
>                 }
>                 Case (0x03)
>                 {
>                     If ((Arg1 < One))
>                     {
>                         Break
>                     }
> 
>                     Name (BUF3, Package (0x01)
>                     {
>                         0x0F
>                     })
>                     Return (BUF3) /* \_SB_.PC00.I2C1.PA06._DSM.BUF3 */
>                 }
>                 Case (0x04)
>                 {
>                     If ((Arg1 < One))
>                     {
>                         Break
>                     }
> 
>                     Name (BUF4, Package (0x01)
>                     {
>                         Zero
>                     })
>                     Return (BUF4) /* \_SB_.PC00.I2C1.PA06._DSM.BUF4 */
>                 }
>                 Case (0x05)
>                 {
>                     If ((Arg1 < One))
>                     {
>                         Break
>                     }
> 
>                     Name (BUF5, Package (0x02)
>                     {
>                         0x0400,
>                         0x08
>                     })
>                     Return (BUF5) /* \_SB_.PC00.I2C1.PA06._DSM.BUF5 */
>                 }
>                 Case (0x06)
>                 {
>                     If ((Arg1 < One))
>                     {
>                         Break
>                     }
> 
>                     Name (BUF6, Package (0x01)
>                     {
>                         0x0384
>                     })
>                     Return (BUF6) /* \_SB_.PC00.I2C1.PA06._DSM.BUF6 */
>                 }
> 
>             }
> 
>             Return (Buffer (One)
>             {
>                  0x00                                             // .
>             })
>         }
>     }
> }
> 
> #3 (also seems related to another device)
> ElseIf ((I2SB == One))
> {
>     Scope (_SB.PC00.I2C1)
>     {
>         Device (HDAC)
>         {
>             Name (_HID, "INT00000")  // _HID: Hardware ID
>             Name (_DDN, "Intel(R) Smart Sound Technology Audio Codec")
>  // _DDN: DOS Device Name
>             Name (_UID, One)  // _UID: Unique ID
>             Name (CADR, Zero)
>             Name (CDIS, Zero)
>             Method (_INI, 0, NotSerialized)  // _INI: Initialize
>             {
>                 If ((I2SC == One))
>                 {
>                     _HID = "INT34C2"
>                     _CID = "INT34C2"
>                     CADR = 0x1C
>                 }
>                 ElseIf ((I2SC == 0x02))
>                 {
>                     _HID = "10EC1308"
>                     _CID = "10EC1308"
>                     CADR = 0x10
>                 }
>                 ElseIf ((I2SC == 0x03))
>                 {
>                     _HID = "ESSX8326"
>                     _CID = "ESSX8326"
>                     _DDN = "ESSX Codec Controller 8326 "
>                 }
>             }
> 
>             Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
>             {
>                 If ((I2SC == 0x03))
>                 {
>                     Name (SBFB, ResourceTemplate ()
>                     {
>                         I2cSerialBusV2 (0x0018, ControllerInitiated, 0x00061A80,
>                             AddressingMode7Bit, "\\_SB.PC00.I2C0",
>                             0x00, ResourceConsumer, , Exclusive,
>                             )
>                         I2cSerialBusV2 (0x0009, ControllerInitiated, 0x00061A80,
>                             AddressingMode7Bit, "\\_SB.PC00.I2C0",
>                             0x00, ResourceConsumer, , Exclusive,
>                             )
>                     })
>                     Name (PBUF, ResourceTemplate ()
>                     {
>                         GpioIo (Exclusive, PullDefault, 0x0000,
> 0x0000, IoRestrictionOutputOnly,
>                             "\\_SB.GPI0", 0x00, ResourceConsumer, ,
>                             )
>                             {   // Pin list
>                                 0x0000
>                             }
>                     })
>                     Name (SBFG, ResourceTemplate ()
>                     {
>                         GpioInt (Edge, ActiveBoth, ExclusiveAndWake,
> PullNone, 0x0000,
>                             "\\_SB.GPI0", 0x00, ResourceConsumer, ,
>                             )
>                             {   // Pin list
>                                 0x0000
>                             }
>                     })
>                     CreateWordField (PBUF, 0x17, PWRP)
>                     PWRP = GNUM (0x09030006)
>                     CreateWordField (SBFG, 0x17, INTP)
>                     INTP = GNUM (0x09030007)
>                     Return (ConcatenateResTemplate (SBFB,
> ConcatenateResTemplate (PBUF, SBFG)))
>                 }
>                 Else
>                 {
>                     Return (ConcatenateResTemplate (IICB (CADR, I2SB),
> INTB (I2SI, Zero, Zero)))
>                 }
>             }
> 
>             Method (_STA, 0, NotSerialized)  // _STA: Status
>             {
>                 If (((I2SC != Zero) && (CDIS != One)))
>                 {
>                     Return (0x0F)
>                 }
> 
>                 If ((CDIS == One))
>                 {
>                     Return (0x0D)
>                 }
> 
>                 Return (Zero)
>             }
> 
>             Method (_SRS, 1, Serialized)  // _SRS: Set Resource Settings
>             {
>                 CDIS = Zero
>             }
> 
>             Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
>             {
>                 CDIS = One
>             }
> 
>             Method (_DSM, 4, NotSerialized)  // _DSM: Device-Specific Method
>             {
>                 If ((Arg0 == Buffer (0x10)
>                         {
>                             /* 0000 */  0x04, 0x0C, 0x80, 0xA9, 0x16,
> 0xE0, 0x3E, 0x34,  // ......>4
>                             /* 0008 */  0x41, 0xF4, 0x6B, 0xCC, 0xE7,
> 0x0F, 0x43, 0x32   // A.k...C2
>                         }))
>                 {
>                     If ((Arg2 == Zero))
>                     {
>                         Return (0x55)
>                     }
> 
>                     [...Rest are similar to above, for values of Arg2
> from 0 to DF]
>                 }
> 
>                 Return (0xFF)
>             }
>         }
>     }
> }
Randolph Ha Jan. 8, 2025, 9:29 a.m. UTC | #9
Hello,

On Tue, Jan 7, 2025 at 11:51 PM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> There should be Device() node for that too. The ones you listed are just
> child devices connected to that bus.

You're right, after searching for Device nodes I was able to find this
snippet. But it doesn't seem to have anything related to HCNT/LCNT
values either, but maybe they're hidden somewhere.
Thanks for the tip again.

Scope (_SB.PC00)
{
    Scope (\_SB.PC00)
    {
        Method (SOD3, 3, Serialized)
        {
            OperationRegion (ICB1, SystemMemory, (GPCB () + Arg0), 0x88)
            If (Arg1)
            {
                Field (ICB1, ByteAcc, NoLock, Preserve)
                {
                    Offset (0x84),
                    PMEC,   8
                }

                PMEC = 0x03
                PMEC |= Zero
            }

            If ((Arg1 && Arg2))
            {
                Field (ICB1, AnyAcc, NoLock, Preserve)
                {
                    Offset (0x10),
                    BAR0,   64
                }

                BAR0 = Zero
            }
        }
    }

    Method (I2CH, 1, Serialized)
    {
        OperationRegion (ICB1, SystemMemory, Arg0, 0x20)
        Field (ICB1, AnyAcc, NoLock, Preserve)
        {
            Offset (0x10),
            BAR0,   64,
            BAR1,   64
        }

        Name (BUF0, ResourceTemplate ()
        {
            Memory32Fixed (ReadWrite,
                0x00000000,         // Address Base
                0x00001000,         // Address Length
                _Y2B)
        })
        Name (BUF1, ResourceTemplate ()
        {
            Memory32Fixed (ReadWrite,
                0x00000000,         // Address Base
                0x00001000,         // Address Length
                _Y2C)
        })
        CreateDWordField (BUF0, \_SB.PC00.I2CH._Y2B._BAS, ADR0)  //
_BAS: Base Address
        CreateDWordField (BUF1, \_SB.PC00.I2CH._Y2C._BAS, ADR1)  //
_BAS: Base Address
        ADR0 = (BAR0 & 0xFFFFFFFFFFFFF000)
        ADR1 = (BAR1 & 0xFFFFFFFFFFFFF000)
        ConcatenateResTemplate (BUF0, BUF1, Local0)
        Return (Local0)
    }

    Device (I2C0)
    {
        If ((IM00 == 0x02))
        {
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Return (I2CH (IC00))
            }

            Name (_STA, 0x08)  // _STA: Status
        }

        If ((IM00 == One))
        {
            Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
            {
                If (PCIC (Arg0))
                {
                    Return (PCID (Arg0, Arg1, Arg2, Arg3))
                }

                Return (Buffer (One)
                {
                     0x00                                             // .
                })
            }

            Method (_PS3, 0, NotSerialized)  // _PS3: Power State 3
            {
                SOD3 (IC00, One, One)
            }

            Method (_PS0, 0, NotSerialized)  // _PS0: Power State 0
            {
            }
        }

        If (((IM00 == One) || (IM00 == Zero)))
        {
            Method (_ADR, 0, NotSerialized)  // _ADR: Address
            {
                Return (0x00150000)
            }
        }
    }

    [...I2C1-7 nodes removed]

    Method (SPIH, 1, Serialized)
    {
        OperationRegion (ICB1, SystemMemory, Arg0, 0x20)
        Field (ICB1, AnyAcc, NoLock, Preserve)
        {
            Offset (0x10),
            BAR0,   64,
            BAR1,   64
        }

        Name (BUF0, ResourceTemplate ()
        {
            Memory32Fixed (ReadWrite,
                0x00000000,         // Address Base
                0x00001000,         // Address Length
                _Y2D)
        })
        Name (BUF1, ResourceTemplate ()
        {
            Memory32Fixed (ReadWrite,
                0x00000000,         // Address Base
                0x00001000,         // Address Length
                _Y2E)
        })
        CreateDWordField (BUF0, \_SB.PC00.SPIH._Y2D._BAS, ADR0)  //
_BAS: Base Address
        CreateDWordField (BUF1, \_SB.PC00.SPIH._Y2E._BAS, ADR1)  //
_BAS: Base Address
        ADR0 = (BAR0 & 0xFFFFFFFFFFFFF000)
        ADR1 = (BAR1 & 0xFFFFFFFFFFFFF000)
        ConcatenateResTemplate (BUF0, BUF1, Local0)
        Return (Local0)
    }

    [...SPI nodes removed]
}
Mika Westerberg Jan. 9, 2025, 11:19 a.m. UTC | #10
Hi,

On Wed, Jan 08, 2025 at 03:29:34AM -0600, R Ha wrote:
> On Tue, Jan 7, 2025 at 11:51 PM Mika Westerberg
> <mika.westerberg@linux.intel.com> wrote:
> > There should be Device() node for that too. The ones you listed are just
> > child devices connected to that bus.
> 
> You're right, after searching for Device nodes I was able to find this
> snippet. But it doesn't seem to have anything related to HCNT/LCNT
> values either, but maybe they're hidden somewhere.
> Thanks for the tip again.

Can you share the whole acpidump? It is easier for us to check the
necessary descriptions directly from that.
Randolph Ha Jan. 10, 2025, 8:31 a.m. UTC | #11
Hi,

Sounds like a good idea. I'm a little worried I'm missing something,
so I think being able to check my earlier answers will help as well.
I'm sending the entire output as attachments, but let me know if it's
better to upload them somewhere and paste the link instead. Some of
the ssdt* files are missing, but they're empty files so Gmail won't
let me attach them.

On Thu, Jan 9, 2025 at 5:19 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
>
> Hi,
>
> On Wed, Jan 08, 2025 at 03:29:34AM -0600, R Ha wrote:
> > On Tue, Jan 7, 2025 at 11:51 PM Mika Westerberg
> > <mika.westerberg@linux.intel.com> wrote:
> > > There should be Device() node for that too. The ones you listed are just
> > > child devices connected to that bus.
> >
> > You're right, after searching for Device nodes I was able to find this
> > snippet. But it doesn't seem to have anything related to HCNT/LCNT
> > values either, but maybe they're hidden somewhere.
> > Thanks for the tip again.
>
> Can you share the whole acpidump? It is easier for us to check the
> necessary descriptions directly from that.
Mika Westerberg Jan. 10, 2025, 11:26 a.m. UTC | #12
Hi,

On Fri, Jan 10, 2025 at 02:31:26AM -0600, R Ha wrote:
> Hi,
> 
> Sounds like a good idea. I'm a little worried I'm missing something,
> so I think being able to check my earlier answers will help as well.
> I'm sending the entire output as attachments, but let me know if it's
> better to upload them somewhere and paste the link instead. Some of
> the ssdt* files are missing, but they're empty files so Gmail won't
> let me attach them.

Thanks for sharing! Okay checked now dsdt.dsl (the other files are not
relevant here) and what I can tell the device is supposed to be run at 400
kHz. I suspect this is what Windows is doing as well, there is nothing that
indicates otherwise.

And since this is a standard I2C HID device it should just work (as it does
not require any vendor specific driver even in Windows).

Only thing I can think of that affects this is the LCNT/HCNT and SDA hold
values of the I2C designware controller (and maybe the input clock) but
there is nothing in the ACPI tables that set these so it could be that the
Windows driver uses different values for those and that explains why it
works better there.

@Jarkko, do you have any input here? If we cannot figure a better way then
I don't see other option than to add this quirk.
Jarkko Nikula Jan. 10, 2025, 11:45 a.m. UTC | #13
On 1/10/25 1:26 PM, Mika Westerberg wrote:
> Hi,
> 
> On Fri, Jan 10, 2025 at 02:31:26AM -0600, R Ha wrote:
>> Hi,
>>
>> Sounds like a good idea. I'm a little worried I'm missing something,
>> so I think being able to check my earlier answers will help as well.
>> I'm sending the entire output as attachments, but let me know if it's
>> better to upload them somewhere and paste the link instead. Some of
>> the ssdt* files are missing, but they're empty files so Gmail won't
>> let me attach them.
> 
> Thanks for sharing! Okay checked now dsdt.dsl (the other files are not
> relevant here) and what I can tell the device is supposed to be run at 400
> kHz. I suspect this is what Windows is doing as well, there is nothing that
> indicates otherwise.
> 
> And since this is a standard I2C HID device it should just work (as it does
> not require any vendor specific driver even in Windows).
> 
> Only thing I can think of that affects this is the LCNT/HCNT and SDA hold
> values of the I2C designware controller (and maybe the input clock) but
> there is nothing in the ACPI tables that set these so it could be that the
> Windows driver uses different values for those and that explains why it
> works better there.
> 
> @Jarkko, do you have any input here? If we cannot figure a better way then
> I don't see other option than to add this quirk.

Unfortunately I don't have idea.
Mika Westerberg Jan. 10, 2025, 12:07 p.m. UTC | #14
On Fri, Jan 10, 2025 at 01:45:03PM +0200, Jarkko Nikula wrote:
> On 1/10/25 1:26 PM, Mika Westerberg wrote:
> > Hi,
> > 
> > On Fri, Jan 10, 2025 at 02:31:26AM -0600, R Ha wrote:
> > > Hi,
> > > 
> > > Sounds like a good idea. I'm a little worried I'm missing something,
> > > so I think being able to check my earlier answers will help as well.
> > > I'm sending the entire output as attachments, but let me know if it's
> > > better to upload them somewhere and paste the link instead. Some of
> > > the ssdt* files are missing, but they're empty files so Gmail won't
> > > let me attach them.
> > 
> > Thanks for sharing! Okay checked now dsdt.dsl (the other files are not
> > relevant here) and what I can tell the device is supposed to be run at 400
> > kHz. I suspect this is what Windows is doing as well, there is nothing that
> > indicates otherwise.
> > 
> > And since this is a standard I2C HID device it should just work (as it does
> > not require any vendor specific driver even in Windows).
> > 
> > Only thing I can think of that affects this is the LCNT/HCNT and SDA hold
> > values of the I2C designware controller (and maybe the input clock) but
> > there is nothing in the ACPI tables that set these so it could be that the
> > Windows driver uses different values for those and that explains why it
> > works better there.
> > 
> > @Jarkko, do you have any input here? If we cannot figure a better way then
> > I don't see other option than to add this quirk.
> 
> Unfortunately I don't have idea.

Okay thanks anyway! Then I don't see any other option than adding that
quirk.

@R Ha, can you then submit a new version of the patch with the latest
details in the changelog?
Randolph Ha Jan. 11, 2025, 4:05 p.m. UTC | #15
Hi,

I updated the description, please let me know if it's covered everything.

Just as a question, because the touchpad works well at both 100KHz and
1000KHz, is it better to force it to 100KHz or 1000KHz? I was
considering that the Microsoft docs [1] specified that the frequency
should be "no less than 400KHz", but didn't change it for now because
the touchpad feels the same at 100KHz and 1000KHz, including for
gestures.

Is it possible that there will be any sort of compatibility issues if
the speed is set to 1000KHz? From what I can tell, the only other
device on I2C1 is the "Intel Smart Sound" related device, but I'm not
exactly sure what that does or whether it will work at 1000KHz. The
sound output itself seems to be unaffected regardless of the
frequency, though I don't think the other device is directly related
to sound output.

[1]: https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchpad-device-bus-connectivity#acpi-table-entries

On Fri, Jan 10, 2025 at 6:07 AM Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
>
> On Fri, Jan 10, 2025 at 01:45:03PM +0200, Jarkko Nikula wrote:
> > On 1/10/25 1:26 PM, Mika Westerberg wrote:
> > > Hi,
> > >
> > > On Fri, Jan 10, 2025 at 02:31:26AM -0600, R Ha wrote:
> > > > Hi,
> > > >
> > > > Sounds like a good idea. I'm a little worried I'm missing something,
> > > > so I think being able to check my earlier answers will help as well.
> > > > I'm sending the entire output as attachments, but let me know if it's
> > > > better to upload them somewhere and paste the link instead. Some of
> > > > the ssdt* files are missing, but they're empty files so Gmail won't
> > > > let me attach them.
> > >
> > > Thanks for sharing! Okay checked now dsdt.dsl (the other files are not
> > > relevant here) and what I can tell the device is supposed to be run at 400
> > > kHz. I suspect this is what Windows is doing as well, there is nothing that
> > > indicates otherwise.
> > >
> > > And since this is a standard I2C HID device it should just work (as it does
> > > not require any vendor specific driver even in Windows).
> > >
> > > Only thing I can think of that affects this is the LCNT/HCNT and SDA hold
> > > values of the I2C designware controller (and maybe the input clock) but
> > > there is nothing in the ACPI tables that set these so it could be that the
> > > Windows driver uses different values for those and that explains why it
> > > works better there.
> > >
> > > @Jarkko, do you have any input here? If we cannot figure a better way then
> > > I don't see other option than to add this quirk.
> >
> > Unfortunately I don't have idea.
>
> Okay thanks anyway! Then I don't see any other option than adding that
> quirk.
>
> @R Ha, can you then submit a new version of the patch with the latest
> details in the changelog?
Mika Westerberg Jan. 13, 2025, 6:49 a.m. UTC | #16
On Sat, Jan 11, 2025 at 10:05:23AM -0600, R Ha wrote:
> Hi,
> 
> I updated the description, please let me know if it's covered everything.

Thanks, I commented few things there.

> Just as a question, because the touchpad works well at both 100KHz and
> 1000KHz, is it better to force it to 100KHz or 1000KHz? I was
> considering that the Microsoft docs [1] specified that the frequency
> should be "no less than 400KHz", but didn't change it for now because
> the touchpad feels the same at 100KHz and 1000KHz, including for
> gestures.
> 
> Is it possible that there will be any sort of compatibility issues if
> the speed is set to 1000KHz? From what I can tell, the only other
> device on I2C1 is the "Intel Smart Sound" related device, but I'm not
> exactly sure what that does or whether it will work at 1000KHz. The
> sound output itself seems to be unaffected regardless of the
> frequency, though I don't think the other device is directly related
> to sound output.

I would say 100kHz is safer, all the devices should support it even the
older ones.
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;
 }