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.