From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EAE2C2F5491; Sat, 18 Jul 2026 17:09:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394567; cv=pass; b=FwBWMV7WTKOMMKT6w4QmMR/aIs4DKe8G1OWTxlHLYnq7ZLNFgbANNW2cx5HpmE31anwrxcJIaEnh9HzlL69L9Q66vhGm0fCLeguhABPAcwClkivlN4gY0X5veDXNvIIZNqWYDMGYxMjbjNJI4bZYICSBb1y0nBukzJ6/8jZXQZc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394567; c=relaxed/simple; bh=bJnTXATyAYlzXpZPk8Dfcz0jlDB1H48T+urva4t1gyo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uq7LDsLUz95dje6GwDx45LzUftyI+cD/+KDzOs+p87AXRRWSNlaihy7DgpsEWztOzFXcbgKUi1/3eFtrVjIYqZQC+8uid0VPTDUFKxO4zTpx/7BzkWcor1/XlYJhc2x5KtVV2poEzpb8TOHPOxmSo+eDIWIvvQbbmJ6ohzQU+oY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=SQUks7KN; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="SQUks7KN" ARC-Seal: i=1; a=rsa-sha256; t=1784394524; cv=none; d=zohomail.com; s=zohoarc; b=CkutoRfB/YBnmFvipxcTO49sV2347B1UcGV1qAnfXIkbxvWO1E2EQ0A85LQ7h4MmHpnNOK4bP2A1RqJjZeyQl8gCHIpdzdlgEY5BAP9rEXjodUiBwkUtxAI4DASAPhQ608tQWio4lira4bZV251jGRKCxKet1SsEYjBJwxcxTPo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394524; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=y+6hZ2OlWJ9isoyhTLOLbV0taQiuXabgo/K8f33HwOc=; b=Q0YJQFj6eYuSXU6wJXb1FSQzJEAi46ymQjzHp4b2BWvcoDsm5w65TLwrbDIIj/AQVgQqG6loM690w7IfHwb0sRBkXvNMD8jPQRczcY8CrAdMw9gGMXfWTkOL2Huc6faVY20ESpAWEQDrXuug+JGh/BnbnBViTFHeeGwfmZk5ey0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394524; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=y+6hZ2OlWJ9isoyhTLOLbV0taQiuXabgo/K8f33HwOc=; b=SQUks7KNK2sNS8Vbtw6qxSYboOBMID4r/Zajai2KylXHVq71nPKAarlissSY89v4 lXOZFtnwxSSigMl2c/dLu6thlyNqioWAoG7cofDe9RRZM+3JD1SljS7wi7b9ZU0xHUZ 644pgQERDSahZKS5dlCDFq8AnnrTCjYBbReKz9cVdANFJ4OrB4hDxqgk/+6Ch8fNWvB BBWgXisEVIUkhjYpHjP9anblGpKtKXLm0qKF+ugGPuVdyyG1pjsZgfKA+cU5FtVccQ4 Hd5/fLXNwBZICv7xWy5NdvaQ/vKYZyyGcCBIu9dAKZ9O617drMjt2w0O4Q1dZiJsYdU lmgPqqbZNg== Received: by mx.zohomail.com with SMTPS id 1784394521636564.3850641962187; Sat, 18 Jul 2026 10:08:41 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:18 +0800 Subject: [PATCH RFC v3 01/11] leds: Move led_trigger_is_hw_controlled() to the right place Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-1-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External Currently led_trigger_is_hw_controlled() is placed at led-class.c, which is not an right place as it falls into the triggers namespace and does triggers stuff. Move it into led-triggers.c, and split it into locked and unlocked variant for convenience. Fixes: b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware= controlled LED") Signed-off-by: Rong Zhang --- Changes in v3: - New patch in the series, the dependency of the following patches --- drivers/leds/led-class.c | 10 ---------- drivers/leds/led-triggers.c | 19 +++++++++++++++++++ include/linux/leds.h | 8 ++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index a51b0ed53886..1b8b688aaaaf 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -27,16 +27,6 @@ static LIST_HEAD(leds_lookup_list); =20 static struct workqueue_struct *leds_wq; =20 -static bool led_trigger_is_hw_controlled(struct led_classdev *led_cdev) -{ -#ifdef CONFIG_LEDS_TRIGGERS - guard(rwsem_read)(&led_cdev->trigger_lock); - return led_cdev->trigger && led_cdev->trigger->trigger_type; -#else - return false; -#endif -} - static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index b1223218bda1..bf2543538ed0 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -7,9 +7,11 @@ * Author: Richard Purdie */ =20 +#include #include #include #include +#include #include #include #include @@ -33,6 +35,23 @@ trigger_relevant(struct led_classdev *led_cdev, struct l= ed_trigger *trig) return !trig->trigger_type || trig->trigger_type =3D=3D led_cdev->trigger= _type; } =20 +static bool __led_trigger_is_hw_controlled(struct led_classdev *led_cdev) +{ + lockdep_assert_held(&led_cdev->trigger_lock); + + if (!led_cdev->trigger) + return false; + + return led_cdev->trigger->trigger_type; +} + +bool led_trigger_is_hw_controlled(struct led_classdev *led_cdev) +{ + guard(rwsem_read)(&led_cdev->trigger_lock); + return __led_trigger_is_hw_controlled(led_cdev); +} +EXPORT_SYMBOL_GPL(led_trigger_is_hw_controlled); + ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, const struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) diff --git a/include/linux/leds.h b/include/linux/leds.h index b16b803cc1ac..a630f5a79f6b 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -534,6 +534,8 @@ void led_trigger_set_default(struct led_classdev *led_c= dev); int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *tri= gger); void led_trigger_remove(struct led_classdev *led_cdev); =20 +bool led_trigger_is_hw_controlled(struct led_classdev *led_cdev); + static inline void led_set_trigger_data(struct led_classdev *led_cdev, void *trigger_data) { @@ -584,6 +586,12 @@ static inline int led_trigger_set(struct led_classdev = *led_cdev, } =20 static inline void led_trigger_remove(struct led_classdev *led_cdev) {} + +static inline bool led_trigger_is_hw_controlled(struct led_classdev *led_c= dev) +{ + return false; +} + static inline void led_set_trigger_data(struct led_classdev *led_cdev) {} static inline void *led_get_trigger_data(struct led_classdev *led_cdev) { --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A24022E62C4; Sat, 18 Jul 2026 17:09:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394590; cv=pass; b=b7pKZAy06ikUKE1EfguhLy7V5q8EumqLRb0bGXc5W8A4luP3p1nTtSEdtiwcZ/mUbGPFUckP3D/nYuv2tEa7Dxgs6PotRqz1hnGWGnO66hTktP+ov/3uZw4YVdKqTvaOdlna6aiIxoEqwMnxm8K52tusjGC28bY4EnJLchutjfc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394590; c=relaxed/simple; bh=mTd1U3w5kJP9KL/eJmZjW33Th2AsNX/WrKXs3Ams+Jc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eKwnPi9kkK/kDG/A/UFLfKeCfnysm1E/IND3X2k3Lmibp1wHY5bgHFGYjXvTUeIeRPKeEol/0LT901FJvlWCk4p6OXYyDTqXzA5Pfr1o638xa7VNjIRza7sRgoFTO9gdUItdSweFoihzM9nyHPx5ZJweSKn8oMjXkCWysolu+Sk= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=QzLYWhp2; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="QzLYWhp2" ARC-Seal: i=1; a=rsa-sha256; t=1784394530; cv=none; d=zohomail.com; s=zohoarc; b=HOVdxubxwVNv/h8gUrrrltoO18MttpnZEd6EDxf7s1PZfuUUnWOcevxnh0xlJEXDvPcJ7JavofOcr83/nu5F76OEwo0JoX5CPTULrzCoTL8DhjsRBeRHYkw4YmNZieqBgLr8ApUlIL6vdzY6zDe4x8MryKlct6vwIOTr++Az2a4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394530; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=xz8KnFymT5hESdr7xdAcMXoJSRczBvNSNj4kIhe0Ha0=; b=I0Ctq44J35uKg7juGEVKj8lkA/vycHpp4YyFyw8hDpii9bVkGZ2SgXZXPiPhLHqUOGC2UuQ8HFPMHQGH7JttolhaXtWKuibuRzuqbFi6EU/cna3UDszChM7EcJ7yq91SrDozIv5PBPloJxfh89cCkYHQunzz5zBQ5Zbyr2oAN2g= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394530; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=xz8KnFymT5hESdr7xdAcMXoJSRczBvNSNj4kIhe0Ha0=; b=QzLYWhp24TF0LCUUeipOogO/QbMaHpxYlIVGwAN/dLDGvhT4ZKZB+1ihQk+5ChWC HDZnEwGZzTGzb2wkHGspH9S0YeNhPzWD5eVEbD9eJmSV4AZdAkJrCVzjR5VtUIts46P dTZW8fu3+og7b2l7BDX8DrMoyUav/1qf1lkseLi1UHwSzIiXiG47nFe/rp3VMrWXh2q MRPtqh4RL0F85O0m3VPYjrstUZvkL4ysoueMBkv5GhqbZ8Bq1flxdP7hAAVqenIPrpK 4J036Gxi2UpsERqD/YbKfpZfFVw5yHMSgbRo3HKebyU+dlIL28qer4GFXmKjzWkJZTH dnNFS1fdaA== Received: by mx.zohomail.com with SMTPS id 17843945284411005.0000341232434; Sat, 18 Jul 2026 10:08:48 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:19 +0800 Subject: [PATCH RFC v3 02/11] leds: class: Remove hardware control trigger when writing brightness Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-2-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External Since commit b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware controlled LED"), the brightness attribute becomes write-only when the LED is controlled fully by the hardware. A write-only attribute is very confusing. Moreover, most LED drivers set hardware brightness innocently with the side effect of disabling hardware control, but the hardware control trigger remains active, resulting in the software and hardware being out of sync. Fix it by removing the hardware control trigger when writing the brightness attribute. This should also match the semantics of hardware control: When the LED is in hw control, no software blink is possible and doing so will effectively disable hw control. Fixes: b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware= controlled LED") Signed-off-by: Rong Zhang --- Changes in v3: - New patch in the series, integrated from https://lore.kernel.org/all/2026= 0712-leds-hw-control-brightness-set-v1-1-1de593b09d26@rong.moe/ - The following patches will improve __led_trigger_is_hw_controlled() to include offloaded generic triggers and take the advantage of it --- drivers/leds/led-class.c | 3 +++ drivers/leds/led-triggers.c | 9 +++++++++ include/linux/leds.h | 2 ++ 3 files changed, 14 insertions(+) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 1b8b688aaaaf..ab61e41a00a3 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -64,6 +64,9 @@ static ssize_t brightness_store(struct device *dev, =20 if (state =3D=3D LED_OFF) led_trigger_remove(led_cdev); + else + led_trigger_remove_hw_control(led_cdev); + led_set_brightness(led_cdev, state); =20 ret =3D size; diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index bf2543538ed0..804a04b326c4 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -287,6 +287,15 @@ void led_trigger_remove(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_trigger_remove); =20 +void led_trigger_remove_hw_control(struct led_classdev *led_cdev) +{ + guard(rwsem_write)(&led_cdev->trigger_lock); + + if (__led_trigger_is_hw_controlled(led_cdev)) + led_trigger_set(led_cdev, NULL); +} +EXPORT_SYMBOL_GPL(led_trigger_remove_hw_control); + static bool led_match_default_trigger(struct led_classdev *led_cdev, struct led_trigger *trig) { diff --git a/include/linux/leds.h b/include/linux/leds.h index a630f5a79f6b..d7d3dd905432 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -533,6 +533,7 @@ void led_trigger_blink_oneshot(struct led_trigger *trig= ger, void led_trigger_set_default(struct led_classdev *led_cdev); int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *tri= gger); void led_trigger_remove(struct led_classdev *led_cdev); +void led_trigger_remove_hw_control(struct led_classdev *led_cdev); =20 bool led_trigger_is_hw_controlled(struct led_classdev *led_cdev); =20 @@ -586,6 +587,7 @@ static inline int led_trigger_set(struct led_classdev *= led_cdev, } =20 static inline void led_trigger_remove(struct led_classdev *led_cdev) {} +static inline void led_trigger_remove_hw_control(struct led_classdev *led_= cdev) {} =20 static inline bool led_trigger_is_hw_controlled(struct led_classdev *led_c= dev) { --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCC332F3C13; Sat, 18 Jul 2026 17:10:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394615; cv=pass; b=L6UedjFMpDzIF+lldvOPqV8U+OlH5RvSM1ZTF3l5ERc0SvT0lKM8SJHzy/M1ST7SLOTUF8590FwDqWzcF6DWwtMY3HcDvv5oF/ktHAiq0O2KmvC9tNvZuM30SWxodyiYe9x/PkkENEOmQTMUyH3UZ0XleLNb1HKCy51nfc1L3xA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394615; c=relaxed/simple; bh=siPKpdpScYCv3uER4hIOD0lPfZy8RBv8ZENZQCMPYUs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jeysJ2n7F/hEKy1mOnOlG3CcrPUETauw3U3cilXY0Yt6q6qMxVwOPfQTjNEXR+iRQ/JVTi1rp0DljTABOq2SI/Mq4QVayko5hrNcSXqJ0byz+aPu8a6LztXgdPT3qpYHTAl0YM1ejmitVop53ld2iZ2HB6Ehb3PCu0ulHd7BK5U= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=Gd2163/m; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="Gd2163/m" ARC-Seal: i=1; a=rsa-sha256; t=1784394538; cv=none; d=zohomail.com; s=zohoarc; b=BrdvW5PnLYec5aLnK0qFe5zgQv9+6u0k73I1N65bK+zGwEKXgOXrfZz08ygp3cecjwkiIDLlnWBBpczQUbqkraoHHKMzK+j1AGt4+DK3Mn30tbSias0IqgUVgs1++wA1ZShoA0Z3yrpf1U3gUia7QJKRjjl/VQR04SXh4aFH9Vc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394538; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=k/+Bnsj+ppa22WLJNmhmAmQwDPVBSSHpduVYFS4pCUs=; b=EzTN9mA6kZZYqRlABVJUIPml8NjsODue8i2pFiaXZwihA+l6ZOSZy9xO/uEJDyg37qH9nzBhkAbFALHQ3CKsrFPhtS9MclThh2cmTfbEoKy4c+n242DbLTqcGuCQLhQ1i21hzZpw3r9zY/e3EWcR3MzENLnsAgilNG5jLI0szfw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394538; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=k/+Bnsj+ppa22WLJNmhmAmQwDPVBSSHpduVYFS4pCUs=; b=Gd2163/mv2wXPN2LeBfdLFEo0dVVhkEa9IaIhPcnAzc5cG8GbVMid90ffeJ4OScE kvJxrW5uUD8YsrYiblhxMSqvng68nEpBCJl/+xudycM4MYPXe8WezE9HjC57cuFPZHj pauvtOlkOQ9n+UOfLHZxhcJQE7x5nI6uGUegXV7SI9jLH178KYMo4KygHcBDR9ZkU0i 6u3DVy50Hw35fKLKKTzKV29wFXGv1FqD+ZuOh5irRjsP4MhBffphzarHlnGObWzMVlK m0rLPzkFheh8UPNEBKec8ZcBKKtFbR4hnh434xtBTty3CHBS1ArWb4nxoNjmIywr92V kVMa7Gs+Mg== Received: by mx.zohomail.com with SMTPS id 1784394535062245.39213576405973; Sat, 18 Jul 2026 10:08:55 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:20 +0800 Subject: [PATCH RFC v3 03/11] leds: trigger: Add offloaded() callback and provide trigger_may_offload attribute Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-3-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External There are multiple triggers implementing hardware control. However, the LED trigger core doesn't really know the hardware control (offloaded) state since the coordination is done directly between the trigger and the LED driver. It can only assume private triggers as offloaded and generic ones as not offloaded. Add an offloaded() callback so that triggers can report their offloaded states to the LED trigger core. When unimplemented, it defaults to true for private triggers and false for generic ones to keep the current behavior unchanged. With that, provide a new attribute "trigger_may_offload", so that userspace can determine: - if the LED device supports hardware control (supported =3D> visible) - which trigger is the hardware control trigger selected by the LED device - if the trigger is selected ("") - if the trigger is offloaded ("[foo_trigger]") Note: the documentation describes the attribute as "returning a list" despite the LED core currently only supports one hardware control trigger per LED device. This is intentional to make the attribute extensible in the future without breaking userspace. Signed-off-by: Rong Zhang --- Changes in v3: - Rearrange the series so that the code using the offloaded() callback is introduced before the driver implementation (thanks Thomas Wei=C3=9Fschuh) - Reword documentation (ditto) - Adopt guard() and lockdep (ditto) - Adopt __led_trigger_is_hw_controlled() from newly-integrated PATCH 1 --- Documentation/ABI/testing/sysfs-class-led | 22 ++++++++++++++++++++++ Documentation/leds/leds-class.rst | 20 ++++++++++++++++++++ drivers/leds/led-class.c | 22 ++++++++++++++++++++++ drivers/leds/led-triggers.c | 29 +++++++++++++++++++++++++++= ++ drivers/leds/leds.h | 2 ++ include/linux/leds.h | 1 + 6 files changed, 96 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/= testing/sysfs-class-led index d4c918cc11a1..b61fc2e71bd3 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -78,6 +78,28 @@ Description: (which would often be configured in the device tree for the hardware). =20 +What: /sys/class/leds//trigger_may_offload +Date: July 2026 +KernelVersion: 7.3 +Contact: linux-leds@vger.kernel.org +Description: + Names and states of triggers that may be offloaded to hardware. + Such triggers are also called "hardware control trigger" in some + context. + + Only exists when the LED supports trigger offload. + + Reading this file returns a list of triggers that are capable to + be offloaded. The optional brackets around the trigger name + indicate the state of the current trigger: + + - `foo_trigger`: the trigger is not selected. + - ``: the trigger is selected, but falls back to + software blink for some reason (e.g., incompatible trigger + parameters) + - `[foo_trigger]`: the trigger is selected and offloaded to + hardware. + What: /sys/class/leds//inverted Date: January 2011 KernelVersion: 2.6.38 diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-cl= ass.rst index 3913966cfdac..2d41a6db602c 100644 --- a/Documentation/leds/leds-class.rst +++ b/Documentation/leds/leds-class.rst @@ -242,6 +242,9 @@ ops and needs to declare specific support for the suppo= rted triggers. =20 With hw control we refer to the LED driven by hardware. =20 +A sysfs attribute `trigger_may_offload` is provided for userspace to +query supported triggers and their states. + LED driver must define the following value to support hw control: =20 - hw_control_trigger: @@ -298,6 +301,15 @@ LED driver must implement the following API to support= hw control: Returns a pointer to a struct device or NULL if nothing is currently attached. =20 +LED trigger should implement the following API to indicate hw control: + - offloaded: + return a boolean indicating if the trigger is currently + offloaded to hardware. + + If a trigger doesn't implement this callback, the default + value will be true for private triggers and false for gene= ric + ones. + LED driver can activate additional modes by default to workaround the impossibility of supporting each different mode on the supported trigger. Examples are hardcoding the blink speed to a set interval, enable special @@ -311,6 +323,14 @@ the end use hw_control_set to activate hw control. A trigger can use hw_control_get to check if a LED is already in hw control and init their flags. =20 +Alternatively, a private trigger can be implemented along with the LED dri= ver if +the LED's hardware control doesn't fit any generic trigger. To associate t= he +private trigger with the LED classdev, their `trigger_type` must be the sa= me. To +declare that the private trigger provides hardware control for the associa= ted +LED classdev, set the `hw_control_trigger` string to the trigger's name. S= ince +both the LED classdev and the private trigger are in the same LED driver, = it's +not necessary for them to coordinate via `hw_control_*` callbacks. + When the LED is in hw control, no software blink is possible and doing so will effectively disable hw control. =20 diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index ab61e41a00a3..2460fcf0c469 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -96,8 +96,30 @@ static const struct bin_attribute *const led_trigger_bin= _attrs[] =3D { &bin_attr_trigger, NULL, }; + +static DEVICE_ATTR_RO(trigger_may_offload); +static struct attribute *led_trigger_attrs[] =3D { + &dev_attr_trigger_may_offload.attr, + NULL +}; + +static umode_t led_trigger_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + struct device *dev =3D kobj_to_dev(kobj); + struct led_classdev *led_cdev =3D dev_get_drvdata(dev); + + if (attr =3D=3D &dev_attr_trigger_may_offload.attr) + return led_cdev->hw_control_trigger ? attr->mode : 0; + + return attr->mode; +} + static const struct attribute_group led_trigger_group =3D { .bin_attrs =3D led_trigger_bin_attrs, + .attrs =3D led_trigger_attrs, + .is_visible =3D led_trigger_is_visible, }; #endif =20 diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 804a04b326c4..c3c41ef40f01 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -42,6 +42,9 @@ static bool __led_trigger_is_hw_controlled(struct led_cla= ssdev *led_cdev) if (!led_cdev->trigger) return false; =20 + if (led_cdev->trigger->offloaded) + return led_cdev->trigger->offloaded(led_cdev); + return led_cdev->trigger->trigger_type; } =20 @@ -341,6 +344,32 @@ void led_trigger_set_default(struct led_classdev *led_= cdev) } EXPORT_SYMBOL_GPL(led_trigger_set_default); =20 +ssize_t trigger_may_offload_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev =3D dev_get_drvdata(dev); + struct led_trigger *trig; + bool hit, offloaded; + int len; + + guard(mutex)(&led_cdev->led_access); + guard(rwsem_read)(&led_cdev->trigger_lock); + + trig =3D led_cdev->trigger; + + offloaded =3D __led_trigger_is_hw_controlled(led_cdev); + hit =3D offloaded || (trig && !strcmp(led_cdev->hw_control_trigger, trig-= >name)); + + /* [offloaded] inactive */ + len =3D sysfs_emit(buf, "%s%s%s\n", + offloaded ? "[" : (hit ? "<" : ""), + led_cdev->hw_control_trigger, + offloaded ? "]" : (hit ? ">" : "")); + + return len; +} +EXPORT_SYMBOL_GPL(trigger_may_offload_show); + /* LED Trigger Interface */ =20 int led_trigger_register(struct led_trigger *trig) diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h index bee46651e068..b08a289397e4 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -27,6 +27,8 @@ ssize_t led_trigger_read(struct file *filp, struct kobjec= t *kobj, ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, const struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count); +ssize_t trigger_may_offload_show(struct device *dev, + struct device_attribute *attr, char *buf); =20 extern struct rw_semaphore leds_list_lock; extern struct list_head leds_list; diff --git a/include/linux/leds.h b/include/linux/leds.h index d7d3dd905432..cc664da33e94 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -485,6 +485,7 @@ struct led_trigger { const char *name; int (*activate)(struct led_classdev *led_cdev); void (*deactivate)(struct led_classdev *led_cdev); + bool (*offloaded)(struct led_classdev *led_cdev); =20 /* Brightness set by led_trigger_event */ enum led_brightness brightness; --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E8E562F8E82; Sat, 18 Jul 2026 17:10:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394638; cv=pass; b=kkSmwqFzgIQAZoUBX5Podf6x1ltquJJgyP6sjO5TOJ5PEqMwpsHWrt4dwbtRYyY5DQp2/IXJwmRc3rU5syPR2L3S6gCTE+HMCN6TgBmITuGr9We3fq6K0B+7n/LrQF/IQfWf92aNq0U5+H4DWJhFvqj506asBfPuSQjxxyKEGUw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394638; c=relaxed/simple; bh=mMn5/gAcfXIS2dHn1eXIBVFDG7SYtH4xeqLKKDH+b/0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lXyQRbmjF9+nGKnM7BqoYULgKlPENZxbiJrf6MsefCcX3NwBVsQ/zZ/3nqien5mf0nslMpTDevvv9S5f6MAX4giTtiHBh1qX8tdehYX1qYYfw8JRRAFh9xlCJp5Ooh4R3PqqMFhzRphtwOAcrIj86JxhblstT/+lYBkaO9s0tKI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=Y5M8bSnq; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="Y5M8bSnq" ARC-Seal: i=1; a=rsa-sha256; t=1784394545; cv=none; d=zohomail.com; s=zohoarc; b=bBdrYEbmtwqeFXoYwnqK51S6CD3jrmnZH4ddjxzUB0cM1wCLZhIvpeh3vYa8a07yQI8c96+2/yUVKdOMjU5WIvo3Pp31YGUX6jSfFHL7KCThY3OZ35Aw3M4s50SNDyM5jW8KyGRaX3gf0aYIu9j2qSTuVCvPA42on1H5xJ8jEvI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394545; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=a+eZigGV0AFd+mJMUPLC0jjiv54AsqNFdGiskTsot5I=; b=lW087ToINOExwvRoBmQnvukl86Cfor315tMWMJ0ZcKRUp5b+8aTUsR2ze8NhREdFfAFDMbISiPQDIXrLJdYd+8cN5O+khLF6H/47kDRu9YwgXt5gH0Y1A1U3LH2flFTUxRFoW+vb4niuJlfmWGcx6LT9ddC79KVdYn/uv1xdqYc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394544; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=a+eZigGV0AFd+mJMUPLC0jjiv54AsqNFdGiskTsot5I=; b=Y5M8bSnqQpqv1vHUxZg22jh9yej8InBAvlixPkocBZvq3lFCRqR59qNx5ITqvJ7w 4TTOGH4a3IuQEyiVQmN9h95JSR5G2I/zMeabQ4lAfwiI8BYzypZTtWXTi3WkxV6veMn InZ9D5Qaao/2q1IIxf6/CO2sBfZ6Cs3VZlmyPlgY1z7uB2WwJBJRgJQSsfhuNvc2EQ/ +jR3CBkYuShXu0729ndnPrfGAXJGKgnMzAXZvi5Oa3s78XS22+8OjAjdoOKNMLXLIBy YHqZUu3t24hujh87E7reZBzBHwAHLv1uWQfnVA/qUTNQfuiBIyoF1VnmRR8Ml667nVQ 0xUewVkXrg== Received: by mx.zohomail.com with SMTPS id 1784394542020638.1174262743658; Sat, 18 Jul 2026 10:09:02 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:21 +0800 Subject: [PATCH RFC v3 04/11] leds: cros_ec: trigger: Implement offloaded() callback Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-4-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External "chromeos-auto" is a private hardware control trigger which always stays in hardware control. Implement offloaded() callback with its return value to be always true to reflect this. Reviewed-by: Thomas Wei=C3=9Fschuh Signed-off-by: Rong Zhang --- drivers/leds/leds-cros_ec.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/leds/leds-cros_ec.c b/drivers/leds/leds-cros_ec.c index 1844d0cd5f52..6db83d015277 100644 --- a/drivers/leds/leds-cros_ec.c +++ b/drivers/leds/leds-cros_ec.c @@ -85,12 +85,18 @@ static int cros_ec_led_trigger_activate(struct led_clas= sdev *led_cdev) return cros_ec_led_send_cmd(priv->cros_ec, &arg); } =20 +static bool cros_ec_led_trigger_offloaded(struct led_classdev *led_cdev) +{ + return true; +} + static struct led_hw_trigger_type cros_ec_led_trigger_type; =20 static struct led_trigger cros_ec_led_trigger =3D { .name =3D "chromeos-auto", .trigger_type =3D &cros_ec_led_trigger_type, .activate =3D cros_ec_led_trigger_activate, + .offloaded =3D cros_ec_led_trigger_offloaded, }; =20 static int cros_ec_led_brightness_set_blocking(struct led_classdev *led_cd= ev, --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A4FB2F3C13; Sat, 18 Jul 2026 17:10:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394658; cv=pass; b=c5gRC7FdUyOPHuEo25QAV3s9/XFTxX7+XkjiVaZUbLjlFgtEWPfWhbyU5MUR5I3Tj68ytKuckBi6t86VGJwQnvUtw1JvRT04ZjD4YxlGf+watHrWcTLxvKUPtU5UETsKGwFxx47sSUl4Wj7fpmJy+UIxhCj6Zdz3JAx7artiNJM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394658; c=relaxed/simple; bh=X9foO89JV8OGyX1PRKtcqc93ExKcnfUD0n2o9In4eWM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TfaC+kC9deZoRMq8nanDRuOE6cavhFeWN22s3YgXXct1mFJR9JlKk5c8bD/cUTDkpAv8kN0CpKuwQ4tzpF1deQ6sdJ3mFQxfBpxzC9jPJJbb1AqklnSmUgIB7V/8ZmznNaRpTPfUYDyEQzrhnaABcuMjIYuaOOrqKcM0gxi1b/I= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=BY77sVza; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="BY77sVza" ARC-Seal: i=1; a=rsa-sha256; t=1784394550; cv=none; d=zohomail.com; s=zohoarc; b=L7qq3LLzAzoK+5JNpFDE9QccxYd6h5NyWcTfiZOfdt+0tqX8fA5qm7seaKjefsXbQbpJ0NihdyKTEQxfzVYs/LKJffX6l91SsMImrOioBXgPqNFspE6A/6qXzVePvuLwGuOyIjDyCQx1I0y/5WqWVSAqDWiqRPX867AHTRcSf0U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394550; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=QVl4+M4/9Wz+ooVoO++Gqv0osQsXIMyFgRbac2TUkaU=; b=nTJULNeo/GlZX7reZ5UOARcUj0cKeyUVAzjRIitF7dgEoXVuPrFqfNHenCZ0b6mpbOqzvg9WaomLLxSZ0BuFWyIOTogOGL+6tYO77uLp2wYyEzmt4tsChvw4mK9e6z6eqfCl1HUk9dD8UjbhuYQXODqvEjv1V1WpB0fElqqmM4M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394550; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=QVl4+M4/9Wz+ooVoO++Gqv0osQsXIMyFgRbac2TUkaU=; b=BY77sVzaZ2B84rXkfDbNmkVY7GCUawWe5/XD/SX9vqXjWQuvmedwyRenPuIWUaMP B8OFCGojK6naJ+L1MXw0ebS2LUTg1YLUgi6NDIjzaeKrBO+sL5mXBxzIFggqFDyMY8r k93hiLHn3hcVNQhYRIxuYn0sQZpK7fiYHquSwu+TuuperTy/LTp/OBNKxJfXueJ6nWl w/F+iZ2BsXtOJX7K3KniWr9PUfbZlJpHvD8gTwaESsKKbgk/XO+89s3UCnytovZGXHD E0DlM8aKiaTXHoqNyQn2iD319ncOqyHPL//zOMvPOsXAy82nATW2a6LBPfF39kRYOI/ MftbtuUkBA== Received: by mx.zohomail.com with SMTPS id 1784394548534983.9557685965633; Sat, 18 Jul 2026 10:09:08 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:22 +0800 Subject: [PATCH RFC v3 05/11] leds: turris-omnia: trigger: Implement offloaded() and declare hw_control_trigger Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-5-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External "omnia-mcu" is a private hardware control trigger which always stays in hardware control mode. Implement offloaded() callback with its return value to be always true to reflect this. Meanwhile, declare it as a hardware control trigger as it's forgotten before. Signed-off-by: Rong Zhang --- drivers/leds/leds-turris-omnia.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-om= nia.c index ed6a47bbb44f..32d40d176d3f 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -195,10 +195,16 @@ static void omnia_hwtrig_deactivate(struct led_classd= ev *cdev) err); } =20 +static bool omnia_hwtrig_offloaded(struct led_classdev *cdev) +{ + return true; +} + static struct led_trigger omnia_hw_trigger =3D { .name =3D "omnia-mcu", .activate =3D omnia_hwtrig_activate, .deactivate =3D omnia_hwtrig_deactivate, + .offloaded =3D omnia_hwtrig_offloaded, .trigger_type =3D &omnia_hw_trigger_type, }; =20 @@ -251,6 +257,7 @@ static int omnia_led_register(struct i2c_client *client= , struct omnia_led *led, * by LED class from the linux,default-trigger property. */ cdev->default_trigger =3D omnia_hw_trigger.name; + cdev->hw_control_trigger =3D omnia_hw_trigger.name; =20 /* Put the LED into software mode */ ret =3D omnia_cmd_write_u8(client, OMNIA_CMD_LED_MODE, OMNIA_CMD_LED_MODE= _LED(led->reg) | --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C17DD17BB21; Sat, 18 Jul 2026 17:11:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394679; cv=pass; b=X4iEgzY8EfrjvYmPEo1srKEXRO9Sc9ohT+bVYESZkfT6TIf2Krc/BlQ83cGeEsmzVxllsmB+aM2Cr+i185eHJqc76L3yG3riVwfOhjeyp/t3Ymk/0BHR8jKryvFrfSWyLM96JHBO0fMAiwewMiLocaQF59wR9E4oE03IZNT+HjQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394679; c=relaxed/simple; bh=4T2pGEXqjw1NmLQAnBSCJ61qYoJ5LDpeL5hLcljC0MI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MsQH7SA9N/LGGFc9cxloSVVu9gP7FbAQHwVaa/Z6HhlkrYswAJS8xYHF3MfhfG4emL6y1L5dPcrpywK/jjTF+1tOIBeIlEZsPmzkx0/GD9nLsdoOogR0WPBJu41JTm31PFVtBJWZ+4Al1ZiljnOjO+PYaqf7dfzJb0M4BH+Nk3o= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=Lwve+T/M; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="Lwve+T/M" ARC-Seal: i=1; a=rsa-sha256; t=1784394559; cv=none; d=zohomail.com; s=zohoarc; b=Im6qk9AQ4GiM3yDDhSq6xkvyxQsLy26KsLOQrQ94TivRsCt2DCILxOgWCjBP6Y/3YN2hfbATtFXd6apWqu45XT/JKTpw0DAPszPNtwxe5Azuo7eodqeZLV7YR0JE7NpFm31J1vPSG6Ccpk99/kEuqxMsC0oHmkI97J8HXI1BOLc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394559; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=p2wKjKwxZJsRgFmU4Uh4/kREypsgmL6qSRMs+0v5GLo=; b=hOGlVrmCmlY8hsj16X+RIVCq7mRJ7fL7341b5ulyFON+MNcV13cya7HpZlGY/SM7G31rWrb3Q8g3MQL2ZM8TLYJn2GgsNK/RLWm2+eZryBQeqt00iXwJJj7E199chud2tviwtR+cEEgblZe6Pd05ssDNXu+VxGjFNj1knxKw+8k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394559; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=p2wKjKwxZJsRgFmU4Uh4/kREypsgmL6qSRMs+0v5GLo=; b=Lwve+T/MdAUCTHzXHa97dnaK3ykcOUu5TX+6ow5x7fF/2S/srVX6cJYjRLhj8g1a iVHfMD//kUe4FKfLy+MapmN1ysrKnvym8ymZiogDR+VFhL3u2d10L2R3DVailrbdEl9 ftq8Zfsbeya3ug1vdv+Vib9+0KtgXrO7GmqTo+6TEvEyJURzMOHmLqwSvFkubKJcFQ4 GqarcEDpf/BGIAO+AGXr0LJK1MnitpliyMEiuIqCxKznzqiqFM6XekB1qMDZWlxHh1U cYwqH7KawvJJbNuFoB8zohxQTYQg/bSkfcDtb35rhYkKN17t733rTijeRNZmrbH+3rG iZr/BnaLwg== Received: by mx.zohomail.com with SMTPS id 1784394555064358.8195120922568; Sat, 18 Jul 2026 10:09:15 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:23 +0800 Subject: [PATCH RFC v3 06/11] leds: trigger: netdev: Implement offloaded() callback Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-6-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External "netdev" can run in hardware control according to hardware capabilities and trigger options. Implement offloaded() callback to provide its hardware control state to the LED core, and document the relation between the custom "offloaded" attribute and the generic "trigger_may_offload" attribute. Signed-off-by: Rong Zhang --- Changes in v3: - Do not deprecate netdev's "offloaded" attribute (thanks Thomas Wei=C3=9Fschuh) - Document the relation between the custom "offloaded" attribute and the generic "trigger_may_offload" attribute (ditto) --- Documentation/ABI/testing/sysfs-class-led | 3 +++ Documentation/ABI/testing/sysfs-class-led-trigger-netdev | 3 +++ drivers/leds/trigger/ledtrig-netdev.c | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/= testing/sysfs-class-led index b61fc2e71bd3..7dc95f7a3505 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -100,6 +100,9 @@ Description: - `[foo_trigger]`: the trigger is selected and offloaded to hardware. =20 + The "netdev" trigger also provides a custom attribute to + indicate its state, see `/sys/class/leds//offloaded`. + What: /sys/class/leds//inverted Date: January 2011 KernelVersion: 2.6.38 diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Doc= umentation/ABI/testing/sysfs-class-led-trigger-netdev index ed46b37ab8a2..a5146ea1e3e6 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev @@ -75,6 +75,9 @@ Description: If 1, the LED blinking in requested mode is offloaded to hardware. =20 + LED trigger core also provides a generic attribute for this + purpose, see `/sys/class/leds//trigger_may_offload`. + What: /sys/class/leds//link_10 Date: Jun 2023 KernelVersion: 6.5 diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/l= edtrig-netdev.c index 64c078e997f2..a26109ca4b1c 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -754,10 +754,18 @@ static void netdev_trig_deactivate(struct led_classde= v *led_cdev) kfree(trigger_data); } =20 +static bool netdev_trig_offloaded(struct led_classdev *led_cdev) +{ + struct led_netdev_data *trigger_data =3D led_get_trigger_data(led_cdev); + + return trigger_data->hw_control; +} + static struct led_trigger netdev_led_trigger =3D { .name =3D "netdev", .activate =3D netdev_trig_activate, .deactivate =3D netdev_trig_deactivate, + .offloaded =3D netdev_trig_offloaded, .groups =3D netdev_trig_groups, }; =20 --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 66310346FA4; Sat, 18 Jul 2026 17:11:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394699; cv=pass; b=HEfj0o28K7FVfnVsb4+LNgSerc/4DboJSIlDGcqykWZ4fMNe/IgP849XhBLg31uLYtnr35Ey8jgq0QU3qnPjYqV1OeqimWWBdHyJs575OkopOtnarwHpGSk/d6zkM+p/7rgKp1FqfRXejthEHYCxUZq0sbPc2EDAB1pPvrYRp5k= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394699; c=relaxed/simple; bh=+Thp/jc9SIz/ZrGRmTtRkgQn7xFt5lFdfmT0WWrC0/s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Hr1lTa5klUsXIdtZb5Ye7XZCjxkmSK1WC7kzcLuD69IZvI8UhtGqi83hGjavnG2MwoIITNjlfv9YbY1t//qzfwSW/7+b4/S7lO9hiqgfh2x9Jybwg9NnlDip4t17TGDovO3ABB1ZLvgXOVTlC3I1MtBMrMdWvM5Swl3w2W+dmdw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=QLB1Ay+w; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="QLB1Ay+w" ARC-Seal: i=1; a=rsa-sha256; t=1784394565; cv=none; d=zohomail.com; s=zohoarc; b=CmkdDJNu7ZXZIU56I99blKRzNvGpOZMwFq6lQtP3gttF49g/vzoX24/o6FhHLnKFHemG/GwDGtdpCE3+FvqWTAiA7enPmVcBuq+K3IAbRlpIS7e1jDgocA6ZoDY14LM3BJqaWDqbooF32WMimbdIoEeVYzIcVltWReI/uXTu8hs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394565; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=H+EGsbKbUKh/mzUdXXdH0o7bUxq0TfxOnBDjf2XMh34=; b=juuli9aWmc1CsPTY1iLgIc9Gmynzj+gAofxky4xWX/vtBhPLAnhaVk9hXKKc8RDNXKH4wiGgpXBKz0oQdO8jNtvyjLAijCD3LA6Lu5m+WI5t79jltPlDNdFpaiEhglI8X0JO5TZNnzA4Ml0ckS4SavMQorGkNKYDY6Qdvf9bfqo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394565; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=H+EGsbKbUKh/mzUdXXdH0o7bUxq0TfxOnBDjf2XMh34=; b=QLB1Ay+wc6V4URfZeZcFlGrTcGERGK8sB1O3KRO9EV/ifnDmEjEs0llZJQFQr3Ha 8afRdjea0mUaTdnGD7DMj8jaBbN1dsIZElhIxyeMp5jfnLVvNTmFsOaOHBkB22RxkEU O0U2cBlOwJ3RIzf2v+SYe/9zHgxIBkXF3Lq/+efYNuUS+9sPaSvypU98y3gzQWtQstT my30KlXBUzIZIck9kBFZL2xG3YiDs3X+ph0DPAE3nAK/f1uVLMzAXFoawAnRLrrYxpW m3wQJWLPQU8WIHQEukx10XlqrkXnXJLE5F9S35aQv09GCE43ylBjCB4VCNkqqMNeQVI GGCzP7l3DA== Received: by mx.zohomail.com with SMTPS id 178439456248279.82387641494734; Sat, 18 Jul 2026 10:09:22 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:24 +0800 Subject: [PATCH RFC v3 07/11] leds: trigger: Enforce strict checks in led_trigger_is_hw_controlled() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-7-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External With all existing triggers adopting the new interface, strict checks could be enforced to make the semantics of hardware control triggers clearer. In detail, a hardware control trigger should: - Implement offloaded() callback to indicate hardware control - Associate with the LED classdev's hw_control_trigger string Signed-off-by: Rong Zhang --- Changes in v3: - New patch in the series, splitted from PATCH 3 (thanks Thomas Wei=C3=9Fschuh) --- drivers/leds/led-triggers.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index c3c41ef40f01..726fa7bf88cf 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -42,9 +42,16 @@ static bool __led_trigger_is_hw_controlled(struct led_cl= assdev *led_cdev) if (!led_cdev->trigger) return false; =20 + if (!led_cdev->hw_control_trigger || + strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name)) + return false; + if (led_cdev->trigger->offloaded) return led_cdev->trigger->offloaded(led_cdev); =20 + dev_warn_once(led_cdev->dev, "hw control trigger %s doesn't implement off= loaded()\n", + led_cdev->trigger->name); + return led_cdev->trigger->trigger_type; } =20 --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ACB852F3C13; Sat, 18 Jul 2026 17:11:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394721; cv=pass; b=qfZMDlzqIjju4WpT1Oko9Hj7gnRrdp8AAxZGXfFbA7sGDskE/ZZS4QKII9hi18Bp76y8//L511EtKI4+sb+mhs2HZxPH/xty1uYSoAvStrrz8RH0S12FSrLto9tXfYzT9EXr7jppK2s9Sk0jqhHn2JLRBwyvBaRDJfeVF8XnHCs= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394721; c=relaxed/simple; bh=2OWihFvvggiYQs78T/F9z+LoDm38UPfu54llV3EgWiU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DZqUn/A5if4FuMJ/PUXbZPUTyvF8+3KdjAn8k6ZVjt4KdECavAzqOfl2zlv4KJiNjYcnAQ1Nhdx7SIewIGWuffL8l/h4KnL9xjjx78Qe+K4WF1uosTP76VBzEBRe4UanIDG7D+A7JsjwvV3czKIxYigPDV1p18Cwm1W27qUIXwU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=GrpI2oTb; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="GrpI2oTb" ARC-Seal: i=1; a=rsa-sha256; t=1784394573; cv=none; d=zohomail.com; s=zohoarc; b=dCJfPMvtZDEKP8h/A8LPBhR5F9K9h/wuMvTVmyl+C2MPSWAfpuUYrJZczJAC1Sizsp3qpiuKU2bv5jgnJllqACa0p/dyXeiyrf+8AH5pEuW9RRtMoJTn1UAhbZeyhxBU7of2O77zC2A2Vf5vUPdJX1aSwMrn0Ar/TXztYZV6e0I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394573; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=SJ3xvKFlIzPaCFL/Xmz2CoqSlATafTeB5OQGACwgtNQ=; b=nEIWFkaluYkO4fg+dr91jUDTv9It4/ECwkVrcsb9VVy9TopiM0uEhloDPUYKBZNmiR2KseyarYNnZe/gVliU1J/p8FWgqTFLEiYvVA0mcxHVo62FK6U4Ar9JMO3/nHpxs7zeqLfdqzX3Hf6qSpyChmcwA9tIBJLMJuoAughM934= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394573; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=SJ3xvKFlIzPaCFL/Xmz2CoqSlATafTeB5OQGACwgtNQ=; b=GrpI2oTbrhv2rSsi9J0pcutDxsLNm3Galn3pHnmPsLAjHygzaML6+sC6DvSttQCV +0RI5vk/u/V4CRPbmaLDrItsxxdXuwwlpXyI2CN3x3PJSe2TPXyNGJkFctxnvSA9uX+ Qc97FDjzoJrVnaUZYi8XWuoT7OAPvh5IV9h0ctIPDHRNMiTZ+T4mzWcXSA23D+jQDgV HLBxjK+gXr/u0onwaqxnwqQBARLpd8PxpveL8xl1MvncYjb0oKxeHCyejuyp9GRQg5v gM1iW6DF+BMfZJn+ewkHQQa+hRZFZSDas96H/6CxO79w1Gob41RkTF/Y7I5vfGHO1BT QU6RtJjUwA== Received: by mx.zohomail.com with SMTPS id 1784394569554688.9236596937429; Sat, 18 Jul 2026 10:09:29 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:25 +0800 Subject: [PATCH RFC v3 08/11] leds: trigger: Add led_trigger_notify_hw_control_changed() interface Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-8-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External Some hardware can autonomously activate/deactivate hardware control. After that, the LED hardware notifies the LED driver. Currently, there is no mechanism for LED drivers to notify the LED core about such events and initiate a trigger transition to reflect the hardware state. Add a new interface called led_trigger_notify_hw_control_changed(), so that LED drivers can call it to notify the LED core about the transition. The interface only allows two transitions: 1. "none" =3D> private trigger 2. private trigger =3D> "none" If the current trigger is neither the private trigger nor "none", no transition will be made. This protects the currently selected software trigger. Note that LED_OFF won't be emitted during the #2 transition, as some hardware may have selected a new brightness level during its hardware state transition (e.g., laptop keyboards with a shortcut cycling through different backlight brightnesses and auto mode). The interface is designed as a void function as any failure should be non-fatal and the result of transition should not have any impact on the LED drivers' event handling procedures. To use the interface, LEDS_TRIGGERS_HW_CHANGED must be enabled in Kconfig, and the LED driver must set the LED_TRIG_HW_CHANGED flag for the classdev. Signed-off-by: Rong Zhang --- Changes in v3: - Adopt guard() (Thanks Thomas Wei=C3=9Fschuh) - Reword documentations --- Documentation/leds/leds-class.rst | 52 +++++++++++++++++++++++++ drivers/leds/led-triggers.c | 82 +++++++++++++++++++++++++++++++++++= +++- drivers/leds/trigger/Kconfig | 9 +++++ include/linux/leds.h | 8 ++++ 4 files changed, 149 insertions(+), 2 deletions(-) diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-cl= ass.rst index 2d41a6db602c..adbc57b9f49c 100644 --- a/Documentation/leds/leds-class.rst +++ b/Documentation/leds/leds-class.rst @@ -334,6 +334,58 @@ not necessary for them to coordinate via `hw_control_*= ` callbacks. When the LED is in hw control, no software blink is possible and doing so will effectively disable hw control. =20 +Hardware-initiated trigger transition +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Some hardware can autonomously activate/deactivate hardware control. After= that, +the LED hardware notifies the LED driver. + +If the driver can detect such transitions and thus wants to notify the LED= core +to update the current trigger then the `LED_TRIG_HW_CHANGED` flag must be = set in +flags before registering. To update the current trigger accordingly, call +`led_trigger_notify_hw_control_changed` on the LED classdev. + +This capability is restricted to the LED device's private trigger. The pri= vate +trigger must have been properly registered (see above) and named after +`hw_control_trigger`. + +Only two transitions are defined: + +- "none" =3D> private trigger: + This happens when the hardware autonomously activates hardware con= trol + and when "none" (i.e., no trigger) is currently active. If the pri= vate + trigger is already active when the method is called, this is essen= tially + a no-op. + + The activation sequence for the private trigger will be executed as + normal. + + The LED driver and its private trigger must be able to handle the + activation sequence even if the hardware is currently in hardware + control. + + If error occurs in the activation sequence, the LED Trigger core r= everts + the effective trigger to "none". + +- private trigger =3D> "none" + This happens when the hardware autonomously deactivates hardware c= ontrol + and when the private trigger is currently active. If "none" (i.e.,= no + trigger) is active when the method is called, this is essentially a + no-op. + + The deactivation sequence for the private trigger will be executed= as + normal, except that the current LED brightness is retained. The re= ason + for keeping the brightness unchanged is that some hardware may cho= ose a + specific brightness instead of simply turning off the LED after + autonomously deactivating hardware control. + + The LED driver and its private trigger must be able to handle the + deactivation sequence even if the hardware is not currently in har= dware + control. + +If the current trigger is neither the private trigger nor "none", no trans= ition +will be made. + Known Issues =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 726fa7bf88cf..6ae28cbd1c77 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -7,6 +7,7 @@ * Author: Richard Purdie */ =20 +#include #include #include #include @@ -192,7 +193,8 @@ ssize_t led_trigger_read(struct file *filp, struct kobj= ect *kobj, EXPORT_SYMBOL_GPL(led_trigger_read); =20 /* Caller must ensure led_cdev->trigger_lock held */ -int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *tri= g) +static int __led_trigger_set(struct led_classdev *led_cdev, struct led_tri= gger *trig, + bool hw_triggered) { char *event =3D NULL; char *envp[2]; @@ -223,7 +225,21 @@ int led_trigger_set(struct led_classdev *led_cdev, str= uct led_trigger *trig) led_cdev->trigger_data =3D NULL; led_cdev->activated =3D false; led_cdev->flags &=3D ~LED_INIT_DEFAULT_TRIGGER; - led_set_brightness(led_cdev, LED_OFF); + + /* + * Hardware may have selected a new brightness level during its + * hardware control transition, so only reset brightness if we + * are switching to another trigger or if the switching is not + * hardware triggered. + * + * Note that this does not apply to the error path, as running + * into the error path implies a none =3D> private trigger + * transition. This hints that the LED driver and its private + * trigger must have some fundamental bugs, so don't bother + * leaving the LED in an undefined state. + */ + if (trig || !hw_triggered) + led_set_brightness(led_cdev, LED_OFF); } if (trig) { spin_lock(&trig->leddev_list_lock); @@ -287,6 +303,11 @@ int led_trigger_set(struct led_classdev *led_cdev, str= uct led_trigger *trig) =20 return ret; } + +int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *tri= g) +{ + return __led_trigger_set(led_cdev, trig, false); +} EXPORT_SYMBOL_GPL(led_trigger_set); =20 void led_trigger_remove(struct led_classdev *led_cdev) @@ -467,6 +488,63 @@ int devm_led_trigger_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_led_trigger_register); =20 +#ifdef CONFIG_LEDS_TRIGGERS_HW_CHANGED +static void led_trigger_do_hw_control_transition(struct led_classdev *led_= cdev, bool activate, + struct led_trigger *hc_trig) +{ + int err =3D 0; + + if (!led_cdev->trigger) { + /* "none" =3D> private trigger. */ + if (activate) + err =3D __led_trigger_set(led_cdev, hc_trig, true); + } else if (led_cdev->trigger =3D=3D hc_trig) { + /* private trigger =3D> "none". */ + if (!activate) + err =3D __led_trigger_set(led_cdev, NULL, true); + } else { + /* Other trigger is active. */ + dev_dbg(led_cdev->dev, + "Ignoring hw control transition (%s %s) while %s is active", + activate ? "activate" : "deactivate", hc_trig->name, + led_cdev->trigger->name); + + return; + } + + if (err) + dev_warn(led_cdev->dev, "Failed to %s %s in hw control transition: %d", + activate ? "activate" : "deactivate", hc_trig->name, err); +} + +void led_trigger_notify_hw_control_changed(struct led_classdev *led_cdev, = bool activate) +{ + struct led_trigger *trig; + + /* Restricted to private triggers. */ + if (WARN_ON(!(led_cdev->flags & LED_TRIG_HW_CHANGED) || + !led_cdev->hw_control_trigger || !led_cdev->trigger_type)) + return; + + scoped_guard(rwsem_read, &triggers_list_lock) { + list_for_each_entry(trig, &trigger_list, next_trig) { + if (trig->trigger_type =3D=3D led_cdev->trigger_type && + !strcmp(trig->name, led_cdev->hw_control_trigger)) { + guard(rwsem_write)(&led_cdev->trigger_lock); + + led_trigger_do_hw_control_transition(led_cdev, activate, trig); + return; + } + } + } + + dev_err(led_cdev->dev, + "%s() is called, but the private trigger (%s) is not properly registered= \n", + __func__, led_cdev->hw_control_trigger); +} +EXPORT_SYMBOL_GPL(led_trigger_notify_hw_control_changed); +#endif /* CONFIG_LEDS_TRIGGERS_HW_CHANGED */ + /* Simple LED Trigger Interface */ =20 void led_trigger_event(struct led_trigger *trig, diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index c11282a74b5a..798122154049 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -9,6 +9,15 @@ menuconfig LEDS_TRIGGERS =20 if LEDS_TRIGGERS =20 +config LEDS_TRIGGERS_HW_CHANGED + bool "LED hardware-initiated trigger transition support" + help + This option enables support for hardware initiated hardware control + transitions, where the LED hardware autonomously switches between + "none" (i.e., no trigger) and its private trigger. + + See Documentation/leds/leds-class.rst for details. + config LEDS_TRIGGER_TIMER tristate "LED Timer Trigger" help diff --git a/include/linux/leds.h b/include/linux/leds.h index cc664da33e94..167598962b73 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -109,6 +109,7 @@ struct led_classdev { #define LED_INIT_DEFAULT_TRIGGER BIT(23) #define LED_REJECT_NAME_CONFLICT BIT(24) #define LED_MULTI_COLOR BIT(25) +#define LED_TRIG_HW_CHANGED BIT(26) =20 /* set_brightness_work / blink_timer flags, atomic, private. */ unsigned long work_flags; @@ -609,6 +610,13 @@ led_trigger_get_brightness(const struct led_trigger *t= rigger) =20 #endif /* CONFIG_LEDS_TRIGGERS */ =20 +#ifdef CONFIG_LEDS_TRIGGERS_HW_CHANGED +void led_trigger_notify_hw_control_changed(struct led_classdev *led_cdev, = bool activate); +#else +static inline void led_trigger_notify_hw_control_changed(struct led_classd= ev *led_cdev, + bool activate) {} +#endif + /* Trigger specific enum */ enum led_trigger_netdev_modes { TRIGGER_NETDEV_LINK =3D 0, --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74ABB26E6F2; Sat, 18 Jul 2026 17:12:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394741; cv=pass; b=bZEt9lYHU5l4+DhWC51SNQYLeYqtetmtjFaXMCKfkiWKknnGh7yLO5AX5WdlN8H5KZ4cRKY0cUk0tFd6IOViaDBl2bBhPEqciUQSAmhBHTuy4AJxSvc7peAPsmtx2OI3j5zWaRv5BSCnsLEFZeW4veO48j0LgC8jrELQz0ChQrY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394741; c=relaxed/simple; bh=vAemNfI/UaWPjD2SHsJqf264AVmIBPrKWH8RGEQzhJc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uf0RbcoHbTTsehYn71+Y414FRRPoCncHXvKfv5oq5qIRRVTQdcW2OeW3Ji0kpMBbNBJjcQ3xRdP8EkghneMAJU71ejkeJvhe5kJr2ljIa7mPonJMzZ8H2Xk0gTDxI1geztdgwcL3VDuLQkD4+lK33Zuz8ookD7Ge3cUnuItUkII= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=G2WyNxa0; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="G2WyNxa0" ARC-Seal: i=1; a=rsa-sha256; t=1784394579; cv=none; d=zohomail.com; s=zohoarc; b=mmelDrYpishJJQoms07a3Ce1koONTivuac7SdH+xixmyI63RcTubuLz2lXtPfTdsWj5HOmKfzpnFNGNIxOCJ18fD1JxX9uXNEZxmWmrdKcLWb04QYDzLVjCPSX5AJyzIuvAij3yCJHGZ308N6wrEwi+SBcI/ULf09QJGyETH4GY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394579; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=w1ke2EOTiK2w1y2YjflmS7/fALaputoCJT0OsKY6X+8=; b=jXuzcR+EJcY4eKTlR6WlSBZbD8XlQ58mW6nRj4W8gRL+2hLB5hoO89gSkJ0qzbkk9fnF28yDTLolCJzt+yHd+dMItS11y5kijTpfZk+ZxlObhUby8PIH5RMK6wIbwPq+V4V30WYkuCXvGvqtKRVPBKPAOg8eSkNvPmjkUXj1SWQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394579; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=w1ke2EOTiK2w1y2YjflmS7/fALaputoCJT0OsKY6X+8=; b=G2WyNxa0uVsjZFABsV0PGSiNdpYD5L2oqd9BYAd4V1JYQ//2qVolZLwz8tiG5+kD 1R3VXPS60LXGeP6wOoqjVWwPCBihR5bGLllFOnT4CrO7gQpeMP4p//iDjB2CaJStOG7 bS2OBQ0J5mhtS9yA/weAVzW+FMdJLNN2rmMF9XDfjZBf7N0L7DaI5B0ZytFqC6Gx/tu cQGmOFMBzMENg91SPWUjXCArWMVzVEYTxVkiW2Hd5pYC8CpqvVflDA35faUIjhZlclm q3PF5M6eBwVgIvdOXZLFVM0q5OM6zx1nx0em6+GgV7ZBeYPpDsVmhlUOmYirRJxJd0g qjQQTL6OOQ== Received: by mx.zohomail.com with SMTPS id 178439457617793.18768970626479; Sat, 18 Jul 2026 10:09:36 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:26 +0800 Subject: [PATCH RFC v3 09/11] platform/x86: ideapad-laptop: Decouple hardware & classdev brightness for keyboard backlight Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-9-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External Some recent models come with an ambient light sensor (ALS). On these models, their EC will automatically set the keyboard backlight to an appropriate brightness when the effective "hardware brightness" is 3. "Hardware brightness" can't be perfectly mapped to an LED classdev brightness, but the EC does use this predefined brightness value to represent auto mode. Currently, the code processing keyboard backlight is coupled with LED classdev, making it hard to expose the auto brightness (ALS) mode to the userspace. As the first step toward the goal, decouple hardware brightness from LED classdev brightness, and update comments about corresponding backlight modes. Since upcoming changes will heavily rely on kbd_bl.last_hw_brightness, also convert it into an atomic_t to prevent potential race conditions. To minimalize the diff set in upcoming changes, a trivial refactor also converts the initialization path into another equivalent form. Signed-off-by: Rong Zhang --- drivers/platform/x86/lenovo/Kconfig | 1 + drivers/platform/x86/lenovo/ideapad-laptop.c | 144 ++++++++++++++++++-----= ---- 2 files changed, 100 insertions(+), 45 deletions(-) diff --git a/drivers/platform/x86/lenovo/Kconfig b/drivers/platform/x86/len= ovo/Kconfig index 4443f40ef8aa..e92b1e900795 100644 --- a/drivers/platform/x86/lenovo/Kconfig +++ b/drivers/platform/x86/lenovo/Kconfig @@ -16,6 +16,7 @@ config IDEAPAD_LAPTOP select INPUT_SPARSEKMAP select NEW_LEDS select LEDS_CLASS + select LEDS_TRIGGERS help This is a driver for Lenovo IdeaPad netbooks contains drivers for rfkill switch, hotkey, fan control and backlight control. diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platfor= m/x86/lenovo/ideapad-laptop.c index 4fbc904f1fc3..5aa2fedb8472 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt =20 #include +#include #include #include #include @@ -134,10 +135,31 @@ enum { }; =20 /* - * These correspond to the number of supported states - 1 - * Future keyboard types may need a new system, if there's a collision - * KBD_BL_TRISTATE_AUTO has no way to report or set the auto state - * so it effectively has 3 states, but needs to handle 4 + * The enumeration has two purposes: + * - as an internal identifier for all known types of keyboard backlight + * - as a mandatory parameter of the KBLC command + * + * For each type, the hardware brightness values are defined as follows: + * +--------------------------+----------+-----+------+------+ + * | Hardware brightness | 0 | 1 | 2 | 3 | + * | Type | | | | | + * +--------------------------+----------+-----+------+------+ + * | KBD_BL_STANDARD | off | on | N/A | N/A | + * +--------------------------+----------+-----+------+------+ + * | KBD_BL_TRISTATE | off | low | high | N/A | + * +--------------------------+----------+-----+------+------+ + * | KBD_BL_TRISTATE_AUTO | off | low | high | auto | + * +--------------------------+----------+-----+------+------+ + * + * We map LED classdev brightness for KBD_BL_TRISTATE_AUTO as follows: + * +--------------------------+----------+-----+------+ + * | LED classdev brightness | 0 | 1 | 2 | + * | Operation | | | | + * +--------------------------+----------+-----+------+ + * | Read | off/auto | low | high | + * +--------------------------+----------+-----+------+ + * | Write | off | low | high | + * +--------------------------+----------+-----+------+ */ enum { KBD_BL_STANDARD =3D 1, @@ -145,6 +167,8 @@ enum { KBD_BL_TRISTATE_AUTO =3D 3, }; =20 +#define KBD_BL_AUTO_MODE_HW_BRIGHTNESS 3 + #define KBD_BL_QUERY_TYPE 0x1 #define KBD_BL_TRISTATE_TYPE 0x5 #define KBD_BL_TRISTATE_AUTO_TYPE 0x7 @@ -203,7 +227,7 @@ struct ideapad_private { bool initialized; int type; struct led_classdev led; - unsigned int last_brightness; + atomic_t last_hw_brightness; } kbd_bl; struct { bool initialized; @@ -1592,7 +1616,24 @@ static int ideapad_kbd_bl_check_tristate(int type) return (type =3D=3D KBD_BL_TRISTATE) || (type =3D=3D KBD_BL_TRISTATE_AUTO= ); } =20 -static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv) +static int ideapad_kbd_bl_brightness_parse(struct ideapad_private *priv, i= nt hw_brightness) +{ + /* Off, low or high */ + if (hw_brightness <=3D priv->kbd_bl.led.max_brightness) + return hw_brightness; + + /* Auto (controlled by EC according to ALS), report as off */ + if (priv->kbd_bl.type =3D=3D KBD_BL_TRISTATE_AUTO && + hw_brightness =3D=3D KBD_BL_AUTO_MODE_HW_BRIGHTNESS) + return 0; + + /* Unknown value */ + dev_warn(&priv->platform_device->dev, + "Unknown keyboard backlight value: %d", hw_brightness); + return -EINVAL; +} + +static int ideapad_kbd_bl_hw_brightness_get(struct ideapad_private *priv) { unsigned long value; int err; @@ -1606,21 +1647,7 @@ static int ideapad_kbd_bl_brightness_get(struct idea= pad_private *priv) if (err) return err; =20 - /* Convert returned value to brightness level */ - value =3D FIELD_GET(KBD_BL_GET_BRIGHTNESS, value); - - /* Off, low or high */ - if (value <=3D priv->kbd_bl.led.max_brightness) - return value; - - /* Auto, report as off */ - if (value =3D=3D priv->kbd_bl.led.max_brightness + 1) - return 0; - - /* Unknown value */ - dev_warn(&priv->platform_device->dev, - "Unknown keyboard backlight value: %lu", value); - return -EINVAL; + return FIELD_GET(KBD_BL_GET_BRIGHTNESS, value); } =20 err =3D eval_hals(priv->adev->handle, &value); @@ -1630,6 +1657,16 @@ static int ideapad_kbd_bl_brightness_get(struct idea= pad_private *priv) return !!test_bit(HALS_KBD_BL_STATE_BIT, &value); } =20 +static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv) +{ + int hw_brightness =3D ideapad_kbd_bl_hw_brightness_get(priv); + + if (hw_brightness < 0) + return hw_brightness; + + return ideapad_kbd_bl_brightness_parse(priv, hw_brightness); +} + static enum led_brightness ideapad_kbd_bl_led_cdev_brightness_get(struct l= ed_classdev *led_cdev) { struct ideapad_private *priv =3D container_of(led_cdev, struct ideapad_pr= ivate, kbd_bl.led); @@ -1637,32 +1674,37 @@ static enum led_brightness ideapad_kbd_bl_led_cdev_= brightness_get(struct led_cla return ideapad_kbd_bl_brightness_get(priv); } =20 -static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, uns= igned int brightness) +static int ideapad_kbd_bl_hw_brightness_set(struct ideapad_private *priv, = int hw_brightness) { - int err; unsigned long value; int type =3D priv->kbd_bl.type; + int err; =20 if (ideapad_kbd_bl_check_tristate(type)) { - if (brightness > priv->kbd_bl.led.max_brightness) - return -EINVAL; - - value =3D FIELD_PREP(KBD_BL_SET_BRIGHTNESS, brightness) | + value =3D FIELD_PREP(KBD_BL_SET_BRIGHTNESS, hw_brightness) | FIELD_PREP(KBD_BL_COMMAND_TYPE, type) | KBD_BL_COMMAND_SET; err =3D exec_kblc(priv->adev->handle, value); } else { - err =3D exec_sals(priv->adev->handle, brightness ? SALS_KBD_BL_ON : SALS= _KBD_BL_OFF); + value =3D hw_brightness ? SALS_KBD_BL_ON : SALS_KBD_BL_OFF; + err =3D exec_sals(priv->adev->handle, value); } - if (err) return err; =20 - priv->kbd_bl.last_brightness =3D brightness; + atomic_set(&priv->kbd_bl.last_hw_brightness, hw_brightness); =20 return 0; } =20 +static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, int= brightness) +{ + if (brightness > priv->kbd_bl.led.max_brightness) + return -EINVAL; + + return ideapad_kbd_bl_hw_brightness_set(priv, brightness); +} + static int ideapad_kbd_bl_led_cdev_brightness_set(struct led_classdev *led= _cdev, enum led_brightness brightness) { @@ -1673,26 +1715,29 @@ static int ideapad_kbd_bl_led_cdev_brightness_set(s= truct led_classdev *led_cdev, =20 static void ideapad_kbd_bl_notify(struct ideapad_private *priv) { - int brightness; + int hw_brightness, brightness, last_hw_brightness; =20 if (!priv->kbd_bl.initialized) return; =20 - brightness =3D ideapad_kbd_bl_brightness_get(priv); - if (brightness < 0) + hw_brightness =3D ideapad_kbd_bl_hw_brightness_get(priv); + if (hw_brightness < 0) return; =20 - if (brightness =3D=3D priv->kbd_bl.last_brightness) - return; + brightness =3D ideapad_kbd_bl_brightness_parse(priv, hw_brightness); + if (brightness < 0) + return; /* Reject insane values early. */ =20 - priv->kbd_bl.last_brightness =3D brightness; + last_hw_brightness =3D atomic_xchg(&priv->kbd_bl.last_hw_brightness, hw_b= rightness); + if (hw_brightness =3D=3D last_hw_brightness) + return; =20 led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness); } =20 static int ideapad_kbd_bl_init(struct ideapad_private *priv) { - int brightness, err; + int hw_brightness, err; =20 if (!priv->features.kbd_bl) return -ENODEV; @@ -1700,21 +1745,30 @@ static int ideapad_kbd_bl_init(struct ideapad_priva= te *priv) if (WARN_ON(priv->kbd_bl.initialized)) return -EEXIST; =20 - if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) - priv->kbd_bl.led.max_brightness =3D 2; - else - priv->kbd_bl.led.max_brightness =3D 1; + hw_brightness =3D ideapad_kbd_bl_hw_brightness_get(priv); + if (hw_brightness < 0) + return hw_brightness; =20 - brightness =3D ideapad_kbd_bl_brightness_get(priv); - if (brightness < 0) - return brightness; + atomic_set(&priv->kbd_bl.last_hw_brightness, hw_brightness); =20 - priv->kbd_bl.last_brightness =3D brightness; priv->kbd_bl.led.name =3D "platform::" LED_FUNCTION_KB= D_BACKLIGHT; priv->kbd_bl.led.brightness_get =3D ideapad_kbd_bl_led_cdev_brig= htness_get; priv->kbd_bl.led.brightness_set_blocking =3D ideapad_kbd_bl_led_cdev_brig= htness_set; priv->kbd_bl.led.flags =3D LED_BRIGHT_HW_CHANGED | LED_= RETAIN_AT_SHUTDOWN; =20 + switch (priv->kbd_bl.type) { + case KBD_BL_TRISTATE_AUTO: + case KBD_BL_TRISTATE: + priv->kbd_bl.led.max_brightness =3D 2; + break; + case KBD_BL_STANDARD: + priv->kbd_bl.led.max_brightness =3D 1; + break; + default: + /* This has already been validated by ideapad_check_features(). */ + unreachable(); + } + err =3D led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.= led); if (err) return err; --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6660514A60F; Sat, 18 Jul 2026 17:12:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394761; cv=pass; b=NiDeW4dYQwSm14/3psb8GFc6XqKE328VkHWx8yZhl46ijeGG1rdr0ZKxAGLo+CCIt7g0xfTJYqTg5z5nuUzGpjSJUOOKOD8msdORF80w/2O0aBpIqNwTVvuPy07eQNF24CCk+LZBL8PxIfXXYjpPW/UzlISCoLRE3nPWklD5vME= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394761; c=relaxed/simple; bh=NMopLgYmeCiGKilNAjzcDm9iFIh3oX2+PU4htZxSk3o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=svPghsabRB8Az9v/FR5vQNmj9aY+EPLbdiUeDsHVmYL29flnjFXUfWljUJnZ1rDaC/H8KxwYLxhSbJJCX7ieYmRYHc0ir+E0GM/QwEWrORllH+1JbGNAvFFJw9VtHqJsFY6Aqkx8qKOOtkLsCjFwZ2BQ0Slo34qGVTDxO/kIU1A= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=hUi/UMh7; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="hUi/UMh7" ARC-Seal: i=1; a=rsa-sha256; t=1784394585; cv=none; d=zohomail.com; s=zohoarc; b=JPmb+rydMrHXk2F0MUTFz82FR4f3VbulMgBhxRpGGLixzIsTWfXf6D9iWQebvjKYhXlV6hCzH4z/gDKewvBo9f76jGDs6BLQ1hWXz0KX+u0VF9k1z2akVreTr2nn1GadI7b3jRxgysF5qSAko+HWYTU1pd9//TqwV2ZLkjFtqEQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394585; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=rqv6Wi8gxxkrU5PPJYihAPAEPRWqEV+y5UZDjaSo8+o=; b=Nw761KG9zeOzeVUzowk8TDv3lm8/qL/BM2H6hJg1oacveSsOtrCdMCXeYsMPzbhs7KLxHGB8QG7f/aFIMRSKxHN3hi4m8PyPuQ67fXubEJ22cqCRJWa70uctOW4zSvn5WxIswq5auFa2QEfNfLxX/WLdC+g+86oT0nutGMaz2Gs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394585; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=rqv6Wi8gxxkrU5PPJYihAPAEPRWqEV+y5UZDjaSo8+o=; b=hUi/UMh7UrSkk5NBLES0x+hIw471qS3LjLCq+03cuNGOgPRJZ5FXMJtd3H983mzl 8kD4/203JcwJDpnIL8t/MeQjig/NWn7lUhsGErN9FpmBNfztP8Rk1YDfqmA0CKGSxaE iYbqSFur0GXXv0kZOdqob49rOzCcAyhJQWCQJKJLf6G6lLMVqFHtdHLFiqRswIce0Wi 5XANoTOJK9gMTDLsW6X7sA0rHuwLlAooD1dd1+OFkZTjpMWXTT08PEW2ZsXlFVQQlfD WHYZDIMKzR6RNQg+P2efpQyvfEGkxagJAc70LkbKf4tzjkFZuIrZopzedkgNQ84Sbdz A8r8yLNegA== Received: by mx.zohomail.com with SMTPS id 1784394582729398.6970573466119; Sat, 18 Jul 2026 10:09:42 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:27 +0800 Subject: [PATCH RFC v3 10/11] platform/x86: ideapad-laptop: Serialize keyboard backlight notifications Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-10-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External ACPI notifications are delivered in dedicated work contexts and may arrive simultaneously. In the following change, much work will be done while handling the notification, which could lead to potential race conditions. Introduce a new mutex to serialize keyboard backlight notifications to prevent potential race conditions. Signed-off-by: Rong Zhang --- drivers/platform/x86/lenovo/ideapad-laptop.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platfor= m/x86/lenovo/ideapad-laptop.c index 5aa2fedb8472..66e16abda5e3 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -228,6 +230,8 @@ struct ideapad_private { int type; struct led_classdev led; atomic_t last_hw_brightness; + + struct mutex notif_mutex; /* protects notifications */ } kbd_bl; struct { bool initialized; @@ -1720,6 +1724,8 @@ static void ideapad_kbd_bl_notify(struct ideapad_priv= ate *priv) if (!priv->kbd_bl.initialized) return; =20 + guard(mutex)(&priv->kbd_bl.notif_mutex); + hw_brightness =3D ideapad_kbd_bl_hw_brightness_get(priv); if (hw_brightness < 0) return; @@ -1745,6 +1751,10 @@ static int ideapad_kbd_bl_init(struct ideapad_privat= e *priv) if (WARN_ON(priv->kbd_bl.initialized)) return -EEXIST; =20 + err =3D devm_mutex_init(&priv->platform_device->dev, &priv->kbd_bl.notif_= mutex); + if (err) + return err; + hw_brightness =3D ideapad_kbd_bl_hw_brightness_get(priv); if (hw_brightness < 0) return hw_brightness; --=20 2.53.0 From nobody Sat Jul 25 04:21:24 2026 Received: from sender4-op-o15.zoho.com (sender4-op-o15.zoho.com [136.143.188.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2249538E8A7; Sat, 18 Jul 2026 17:13:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394783; cv=pass; b=cSQFDxLJ5j0bCrc0sqITk30P+zkuqqHNCtCoXirCULL/pWr37FWyR7q+KIdwULtnwm667/1nRaoGuniaOc4x51GYsaPiENBn+oLK8L/cTRlvcdHldWZjLWQzjA7izfBUAr21coOdwngd1Y1yJzhx+S9/mSuIaQ3JIOWMpBAfeoU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784394783; c=relaxed/simple; bh=L3ZscbR5KQ2zc/YbN6Z4Hul70ZBtDLupdSivXD/i8f8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=N50oLwNAZjPELDVForTFNfmhMbhEnCT5Xj5N9TYLzDekEr5h8WLyjFsM4+5x1vkV5UCXXsT37hsHmBEL3zMubYFAgc4rJtXnFMS4wfXXG/GLMu5yZGpRYd/LuW9zZV3tuI/gDgHPETnV7gNKHgJyZUfFl4K197dhSMYtLp6pBKo= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe; spf=pass smtp.mailfrom=rong.moe; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b=F6xdsodw; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rong.moe Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rong.moe Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rong.moe header.i=i@rong.moe header.b="F6xdsodw" ARC-Seal: i=1; a=rsa-sha256; t=1784394593; cv=none; d=zohomail.com; s=zohoarc; b=fzdw87NncWfZ08DXwAGgS7RV+Obw+jWzOeMqcl6TZzUq8wq5Uc10QLAAAWNkf7hh6yop2l4hXgc/7HWoBH2VG2BbF8OnwAd5YFskJG83g0O86zCtFsVYpKEdZYHr5NPyLLvJyFfYG19xq2pEduTU0/8q9FnTXADA18Hyhizrp+8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784394593; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=b/M8GgLwAWPI3fUkEx8GGDQY1JOCadsXweVj1W2J9IA=; b=IO9SMHhLrmQ9N6dquP5eyxpuSL+SBEbHwYGQh2uJ/SR/6mFYQPiOpbTDKs+Lwgg0IDMl04IYL1Bj+wH2y2B5NyteugmAvKEerx32r42AY2kuyf62TgqzRj1jivqg4JVuMxFR1ti/eY/mgQHFoPZksJgQ8oDuXY29rMRgVVeMYTk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=rong.moe; spf=pass smtp.mailfrom=i@rong.moe; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1784394593; s=zmail2048; d=rong.moe; i=i@rong.moe; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=b/M8GgLwAWPI3fUkEx8GGDQY1JOCadsXweVj1W2J9IA=; b=F6xdsodwqTWdnrHcYMtwuAFaTfOjaPBgmFHwN2RQzyP0uN3oNFGRLjiQN9YQY70d /0i8zGh9qYQNHH1sJA6gIg17622APpA+gYuQ627dZ11eQ35lHjjwpuoUG/YCv03R6Ju WxALa/4qYbE8ku3P73My98lQYgFT1ZiyT88RTP3XkiW77pjutkkg+nE8OE8MDuR+G3Q jBTC1jnWpaTKnwuFPu1b9tEq47/7CAYNvwdU5iaAh3CsATqJ6mQb82ssXyfDa1BeJsP 2UMQzuk/pyHv7n2pYQY9jOEqMbvHiZ9561zT4LYxNqIDDAOX8gDl+yo3tBCau2tNeeS kJ9/23LFGA== Received: by mx.zohomail.com with SMTPS id 1784394589750195.17178609482085; Sat, 18 Jul 2026 10:09:49 -0700 (PDT) From: Rong Zhang Date: Sun, 19 Jul 2026 01:05:28 +0800 Subject: [PATCH RFC v3 11/11] platform/x86: ideapad-laptop: Fully support auto keyboard backlight Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260719-leds-trigger-hw-changed-v3-11-5fb55722e36e@rong.moe> References: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> In-Reply-To: <20260719-leds-trigger-hw-changed-v3-0-5fb55722e36e@rong.moe> To: Lee Jones , Pavel Machek , Jonathan Corbet , Shuah Khan , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck , =?utf-8?q?Marek_Beh=C3=BAn?= , Mark Pearson , "Derek J. Clark" , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Ike Panhc Cc: Andrew Lunn , Jakub Kicinski , Vishnu Sankar , Vishnu Sankar , linux-leds@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, platform-driver-x86@vger.kernel.org, Rong Zhang X-Mailer: b4 0.16-dev-4217c X-ZohoMailClient: External Currently, the auto brightness mode of keyboard backlight maps to brightness=3D0 in LED classdev. The only method to switch to such a mode is by pressing the manufacturer-defined shortcut (Fn+Space). However, 0 is a multiplexed brightness value; writing 0 simply results in the backlight being turned off. With brightness processing code decoupled from LED classdev, we can now fully support the auto brightness mode. In this mode, the keyboard backlight is controlled by the EC according to the ambient light sensor (ALS). To utilize this, a private hardware control trigger "ideapad-auto" is added, with the event handling procedure calling the led_trigger_notify_hw_control_changed() interface to activate/deactivate the private trigger according to the current LED trigger state. Meanwhile, block brightness changes on exit to prevent the side effect of LED device unregistration when the private trigger is active from resetting the brightness to zero, so that we can retain the state of auto mode among boots. Signed-off-by: Rong Zhang --- Changes in v3: - Address concerns from Sashiko - Fix a race condition in ideapad_kbd_bl_led_cdev_brightness_set() - Fix trigger re-registration of ideapad_kbd_bl_auto_trigger - https://sashiko.dev/#/patchset/20260618-leds-trigger-hw-changed-v2-0-c2= 8c44053cf3%40rong.moe - Make registration failures of ideapad_kbd_bl_auto_trigger non-fatal --- drivers/platform/x86/lenovo/ideapad-laptop.c | 112 +++++++++++++++++++++++= +--- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platfor= m/x86/lenovo/ideapad-laptop.c index 66e16abda5e3..253d2962b927 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -1714,9 +1714,58 @@ static int ideapad_kbd_bl_led_cdev_brightness_set(st= ruct led_classdev *led_cdev, { struct ideapad_private *priv =3D container_of(led_cdev, struct ideapad_pr= ivate, kbd_bl.led); =20 + /* + * When deinitializing: It must be the side effect of led_cdev + * unregistration when our private trigger is active. We've set + * LED_RETAIN_AT_SHUTDOWN to retain led_cdev brightness level. + * To do the same for auto mode, gate changes and return early. + */ + if (unlikely(!priv->kbd_bl.initialized)) + return 0; + return ideapad_kbd_bl_brightness_set(priv, brightness); } =20 +static bool ideapad_kbd_bl_auto_trigger_offloaded(struct led_classdev *led= _cdev) +{ + struct ideapad_private *priv =3D container_of(led_cdev, struct ideapad_pr= ivate, kbd_bl.led); + + return atomic_read(&priv->kbd_bl.last_hw_brightness) =3D=3D KBD_BL_AUTO_M= ODE_HW_BRIGHTNESS; +} + +static int ideapad_kbd_bl_auto_trigger_activate(struct led_classdev *led_c= dev) +{ + struct ideapad_private *priv =3D container_of(led_cdev, struct ideapad_pr= ivate, kbd_bl.led); + + return ideapad_kbd_bl_hw_brightness_set(priv, KBD_BL_AUTO_MODE_HW_BRIGHTN= ESS); +} + +static struct led_hw_trigger_type ideapad_kbd_bl_auto_trigger_type; + +static struct led_trigger ideapad_kbd_bl_auto_trigger =3D { + .name =3D "ideapad-auto", + .trigger_type =3D &ideapad_kbd_bl_auto_trigger_type, + .activate =3D ideapad_kbd_bl_auto_trigger_activate, + .offloaded =3D ideapad_kbd_bl_auto_trigger_offloaded, +}; + +static bool ideapad_kbd_bl_auto_trigger_registered; + +static void ideapad_kbd_bl_notify_hw_control(struct ideapad_private *priv, + int hw_brightness, int last_hw_brightness) +{ + bool hw_control, last_hw_control; + + if (priv->kbd_bl.type !=3D KBD_BL_TRISTATE_AUTO) + return; + + hw_control =3D hw_brightness =3D=3D KBD_BL_AUTO_MODE_HW_BRIGHTNESS; + last_hw_control =3D last_hw_brightness =3D=3D KBD_BL_AUTO_MODE_HW_BRIGHTN= ESS; + + if (hw_control !=3D last_hw_control) + led_trigger_notify_hw_control_changed(&priv->kbd_bl.led, hw_control); +} + static void ideapad_kbd_bl_notify(struct ideapad_private *priv) { int hw_brightness, brightness, last_hw_brightness; @@ -1738,6 +1787,8 @@ static void ideapad_kbd_bl_notify(struct ideapad_priv= ate *priv) if (hw_brightness =3D=3D last_hw_brightness) return; =20 + ideapad_kbd_bl_notify_hw_control(priv, hw_brightness, last_hw_brightness); + led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness); } =20 @@ -1768,6 +1819,24 @@ static int ideapad_kbd_bl_init(struct ideapad_privat= e *priv) =20 switch (priv->kbd_bl.type) { case KBD_BL_TRISTATE_AUTO: + priv->kbd_bl.led.max_brightness =3D 2; + + if (!ideapad_kbd_bl_auto_trigger_registered) { + dev_warn(&priv->platform_device->dev, + "Could not provide LED trigger %s for keyboard backlight\n", + ideapad_kbd_bl_auto_trigger.name); + break; + } + + priv->kbd_bl.led.flags |=3D LED_TRIG_HW_CHANGED; + priv->kbd_bl.led.hw_control_trigger =3D ideapad_kbd_bl_auto_trigger.name; + priv->kbd_bl.led.trigger_type =3D &ideapad_kbd_bl_auto_trigger_typ= e; + + /* Hardware remembers the last brightness level, including auto mode. */ + if (hw_brightness =3D=3D KBD_BL_AUTO_MODE_HW_BRIGHTNESS) + priv->kbd_bl.led.default_trigger =3D ideapad_kbd_bl_auto_trigger.name; + + break; case KBD_BL_TRISTATE: priv->kbd_bl.led.max_brightness =3D 2; break; @@ -1779,13 +1848,22 @@ static int ideapad_kbd_bl_init(struct ideapad_priva= te *priv) unreachable(); } =20 - err =3D led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.= led); - if (err) - return err; + /* Queue notifications, as kbd_bl.initialized is about to be set. */ + guard(mutex)(&priv->kbd_bl.notif_mutex); =20 + /* + * Setting kbd_bl.initialized after led_classdev_register() could lead + * to race conditions in ideapad_kbd_bl_led_cdev_brightness_set() where + * kbd_bl.initialized is checked, so set it now. It can be reverted back + * if the LED classdev failed to register. + */ priv->kbd_bl.initialized =3D true; =20 - return 0; + err =3D led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.= led); + if (err) + priv->kbd_bl.initialized =3D false; + + return err; } =20 static void ideapad_kbd_bl_exit(struct ideapad_private *priv) @@ -2612,17 +2690,30 @@ static int __init ideapad_laptop_init(void) { int err; =20 + err =3D led_trigger_register(&ideapad_kbd_bl_auto_trigger); + if (err) { + pr_warn("Failed to register LED trigger %s: %d\n", + ideapad_kbd_bl_auto_trigger.name, err); + } else { + ideapad_kbd_bl_auto_trigger_registered =3D true; + } + err =3D ideapad_wmi_driver_register(); if (err) - return err; + goto err_ledtrig; =20 err =3D platform_driver_register(&ideapad_acpi_driver); - if (err) { - ideapad_wmi_driver_unregister(); - return err; - } + if (err) + goto err_wmi; =20 return 0; + +err_wmi: + ideapad_wmi_driver_unregister(); +err_ledtrig: + if (ideapad_kbd_bl_auto_trigger_registered) + led_trigger_unregister(&ideapad_kbd_bl_auto_trigger); + return err; } module_init(ideapad_laptop_init) =20 @@ -2630,6 +2721,9 @@ static void __exit ideapad_laptop_exit(void) { ideapad_wmi_driver_unregister(); platform_driver_unregister(&ideapad_acpi_driver); + + if (ideapad_kbd_bl_auto_trigger_registered) + led_trigger_unregister(&ideapad_kbd_bl_auto_trigger); } module_exit(ideapad_laptop_exit) =20 --=20 2.53.0