drivers/acpi/battery.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
On Friday, May 29, 2026 9:17:55 PM CEST goldi fiche wrote:
> Kernel versions:
> Works correctly: 6.18.13
> Regression starts: 6.18.16
> Affected hardware:
> Intel Gemini Lake (Celeron N4020)
> GLK MRD platform
> White-label ODM/OEM laptop (Denver branded)
> Broken SMBIOS/DMI firmware
> Relevant commit:
> bb1256e0ddc7e9e406164319769b9f8d8389f056
> "ACPI: battery: fix incorrect charging status when current is zero"
> Problem description:
> The
> heuristic introduced in the above commit appears to regress charging
> state reporting on some Gemini Lake GLK MRD systems with broken OEM
> firmware.
> The firmware reports inconsistent battery information:
> AC connected
> battery charging or pending-charge state active
> but energy-rate/current reported as 0 W
> Example UPower output while charger is connected and battery is at 37%:
> state: pending-charge
> energy-rate: 0 W
> online: yes
> percentage: 37%
> Before this commit/kernel version, the battery charging state behaved correctly from the user perspective.
What exactly do you mean by "correctly"?
I guess you want the status to be "charging" when "percentage" is not 100%?
> The affected system also contains severely broken SMBIOS/DMI data:
> "Default string"
> unresolved AMI template variables
> invalid cache sizes
> "To Be Filled By O.E.M."
> This appears to be common among Gemini Lake white-label ODM devices using GLK MRD firmware.
> A local test patch that bypasses the rate_now == 0 charging-state override restores expected charging-state behavior on this hardware.
> The
> Huawei-oriented heuristic in the referenced commit appears to be too
> broad for some GLK MRD systems with faulty EC/ACPI implementations.
It might also check whether or not the battery is full by the
capacity_now/full_charge_capacity ratio, which is done in the
patch below, so please give it a go.
However, it may not work on the Huawei machine in which case
some quirking may be needed.
---
drivers/acpi/battery.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -150,27 +150,28 @@ static int acpi_battery_technology(struc
static int acpi_battery_get_state(struct acpi_battery *battery);
-static int acpi_battery_is_charged(struct acpi_battery *battery)
+static bool __acpi_battery_is_charged(struct acpi_battery *battery)
{
- /* charging, discharging, critical low or charge limited */
- if (battery->state != 0)
- return 0;
-
/* battery not reporting charge */
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
battery->capacity_now == 0)
- return 0;
+ return false;
/* good batteries update full_charge as the batteries degrade */
- if (battery->full_charge_capacity == battery->capacity_now)
- return 1;
+ if (battery->full_charge_capacity <= battery->capacity_now)
+ return true;
/* fallback to using design values for broken batteries */
- if (battery->design_capacity <= battery->capacity_now)
- return 1;
+ return battery->design_capacity <= battery->capacity_now;
+}
- /* we don't do any sort of metric based on percentages */
- return 0;
+static int acpi_battery_is_charged(struct acpi_battery *battery)
+{
+ /* charging, discharging, critical low or charge limited */
+ if (battery->state != 0)
+ return 0;
+
+ return __acpi_battery_is_charged(battery);
}
static bool acpi_battery_is_degraded(struct acpi_battery *battery)
@@ -211,13 +212,14 @@ static int acpi_battery_get_property(str
if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
val->intval = acpi_battery_handle_discharging(battery);
else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
- /* Validate the status by checking the current. */
- if (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
- battery->rate_now == 0) {
- /* On charge but no current (0W/0mA). */
- val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else {
+ /* Check the rate and capacity to validate the status. */
+ if (!__acpi_battery_is_charged(battery) ||
+ (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
+ battery->rate_now > 0)) {
val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ } else {
+ /* Full and zero rate. */
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
else if (battery->state & ACPI_BATTERY_STATE_CHARGE_LIMITING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
© 2016 - 2026 Red Hat, Inc.