zam@zsbahtiar:~$

cat ~/notes/touchpad-dead-after-suspend.md

reviving an i2c touchpad after suspend without rebooting

[id]

reviving an i2c touchpad after suspend without rebooting

Every time my laptop resumed from suspend, the screen, keyboard, and applications came back normally. The touchpad did not.

It remained visible to Linux, but stopped producing input completely. A Bluetooth mouse still worked, so the failure was isolated to one device path.

Rebooting brought the touchpad back. Unbinding and rebinding one driver did the same thing in a few seconds.

Which path does the touchpad use?

The first step was identifying the bus and driver behind the input device:

grep -iE "touchpad|i2c" /proc/bus/input/devices

The relevant output was:

N: Name="GXTP5100:00 27C6:01E0 Touchpad"
S: Sysfs=.../i2c_designware.0/i2c-0/i2c-GXTP5100:00/...

This is a Goodix GXTP5100 connected over I2C, not USB. The hardware path goes through Intel’s i2c-designware controller, while i2c_hid_acpi handles the touchpad itself.

The expected modules were loaded:

lsmod | grep -iE "i2c_hid|hid_multitouch"
# i2c_hid_acpi   ...
# i2c_hid        ...
# hid_multitouch ...

Nothing was missing. That was the problem: Linux still believed the device was initialized even though communication with it had stopped.

What breaks during resume?

Suspend powers down the I2C controller to save energy. Resume has to bring the controller back, reset the touchpad, and read its HID descriptor again.

If that power and reset sequence happens in the wrong order, the driver can remain bound to a device that no longer exchanges data. The touchpad appears present in sysfs and the modules remain loaded, but no input events arrive.

The Bluetooth mouse was a useful control case. It took a completely different hardware and driver path, so it survived the same suspend cycle.

The usual causes are:

  • a regression in the i2c-designware or i2c-hid suspend and resume path
  • laptop firmware with unreliable power sequencing during resume

I was running kernel 6.17, so a kernel regression was plausible. The immediate goal was not proving which layer was at fault. It was finding the smallest reset that restored the device.

Resetting only the touchpad driver

The device did not need a full reboot. It needed i2c_hid_acpi to release it and initialize it again.

echo -n 'i2c-GXTP5100:00' | sudo tee /sys/bus/i2c/drivers/i2c_hid_acpi/unbind
echo -n 'i2c-GXTP5100:00' | sudo tee /sys/bus/i2c/drivers/i2c_hid_acpi/bind

The identifier is specific to this laptop. Before copying the commands, list the devices attached to the driver:

ls /sys/bus/i2c/drivers/i2c_hid_acpi/

Rebinding forces the driver to repeat its initialization path. The touchpad started responding immediately.

No reboot…

If rebinding the device is not enough, the I2C controller path may need a broader reset. Reloading the modules is the next step:

sudo modprobe -r i2c_hid_acpi i2c_hid && sudo modprobe i2c_hid_acpi

Running the rebind after every resume

A manual command proved the recovery mechanism, but it did not make the laptop usable. The touchpad failed after every suspend.

systemd runs scripts in /usr/lib/systemd/system-sleep/ before suspend and after resume. Each script receives pre or post as its first argument.

I added the rebind to the post path:

sudo tee /usr/lib/systemd/system-sleep/fix-touchpad.sh > /dev/null <<'EOF'
#!/bin/sh
case "$1/$2" in
  post/*)
    D=i2c-GXTP5100:00
    echo -n "$D" > /sys/bus/i2c/drivers/i2c_hid_acpi/unbind 2>/dev/null
    sleep 1
    echo -n "$D" > /sys/bus/i2c/drivers/i2c_hid_acpi/bind 2>/dev/null
    ;;
esac
EOF
sudo chmod +x /usr/lib/systemd/system-sleep/fix-touchpad.sh

Now every resume triggers the same reset that worked manually. The rest of the system stays untouched.

A workaround with a useful boundary

This does not fix the broken resume sequence in the kernel or BIOS. It repairs the driver state after the failure has already happened.

That distinction matters when diagnosing similar issues. If an external mouse works, the touchpad remains visible, and a driver rebind restores it, the desktop session is probably not the broken layer. The failure sits lower in the I2C device path.

Until the kernel or firmware handles that path correctly, rebinding the smallest affected device is enough to avoid a reboot.


← back to blog