A Framework touchpad that "lagged" after resume, and the one-line driver rebind that fixed it

This morning I sat down at my Framework as usual, but the touchpad was annoying — glitchy, laggy, unresponsive, a whole bunch of little problems at once.

At first I suspected something mechanical, so I tried all sorts of things, including bending the chassis a bit to see if it was a flaky connection. I was too lazy to reboot — but the nagging thought that a reboot might fix it was itself the clue that this could be software. Apparently I wasn't too lazy to start debugging.

Once I actually paid attention, the fault had a distinctive shape: a slight delay before the touchpad started sending events. Move a finger, brief nothing, then the pointer catches up. Once it was moving it tracked perfectly; the lag only hit on the first touch after a pause. That "wake-up latency on first event" shape is the tell — it points at power state, not load or configuration.

Not the usual suspects

The reflex is to blame the compositor's input config. On Hyprland that would be input { touchpad { ... } } in hyprland.conf — but nothing there had changed, and a bad sensitivity~/~accel setting produces wrong motion, not delayed onset. Ruled out.

Load average was 1.0 on a 16-thread machine, ~87% idle. Not contention.

The device itself, from libinput list-devices:

1Device:           PIXA3854:00 093A:0274 Touchpad
2Kernel:           /dev/input/event5
3Id:               i2c:093a:0274
4Capabilities:     pointer gesture

An I2C-HID device (i2c:093a:0274), bound to the i2c_hid_acpi driver, hanging off the AMD I2C controller AMDI0010:03. That detail matters: I2C-HID peripherals are woken/slept over the I2C bus via ACPI power methods, and that handshake can fail in ways a USB device's cannot.

The kernel ring buffer had it

dmesg told the whole story. Timestamps well into the session (~47950s ≈ 13h uptime), not from boot:

1i2c_hid_acpi i2c-PIXA3854:00: failed to change power setting.
2i2c_hid_acpi i2c-PIXA3854:00: PM: dpm_run_callback(): acpi_subsys_resume returns -121
3i2c_hid_acpi i2c-PIXA3854:00: PM: failed to resume async: error -121

-121 is EREMOTEIO — a remote I/O error on the I2C transaction. The device failed to complete its resume power-setting change. Correlating with systemd in the journal pinned it to a specific suspend/resume:

1Jul 13 09:16:41 framework kernel: pcieport 0000:00:08.3: quirk: disabling D3cold for suspend
2Jul 13 09:16:41 framework kernel: i2c_hid_acpi i2c-PIXA3854:00: PM: dpm_run_callback(): acpi_subsys_resume returns -121
3Jul 13 09:16:41 framework kernel: i2c_hid_acpi i2c-PIXA3854:00: PM: failed to resume async: error -121
4Jul 13 09:16:41 framework systemd-sleep[*]: System returned from sleep operation 'suspend'.

So: the machine suspended in the morning; on resume the touchpad's I2C-HID controller did not complete its power transition. The driver stayed attached but the device sat in a half-initialised power state, re-negotiating the bus on each first touch — exactly the observed latency.

Runtime PM was not the cause, incidentally. The controller reports:

1/sys/bus/i2c/devices/i2c-PIXA3854:00/power/control        = auto
2/sys/bus/i2c/devices/i2c-PIXA3854:00/power/runtime_status = unsupported

runtime_status = unsupported rules out autosuspend-on-idle as the mechanism. This was purely the system-sleep resume path failing.

The fix: unbind/rebind the driver

No reboot needed. Forcing the driver to detach and re-probe re-runs the device's power-on/initialisation from a clean state:

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

The device string is the I2C device name (the i2c-hid instance under /sys/bus/i2c/drivers/i2c_hid_acpi/), not the HID node. After the rebind, dmesg showed a fresh probe with no -121:

1hid-multitouch 0018:093A:0274.000A: Returned feature report did not match the request
2input: PIXA3854:00 093A:0274 Mouse as .../input/input19
3input: PIXA3854:00 093A:0274 Touchpad as .../input/input20
4hid-multitouch 0018:093A:0274.000A: input,hidraw2: I2C HID v1.00 Mouse [PIXA3854:00 093A:0274] on i2c-PIXA3854:00

(The Returned feature report did not match the request line is benign — it prints on every probe, including at boot, and does not affect function.) libinput re-enumerated the touchpad and Hyprland picked it back up automatically as pixa3854:00-093a:0274-touchpad. Latency gone.

Why the rebind works, and when to reach for something heavier

Unbind runs the driver's .remove; bind runs .probe, which re-issues the ACPI power-on and re-reads the HID descriptors. It is the software equivalent of unplugging and replugging, without the physical port — and for an I2C-HID device stuck in a bad power state after resume, that is precisely enough. It is reversible and low-risk (keep a USB mouse or the keyboard handy in case anything needs confirming during the second or two the device is gone).

Cheaper alternatives that also clear it: another suspend/resume cycle (lid close/open) or a reboot. The rebind is just the least disruptive.

This was a one-off resume glitch. If it recurs after most suspends, that is a different problem and deserves a durable fix rather than repeated rebinds. So far I only recall this happening this one time.