[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260106220949.1518571-1-jriemenschne@student.ethz.ch>
Date: Tue, 6 Jan 2026 23:09:49 +0100
From: Jakob <riemenschneiderjakob@...il.com>
To: mpearson-lenovo@...ebb.ca,
derekjohn.clark@...il.com,
ikepanhc@...il.com,
hansg@...nel.org,
ilpo.jarvinen@...ux.intel.com
Cc: platform-driver-x86@...r.kernel.org,
linux-kernel@...r.kernel.org,
Jakob <jriemenschne@...dent.ethz.ch>
Subject: [PATCH v1] platform/x86: ideapad-laptop: Fix resume behavior for Lenovo Yoga 15ILL9
On the Lenovo Yoga Slim 7 15ILL9, the Embedded Controller fails to restore
its state after resuming from suspend. This results in the cooling fans
remaining stopped (causing overheating), the keyboard backlight and
brightness keys becoming unresponsive, and the power button LED continuing
to pulse as if still suspended.
Testing shows that invoking the UPHK method with command 0x09 properly
resets the EC state. This single command restores fan control, fixes the
keyboard backlight and brightness keys and corrects the power LED behavior.
This patch adds a DMI quirk to invoke this method on resume.
Note: On this model, UPHK is located at \_SB.PC00.LPCB.EC0.UPHK rather
than the standard VPC2004 device, so we access it via its absolute path.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220505
Signed-off-by: Jakob <jriemenschne@...dent.ethz.ch>
---
drivers/platform/x86/lenovo/ideapad-laptop.c | 56 ++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c
index 5171a077f..c9fec590a 100644
--- a/drivers/platform/x86/lenovo/ideapad-laptop.c
+++ b/drivers/platform/x86/lenovo/ideapad-laptop.c
@@ -43,6 +43,7 @@
#include <dt-bindings/leds/common.h>
#define IDEAPAD_RFKILL_DEV_NUM 3
+#define IDEAPAD_EC_UPHK_PATH "\\_SB.PC00.LPCB.EC0.UPHK"
enum {
CFG_CAP_BT_BIT = 16,
@@ -105,6 +106,10 @@ enum {
SALS_FNLOCK_OFF = 0xf,
};
+enum {
+ UPHK_FAN_RESUME = 0x9,
+};
+
enum {
VPCCMD_R_VPC1 = 0x10,
VPCCMD_R_BL_MAX,
@@ -198,6 +203,7 @@ struct ideapad_private {
bool ctrl_ps2_aux_port : 1;
bool usb_charging : 1;
bool ymc_ec_trigger : 1;
+ bool fan_mode_fix : 1;
} features;
struct {
bool initialized;
@@ -246,6 +252,12 @@ MODULE_PARM_DESC(touchpad_ctrl_via_ec,
"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
"tell the EC to enable/disable the touchpad. This may not work on all models.");
+static bool fan_mode_fix;
+module_param(fan_mode_fix, bool, 0444);
+MODULE_PARM_DESC(fan_mode_fix,
+ "Enable fan-mode resume fix for laptops that stop cooling after sleep. "
+ "If you need this please report this to: platform-driver-x86@...r.kernel.org");
+
static bool ymc_ec_trigger __read_mostly;
module_param(ymc_ec_trigger, bool, 0444);
MODULE_PARM_DESC(ymc_ec_trigger,
@@ -2022,6 +2034,24 @@ static const struct dmi_system_id hw_rfkill_list[] = {
{}
};
+/*
+ * On the Lenovo Yoga Slim 15ILL9, the EC fails to restore the fan control profile after
+ * resuming from suspend, causing the fans to stop working.
+ * On this model, the driver needs to explicitly reset the fan mode
+ * on resume.
+ * See https://bugzilla.kernel.org/show_bug.cgi?id=220505
+ */
+static const struct dmi_system_id fan_mode_fix_list[] = {
+ {
+ /* Lenovo Yoga Slim 7 15ILL9 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83HM"),
+ },
+ },
+ {}
+};
+
/*
* On some models the EC toggles the touchpad muted LED on touchpad toggle
* hotkey presses, but the EC does not actually disable the touchpad itself.
@@ -2185,6 +2215,8 @@ static int ideapad_check_features(struct ideapad_private *priv)
priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
priv->features.ymc_ec_trigger =
ymc_ec_trigger || dmi_check_system(ymc_ec_trigger_quirk_dmi_table);
+ priv->features.fan_mode_fix =
+ fan_mode_fix || dmi_check_system(fan_mode_fix_list);
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
priv->features.fan_mode = true;
@@ -2517,6 +2549,28 @@ static void ideapad_acpi_remove(struct platform_device *pdev)
ideapad_debugfs_exit(priv);
}
+static void ideapad_fan_mode_fix(struct ideapad_private *priv)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!priv->features.fan_mode_fix)
+ return;
+
+ status = acpi_get_handle(NULL, IDEAPAD_EC_UPHK_PATH, &handle);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(&priv->platform_device->dev, "Could not find UPHK method for fan fix\n");
+ return;
+ }
+
+ status = acpi_execute_simple_method(handle, NULL, UPHK_FAN_RESUME);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(&priv->platform_device->dev, "Failed to execute UPHK fix: %s\n",
+ acpi_format_exception(status));
+ return;
+ }
+}
+
#ifdef CONFIG_PM_SLEEP
static int ideapad_acpi_resume(struct device *dev)
{
@@ -2528,6 +2582,8 @@ static int ideapad_acpi_resume(struct device *dev)
if (priv->dytc)
dytc_profile_refresh(priv);
+ ideapad_fan_mode_fix(priv);
+
return 0;
}
#endif
--
2.52.0
Powered by blists - more mailing lists