On Lenovo 14w Gen 2 laptop, the touchpad (ELAN0643) does not work on Linux. This is due to ACPI DSDT.
This method has been tested on Debian 13.
Make sure acpidump and iasl tools are installed.
As root :
$ mkdir -p acpi/dat
$ mkdir -p acpi/dsl
$ cd acpi/dat
$ acpidump -b
$ iasl -d *.dat
$ mv *.dat ../dsl
$ cd ../../
The next step is to hack the "_DSM: Device-Specific Method" and "_CRS: Current Resource Settings" to force touchpad enablement.
Edit acpi/dsl/dsdt.dsl and locate :
Scope (_SB.I2CD)
...
Name (_HID, "ELAN0643") // _HID: Hardware ID
...
Case (0x01)
{
If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x01))
{
Return (0x01)
}
If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x02))
{
Return (0x20)
}
Change as follow (comment If and add Else):
Case (0x01)
{
If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x01))
{
Return (0x01)
}
Else
// If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x02))
{
Return (0x20)
}
Then :
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullUp, 0x0000,
"\\_SB.GPIO", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0009
}
})
If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x01))
{
Name (SBFB, ResourceTemplate ()
{
I2cSerialBusV2 (0x0015, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\\_SB.I2CD",
0x00, ResourceConsumer, , Exclusive,
)
})
Return (ConcatenateResTemplate (SBFB, SBFG))
}
If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x02))
{
Name (SBFC, ResourceTemplate ()
{
I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\\_SB.I2CD",
0x00, ResourceConsumer, , Exclusive,
)
})
Return (ConcatenateResTemplate (SBFC, SBFG))
}
}
Change as follow (Comment If and add Else) :
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullUp, 0x0000,
"\\_SB.GPIO", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0009
}
})
If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x01))
{
Name (SBFB, ResourceTemplate ()
{
I2cSerialBusV2 (0x0015, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\\_SB.I2CD",
0x00, ResourceConsumer, , Exclusive,
)
})
Return (ConcatenateResTemplate (SBFB, SBFG))
}
Else
// If ((^^^PCI0.LPC0.H_EC.ECRD (RefOf (^^^PCI0.LPC0.H_EC.TPTY)) == 0x02))
{
Name (SBFC, ResourceTemplate ()
{
I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\\_SB.I2CD",
0x00, ResourceConsumer, , Exclusive,
)
})
Return (ConcatenateResTemplate (SBFC, SBFG))
}
}
Then, we will override ACPI table :
$ mkdir -p kernel/firmware/acpi
$ cp dsl/dsdt.dsl ./
$ iasl -sa dsdt.dsl
$ cp dsdt.aml kernel/firmware/acpi
$ find kernel | cpio -H newc --create > /boot/initrd_acpi_patched
$ echo 'GRUB_EARLY_INITRD_LINUX_CUSTOM="initrd_acpi_patched"' > /etc/default/grub.d/acpi-tables.cfg
$ update-grub
Reboot ! And Voilà !