[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <30354f74-91c0-4fd6-82b1-15f79ae7a60f@kernel.org>
Date: Sun, 8 Feb 2026 11:54:46 +0100
From: Hans de Goede <hansg@...nel.org>
To: Vishnu Sankar <vishnuocv@...il.com>, hmh@....eng.br,
derekjohn.clark@...il.com, ilpo.jarvinen@...ux.intel.com,
mpearson-lenovo@...ebb.ca
Cc: ibm-acpi-devel@...ts.sourceforge.net,
platform-driver-x86@...r.kernel.org, linux-kernel@...r.kernel.org,
vsankar@...ovo.com
Subject: Re: [PATCH] thinkpad_acpi: Add Auto mode support with dynamic
max_brightness
Hi Vishnu,
On 4-Feb-26 00:22, Vishnu Sankar wrote:
> Dynamically detect keyboard backlight capabilities and set
> max_brightness correctly (2 for old models, 3 for new models
> with Auto mode).
Thank you for your patch.
If I understand this correctly, writing 3 as level does not
make the backlight more bright then writing 2, but instead
it puts the backlight in some auto mode ?
If I've that correct then userspace should keep seeing
a range of 0 - 2 and the special auto mode value should
be reported / be made settable through a separate als_enabled
sysfs attribute under the LED class device. See:
Documentation/ABI/testing/sysfs-platform-dell-laptop
You can add extra attributes there by setting the groups
member of the struct led_classdev, see kbd_led_groups[]
in drivers/platform/x86/dell/dell-laptop.c, except that
you should use a .is_visible callback to only show this
on hw which supports it and you only need 1 group with
1 attribute.
Regards,
Hans
>
> Suggested-by: Mark Pearson <mpearson-lenovo@...ebb.ca>
> Signed-off-by: Vishnu Sankar <vishnuocv@...il.com>
> ---
> drivers/platform/x86/lenovo/thinkpad_acpi.c | 33 ++++++++++++++++++---
> 1 file changed, 29 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
> index cc19fe520ea9..f670cdd1791e 100644
> --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
> +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
> @@ -5043,6 +5043,9 @@ static struct ibm_struct video_driver_data = {
> static enum led_brightness kbdlight_brightness;
> static DEFINE_MUTEX(kbdlight_mutex);
>
> +/* Maximum level supported by hardware, will be updated in init */
> +static int kbdlight_max_level = 2;
> +
> static int kbdlight_set_level(int level)
> {
> int ret = 0;
> @@ -5050,6 +5053,10 @@ static int kbdlight_set_level(int level)
> if (!hkey_handle)
> return -ENXIO;
>
> + /* Validate against detected max level */
> + if (level < 0 || level > kbdlight_max_level)
> + return -EINVAL;
> +
> mutex_lock(&kbdlight_mutex);
>
> if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level))
> @@ -5075,6 +5082,7 @@ static int kbdlight_get_level(void)
> if (status < 0)
> return status;
>
> + /* Status can be 0, 1, 2, or 3 (Auto) */
> return status & 0x3;
> }
>
> @@ -5143,7 +5151,7 @@ static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev)
> static struct tpacpi_led_classdev tpacpi_led_kbdlight = {
> .led_classdev = {
> .name = "tpacpi::kbd_backlight",
> - .max_brightness = 2,
> + .max_brightness = 2, /*Initial value, will be updated in init*/
> .flags = LED_BRIGHT_HW_CHANGED,
> .brightness_set_blocking = &kbdlight_sysfs_set,
> .brightness_get = &kbdlight_sysfs_get,
> @@ -5167,6 +5175,17 @@ static int __init kbdlight_init(struct ibm_init_struct *iibm)
> kbdlight_brightness = kbdlight_sysfs_get(NULL);
> tp_features.kbdlight = 1;
>
> + /* Detect hardware capabilities and set max_brightness */
> + if (acpi_evalf(hkey_handle, NULL, "MLCS", "dd", 3)) {
> + /* MLCS accepts level 3 - new ThinkPad with Auto mode */
> + kbdlight_max_level = 3;
> + tpacpi_led_kbdlight.led_classdev.max_brightness = 3;
> + } else {
> + /* MLCS rejects level 3 - old ThinkPad */
> + kbdlight_max_level = 2;
> + tpacpi_led_kbdlight.led_classdev.max_brightness = 2;
> + }
> +
> rc = led_classdev_register(&tpacpi_pdev->dev,
> &tpacpi_led_kbdlight.led_classdev);
> if (rc < 0) {
> @@ -5201,6 +5220,7 @@ static int kbdlight_set_level_and_update(int level)
> static int kbdlight_read(struct seq_file *m)
> {
> int level;
> + int i;
>
> if (!tp_features.kbdlight) {
> seq_printf(m, "status:\t\tnot supported\n");
> @@ -5210,9 +5230,13 @@ static int kbdlight_read(struct seq_file *m)
> seq_printf(m, "status:\t\terror %d\n", level);
> else
> seq_printf(m, "status:\t\t%d\n", level);
> - seq_printf(m, "commands:\t0, 1, 2\n");
> - }
>
> + /* Show available commands based on hardware */
> + seq_puts(m, "commands:\t0");
> + for (i = 1; i <= tpacpi_led_kbdlight.led_classdev.max_brightness; i++)
> + seq_printf(m, ", %d", i);
> + seq_puts(m, "\n");
> + }
> return 0;
> }
>
> @@ -5230,7 +5254,8 @@ static int kbdlight_write(char *buf)
> return res;
> }
>
> - if (level >= 3 || level < 0)
> + /* Validate against max level */
> + if (level < 0 || level > tpacpi_led_kbdlight.led_classdev.max_brightness)
> return -EINVAL;
>
> return kbdlight_set_level_and_update(level);
Powered by blists - more mailing lists