From nobody Sun Dec 14 21:54:47 2025 Received: from todd.t-8ch.de (todd.t-8ch.de [159.69.126.157]) (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 F1274209F22; Wed, 11 Dec 2024 19:58:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.69.126.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733947084; cv=none; b=Y50VltA8HK1iYYzW5QRaxvRK1je8SGSX/pL0ZdnqdoJTe1erJpEMpeg9xmgggApX0RESEQdZ/t7OZ2MtxR2rlOLqm2r3Wn/sk5FnQbRi5e5LQznd/WAY3NFm04311GvsFcpsfmWujWaUDsEUPsGHp/aGNHzp1OgDDdVRc7PMOw0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733947084; c=relaxed/simple; bh=46WotVaECWG26OkEOVXUg7kQui6ipeeebMh7OoLHVwk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qSsnaZOrsIiBq3DLQqF7tVOyNwHB0R64sygovffzWws+b6UmEecbgOWY++hsDQtnBENU3/nk/iIXHE5Wi/mpUuqNO6h4fOC8ljDZMgk+u/ka5RNZ0bLROnehiGAMog/lYybDzaeXUtiU6//St4hGpKE8o9Lnghiqp0XHSgnhKMg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=weissschuh.net; spf=pass smtp.mailfrom=weissschuh.net; dkim=pass (1024-bit key) header.d=weissschuh.net header.i=@weissschuh.net header.b=TKpJDP+M; arc=none smtp.client-ip=159.69.126.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=weissschuh.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=weissschuh.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=weissschuh.net header.i=@weissschuh.net header.b="TKpJDP+M" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=weissschuh.net; s=mail; t=1733947079; bh=46WotVaECWG26OkEOVXUg7kQui6ipeeebMh7OoLHVwk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=TKpJDP+MG1RacbluxG6wPl/2704S1qDCz+fJsaY3RiZbLiUtTIVZcoTK3mZ+Z2mMB TCRgJINQYDoYhY4+cidDfrLVAi61pGGswAIRaz4bA93TQUWRBeqiOVvKi+IetXk3hI t8nmecnqPaYVTD0kWxL4Cdbfy1f8bg+ZnrgmXQ6E= From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= Date: Wed, 11 Dec 2024 20:57:58 +0100 Subject: [PATCH v6 4/4] power: supply: core: add UAPI to discover currently used extensions 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: <20241211-power-supply-extensions-v6-4-9d9dc3f3d387@weissschuh.net> References: <20241211-power-supply-extensions-v6-0-9d9dc3f3d387@weissschuh.net> In-Reply-To: <20241211-power-supply-extensions-v6-0-9d9dc3f3d387@weissschuh.net> To: Sebastian Reichel , Armin Wolf , Hans de Goede , =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , Benson Leung , Guenter Roeck Cc: linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, linux-pm@vger.kernel.org, =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1733947078; l=8969; i=linux@weissschuh.net; s=20221212; h=from:subject:message-id; bh=46WotVaECWG26OkEOVXUg7kQui6ipeeebMh7OoLHVwk=; b=I2vNYp+UAkSebwP2cXbdpyM9j7jV2egrrjlxacXd0Hr0lZrydI1lEXKWzEaYHRdWROJhbiVBA GIGldCyYEOqDTaBDah2PImGxtorw71b4di08Hf/Kf13OKBbrQOtXGyt X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=KcycQgFPX2wGR5azS7RhpBqedglOZVgRPfdFSPB1LNw= Userspace wants to now about the used power supply extensions, for example to handle a device extended by a certain extension differently or to discover information about the extending device. Add a sysfs directory to the power supply device. This directory contains links which are named after the used extension and point to the device implementing that extension. Signed-off-by: Thomas Wei=C3=9Fschuh Reviewed-by: Armin Wolf --- Documentation/ABI/testing/sysfs-class-power | 9 +++++++++ drivers/power/supply/cros_charge-control.c | 5 ++++- drivers/power/supply/power_supply.h | 2 ++ drivers/power/supply/power_supply_core.c | 19 +++++++++++++++++-- drivers/power/supply/power_supply_sysfs.c | 10 ++++++++++ drivers/power/supply/test_power.c | 4 +++- include/linux/power_supply.h | 2 ++ 7 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/AB= I/testing/sysfs-class-power index 45180b62d42686c8999eda54f38435cb6c74a879..31e8b33d849cbe99dc93a4ba372= 3a43440ac3103 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -793,3 +793,12 @@ Description: =20 Access: Read Valid values: 1-31 + +What: /sys/class/power_supply//extensions/ +Date: March 2025 +Contact: linux-pm@vger.kernel.org +Description: + Reports the extensions registered to the power supply. + Each entry is a link to the device which registered the extension. + + Access: Read diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/sup= ply/cros_charge-control.c index fb4af232721dec1d4f0090f6616922848812b2a2..02d5bdbe2e8d45108dd8f2d3ab6= a927b94864b9e 100644 --- a/drivers/power/supply/cros_charge-control.c +++ b/drivers/power/supply/cros_charge-control.c @@ -31,6 +31,7 @@ */ =20 struct cros_chctl_priv { + struct device *dev; struct cros_ec_device *cros_ec; struct acpi_battery_hook battery_hook; struct power_supply *hooked_battery; @@ -202,6 +203,7 @@ static int cros_chctl_psy_prop_is_writeable(struct powe= r_supply *psy, }; \ \ static const struct power_supply_ext _name =3D { \ + .name =3D "cros-charge-control", \ .properties =3D _name ## _props, \ .num_properties =3D ARRAY_SIZE(_name ## _props), \ .charge_behaviours =3D EC_CHARGE_CONTROL_BEHAVIOURS, \ @@ -233,7 +235,7 @@ static int cros_chctl_add_battery(struct power_supply *= battery, struct acpi_batt return 0; =20 priv->hooked_battery =3D battery; - return power_supply_register_extension(battery, priv->psy_ext, priv); + return power_supply_register_extension(battery, priv->psy_ext, priv->dev,= priv); } =20 static int cros_chctl_remove_battery(struct power_supply *battery, struct = acpi_battery_hook *hook) @@ -299,6 +301,7 @@ static int cros_chctl_probe(struct platform_device *pde= v) =20 dev_dbg(dev, "Command version: %u\n", (unsigned int)priv->cmd_version); =20 + priv->dev =3D dev; priv->cros_ec =3D cros_ec; =20 if (priv->cmd_version =3D=3D 1) diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/pow= er_supply.h index 531785516d2ac31f9a7f73a58e15e64cb81820ed..9ed749cd09369f0f13017847687= 509736b30aae8 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -25,6 +25,7 @@ extern bool power_supply_ext_has_property(const struct po= wer_supply_ext *ext, struct power_supply_ext_registration { struct list_head list_head; const struct power_supply_ext *ext; + struct device *dev; void *data; }; =20 @@ -39,6 +40,7 @@ struct power_supply_ext_registration { =20 extern void __init power_supply_init_attrs(void); extern int power_supply_uevent(const struct device *dev, struct kobj_ueven= t_env *env); +extern const struct attribute_group power_supply_extension_group; extern const struct attribute_group *power_supply_attr_groups[]; =20 #else diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/suppl= y/power_supply_core.c index bc22edbd0e6a02c27500132075f5c98d814a7330..5142fbd580ee3d629a2aae7d0b9= bcd5709162129 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -1346,17 +1346,21 @@ static int power_supply_update_sysfs_and_hwmon(stru= ct power_supply *psy) } =20 int power_supply_register_extension(struct power_supply *psy, const struct= power_supply_ext *ext, - void *data) + struct device *dev, void *data) { struct power_supply_ext_registration *reg; size_t i; int ret; =20 - if (!psy || !ext || !ext->properties || !ext->num_properties) + if (!psy || !dev || !ext || !ext->name || !ext->properties || !ext->num_p= roperties) return -EINVAL; =20 guard(rwsem_write)(&psy->extensions_sem); =20 + power_supply_for_each_extension(reg, psy) + if (strcmp(ext->name, reg->ext->name) =3D=3D 0) + return -EEXIST; + for (i =3D 0; i < ext->num_properties; i++) if (power_supply_has_property(psy, ext->properties[i])) return -EEXIST; @@ -1366,9 +1370,15 @@ int power_supply_register_extension(struct power_sup= ply *psy, const struct power return -ENOMEM; =20 reg->ext =3D ext; + reg->dev =3D dev; reg->data =3D data; list_add(®->list_head, &psy->extensions); =20 + ret =3D sysfs_add_link_to_group(&psy->dev.kobj, power_supply_extension_gr= oup.name, + &dev->kobj, ext->name); + if (ret) + goto sysfs_link_failed; + ret =3D power_supply_update_sysfs_and_hwmon(psy); if (ret) goto sysfs_hwmon_failed; @@ -1376,6 +1386,8 @@ int power_supply_register_extension(struct power_supp= ly *psy, const struct power return 0; =20 sysfs_hwmon_failed: + sysfs_remove_link_from_group(&psy->dev.kobj, power_supply_extension_group= .name, ext->name); +sysfs_link_failed: list_del(®->list_head); kfree(reg); return ret; @@ -1392,6 +1404,9 @@ void power_supply_unregister_extension(struct power_s= upply *psy, const struct po if (reg->ext =3D=3D ext) { list_del(®->list_head); kfree(reg); + sysfs_remove_link_from_group(&psy->dev.kobj, + power_supply_extension_group.name, + reg->ext->name); power_supply_update_sysfs_and_hwmon(psy); return; } diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supp= ly/power_supply_sysfs.c index 927ddb9d83bb7259809ba695cb9398d1ad654b46..aadc41ca741d8acd27a83f6bd01= d578d7877e7c2 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -421,8 +421,18 @@ static const struct attribute_group power_supply_attr_= group =3D { .is_visible =3D power_supply_attr_is_visible, }; =20 +static struct attribute *power_supply_extension_attrs[] =3D { + NULL +}; + +const struct attribute_group power_supply_extension_group =3D { + .name =3D "extensions", + .attrs =3D power_supply_extension_attrs, +}; + const struct attribute_group *power_supply_attr_groups[] =3D { &power_supply_attr_group, + &power_supply_extension_group, NULL }; =20 diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_= power.c index 66f9ef52e0f3e6e6e6bebcfd438c2acd421284ec..2a975a110f4859a77f768936967= 5f2008816d704 100644 --- a/drivers/power/supply/test_power.c +++ b/drivers/power/supply/test_power.c @@ -293,6 +293,7 @@ static int test_power_battery_extproperty_is_writeable(= struct power_supply *psy, } =20 static const struct power_supply_ext test_power_battery_ext =3D { + .name =3D "test_power", .properties =3D test_power_battery_extprops, .num_properties =3D ARRAY_SIZE(test_power_battery_extprops), .get_property =3D test_power_battery_extget_property, @@ -307,7 +308,8 @@ static void test_power_configure_battery_extension(bool= enable) psy =3D test_power_supplies[TEST_BATTERY]; =20 if (enable) { - if (power_supply_register_extension(psy, &test_power_battery_ext, NULL))= { + if (power_supply_register_extension(psy, &test_power_battery_ext, &psy->= dev, + NULL)) { pr_err("registering battery extension failed\n"); return; } diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index e434516086f032cdb4698005bb1a99eda303a307..88a7bd34c8a74d694013aaaebd3= 0269b30509e8b 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -284,6 +284,7 @@ struct power_supply_desc { }; =20 struct power_supply_ext { + const char *const name; u8 charge_behaviours; const enum power_supply_property *properties; size_t num_properties; @@ -907,6 +908,7 @@ extern int power_supply_powers(struct power_supply *psy= , struct device *dev); extern int __must_check power_supply_register_extension(struct power_supply *psy, const struct power_supply_ext *ext, + struct device *dev, void *data); extern void power_supply_unregister_extension(struct power_supply *psy, const struct power_supply_ext *ext); --=20 2.47.1