From nobody Thu Sep 24 20:37:27 2026 Received: from sender6-op-o15.zoho.com (sender6-op-o15.zoho.com [165.173.180.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 1599347532E; Sun, 20 Sep 2026 19:41:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933311; cv=pass; b=Du7jCajVUVqiaS+zXZ7axfohXhYC0WoJ0G+sfPge/ReGY54376fcuSXms7bqUEeIiz4Lp9chzsV3MICIRGTMdsoTM95GiTxwlDIQdm2jXJK0uYFl9UCSWVks2uH1CYeCXSvni4sTdCr64QSYvM1hvXX/NuT3Y9fhUNDQokd6Bdc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933311; c=relaxed/simple; bh=0AXEy5KeefClAqrLkM2xK+utd+ujlnIlxIBgrEFv0Kk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZISXeRDzmAwO2Ynmor1mMJTyGADtDNfwOEYl8oWOz1mDkFoevqJ0EXYozqwpHwW6bGOzlYxTWTTumR/LzjRbNjedFNd+qBFUN2LIxD5t/d47p9c5cCR0plNT+rGvoI/ovZsTI5UPgVDJ+UEejUiSFfZxNJTxWLTBsa8mU9oV23M= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=ogPO+H+i; arc=pass smtp.client-ip=165.173.180.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="ogPO+H+i" ARC-Seal: i=1; a=rsa-sha256; t=1789933230; cv=none; d=zohomail.com; s=zohoarc; b=fKDzj1lXm6K3wxf0CdOCnulRT6o4FgP3Zx4i+M16NwZr4Bxj/jx1zsVhhV+9PPW/vhXk4pImBh5Le1gOHuXwM2wTbqJkOhT2wrrBueqs1ErOJHf0dEOmYYOaFMmcIQfDYYtIHXkEgS0Vl15JA6vBfFE+0HxH+e/fuF+VnHDerOM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933230; 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=4Mtz/AFM80jv4Dc2UsakzXZvBkH2sDnyNjioBHCW4Ms=; b=We96kL0BwlalPJpG69WonsxRioTU4PDliieyO0SzJoR82KvbwgbYQH/ymUOoILYQ1W5w6PHY60yjEBcC7grUQNFELBcY1E0eEBAZxUM12g603pa7ZxNb6aGP319/KSdcG4DZu4bxxTokzCeaWcRTIohuMoliAxUFZQoxCLHeHow= 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=1789933230; 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=4Mtz/AFM80jv4Dc2UsakzXZvBkH2sDnyNjioBHCW4Ms=; b=ogPO+H+imsDs7oJC/nnstQFbY8EE7fYU2ph7vMs2SjiU28B4v2xJE6KoPBpTP3IQ gts//yOR2w8QSq/k+XC4ee0MM5V4UZCbMUB91gafQ1U6RrTqMAC8NRugC7Chk9KZoh0 iu3GVdAPONDlxSfaHb1EEn/uVzw//23GWVtAsWhNTTd4d8Ex1cPHjUMDjy6I1G9zwVa ENwjzEnwwzs4agKfUkXNmRNdCbg2HpUlUbQUlFzxivMVP3IiZmQSBJV4N+eppQ6I6bD nMkW4+2Yu09LUdZpc6czGAiSn9iFVLhy8/koYBEicnM+BvHXGggT20DTacfLY/7e7L8 dmKIe4H1nQ== Received: by smtp.zohomail.com with SMTPS id 1789933228804856.8834715894247; Sun, 20 Sep 2026 12:40:28 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:15 +0800 Subject: [PATCH v7 01/13] leds: class: Always protect brightness_show() with led_access 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: <20260921-leds-trigger-hw-changed-v7-1-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 X-ZohoMailClient: External The led_classdev_register_ext() protects transient states when registering with the led_access mutex and relies on all sensitive sysfs attribute callbacks holding the mutex to prevent exposing transient states. The Fixes: commit broke this as it accessed trigger_lock without holding led_access. Fix it by protecting brightness_show() with led_access in all code paths. Fixes: b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware= controlled LED") Signed-off-by: Rong Zhang Acked-by: Ike Panhc --- Changes in v6: - New patch in the series to address a concern from Sashiko - https://sashiko.dev/#/patchset/20260821-leds-trigger-hw-changed-v5-0-3e= 00d6c4a936@rong.moe?part=3D7 --- drivers/leds/led-class.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index a51b0ed53886..4259533dafa1 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -43,13 +43,13 @@ static ssize_t brightness_show(struct device *dev, struct led_classdev *led_cdev =3D dev_get_drvdata(dev); unsigned int brightness; =20 - if (led_trigger_is_hw_controlled(led_cdev)) - return -ENODATA; + scoped_guard(mutex, &led_cdev->led_access) { + if (led_trigger_is_hw_controlled(led_cdev)) + return -ENODATA; =20 - mutex_lock(&led_cdev->led_access); - led_update_brightness(led_cdev); - brightness =3D led_cdev->brightness; - mutex_unlock(&led_cdev->led_access); + led_update_brightness(led_cdev); + brightness =3D led_cdev->brightness; + } =20 return sysfs_emit(buf, "%u\n", brightness); } --=20 2.55.0 From nobody Thu Sep 24 20:37:27 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 5F838471429; Sun, 20 Sep 2026 19:42:09 +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=1789933330; cv=pass; b=aRfrjOREwLsiSOwQjiymD0pVB9opBNIv62tCxps3Y/0xLIB5kPsQRdOlLiMilNpA6BnA87Q2n/u9DRVr/t5oSo7UCSbYkAHdVnGVaCcdkWI2i4IkPLhzR4JmPNfmEVTJAhMFBb9iwqLp/QL/i1PFtwA4mu8VOyf0YddSB01davo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933330; c=relaxed/simple; bh=7ZAsoBjFbWKnWetAs9AfEUvhkJPFN0slytnXiKl2zDQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZmIvBQXn4fr+agGGxMeE2Jrto120CzV2rvvQkFFoMptTqSRBDlSgxGe6fkT++bZkH6V8dI06DHjiu8Lmno66cvBpVUCITYMjIU1OfoFQbr4sn3lEDlKYu2KWsg8hELHXQGuSXUaywLZ2v4SR3GLX0Rh0+4XWmfvAXD2HZud0idw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=cVld20WT; arc=pass smtp.client-ip=136.143.188.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="cVld20WT" ARC-Seal: i=1; a=rsa-sha256; t=1789933234; cv=none; d=zohomail.com; s=zohoarc; b=VhchqprH2utNAXr5wc563jmV1dyZgHehuKqWlf8IyFh0cbfBVepxH5uVVOkcKTCv5S3USWUBOba0g3jS/mX91QgwxoUHLN8F9XNhAmM09McS1sZxA+Un9u1AJXrgeZaEtKnk5dU5c34IPyPVz3GgvGxJQw4dnDZpAaSMjQSKOwU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933234; 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=aOkhjiTA152ajScLyQAGXJjOlyLqpZinwlJKaTnX7k4=; b=CPAE4BNCEtuPsNDUCxj8EyXy7iU2SlRuoci+Ba/i7puWT3e0Visz+nJ7NnGyPv2B5vdKfWB21h5uHCxWsPueGqZERHwmfklLT4nq/mXMSsKRiFDqj3is6L4HAKNPCoAZLzO4fQ2Jhn7BbDOlcU8IYL2S0bh368AO7Lm1O2qRjTc= 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=1789933234; 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=aOkhjiTA152ajScLyQAGXJjOlyLqpZinwlJKaTnX7k4=; b=cVld20WTMUZrCd1o4tjEzrLb7tyfD0fPhizfaZVlqNQF0WJq4JalExFe54kHodRv SSeLN0knKGRE2vbDLbPmmzelwlQ23S8moeLxzUal2pUCakb/quJUTgpxX2kIfLa1a7m 9SsYcXHwHWz7B9QK7hmYBgSDITzquwtKhZQ6KCTXaSv0IwehW9O/TNQvvrtZGV+ooMl cCann9ROlznMS8JZTp6zm+YeIPlJwL/G1sx9QcDAs0kGQx4U5nOAJoLu4kuCs1J1SyL IwaPMDdN+3AhzuGT5CRh5eVKkCk11Qz/3cwrvKlyx9ZtPkO2yNhwa/zMBj99tT2NMaK 60HCi8hFXg== Received: by smtp.zohomail.com with SMTPS id 1789933233687728.8641843943246; Sun, 20 Sep 2026 12:40:33 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:16 +0800 Subject: [PATCH v7 02/13] leds: trigger: 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: <20260921-leds-trigger-hw-changed-v7-2-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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") Acked-by: Ike Panhc 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 4259533dafa1..7110bfbe3b83 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 a515f075c29a..46ad2e03e1c6 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.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender6-op-o15.zoho.com (sender6-op-o15.zoho.com [165.173.180.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 E2399471429; Sun, 20 Sep 2026 19:42:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933349; cv=pass; b=Vsdq8Ot5KL8BojDhmeobW7oV6Inf0UkciG2bDKfQNZZDdYOmhPLz3q7CzB4CfCqpv+Ac7lOWkAvCsyebEYmaZ3IXZuMqe96/nI1znYL40aDiShUuQpTH0rpsqiG06GPNQNrX3+XihAjmk1QDYNIZXy9F4TkEH++PtyrbPMWDXY8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933349; c=relaxed/simple; bh=tNPNvfDycyTQ1SDYUT1/BaFQrL99uV0tYcq7dx/xbIU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rh9IFUV033iyh4BB6ecOunORYz+Yvm+2CGqJOl4BdOOMTVTYeSTgf7QoCpBs68JLya5VOorc/LtjwWnQTB8eXyJ5KvRog+dmc5TAGI4Iqfx3QyfVT2ic/eYLHJBv+A8p2piw+eRtCNs4Q0khWktA6T3LoosFAEMX6MGX1DZKaD0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=BileC0Wm; arc=pass smtp.client-ip=165.173.180.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="BileC0Wm" ARC-Seal: i=1; a=rsa-sha256; t=1789933240; cv=none; d=zohomail.com; s=zohoarc; b=V7dDl/6LIO8HWZmS5PBQ53e+O6uO7sdbAImc1Eio94bRXD9EyiP8YWfERqHESNa8n15RKksMjqFAkg99e8ErJyIM+gvyotpxxZPAEr4bVQ6r5lmjoyS349wDAi9o6/DpAezSDfEteE9eMaQLMwcQIeYZOjyZMuFAB+Da/bqlZnA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933240; 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=FF0/cPdYXHNseaMCYnny9SPWkfmLb/uQebHuGGL5mm8=; b=YDPNrtQMSTihQSsjFm8za/o7Zt4aGwyCGvX8imctVhHn4jVwqld1Hv5xxIcyx5ErINhqbNDW4zzUg3YBgZ46c4boD7UOLAXwb5EgKM79b3b3Gwo8GVTbbiGCQO6kOzP6JZ+CK85YuWA/4V3HkrasYTLA6WP+USBYyxUMThqEbqI= 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=1789933240; 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=FF0/cPdYXHNseaMCYnny9SPWkfmLb/uQebHuGGL5mm8=; b=BileC0WmO3GUdoc2NzAkEgEHl2FcPYgur2g963zSzjI/gTVwWqdBb5EjOlcxenvi dqEPaIVCpOv5L998kUXyhOHJs/RE0wyd3wxCnRd0V9Xv0wOw/biejxDoEnMuaAT2iDq Hav681kHBAVVhID0fzQppXKkXvVbrVXQZiGqsRgfEq0Hw0A8AOWyl654rhZEEbqvAu1 A2382JhEBewzwqBrJJqtp6DCg8xMMOzPl0IAoomvH3KJBdwTtOs8nCAcHqDeEt0VrpJ HV6ZnSKwVtuSs3VfM7b9CuxcqxoPwaBGMlZj/EoOjn4KqAtKBU/RJ4B0BLczJXwYLn2 IYlVMYGnOA== Received: by smtp.zohomail.com with SMTPS id 1789933238614443.83326529004876; Sun, 20 Sep 2026 12:40:38 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:17 +0800 Subject: [PATCH v7 03/13] 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: <20260921-leds-trigger-hw-changed-v7-3-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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") Acked-by: Ike Panhc 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 --- Documentation/ABI/testing/sysfs-class-led | 4 +++- drivers/leds/led-class.c | 3 +++ drivers/leds/led-triggers.c | 9 +++++++++ include/linux/leds.h | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/= testing/sysfs-class-led index d4c918cc11a1..f6d4e17e1a3b 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -28,7 +28,9 @@ Description: Writing 0 to this file clears active trigger. =20 Writing non-zero to this file while trigger is active changes the - top brightness trigger is going to use. + top brightness trigger is going to use, unless the current + trigger is offloaded to hardware (in which case writing any + value will deactivate the trigger). =20 =20 =20 diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 7110bfbe3b83..39cc2f3ea63f 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 46ad2e03e1c6..d778709f5b1b 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.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender6-op-o15.zoho.com (sender6-op-o15.zoho.com [165.173.180.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 8BF2447ACF3; Sun, 20 Sep 2026 19:42:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933370; cv=pass; b=MLx53eLeV3qkejeHbKa10gz+qxMCkvuk7T0cBXPbeLB0FLOiiypaqX4fcDB3iIjA4zGl9tjT4MtsGsu+m4tJB/HLLSlAATR2blCz7xpPOr3qfNjbJaIckTfPA1ot9416kmFzx9us4Emn4JeTfjdj5eiozT6Yg9b3Ypety/J3C4s= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933370; c=relaxed/simple; bh=6PM1FrhmNIGZlw6oZpV2rF34bsqDRbem3JOmrVKjo5I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kXiv7yW8FloSAU4+zsCkFRnUxXEgVM1HxLiZvxPGsVUNrAd390aYhjwwSPzaePSYB/khv8y4Pw6HVH7ag9qMNNqZdMhRdI2jz/B13HhObEbTuy5iLEUm1uIWLkIfjB45ZoDQjVuGyt2A8FvLHQqYxUNTTa7ADaYinE5gQLTb5D0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=prNxBefM; arc=pass smtp.client-ip=165.173.180.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="prNxBefM" ARC-Seal: i=1; a=rsa-sha256; t=1789933244; cv=none; d=zohomail.com; s=zohoarc; b=Oh/MIGlf/mcc3cYeR8DeGA1RU8WfpyvYbNfR5DpCaNprei7pOuVpL3AL/mRE+yP4wpzR7ldhMNkj9mHE/pquMAzyaxXjZguUvq/as31H+V6y+XyKWNfqKOie/98qEe11wwygzaV0LamQhAkyh1Zt10OT+O5ybaFs2V5vI5xQhMw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933244; 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=MH/GLTkY4E1a90PAm9Tg7XoGhfvi0m4G9L3vItnyqn4=; b=PiU3yHIvxoCM2ODvVmjfqYm3JkdGqetvRmCmXUBWw8BSwKkdgJ0zWNNOpY58erHfHQmo6g5IbOUMMKQNIVF7Z3CMMwHpuk90NChvGsa38TpHr9w94G9e7c0Ek9W80EJZDVMxd+Ji4KjMacUOyllEZZ/U2Dsi9MaXXJinvfzBkeU= 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=1789933244; 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=MH/GLTkY4E1a90PAm9Tg7XoGhfvi0m4G9L3vItnyqn4=; b=prNxBefMZMRW66knmcwc2e+cHhIspMykwQ/49yLbbkis/AY3b6LNIyBw4P+iEVW4 8kz3VO5WuuZP/+N8CoA5sgpRNaTqZPt3BJgAJYq9jdfLHnr4Vp4Z1b5T40VjAXKu9NU gs0ZRNAKQgYy1muQFeNETPPvdbU6dU5vKNWgVyz7ZYJoUgJ/pp6q1M8+9nlWl/3OMOA c8phbaFsejB2ZtM90NI51UcEDNFUzjzNNgcYxtp7zlxMOMxMqkjsmMGOedCIWijuiKg uQIShLcYHxyFnvTZidzKAuQGZq+SMWvRxHzam9yA5Fg+tLJsdLxM2o3OFi6DWgrbXea ccDcmZZaSA== Received: by smtp.zohomail.com with SMTPS id 1789933243566611.1316157652694; Sun, 20 Sep 2026 12:40:43 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:18 +0800 Subject: [PATCH v7 04/13] leds: trigger: Move led_trigger_group 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: <20260921-leds-trigger-hw-changed-v7-4-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 X-ZohoMailClient: External Currently led_trigger_group and its members are placed at led-class.c, but they falls into the triggers namespace and does triggers stuff. Placing them at led-class.c also requires the read and write callback to be exported and results in an extra #ifdef block. Move it into led-triggers.c, so that it becomes the only symbol to be exported for sysfs attributes. Signed-off-by: Rong Zhang Acked-by: Ike Panhc --- Changes in v7: - Add a new patch to the series to collect trigger attribute stuff together into led-triggers.c (thanks Lee Jones) --- drivers/leds/led-class.c | 11 ----------- drivers/leds/led-triggers.c | 25 +++++++++++++++++-------- drivers/leds/leds.h | 7 +------ 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 39cc2f3ea63f..7f51715fac69 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -90,17 +90,6 @@ static ssize_t max_brightness_show(struct device *dev, } static DEVICE_ATTR_RO(max_brightness); =20 -#ifdef CONFIG_LEDS_TRIGGERS -static const BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, = 0); -static const struct bin_attribute *const led_trigger_bin_attrs[] =3D { - &bin_attr_trigger, - NULL, -}; -static const struct attribute_group led_trigger_group =3D { - .bin_attrs =3D led_trigger_bin_attrs, -}; -#endif - static struct attribute *led_class_attrs[] =3D { &dev_attr_brightness.attr, &dev_attr_max_brightness.attr, diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 804a04b326c4..de6056bc80e6 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -52,9 +52,9 @@ bool led_trigger_is_hw_controlled(struct led_classdev *le= d_cdev) } EXPORT_SYMBOL_GPL(led_trigger_is_hw_controlled); =20 -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) +static ssize_t trigger_write(struct file *filp, struct kobject *kobj, + const struct bin_attribute *bin_attr, char *buf, + loff_t pos, size_t count) { struct device *dev =3D kobj_to_dev(kobj); struct led_classdev *led_cdev =3D dev_get_drvdata(dev); @@ -97,7 +97,6 @@ ssize_t led_trigger_write(struct file *filp, struct kobje= ct *kobj, mutex_unlock(&led_cdev->led_access); return ret; } -EXPORT_SYMBOL_GPL(led_trigger_write); =20 __printf(3, 4) static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, = ...) @@ -149,9 +148,9 @@ static int led_trigger_format(char *buf, size_t size, * attribute, which is not limited by length. This is _not_ good design, d= o not * copy it. */ -ssize_t led_trigger_read(struct file *filp, struct kobject *kobj, - const struct bin_attribute *attr, char *buf, - loff_t pos, size_t count) +static ssize_t trigger_read(struct file *filp, struct kobject *kobj, + const struct bin_attribute *attr, char *buf, + loff_t pos, size_t count) { struct device *dev =3D kobj_to_dev(kobj); struct led_classdev *led_cdev =3D dev_get_drvdata(dev); @@ -179,7 +178,17 @@ ssize_t led_trigger_read(struct file *filp, struct kob= ject *kobj, =20 return len; } -EXPORT_SYMBOL_GPL(led_trigger_read); +static const BIN_ATTR_RW(trigger, 0); + +static const struct bin_attribute *const led_trigger_bin_attrs[] =3D { + &bin_attr_trigger, + NULL +}; + +const struct attribute_group led_trigger_group =3D { + .bin_attrs =3D led_trigger_bin_attrs, +}; +EXPORT_SYMBOL_GPL(led_trigger_group); =20 /* Caller must ensure led_cdev->trigger_lock held */ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *tri= g) diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h index bee46651e068..c1db21e943b0 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -21,14 +21,9 @@ void led_init_core(struct led_classdev *led_cdev); void led_stop_software_blink(struct led_classdev *led_cdev); void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int v= alue); void led_set_brightness_nosleep(struct led_classdev *led_cdev, unsigned in= t value); -ssize_t led_trigger_read(struct file *filp, struct kobject *kobj, - const struct bin_attribute *attr, char *buf, - loff_t pos, size_t count); -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); =20 extern struct rw_semaphore leds_list_lock; extern struct list_head leds_list; +extern const struct attribute_group led_trigger_group; =20 #endif /* __LEDS_H_INCLUDED */ --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender6-op-o15.zoho.com (sender6-op-o15.zoho.com [165.173.180.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 8AB1E476047; Sun, 20 Sep 2026 19:43:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933389; cv=pass; b=QI6NBmXA3t3a+lmZuHJ4jOp1zULUsWQYMMmNgjd04C3L9BxIq8idv2fhxCoCxCEeFUPCcGeICVZtXXzNIpOmxlHqatDbGkQ0vBloHLNGtjRAZtcZxms0wrpiLB83VumbY6dgdBiJL/YiGHL3ZDGaZGYYx/tQiI211oU9tRSqj14= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933389; c=relaxed/simple; bh=+dRiW1c+u+UBr2MFC6p/vQS3YD2zD9vCjyjBoX1E984=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UY0dgjARnKH57+c/wdmMc7kQg+znqo0omjjPn0ntuPpDFbhW5QF32DLBJED1isNcBnMN9hFhcS54CnSiXK5SJ9Th5HAyFTSHHW5wkGh0ZSPbgXbKE2yqu9tPxcTdoAeOR+VPL2m879F0q1qrMLAcPeZom11lEoI28y34RCgbW+0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=FEViFf+2; arc=pass smtp.client-ip=165.173.180.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="FEViFf+2" ARC-Seal: i=1; a=rsa-sha256; t=1789933248; cv=none; d=zohomail.com; s=zohoarc; b=Ze8wFl0N8nvhmXdAcLN250FVsi6nOM4Q8mUtMY78nl5/pn0KZHLBnO+PfTNGgixUXVLD+PBJQTAI1j7SReWBif302Sd89PQAgAYh28K1o4ekqJhoqFDcgGd2O+zo4x8mQbz2U7WtoUGhzMZtMsThzUayMVYxiWUC7muqxMkCQeQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933248; 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=/OJWNPRt7C6E6XKPHIegE5RkOkall67Zr88plpfiiMs=; b=DZudoQppmO9mLYgKEiZX7WPfS/F5djljqIQ4rk463OFtvO69gPzK+bgyJuDi5DbQdMFN3F7FOp+EZlGluj4+BYxYohoqKqtBhLd5g240fDW70hph58IAvUcEGKTftxZCP90NIjfcc1oeRGt7fJxxiQm+hopQoTWhDSpj3bHt9cc= 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=1789933248; 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=/OJWNPRt7C6E6XKPHIegE5RkOkall67Zr88plpfiiMs=; b=FEViFf+2Q6IBefoZ5yw9YP7GCSe5lDryoChPhWqJxkg0Dkyo98MIFRoV47IUPzuH RpY1TTC6lXE2/DPisAeuUgCbMPMkIDqWEvbRgbswaf1RKbEppk4N66x2RXP46PpjlO1 fG1HS+QF/wmKLAPcaak1btilNxGrZTaSuZXV7zgr4e5w8RJ2bIB48QB9DHVtRkeqAMZ Kb8LASShn4Uk4Ba/fQCDugPiX+C60jwdonIw15Xe0AJrr9R6+/rL9P2792l6hBGeGtN +g7W7+gsilBbZk9NVuc+rgXqfhveUFNeLjiU1GPyqQPEGRiPs2k9kGAzL8W9HfaFfoR FNgb7SOHpw== Received: by smtp.zohomail.com with SMTPS id 1789933248499390.50035480257634; Sun, 20 Sep 2026 12:40:48 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:19 +0800 Subject: [PATCH v7 05/13] leds: trigger: Add hw_offloaded() callback and provide trigger_may_offload_to_hw 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: <20260921-leds-trigger-hw-changed-v7-5-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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 hw_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_to_hw", 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 and offloaded to hardware ("[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. IOW, userspace should parse the new attribute in the same way as /sys/class/leds//trigger. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Leave all attribute stuff at led-triggers.c (thanks Lee Jones) - Rename the offloaded() callback to hw_offloaded() (ditto) - Rename the trigger_may_offload attribute to trigger_may_offload_to_hw (ditto) - Use "[foo_trigger]" to represent a selected and offloaded trigger, and no longer use a dedicated container to represent selected but not offloaded ones (ditto) - In this commit, the trigger_may_offload_to_hw_show() callback does not match the current trigger's name against hw_control_trigger yet. The check will be added in a later commit once all relevant LED drivers have properly declared hw_control_trigger and LED triggers have implemented hw_offloaded() - For now, only "netdev" and "chromeos-auto" have associated LED drivers, which expose the new attribute. The former is always reproted as not offloaded in this commit, while a later commit will implement hw_offloaded() to properly provide the offloaded state. The latter's associated driver's only private trigger is exactly "chromeos-auto", which is always correctly reported as offloaded in this commit - All private triggers will gain hw_offloaded() and their associated LED drivers will gain hw_control_trigger in later commits, so that they can provide the attribute properly - Constify device attribute trigger_may_offload_to_hw Changes in v6: - Update Date: and KernelVersion: for the document of /sys/class/leds//trigger_may_offload 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 | 21 ++++++++++++++++++ Documentation/leds/leds-class.rst | 20 +++++++++++++++++ drivers/leds/led-triggers.c | 36 +++++++++++++++++++++++++++= ++++ include/linux/leds.h | 1 + 4 files changed, 78 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/= testing/sysfs-class-led index f6d4e17e1a3b..123e3a15b7d6 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -80,6 +80,27 @@ Description: (which would often be configured in the device tree for the hardware). =20 +What: /sys/class/leds//trigger_may_offload_to_hw +Date: September 2026 +KernelVersion: 7.4 +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, or selected but + falls back to software blink for some reasons, 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..ea478989aae2 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_to_hw` 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: + - hw_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-triggers.c b/drivers/leds/led-triggers.c index de6056bc80e6..38ce3350c870 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -42,6 +42,10 @@ static bool __led_trigger_is_hw_controlled(struct led_cl= assdev *led_cdev) if (!led_cdev->trigger) return false; =20 + if (led_cdev->trigger->hw_offloaded) + return led_cdev->trigger->hw_offloaded(led_cdev); + + /* Otherwise assume private triggers are always offloaded. */ return led_cdev->trigger->trigger_type; } =20 @@ -185,8 +189,40 @@ static const struct bin_attribute *const led_trigger_b= in_attrs[] =3D { NULL }; =20 +static ssize_t trigger_may_offload_to_hw_show(struct device *dev, + const struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev =3D dev_get_drvdata(dev); + bool offloaded =3D led_trigger_is_hw_controlled(led_cdev); + + return sysfs_emit(buf, "%s%s%s\n", + offloaded ? "[" : "", + led_cdev->hw_control_trigger, + offloaded ? "]" : ""); +} +static const DEVICE_ATTR_RO(trigger_may_offload_to_hw); + +static const struct attribute *const led_trigger_attrs[] =3D { + &dev_attr_trigger_may_offload_to_hw.attr, + NULL +}; + +static umode_t led_trigger_is_visible(struct kobject *kobj, + const 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_to_hw.attr) + return led_cdev->hw_control_trigger ? attr->mode : 0; + + return attr->mode; +} + const struct attribute_group led_trigger_group =3D { .bin_attrs =3D led_trigger_bin_attrs, + .attrs_const =3D led_trigger_attrs, + .is_visible_const =3D led_trigger_is_visible, }; EXPORT_SYMBOL_GPL(led_trigger_group); =20 diff --git a/include/linux/leds.h b/include/linux/leds.h index d778709f5b1b..9a0bfd985b46 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 (*hw_offloaded)(struct led_classdev *led_cdev); =20 /* Brightness set by led_trigger_event */ enum led_brightness brightness; --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender5-op-o15.zoho.com (sender5-op-o15.zoho.com [165.173.182.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 554FB472F76; Sun, 20 Sep 2026 19:43:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.182.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933409; cv=pass; b=d0fypGqdWtroPVF/Tj55FA9EdD5Vs6dIGCt/Er2KA5THU3DG9Xx69AuXId1uKFmLYKjhX+703/ZMNkJt8745ru4zpeaQ8ncFt04Sb03/b4iLEd5Ba2IQH8mrciWNlcxdDY4JzTPr6hbSs3HAWrKee1lc1eYlXEYNcAA2P0/hqAY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933409; c=relaxed/simple; bh=+MnPZ6eTfH7cB4uYmJZeytj4RVmJh07mpPdY3pCeH9s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=p+9hUXX875viOUixSv4ZdEwkCANX2ZraA0GYn+kXCUuDkrtUMGCsPpr7Dgh/zsyG9zSdZf3Yr43BdKw+fyLHy8dBkWb+G1SCA2A2h31lMsEVkV+0hDhJTuJ6bBIqUK9yfTR1ehKVN3pYFZBJGA+XdwN3hn3SgEOFA7e1iRPZPtU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=GtCGa5oJ; arc=pass smtp.client-ip=165.173.182.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="GtCGa5oJ" ARC-Seal: i=1; a=rsa-sha256; t=1789933254; cv=none; d=zohomail.com; s=zohoarc; b=gyqy9eiW+fEZA0CzF1GdQbSXXHlmhRSrPx6RdBI38ypkSju7yDiWnOBpzc2WYhPNEz18+hRVNRCcguDOTYDME3vSNJxNzCZ9Ox75GSI2tMbWO5ZKKYGC8OfJfrNfx2nE4BkNfwNbTuLsTzsqCtvX/+k97f1pQ4/oLUWbAxvd54k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933254; 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=0qZIsMmvYd8h/PC17ld1PmriS5Rph3OJl9Ig1y/Rtv8=; b=m4efM7RD61fNHVP4blM6cxWJKcQXAm6Gxwrx99Obl4lSWUrWvPJdKhmCfQt9uDhXGslqLAPyhxsrHmRh0MSwyeLfM5Hw36im9nviXArkIsYcrvRs6IrqRs6yERnZD4KDkWudyA8Mmsula09Z5p/KdZjP/h+p3zvkNQgeY/QIIfg= 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=1789933254; 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=0qZIsMmvYd8h/PC17ld1PmriS5Rph3OJl9Ig1y/Rtv8=; b=GtCGa5oJS+CN+Njt9crtEG4fQGVsa/eZCPw6z+CiT6bkipxPihI5QFPoREP9gpBq uZWYuBe5CRV1g/mKYx0LZTbsSekNw3xjrT3jGki9thjy16ga1viDJuwHjeAlFvcl/AM y3gqhFuor8DbI2f8+v/WFMKgoWcai/gGIy5+fStPtv/jw8aDkaCcjRqBjQi8A2EYKfE +57XeAnflOMG8PFKdOWeYj902hCDJT20SiGZDuo/96n3OBgoFyvZ3d7qVxbm/y6CQRx kYn6fVLtcAYELJyiQdmPDpKrYd5sMjwZVOIKiPi5engrM8j3qD063FmaVwWqyLemSQX mjHEmHFTwA== Received: by smtp.zohomail.com with SMTPS id 1789933253374126.41935058215722; Sun, 20 Sep 2026 12:40:53 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:20 +0800 Subject: [PATCH v7 06/13] leds: cros_ec: Implement hw_offloaded() trigger 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: <20260921-leds-trigger-hw-changed-v7-6-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 X-ZohoMailClient: External "chromeos-auto" is a private hardware control trigger which always stays in hardware control. Implement hw_offloaded() callback with its return value to be always true to reflect this. Reviewed-by: Thomas Wei=C3=9Fschuh Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Rename the offloaded() callback to hw_offloaded() (thanks Lee Jones) --- 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..0e93aa28a8b1 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_hw_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, + .hw_offloaded =3D cros_ec_led_trigger_hw_offloaded, }; =20 static int cros_ec_led_brightness_set_blocking(struct led_classdev *led_cd= ev, --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender5-op-o15.zoho.com (sender5-op-o15.zoho.com [165.173.182.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 A01694718FC; Sun, 20 Sep 2026 19:43:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.182.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933427; cv=pass; b=i2qTTguBsWl804Hw06kslpDgQEsMEpG1jAHXARH5wxp1wyIfQbf77Y2cxh6pSqpRCrLzqnECAQUT7yCsNbnpNiXJOMXN84PL5zSpPXe/qY7tTI2J5AKu5+wjV4rKqtVqPyXoPNqnQlJLKx5KRvJW2U54ojd/0A5TrTpYK5T5LGc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933427; c=relaxed/simple; bh=8whFkDT3q2FBkk4KXznACO6L9PWdgSvBZxlEza4pSeA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pOtUmGnBIRSy+a/nFp0eHgjG8SS+6opgV9jdoletaT+iOIkLyzffqpq0MPQrUay5zUTT1lBJG/kMjt+JsZiQCdqBwhe+JFMSWEZQ4AMfezKce7PJcHtp4pswEK0Ukqj8XPmiNYCp6OU3YWIv7AkLWgn3Cfm6AQiyZDBC9rU86NI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=EeAg+Ixy; arc=pass smtp.client-ip=165.173.182.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="EeAg+Ixy" ARC-Seal: i=1; a=rsa-sha256; t=1789933258; cv=none; d=zohomail.com; s=zohoarc; b=l9noJ/QGs8nPo2nfYWeJXAY5pSyWKXEPSrmBHh02z9ACFiwrlsBG8v26o98aWP98KZHhDYEEzS+LqqjJguEi9MC/dxkygfpno9GrP/JThAVCCDKPAD5cPY2zTS+xxp5PW/HsJ6gcOgSD8y/vOHGZwDVjKtKbZcjTbO8Iomy1IAc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933258; 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=WYe+gEZ9YtZFO0g7tdDS+u0u2ekHnDyCAIRMeQPpZow=; b=J/CWunS+fUh9Yn5+QGrD+jaflyM4RG3+3uR82AXf6Bp1Jx1KRDNwEDEC7xrdMuuCkXfTil+xNrgygjRcAaD43x6OVCoFlllcwDXPp2yhhi+HCUwKySXym/jPbL8C7l735rT5Gx7SsTjTlZJES7CArC3Ag3thUDtiHWrdrzQKhAY= 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=1789933258; 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=WYe+gEZ9YtZFO0g7tdDS+u0u2ekHnDyCAIRMeQPpZow=; b=EeAg+IxyqICM+4WfaRZZq4EJJ8ky63+dM2tZ5pHG7ABmBOUCbXQ29GyR0B9yLVtF HtHkv3k51H5hqPznKoV3bdh+jbJGIyChc4A1ygkn/g3AMiNO2xGW/l0wTT+dK2/I3BA TyTiGAUmikUmff+KRm7Jqx/PBNI9XdnuBv7WNvBS1Isi5FD7o0PgsYsRTUpGlyJm31b cBPbI28WxXV+n/nJOm/KSUwKidSjvmX3QzwC2ZX/aX0DRSEY3Adm1MvMk3YM3+UmFqU g7NR0+eYVggW9h3vTSgJzyxH4DVT9x/EOyl2A0uzjBygTDMjE+mR/UbehVcCTvWkdab S19OoIR/gA== Received: by smtp.zohomail.com with SMTPS id 1789933258322869.2728040975137; Sun, 20 Sep 2026 12:40:58 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:21 +0800 Subject: [PATCH v7 07/13] leds: turris-omnia: Implement hw_offloaded() trigger callback 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: <20260921-leds-trigger-hw-changed-v7-7-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 X-ZohoMailClient: External "omnia-mcu" is a private hardware control trigger which always stays in hardware control mode. Implement hw_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. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Rename the offloaded() callback to hw_offloaded() (thanks Lee Jones) --- 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..57128ae7e8fd 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_hw_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, + .hw_offloaded =3D omnia_hwtrig_hw_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.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender6-op-o15.zoho.com (sender6-op-o15.zoho.com [165.173.180.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 3BC6C29B228; Sun, 20 Sep 2026 19:44:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933447; cv=pass; b=mR/HYdwX5pl4+L1RistUWhBLvAormuT4yOLVPz6fduZgYnmHW6/iIUWtwDBRAnoIBHrIXYnBB1KeKcmwcuT5rGxOmkVFpgYgGRXwLlxBEs9oOJ0HbWwruO+/qYCXXahpzHpYC1sIDlFo8qCW6RMI7n4JRR3opuTik7NerJ09zSE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933447; c=relaxed/simple; bh=TZibX3aCUK0ohSyPFEFa1zR7eA71hHYC6eJpYxJZ5RU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=a15ffdNl2p+mY1nbThqnaRIHVl6d05dPrpy1FtqkgmA9LfC7xAIf6toZep9Uek4Lh6bY8bH548yxsmoBCQ+yyqdvy4k7JBIGW/hXu5fwPOCidGEo8tw2843vlByD/KDbgmi6arpSK2bG979k3Nl5BLNvVPEJlmV8Gg/C1QjxrMk= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=IPrDTL06; arc=pass smtp.client-ip=165.173.180.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="IPrDTL06" ARC-Seal: i=1; a=rsa-sha256; t=1789933264; cv=none; d=zohomail.com; s=zohoarc; b=myOuS++VeUXr4fHagZI0w+BcuVrPl1GG/clB7EZAjf7OtPaN6S9n3oCfFDSmifoFbZxe9ZlF0/JhWjfVkS/DyisyJPZ5fR9JvYW37aYhUv/uzIHNjpGzz2WICAAFqfc62TgbXVMjqbp8VKChj5uX79xrULsPyCfRfTnZmfEL9oo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933264; 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=RXm78mSTGjQvWV8MVp20FX0JztZDQljla/8XmUE7cbs=; b=J7QiZ7+JvP+9oSrehpv2/6VfWM8Rf4wHlPk2wPvEMSmmznyHa3MYG3GHBYMChr/QHGUw6H3E4IERA3P0OiZNoOe2AkYJuWuEAgcwffcoyWX2Q5Lw4T/oLiePUnXi6U7J+WAFT0X62CpMrbJggzPj0HQ/XHJ92KhFGXUJWKX7zMs= 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=1789933264; 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=RXm78mSTGjQvWV8MVp20FX0JztZDQljla/8XmUE7cbs=; b=IPrDTL06cQYp0l/x2WVn7sKZJnNapG2iut4UXj+WKnxh18nH7L+RVE5RzMxV7lJC 8gyrAXfkF4IrXSKbXrS4O2dS6UvOv+6pKBw1ONZ2kq6dzN1IM9iLFWsv1hW6PGgKAs4 ikPPCA8OYy4hJVVs1iSUf/dAfBrEXCOmCFABhn/CriVEzJtm/qxYhLjZByR0Y8W/8O5 d2SkJXwKiLTYE72wB5VHJCHzw9T9cgoyiMkguKkAmDSZHF8K8Yv5kwHfNsy7FPzWqbe /G2KLEqHafNpAQ3eOVFFqtTM0bxCnn44jEcJOOPRnTmaYPzM9/dE/ymRbHoVMvm9RAm yZ0cVRgdmA== Received: by smtp.zohomail.com with SMTPS id 1789933263241514.6431318792389; Sun, 20 Sep 2026 12:41:03 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:22 +0800 Subject: [PATCH v7 08/13] leds: trigger: netdev: Implement hw_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: <20260921-leds-trigger-hw-changed-v7-8-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 X-ZohoMailClient: External "netdev" can run in hardware control according to hardware capabilities and trigger options. Implement hw_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_to_hw" attribute. The callback mimics how the existing "offloaded" attribute does, i.e., locklessly reads hw_control, as it's just a hint and don't need to be accurate. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Rename the offloaded() callback to hw_offloaded() (thanks Lee Jones) - Rename the trigger_may_offload attribute to trigger_may_offload_to_hw (ditto) 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 123e3a15b7d6..ea113fed10ef 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -101,6 +101,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..203ea58396ed 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_to_hw`. + 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 5b4e92c14dbb..60409f054e22 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -798,10 +798,18 @@ static void netdev_trig_deactivate(struct led_classde= v *led_cdev) kfree(trigger_data); } =20 +static bool netdev_trig_hw_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, + .hw_offloaded =3D netdev_trig_hw_offloaded, .groups =3D netdev_trig_groups, }; =20 --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender5-op-o15.zoho.com (sender5-op-o15.zoho.com [165.173.182.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 368C4476681; Sun, 20 Sep 2026 19:44:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.182.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933465; cv=pass; b=iLpBrJfTeW5knHPrWNriMOVOArk+CgrA5Gap+f5wrjUC1MLJd2NyqwAVH7LOK1fdLQ5zB9iDvn1wXMwa82HLxzgp6c8zpirGtrAhz5QMwvofs4QeeTEe2RamjMcs+afcLPQ8D616TB+RNEehACTyU8vB2YPe0sSRqon+XA+Quns= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933465; c=relaxed/simple; bh=yG3cWWzjIZAXZagai4B1TYafER2rr+mUiH5N9vTwpQ0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EcrT4Ywq3t0HlMenlKz+Oe8dtkbwC9iVxs2exC43Y0I/OLtgKBEIUp7y7m3EIuRsFXOUNE9TQIOQfcgXJ9dFvcPuS4a/AYF6erl5iThtb/QjeBAPnwFFKBDmM3BNFzJiQssfsym5B3tVIZkqlOyyH3YWIUDyh++CWn8lIbm31ys= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=PcWPA1GY; arc=pass smtp.client-ip=165.173.182.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="PcWPA1GY" ARC-Seal: i=1; a=rsa-sha256; t=1789933268; cv=none; d=zohomail.com; s=zohoarc; b=jmM9xGqrGAl4kEkAD8jf+4E5GuVUmZy5ueV5gwatOW7yhFApsiL+WAS0pnXGjejs8NumpCWCFNfxCkq/InZ94DkCwGex9N0Y5N8trWPv25iig5gYHt2QizUFItQNZOWyTPauYgKLIYe0JBM/9kGBRZK/Z07NZJGKb5GbYUllCWI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933268; 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=2FcYYdrcjAE0hgS3YmVlv+tJ1/G1wYcCRwkRcENotIo=; b=CESUU3sgKDFo/3GoG9aisHpALdvGGHOiseeXxtVPRY8+GmXpztCph2p6gqKK/E1G6E5CulBuuFcc/ZBEAXmUmZLGRWkPmA26vKptzkFtzP4BsMAJZwpiNRxrA5QtWnF8sNHGuv3e8ajiw1QQFu/D4QAyB5k1KhacUVAqByku20A= 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=1789933268; 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=2FcYYdrcjAE0hgS3YmVlv+tJ1/G1wYcCRwkRcENotIo=; b=PcWPA1GYQLvrScMIV7mpPGn5Ivpqdlu7JQQAWiN97fJMoNYrKFTXDWo+P29bksl2 GxMJm4Rq60nYZXSYwYiN9tCRdgudkaJfOAQQ0+lQnBEyQKQO1drDxxeETdCZqDJMufl 3202ZsNfcXHni1PQGh+jAW5tV+Q6cc6WIPc3W5BIEkT0xsIYgNKY566RgERoXbj9bAy CIq4bYrbLL4P8rAmgffXZFnbDckznyhiupGKIBFV8jpHDji5fM1ocoAoICyshVYBhU8 k68yPgRI/mDebD7rJ1Gjw4UKEaFMIg6AfVEf6fWQ5YJyk+2HdOhFqESKOicUiigRwPh uA9FYL8Ezw== Received: by smtp.zohomail.com with SMTPS id 1789933268181778.553587833174; Sun, 20 Sep 2026 12:41:08 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:23 +0800 Subject: [PATCH v7 09/13] 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: <20260921-leds-trigger-hw-changed-v7-9-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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 hw_offloaded() callback to indicate hardware control - Associate with the LED classdev's hw_control_trigger string The fallback path is kept, but a warning message is emitted when it reaches there. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Rename the offloaded() callback to hw_offloaded() (thanks Lee Jones) Changes in v3: - New patch in the series, splitted from PATCH 3 (thanks Thomas Wei=C3=9Fschuh) --- drivers/leds/led-triggers.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 38ce3350c870..6fee3145caab 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -42,9 +42,17 @@ 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->hw_offloaded) return led_cdev->trigger->hw_offloaded(led_cdev); =20 + dev_warn_once(led_cdev->dev, + "Hardware control trigger %s doesn't provide offloaded state\n", + led_cdev->trigger->name); + /* Otherwise assume private triggers are always offloaded. */ return led_cdev->trigger->trigger_type; } --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender5-op-o15.zoho.com (sender5-op-o15.zoho.com [165.173.182.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 6B4624756C3; Sun, 20 Sep 2026 19:44:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.182.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933484; cv=pass; b=RL3DTcznlqFsziOJ9IOoE3ocpPL5HfgwTXeQsFd30HDAkAcV05RyXzyZPcR8J40HRtdIcX/U4mnknHGuWS2A8I2XPFwuqa0mCIeDUxXLwyfGaQAAJcmfwx5GAhVfzJs7Is028FJ0Ckwjn0DDz14YB6D8RVAvIXXAKuowQWYb2Ek= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933484; c=relaxed/simple; bh=runTBY2NNn9QueCTTyhYuL5oHzS8Lp5Ff1DsV2L/M2c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AO+zy/nUzVvh9VtzA7mkyHJbp8el0DzfeI5+yjwKNCuaJ6zYWTQ4b17e3dhvNaGOIVf540l1EVHsITk6j224L+6dPGwnHT3ipkkdcOUY/GOQNc7Pm4tAQRwJ3vDbAbl7xt3g9ZjzswuRIbfsfnAjgEomgKtEZuMulNWFWpplFpI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=L2En/sgd; arc=pass smtp.client-ip=165.173.182.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="L2En/sgd" ARC-Seal: i=1; a=rsa-sha256; t=1789933275; cv=none; d=zohomail.com; s=zohoarc; b=N8rCbipr8LoXq4qKj1a9SNHnIYsGpKBcsV0XL5zcLYVlV7DOlhWktXoOaKyGSRGQG0IFD55WarUcXK1u2jeTaECN84c/D2uBZZI/ONwSr3aGqgG7sn8Y8vye8JI+N3aRALjptvojcc9ZhOw31FDEPdtfA6Z/Dk1cMgNgP96TUNA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933275; 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=/HgdVTj/PT8YV7K36sl8SXkauJ4S64cxi7yuBQyXDd8=; b=oGMfexjUowP3TRWudD77Ofs7KVHnitBdoab91MpM9ZjHc1S6uiSMQywTnf+kW/33pMSLkR/p/NMhVspXpiGuk2dB3ZsO+E3jcjG+CSeaef4NDsAstKNBofUxSTC1fJzAIwMh9W1cZZfJaPRXQe3WNxlutaed0igzX7c3kCHelLk= 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=1789933275; 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=/HgdVTj/PT8YV7K36sl8SXkauJ4S64cxi7yuBQyXDd8=; b=L2En/sgdj4w2emUrWiCfheJRyxr084KiKmh6xUlGO+WOkZn7asIBTaG8f9EqAkvP //vBy+lWijzgU7vjQNxYcy9hKZj0BrYPsafgoPTEusFImvvchCIwI1i/cJxIrWn0qEY 8heWVR8GcfyvkaJ1j4c2ToIUHp6hE8Y5panznpMIx+ClBUqf1GD+KHe2pdpiqArxcKN jObAT1gDQ9pfGeZ50ZLanl4FHgS7qHIktfFs8Qyi8lgXIfYFIUAh/9xDKoXi1OiH5CQ +ckTtt5bM9V95twIVmO4fb9jD9pYRA47xOHlADiu/Rkz/ifdEMQc+AVywHwsOEwGHfO sQcpCEn+QQ== Received: by smtp.zohomail.com with SMTPS id 1789933273169617.1755194883555; Sun, 20 Sep 2026 12:41:13 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:24 +0800 Subject: [PATCH v7 10/13] 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: <20260921-leds-trigger-hw-changed-v7-10-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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, the config LEDS_TRIGGERS_HW_CHANGED must be enabled, and the LED driver must set the LED_TRIG_HW_CHANGED flag for the classdev. By default, the config is enabled when LEDS_BRIGHTNESS_HW_CHANGED is enabled. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Remove messages mainly for debugging (thanks Lee Jones) - Inline led_trigger_{init,destroy}_hw_changed() into led-class.c by exporting led_trigger_hw_control_changed_worker() (ditto) - Rephrase some comments and messages (ditto) Changes in v6: - Implement workqueue deferal mechanism - https://msgid.link/e2b081dfd8f96511a73b86ab3ec75e5cd759b79b.camel@rong.= moe Changes in v5: - Address a concern from Sashiko: - led_trigger_notify_hw_control_changed() might sleep, but without any internal deferral mechanism or annotation - Annotate the method with might_sleep(), since the very first users of the interface, i.e., ideapad-laptop and (supposedly) thinkpad_acpi, will call the interface from work contexts. It does not deserve the overhead of internal deferral mechanism - https://sashiko.dev/#/patchset/20260802-leds-trigger-hw-changed-v4-0-f9= 7e2ca976fe@rong.moe?part=3D9 Changes in v4: - Enable LEDS_TRIGGERS_HW_CHANGED by default when LEDS_BRIGHTNESS_HW_CHANGED is enabled Changes in v3: - Adopt guard() (Thanks Thomas Wei=C3=9Fschuh) - Reword documentations --- Documentation/leds/leds-class.rst | 52 +++++++++++++++++++++++++ drivers/leds/led-class.c | 10 +++++ drivers/leds/led-triggers.c | 80 +++++++++++++++++++++++++++++++++++= +++- drivers/leds/leds.h | 1 + drivers/leds/trigger/Kconfig | 10 +++++ include/linux/leds.h | 13 +++++++ 6 files changed, 164 insertions(+), 2 deletions(-) diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-cl= ass.rst index ea478989aae2..464e54cabf52 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-class.c b/drivers/leds/led-class.c index 7f51715fac69..00be3cb96c00 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -559,6 +559,11 @@ int led_classdev_register_ext(struct device *parent, #endif #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED led_cdev->brightness_hw_changed =3D -1; +#endif +#ifdef CONFIG_LEDS_TRIGGERS_HW_CHANGED + if (led_cdev->flags & LED_TRIG_HW_CHANGED) + INIT_WORK(&led_cdev->trigger_hw_changed_work, + led_trigger_hw_control_changed_worker); #endif if (!led_cdev->max_brightness) led_cdev->max_brightness =3D LED_FULL; @@ -598,6 +603,11 @@ void led_classdev_unregister(struct led_classdev *led_= cdev) if (IS_ERR_OR_NULL(led_cdev->dev)) return; =20 +#ifdef CONFIG_LEDS_TRIGGERS_HW_CHANGED + if (led_cdev->flags & LED_TRIG_HW_CHANGED) + disable_work_sync(&led_cdev->trigger_hw_changed_work); +#endif + #ifdef CONFIG_LEDS_TRIGGERS down_write(&led_cdev->trigger_lock); if (led_cdev->trigger) diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 6fee3145caab..f16603b5ff44 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -7,7 +7,9 @@ * Author: Richard Purdie */ =20 +#include #include +#include #include #include #include @@ -235,7 +237,8 @@ const struct attribute_group led_trigger_group =3D { EXPORT_SYMBOL_GPL(led_trigger_group); =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]; @@ -266,7 +269,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 the error path + * always turns off the LED to reset it to a certain state. + */ + if (trig || !hw_triggered) + led_set_brightness(led_cdev, LED_OFF); } if (trig) { spin_lock(&trig->leddev_list_lock); @@ -330,6 +347,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) @@ -484,6 +506,60 @@ 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) +{ + if (activate && !led_cdev->trigger) /* "none" =3D> private trigger. */ + __led_trigger_set(led_cdev, hc_trig, true); + else if (!activate && led_cdev->trigger =3D=3D hc_trig) /* private trigge= r =3D> "none". */ + __led_trigger_set(led_cdev, NULL, true); + + /* Already in the desired state, or another trigger is active, ignore. */ +} + +void led_trigger_hw_control_changed_worker(struct work_struct *work) +{ + struct led_classdev *led_cdev =3D + container_of(work, struct led_classdev, trigger_hw_changed_work); + bool activate =3D READ_ONCE(led_cdev->trigger_hw_changed); + + scoped_guard(rwsem_read, &triggers_list_lock) { + struct led_trigger *trig; + + 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_warn(led_cdev->dev, + "Private trigger %s is not registered, can't toggle hardware control\n", + led_cdev->hw_control_trigger); +} +EXPORT_SYMBOL_GPL(led_trigger_hw_control_changed_worker); + +void led_trigger_notify_hw_control_changed(struct led_classdev *led_cdev, = bool activate) +{ + /* Restricted to private triggers. */ + if (WARN_ON(!(led_cdev->flags & LED_TRIG_HW_CHANGED) || + !led_cdev->hw_control_trigger || !led_cdev->trigger_type)) + return; + + WRITE_ONCE(led_cdev->trigger_hw_changed, activate); + + schedule_work(&led_cdev->trigger_hw_changed_work); +} +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/leds.h b/drivers/leds/leds.h index c1db21e943b0..6d00e6f44126 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -21,6 +21,7 @@ void led_init_core(struct led_classdev *led_cdev); void led_stop_software_blink(struct led_classdev *led_cdev); void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int v= alue); void led_set_brightness_nosleep(struct led_classdev *led_cdev, unsigned in= t value); +void led_trigger_hw_control_changed_worker(struct work_struct *work); =20 extern struct rw_semaphore leds_list_lock; extern struct list_head leds_list; diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index c11282a74b5a..a11d04ce4ab2 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -9,6 +9,16 @@ menuconfig LEDS_TRIGGERS =20 if LEDS_TRIGGERS =20 +config LEDS_TRIGGERS_HW_CHANGED + bool "LED hardware-initiated trigger transition support" + default LEDS_BRIGHTNESS_HW_CHANGED + 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 9a0bfd985b46..beaf23993063 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; @@ -239,6 +240,11 @@ struct led_classdev { struct kernfs_node *brightness_hw_changed_kn; #endif =20 +#ifdef CONFIG_LEDS_TRIGGERS_HW_CHANGED + bool trigger_hw_changed; + struct work_struct trigger_hw_changed_work; +#endif + /* Ensures consistent access to the LED class device */ struct mutex led_access; }; @@ -609,6 +615,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.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender6-op-o15.zoho.com (sender6-op-o15.zoho.com [165.173.180.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 026014746CE; Sun, 20 Sep 2026 19:44:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933501; cv=pass; b=HrSs3oz15yxlRCMubd9y4fLitqVokom1CoabJE/F9vWHYTpkyLU7WuX19S03KNQUFFSadlJTHmHp/K6l1jNJuxoEGsvAUU3hxT2s6HAVHeWd9lQKFe6Fnu94ovW2q2Jz+yt0hRo+RanTKKNtnXrgdXBXzDAcQJPsshy2zrWeEgE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933501; c=relaxed/simple; bh=kbWO3d4W1V5pmzBTou6J2PpxmnVkxPo0U0r7mMtvvyI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LQOQ3/pX2tEjSUG/5xTS/lPg/Cjpk1hNZ7/czCxCWYGDqboKyQqGnCYElmkBOIhCOPc6d26piPqkC1WXc+VpK9X7uXSf/9wBbkdm2gRy99h3ALIeSnxFPgcMt42CxxtdhN2fcGe5fn7b+8hIKDEYaUHHAF+CfIQ9fclyvQG6B2E= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=pinLuAV/; arc=pass smtp.client-ip=165.173.180.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="pinLuAV/" ARC-Seal: i=1; a=rsa-sha256; t=1789933279; cv=none; d=zohomail.com; s=zohoarc; b=hs/v4ihtEGyYrbQEcB8HklE59/9V4TVf4jj0/6w7OdlvS7eaSUb+TM+CbC01lINQMmIXUHYzp1dFwliFfiT5Y1uAF2kj6LYkIWf3BWVK7PG72c5TnjV+K+/DaF1reMXBjqpKMLpZF/xlpHa/Vr0yVo5KBP/mac1zEiPQKWNf8Qg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933279; 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=ToI18bR9XJY1UTByBrP+FM1o48uVmfnxpVfIbtodrQo=; b=RI4wjD0hZ8TQ93hb2egfeSzr63XoMmfYmsbCIJ1/zGQmSvFUbfPxj8cYVIUG6Rb6CYSB+SVOCQsKLGF7aPUWwMiUHjwtwsVTGVrJaZxhsgZ4aRBr+DKdgKkzgUf6XPsKE68fqqgXs21imgJHUAfcJHHOkOURGozGVB+gemKZxIw= 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=1789933278; 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=ToI18bR9XJY1UTByBrP+FM1o48uVmfnxpVfIbtodrQo=; b=pinLuAV/SH1jMBNJ5IheFyVpbGhSsPOKtnpk5TehEaVQOcSXVbf8kDUvfRpPfQ+X Qg4Yi5oCf2R0t40AFib7lTYwZXyUG5EbL3kAe8oY7IbrUKfhWKeH8GN35zggiTfOBBw RZbGdrTy4CYUKemegu4qM0EKo4hXQ5g0C81bbzLb3QQepFoFqtwyodcrUrbB5e2Ggg+ fmEO+BOS5iMb1HIrIYTdAAMU8L7NWWYKFPzRXIhlTWs/GYVSxPJmNAngMAUYee9rX9j jVupZQylIyjhdV+gjnxPCViPg9/0W4mS9ZdxeCtVqZ7wtBFOa2knf2HsYkurMm3T+Yl QG6h8VxoOw== Received: by smtp.zohomail.com with SMTPS id 1789933278052721.8772421082251; Sun, 20 Sep 2026 12:41:18 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:25 +0800 Subject: [PATCH v7 11/13] platform/x86: ideapad-laptop: Serialize keyboard backlight tracking 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: <20260921-leds-trigger-hw-changed-v7-11-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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 tracking to prevent potential race conditions. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v6: - Protects ideapad_kbd_bl_led_cdev_brightness_set() as well Changes in v4: - Remove needless #include (Thanks Ilpo J=C3=A4rvinen) --- 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 8213524504ee..684421ba53cb 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,7 @@ struct ideapad_private { int type; struct led_classdev led; unsigned int last_brightness; + struct mutex mutex; /* protects brightness tracking */ } kbd_bl; struct { bool initialized; @@ -1643,6 +1645,8 @@ static int ideapad_kbd_bl_brightness_set(struct ideap= ad_private *priv, unsigned unsigned long value; int type =3D priv->kbd_bl.type; =20 + guard(mutex)(&priv->kbd_bl.mutex); + if (ideapad_kbd_bl_check_tristate(type)) { if (brightness > priv->kbd_bl.led.max_brightness) return -EINVAL; @@ -1678,6 +1682,8 @@ static void ideapad_kbd_bl_notify(struct ideapad_priv= ate *priv) if (!priv->kbd_bl.initialized) return; =20 + guard(mutex)(&priv->kbd_bl.mutex); + brightness =3D ideapad_kbd_bl_brightness_get(priv); if (brightness < 0) return; @@ -1700,6 +1706,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.mutex); + if (err) + return err; + if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) priv->kbd_bl.led.max_brightness =3D 2; else --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender5-op-o15.zoho.com (sender5-op-o15.zoho.com [165.173.182.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 17896474262; Sun, 20 Sep 2026 19:45:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.182.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933520; cv=pass; b=MAnyYL54C8Nosb9hqviXiULz6ZGUpFG4yyfp9SBPeBm7no8aK98CjXhGPtXKrd4iATE7fpFhhJKmPOhfgCB22kZ0XfMBn5WUNWMavAF/iIn+QIiTkeREAYfmdgk4n5tcmHAGpLAWQlRrZxN8azVLEi058Pwc86/H4UdNCskHpTY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933520; c=relaxed/simple; bh=knU9n85ZF0reDnxSfdYGZBv6PDVYNDCOzZ/bEExX1M4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uecUcdlrfk5wNu0YAFagOt4WyvyngYALA759snrixODEZK9n3fLGeOc1kJg9/9T9ggL+UCfhc2ZG946baPLfZ1UJIGmtxHKbEDZxngwckl39DbOHmGAoB84NQ4rRhrCy46Lq7UEgnfFaKBij+kgadPiX5LCL3FhtVjcrcdZqDuY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=mUF2n0Tg; arc=pass smtp.client-ip=165.173.182.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="mUF2n0Tg" ARC-Seal: i=1; a=rsa-sha256; t=1789933285; cv=none; d=zohomail.com; s=zohoarc; b=iaLoHwL9Fmq4ZNo7/E0OayGi3pFYvPe//wTRBd5JIe8oa4/dbvCDSHq56OK8oMkbXOXplLk7d+7iLxShiqz1cxET4i2eRjOkWeRJC5ANc76+rubAJfqaK0gS7Gi5TGI+NEzTr5fUCv4PnRRdhXL+BurukrMCyX65Gxr+OQvyZ8k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933285; 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=reqQtgR14D3FWvwJw7AQMiN41dNfcxplQQKxtf3niLo=; b=fxkoVa918JuUcXKUKSxWekAzkVUfik+/45BmIcKGg0fNTXJ0F3sHse6Y6kZHAtD8X/sVHhhkVojpNDruk1D/FCmlMq+IaGYCU7N571gdn+fGoPw6h6YDtTVUFP1nxfrcWFO/JD8ezRzVhLqzrAP971wHqrBM/PRyIptU4xjGH2c= 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=1789933285; 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=reqQtgR14D3FWvwJw7AQMiN41dNfcxplQQKxtf3niLo=; b=mUF2n0TgVItTHnLnPE+QgeLi/h5OnxiXErj0Jm2Jf/epdzbBXxUtXIMZty8PVqKp MZ/PAaB1n7LzJLimeroaRsztx7i6CXAyobJvQmp0lFOXpRvx3E/fLP25alIPBLHj+Kq cfW3TbI/pgsTH29kVd98txOnAvLP+VCxbAPbhPatSk/VcroUDx+M3iT0uC9g32Cp6QG C9ApXm/ZkPOAWCcuZAInMVbiTyvgPcfbU1ZL+7QL986BWFwh5hLB2zhwkpwXKqltzXc hNl4eGf5DGhw+joh13cyQDT0tOn5sYMWeSVF1R+mLbjNIHWE9Q7zrF55SX3HTr0ZolO 4J7xUc/2jw== Received: by smtp.zohomail.com with SMTPS id 1789933283017885.5864709174683; Sun, 20 Sep 2026 12:41:23 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:26 +0800 Subject: [PATCH v7 12/13] 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: <20260921-leds-trigger-hw-changed-v7-12-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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. To minimalize the diff set in upcoming changes, a trivial refactor also converts the initialization path into another equivalent form. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Address a concern from Sashiko - Fix printf format string - https://sashiko.dev/#/patchset/20260902-leds-trigger-hw-changed-v6-0-55= 693cd78877@rong.moe?part=3D11 Changes in v6: - No longer convert last_hw_brightness into atomic_t as it's not required now Changes in v4: - Add missing #include (Thanks Ilpo J=C3=A4rvinen) - Address concerns from Sashiko - Reject insane hardware brightness - https://sashiko.dev/#/patchset/20260719-leds-trigger-hw-changed-v3-0-5f= b55722e36e@rong.moe?part=3D9 --- drivers/platform/x86/lenovo/ideapad-laptop.c | 150 +++++++++++++++++++----= ---- 1 file changed, 106 insertions(+), 44 deletions(-) diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platfor= m/x86/lenovo/ideapad-laptop.c index 684421ba53cb..b57c4f18d0ea 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -135,10 +137,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, @@ -146,6 +169,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 @@ -204,7 +229,7 @@ struct ideapad_private { bool initialized; int type; struct led_classdev led; - unsigned int last_brightness; + unsigned int last_hw_brightness; struct mutex mutex; /* protects brightness tracking */ } kbd_bl; struct { @@ -1594,7 +1619,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, u= nsigned int 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: %u", hw_brightness); + return -EINVAL; +} + +static int ideapad_kbd_bl_hw_brightness_get(struct ideapad_private *priv) { unsigned long value; int err; @@ -1608,21 +1650,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); @@ -1632,6 +1660,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); @@ -1639,34 +1677,40 @@ 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, + unsigned int hw_brightness) { - int err; unsigned long value; int type =3D priv->kbd_bl.type; + int err; =20 guard(mutex)(&priv->kbd_bl.mutex); =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; + priv->kbd_bl.last_hw_brightness =3D hw_brightness; =20 return 0; } =20 +static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, uns= igned 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) { @@ -1677,28 +1721,32 @@ 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; =20 if (!priv->kbd_bl.initialized) return; =20 guard(mutex)(&priv->kbd_bl.mutex); =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) + brightness =3D ideapad_kbd_bl_brightness_parse(priv, hw_brightness); + if (brightness < 0) + return; /* Reject insane values early. */ + + if (priv->kbd_bl.last_hw_brightness =3D=3D hw_brightness) return; =20 - priv->kbd_bl.last_brightness =3D brightness; + priv->kbd_bl.last_hw_brightness =3D hw_brightness; =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; @@ -1710,21 +1758,35 @@ static int ideapad_kbd_bl_init(struct ideapad_priva= te *priv) if (err) return err; =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; + priv->kbd_bl.last_hw_brightness =3D 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(); + } + + /* Reject insane values. */ + err =3D ideapad_kbd_bl_brightness_parse(priv, hw_brightness); + if (err < 0) + return err; + err =3D led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.= led); if (err) return err; --=20 2.55.0 From nobody Thu Sep 24 20:37:27 2026 Received: from sender5-op-o15.zoho.com (sender5-op-o15.zoho.com [165.173.182.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 9B64D471CED; Sun, 20 Sep 2026 19:45:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.182.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933539; cv=pass; b=KtCKF3WffnpDoofcxanH2uNgCPjEQieNdMcOWo7d475OKwxYHNz2/GZ4jC/X3iiOgZNyXO1MfKRDu12yEgGwnmJy7+oZpAlXrjlrLxRE2bfcREotWfUrIdkGnxKeymWuaxJHxM1EdfjCB9PGTaW63L0r9aAvbjMz9EbHN/An9Do= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789933539; c=relaxed/simple; bh=5u8zaxPREYZxlq84Fkr7UzG0gA1V2a5MvJVVd04e+Bk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eN9nOTY9KiAF/uMrTT+mgvxlgS++OG19P111Shzc8I11SMwEXo8O0kPSeBM24SQYlMEm2/UvktJZyW/2HZBf4pF931cdOB2wNBhDCwFGkOgoEXWyDWzqxAJazLtUsz+ini/Ztz3bPcuC/ELW8ASVMJR0TsQP1cFSK9UTdtXnA0o= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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=ONCh1drJ; arc=pass smtp.client-ip=165.173.182.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine 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="ONCh1drJ" ARC-Seal: i=1; a=rsa-sha256; t=1789933289; cv=none; d=zohomail.com; s=zohoarc; b=gmLC1VQOcAI+77m5QhnhhkpC2ur+szOw8SvrEH+GfegLZGuGTC2TM2MCh/+o+69+P3KUW9AlfX8veHZmnkq+0ApJSKrlphB8kmJzKEMLoLJdkKjkYgzEacA8qFbCefvC/w0fTKSM3PXuFN/KMpsT7oiIJtOKX1HxL9aJRZrdBac= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789933289; 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=rsOlzcBi+bit3bNNiL4SBRxL2dg7cwN2NXcGIs1niS8=; b=kWNOoO9BTzYsCDVPYtPVzLqkTsjiU8Iar4NP4kOOKJTceBeeuTdB6EUa/dlFzoGjoqJ2NbGzJyHvHsPCGKklAXP3X+1Owe1puY3ITHwp3ISU86TlIFL6F759iE1m+0L2NxTXcw37+lGfT3XvbvKfB+r4lsBY+okwdA/kBq23Wwc= 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=1789933289; 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=rsOlzcBi+bit3bNNiL4SBRxL2dg7cwN2NXcGIs1niS8=; b=ONCh1drJZ9biPsCT1kXWz/GIxrghm0X7fTLc1ZgDyTRTA7Paab6c2pvLUO33wtt5 owaY2gK5IF0u53m3k0t8dp4gCsy3V8FZ3ThTYkpZXEmV9aajZajHOKhrxAMLoxBNEsG F/891wz9jmS1nus0OW99V6Gy5S8/LplrSb7CTY/UbhMmvU4MkmWlTyc0A7bNIcVp9ut MbpyfoJUsjRT2ZUVCDL8X6Q9pJJw7ssSrsph0SLnS6/i/43JrieK6Cg4ejPR4nS2Z2n 0ro7Gg28UcmkltrYSBN/DgCzjusFeJAWwtDBGFVxrYfDjXLZbA76jofAHwqtxX83oRC LE23zY0PNw== Received: by smtp.zohomail.com with SMTPS id 1789933287945171.018860174824; Sun, 20 Sep 2026 12:41:27 -0700 (PDT) From: Rong Zhang Date: Mon, 21 Sep 2026 03:40:27 +0800 Subject: [PATCH v7 13/13] 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: <20260921-leds-trigger-hw-changed-v7-13-fe3cdb6dec51@rong.moe> References: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@rong.moe> In-Reply-To: <20260921-leds-trigger-hw-changed-v7-0-fe3cdb6dec51@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.17-dev-1f2f7 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. To align with LEDS_BRIGHTNESS_HW_CHANGED, the driver neither depends on LEDS_TRIGGERS_HW_CHANGED nor selects it. 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 the state of auto mode can retain among boots. Acked-by: Ike Panhc Signed-off-by: Rong Zhang --- Changes in v7: - Rename the offloaded() callback to hw_offloaded() (thanks Lee Jones) Changes in v6: - Simplify the auto mode state preservation logic by converting `priv->kbd_bl.initialized' into a tristate integer Changes in v4: - Add missing #include (Thanks Ilpo J=C3=A4rvinen) - Remove needless code alignment (ditto) - Address concerns from Sashiko - Do not notify the LED trigger core when the registration of the private trigger has failed - https://sashiko.dev/#/patchset/20260719-leds-trigger-hw-changed-v3-0-5f= b55722e36e@rong.moe?part=3D11 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/Kconfig | 1 + drivers/platform/x86/lenovo/ideapad-laptop.c | 119 +++++++++++++++++++++++= +--- 2 files changed, 109 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/lenovo/Kconfig b/drivers/platform/x86/len= ovo/Kconfig index 516594993073..a97852b0b228 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 b57c4f18d0ea..db03c0c9e497 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -226,7 +228,10 @@ struct ideapad_private { bool ymc_ec_trigger : 1; } features; struct { - bool initialized; + int initialized; /* 0: initializion pending/ongoing/failed + * >0: initializion finished + * <0: unregisteration ongoing/finished + */ int type; struct led_classdev led; unsigned int last_hw_brightness; @@ -1716,14 +1721,68 @@ static int ideapad_kbd_bl_led_cdev_brightness_set(s= truct led_classdev *led_cdev, { struct ideapad_private *priv =3D container_of(led_cdev, struct ideapad_pr= ivate, kbd_bl.led); =20 + /* + * When unregistering: It must be the side effect of LED 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. + * + * It's needless to gate changes when initializing, as there may be a + * time margin between sysfs attribute creation and state change. + */ + if (unlikely(priv->kbd_bl.initialized < 0)) + return 0; + return ideapad_kbd_bl_brightness_set(priv, brightness); } =20 +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 bool ideapad_kbd_bl_auto_trigger_hw_offloaded(struct led_classdev *= led_cdev) +{ + struct ideapad_private *priv =3D container_of(led_cdev, struct ideapad_pr= ivate, kbd_bl.led); + + guard(mutex)(&priv->kbd_bl.mutex); + + return priv->kbd_bl.last_hw_brightness =3D=3D 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, + .hw_offloaded =3D ideapad_kbd_bl_auto_trigger_hw_offloaded, +}; + +static bool ideapad_kbd_bl_auto_trigger_registered; + +static void ideapad_kbd_bl_notify_hw_control(struct ideapad_private *priv, + unsigned int hw_brightness) +{ + bool hw_control, last_hw_control; + + if (!ideapad_kbd_bl_auto_trigger_registered || 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 priv->kbd_bl.last_hw_brightness =3D=3D KBD_BL_AUTO_MO= DE_HW_BRIGHTNESS; + + 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; =20 - if (!priv->kbd_bl.initialized) + if (unlikely(priv->kbd_bl.initialized <=3D 0)) return; =20 guard(mutex)(&priv->kbd_bl.mutex); @@ -1739,6 +1798,8 @@ static void ideapad_kbd_bl_notify(struct ideapad_priv= ate *priv) if (priv->kbd_bl.last_hw_brightness =3D=3D hw_brightness) return; =20 + ideapad_kbd_bl_notify_hw_control(priv, hw_brightness); + priv->kbd_bl.last_hw_brightness =3D hw_brightness; =20 led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness); @@ -1751,9 +1812,11 @@ static int ideapad_kbd_bl_init(struct ideapad_privat= e *priv) if (!priv->features.kbd_bl) return -ENODEV; =20 - if (WARN_ON(priv->kbd_bl.initialized)) + if (WARN_ON(priv->kbd_bl.initialized > 0)) return -EEXIST; =20 + priv->kbd_bl.initialized =3D 0; + err =3D devm_mutex_init(&priv->platform_device->dev, &priv->kbd_bl.mutex); if (err) return err; @@ -1771,6 +1834,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, + "Cannot 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.trigger_type =3D &ideapad_kbd_bl_auto_trigger_type; + priv->kbd_bl.led.hw_control_trigger =3D ideapad_kbd_bl_auto_trigger.name; + + /* 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; @@ -1791,17 +1872,17 @@ static int ideapad_kbd_bl_init(struct ideapad_priva= te *priv) if (err) return err; =20 - priv->kbd_bl.initialized =3D true; + priv->kbd_bl.initialized =3D 1; =20 return 0; } =20 static void ideapad_kbd_bl_exit(struct ideapad_private *priv) { - if (!priv->kbd_bl.initialized) + if (priv->kbd_bl.initialized <=3D 0) return; =20 - priv->kbd_bl.initialized =3D false; + priv->kbd_bl.initialized =3D -1; =20 led_classdev_unregister(&priv->kbd_bl.led); } @@ -2620,17 +2701,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 @@ -2638,6 +2732,9 @@ static void __exit ideapad_laptop_exit(void) { platform_driver_unregister(&ideapad_acpi_driver); ideapad_wmi_driver_unregister(); + + if (ideapad_kbd_bl_auto_trigger_registered) + led_trigger_unregister(&ideapad_kbd_bl_auto_trigger); } module_exit(ideapad_laptop_exit) =20 --=20 2.55.0