* [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes
@ 2026-09-05 13:01 Armin Wolf
2026-09-05 13:01 ` [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness Armin Wolf
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Armin Wolf @ 2026-09-05 13:01 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
This patch series mainly deals with various issues inside the code
responsible for controlling the lightbar on supported devices.
The first patch utilizes the improved multicolor LED API to report
the correct brightness of the lightbar to userspace. The next two
patches fix issues discovered inside the code for controlling
animations, while the fourth patch fixes an issue with the naming
of the LEDs in general. The last patch also adds support for another
variant of the Intel NUC x15 laptop kit.
All patches have been tested on said Intel NUC x15 laptop and appear
to work.
Armin Wolf (5):
platform/x86: uniwill-laptop: Report correct lightbar brightness
platform/x86: uniwill-laptop: Implement rainbow animation as trigger
platform/x86: uniwill-laptop: Fix breathing animation on Intel QC
platform/x86: uniwill-laptop: Label multicolor LEDs correctly
platform/x86: uniwill-laptop: Extend support for the Intel NUC x15
.../ABI/removed/sysfs-driver-uniwill-laptop | 10 +
.../ABI/testing/sysfs-driver-uniwill-laptop | 15 +-
.../admin-guide/laptops/uniwill-laptop.rst | 9 +-
MAINTAINERS | 1 +
drivers/platform/x86/uniwill/Kconfig | 1 +
drivers/platform/x86/uniwill/uniwill-acpi.c | 225 +++++++++++-------
6 files changed, 161 insertions(+), 100 deletions(-)
create mode 100644 Documentation/ABI/removed/sysfs-driver-uniwill-laptop
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
@ 2026-09-05 13:01 ` Armin Wolf
2026-10-05 16:12 ` Ilpo Järvinen
2026-09-05 13:01 ` [PATCH 2/5] platform/x86: uniwill-laptop: Implement rainbow animation as trigger Armin Wolf
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Armin Wolf @ 2026-09-05 13:01 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
The LED sysfs ABI now allows us to specify the maximum values for the
global brightness and the color intensity values independently. At the
same time the maximum brightness value reported for the lightbar (like
200) does not match the real value supported by the hardware (1),
potentially confusing users.
Report the correct maximum brightness value and only use the intensity
values for controlling the lightbar color.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 35 ++++++++++-----------
1 file changed, 16 insertions(+), 19 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 7a2eeaec4c96..7420e1dd4716 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -398,7 +398,7 @@ struct uniwill_data {
struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
struct list_head batteries;
struct mutex led_lock; /* Protects writes to the lightbar registers */
- u8 lightbar_max_brightness;
+ u8 lightbar_max_intensity;
struct led_classdev_mc led_mc_cdev;
struct mc_subled led_mc_subled_info[LED_CHANNELS];
bool kbd_led_single_color;
@@ -429,7 +429,7 @@ struct uniwill_device_descriptor {
unsigned int features;
bool kbd_led_single_color;
u8 kbd_led_max_brightness;
- u8 lightbar_max_brightness;
+ u8 lightbar_max_intensity;
/* Executed during driver probing */
int (*probe)(struct uniwill_data *data);
};
@@ -1509,20 +1509,16 @@ static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_br
unsigned int value;
int ret;
- ret = led_mc_calc_color_components(led_mc_cdev, brightness);
- if (ret < 0)
- return ret;
-
guard(mutex)(&data->led_lock);
for (int i = 0; i < LED_CHANNELS; i++) {
- /* Prevent the brightness values from overflowing */
- value = min(data->lightbar_max_brightness, data->led_mc_subled_info[i].brightness);
- ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
+ ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i],
+ data->led_mc_subled_info[i].intensity);
if (ret < 0)
return ret;
- ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value);
+ ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i],
+ data->led_mc_subled_info[i].intensity);
if (ret < 0)
return ret;
}
@@ -1586,14 +1582,14 @@ static int uniwill_led_init(struct uniwill_data *data)
return ret;
data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;
- data->led_mc_cdev.led_cdev.max_brightness = data->lightbar_max_brightness;
+ data->led_mc_cdev.led_cdev.max_brightness = 1;
data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT;
data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set;
if (value & LIGHTBAR_S0_OFF)
data->led_mc_cdev.led_cdev.brightness = 0;
else
- data->led_mc_cdev.led_cdev.brightness = data->lightbar_max_brightness;
+ data->led_mc_cdev.led_cdev.brightness = 1;
for (int i = 0; i < LED_CHANNELS; i++) {
data->led_mc_subled_info[i].color_index = color_indices[i];
@@ -1604,9 +1600,9 @@ static int uniwill_led_init(struct uniwill_data *data)
/*
* Make sure that the initial intensity value is not greater than
- * the maximum brightness.
+ * the maximum intensity.
*/
- value = min(data->lightbar_max_brightness, value);
+ value = min(data->lightbar_max_intensity, value);
ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
if (ret < 0)
return ret;
@@ -1616,6 +1612,7 @@ static int uniwill_led_init(struct uniwill_data *data)
return ret;
data->led_mc_subled_info[i].intensity = value;
+ data->led_mc_subled_info[i].max_intensity = data->lightbar_max_intensity;
data->led_mc_subled_info[i].channel = i;
}
@@ -2338,7 +2335,7 @@ static int uniwill_probe(struct platform_device *pdev)
data->features = device_descriptor.features;
data->kbd_led_single_color = device_descriptor.kbd_led_single_color;
data->kbd_led_max_brightness = device_descriptor.kbd_led_max_brightness;
- data->lightbar_max_brightness = device_descriptor.lightbar_max_brightness;
+ data->lightbar_max_intensity = device_descriptor.lightbar_max_intensity;
/*
* Some devices might need to perform some device-specific initialization steps
@@ -2685,7 +2682,7 @@ static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata
UNIWILL_FEATURE_GPU_TEMP |
UNIWILL_FEATURE_PRIMARY_FAN |
UNIWILL_FEATURE_SECONDARY_FAN,
- .lightbar_max_brightness = 36,
+ .lightbar_max_intensity = 36,
};
static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
@@ -2709,7 +2706,7 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
UNIWILL_FEATURE_GPU_TEMP |
UNIWILL_FEATURE_PRIMARY_FAN |
UNIWILL_FEATURE_SECONDARY_FAN,
- .lightbar_max_brightness = 200,
+ .lightbar_max_intensity = 200,
};
/*
@@ -3355,8 +3352,8 @@ static int __init uniwill_init(void)
device_descriptor.kbd_led_single_color = false;
/* Some models only support 3 brightness levels */
device_descriptor.kbd_led_max_brightness = 4;
- /* Some models only support 36 brightness levels per color component */
- device_descriptor.lightbar_max_brightness = 200;
+ /* Some models only support 36 intensity levels per color component */
+ device_descriptor.lightbar_max_intensity = 200;
pr_warn("Enabling potentially unsupported features\n");
}
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/5] platform/x86: uniwill-laptop: Implement rainbow animation as trigger
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
2026-09-05 13:01 ` [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness Armin Wolf
@ 2026-09-05 13:01 ` Armin Wolf
2026-09-05 13:01 ` [PATCH 3/5] platform/x86: uniwill-laptop: Fix breathing animation on Intel QC Armin Wolf
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Armin Wolf @ 2026-09-05 13:01 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
It turns out that some models require the lightbar to be activated
in order to display the rainbow animation, so users have to access
both the "rainbow_animation" sysfs attribute and the LED sysfs
interface when enabling the rainbow animation. This can cause short
glitches when the lightbar was previously disabled.
Fix this by replacing the sysfs attribute with a custom LED trigger
called "uniwill-rainbow". Selecting this trigger will atomically
activate the lightbar and enable the rainbow animation mode. This
can potentially break userspace applications using the old sysfs
attribute, but so far no such application is known to exist (yet).
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
.../ABI/removed/sysfs-driver-uniwill-laptop | 10 ++
.../ABI/testing/sysfs-driver-uniwill-laptop | 11 --
.../admin-guide/laptops/uniwill-laptop.rst | 5 +-
MAINTAINERS | 1 +
drivers/platform/x86/uniwill/Kconfig | 1 +
drivers/platform/x86/uniwill/uniwill-acpi.c | 133 +++++++++++-------
6 files changed, 95 insertions(+), 66 deletions(-)
create mode 100644 Documentation/ABI/removed/sysfs-driver-uniwill-laptop
diff --git a/Documentation/ABI/removed/sysfs-driver-uniwill-laptop b/Documentation/ABI/removed/sysfs-driver-uniwill-laptop
new file mode 100644
index 000000000000..c226efc23b59
--- /dev/null
+++ b/Documentation/ABI/removed/sysfs-driver-uniwill-laptop
@@ -0,0 +1,10 @@
+What: /sys/bus/platform/devices/INOU0000:XX/rainbow_animation
+Date: November 2025
+KernelVersion: 6.19
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Forces the integrated lightbar to display a rainbow animation when the machine
+ is not suspended. Writing "1"/"0" into this file enables/disables this
+ functionality.
+
+ Reading this file returns the current status of the rainbow animation functionality.
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
index 943f92c6b561..b9b9feebe2ed 100644
--- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -29,17 +29,6 @@ Description:
Reading this file returns the current enable status of the touchpad toggle
functionality.
-What: /sys/bus/platform/devices/INOU0000:XX/rainbow_animation
-Date: November 2025
-KernelVersion: 6.19
-Contact: Armin Wolf <W_Armin@gmx.de>
-Description:
- Forces the integrated lightbar to display a rainbow animation when the machine
- is not suspended. Writing "1"/"0" into this file enables/disables this
- functionality.
-
- Reading this file returns the current status of the rainbow animation functionality.
-
What: /sys/bus/platform/devices/INOU0000:XX/breathing_in_suspend
Date: November 2025
KernelVersion: 6.19
diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
index be50b45b82ef..aaf50e3074c1 100644
--- a/Documentation/admin-guide/laptops/uniwill-laptop.rst
+++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
@@ -74,8 +74,9 @@ Lightbar
The ``uniwill-laptop`` driver exposes the lightbar found on some models as a standard multicolor
LED class device. The default name of this LED class device is ``uniwill:multicolor:status``.
-See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various
-animation modes of the lightbar.
+The lightbar supports a separate rainbow animation mode that can be enabled by selecting the
+`uniwill-rainbow` LED trigger. To enable a breathing animation during suspend, see
+Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
Keyboard Backlight
------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c..a3e25d111203 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -28107,6 +28107,7 @@ UNIWILL LAPTOP DRIVER
M: Armin Wolf <W_Armin@gmx.de>
L: platform-driver-x86@vger.kernel.org
S: Maintained
+F: Documentation/ABI/removed/sysfs-driver-uniwill-laptop
F: Documentation/ABI/testing/sysfs-driver-uniwill-laptop
F: Documentation/admin-guide/laptops/uniwill-laptop.rst
F: Documentation/wmi/devices/uniwill-laptop.rst
diff --git a/drivers/platform/x86/uniwill/Kconfig b/drivers/platform/x86/uniwill/Kconfig
index d07cc8440188..f80794bdfaef 100644
--- a/drivers/platform/x86/uniwill/Kconfig
+++ b/drivers/platform/x86/uniwill/Kconfig
@@ -28,6 +28,7 @@ config UNIWILL_LAPTOP
depends on DMI
select REGMAP
select INPUT_SPARSEKMAP
+ select LEDS_TRIGGERS
help
This driver adds support for various extra features found on Uniwill laptops,
like the lightbar, hwmon sensors and hotkeys. It also supports many OEM laptops
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 7420e1dd4716..6366171c6981 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -898,51 +898,6 @@ static ssize_t touchpad_toggle_enable_show(struct device *dev, struct device_att
static DEVICE_ATTR_RW(touchpad_toggle_enable);
-static ssize_t rainbow_animation_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct uniwill_data *data = dev_get_drvdata(dev);
- unsigned int value;
- bool enable;
- int ret;
-
- ret = kstrtobool(buf, &enable);
- if (ret < 0)
- return ret;
-
- if (enable)
- value = LIGHTBAR_WELCOME;
- else
- value = 0;
-
- guard(mutex)(&data->led_lock);
-
- ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_WELCOME, value);
- if (ret < 0)
- return ret;
-
- ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_WELCOME, value);
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static ssize_t rainbow_animation_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct uniwill_data *data = dev_get_drvdata(dev);
- unsigned int value;
- int ret;
-
- ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
- if (ret < 0)
- return ret;
-
- return sysfs_emit(buf, "%d\n", !!(value & LIGHTBAR_WELCOME));
-}
-
-static DEVICE_ATTR_RW(rainbow_animation);
-
static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1256,7 +1211,6 @@ static struct attribute *uniwill_attrs[] = {
&dev_attr_super_key_enable.attr,
&dev_attr_touchpad_toggle_enable.attr,
/* Lightbar-related */
- &dev_attr_rainbow_animation.attr,
&dev_attr_breathing_in_suspend.attr,
/* Power-management-related */
&dev_attr_ctgp_offset.attr,
@@ -1286,8 +1240,7 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
return attr->mode;
}
- if (attr == &dev_attr_rainbow_animation.attr ||
- attr == &dev_attr_breathing_in_suspend.attr) {
+ if (attr == &dev_attr_breathing_in_suspend.attr) {
if (uniwill_device_supports(data, UNIWILL_FEATURE_LIGHTBAR))
return attr->mode;
}
@@ -1535,6 +1488,59 @@ static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_br
return regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_S0_OFF, value);
}
+static int uniwill_led_hw_control_set(struct led_classdev *led_cdev, unsigned long flags)
+{
+ struct led_classdev_mc *led_mc_cdev = lcdev_to_mccdev(led_cdev);
+ struct uniwill_data *data = container_of(led_mc_cdev, struct uniwill_data, led_mc_cdev);
+ unsigned int value;
+ int ret;
+
+ guard(mutex)(&data->led_lock);
+
+ if (flags)
+ value = LIGHTBAR_WELCOME;
+ else
+ value = LIGHTBAR_S0_OFF;
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL,
+ LIGHTBAR_S0_OFF | LIGHTBAR_WELCOME, value);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL,
+ LIGHTBAR_S0_OFF | LIGHTBAR_WELCOME, value);
+ if (ret < 0)
+ return ret;
+
+ /* The LED is always on during hw control */
+ led_cdev->brightness = flags;
+
+ return 0;
+}
+
+static int uniwill_lightbar_trigger_activate(struct led_classdev *led_cdev)
+{
+ return led_cdev->hw_control_set(led_cdev, 1);
+}
+
+static void uniwill_lightbar_trigger_deactivate(struct led_classdev *led_cdev)
+{
+ int ret;
+
+ ret = led_cdev->hw_control_set(led_cdev, 0);
+ if (ret < 0)
+ dev_err(led_cdev->dev, "Failed to stop rainbow animation: %d\n", ret);
+}
+
+static struct led_hw_trigger_type uniwill_lightbar_trigger_type;
+
+static struct led_trigger uniwill_lightbar_trigger = {
+ .name = "uniwill-rainbow",
+ .activate = uniwill_lightbar_trigger_activate,
+ .deactivate = uniwill_lightbar_trigger_deactivate,
+ .trigger_type = &uniwill_lightbar_trigger_type,
+};
+
#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | LIGHTBAR_WELCOME)
static int uniwill_led_init(struct uniwill_data *data)
@@ -1585,12 +1591,18 @@ static int uniwill_led_init(struct uniwill_data *data)
data->led_mc_cdev.led_cdev.max_brightness = 1;
data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT;
data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set;
+ data->led_mc_cdev.led_cdev.trigger_type = &uniwill_lightbar_trigger_type;
+ data->led_mc_cdev.led_cdev.hw_control_trigger = uniwill_lightbar_trigger.name;
+ data->led_mc_cdev.led_cdev.hw_control_set = uniwill_led_hw_control_set;
if (value & LIGHTBAR_S0_OFF)
data->led_mc_cdev.led_cdev.brightness = 0;
else
data->led_mc_cdev.led_cdev.brightness = 1;
+ if (value & LIGHTBAR_WELCOME)
+ data->led_mc_cdev.led_cdev.default_trigger = uniwill_lightbar_trigger.name;
+
for (int i = 0; i < LED_CHANNELS; i++) {
data->led_mc_subled_info[i].color_index = color_indices[i];
@@ -3357,17 +3369,31 @@ static int __init uniwill_init(void)
pr_warn("Enabling potentially unsupported features\n");
}
- ret = platform_driver_register(&uniwill_driver);
+ /*
+ * We cannot register the trigger inside the .probe callback of the
+ * platform driver, because each trigger needs a unique name.
+ */
+ ret = led_trigger_register(&uniwill_lightbar_trigger);
if (ret < 0)
return ret;
+ ret = platform_driver_register(&uniwill_driver);
+ if (ret < 0)
+ goto err_platform;
+
ret = uniwill_wmi_register_driver();
- if (ret < 0) {
- platform_driver_unregister(&uniwill_driver);
- return ret;
- }
+ if (ret < 0)
+ goto err_wmi;
return 0;
+
+err_wmi:
+ platform_driver_unregister(&uniwill_driver);
+
+err_platform:
+ led_trigger_unregister(&uniwill_lightbar_trigger);
+
+ return ret;
}
module_init(uniwill_init);
@@ -3375,6 +3401,7 @@ static void __exit uniwill_exit(void)
{
uniwill_wmi_unregister_driver();
platform_driver_unregister(&uniwill_driver);
+ led_trigger_unregister(&uniwill_lightbar_trigger);
}
module_exit(uniwill_exit);
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/5] platform/x86: uniwill-laptop: Fix breathing animation on Intel QC
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
2026-09-05 13:01 ` [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness Armin Wolf
2026-09-05 13:01 ` [PATCH 2/5] platform/x86: uniwill-laptop: Implement rainbow animation as trigger Armin Wolf
@ 2026-09-05 13:01 ` Armin Wolf
2026-10-05 16:13 ` Ilpo Järvinen
2026-09-05 13:01 ` [PATCH 4/5] platform/x86: uniwill-laptop: Label multicolor LEDs correctly Armin Wolf
` (2 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Armin Wolf @ 2026-09-05 13:01 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
Intel NUC 9 Extreme (Queens County) devices have a separate bit
inside the EC_ADDR_LIGHTBAR_AC:CTRL register for enabling the
breathing animation in s2idle mode.
Add support for this additional setting.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
.../ABI/testing/sysfs-driver-uniwill-laptop | 4 +--
drivers/platform/x86/uniwill/uniwill-acpi.c | 27 ++++++++++++++-----
2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
index b9b9feebe2ed..f3060aaf8a76 100644
--- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -35,8 +35,8 @@ KernelVersion: 6.19
Contact: Armin Wolf <W_Armin@gmx.de>
Description:
Causes the integrated lightbar to display a breathing animation when the machine
- has been suspended and is running on AC power. Writing "1"/"0" into this file
- enables/disables this functionality.
+ has been suspended, is running on AC power and the lightbar brightness not zero.
+ Writing "1"/"0" into this file enables/disables this functionality.
Reading this file returns the current status of the breathing animation
functionality.
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 6366171c6981..e527ed7461c3 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -165,9 +165,10 @@
#define EC_ADDR_LIGHTBAR_AC_CTRL 0x0748
#define LIGHTBAR_APP_EXISTS BIT(0)
#define LIGHTBAR_POWER_SAVE BIT(1)
-#define LIGHTBAR_S0_OFF BIT(2)
-#define LIGHTBAR_S3_OFF BIT(3) // Breathing animation when suspended
-#define LIGHTBAR_WELCOME BIT(7) // Rainbow animation
+#define LIGHTBAR_S0_OFF BIT(2) /* Also disables animations */
+#define LIGHTBAR_S3_OFF BIT(3) /* No breathing animation when in s2ram */
+#define LIGHTBAR_MODERN_STANDBY_ON BIT(6) /* Breathing animation when in s2idle */
+#define LIGHTBAR_WELCOME BIT(7) /* Rainbow animation */
#define EC_ADDR_LIGHTBAR_AC_RED 0x0749
@@ -306,7 +307,7 @@
#define EC_ADDR_USB_C_POWER_PRIORITY 0x07CC
#define USB_C_POWER_PRIORITY BIT(7)
-/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
+/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF and LIGHTBAR_MODERN_STANDBY_ON */
#define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2
#define EC_ADDR_LIGHTBAR_BAT_RED 0x07E3
@@ -911,12 +912,13 @@ static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attr
return ret;
if (enable)
- value = 0;
+ value = LIGHTBAR_MODERN_STANDBY_ON;
else
value = LIGHTBAR_S3_OFF;
/* We only access a single register here, so we do not need to use data->led_lock */
- ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S3_OFF, value);
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL,
+ LIGHTBAR_S3_OFF | LIGHTBAR_MODERN_STANDBY_ON, value);
if (ret < 0)
return ret;
@@ -934,6 +936,10 @@ static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attri
if (ret < 0)
return ret;
+ /*
+ * We only test LIGHTBAR_S3_OFF here, because LIGHTBAR_MODERN_STANDBY_ON
+ * should have the exact opposite value.
+ */
return sysfs_emit(buf, "%d\n", !(value & LIGHTBAR_S3_OFF));
}
@@ -1541,7 +1547,8 @@ static struct led_trigger uniwill_lightbar_trigger = {
.trigger_type = &uniwill_lightbar_trigger_type,
};
-#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | LIGHTBAR_WELCOME)
+#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | \
+ LIGHTBAR_MODERN_STANDBY_ON | LIGHTBAR_WELCOME)
static int uniwill_led_init(struct uniwill_data *data)
{
@@ -1574,6 +1581,11 @@ static int uniwill_led_init(struct uniwill_data *data)
return ret;
value |= LIGHTBAR_APP_EXISTS;
+ if (value & LIGHTBAR_S3_OFF)
+ value &= ~LIGHTBAR_MODERN_STANDBY_ON;
+ else
+ value |= LIGHTBAR_MODERN_STANDBY_ON;
+
ret = regmap_write(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, value);
if (ret < 0)
return ret;
@@ -1583,6 +1595,7 @@ static int uniwill_led_init(struct uniwill_data *data)
* running on battery power.
*/
value |= LIGHTBAR_S3_OFF;
+ value &= ~LIGHTBAR_MODERN_STANDBY_ON;
ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_MASK, value);
if (ret < 0)
return ret;
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/5] platform/x86: uniwill-laptop: Label multicolor LEDs correctly
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
` (2 preceding siblings ...)
2026-09-05 13:01 ` [PATCH 3/5] platform/x86: uniwill-laptop: Fix breathing animation on Intel QC Armin Wolf
@ 2026-09-05 13:01 ` Armin Wolf
2026-09-05 13:01 ` [PATCH 5/5] platform/x86: uniwill-laptop: Extend support for the Intel NUC x15 Armin Wolf
2026-09-22 20:45 ` [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
5 siblings, 0 replies; 9+ messages in thread
From: Armin Wolf @ 2026-09-05 13:01 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
The LED subsystem specifies that LEDs capable of producing arbitrary
colors (like RGB) should label themselfs as "rgb" instead of
"multicolor".
Use the "rgb" label instead of the "multicolor" label to fix
detection by userspace applications.
Reported-by: Werner Sembach <wse@tuxedocomputers.com>
Closes: https://github.com/Wer-Wolf/uniwill-laptop/issues/18
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
Documentation/admin-guide/laptops/uniwill-laptop.rst | 4 ++--
drivers/platform/x86/uniwill/uniwill-acpi.c | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
index aaf50e3074c1..d8ce30f10d7c 100644
--- a/Documentation/admin-guide/laptops/uniwill-laptop.rst
+++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
@@ -72,7 +72,7 @@ Lightbar
--------
The ``uniwill-laptop`` driver exposes the lightbar found on some models as a standard multicolor
-LED class device. The default name of this LED class device is ``uniwill:multicolor:status``.
+LED class device. The default name of this LED class device is ``uniwill:rgb:status``.
The lightbar supports a separate rainbow animation mode that can be enabled by selecting the
`uniwill-rainbow` LED trigger. To enable a breathing animation during suspend, see
@@ -83,7 +83,7 @@ Keyboard Backlight
The ``uniwill-laptop`` driver supports controlling the keyboard backlight using the standard
LED class interface. The default name of this LED class device is ``uniwill:white:kbd_backlight``
-when the keyboard backlight supports only a single color, or ``uniwill:multicolor:kbd_backlight``
+when the keyboard backlight supports only a single color, or ``uniwill:rgb:kbd_backlight``
when the keyboard backlight supports RGB colors. The maximum intensity for each color channel
in RGB mode is 50.
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index e527ed7461c3..27d5e54f0e1c 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -1554,7 +1554,7 @@ static int uniwill_led_init(struct uniwill_data *data)
{
struct led_init_data init_data = {
.devicename = DRIVER_NAME,
- .default_label = "multicolor:" LED_FUNCTION_STATUS,
+ .default_label = "rgb:" LED_FUNCTION_STATUS,
.devname_mandatory = true,
};
unsigned int color_indices[3] = {
@@ -1600,7 +1600,7 @@ static int uniwill_led_init(struct uniwill_data *data)
if (ret < 0)
return ret;
- data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;
+ data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_RGB;
data->led_mc_cdev.led_cdev.max_brightness = 1;
data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT;
data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set;
@@ -1782,7 +1782,7 @@ static int uniwill_rgb_kbd_led_init(struct uniwill_data *data)
LED_COLOR_ID_BLUE,
};
struct led_init_data init_data = {
- .default_label = "multicolor:" LED_FUNCTION_KBD_BACKLIGHT,
+ .default_label = "rgb:" LED_FUNCTION_KBD_BACKLIGHT,
.devicename = DRIVER_NAME,
.devname_mandatory = true,
};
@@ -1843,7 +1843,7 @@ static int uniwill_rgb_kbd_led_init(struct uniwill_data *data)
return ret;
data->kbd_led_mc_cdev.led_cdev.max_brightness = data->kbd_led_max_brightness;
- data->kbd_led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;
+ data->kbd_led_mc_cdev.led_cdev.color = LED_COLOR_ID_RGB;
data->kbd_led_mc_cdev.led_cdev.flags = LED_BRIGHT_HW_CHANGED | LED_REJECT_NAME_CONFLICT;
data->kbd_led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_kbd_led_mc_brightness_set;
data->kbd_led_mc_cdev.led_cdev.brightness_get = uniwill_kbd_led_mc_brightness_get;
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/5] platform/x86: uniwill-laptop: Extend support for the Intel NUC x15
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
` (3 preceding siblings ...)
2026-09-05 13:01 ` [PATCH 4/5] platform/x86: uniwill-laptop: Label multicolor LEDs correctly Armin Wolf
@ 2026-09-05 13:01 ` Armin Wolf
2026-09-22 20:45 ` [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
5 siblings, 0 replies; 9+ messages in thread
From: Armin Wolf @ 2026-09-05 13:01 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
A user has reported that the LAPKC71E variant of the Intel NUC x15
also works with the uniwill-laptop driver. The difference between the
LAPKC71E and the LAPKC71F seems to be the dedicated NVidia GPU module.
Add support for this device as well. It is suspected that the LAPKC71F
also supports the new UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL feature, but
this would need to be verified on real hardware.
Link: https://github.com/Wer-Wolf/uniwill-laptop/issues/17
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 22 +++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 27d5e54f0e1c..433a7a0eeba6 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -2721,6 +2721,20 @@ static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
UNIWILL_FEATURE_SECONDARY_FAN,
};
+static struct uniwill_device_descriptor lapkc71e_descriptor __initdata = {
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
+ UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
+ UNIWILL_FEATURE_LIGHTBAR |
+ UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT |
+ UNIWILL_FEATURE_CPU_TEMP |
+ UNIWILL_FEATURE_GPU_TEMP |
+ UNIWILL_FEATURE_PRIMARY_FAN |
+ UNIWILL_FEATURE_SECONDARY_FAN |
+ UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
+ .lightbar_max_intensity = 200,
+};
+
static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
.features = UNIWILL_FEATURE_FN_LOCK |
UNIWILL_FEATURE_SUPER_KEY |
@@ -2946,6 +2960,14 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
},
.driver_data = &lapac71h_descriptor,
},
+ {
+ .ident = "Intel NUC x15",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPKC71E"),
+ },
+ .driver_data = &lapkc71e_descriptor,
+ },
{
.ident = "Intel NUC x15",
.matches = {
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
` (4 preceding siblings ...)
2026-09-05 13:01 ` [PATCH 5/5] platform/x86: uniwill-laptop: Extend support for the Intel NUC x15 Armin Wolf
@ 2026-09-22 20:45 ` Armin Wolf
5 siblings, 0 replies; 9+ messages in thread
From: Armin Wolf @ 2026-09-22 20:45 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
Am 05.09.26 um 15:01 schrieb Armin Wolf:
> This patch series mainly deals with various issues inside the code
> responsible for controlling the lightbar on supported devices.
>
> The first patch utilizes the improved multicolor LED API to report
> the correct brightness of the lightbar to userspace. The next two
> patches fix issues discovered inside the code for controlling
> animations, while the fourth patch fixes an issue with the naming
> of the LEDs in general. The last patch also adds support for another
> variant of the Intel NUC x15 laptop kit.
>
> All patches have been tested on said Intel NUC x15 laptop and appear
> to work.
Any thoughts on this series?
Thanks,
Armin Wolf
>
> Armin Wolf (5):
> platform/x86: uniwill-laptop: Report correct lightbar brightness
> platform/x86: uniwill-laptop: Implement rainbow animation as trigger
> platform/x86: uniwill-laptop: Fix breathing animation on Intel QC
> platform/x86: uniwill-laptop: Label multicolor LEDs correctly
> platform/x86: uniwill-laptop: Extend support for the Intel NUC x15
>
> .../ABI/removed/sysfs-driver-uniwill-laptop | 10 +
> .../ABI/testing/sysfs-driver-uniwill-laptop | 15 +-
> .../admin-guide/laptops/uniwill-laptop.rst | 9 +-
> MAINTAINERS | 1 +
> drivers/platform/x86/uniwill/Kconfig | 1 +
> drivers/platform/x86/uniwill/uniwill-acpi.c | 225 +++++++++++-------
> 6 files changed, 161 insertions(+), 100 deletions(-)
> create mode 100644 Documentation/ABI/removed/sysfs-driver-uniwill-laptop
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness
2026-09-05 13:01 ` [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness Armin Wolf
@ 2026-10-05 16:12 ` Ilpo Järvinen
0 siblings, 0 replies; 9+ messages in thread
From: Ilpo Järvinen @ 2026-10-05 16:12 UTC (permalink / raw)
To: Armin Wolf; +Cc: Hans de Goede, wse, platform-driver-x86, LKML
On Sat, 5 Sep 2026, Armin Wolf wrote:
> The LED sysfs ABI now allows us to specify the maximum values for the
> global brightness and the color intensity values independently. At the
> same time the maximum brightness value reported for the lightbar (like
> 200) does not match the real value supported by the hardware (1),
> potentially confusing users.
>
> Report the correct maximum brightness value and only use the intensity
> values for controlling the lightbar color.
>
> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
> ---
> drivers/platform/x86/uniwill/uniwill-acpi.c | 35 ++++++++++-----------
> 1 file changed, 16 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 7a2eeaec4c96..7420e1dd4716 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -398,7 +398,7 @@ struct uniwill_data {
> struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
> struct list_head batteries;
> struct mutex led_lock; /* Protects writes to the lightbar registers */
> - u8 lightbar_max_brightness;
> + u8 lightbar_max_intensity;
> struct led_classdev_mc led_mc_cdev;
> struct mc_subled led_mc_subled_info[LED_CHANNELS];
> bool kbd_led_single_color;
> @@ -429,7 +429,7 @@ struct uniwill_device_descriptor {
> unsigned int features;
> bool kbd_led_single_color;
> u8 kbd_led_max_brightness;
> - u8 lightbar_max_brightness;
> + u8 lightbar_max_intensity;
> /* Executed during driver probing */
> int (*probe)(struct uniwill_data *data);
> };
> @@ -1509,20 +1509,16 @@ static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_br
> unsigned int value;
> int ret;
>
> - ret = led_mc_calc_color_components(led_mc_cdev, brightness);
> - if (ret < 0)
> - return ret;
> -
> guard(mutex)(&data->led_lock);
>
> for (int i = 0; i < LED_CHANNELS; i++) {
> - /* Prevent the brightness values from overflowing */
> - value = min(data->lightbar_max_brightness, data->led_mc_subled_info[i].brightness);
> - ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
> + ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i],
> + data->led_mc_subled_info[i].intensity);
> if (ret < 0)
> return ret;
>
> - ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value);
> + ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i],
> + data->led_mc_subled_info[i].intensity);
> if (ret < 0)
> return ret;
> }
> @@ -1586,14 +1582,14 @@ static int uniwill_led_init(struct uniwill_data *data)
> return ret;
>
> data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;
> - data->led_mc_cdev.led_cdev.max_brightness = data->lightbar_max_brightness;
> + data->led_mc_cdev.led_cdev.max_brightness = 1;
> data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT;
> data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set;
>
> if (value & LIGHTBAR_S0_OFF)
> data->led_mc_cdev.led_cdev.brightness = 0;
> else
> - data->led_mc_cdev.led_cdev.brightness = data->lightbar_max_brightness;
> + data->led_mc_cdev.led_cdev.brightness = 1;
>
> for (int i = 0; i < LED_CHANNELS; i++) {
> data->led_mc_subled_info[i].color_index = color_indices[i];
> @@ -1604,9 +1600,9 @@ static int uniwill_led_init(struct uniwill_data *data)
>
> /*
> * Make sure that the initial intensity value is not greater than
> - * the maximum brightness.
> + * the maximum intensity.
> */
> - value = min(data->lightbar_max_brightness, value);
> + value = min(data->lightbar_max_intensity, value);
> ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
> if (ret < 0)
> return ret;
> @@ -1616,6 +1612,7 @@ static int uniwill_led_init(struct uniwill_data *data)
> return ret;
>
> data->led_mc_subled_info[i].intensity = value;
> + data->led_mc_subled_info[i].max_intensity = data->lightbar_max_intensity;
> data->led_mc_subled_info[i].channel = i;
> }
>
> @@ -2338,7 +2335,7 @@ static int uniwill_probe(struct platform_device *pdev)
> data->features = device_descriptor.features;
> data->kbd_led_single_color = device_descriptor.kbd_led_single_color;
> data->kbd_led_max_brightness = device_descriptor.kbd_led_max_brightness;
> - data->lightbar_max_brightness = device_descriptor.lightbar_max_brightness;
> + data->lightbar_max_intensity = device_descriptor.lightbar_max_intensity;
>
> /*
> * Some devices might need to perform some device-specific initialization steps
> @@ -2685,7 +2682,7 @@ static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata
> UNIWILL_FEATURE_GPU_TEMP |
> UNIWILL_FEATURE_PRIMARY_FAN |
> UNIWILL_FEATURE_SECONDARY_FAN,
> - .lightbar_max_brightness = 36,
> + .lightbar_max_intensity = 36,
> };
>
> static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
> @@ -2709,7 +2706,7 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
> UNIWILL_FEATURE_GPU_TEMP |
> UNIWILL_FEATURE_PRIMARY_FAN |
> UNIWILL_FEATURE_SECONDARY_FAN,
> - .lightbar_max_brightness = 200,
> + .lightbar_max_intensity = 200,
> };
Can you respin this on top of what's in the review-ilpo-next I think there
are now more entries to touch after Werner's descriptor splits.
> /*
> @@ -3355,8 +3352,8 @@ static int __init uniwill_init(void)
> device_descriptor.kbd_led_single_color = false;
> /* Some models only support 3 brightness levels */
> device_descriptor.kbd_led_max_brightness = 4;
> - /* Some models only support 36 brightness levels per color component */
> - device_descriptor.lightbar_max_brightness = 200;
> + /* Some models only support 36 intensity levels per color component */
> + device_descriptor.lightbar_max_intensity = 200;
> pr_warn("Enabling potentially unsupported features\n");
> }
>
>
--
i.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/5] platform/x86: uniwill-laptop: Fix breathing animation on Intel QC
2026-09-05 13:01 ` [PATCH 3/5] platform/x86: uniwill-laptop: Fix breathing animation on Intel QC Armin Wolf
@ 2026-10-05 16:13 ` Ilpo Järvinen
0 siblings, 0 replies; 9+ messages in thread
From: Ilpo Järvinen @ 2026-10-05 16:13 UTC (permalink / raw)
To: Armin Wolf; +Cc: hansg, ilpo.jarvinen, wse, platform-driver-x86, linux-kernel
On Sat, 5 Sep 2026, Armin Wolf wrote:
> Intel NUC 9 Extreme (Queens County) devices have a separate bit
> inside the EC_ADDR_LIGHTBAR_AC:CTRL register for enabling the
Should be _
--
i.
> breathing animation in s2idle mode.
>
> Add support for this additional setting.
>
> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
> ---
> .../ABI/testing/sysfs-driver-uniwill-laptop | 4 +--
> drivers/platform/x86/uniwill/uniwill-acpi.c | 27 ++++++++++++++-----
> 2 files changed, 22 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
> index b9b9feebe2ed..f3060aaf8a76 100644
> --- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
> +++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
> @@ -35,8 +35,8 @@ KernelVersion: 6.19
> Contact: Armin Wolf <W_Armin@gmx.de>
> Description:
> Causes the integrated lightbar to display a breathing animation when the machine
> - has been suspended and is running on AC power. Writing "1"/"0" into this file
> - enables/disables this functionality.
> + has been suspended, is running on AC power and the lightbar brightness not zero.
> + Writing "1"/"0" into this file enables/disables this functionality.
>
> Reading this file returns the current status of the breathing animation
> functionality.
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 6366171c6981..e527ed7461c3 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -165,9 +165,10 @@
> #define EC_ADDR_LIGHTBAR_AC_CTRL 0x0748
> #define LIGHTBAR_APP_EXISTS BIT(0)
> #define LIGHTBAR_POWER_SAVE BIT(1)
> -#define LIGHTBAR_S0_OFF BIT(2)
> -#define LIGHTBAR_S3_OFF BIT(3) // Breathing animation when suspended
> -#define LIGHTBAR_WELCOME BIT(7) // Rainbow animation
> +#define LIGHTBAR_S0_OFF BIT(2) /* Also disables animations */
> +#define LIGHTBAR_S3_OFF BIT(3) /* No breathing animation when in s2ram */
> +#define LIGHTBAR_MODERN_STANDBY_ON BIT(6) /* Breathing animation when in s2idle */
> +#define LIGHTBAR_WELCOME BIT(7) /* Rainbow animation */
>
> #define EC_ADDR_LIGHTBAR_AC_RED 0x0749
>
> @@ -306,7 +307,7 @@
> #define EC_ADDR_USB_C_POWER_PRIORITY 0x07CC
> #define USB_C_POWER_PRIORITY BIT(7)
>
> -/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
> +/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF and LIGHTBAR_MODERN_STANDBY_ON */
> #define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2
>
> #define EC_ADDR_LIGHTBAR_BAT_RED 0x07E3
> @@ -911,12 +912,13 @@ static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attr
> return ret;
>
> if (enable)
> - value = 0;
> + value = LIGHTBAR_MODERN_STANDBY_ON;
> else
> value = LIGHTBAR_S3_OFF;
>
> /* We only access a single register here, so we do not need to use data->led_lock */
> - ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S3_OFF, value);
> + ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL,
> + LIGHTBAR_S3_OFF | LIGHTBAR_MODERN_STANDBY_ON, value);
> if (ret < 0)
> return ret;
>
> @@ -934,6 +936,10 @@ static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attri
> if (ret < 0)
> return ret;
>
> + /*
> + * We only test LIGHTBAR_S3_OFF here, because LIGHTBAR_MODERN_STANDBY_ON
> + * should have the exact opposite value.
> + */
> return sysfs_emit(buf, "%d\n", !(value & LIGHTBAR_S3_OFF));
> }
>
> @@ -1541,7 +1547,8 @@ static struct led_trigger uniwill_lightbar_trigger = {
> .trigger_type = &uniwill_lightbar_trigger_type,
> };
>
> -#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | LIGHTBAR_WELCOME)
> +#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | \
> + LIGHTBAR_MODERN_STANDBY_ON | LIGHTBAR_WELCOME)
>
> static int uniwill_led_init(struct uniwill_data *data)
> {
> @@ -1574,6 +1581,11 @@ static int uniwill_led_init(struct uniwill_data *data)
> return ret;
>
> value |= LIGHTBAR_APP_EXISTS;
> + if (value & LIGHTBAR_S3_OFF)
> + value &= ~LIGHTBAR_MODERN_STANDBY_ON;
> + else
> + value |= LIGHTBAR_MODERN_STANDBY_ON;
> +
> ret = regmap_write(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, value);
> if (ret < 0)
> return ret;
> @@ -1583,6 +1595,7 @@ static int uniwill_led_init(struct uniwill_data *data)
> * running on battery power.
> */
> value |= LIGHTBAR_S3_OFF;
> + value &= ~LIGHTBAR_MODERN_STANDBY_ON;
> ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_MASK, value);
> if (ret < 0)
> return ret;
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-05 16:13 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-05 13:01 [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
2026-09-05 13:01 ` [PATCH 1/5] platform/x86: uniwill-laptop: Report correct lightbar brightness Armin Wolf
2026-10-05 16:12 ` Ilpo Järvinen
2026-09-05 13:01 ` [PATCH 2/5] platform/x86: uniwill-laptop: Implement rainbow animation as trigger Armin Wolf
2026-09-05 13:01 ` [PATCH 3/5] platform/x86: uniwill-laptop: Fix breathing animation on Intel QC Armin Wolf
2026-10-05 16:13 ` Ilpo Järvinen
2026-09-05 13:01 ` [PATCH 4/5] platform/x86: uniwill-laptop: Label multicolor LEDs correctly Armin Wolf
2026-09-05 13:01 ` [PATCH 5/5] platform/x86: uniwill-laptop: Extend support for the Intel NUC x15 Armin Wolf
2026-09-22 20:45 ` [PATCH 0/5] platform/x86: uniwill-laptop: Lightbar fixes Armin Wolf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®