* [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property()
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:56 ` Hans de Goede
2024-09-14 9:30 ` Sebastian Reichel
2024-09-04 19:25 ` [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery Thomas Weißschuh
` (7 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
The function only takes a desc as parameter, align the naming.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/power_supply_core.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 8f6025acd10a..cff68c4fd63c 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -1183,8 +1183,8 @@ bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
}
EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range);
-static bool psy_has_property(const struct power_supply_desc *psy_desc,
- enum power_supply_property psp)
+static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
+ enum power_supply_property psp)
{
bool found = false;
int i;
@@ -1209,7 +1209,7 @@ int power_supply_get_property(struct power_supply *psy,
return -ENODEV;
}
- if (psy_has_property(psy->desc, psp))
+ if (psy_desc_has_property(psy->desc, psp))
return psy->desc->get_property(psy, psp, val);
else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
return power_supply_battery_info_get_prop(psy->battery_info, psp, val);
@@ -1308,7 +1308,7 @@ static int psy_register_thermal(struct power_supply *psy)
return 0;
/* Register battery zone device psy reports temperature */
- if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
+ if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
/* Prefer our hwmon device and avoid duplicates */
struct thermal_zone_params tzp = {
.no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
@@ -1361,7 +1361,7 @@ __power_supply_register(struct device *parent,
pr_warn("%s: Expected proper parent device for '%s'\n",
__func__, desc->name);
- if (psy_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
+ if (psy_desc_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
(!desc->usb_types || !desc->num_usb_types))
return ERR_PTR(-EINVAL);
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property()
2024-09-04 19:25 ` [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property() Thomas Weißschuh
@ 2024-09-04 19:56 ` Hans de Goede
2024-09-14 9:30 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2024-09-04 19:56 UTC (permalink / raw)
To: Thomas Weißschuh, Sebastian Reichel, Armin Wolf
Cc: linux-pm, linux-kernel
Hi,
On 9/4/24 9:25 PM, Thomas Weißschuh wrote:
> The function only takes a desc as parameter, align the naming.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/power/supply/power_supply_core.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index 8f6025acd10a..cff68c4fd63c 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -1183,8 +1183,8 @@ bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
> }
> EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range);
>
> -static bool psy_has_property(const struct power_supply_desc *psy_desc,
> - enum power_supply_property psp)
> +static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> + enum power_supply_property psp)
> {
> bool found = false;
> int i;
> @@ -1209,7 +1209,7 @@ int power_supply_get_property(struct power_supply *psy,
> return -ENODEV;
> }
>
> - if (psy_has_property(psy->desc, psp))
> + if (psy_desc_has_property(psy->desc, psp))
> return psy->desc->get_property(psy, psp, val);
> else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> return power_supply_battery_info_get_prop(psy->battery_info, psp, val);
> @@ -1308,7 +1308,7 @@ static int psy_register_thermal(struct power_supply *psy)
> return 0;
>
> /* Register battery zone device psy reports temperature */
> - if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> + if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> /* Prefer our hwmon device and avoid duplicates */
> struct thermal_zone_params tzp = {
> .no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
> @@ -1361,7 +1361,7 @@ __power_supply_register(struct device *parent,
> pr_warn("%s: Expected proper parent device for '%s'\n",
> __func__, desc->name);
>
> - if (psy_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
> + if (psy_desc_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
> (!desc->usb_types || !desc->num_usb_types))
> return ERR_PTR(-EINVAL);
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property()
2024-09-04 19:25 ` [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property() Thomas Weißschuh
2024-09-04 19:56 ` Hans de Goede
@ 2024-09-14 9:30 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-14 9:30 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2416 bytes --]
Hi,
On Wed, Sep 04, 2024 at 09:25:34PM GMT, Thomas Weißschuh wrote:
> The function only takes a desc as parameter, align the naming.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
too late for 6.12, so
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
-- Sebastian
> drivers/power/supply/power_supply_core.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index 8f6025acd10a..cff68c4fd63c 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -1183,8 +1183,8 @@ bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
> }
> EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range);
>
> -static bool psy_has_property(const struct power_supply_desc *psy_desc,
> - enum power_supply_property psp)
> +static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> + enum power_supply_property psp)
> {
> bool found = false;
> int i;
> @@ -1209,7 +1209,7 @@ int power_supply_get_property(struct power_supply *psy,
> return -ENODEV;
> }
>
> - if (psy_has_property(psy->desc, psp))
> + if (psy_desc_has_property(psy->desc, psp))
> return psy->desc->get_property(psy, psp, val);
> else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> return power_supply_battery_info_get_prop(psy->battery_info, psp, val);
> @@ -1308,7 +1308,7 @@ static int psy_register_thermal(struct power_supply *psy)
> return 0;
>
> /* Register battery zone device psy reports temperature */
> - if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> + if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> /* Prefer our hwmon device and avoid duplicates */
> struct thermal_zone_params tzp = {
> .no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
> @@ -1361,7 +1361,7 @@ __power_supply_register(struct device *parent,
> pr_warn("%s: Expected proper parent device for '%s'\n",
> __func__, desc->name);
>
> - if (psy_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
> + if (psy_desc_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
> (!desc->usb_types || !desc->num_usb_types))
> return ERR_PTR(-EINVAL);
>
>
> --
> 2.46.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
2024-09-04 19:25 ` [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property() Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:56 ` Hans de Goede
2024-09-14 9:29 ` Sebastian Reichel
2024-09-04 19:25 ` [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties Thomas Weißschuh
` (6 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
power_supply_read_team() can also read the temperature from the battery.
But currently when registering the thermal zone, the battery is not
checked for POWER_SUPPLY_PROP_TEMP.
Introduce a helper which can check both the desc and the battery info
for property existence and use that.
Export the helper to the rest of the psy core because it will also be
used by different subcomponents.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/power_supply.h | 3 +++
drivers/power/supply/power_supply_core.c | 14 +++++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
index 3cbafc58bdad..b01faeaf7827 100644
--- a/drivers/power/supply/power_supply.h
+++ b/drivers/power/supply/power_supply.h
@@ -13,6 +13,9 @@ struct device;
struct device_type;
struct power_supply;
+extern bool power_supply_has_property(struct power_supply *psy,
+ enum power_supply_property psp);
+
#ifdef CONFIG_SYSFS
extern void power_supply_init_attrs(void);
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index cff68c4fd63c..dcb7e4853030 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -1199,6 +1199,18 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
return found;
}
+bool power_supply_has_property(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ if (psy_desc_has_property(psy->desc, psp))
+ return true;
+
+ if (power_supply_battery_info_has_prop(psy->battery_info, psp))
+ return true;
+
+ return false;
+}
+
int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -1308,7 +1320,7 @@ static int psy_register_thermal(struct power_supply *psy)
return 0;
/* Register battery zone device psy reports temperature */
- if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
+ if (power_supply_has_property(psy, POWER_SUPPLY_PROP_TEMP)) {
/* Prefer our hwmon device and avoid duplicates */
struct thermal_zone_params tzp = {
.no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery
2024-09-04 19:25 ` [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery Thomas Weißschuh
@ 2024-09-04 19:56 ` Hans de Goede
2024-09-14 9:29 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2024-09-04 19:56 UTC (permalink / raw)
To: Thomas Weißschuh, Sebastian Reichel, Armin Wolf
Cc: linux-pm, linux-kernel
Hi,
On 9/4/24 9:25 PM, Thomas Weißschuh wrote:
> power_supply_read_team() can also read the temperature from the battery.
> But currently when registering the thermal zone, the battery is not
> checked for POWER_SUPPLY_PROP_TEMP.
> Introduce a helper which can check both the desc and the battery info
> for property existence and use that.
> Export the helper to the rest of the psy core because it will also be
> used by different subcomponents.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/power/supply/power_supply.h | 3 +++
> drivers/power/supply/power_supply_core.c | 14 +++++++++++++-
> 2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
> index 3cbafc58bdad..b01faeaf7827 100644
> --- a/drivers/power/supply/power_supply.h
> +++ b/drivers/power/supply/power_supply.h
> @@ -13,6 +13,9 @@ struct device;
> struct device_type;
> struct power_supply;
>
> +extern bool power_supply_has_property(struct power_supply *psy,
> + enum power_supply_property psp);
> +
> #ifdef CONFIG_SYSFS
>
> extern void power_supply_init_attrs(void);
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index cff68c4fd63c..dcb7e4853030 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -1199,6 +1199,18 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> return found;
> }
>
> +bool power_supply_has_property(struct power_supply *psy,
> + enum power_supply_property psp)
> +{
> + if (psy_desc_has_property(psy->desc, psp))
> + return true;
> +
> + if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> + return true;
> +
> + return false;
> +}
> +
> int power_supply_get_property(struct power_supply *psy,
> enum power_supply_property psp,
> union power_supply_propval *val)
> @@ -1308,7 +1320,7 @@ static int psy_register_thermal(struct power_supply *psy)
> return 0;
>
> /* Register battery zone device psy reports temperature */
> - if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> + if (power_supply_has_property(psy, POWER_SUPPLY_PROP_TEMP)) {
> /* Prefer our hwmon device and avoid duplicates */
> struct thermal_zone_params tzp = {
> .no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
>
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery
2024-09-04 19:25 ` [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery Thomas Weißschuh
2024-09-04 19:56 ` Hans de Goede
@ 2024-09-14 9:29 ` Sebastian Reichel
2024-09-14 9:55 ` Thomas Weißschuh
1 sibling, 1 reply; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-14 9:29 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2916 bytes --]
Hi,
On Wed, Sep 04, 2024 at 09:25:35PM GMT, Thomas Weißschuh wrote:
> power_supply_read_team() can also read the temperature from the battery.
power_supply_read_temp()
> But currently when registering the thermal zone, the battery is
> not checked for POWER_SUPPLY_PROP_TEMP. Introduce a helper which
> can check both the desc and the battery info for property
> existence and use that. Export the helper to the rest of the psy
> core because it will also be used by different subcomponents.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
power_supply_battery_info contains constant battery information like
design capacity or maximum voltage, which is e.g. supplied by the
firmware and needed by fuel-gauges or chargers. The temperature is
not constant and cannot be part of power_supply_battery_info, so
this does not really make sense.
Greetings,
-- Sebastian
> drivers/power/supply/power_supply.h | 3 +++
> drivers/power/supply/power_supply_core.c | 14 +++++++++++++-
> 2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
> index 3cbafc58bdad..b01faeaf7827 100644
> --- a/drivers/power/supply/power_supply.h
> +++ b/drivers/power/supply/power_supply.h
> @@ -13,6 +13,9 @@ struct device;
> struct device_type;
> struct power_supply;
>
> +extern bool power_supply_has_property(struct power_supply *psy,
> + enum power_supply_property psp);
> +
> #ifdef CONFIG_SYSFS
>
> extern void power_supply_init_attrs(void);
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index cff68c4fd63c..dcb7e4853030 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -1199,6 +1199,18 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> return found;
> }
>
> +bool power_supply_has_property(struct power_supply *psy,
> + enum power_supply_property psp)
> +{
> + if (psy_desc_has_property(psy->desc, psp))
> + return true;
> +
> + if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> + return true;
> +
> + return false;
> +}
> +
> int power_supply_get_property(struct power_supply *psy,
> enum power_supply_property psp,
> union power_supply_propval *val)
> @@ -1308,7 +1320,7 @@ static int psy_register_thermal(struct power_supply *psy)
> return 0;
>
> /* Register battery zone device psy reports temperature */
> - if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> + if (power_supply_has_property(psy, POWER_SUPPLY_PROP_TEMP)) {
> /* Prefer our hwmon device and avoid duplicates */
> struct thermal_zone_params tzp = {
> .no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
>
> --
> 2.46.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery
2024-09-14 9:29 ` Sebastian Reichel
@ 2024-09-14 9:55 ` Thomas Weißschuh
0 siblings, 0 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-14 9:55 UTC (permalink / raw)
To: Sebastian Reichel; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
Hi,
On 2024-09-14 11:29:04+0000, Sebastian Reichel wrote:
> On Wed, Sep 04, 2024 at 09:25:35PM GMT, Thomas Weißschuh wrote:
> > power_supply_read_team() can also read the temperature from the battery.
> power_supply_read_temp()
>
> > But currently when registering the thermal zone, the battery is
> > not checked for POWER_SUPPLY_PROP_TEMP. Introduce a helper which
> > can check both the desc and the battery info for property
> > existence and use that. Export the helper to the rest of the psy
> > core because it will also be used by different subcomponents.
> >
> > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> > ---
>
> power_supply_battery_info contains constant battery information like
> design capacity or maximum voltage, which is e.g. supplied by the
> firmware and needed by fuel-gauges or chargers. The temperature is
> not constant and cannot be part of power_supply_battery_info, so
> this does not really make sense.
Good point. Also this code will run before the extensions will be
registered, so it doesn't make sense for that either.
I'll change the patch to only introduce power_supply_has_property().
>
> Greetings,
>
> -- Sebastian
>
> > drivers/power/supply/power_supply.h | 3 +++
> > drivers/power/supply/power_supply_core.c | 14 +++++++++++++-
> > 2 files changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
> > index 3cbafc58bdad..b01faeaf7827 100644
> > --- a/drivers/power/supply/power_supply.h
> > +++ b/drivers/power/supply/power_supply.h
> > @@ -13,6 +13,9 @@ struct device;
> > struct device_type;
> > struct power_supply;
> >
> > +extern bool power_supply_has_property(struct power_supply *psy,
> > + enum power_supply_property psp);
> > +
> > #ifdef CONFIG_SYSFS
> >
> > extern void power_supply_init_attrs(void);
> > diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> > index cff68c4fd63c..dcb7e4853030 100644
> > --- a/drivers/power/supply/power_supply_core.c
> > +++ b/drivers/power/supply/power_supply_core.c
> > @@ -1199,6 +1199,18 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> > return found;
> > }
> >
> > +bool power_supply_has_property(struct power_supply *psy,
> > + enum power_supply_property psp)
> > +{
> > + if (psy_desc_has_property(psy->desc, psp))
> > + return true;
> > +
> > + if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> > + return true;
> > +
> > + return false;
> > +}
> > +
> > int power_supply_get_property(struct power_supply *psy,
> > enum power_supply_property psp,
> > union power_supply_propval *val)
> > @@ -1308,7 +1320,7 @@ static int psy_register_thermal(struct power_supply *psy)
> > return 0;
> >
> > /* Register battery zone device psy reports temperature */
> > - if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
> > + if (power_supply_has_property(psy, POWER_SUPPLY_PROP_TEMP)) {
> > /* Prefer our hwmon device and avoid duplicates */
> > struct thermal_zone_params tzp = {
> > .no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
> >
> > --
> > 2.46.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
2024-09-04 19:25 ` [PATCH RFC v3 1/9] power: supply: core: rename psy_has_property() to psy_desc_has_property() Thomas Weißschuh
2024-09-04 19:25 ` [PATCH RFC v3 2/9] power: supply: core: register thermal zone for battery Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:57 ` Hans de Goede
2024-09-14 9:35 ` Sebastian Reichel
2024-09-04 19:25 ` [PATCH RFC v3 4/9] power: supply: sysfs: " Thomas Weißschuh
` (5 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Instead of only registering properties from the psy_desc itself,
also register the ones from the battery.
Use power_supply_has_property() for this test which makes the logic also
easier to read.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/power_supply_hwmon.c | 52 +++++++++++++++----------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c
index baacefbdf768..1c1ad3e1d81f 100644
--- a/drivers/power/supply/power_supply_hwmon.c
+++ b/drivers/power/supply/power_supply_hwmon.c
@@ -8,6 +8,8 @@
#include <linux/power_supply.h>
#include <linux/slab.h>
+#include "power_supply.h"
+
struct power_supply_hwmon {
struct power_supply *psy;
unsigned long *props;
@@ -347,9 +349,28 @@ static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
.info = power_supply_hwmon_info,
};
+static const enum power_supply_property power_supply_hwmon_props[] = {
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_POWER_AVG,
+ POWER_SUPPLY_PROP_POWER_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_MAX,
+ POWER_SUPPLY_PROP_TEMP_MIN,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
int power_supply_add_hwmon_sysfs(struct power_supply *psy)
{
- const struct power_supply_desc *desc = psy->desc;
struct power_supply_hwmon *psyhw;
struct device *dev = &psy->dev;
struct device *hwmon;
@@ -375,32 +396,11 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
goto error;
}
- for (i = 0; i < desc->num_properties; i++) {
- const enum power_supply_property prop = desc->properties[i];
-
- switch (prop) {
- case POWER_SUPPLY_PROP_CURRENT_AVG:
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- case POWER_SUPPLY_PROP_POWER_AVG:
- case POWER_SUPPLY_PROP_POWER_NOW:
- case POWER_SUPPLY_PROP_TEMP:
- case POWER_SUPPLY_PROP_TEMP_MAX:
- case POWER_SUPPLY_PROP_TEMP_MIN:
- case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
- case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
- case POWER_SUPPLY_PROP_TEMP_AMBIENT:
- case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
- case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- case POWER_SUPPLY_PROP_VOLTAGE_MIN:
- case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ for (i = 0; i < ARRAY_SIZE(power_supply_hwmon_props); i++) {
+ const enum power_supply_property prop = power_supply_hwmon_props[i];
+
+ if (power_supply_has_property(psy, prop))
set_bit(prop, psyhw->props);
- break;
- default:
- break;
- }
}
name = psy->desc->name;
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties
2024-09-04 19:25 ` [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties Thomas Weißschuh
@ 2024-09-04 19:57 ` Hans de Goede
2024-09-14 9:35 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2024-09-04 19:57 UTC (permalink / raw)
To: Thomas Weißschuh, Sebastian Reichel, Armin Wolf
Cc: linux-pm, linux-kernel
Hi,
On 9/4/24 9:25 PM, Thomas Weißschuh wrote:
> Instead of only registering properties from the psy_desc itself,
> also register the ones from the battery.
> Use power_supply_has_property() for this test which makes the logic also
> easier to read.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/power/supply/power_supply_hwmon.c | 52 +++++++++++++++----------------
> 1 file changed, 26 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c
> index baacefbdf768..1c1ad3e1d81f 100644
> --- a/drivers/power/supply/power_supply_hwmon.c
> +++ b/drivers/power/supply/power_supply_hwmon.c
> @@ -8,6 +8,8 @@
> #include <linux/power_supply.h>
> #include <linux/slab.h>
>
> +#include "power_supply.h"
> +
> struct power_supply_hwmon {
> struct power_supply *psy;
> unsigned long *props;
> @@ -347,9 +349,28 @@ static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
> .info = power_supply_hwmon_info,
> };
>
> +static const enum power_supply_property power_supply_hwmon_props[] = {
> + POWER_SUPPLY_PROP_CURRENT_AVG,
> + POWER_SUPPLY_PROP_CURRENT_MAX,
> + POWER_SUPPLY_PROP_CURRENT_NOW,
> + POWER_SUPPLY_PROP_POWER_AVG,
> + POWER_SUPPLY_PROP_POWER_NOW,
> + POWER_SUPPLY_PROP_TEMP,
> + POWER_SUPPLY_PROP_TEMP_MAX,
> + POWER_SUPPLY_PROP_TEMP_MIN,
> + POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
> + POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
> + POWER_SUPPLY_PROP_TEMP_AMBIENT,
> + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
> + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
> + POWER_SUPPLY_PROP_VOLTAGE_AVG,
> + POWER_SUPPLY_PROP_VOLTAGE_MIN,
> + POWER_SUPPLY_PROP_VOLTAGE_MAX,
> + POWER_SUPPLY_PROP_VOLTAGE_NOW,
> +};
> +
> int power_supply_add_hwmon_sysfs(struct power_supply *psy)
> {
> - const struct power_supply_desc *desc = psy->desc;
> struct power_supply_hwmon *psyhw;
> struct device *dev = &psy->dev;
> struct device *hwmon;
> @@ -375,32 +396,11 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
> goto error;
> }
>
> - for (i = 0; i < desc->num_properties; i++) {
> - const enum power_supply_property prop = desc->properties[i];
> -
> - switch (prop) {
> - case POWER_SUPPLY_PROP_CURRENT_AVG:
> - case POWER_SUPPLY_PROP_CURRENT_MAX:
> - case POWER_SUPPLY_PROP_CURRENT_NOW:
> - case POWER_SUPPLY_PROP_POWER_AVG:
> - case POWER_SUPPLY_PROP_POWER_NOW:
> - case POWER_SUPPLY_PROP_TEMP:
> - case POWER_SUPPLY_PROP_TEMP_MAX:
> - case POWER_SUPPLY_PROP_TEMP_MIN:
> - case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
> - case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
> - case POWER_SUPPLY_PROP_TEMP_AMBIENT:
> - case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
> - case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
> - case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> - case POWER_SUPPLY_PROP_VOLTAGE_MIN:
> - case POWER_SUPPLY_PROP_VOLTAGE_MAX:
> - case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> + for (i = 0; i < ARRAY_SIZE(power_supply_hwmon_props); i++) {
> + const enum power_supply_property prop = power_supply_hwmon_props[i];
> +
> + if (power_supply_has_property(psy, prop))
> set_bit(prop, psyhw->props);
> - break;
> - default:
> - break;
> - }
> }
>
> name = psy->desc->name;
>
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties
2024-09-04 19:25 ` [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties Thomas Weißschuh
2024-09-04 19:57 ` Hans de Goede
@ 2024-09-14 9:35 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-14 9:35 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 3465 bytes --]
Hi,
On Wed, Sep 04, 2024 at 09:25:36PM GMT, Thomas Weißschuh wrote:
> Instead of only registering properties from the psy_desc itself,
> also register the ones from the battery.
> Use power_supply_has_property() for this test which makes the logic also
> easier to read.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Greetings,
-- Sebastian
> drivers/power/supply/power_supply_hwmon.c | 52 +++++++++++++++----------------
> 1 file changed, 26 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c
> index baacefbdf768..1c1ad3e1d81f 100644
> --- a/drivers/power/supply/power_supply_hwmon.c
> +++ b/drivers/power/supply/power_supply_hwmon.c
> @@ -8,6 +8,8 @@
> #include <linux/power_supply.h>
> #include <linux/slab.h>
>
> +#include "power_supply.h"
> +
> struct power_supply_hwmon {
> struct power_supply *psy;
> unsigned long *props;
> @@ -347,9 +349,28 @@ static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
> .info = power_supply_hwmon_info,
> };
>
> +static const enum power_supply_property power_supply_hwmon_props[] = {
> + POWER_SUPPLY_PROP_CURRENT_AVG,
> + POWER_SUPPLY_PROP_CURRENT_MAX,
> + POWER_SUPPLY_PROP_CURRENT_NOW,
> + POWER_SUPPLY_PROP_POWER_AVG,
> + POWER_SUPPLY_PROP_POWER_NOW,
> + POWER_SUPPLY_PROP_TEMP,
> + POWER_SUPPLY_PROP_TEMP_MAX,
> + POWER_SUPPLY_PROP_TEMP_MIN,
> + POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
> + POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
> + POWER_SUPPLY_PROP_TEMP_AMBIENT,
> + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
> + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
> + POWER_SUPPLY_PROP_VOLTAGE_AVG,
> + POWER_SUPPLY_PROP_VOLTAGE_MIN,
> + POWER_SUPPLY_PROP_VOLTAGE_MAX,
> + POWER_SUPPLY_PROP_VOLTAGE_NOW,
> +};
> +
> int power_supply_add_hwmon_sysfs(struct power_supply *psy)
> {
> - const struct power_supply_desc *desc = psy->desc;
> struct power_supply_hwmon *psyhw;
> struct device *dev = &psy->dev;
> struct device *hwmon;
> @@ -375,32 +396,11 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
> goto error;
> }
>
> - for (i = 0; i < desc->num_properties; i++) {
> - const enum power_supply_property prop = desc->properties[i];
> -
> - switch (prop) {
> - case POWER_SUPPLY_PROP_CURRENT_AVG:
> - case POWER_SUPPLY_PROP_CURRENT_MAX:
> - case POWER_SUPPLY_PROP_CURRENT_NOW:
> - case POWER_SUPPLY_PROP_POWER_AVG:
> - case POWER_SUPPLY_PROP_POWER_NOW:
> - case POWER_SUPPLY_PROP_TEMP:
> - case POWER_SUPPLY_PROP_TEMP_MAX:
> - case POWER_SUPPLY_PROP_TEMP_MIN:
> - case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
> - case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
> - case POWER_SUPPLY_PROP_TEMP_AMBIENT:
> - case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
> - case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
> - case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> - case POWER_SUPPLY_PROP_VOLTAGE_MIN:
> - case POWER_SUPPLY_PROP_VOLTAGE_MAX:
> - case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> + for (i = 0; i < ARRAY_SIZE(power_supply_hwmon_props); i++) {
> + const enum power_supply_property prop = power_supply_hwmon_props[i];
> +
> + if (power_supply_has_property(psy, prop))
> set_bit(prop, psyhw->props);
> - break;
> - default:
> - break;
> - }
> }
>
> name = psy->desc->name;
>
> --
> 2.46.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH RFC v3 4/9] power: supply: sysfs: register battery properties
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
` (2 preceding siblings ...)
2024-09-04 19:25 ` [PATCH RFC v3 3/9] power: supply: hwmon: register battery properties Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:57 ` Hans de Goede
2024-09-14 9:43 ` Sebastian Reichel
2024-09-04 19:25 ` [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop Thomas Weißschuh
` (4 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Instead of only registering properties from the psy_desc itself,
also register the ones from the battery.
Use power_supply_has_property() for this test which makes the logic also
easier to read.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/power_supply_sysfs.c | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 3e63d165b2f7..4ab08386bcb7 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -367,7 +367,6 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
struct device *dev = kobj_to_dev(kobj);
struct power_supply *psy = dev_get_drvdata(dev);
umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
- int i;
if (!power_supply_attrs[attrno].prop_name)
return 0;
@@ -375,19 +374,11 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
if (attrno == POWER_SUPPLY_PROP_TYPE)
return mode;
- for (i = 0; i < psy->desc->num_properties; i++) {
- int property = psy->desc->properties[i];
-
- if (property == attrno) {
- if (power_supply_property_is_writeable(psy, property) > 0)
- mode |= S_IWUSR;
-
- return mode;
- }
- }
-
- if (power_supply_battery_info_has_prop(psy->battery_info, attrno))
+ if (power_supply_has_property(psy, attrno)) {
+ if (power_supply_property_is_writeable(psy, attrno) > 0)
+ mode |= S_IWUSR;
return mode;
+ }
return 0;
}
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 4/9] power: supply: sysfs: register battery properties
2024-09-04 19:25 ` [PATCH RFC v3 4/9] power: supply: sysfs: " Thomas Weißschuh
@ 2024-09-04 19:57 ` Hans de Goede
2024-09-14 9:43 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2024-09-04 19:57 UTC (permalink / raw)
To: Thomas Weißschuh, Sebastian Reichel, Armin Wolf
Cc: linux-pm, linux-kernel
Hi,
On 9/4/24 9:25 PM, Thomas Weißschuh wrote:
> Instead of only registering properties from the psy_desc itself,
> also register the ones from the battery.
> Use power_supply_has_property() for this test which makes the logic also
> easier to read.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/power/supply/power_supply_sysfs.c | 17 ++++-------------
> 1 file changed, 4 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> index 3e63d165b2f7..4ab08386bcb7 100644
> --- a/drivers/power/supply/power_supply_sysfs.c
> +++ b/drivers/power/supply/power_supply_sysfs.c
> @@ -367,7 +367,6 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
> struct device *dev = kobj_to_dev(kobj);
> struct power_supply *psy = dev_get_drvdata(dev);
> umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
> - int i;
>
> if (!power_supply_attrs[attrno].prop_name)
> return 0;
> @@ -375,19 +374,11 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
> if (attrno == POWER_SUPPLY_PROP_TYPE)
> return mode;
>
> - for (i = 0; i < psy->desc->num_properties; i++) {
> - int property = psy->desc->properties[i];
> -
> - if (property == attrno) {
> - if (power_supply_property_is_writeable(psy, property) > 0)
> - mode |= S_IWUSR;
> -
> - return mode;
> - }
> - }
> -
> - if (power_supply_battery_info_has_prop(psy->battery_info, attrno))
> + if (power_supply_has_property(psy, attrno)) {
> + if (power_supply_property_is_writeable(psy, attrno) > 0)
> + mode |= S_IWUSR;
> return mode;
> + }
>
> return 0;
> }
>
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 4/9] power: supply: sysfs: register battery properties
2024-09-04 19:25 ` [PATCH RFC v3 4/9] power: supply: sysfs: " Thomas Weißschuh
2024-09-04 19:57 ` Hans de Goede
@ 2024-09-14 9:43 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-14 9:43 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1913 bytes --]
Hi,
On Wed, Sep 04, 2024 at 09:25:37PM GMT, Thomas Weißschuh wrote:
> Instead of only registering properties from the psy_desc itself,
> also register the ones from the battery.
> Use power_supply_has_property() for this test which makes the logic also
> easier to read.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
The properties from the battery_info are already registered, so this
"just" simplifies the logic. Otherwise LGTM.
Greetings,
-- Sebastian
> drivers/power/supply/power_supply_sysfs.c | 17 ++++-------------
> 1 file changed, 4 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> index 3e63d165b2f7..4ab08386bcb7 100644
> --- a/drivers/power/supply/power_supply_sysfs.c
> +++ b/drivers/power/supply/power_supply_sysfs.c
> @@ -367,7 +367,6 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
> struct device *dev = kobj_to_dev(kobj);
> struct power_supply *psy = dev_get_drvdata(dev);
> umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
> - int i;
>
> if (!power_supply_attrs[attrno].prop_name)
> return 0;
> @@ -375,19 +374,11 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
> if (attrno == POWER_SUPPLY_PROP_TYPE)
> return mode;
>
> - for (i = 0; i < psy->desc->num_properties; i++) {
> - int property = psy->desc->properties[i];
> -
> - if (property == attrno) {
> - if (power_supply_property_is_writeable(psy, property) > 0)
> - mode |= S_IWUSR;
> -
> - return mode;
> - }
> - }
> -
> - if (power_supply_battery_info_has_prop(psy->battery_info, attrno))
> + if (power_supply_has_property(psy, attrno)) {
> + if (power_supply_property_is_writeable(psy, attrno) > 0)
> + mode |= S_IWUSR;
> return mode;
> + }
>
> return 0;
> }
>
> --
> 2.46.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
` (3 preceding siblings ...)
2024-09-04 19:25 ` [PATCH RFC v3 4/9] power: supply: sysfs: " Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:58 ` Hans de Goede
2024-09-14 9:59 ` Sebastian Reichel
2024-09-04 19:25 ` [PATCH RFC v3 6/9] power: supply: core: implement extension API Thomas Weißschuh
` (3 subsequent siblings)
8 siblings, 2 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Instead of looping through all properties known to be supported by the
psy, loop over all known properties and decide based on the return value
of power_supply_get_property() whether the property existed.
This makes the code shorter now and even more so when power supply
extensions are added.
It also simplifies the locking, as it can all happen inside
power_supply_get_property().
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/power_supply_sysfs.c | 26 +++++---------------------
1 file changed, 5 insertions(+), 21 deletions(-)
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 4ab08386bcb7..915a4ba62258 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -290,6 +290,8 @@ static ssize_t power_supply_show_property(struct device *dev,
dev_dbg_ratelimited(dev,
"driver has no data for `%s' property\n",
attr->attr.name);
+ else if (ret == -EINVAL) /* property is not supported */
+ return -ENODATA;
else if (ret != -ENODEV && ret != -EAGAIN)
dev_err_ratelimited(dev,
"driver failed to report `%s' property: %zd\n",
@@ -451,11 +453,7 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env
int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- const struct power_supply *psy = dev_get_drvdata(dev);
- const enum power_supply_property *battery_props =
- power_supply_battery_info_properties;
- unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT /
- sizeof(unsigned long) + 1] = {0};
+ struct power_supply *psy = dev_get_drvdata(dev);
int ret = 0, j;
char *prop_buf;
@@ -483,22 +481,8 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
if (ret)
goto out;
- for (j = 0; j < psy->desc->num_properties; j++) {
- set_bit(psy->desc->properties[j], psy_drv_properties);
- ret = add_prop_uevent(dev, env, psy->desc->properties[j],
- prop_buf);
- if (ret)
- goto out;
- }
-
- for (j = 0; j < power_supply_battery_info_properties_size; j++) {
- if (test_bit(battery_props[j], psy_drv_properties))
- continue;
- if (!power_supply_battery_info_has_prop(psy->battery_info,
- battery_props[j]))
- continue;
- ret = add_prop_uevent(dev, env, battery_props[j],
- prop_buf);
+ for (j = 0; j < POWER_SUPPLY_ATTR_CNT; j++) {
+ ret = add_prop_uevent(dev, env, j, prop_buf);
if (ret)
goto out;
}
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop
2024-09-04 19:25 ` [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop Thomas Weißschuh
@ 2024-09-04 19:58 ` Hans de Goede
2024-09-14 9:59 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2024-09-04 19:58 UTC (permalink / raw)
To: Thomas Weißschuh, Sebastian Reichel, Armin Wolf
Cc: linux-pm, linux-kernel
Hi,
On 9/4/24 9:25 PM, Thomas Weißschuh wrote:
> Instead of looping through all properties known to be supported by the
> psy, loop over all known properties and decide based on the return value
> of power_supply_get_property() whether the property existed.
>
> This makes the code shorter now and even more so when power supply
> extensions are added.
> It also simplifies the locking, as it can all happen inside
> power_supply_get_property().
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
p.s.
Last review for me in this set. I'm afraid I don't have the bandwidth
atm to also review the actual extension API.
> ---
> drivers/power/supply/power_supply_sysfs.c | 26 +++++---------------------
> 1 file changed, 5 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> index 4ab08386bcb7..915a4ba62258 100644
> --- a/drivers/power/supply/power_supply_sysfs.c
> +++ b/drivers/power/supply/power_supply_sysfs.c
> @@ -290,6 +290,8 @@ static ssize_t power_supply_show_property(struct device *dev,
> dev_dbg_ratelimited(dev,
> "driver has no data for `%s' property\n",
> attr->attr.name);
> + else if (ret == -EINVAL) /* property is not supported */
> + return -ENODATA;
> else if (ret != -ENODEV && ret != -EAGAIN)
> dev_err_ratelimited(dev,
> "driver failed to report `%s' property: %zd\n",
> @@ -451,11 +453,7 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env
>
> int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
> {
> - const struct power_supply *psy = dev_get_drvdata(dev);
> - const enum power_supply_property *battery_props =
> - power_supply_battery_info_properties;
> - unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT /
> - sizeof(unsigned long) + 1] = {0};
> + struct power_supply *psy = dev_get_drvdata(dev);
> int ret = 0, j;
> char *prop_buf;
>
> @@ -483,22 +481,8 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
> if (ret)
> goto out;
>
> - for (j = 0; j < psy->desc->num_properties; j++) {
> - set_bit(psy->desc->properties[j], psy_drv_properties);
> - ret = add_prop_uevent(dev, env, psy->desc->properties[j],
> - prop_buf);
> - if (ret)
> - goto out;
> - }
> -
> - for (j = 0; j < power_supply_battery_info_properties_size; j++) {
> - if (test_bit(battery_props[j], psy_drv_properties))
> - continue;
> - if (!power_supply_battery_info_has_prop(psy->battery_info,
> - battery_props[j]))
> - continue;
> - ret = add_prop_uevent(dev, env, battery_props[j],
> - prop_buf);
> + for (j = 0; j < POWER_SUPPLY_ATTR_CNT; j++) {
> + ret = add_prop_uevent(dev, env, j, prop_buf);
> if (ret)
> goto out;
> }
>
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop
2024-09-04 19:25 ` [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop Thomas Weißschuh
2024-09-04 19:58 ` Hans de Goede
@ 2024-09-14 9:59 ` Sebastian Reichel
1 sibling, 0 replies; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-14 9:59 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 3150 bytes --]
Hi,
On Wed, Sep 04, 2024 at 09:25:38PM GMT, Thomas Weißschuh wrote:
> Instead of looping through all properties known to be supported by the
> psy, loop over all known properties and decide based on the return value
> of power_supply_get_property() whether the property existed.
>
> This makes the code shorter now and even more so when power supply
> extensions are added.
> It also simplifies the locking, as it can all happen inside
> power_supply_get_property().
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
> drivers/power/supply/power_supply_sysfs.c | 26 +++++---------------------
> 1 file changed, 5 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> index 4ab08386bcb7..915a4ba62258 100644
> --- a/drivers/power/supply/power_supply_sysfs.c
> +++ b/drivers/power/supply/power_supply_sysfs.c
> @@ -290,6 +290,8 @@ static ssize_t power_supply_show_property(struct device *dev,
> dev_dbg_ratelimited(dev,
> "driver has no data for `%s' property\n",
> attr->attr.name);
> + else if (ret == -EINVAL) /* property is not supported */
> + return -ENODATA;
I think it's better to update the check in add_prop_uevent, so that
it also skips -EINVAL. That way sysfs still exposes the correct
error code.
Otherwise LGTM, even though I wonder about the performance impact of
this change. I suppose this is not called often enough to really
matter, though.
Greetings,
-- Sebastian
> else if (ret != -ENODEV && ret != -EAGAIN)
> dev_err_ratelimited(dev,
> "driver failed to report `%s' property: %zd\n",
> @@ -451,11 +453,7 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env
>
> int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
> {
> - const struct power_supply *psy = dev_get_drvdata(dev);
> - const enum power_supply_property *battery_props =
> - power_supply_battery_info_properties;
> - unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT /
> - sizeof(unsigned long) + 1] = {0};
> + struct power_supply *psy = dev_get_drvdata(dev);
> int ret = 0, j;
> char *prop_buf;
>
> @@ -483,22 +481,8 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
> if (ret)
> goto out;
>
> - for (j = 0; j < psy->desc->num_properties; j++) {
> - set_bit(psy->desc->properties[j], psy_drv_properties);
> - ret = add_prop_uevent(dev, env, psy->desc->properties[j],
> - prop_buf);
> - if (ret)
> - goto out;
> - }
> -
> - for (j = 0; j < power_supply_battery_info_properties_size; j++) {
> - if (test_bit(battery_props[j], psy_drv_properties))
> - continue;
> - if (!power_supply_battery_info_has_prop(psy->battery_info,
> - battery_props[j]))
> - continue;
> - ret = add_prop_uevent(dev, env, battery_props[j],
> - prop_buf);
> + for (j = 0; j < POWER_SUPPLY_ATTR_CNT; j++) {
> + ret = add_prop_uevent(dev, env, j, prop_buf);
> if (ret)
> goto out;
> }
>
> --
> 2.46.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH RFC v3 6/9] power: supply: core: implement extension API
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
` (4 preceding siblings ...)
2024-09-04 19:25 ` [PATCH RFC v3 5/9] power: supply: sysfs: rework uevent property loop Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-14 10:50 ` Sebastian Reichel
2024-09-04 19:25 ` [PATCH RFC v3 7/9] power: supply: core: add locking around extension access Thomas Weißschuh
` (2 subsequent siblings)
8 siblings, 1 reply; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/power_supply.h | 12 ++++
drivers/power/supply/power_supply_core.c | 114 +++++++++++++++++++++++++++++-
drivers/power/supply/power_supply_sysfs.c | 20 +++++-
include/linux/power_supply.h | 30 ++++++++
4 files changed, 171 insertions(+), 5 deletions(-)
diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
index b01faeaf7827..fb45f0717bd1 100644
--- a/drivers/power/supply/power_supply.h
+++ b/drivers/power/supply/power_supply.h
@@ -15,6 +15,18 @@ struct power_supply;
extern bool power_supply_has_property(struct power_supply *psy,
enum power_supply_property psp);
+extern bool power_supply_ext_has_property(const struct power_supply_ext *ext,
+ enum power_supply_property psp);
+
+struct power_supply_ext_registration {
+ struct list_head list_head;
+ const struct power_supply_ext *ext;
+ void *data;
+};
+
+#define power_supply_for_each_extension(pos, psy) \
+ list_for_each_entry(pos, &(psy)->extensions, list_head)
+
#ifdef CONFIG_SYSFS
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index dcb7e4853030..db5e7af57e67 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -1199,15 +1199,40 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
return found;
}
+bool power_supply_ext_has_property(const struct power_supply_ext *psy_ext,
+ enum power_supply_property psp)
+{
+ bool found = false;
+ int i;
+
+ if (!psy_ext)
+ return false;
+
+ for (i = 0; i < psy_ext->num_properties; i++) {
+ if (psy_ext->properties[i] == psp) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
bool power_supply_has_property(struct power_supply *psy,
enum power_supply_property psp)
{
+ struct power_supply_ext_registration *reg;
+
if (psy_desc_has_property(psy->desc, psp))
return true;
if (power_supply_battery_info_has_prop(psy->battery_info, psp))
return true;
+ power_supply_for_each_extension(reg, psy)
+ if (power_supply_ext_has_property(reg->ext, psp))
+ return true;
+
return false;
}
@@ -1215,12 +1240,19 @@ int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
+ struct power_supply_ext_registration *reg;
+
if (atomic_read(&psy->use_cnt) <= 0) {
if (!psy->initialized)
return -EAGAIN;
return -ENODEV;
}
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp))
+ return reg->ext->get_property(psy, reg->ext, reg->data, psp, val);
+ }
+
if (psy_desc_has_property(psy->desc, psp))
return psy->desc->get_property(psy, psp, val);
else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
@@ -1234,7 +1266,21 @@ int power_supply_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
- if (atomic_read(&psy->use_cnt) <= 0 || !psy->desc->set_property)
+ struct power_supply_ext_registration *reg;
+
+ if (atomic_read(&psy->use_cnt) <= 0)
+ return -ENODEV;
+
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp)) {
+ if (reg->ext->set_property)
+ return reg->ext->set_property(psy, reg->ext, reg->data, psp, val);
+ else
+ return -ENODEV;
+ }
+ }
+
+ if (!psy->desc->set_property)
return -ENODEV;
return psy->desc->set_property(psy, psp, val);
@@ -1244,8 +1290,21 @@ EXPORT_SYMBOL_GPL(power_supply_set_property);
int power_supply_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
- if (atomic_read(&psy->use_cnt) <= 0 ||
- !psy->desc->property_is_writeable)
+ struct power_supply_ext_registration *reg;
+
+ if (atomic_read(&psy->use_cnt) <= 0)
+ return -ENODEV;
+
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp)) {
+ if (reg->ext->property_is_writeable)
+ return reg->ext->property_is_writeable(psy, reg->ext, reg->data, psp);
+ else
+ return -ENODEV;
+ }
+ }
+
+ if (!psy->desc->property_is_writeable)
return -ENODEV;
return psy->desc->property_is_writeable(psy, psp);
@@ -1268,6 +1327,54 @@ int power_supply_powers(struct power_supply *psy, struct device *dev)
}
EXPORT_SYMBOL_GPL(power_supply_powers);
+static int power_supply_update_groups(struct power_supply *psy)
+{
+ int ret;
+
+ ret = sysfs_update_groups(&psy->dev.kobj, power_supply_dev_type.groups);
+ power_supply_changed(psy);
+ return ret;
+}
+
+int power_supply_register_extension(struct power_supply *psy, const struct power_supply_ext *ext,
+ void *ext_data)
+{
+ struct power_supply_ext_registration *reg;
+ size_t i;
+
+ for (i = 0; i < ext->num_properties; i++) {
+ if (power_supply_has_property(psy, ext->properties[i]))
+ return -EEXIST;
+ }
+
+ reg = kmalloc(sizeof(*reg), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ reg->ext = ext;
+ list_add(®->list_head, &psy->extensions);
+
+ return power_supply_update_groups(psy);
+}
+EXPORT_SYMBOL_GPL(power_supply_register_extension);
+
+void power_supply_unregister_extension(struct power_supply *psy, const struct power_supply_ext *ext)
+{
+ struct power_supply_ext_registration *reg;
+
+ power_supply_for_each_extension(reg, psy) {
+ if (reg->ext == ext) {
+ list_del(®->list_head);
+ kfree(reg);
+ power_supply_update_groups(psy);
+ return;
+ }
+ }
+
+ dev_warn(&psy->dev, "Trying to unregister invalid extension");
+}
+EXPORT_SYMBOL_GPL(power_supply_unregister_extension);
+
static void power_supply_dev_release(struct device *dev)
{
struct power_supply *psy = to_power_supply(dev);
@@ -1427,6 +1534,7 @@ __power_supply_register(struct device *parent,
}
spin_lock_init(&psy->changed_lock);
+ INIT_LIST_HEAD(&psy->extensions);
rc = device_add(dev);
if (rc)
goto device_add_failed;
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 915a4ba62258..e7c306afd846 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -271,6 +271,23 @@ static ssize_t power_supply_show_usb_type(struct device *dev,
return count;
}
+static ssize_t power_supply_show_charge_behaviour(struct device *dev,
+ struct power_supply *psy,
+ union power_supply_propval *value,
+ char *buf)
+{
+ struct power_supply_ext_registration *reg;
+
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR))
+ return power_supply_charge_behaviour_show(dev, reg->ext->charge_behaviours,
+ value->intval, buf);
+ }
+
+ return power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
+ value->intval, buf);
+}
+
static ssize_t power_supply_show_property(struct device *dev,
struct device_attribute *attr,
char *buf) {
@@ -306,8 +323,7 @@ static ssize_t power_supply_show_property(struct device *dev,
&value, buf);
break;
case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
- ret = power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
- value.intval, buf);
+ ret = power_supply_show_charge_behaviour(dev, psy, &value, buf);
break;
case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = sysfs_emit(buf, "%s\n", value.strval);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 72dc7e45c90c..51788faf1d66 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
+#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
@@ -280,6 +281,28 @@ struct power_supply_desc {
int use_for_apm;
};
+struct power_supply_ext {
+ u8 charge_behaviours;
+ const enum power_supply_property *properties;
+ size_t num_properties;
+
+ int (*get_property)(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ union power_supply_propval *val);
+ int (*set_property)(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val);
+
+ int (*property_is_writeable)(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp);
+};
+
struct power_supply {
const struct power_supply_desc *desc;
@@ -303,6 +326,7 @@ struct power_supply {
bool removing;
atomic_t use_cnt;
struct power_supply_battery_info *battery_info;
+ struct list_head extensions;
#ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd;
struct thermal_cooling_device *tcd;
@@ -887,6 +911,12 @@ devm_power_supply_register_no_ws(struct device *parent,
extern void power_supply_unregister(struct power_supply *psy);
extern int power_supply_powers(struct power_supply *psy, struct device *dev);
+extern int power_supply_register_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data);
+extern void power_supply_unregister_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext);
+
#define to_power_supply(device) container_of(device, struct power_supply, dev)
extern void *power_supply_get_drvdata(struct power_supply *psy);
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 6/9] power: supply: core: implement extension API
2024-09-04 19:25 ` [PATCH RFC v3 6/9] power: supply: core: implement extension API Thomas Weißschuh
@ 2024-09-14 10:50 ` Sebastian Reichel
2024-09-14 14:25 ` Thomas Weißschuh
0 siblings, 1 reply; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-14 10:50 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 12158 bytes --]
Hi,
On Wed, Sep 04, 2024 at 09:25:39PM GMT, Thomas Weißschuh wrote:
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
missing long description :)
In general I like the concept. It looks like a good candidate to
clean up the mess with the custom registration of properties done
by the x86 platform code.
Apart from ACPI with custom battery extensions mess, there is
something similar in the embedded world: Many charger chips have
rudimentary fuel-gauge support. Some drivers register a charger/usb
and a battery device. That results in two battery devices when the
machine also has a proper fuel gauge. Having two battery devices
exposed is bad, since that means the machine has two batteries
(like some Thinkpads). Not exposing the battery from the charger
device is possibly loosing information (depending on fuel gauge
features).
I think it should be possible to register the charger's rudimentary
battery device as a power_supply_ext, if it detects a proper fuel
gauge being available (e.g. via the DT "power-supplies" property).
But then the charger's properties are the preferred ones. I think
they should be fallback properties instead. A machine only gets its
own fuel-gauge, when that provides better values than the data
available from the charger :)
So the question is which property getter/setter should be used
when the same property is exposed multiple times. Your examples
only add new properties and does not run into this. The intuitive
thing would be for properties from extensions to be preferred,
but do we actually have a use case for that?
Greetings,
-- Sebastian
> drivers/power/supply/power_supply.h | 12 ++++
> drivers/power/supply/power_supply_core.c | 114 +++++++++++++++++++++++++++++-
> drivers/power/supply/power_supply_sysfs.c | 20 +++++-
> include/linux/power_supply.h | 30 ++++++++
> 4 files changed, 171 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
> index b01faeaf7827..fb45f0717bd1 100644
> --- a/drivers/power/supply/power_supply.h
> +++ b/drivers/power/supply/power_supply.h
> @@ -15,6 +15,18 @@ struct power_supply;
>
> extern bool power_supply_has_property(struct power_supply *psy,
> enum power_supply_property psp);
> +extern bool power_supply_ext_has_property(const struct power_supply_ext *ext,
> + enum power_supply_property psp);
> +
> +struct power_supply_ext_registration {
> + struct list_head list_head;
> + const struct power_supply_ext *ext;
> + void *data;
> +};
> +
> +#define power_supply_for_each_extension(pos, psy) \
> + list_for_each_entry(pos, &(psy)->extensions, list_head)
> +
>
> #ifdef CONFIG_SYSFS
>
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index dcb7e4853030..db5e7af57e67 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -1199,15 +1199,40 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> return found;
> }
>
> +bool power_supply_ext_has_property(const struct power_supply_ext *psy_ext,
> + enum power_supply_property psp)
> +{
> + bool found = false;
> + int i;
> +
> + if (!psy_ext)
> + return false;
> +
> + for (i = 0; i < psy_ext->num_properties; i++) {
> + if (psy_ext->properties[i] == psp) {
> + found = true;
> + break;
> + }
> + }
> +
> + return found;
> +}
> +
> bool power_supply_has_property(struct power_supply *psy,
> enum power_supply_property psp)
> {
> + struct power_supply_ext_registration *reg;
> +
> if (psy_desc_has_property(psy->desc, psp))
> return true;
>
> if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> return true;
>
> + power_supply_for_each_extension(reg, psy)
> + if (power_supply_ext_has_property(reg->ext, psp))
> + return true;
> +
> return false;
> }
>
> @@ -1215,12 +1240,19 @@ int power_supply_get_property(struct power_supply *psy,
> enum power_supply_property psp,
> union power_supply_propval *val)
> {
> + struct power_supply_ext_registration *reg;
> +
> if (atomic_read(&psy->use_cnt) <= 0) {
> if (!psy->initialized)
> return -EAGAIN;
> return -ENODEV;
> }
>
> + power_supply_for_each_extension(reg, psy) {
> + if (power_supply_ext_has_property(reg->ext, psp))
> + return reg->ext->get_property(psy, reg->ext, reg->data, psp, val);
> + }
> +
> if (psy_desc_has_property(psy->desc, psp))
> return psy->desc->get_property(psy, psp, val);
> else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> @@ -1234,7 +1266,21 @@ int power_supply_set_property(struct power_supply *psy,
> enum power_supply_property psp,
> const union power_supply_propval *val)
> {
> - if (atomic_read(&psy->use_cnt) <= 0 || !psy->desc->set_property)
> + struct power_supply_ext_registration *reg;
> +
> + if (atomic_read(&psy->use_cnt) <= 0)
> + return -ENODEV;
> +
> + power_supply_for_each_extension(reg, psy) {
> + if (power_supply_ext_has_property(reg->ext, psp)) {
> + if (reg->ext->set_property)
> + return reg->ext->set_property(psy, reg->ext, reg->data, psp, val);
> + else
> + return -ENODEV;
> + }
> + }
> +
> + if (!psy->desc->set_property)
> return -ENODEV;
>
> return psy->desc->set_property(psy, psp, val);
> @@ -1244,8 +1290,21 @@ EXPORT_SYMBOL_GPL(power_supply_set_property);
> int power_supply_property_is_writeable(struct power_supply *psy,
> enum power_supply_property psp)
> {
> - if (atomic_read(&psy->use_cnt) <= 0 ||
> - !psy->desc->property_is_writeable)
> + struct power_supply_ext_registration *reg;
> +
> + if (atomic_read(&psy->use_cnt) <= 0)
> + return -ENODEV;
> +
> + power_supply_for_each_extension(reg, psy) {
> + if (power_supply_ext_has_property(reg->ext, psp)) {
> + if (reg->ext->property_is_writeable)
> + return reg->ext->property_is_writeable(psy, reg->ext, reg->data, psp);
> + else
> + return -ENODEV;
> + }
> + }
> +
> + if (!psy->desc->property_is_writeable)
> return -ENODEV;
>
> return psy->desc->property_is_writeable(psy, psp);
> @@ -1268,6 +1327,54 @@ int power_supply_powers(struct power_supply *psy, struct device *dev)
> }
> EXPORT_SYMBOL_GPL(power_supply_powers);
>
> +static int power_supply_update_groups(struct power_supply *psy)
> +{
> + int ret;
> +
> + ret = sysfs_update_groups(&psy->dev.kobj, power_supply_dev_type.groups);
> + power_supply_changed(psy);
> + return ret;
> +}
> +
> +int power_supply_register_extension(struct power_supply *psy, const struct power_supply_ext *ext,
> + void *ext_data)
> +{
> + struct power_supply_ext_registration *reg;
> + size_t i;
> +
> + for (i = 0; i < ext->num_properties; i++) {
> + if (power_supply_has_property(psy, ext->properties[i]))
> + return -EEXIST;
> + }
> +
> + reg = kmalloc(sizeof(*reg), GFP_KERNEL);
> + if (!reg)
> + return -ENOMEM;
> +
> + reg->ext = ext;
> + list_add(®->list_head, &psy->extensions);
> +
> + return power_supply_update_groups(psy);
> +}
> +EXPORT_SYMBOL_GPL(power_supply_register_extension);
> +
> +void power_supply_unregister_extension(struct power_supply *psy, const struct power_supply_ext *ext)
> +{
> + struct power_supply_ext_registration *reg;
> +
> + power_supply_for_each_extension(reg, psy) {
> + if (reg->ext == ext) {
> + list_del(®->list_head);
> + kfree(reg);
> + power_supply_update_groups(psy);
> + return;
> + }
> + }
> +
> + dev_warn(&psy->dev, "Trying to unregister invalid extension");
> +}
> +EXPORT_SYMBOL_GPL(power_supply_unregister_extension);
> +
> static void power_supply_dev_release(struct device *dev)
> {
> struct power_supply *psy = to_power_supply(dev);
> @@ -1427,6 +1534,7 @@ __power_supply_register(struct device *parent,
> }
>
> spin_lock_init(&psy->changed_lock);
> + INIT_LIST_HEAD(&psy->extensions);
> rc = device_add(dev);
> if (rc)
> goto device_add_failed;
> diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> index 915a4ba62258..e7c306afd846 100644
> --- a/drivers/power/supply/power_supply_sysfs.c
> +++ b/drivers/power/supply/power_supply_sysfs.c
> @@ -271,6 +271,23 @@ static ssize_t power_supply_show_usb_type(struct device *dev,
> return count;
> }
>
> +static ssize_t power_supply_show_charge_behaviour(struct device *dev,
> + struct power_supply *psy,
> + union power_supply_propval *value,
> + char *buf)
> +{
> + struct power_supply_ext_registration *reg;
> +
> + power_supply_for_each_extension(reg, psy) {
> + if (power_supply_ext_has_property(reg->ext, POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR))
> + return power_supply_charge_behaviour_show(dev, reg->ext->charge_behaviours,
> + value->intval, buf);
> + }
> +
> + return power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
> + value->intval, buf);
> +}
> +
> static ssize_t power_supply_show_property(struct device *dev,
> struct device_attribute *attr,
> char *buf) {
> @@ -306,8 +323,7 @@ static ssize_t power_supply_show_property(struct device *dev,
> &value, buf);
> break;
> case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
> - ret = power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
> - value.intval, buf);
> + ret = power_supply_show_charge_behaviour(dev, psy, &value, buf);
> break;
> case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
> ret = sysfs_emit(buf, "%s\n", value.strval);
> diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> index 72dc7e45c90c..51788faf1d66 100644
> --- a/include/linux/power_supply.h
> +++ b/include/linux/power_supply.h
> @@ -15,6 +15,7 @@
> #include <linux/device.h>
> #include <linux/workqueue.h>
> #include <linux/leds.h>
> +#include <linux/list.h>
> #include <linux/spinlock.h>
> #include <linux/notifier.h>
>
> @@ -280,6 +281,28 @@ struct power_supply_desc {
> int use_for_apm;
> };
>
> +struct power_supply_ext {
> + u8 charge_behaviours;
> + const enum power_supply_property *properties;
> + size_t num_properties;
> +
> + int (*get_property)(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *ext_data,
> + enum power_supply_property psp,
> + union power_supply_propval *val);
> + int (*set_property)(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *ext_data,
> + enum power_supply_property psp,
> + const union power_supply_propval *val);
> +
> + int (*property_is_writeable)(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *ext_data,
> + enum power_supply_property psp);
> +};
> +
> struct power_supply {
> const struct power_supply_desc *desc;
>
> @@ -303,6 +326,7 @@ struct power_supply {
> bool removing;
> atomic_t use_cnt;
> struct power_supply_battery_info *battery_info;
> + struct list_head extensions;
> #ifdef CONFIG_THERMAL
> struct thermal_zone_device *tzd;
> struct thermal_cooling_device *tcd;
> @@ -887,6 +911,12 @@ devm_power_supply_register_no_ws(struct device *parent,
> extern void power_supply_unregister(struct power_supply *psy);
> extern int power_supply_powers(struct power_supply *psy, struct device *dev);
>
> +extern int power_supply_register_extension(struct power_supply *psy,
> + const struct power_supply_ext *ext,
> + void *ext_data);
> +extern void power_supply_unregister_extension(struct power_supply *psy,
> + const struct power_supply_ext *ext);
> +
> #define to_power_supply(device) container_of(device, struct power_supply, dev)
>
> extern void *power_supply_get_drvdata(struct power_supply *psy);
>
> --
> 2.46.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 6/9] power: supply: core: implement extension API
2024-09-14 10:50 ` Sebastian Reichel
@ 2024-09-14 14:25 ` Thomas Weißschuh
2024-09-16 10:58 ` Sebastian Reichel
0 siblings, 1 reply; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-14 14:25 UTC (permalink / raw)
To: Sebastian Reichel; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
On 2024-09-14 12:50:57+0000, Sebastian Reichel wrote:
> On Wed, Sep 04, 2024 at 09:25:39PM GMT, Thomas Weißschuh wrote:
> > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> > ---
>
> missing long description :)
I'll paste the cover letter here for the next one :-)
> In general I like the concept. It looks like a good candidate to
> clean up the mess with the custom registration of properties done
> by the x86 platform code.
>
> Apart from ACPI with custom battery extensions mess, there is
> something similar in the embedded world: Many charger chips have
> rudimentary fuel-gauge support. Some drivers register a charger/usb
> and a battery device. That results in two battery devices when the
> machine also has a proper fuel gauge. Having two battery devices
> exposed is bad, since that means the machine has two batteries
> (like some Thinkpads). Not exposing the battery from the charger
> device is possibly loosing information (depending on fuel gauge
> features).
>
> I think it should be possible to register the charger's rudimentary
> battery device as a power_supply_ext, if it detects a proper fuel
> gauge being available (e.g. via the DT "power-supplies" property).
> But then the charger's properties are the preferred ones. I think
> they should be fallback properties instead. A machine only gets its
> own fuel-gauge, when that provides better values than the data
> available from the charger :)
>
> So the question is which property getter/setter should be used
> when the same property is exposed multiple times. Your examples
> only add new properties and does not run into this. The intuitive
> thing would be for properties from extensions to be preferred,
> but do we actually have a use case for that?
Currently duplicate properties are straight up rejected.
With multiple extensions any order-based resolution of duplicates seems
to be prone for confusion in case the registration order changes.
The x86 platform and embedded usecases seem quite disjunct to me.
If we can keep them separate that would be easier to implement.
x86:
Don't allow any overriding, like the code currently does.
embedded:
Add different extension priorities. When registering a new one,
unregister all lower priority ones; do nothing if a higher priority is
already registered.
This makes the result predictable even if the order changes.
A fallback extension would need quite some bespoke logic I think.
Note:
I noticed that the locking for power_supply_set_property() is currently
broken. In case you are wondering about that.
Thomas
> Greetings,
>
> -- Sebastian
>
> > drivers/power/supply/power_supply.h | 12 ++++
> > drivers/power/supply/power_supply_core.c | 114 +++++++++++++++++++++++++++++-
> > drivers/power/supply/power_supply_sysfs.c | 20 +++++-
> > include/linux/power_supply.h | 30 ++++++++
> > 4 files changed, 171 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
> > index b01faeaf7827..fb45f0717bd1 100644
> > --- a/drivers/power/supply/power_supply.h
> > +++ b/drivers/power/supply/power_supply.h
> > @@ -15,6 +15,18 @@ struct power_supply;
> >
> > extern bool power_supply_has_property(struct power_supply *psy,
> > enum power_supply_property psp);
> > +extern bool power_supply_ext_has_property(const struct power_supply_ext *ext,
> > + enum power_supply_property psp);
> > +
> > +struct power_supply_ext_registration {
> > + struct list_head list_head;
> > + const struct power_supply_ext *ext;
> > + void *data;
> > +};
> > +
> > +#define power_supply_for_each_extension(pos, psy) \
> > + list_for_each_entry(pos, &(psy)->extensions, list_head)
> > +
> >
> > #ifdef CONFIG_SYSFS
> >
> > diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> > index dcb7e4853030..db5e7af57e67 100644
> > --- a/drivers/power/supply/power_supply_core.c
> > +++ b/drivers/power/supply/power_supply_core.c
> > @@ -1199,15 +1199,40 @@ static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
> > return found;
> > }
> >
> > +bool power_supply_ext_has_property(const struct power_supply_ext *psy_ext,
> > + enum power_supply_property psp)
> > +{
> > + bool found = false;
> > + int i;
> > +
> > + if (!psy_ext)
> > + return false;
> > +
> > + for (i = 0; i < psy_ext->num_properties; i++) {
> > + if (psy_ext->properties[i] == psp) {
> > + found = true;
> > + break;
> > + }
> > + }
> > +
> > + return found;
> > +}
> > +
> > bool power_supply_has_property(struct power_supply *psy,
> > enum power_supply_property psp)
> > {
> > + struct power_supply_ext_registration *reg;
> > +
> > if (psy_desc_has_property(psy->desc, psp))
> > return true;
> >
> > if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> > return true;
> >
> > + power_supply_for_each_extension(reg, psy)
> > + if (power_supply_ext_has_property(reg->ext, psp))
> > + return true;
> > +
> > return false;
> > }
> >
> > @@ -1215,12 +1240,19 @@ int power_supply_get_property(struct power_supply *psy,
> > enum power_supply_property psp,
> > union power_supply_propval *val)
> > {
> > + struct power_supply_ext_registration *reg;
> > +
> > if (atomic_read(&psy->use_cnt) <= 0) {
> > if (!psy->initialized)
> > return -EAGAIN;
> > return -ENODEV;
> > }
> >
> > + power_supply_for_each_extension(reg, psy) {
> > + if (power_supply_ext_has_property(reg->ext, psp))
> > + return reg->ext->get_property(psy, reg->ext, reg->data, psp, val);
> > + }
> > +
> > if (psy_desc_has_property(psy->desc, psp))
> > return psy->desc->get_property(psy, psp, val);
> > else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
> > @@ -1234,7 +1266,21 @@ int power_supply_set_property(struct power_supply *psy,
> > enum power_supply_property psp,
> > const union power_supply_propval *val)
> > {
> > - if (atomic_read(&psy->use_cnt) <= 0 || !psy->desc->set_property)
> > + struct power_supply_ext_registration *reg;
> > +
> > + if (atomic_read(&psy->use_cnt) <= 0)
> > + return -ENODEV;
> > +
> > + power_supply_for_each_extension(reg, psy) {
> > + if (power_supply_ext_has_property(reg->ext, psp)) {
> > + if (reg->ext->set_property)
> > + return reg->ext->set_property(psy, reg->ext, reg->data, psp, val);
> > + else
> > + return -ENODEV;
> > + }
> > + }
> > +
> > + if (!psy->desc->set_property)
> > return -ENODEV;
> >
> > return psy->desc->set_property(psy, psp, val);
> > @@ -1244,8 +1290,21 @@ EXPORT_SYMBOL_GPL(power_supply_set_property);
> > int power_supply_property_is_writeable(struct power_supply *psy,
> > enum power_supply_property psp)
> > {
> > - if (atomic_read(&psy->use_cnt) <= 0 ||
> > - !psy->desc->property_is_writeable)
> > + struct power_supply_ext_registration *reg;
> > +
> > + if (atomic_read(&psy->use_cnt) <= 0)
> > + return -ENODEV;
> > +
> > + power_supply_for_each_extension(reg, psy) {
> > + if (power_supply_ext_has_property(reg->ext, psp)) {
> > + if (reg->ext->property_is_writeable)
> > + return reg->ext->property_is_writeable(psy, reg->ext, reg->data, psp);
> > + else
> > + return -ENODEV;
> > + }
> > + }
> > +
> > + if (!psy->desc->property_is_writeable)
> > return -ENODEV;
> >
> > return psy->desc->property_is_writeable(psy, psp);
> > @@ -1268,6 +1327,54 @@ int power_supply_powers(struct power_supply *psy, struct device *dev)
> > }
> > EXPORT_SYMBOL_GPL(power_supply_powers);
> >
> > +static int power_supply_update_groups(struct power_supply *psy)
> > +{
> > + int ret;
> > +
> > + ret = sysfs_update_groups(&psy->dev.kobj, power_supply_dev_type.groups);
> > + power_supply_changed(psy);
> > + return ret;
> > +}
> > +
> > +int power_supply_register_extension(struct power_supply *psy, const struct power_supply_ext *ext,
> > + void *ext_data)
> > +{
> > + struct power_supply_ext_registration *reg;
> > + size_t i;
> > +
> > + for (i = 0; i < ext->num_properties; i++) {
> > + if (power_supply_has_property(psy, ext->properties[i]))
> > + return -EEXIST;
> > + }
> > +
> > + reg = kmalloc(sizeof(*reg), GFP_KERNEL);
> > + if (!reg)
> > + return -ENOMEM;
> > +
> > + reg->ext = ext;
> > + list_add(®->list_head, &psy->extensions);
> > +
> > + return power_supply_update_groups(psy);
> > +}
> > +EXPORT_SYMBOL_GPL(power_supply_register_extension);
> > +
> > +void power_supply_unregister_extension(struct power_supply *psy, const struct power_supply_ext *ext)
> > +{
> > + struct power_supply_ext_registration *reg;
> > +
> > + power_supply_for_each_extension(reg, psy) {
> > + if (reg->ext == ext) {
> > + list_del(®->list_head);
> > + kfree(reg);
> > + power_supply_update_groups(psy);
> > + return;
> > + }
> > + }
> > +
> > + dev_warn(&psy->dev, "Trying to unregister invalid extension");
> > +}
> > +EXPORT_SYMBOL_GPL(power_supply_unregister_extension);
> > +
> > static void power_supply_dev_release(struct device *dev)
> > {
> > struct power_supply *psy = to_power_supply(dev);
> > @@ -1427,6 +1534,7 @@ __power_supply_register(struct device *parent,
> > }
> >
> > spin_lock_init(&psy->changed_lock);
> > + INIT_LIST_HEAD(&psy->extensions);
> > rc = device_add(dev);
> > if (rc)
> > goto device_add_failed;
> > diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> > index 915a4ba62258..e7c306afd846 100644
> > --- a/drivers/power/supply/power_supply_sysfs.c
> > +++ b/drivers/power/supply/power_supply_sysfs.c
> > @@ -271,6 +271,23 @@ static ssize_t power_supply_show_usb_type(struct device *dev,
> > return count;
> > }
> >
> > +static ssize_t power_supply_show_charge_behaviour(struct device *dev,
> > + struct power_supply *psy,
> > + union power_supply_propval *value,
> > + char *buf)
> > +{
> > + struct power_supply_ext_registration *reg;
> > +
> > + power_supply_for_each_extension(reg, psy) {
> > + if (power_supply_ext_has_property(reg->ext, POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR))
> > + return power_supply_charge_behaviour_show(dev, reg->ext->charge_behaviours,
> > + value->intval, buf);
> > + }
> > +
> > + return power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
> > + value->intval, buf);
> > +}
> > +
> > static ssize_t power_supply_show_property(struct device *dev,
> > struct device_attribute *attr,
> > char *buf) {
> > @@ -306,8 +323,7 @@ static ssize_t power_supply_show_property(struct device *dev,
> > &value, buf);
> > break;
> > case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
> > - ret = power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
> > - value.intval, buf);
> > + ret = power_supply_show_charge_behaviour(dev, psy, &value, buf);
> > break;
> > case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
> > ret = sysfs_emit(buf, "%s\n", value.strval);
> > diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> > index 72dc7e45c90c..51788faf1d66 100644
> > --- a/include/linux/power_supply.h
> > +++ b/include/linux/power_supply.h
> > @@ -15,6 +15,7 @@
> > #include <linux/device.h>
> > #include <linux/workqueue.h>
> > #include <linux/leds.h>
> > +#include <linux/list.h>
> > #include <linux/spinlock.h>
> > #include <linux/notifier.h>
> >
> > @@ -280,6 +281,28 @@ struct power_supply_desc {
> > int use_for_apm;
> > };
> >
> > +struct power_supply_ext {
> > + u8 charge_behaviours;
> > + const enum power_supply_property *properties;
> > + size_t num_properties;
> > +
> > + int (*get_property)(struct power_supply *psy,
> > + const struct power_supply_ext *ext,
> > + void *ext_data,
> > + enum power_supply_property psp,
> > + union power_supply_propval *val);
> > + int (*set_property)(struct power_supply *psy,
> > + const struct power_supply_ext *ext,
> > + void *ext_data,
> > + enum power_supply_property psp,
> > + const union power_supply_propval *val);
> > +
> > + int (*property_is_writeable)(struct power_supply *psy,
> > + const struct power_supply_ext *ext,
> > + void *ext_data,
> > + enum power_supply_property psp);
> > +};
> > +
> > struct power_supply {
> > const struct power_supply_desc *desc;
> >
> > @@ -303,6 +326,7 @@ struct power_supply {
> > bool removing;
> > atomic_t use_cnt;
> > struct power_supply_battery_info *battery_info;
> > + struct list_head extensions;
> > #ifdef CONFIG_THERMAL
> > struct thermal_zone_device *tzd;
> > struct thermal_cooling_device *tcd;
> > @@ -887,6 +911,12 @@ devm_power_supply_register_no_ws(struct device *parent,
> > extern void power_supply_unregister(struct power_supply *psy);
> > extern int power_supply_powers(struct power_supply *psy, struct device *dev);
> >
> > +extern int power_supply_register_extension(struct power_supply *psy,
> > + const struct power_supply_ext *ext,
> > + void *ext_data);
> > +extern void power_supply_unregister_extension(struct power_supply *psy,
> > + const struct power_supply_ext *ext);
> > +
> > #define to_power_supply(device) container_of(device, struct power_supply, dev)
> >
> > extern void *power_supply_get_drvdata(struct power_supply *psy);
> >
> > --
> > 2.46.0
> >
> >
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH RFC v3 6/9] power: supply: core: implement extension API
2024-09-14 14:25 ` Thomas Weißschuh
@ 2024-09-16 10:58 ` Sebastian Reichel
0 siblings, 0 replies; 24+ messages in thread
From: Sebastian Reichel @ 2024-09-16 10:58 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Armin Wolf, Hans de Goede, linux-pm, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 3173 bytes --]
Hi,
On Sat, Sep 14, 2024 at 04:25:25PM GMT, Thomas Weißschuh wrote:
> On 2024-09-14 12:50:57+0000, Sebastian Reichel wrote:
> > On Wed, Sep 04, 2024 at 09:25:39PM GMT, Thomas Weißschuh wrote:
> > > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> > > ---
> >
> > missing long description :)
>
> I'll paste the cover letter here for the next one :-)
>
> > In general I like the concept. It looks like a good candidate to
> > clean up the mess with the custom registration of properties done
> > by the x86 platform code.
> >
> > Apart from ACPI with custom battery extensions mess, there is
> > something similar in the embedded world: Many charger chips have
> > rudimentary fuel-gauge support. Some drivers register a charger/usb
> > and a battery device. That results in two battery devices when the
> > machine also has a proper fuel gauge. Having two battery devices
> > exposed is bad, since that means the machine has two batteries
> > (like some Thinkpads). Not exposing the battery from the charger
> > device is possibly loosing information (depending on fuel gauge
> > features).
> >
> > I think it should be possible to register the charger's rudimentary
> > battery device as a power_supply_ext, if it detects a proper fuel
> > gauge being available (e.g. via the DT "power-supplies" property).
> > But then the charger's properties are the preferred ones. I think
> > they should be fallback properties instead. A machine only gets its
> > own fuel-gauge, when that provides better values than the data
> > available from the charger :)
> >
> > So the question is which property getter/setter should be used
> > when the same property is exposed multiple times. Your examples
> > only add new properties and does not run into this. The intuitive
> > thing would be for properties from extensions to be preferred,
> > but do we actually have a use case for that?
>
> Currently duplicate properties are straight up rejected.
> With multiple extensions any order-based resolution of duplicates seems
> to be prone for confusion in case the registration order changes.
Ah, I missed the part about rejecting duplicates.
> The x86 platform and embedded usecases seem quite disjunct to me.
> If we can keep them separate that would be easier to implement.
I wouldn't say they are disjunct. The embedded use case is basically
a superset of the x86 variant.
> x86:
>
> Don't allow any overriding, like the code currently does.
>
> embedded:
>
> Add different extension priorities. When registering a new one,
> unregister all lower priority ones; do nothing if a higher priority is
> already registered.
> This makes the result predictable even if the order changes.
> A fallback extension would need quite some bespoke logic I think.
Adding priorities seems sensible, but also requires assigning
priorities to the base device. I need to think more about this, but
it can wait until the basic version for x86 has landed
> Note:
> I noticed that the locking for power_supply_set_property() is currently
> broken. In case you are wondering about that.
ok.
-- Sebastian
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH RFC v3 7/9] power: supply: core: add locking around extension access
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
` (5 preceding siblings ...)
2024-09-04 19:25 ` [PATCH RFC v3 6/9] power: supply: core: implement extension API Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:25 ` [PATCH RFC v3 8/9] power: supply: test-power: implement a power supply extension Thomas Weißschuh
2024-09-04 19:25 ` [PATCH RFC v3 9/9] power: supply: cros_charge-control: use power_supply extensions Thomas Weißschuh
8 siblings, 0 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
This is only separate for easier review during the RFC phase.
It will be squashed into the actual power supply extension commit later.
---
drivers/power/supply/power_supply.h | 3 ++
drivers/power/supply/power_supply_core.c | 49 ++++++++++++++++++++++++++-----
drivers/power/supply/power_supply_leds.c | 2 ++
drivers/power/supply/power_supply_sysfs.c | 6 ++++
include/linux/power_supply.h | 3 ++
5 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
index fb45f0717bd1..b8e14cc70fcf 100644
--- a/drivers/power/supply/power_supply.h
+++ b/drivers/power/supply/power_supply.h
@@ -9,6 +9,8 @@
* Modified: 2004, Oct Szabolcs Gyurko
*/
+#include <linux/lockdep.h>
+
struct device;
struct device_type;
struct power_supply;
@@ -25,6 +27,7 @@ struct power_supply_ext_registration {
};
#define power_supply_for_each_extension(pos, psy) \
+ lockdep_assert_held(&(psy)->extensions_sem); \
list_for_each_entry(pos, &(psy)->extensions, list_head)
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index db5e7af57e67..4839be25e6be 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -80,6 +81,7 @@ static int __power_supply_changed_work(struct device *dev, void *data)
static void power_supply_changed_work(struct work_struct *work)
{
+ int ret;
unsigned long flags;
struct power_supply *psy = container_of(work, struct power_supply,
changed_work);
@@ -87,6 +89,16 @@ static void power_supply_changed_work(struct work_struct *work)
dev_dbg(&psy->dev, "%s\n", __func__);
spin_lock_irqsave(&psy->changed_lock, flags);
+
+ if (unlikely(psy->update_groups)) {
+ psy->update_groups = false;
+ spin_unlock_irqrestore(&psy->changed_lock, flags);
+ ret = sysfs_update_groups(&psy->dev.kobj, power_supply_dev_type.groups);
+ if (ret)
+ dev_warn(&psy->dev, "failed to update sysfs groups: %pe\n", ERR_PTR(ret));
+ spin_lock_irqsave(&psy->changed_lock, flags);
+ }
+
/*
* Check 'changed' here to avoid issues due to race between
* power_supply_changed() and this routine. In worst case
@@ -1218,17 +1230,26 @@ bool power_supply_ext_has_property(const struct power_supply_ext *psy_ext,
return found;
}
-bool power_supply_has_property(struct power_supply *psy,
- enum power_supply_property psp)
+static bool psy_has_property_no_ext(struct power_supply *psy,
+ enum power_supply_property psp)
{
- struct power_supply_ext_registration *reg;
-
if (psy_desc_has_property(psy->desc, psp))
return true;
if (power_supply_battery_info_has_prop(psy->battery_info, psp))
return true;
+ return false;
+}
+
+bool power_supply_has_property(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ struct power_supply_ext_registration *reg;
+
+ if (psy_has_property_no_ext(psy, psp))
+ return true;
+
power_supply_for_each_extension(reg, psy)
if (power_supply_ext_has_property(reg->ext, psp))
return true;
@@ -1329,11 +1350,14 @@ EXPORT_SYMBOL_GPL(power_supply_powers);
static int power_supply_update_groups(struct power_supply *psy)
{
- int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psy->changed_lock, flags);
+ psy->update_groups = true;
+ spin_unlock_irqrestore(&psy->changed_lock, flags);
- ret = sysfs_update_groups(&psy->dev.kobj, power_supply_dev_type.groups);
power_supply_changed(psy);
- return ret;
+ return 0;
}
int power_supply_register_extension(struct power_supply *psy, const struct power_supply_ext *ext,
@@ -1342,6 +1366,8 @@ int power_supply_register_extension(struct power_supply *psy, const struct power
struct power_supply_ext_registration *reg;
size_t i;
+ guard(rwsem_write)(&psy->extensions_sem);
+
for (i = 0; i < ext->num_properties; i++) {
if (power_supply_has_property(psy, ext->properties[i]))
return -EEXIST;
@@ -1362,6 +1388,8 @@ void power_supply_unregister_extension(struct power_supply *psy, const struct po
{
struct power_supply_ext_registration *reg;
+ guard(rwsem_write)(&psy->extensions_sem);
+
power_supply_for_each_extension(reg, psy) {
if (reg->ext == ext) {
list_del(®->list_head);
@@ -1405,6 +1433,7 @@ static int power_supply_read_temp(struct thermal_zone_device *tzd,
WARN_ON(tzd == NULL);
psy = thermal_zone_device_priv(tzd);
+ guard(rwsem_read)(&psy->extensions_sem);
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
if (ret)
return ret;
@@ -1427,7 +1456,7 @@ static int psy_register_thermal(struct power_supply *psy)
return 0;
/* Register battery zone device psy reports temperature */
- if (power_supply_has_property(psy, POWER_SUPPLY_PROP_TEMP)) {
+ if (psy_has_property_no_ext(psy, POWER_SUPPLY_PROP_TEMP)) {
/* Prefer our hwmon device and avoid duplicates */
struct thermal_zone_params tzp = {
.no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
@@ -1534,7 +1563,9 @@ __power_supply_register(struct device *parent,
}
spin_lock_init(&psy->changed_lock);
+ init_rwsem(&psy->extensions_sem);
INIT_LIST_HEAD(&psy->extensions);
+
rc = device_add(dev);
if (rc)
goto device_add_failed;
@@ -1547,6 +1578,8 @@ __power_supply_register(struct device *parent,
if (rc)
goto register_thermal_failed;
+ guard(rwsem_read)(&psy->extensions_sem);
+
rc = power_supply_create_triggers(psy);
if (rc)
goto create_triggers_failed;
diff --git a/drivers/power/supply/power_supply_leds.c b/drivers/power/supply/power_supply_leds.c
index f4a7e566bea1..09a6f3fe2f85 100644
--- a/drivers/power/supply/power_supply_leds.c
+++ b/drivers/power/supply/power_supply_leds.c
@@ -195,6 +195,8 @@ static void power_supply_remove_gen_triggers(struct power_supply *psy)
void power_supply_update_leds(struct power_supply *psy)
{
+ guard(rwsem_read)(&psy->extensions_sem);
+
if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
power_supply_update_bat_leds(psy);
else
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index e7c306afd846..b56e0bd424f5 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -371,6 +371,8 @@ static ssize_t power_supply_store_property(struct device *dev,
value.intval = ret;
+ guard(rwsem_read)(&psy->extensions_sem);
+
ret = power_supply_set_property(psy, psp, &value);
if (ret < 0)
return ret;
@@ -392,6 +394,8 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
if (attrno == POWER_SUPPLY_PROP_TYPE)
return mode;
+ guard(rwsem_read)(&psy->extensions_sem);
+
if (power_supply_has_property(psy, attrno)) {
if (power_supply_property_is_writeable(psy, attrno) > 0)
mode |= S_IWUSR;
@@ -497,6 +501,8 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
if (ret)
goto out;
+ guard(rwsem_read)(&psy->extensions_sem);
+
for (j = 0; j < POWER_SUPPLY_ATTR_CNT; j++) {
ret = add_prop_uevent(dev, env, j, prop_buf);
if (ret)
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 51788faf1d66..87bc50698649 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
+#include <linux/rwsem.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
@@ -322,10 +323,12 @@ struct power_supply {
struct delayed_work deferred_register_work;
spinlock_t changed_lock;
bool changed;
+ bool update_groups;
bool initialized;
bool removing;
atomic_t use_cnt;
struct power_supply_battery_info *battery_info;
+ struct rw_semaphore extensions_sem; /* protects "extensions" */
struct list_head extensions;
#ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd;
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH RFC v3 8/9] power: supply: test-power: implement a power supply extension
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
` (6 preceding siblings ...)
2024-09-04 19:25 ` [PATCH RFC v3 7/9] power: supply: core: add locking around extension access Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
2024-09-04 19:25 ` [PATCH RFC v3 9/9] power: supply: cros_charge-control: use power_supply extensions Thomas Weißschuh
8 siblings, 0 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Allow easy testing of the new power supply extension functionality.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/test_power.c | 104 ++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
index 442ceb7795e1..da1877f31929 100644
--- a/drivers/power/supply/test_power.c
+++ b/drivers/power/supply/test_power.c
@@ -37,6 +37,7 @@ static int battery_charge_counter = -1000;
static int battery_current = -1600;
static enum power_supply_charge_behaviour battery_charge_behaviour =
POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
+static bool battery_hook;
static bool module_initialized;
@@ -238,6 +239,82 @@ static const struct power_supply_config test_power_configs[] = {
},
};
+static int power_supply_ext_manufacture_year = 1234;
+static const enum power_supply_property power_supply_ext_props[] = {
+ POWER_SUPPLY_PROP_MANUFACTURE_YEAR,
+};
+
+static int power_supply_ext_get_property(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
+ val->intval = power_supply_ext_manufacture_year;
+ break;
+ default:
+ pr_info("%s: some properties deliberately report errors.\n",
+ __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int power_supply_ext_set_property(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
+ power_supply_ext_manufacture_year = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int power_supply_ext_property_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp)
+{
+ return true;
+}
+
+static const struct power_supply_ext power_supply_ext = {
+ .properties = power_supply_ext_props,
+ .num_properties = ARRAY_SIZE(power_supply_ext_props),
+ .get_property = power_supply_ext_get_property,
+ .set_property = power_supply_ext_set_property,
+ .property_is_writeable = power_supply_ext_property_is_writeable,
+};
+
+static void test_battery_configure_battery_hook(bool enable)
+{
+ struct power_supply *psy;
+
+ if (battery_hook == enable)
+ return;
+
+ psy = test_power_supplies[TEST_BATTERY];
+
+ if (enable) {
+ if (power_supply_register_extension(psy, &power_supply_ext, NULL)) {
+ pr_err("registering battery extension failed\n");
+ return;
+ }
+ } else {
+ power_supply_unregister_extension(psy, &power_supply_ext);
+ }
+
+ battery_hook = enable;
+}
+
static int __init test_power_init(void)
{
int i;
@@ -258,6 +335,8 @@ static int __init test_power_init(void)
}
}
+ test_battery_configure_battery_hook(true);
+
module_initialized = true;
return 0;
failed:
@@ -524,6 +603,22 @@ static int param_set_battery_current(const char *key,
#define param_get_battery_current param_get_int
+static int param_set_battery_hook(const char *key,
+ const struct kernel_param *kp)
+{
+ int tmp;
+
+ if (1 != sscanf(key, "%d", &tmp))
+ return -EINVAL;
+ if (tmp != 1 && tmp != 0)
+ return -EINVAL;
+
+ test_battery_configure_battery_hook(tmp);
+ return 0;
+}
+
+#define param_get_battery_hook param_get_int
+
static const struct kernel_param_ops param_ops_ac_online = {
.set = param_set_ac_online,
.get = param_get_ac_online,
@@ -574,6 +669,11 @@ static const struct kernel_param_ops param_ops_battery_current = {
.get = param_get_battery_current,
};
+static const struct kernel_param_ops param_ops_battery_hook = {
+ .set = param_set_battery_hook,
+ .get = param_get_battery_hook,
+};
+
#define param_check_ac_online(name, p) __param_check(name, p, void);
#define param_check_usb_online(name, p) __param_check(name, p, void);
#define param_check_battery_status(name, p) __param_check(name, p, void);
@@ -584,6 +684,7 @@ static const struct kernel_param_ops param_ops_battery_current = {
#define param_check_battery_voltage(name, p) __param_check(name, p, void);
#define param_check_battery_charge_counter(name, p) __param_check(name, p, void);
#define param_check_battery_current(name, p) __param_check(name, p, void);
+#define param_check_battery_hook(name, p) __param_check(name, p, void);
module_param(ac_online, ac_online, 0644);
@@ -621,6 +722,9 @@ MODULE_PARM_DESC(battery_charge_counter,
module_param(battery_current, battery_current, 0644);
MODULE_PARM_DESC(battery_current, "battery current (milliampere)");
+module_param(battery_hook, battery_hook, 0644);
+MODULE_PARM_DESC(battery_hook, "battery hook");
+
MODULE_DESCRIPTION("Power supply driver for testing");
MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
MODULE_LICENSE("GPL");
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH RFC v3 9/9] power: supply: cros_charge-control: use power_supply extensions
2024-09-04 19:25 [PATCH RFC v3 0/9] power: supply: extension API Thomas Weißschuh
` (7 preceding siblings ...)
2024-09-04 19:25 ` [PATCH RFC v3 8/9] power: supply: test-power: implement a power supply extension Thomas Weißschuh
@ 2024-09-04 19:25 ` Thomas Weißschuh
8 siblings, 0 replies; 24+ messages in thread
From: Thomas Weißschuh @ 2024-09-04 19:25 UTC (permalink / raw)
To: Sebastian Reichel, Armin Wolf, Hans de Goede
Cc: linux-pm, linux-kernel, Thomas Weißschuh
Power supply extensions provide an easier mechanism to implement
additional properties for existing power supplies.
Use that instead of reimplementing the sysfs attributes manually.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/power/supply/cros_charge-control.c | 207 +++++++++++------------------
1 file changed, 78 insertions(+), 129 deletions(-)
diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/supply/cros_charge-control.c
index 17c53591ce19..dbfd87f8eb1d 100644
--- a/drivers/power/supply/cros_charge-control.c
+++ b/drivers/power/supply/cros_charge-control.c
@@ -18,13 +18,6 @@
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE))
-enum CROS_CHCTL_ATTR {
- CROS_CHCTL_ATTR_START_THRESHOLD,
- CROS_CHCTL_ATTR_END_THRESHOLD,
- CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR,
- _CROS_CHCTL_ATTR_COUNT
-};
-
/*
* Semantics of data *returned* from the EC API and Linux sysfs differ
* slightly, also the v1 API can not return any data.
@@ -41,13 +34,7 @@ struct cros_chctl_priv {
struct power_supply *hooked_battery;
u8 cmd_version;
- /* The callbacks need to access this priv structure.
- * As neither the struct device nor power_supply are under the drivers
- * control, embed the attributes within priv to use with container_of().
- */
- struct device_attribute device_attrs[_CROS_CHCTL_ATTR_COUNT];
- struct attribute *attributes[_CROS_CHCTL_ATTR_COUNT];
- struct attribute_group group;
+ struct power_supply_ext psy_ext;
enum power_supply_charge_behaviour current_behaviour;
u8 current_start_threshold, current_end_threshold;
@@ -114,123 +101,86 @@ static int cros_chctl_configure_ec(struct cros_chctl_priv *priv)
return cros_chctl_send_charge_control_cmd(priv->cros_ec, priv->cmd_version, &req);
}
-static struct cros_chctl_priv *cros_chctl_attr_to_priv(struct attribute *attr,
- enum CROS_CHCTL_ATTR idx)
-{
- struct device_attribute *dev_attr = container_of(attr, struct device_attribute, attr);
+static const enum power_supply_property cros_chctl_psy_ext_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+};
- return container_of(dev_attr, struct cros_chctl_priv, device_attrs[idx]);
-}
+static const enum power_supply_property cros_chctl_psy_ext_props_v1[] = {
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+};
-static ssize_t cros_chctl_store_threshold(struct device *dev, struct cros_chctl_priv *priv,
- int is_end_threshold, const char *buf, size_t count)
+static int cros_chctl_psy_ext_get_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
{
- int ret, val;
+ struct cros_chctl_priv *priv = data;
- ret = kstrtoint(buf, 10, &val);
- if (ret < 0)
- return ret;
- if (val < 0 || val > 100)
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
+ val->intval = priv->current_start_threshold;
+ return 0;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ val->intval = priv->current_end_threshold;
+ return 0;
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ val->intval = priv->current_behaviour;
+ return 0;
+ default:
return -EINVAL;
-
- if (is_end_threshold) {
- if (val <= priv->current_start_threshold)
- return -EINVAL;
- priv->current_end_threshold = val;
- } else {
- if (val >= priv->current_end_threshold)
- return -EINVAL;
- priv->current_start_threshold = val;
- }
-
- if (priv->current_behaviour == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) {
- ret = cros_chctl_configure_ec(priv);
- if (ret < 0)
- return ret;
}
-
- return count;
-}
-
-static ssize_t charge_control_start_threshold_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_START_THRESHOLD);
-
- return sysfs_emit(buf, "%u\n", (unsigned int)priv->current_start_threshold);
-}
-
-static ssize_t charge_control_start_threshold_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_START_THRESHOLD);
-
- return cros_chctl_store_threshold(dev, priv, 0, buf, count);
-}
-
-static ssize_t charge_control_end_threshold_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_END_THRESHOLD);
-
- return sysfs_emit(buf, "%u\n", (unsigned int)priv->current_end_threshold);
-}
-
-static ssize_t charge_control_end_threshold_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_END_THRESHOLD);
-
- return cros_chctl_store_threshold(dev, priv, 1, buf, count);
}
-static ssize_t charge_behaviour_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR);
-
- return power_supply_charge_behaviour_show(dev, EC_CHARGE_CONTROL_BEHAVIOURS,
- priv->current_behaviour, buf);
-}
-static ssize_t charge_behaviour_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static int cros_chctl_psy_ext_set_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR);
+ struct cros_chctl_priv *priv = data;
int ret;
- ret = power_supply_charge_behaviour_parse(EC_CHARGE_CONTROL_BEHAVIOURS, buf);
- if (ret < 0)
- return ret;
-
- priv->current_behaviour = ret;
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ if (val->intval < 0 || val->intval > 100)
+ return -EINVAL;
- ret = cros_chctl_configure_ec(priv);
- if (ret < 0)
- return ret;
+ if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) {
+ if (val->intval <= priv->current_start_threshold)
+ return -EINVAL;
+ priv->current_end_threshold = val->intval;
+ } else {
+ if (val->intval >= priv->current_end_threshold)
+ return -EINVAL;
+ priv->current_start_threshold = val->intval;
+ }
+
+ if (priv->current_behaviour == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) {
+ ret = cros_chctl_configure_ec(priv);
+ if (ret < 0)
+ return ret;
+ }
- return count;
+ return 0;
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ priv->current_behaviour = val->intval;
+ return cros_chctl_configure_ec(priv); /* FIXME > 0 */
+ default:
+ return -EINVAL;
+ }
}
-static umode_t cros_chtl_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+static int cros_chctl_psy_prop_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp)
{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(attr, n);
-
- if (priv->cmd_version < 2) {
- if (n == CROS_CHCTL_ATTR_START_THRESHOLD)
- return 0;
- if (n == CROS_CHCTL_ATTR_END_THRESHOLD)
- return 0;
- }
-
- return attr->mode;
+ return true;
}
static int cros_chctl_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
@@ -241,7 +191,7 @@ static int cros_chctl_add_battery(struct power_supply *battery, struct acpi_batt
return 0;
priv->hooked_battery = battery;
- return device_add_group(&battery->dev, &priv->group);
+ return power_supply_register_extension(battery, &priv->psy_ext, priv);
}
static int cros_chctl_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
@@ -249,7 +199,7 @@ static int cros_chctl_remove_battery(struct power_supply *battery, struct acpi_b
struct cros_chctl_priv *priv = container_of(hook, struct cros_chctl_priv, battery_hook);
if (priv->hooked_battery == battery) {
- device_remove_group(&battery->dev, &priv->group);
+ power_supply_unregister_extension(battery, &priv->psy_ext);
priv->hooked_battery = NULL;
}
@@ -275,7 +225,6 @@ static int cros_chctl_probe(struct platform_device *pdev)
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
struct cros_chctl_priv *priv;
- size_t i;
int ret;
ret = cros_chctl_fwk_charge_control_versions(cros_ec);
@@ -305,23 +254,23 @@ static int cros_chctl_probe(struct platform_device *pdev)
dev_dbg(dev, "Command version: %u\n", (unsigned int)priv->cmd_version);
priv->cros_ec = cros_ec;
- priv->device_attrs[CROS_CHCTL_ATTR_START_THRESHOLD] =
- (struct device_attribute)__ATTR_RW(charge_control_start_threshold);
- priv->device_attrs[CROS_CHCTL_ATTR_END_THRESHOLD] =
- (struct device_attribute)__ATTR_RW(charge_control_end_threshold);
- priv->device_attrs[CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR] =
- (struct device_attribute)__ATTR_RW(charge_behaviour);
- for (i = 0; i < _CROS_CHCTL_ATTR_COUNT; i++) {
- sysfs_attr_init(&priv->device_attrs[i].attr);
- priv->attributes[i] = &priv->device_attrs[i].attr;
- }
- priv->group.is_visible = cros_chtl_attr_is_visible;
- priv->group.attrs = priv->attributes;
priv->battery_hook.name = dev_name(dev);
priv->battery_hook.add_battery = cros_chctl_add_battery;
priv->battery_hook.remove_battery = cros_chctl_remove_battery;
+ if (priv->cmd_version == 1) {
+ priv->psy_ext.properties = cros_chctl_psy_ext_props_v1;
+ priv->psy_ext.num_properties = ARRAY_SIZE(cros_chctl_psy_ext_props_v1);
+ } else {
+ priv->psy_ext.properties = cros_chctl_psy_ext_props;
+ priv->psy_ext.num_properties = ARRAY_SIZE(cros_chctl_psy_ext_props);
+ }
+ priv->psy_ext.charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS;
+ priv->psy_ext.get_property = cros_chctl_psy_ext_get_prop;
+ priv->psy_ext.set_property = cros_chctl_psy_ext_set_prop;
+ priv->psy_ext.property_is_writeable = cros_chctl_psy_prop_is_writeable;
+
priv->current_behaviour = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
priv->current_start_threshold = 0;
priv->current_end_threshold = 100;
--
2.46.0
^ permalink raw reply related [flat|nested] 24+ messages in thread