bitland-mifs-wmi: battery charge limit (command 0x10) on Xiaomi models

From: Anton Karasev

Date: Thu Oct 08 2026 - 11:31:32 EST


Hi all,

(Sebastian, linux-pm: Cc'd for the charge_types choice below.)

On the Redmi Book Pro 16 2024 (DMI XIAOMI / TM2309, BIOS
RMAMT6B0P0B0B), command 0x10 (WMI_FN_RGB_KB_MODE in the driver) is the
battery interface of WMAA, and its subcommand 2 is the firmware's 80 %
charge limit, which is why writing "fixed" to kb_mode turns the limit
off [1]. Milos found the same handling in the tables of the TM2307 [2].
So please do not write to command 0x10 on Xiaomi machines for now,
kb_mode included; I have sent a patch that hides kb_mode where the
firmware does not answer its GET [3]. I would like to support the limit
in the driver, but the command seems to differ between Xiaomi models,
so the first step is to find out what other firmware does with it.

On this BIOS WMAA handles command 0x10 as follows ("Case (0x1000)";
subcommand in payload bytes 0-1, value in bytes 2-5; full acpidump in
[4]):

GET 0x10/1 EC register SOH1, presumably battery health (96 here)
GET 0x10/2 charge limit: 1 = on, 0 = off (bit 0 of EC LONL)
GET 0x10/3 1 if EC register ADPW < 0x8C (ADPW reads 140 with the
stock 140 W charger, 100 with a 100 W one, 0 on battery)
SET 0x10/2 value 1 sets bit 0 of LONL, any other value clears it

Other subcommands are not handled (the reply is all zeros, return code
included), and nothing else in the ACPI tables touches LONL. As with
command 0x08, the SET reply carries only the return code, so with
23cc56f6dea6 ("platform/x86: bitland-mifs-wmi: Detect failed function
calls") in for-next a SET also needs Chris's GET-only change [5].

With AC connected, setting the bit makes the EC change register AFBC
from 100 to 80; nothing in the ACPI tables writes AFBC, so through the
firmware the limit is fixed at 80 %. Charging stopped at 80 % ("Not
charging"), switching the bit at 80 % toggled charging within about a
second, and turning it on at 81 % stopped charging without
discharging. The setting survived charger replugs, s2idle and about 17
hours on AC, but not the battery running flat: after it had run empty
in s2idle and the machine was started again on AC, the bit was clear
and the battery charged to 100 %, with nothing in Linux writing to it.
Whether the EC lost it with power or earlier, at a critically low
charge, I cannot tell. I have not tested a plain reboot, a power-off or
hibernation.

Because the limit is fixed, the power supply ABI as updated in the
power-supply tree (b3e6d01c33eb, "Documentation: sysfs-class-power:
Update Long_Life description") calls for charge_types "Standard" /
"Long Life" rather than charge_control_end_threshold: an ACPI battery
hook with a power supply extension, as in acer-wmi-battery. Since
command 0x10 is the RGB keyboard mode on the machines the driver was
written for, this needs a per-model flag, so I would base it on the
generalized profile handling Chris is preparing (see Ilpo's reply [6]),
together with the TM2309 entry. One detail for it: the EC notifies BAT0
itself (_Q0B) 0.6-1 s after the write, but an immediate
power_supply_changed() fills the one-second _BST cache, so that
notification reports the old status and the driver has to notify again
a couple of seconds later.

Other models: according to the notes of XiControl [7] (a Windows tool;
in Russian, not verified by me), the Xiaomi Book Pro 14 (TM2424) takes
a level code in 0x10/2, for limits from 40 % to 80 %;
xiaomi_pc_manager_lite [8] maps code 4 to 90 % instead, and the TM2424
WMAA as described in micontrol [9] (which takes these for brightness
levels) writes 0x50, 0x5A, 0x46 ... 0x28 (80, 90, 70 ... 40) to EC
offset 0xA7 for codes 1 and 4-8. CoreCharge [10], which writes the EC
directly, toggles the limit with bit 0 at EC offset 0xA4 (LONL here) on
the Redmibook Pro 14 2025 and the Xiaomi Book Pro 14 2026 and writes
the percentage to 0xA7 as well; on TM2309 that byte is unused by ACPI
and read 0 with the limit on and off. As any value other than 1 turns
the limit off on TM2309, level codes cannot be written blindly, and a
model with real levels would rather use charge_control_end_threshold.
XiControl also found that the Redmi Book Pro 15 2022 Ryzen (TM2113)
does not implement 0x10 at all (writes to 0x10/2 left the reply
unchanged), so support has to be known per model.

Chris, Kento, Yuming: if the SSDT of your Xiaomi Book Pro 14 is at
hand, does its WMAA "Case (0x1000)" agree with these notes, and in
particular, does code 4 write 0x50 or 0x5A to 0xA7? Ilya: which
board_name does your Redmi Book Pro 15 2022 have, and does its WMAA
handle 0x1000 at all? Aleksey (Pro 16 2025), Matias (TM2107), Ibragim
(TM2209), Eason (TM2426): does your WMAA handle 0x1000? From
anyone else, the part of WMAA that handles 0x10, or just the model and
BIOS version, would help, and so would the limits Xiaomi's Windows
software offers. Please send full acpidumps off-list (several MB).

[1] https://lore.kernel.org/all/20260930015058.3076905-1-uselessfire@xxxxxxxxx/
[2] https://lore.kernel.org/all/CAObHBTwnv+kEaFdCp+cr31HtdSo3CaRq84T8vr-Pm75yZMTHqQ@xxxxxxxxxxxxxx/
[3] https://lore.kernel.org/all/20261008-bitland-kb-mode-v1-uselessfire@xxxxxxxxx/
[4] https://bugzilla.kernel.org/attachment.cgi?id=310971
[5] https://lore.kernel.org/all/20260928154337.154969-1-chris@xxxxxxxxx/
[6] https://lore.kernel.org/all/094577b3-7b96-72b6-4ef2-a5d1db457401@xxxxxxxxxxxxxxx/
[7] https://github.com/Oksion/XiControl/blob/main/docs/01-wmi-protocol.md
[8] https://github.com/CHHHHHHEN/xiaomi_pc_manager_lite
[9] https://github.com/arcane-D7/micontrol/blob/main/docs/HARDWARE_INVESTIGATION.md
[10] https://github.com/alex-bogatiuk/Xiaomi-CoreCharge

Thanks,
Anton Karasev