This article documents a clean, reliable, and distribution-agnostic method to dynamically adjust CPU frequency limits based on whether a laptop is running on AC power or battery, using udev and cpupower.
The solution:
cpupower is availableOn Debian/Ubuntu systems, the binary is typically provided by:
linux-tools-common
Verify:
which cpupower
cpupower --version
If missing:
apt install -y linux-tools-common
cpupower frequency-info | grep driver
Typical outputs:
intel_pstateamd_pstateThis solution works correctly with both.
The kernel exposes AC power state via:
/sys/class/power_supply/*/online
online = 1 → AC connectedonline = 0 → Running on batteryudev can react to these state changes.
Create the rule file:
vim /etc/udev/rules.d/99-cpu-power.rules
powersave governorSUBSYSTEM=="power_supply", ATTR{type}=="Mains", ATTR{online}=="1", RUN+="/usr/bin/cpupower frequency-set -g powersave -u 3000MHz"
SUBSYSTEM=="power_supply", ATTR{type}=="Mains", ATTR{online}=="0", RUN+="/usr/bin/cpupower frequency-set -g powersave -u 2000MHz"
Adjust the frequencies to match your hardware and thermal limits.
Reload udev rules:
udevadm control --reload
Trigger the rule immediately (no reboot required):
udevadm trigger --subsystem-match=power_supply
cpupower frequency-info
Look for:
powersaveUnplug AC power
cpupower frequency-info | grep "max frequency"
Expected: 2.00 GHz
Plug AC power back in
cpupower frequency-info | grep "max frequency"
Expected: 3.00 GHz (or your configured value)
cpupower uses kernel-supported cpufreq interfacespower-profiles-daemon) may override limits unless disabled| Aspect | Result |
|---|---|
| Dynamic AC/Battery switching | ✔ |
| Persistent across reboots | ✔ |
| Works with intel_pstate / amd_pstate | ✔ |
| No cron or systemd units | ✔ |
| Kernel-supported | ✔ |
This is one of the simplest and most robust ways to implement battery-aware CPU frequency control on Linux laptops.
End of document