mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
power: supply: core: add UAPI to discover currently used extensions
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ßschuh <linux@weissschuh.net> Reviewed-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20241211-power-supply-extensions-v6-4-9d9dc3f3d387@weissschuh.net Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
This commit is contained in:
parent
bcfe7d6ba2
commit
288a2cabcf
@ -813,3 +813,12 @@ Description:
|
||||
|
||||
Access: Read
|
||||
Valid values: 1-31
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/extensions/<extension_name>
|
||||
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
|
||||
|
@ -31,6 +31,7 @@
|
||||
*/
|
||||
|
||||
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 power_supply *psy,
|
||||
}; \
|
||||
\
|
||||
static const struct power_supply_ext _name = { \
|
||||
.name = "cros-charge-control", \
|
||||
.properties = _name ## _props, \
|
||||
.num_properties = ARRAY_SIZE(_name ## _props), \
|
||||
.charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS, \
|
||||
@ -233,7 +235,7 @@ static int cros_chctl_add_battery(struct power_supply *battery, struct acpi_batt
|
||||
return 0;
|
||||
|
||||
priv->hooked_battery = battery;
|
||||
return power_supply_register_extension(battery, priv->psy_ext, priv);
|
||||
return power_supply_register_extension(battery, priv->psy_ext, priv->dev, priv);
|
||||
}
|
||||
|
||||
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 *pdev)
|
||||
|
||||
dev_dbg(dev, "Command version: %u\n", (unsigned int)priv->cmd_version);
|
||||
|
||||
priv->dev = dev;
|
||||
priv->cros_ec = cros_ec;
|
||||
|
||||
if (priv->cmd_version == 1)
|
||||
|
@ -25,6 +25,7 @@ extern bool power_supply_ext_has_property(const struct power_supply_ext *ext,
|
||||
struct power_supply_ext_registration {
|
||||
struct list_head list_head;
|
||||
const struct power_supply_ext *ext;
|
||||
struct device *dev;
|
||||
void *data;
|
||||
};
|
||||
|
||||
@ -39,6 +40,7 @@ struct power_supply_ext_registration {
|
||||
|
||||
extern void __init power_supply_init_attrs(void);
|
||||
extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env);
|
||||
extern const struct attribute_group power_supply_extension_group;
|
||||
extern const struct attribute_group *power_supply_attr_groups[];
|
||||
|
||||
#else
|
||||
|
@ -1358,17 +1358,21 @@ static int power_supply_update_sysfs_and_hwmon(struct power_supply *psy)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!psy || !ext || !ext->properties || !ext->num_properties)
|
||||
if (!psy || !dev || !ext || !ext->name || !ext->properties || !ext->num_properties)
|
||||
return -EINVAL;
|
||||
|
||||
guard(rwsem_write)(&psy->extensions_sem);
|
||||
|
||||
power_supply_for_each_extension(reg, psy)
|
||||
if (strcmp(ext->name, reg->ext->name) == 0)
|
||||
return -EEXIST;
|
||||
|
||||
for (i = 0; i < ext->num_properties; i++)
|
||||
if (power_supply_has_property(psy, ext->properties[i]))
|
||||
return -EEXIST;
|
||||
@ -1378,9 +1382,15 @@ int power_supply_register_extension(struct power_supply *psy, const struct power
|
||||
return -ENOMEM;
|
||||
|
||||
reg->ext = ext;
|
||||
reg->dev = dev;
|
||||
reg->data = data;
|
||||
list_add(®->list_head, &psy->extensions);
|
||||
|
||||
ret = sysfs_add_link_to_group(&psy->dev.kobj, power_supply_extension_group.name,
|
||||
&dev->kobj, ext->name);
|
||||
if (ret)
|
||||
goto sysfs_link_failed;
|
||||
|
||||
ret = power_supply_update_sysfs_and_hwmon(psy);
|
||||
if (ret)
|
||||
goto sysfs_hwmon_failed;
|
||||
@ -1388,6 +1398,8 @@ int power_supply_register_extension(struct power_supply *psy, const struct power
|
||||
return 0;
|
||||
|
||||
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;
|
||||
@ -1403,6 +1415,9 @@ void power_supply_unregister_extension(struct power_supply *psy, const struct po
|
||||
power_supply_for_each_extension(reg, psy) {
|
||||
if (reg->ext == ext) {
|
||||
list_del(®->list_head);
|
||||
sysfs_remove_link_from_group(&psy->dev.kobj,
|
||||
power_supply_extension_group.name,
|
||||
reg->ext->name);
|
||||
kfree(reg);
|
||||
power_supply_update_sysfs_and_hwmon(psy);
|
||||
return;
|
||||
|
@ -458,8 +458,18 @@ static const struct attribute_group power_supply_attr_group = {
|
||||
.is_visible = power_supply_attr_is_visible,
|
||||
};
|
||||
|
||||
static struct attribute *power_supply_extension_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct attribute_group power_supply_extension_group = {
|
||||
.name = "extensions",
|
||||
.attrs = power_supply_extension_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *power_supply_attr_groups[] = {
|
||||
&power_supply_attr_group,
|
||||
&power_supply_extension_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -293,6 +293,7 @@ static int test_power_battery_extproperty_is_writeable(struct power_supply *psy,
|
||||
}
|
||||
|
||||
static const struct power_supply_ext test_power_battery_ext = {
|
||||
.name = "test_power",
|
||||
.properties = test_power_battery_extprops,
|
||||
.num_properties = ARRAY_SIZE(test_power_battery_extprops),
|
||||
.get_property = test_power_battery_extget_property,
|
||||
@ -307,7 +308,8 @@ static void test_power_configure_battery_extension(bool enable)
|
||||
psy = test_power_supplies[TEST_BATTERY];
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -286,6 +286,7 @@ struct power_supply_desc {
|
||||
};
|
||||
|
||||
struct power_supply_ext {
|
||||
const char *const name;
|
||||
u8 charge_behaviours;
|
||||
const enum power_supply_property *properties;
|
||||
size_t num_properties;
|
||||
@ -911,6 +912,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);
|
||||
|
Loading…
Reference in New Issue
Block a user