]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
platform/x86: uniwill-laptop: Mark FN lock status as being volatile
authorArmin Wolf <W_Armin@gmx.de>
Wed, 18 Feb 2026 00:51:00 +0000 (01:51 +0100)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Mon, 23 Feb 2026 16:06:42 +0000 (18:06 +0200)
It turns out that the FN lock status can be changed by the underlying
hardware when the user presses a special key combination. Mark the
associated register as volatile to prevent regmap from caching said
value. Also add the necessary suspend/resume handling.

Fixes: d050479693bb ("platform/x86: Add Uniwill laptop driver")
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://patch.msgid.link/20260218005101.73680-4-W_Armin@gmx.de
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/x86/uniwill/uniwill-acpi.c

index e0f3740a6d3af936cd4f2025d7ae4dbc5d9d6f85..73b3d909e2b0ba46c3fa0531a7ee32fb2ef0850b 100644 (file)
@@ -330,6 +330,7 @@ struct uniwill_data {
        struct acpi_battery_hook hook;
        unsigned int last_charge_ctrl;
        struct mutex battery_lock;      /* Protects the list of currently registered batteries */
+       unsigned int last_status;
        unsigned int last_switch_status;
        struct mutex super_key_lock;    /* Protects the toggling of the super key lock state */
        struct list_head batteries;
@@ -580,6 +581,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
        case EC_ADDR_SECOND_FAN_RPM_1:
        case EC_ADDR_SECOND_FAN_RPM_2:
        case EC_ADDR_BAT_ALERT:
+       case EC_ADDR_BIOS_OEM:
        case EC_ADDR_PWM_1:
        case EC_ADDR_PWM_2:
        case EC_ADDR_TRIGGER:
@@ -1508,7 +1510,19 @@ static void uniwill_shutdown(struct platform_device *pdev)
        regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
 }
 
-static int uniwill_suspend_keyboard(struct uniwill_data *data)
+static int uniwill_suspend_fn_lock(struct uniwill_data *data)
+{
+       if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+               return 0;
+
+       /*
+        * The EC_ADDR_BIOS_OEM is marked as volatile, so we have to restore it
+        * ourselves.
+        */
+       return regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &data->last_status);
+}
+
+static int uniwill_suspend_super_key(struct uniwill_data *data)
 {
        if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
                return 0;
@@ -1547,7 +1561,11 @@ static int uniwill_suspend(struct device *dev)
        struct uniwill_data *data = dev_get_drvdata(dev);
        int ret;
 
-       ret = uniwill_suspend_keyboard(data);
+       ret = uniwill_suspend_fn_lock(data);
+       if (ret < 0)
+               return ret;
+
+       ret = uniwill_suspend_super_key(data);
        if (ret < 0)
                return ret;
 
@@ -1565,7 +1583,16 @@ static int uniwill_suspend(struct device *dev)
        return 0;
 }
 
-static int uniwill_resume_keyboard(struct uniwill_data *data)
+static int uniwill_resume_fn_lock(struct uniwill_data *data)
+{
+       if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+               return 0;
+
+       return regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS,
+                                 data->last_status);
+}
+
+static int uniwill_resume_super_key(struct uniwill_data *data)
 {
        unsigned int value;
        int ret;
@@ -1613,7 +1640,11 @@ static int uniwill_resume(struct device *dev)
        if (ret < 0)
                return ret;
 
-       ret = uniwill_resume_keyboard(data);
+       ret = uniwill_resume_fn_lock(data);
+       if (ret < 0)
+               return ret;
+
+       ret = uniwill_resume_super_key(data);
        if (ret < 0)
                return ret;