It was reported [1] that some unfortunate combinations of BIOS and Lenovo utilities (e.g., Legion Go 2 + Legion Space) may enable Rapid Charge and Conservation Mode at the same time, which is very out of sepc. If both are enabled during a previous Windows boot, ideapad-laptop will see both bits set and correctly shout "unexpected charge_types". A planned BIOS update will address this. Before that, if unexpected charge_types are encountered on probe, enforce [Long_Life] to prevent the device from operating in an out-of-spec state. On check or fix failure, skip registering the battery hook and the conservation_mode attribute. Note: the switches never enable themselves autonomously, so there is no need to fix it during runtime. Fixes: 90430ea98f55 ("platform/x86: ideapad-laptop: Add charge_types:Fast (Rapid Charge)") Cc: stable@vger.kernel.org Closes: https://github.com/ValveSoftware/SteamOS/issues/2876 [1] Signed-off-by: Rong Zhang --- drivers/platform/x86/lenovo/ideapad-laptop.c | 56 +++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c index 40dab4d321a4..31f74a2021b1 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -2156,6 +2156,50 @@ DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v2, BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)) ); +static int ideapad_battery_check(struct ideapad_private *priv) +{ + enum power_supply_charge_type charge_type; + unsigned long val; + int ret; + + /* Not acquiring gbmd_sbmc_mutex as race condition is impossible on init. */ + ret = eval_gbmd(priv->adev->handle, &val); + if (ret) + return ret; + + priv->features.conservation_mode = true; + priv->features.rapid_charge = test_bit(GBMD_RAPID_CHARGE_SUPPORTED_BIT, &val); + + ret = priv->features.rapid_charge ? ideapad_get_charge_types(priv, val, &charge_type) : 0; + if (ret) { + /* + * Some unfortunate combinations of BIOS and Lenovo utilities + * (e.g., Legion Go 2 + Legion Space) may enable Rapid Charge + * and Conservation Mode at the same time, which is very out of + * sepc. + * + * If both are enabled during a previous Windows boot, we will + * see both bits set. + * + * Conservation Mode should override Rapid Charge. Before a BIOS + * update addresses this, enforce it by selecting [Long_Life]. + */ + dev_notice(&priv->platform_device->dev, + "selecting [Long_life] to fix unexpected charge_types\n"); + + ret = ideapad_set_charge_types(priv, POWER_SUPPLY_CHARGE_TYPE_LONGLIFE); + if (ret) { + dev_err(&priv->platform_device->dev, + "failed to fix unexpected charge_types: %d\n", ret); + return ret; + } + + /* Best-effort only. No read back. */ + } + + return 0; +} + static int ideapad_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook); @@ -2194,12 +2238,12 @@ static int ideapad_check_features(struct ideapad_private *priv) priv->features.fan_mode = true; if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) { - /* Not acquiring gbmd_sbmc_mutex as race condition is impossible on init */ - if (!eval_gbmd(handle, &val)) { - priv->features.conservation_mode = true; - priv->features.rapid_charge = test_bit(GBMD_RAPID_CHARGE_SUPPORTED_BIT, - &val); - + err = ideapad_battery_check(priv); + if (err) { + /* Continue with no battery hook or conservation_mode attribute. */ + priv->features.conservation_mode = false; + priv->features.rapid_charge = false; + } else { priv->battery_ext = priv->features.rapid_charge ? &ideapad_battery_ext_v2 : &ideapad_battery_ext_v1; -- 2.55.0