Environment
- TLP 1.10.1
- Fedora 44, kernel 7.0.9-205.fc44.x86_64
- ThinkPad T14 Gen 6 (21QCCTO1WW), BIOS 1.13, EC 1.12
- AC charging via USB-C PD (port USBC000:002)
Bug
After re-plugging AC, tlp-stat -s shows a contradictory state:
TLP profile = balanced/BAT (BAT-mode profile applied)
Power source = AC (AC correctly detected)
last run = 8 sec(s) ago (tlp auto was triggered)
tlp auto fires correctly on the udev event, detects AC, but applies a BAT profile. tlp ac (manual) works correctly and applies performance/AC. So the AC mode itself is fine — only the auto-detection path inside tlp auto makes the wrong decision.
This breaks DEVICES_TO_ENABLE_ON_AC (Bluetooth stays disabled after re-plug) and any setting that depends on the correct mode being applied.
Reproduction
- Boot with AC connected, confirm
tlp-stat -s shows TLP profile = */AC
- Unplug AC → TLP transitions to
*/BAT correctly
- Re-plug AC →
tlp auto runs but applies a BAT profile despite AC/online = 1
Reproducible at every replug.
Expected
tlp auto should detect /sys/class/power_supply/AC/online = 1 and apply the AC profile.
Actual
tlp auto applies the BAT profile despite AC/online = 1 and tlp-stat reporting Power source = AC.
Diagnostic data
/sys/class/power_supply/ (AC plugged)
AC/online = 1
ucsi-source-psy-USBC000:002/online = 1
ucsi-source-psy-USBC000:001/online = 0
hid-c8:f2:2f:42:78:bb-battery/online = 1
Note the presence of ucsi-source-psy-* (USB-C System Interface) and hid-*-battery (Bluetooth peripheral) pseudo-power-supplies. They likely confuse the auto-detection logic.
udevadm monitor --udev --subsystem-match=power_supply, replug sequence
UDEV [15278.053] change .../ucsi-source-psy-USBC000:002
UDEV [15278.227] change .../ucsi-source-psy-USBC000:002
UDEV [15278.874] change .../ucsi-source-psy-USBC000:002
UDEV [15279.115] change .../ucsi-source-psy-USBC000:002
UDEV [15279.289] change .../ucsi-source-psy-USBC000:002
UDEV [15279.533] change .../power_supply/BAT0
UDEV [15280.036] change .../power_supply/AC ← real AC event 2 s after first ucsi
The default rule (SUBSYSTEM=="power_supply", KERNEL!="hidpp_battery*") fires tlp auto on each event, including the 5 ucsi events that arrive before AC/online is updated. But even running tlp auto manually with stable AC/online = 1 keeps applying the wrong profile, so the bug isn't purely a race condition.
Workaround
Override /usr/lib/udev/rules.d/85-tlp.rules with a stricter version in /etc/udev/rules.d/85-tlp.rules that filters on type=Mains and bypasses tlp auto by calling tlp ac / tlp bat directly:
ACTION=="change", SUBSYSTEM=="power_supply", ATTR{type}=="Mains", ATTR{online}=="1", RUN+="/usr/bin/tlp ac"
ACTION=="change", SUBSYSTEM=="power_supply", ATTR{type}=="Mains", ATTR{online}=="0", RUN+="/usr/bin/tlp bat"
After this change, transitions are reliable and consistent in both directions.
Suggested fix
Two non-exclusive directions:
- Audit
tlp auto's get_power_supply_state() (or equivalent) to ensure it filters power_supply devices by type=Mains and ignores ucsi-source-psy-* and hid-*-battery entries when determining AC vs BAT.
- Tighten the default udev rule with
ATTR{type}=="Mains" to avoid spurious triggers from USB-C PD and HID peripheral events. This is a portable variant of the KERNEL=="ADP*" suggestion from #826, which works regardless of the AC device name.
Related
#826 — Lenovo Legion 15AKP10 firing excessive battery events. Different root cause but same family of problem (default rule too broad). Closed as won't fix at the time.
Happy to provide further diagnostic data or test a patch.
Environment
Bug
After re-plugging AC,
tlp-stat -sshows a contradictory state:tlp autofires correctly on the udev event, detectsAC, but applies a BAT profile.tlp ac(manual) works correctly and appliesperformance/AC. So the AC mode itself is fine — only the auto-detection path insidetlp automakes the wrong decision.This breaks
DEVICES_TO_ENABLE_ON_AC(Bluetooth stays disabled after re-plug) and any setting that depends on the correct mode being applied.Reproduction
tlp-stat -sshowsTLP profile = */AC*/BATcorrectlytlp autoruns but applies a BAT profile despiteAC/online = 1Reproducible at every replug.
Expected
tlp autoshould detect/sys/class/power_supply/AC/online = 1and apply the AC profile.Actual
tlp autoapplies the BAT profile despiteAC/online = 1andtlp-statreportingPower source = AC.Diagnostic data
/sys/class/power_supply/(AC plugged)Note the presence of
ucsi-source-psy-*(USB-C System Interface) andhid-*-battery(Bluetooth peripheral) pseudo-power-supplies. They likely confuse the auto-detection logic.udevadm monitor --udev --subsystem-match=power_supply, replug sequenceThe default rule (
SUBSYSTEM=="power_supply", KERNEL!="hidpp_battery*") firestlp autoon each event, including the 5 ucsi events that arrive beforeAC/onlineis updated. But even runningtlp automanually with stableAC/online = 1keeps applying the wrong profile, so the bug isn't purely a race condition.Workaround
Override
/usr/lib/udev/rules.d/85-tlp.ruleswith a stricter version in/etc/udev/rules.d/85-tlp.rulesthat filters ontype=Mainsand bypassestlp autoby callingtlp ac/tlp batdirectly:After this change, transitions are reliable and consistent in both directions.
Suggested fix
Two non-exclusive directions:
tlp auto'sget_power_supply_state()(or equivalent) to ensure it filters power_supply devices bytype=Mainsand ignoresucsi-source-psy-*andhid-*-batteryentries when determining AC vs BAT.ATTR{type}=="Mains"to avoid spurious triggers from USB-C PD and HID peripheral events. This is a portable variant of theKERNEL=="ADP*"suggestion from #826, which works regardless of the AC device name.Related
#826 — Lenovo Legion 15AKP10 firing excessive battery events. Different root cause but same family of problem (default rule too broad). Closed as won't fix at the time.
Happy to provide further diagnostic data or test a patch.