From: Sebastian Reichel <sebastian.reichel@collabora.com>
To: Alexey Charkov <alchark@flipper.net>
Cc: Lee Jones <lee@kernel.org>,
Chris Morgan <macromorgan@hotmail.com>,
Pavel Machek <pavel@ucw.cz>,
Krzysztof Kozlowski <krzk@kernel.org>,
Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>,
linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/4] power: supply: core: Allow getting battery info before psy is registered
Date: Wed, 9 Sep 2026 21:52:11 +0200 [thread overview]
Message-ID: <aqG3p_GKtncRCRI8@venus> (raw)
In-Reply-To: <20260909-bq257xx-init-v2-2-deb4076b1f02@flipper.net>
[-- Attachment #1: Type: text/plain, Size: 11204 bytes --]
Hello Alexey,
On Wed, Sep 09, 2026 at 07:41:45PM +0400, Alexey Charkov wrote:
> Some power supplies, such as battery chargers, may need to program the
> device parameters based on what their connected battery allows. Current
> API requires registering the power supply to access battery information,
> which is problematic because a registered power supply is immediately
> available to the rest of the system, but the battery parameters may not
> be set yet in the charger.
>
> Given that the battery info helpers really only need a fwnode and a struct
> device to hang devres-allocated resourses on, add a pure dev-based get/put
> API alongside the existing psy-based one, which can be used to query the
> battery information before registering the power supply.
Use the new init callback for that, which got introduced in the v7.3
cycle:
c1eb5905fdce ("power: supply: Add registration init callback")
See for example fdece8642eca ("power: supply: bq25630: Initialize
hardware before exposing the power supply") for a driver that was
converted to this.
Greetings,
-- Sebastian
>
> Signed-off-by: Alexey Charkov <alchark@flipper.net>
> ---
> drivers/power/supply/power_supply_core.c | 102 ++++++++++++++++++++++---------
> include/linux/power_supply.h | 4 ++
> 2 files changed, 77 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index 1279785645fb..09473361772f 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -725,21 +725,18 @@ struct power_supply *devm_power_supply_get_by_reference(struct device *dev,
> }
> EXPORT_SYMBOL_GPL(devm_power_supply_get_by_reference);
>
> -int power_supply_get_battery_info(struct power_supply *psy,
> - struct power_supply_battery_info **info_out)
> +static int __power_supply_get_battery_info(struct device *dev,
> + struct fwnode_handle *srcnode,
> + struct power_supply_battery_info **info_out)
> {
> struct power_supply_resistance_temp_table *resist_table;
> struct power_supply_battery_info *info;
> - struct fwnode_handle *srcnode, *fwnode;
> + struct fwnode_handle *fwnode;
> const char *value;
> int err, len, index, proplen;
> u32 *propdata __free(kfree) = NULL;
> u32 min_max[2];
>
> - srcnode = dev_fwnode(&psy->dev);
> - if (!srcnode && psy->dev.parent)
> - srcnode = dev_fwnode(psy->dev.parent);
> -
> fwnode = fwnode_find_reference(srcnode, "monitored-battery", 0);
> if (IS_ERR(fwnode))
> return PTR_ERR(fwnode);
> @@ -750,7 +747,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
>
>
> /* Try static batteries first */
> - err = samsung_sdi_battery_get_info(&psy->dev, value, &info);
> + err = samsung_sdi_battery_get_info(dev, value, &info);
> if (!err)
> goto out_ret_pointer;
> else if (err == -ENODEV)
> @@ -765,7 +762,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
> goto out_put_node;
> }
>
> - info = devm_kzalloc(&psy->dev, sizeof(*info), GFP_KERNEL);
> + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
> if (!info) {
> err = -ENOMEM;
> goto out_put_node;
> @@ -826,7 +823,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
> else if (!strcmp("lithium-ion-manganese-oxide", value))
> info->technology = POWER_SUPPLY_TECHNOLOGY_LiMn;
> else
> - dev_warn(&psy->dev, "%s unknown battery type\n", value);
> + dev_warn(dev, "%s unknown battery type\n", value);
> }
>
> fwnode_property_read_u32(fwnode, "energy-full-design-microwatt-hours",
> @@ -877,7 +874,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
> err = len;
> goto out_put_node;
> } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
> - dev_err(&psy->dev, "Too many temperature values\n");
> + dev_err(dev, "Too many temperature values\n");
> err = -EINVAL;
> goto out_put_node;
> } else if (len > 0) {
> @@ -892,28 +889,28 @@ int power_supply_get_battery_info(struct power_supply *psy,
> char *propname __free(kfree) = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d",
> index);
> if (!propname) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = -ENOMEM;
> goto out_put_node;
> }
> proplen = fwnode_property_count_u32(fwnode, propname);
> if (proplen < 0 || proplen % 2 != 0) {
> - dev_err(&psy->dev, "failed to get %s\n", propname);
> - power_supply_put_battery_info(psy, info);
> + dev_err(dev, "failed to get %s\n", propname);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = -EINVAL;
> goto out_put_node;
> }
>
> u32 *propdata __free(kfree) = kzalloc_objs(*propdata, proplen);
> if (!propdata) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = -EINVAL;
> goto out_put_node;
> }
> err = fwnode_property_read_u32_array(fwnode, propname, propdata, proplen);
> if (err < 0) {
> - dev_err(&psy->dev, "failed to get %s\n", propname);
> - power_supply_put_battery_info(psy, info);
> + dev_err(dev, "failed to get %s\n", propname);
> + power_supply_put_battery_info_from_dev(dev, info);
> goto out_put_node;
> }
>
> @@ -921,9 +918,9 @@ int power_supply_get_battery_info(struct power_supply *psy,
> info->ocv_table_size[index] = tab_len;
>
> info->ocv_table[index] = table =
> - devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL);
> + devm_kcalloc(dev, tab_len, sizeof(*table), GFP_KERNEL);
> if (!info->ocv_table[index]) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = -ENOMEM;
> goto out_put_node;
> }
> @@ -939,14 +936,14 @@ int power_supply_get_battery_info(struct power_supply *psy,
> err = 0;
> goto out_ret_pointer;
> } else if (proplen < 0 || proplen % 2 != 0) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = (proplen < 0) ? proplen : -EINVAL;
> goto out_put_node;
> }
>
> propdata = kzalloc_objs(*propdata, proplen);
> if (!propdata) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = -ENOMEM;
> goto out_put_node;
> }
> @@ -954,17 +951,17 @@ int power_supply_get_battery_info(struct power_supply *psy,
> err = fwnode_property_read_u32_array(fwnode, "resistance-temp-table",
> propdata, proplen);
> if (err < 0) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> goto out_put_node;
> }
>
> info->resist_table_size = proplen / 2;
> - info->resist_table = resist_table = devm_kcalloc(&psy->dev,
> + info->resist_table = resist_table = devm_kcalloc(dev,
> info->resist_table_size,
> sizeof(*resist_table),
> GFP_KERNEL);
> if (!info->resist_table) {
> - power_supply_put_battery_info(psy, info);
> + power_supply_put_battery_info_from_dev(dev, info);
> err = -ENOMEM;
> goto out_put_node;
> }
> @@ -982,22 +979,69 @@ int power_supply_get_battery_info(struct power_supply *psy,
> fwnode_handle_put(fwnode);
> return err;
> }
> +
> +int power_supply_get_battery_info(struct power_supply *psy,
> + struct power_supply_battery_info **info_out)
> +{
> + struct fwnode_handle *srcnode;
> +
> + srcnode = dev_fwnode(&psy->dev);
> + if (!srcnode && psy->dev.parent)
> + srcnode = dev_fwnode(psy->dev.parent);
> +
> + return __power_supply_get_battery_info(&psy->dev, srcnode, info_out);
> +}
> EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
>
> -void power_supply_put_battery_info(struct power_supply *psy,
> - struct power_supply_battery_info *info)
> +/**
> + * power_supply_get_battery_info_from_dev() - Get battery info without a supply
> + * @dev: Device holding the "monitored-battery" reference, which also owns the
> + * devres allocations made for the returned info
> + * @info_out: Pointer to store the resulting battery info
> + *
> + * Same as power_supply_get_battery_info(), but keyed off a plain device rather
> + * than a registered power supply. Chargers that program hardware limits taken
> + * from the battery node need those values *before* they can safely register
> + * their power supply: registering makes the supply callable, so a later probe
> + * failure would free driver data underneath a running callback.
> + *
> + * Release the result with power_supply_put_battery_info_from_dev().
> + *
> + * Return: 0 on success or an error code on failure.
> + */
> +int power_supply_get_battery_info_from_dev(struct device *dev,
> + struct power_supply_battery_info **info_out)
> +{
> + return __power_supply_get_battery_info(dev, dev_fwnode(dev), info_out);
> +}
> +EXPORT_SYMBOL_GPL(power_supply_get_battery_info_from_dev);
> +
> +/**
> + * power_supply_put_battery_info_from_dev() - Release battery info
> + * @dev: Device passed to power_supply_get_battery_info_from_dev()
> + * @info: Battery info to release
> + */
> +void power_supply_put_battery_info_from_dev(struct device *dev,
> + struct power_supply_battery_info *info)
> {
> int i;
>
> for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) {
> if (info->ocv_table[i])
> - devm_kfree(&psy->dev, info->ocv_table[i]);
> + devm_kfree(dev, info->ocv_table[i]);
> }
>
> if (info->resist_table)
> - devm_kfree(&psy->dev, info->resist_table);
> + devm_kfree(dev, info->resist_table);
> +
> + devm_kfree(dev, info);
> +}
> +EXPORT_SYMBOL_GPL(power_supply_put_battery_info_from_dev);
>
> - devm_kfree(&psy->dev, info);
> +void power_supply_put_battery_info(struct power_supply *psy,
> + struct power_supply_battery_info *info)
> +{
> + power_supply_put_battery_info_from_dev(&psy->dev, info);
> }
> EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
>
> diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> index 131cafded72f..f42ae4e3bf81 100644
> --- a/include/linux/power_supply.h
> +++ b/include/linux/power_supply.h
> @@ -865,6 +865,10 @@ extern int power_supply_get_battery_info(struct power_supply *psy,
> struct power_supply_battery_info **info_out);
> extern void power_supply_put_battery_info(struct power_supply *psy,
> struct power_supply_battery_info *info);
> +extern int power_supply_get_battery_info_from_dev(struct device *dev,
> + struct power_supply_battery_info **info_out);
> +extern void power_supply_put_battery_info_from_dev(struct device *dev,
> + struct power_supply_battery_info *info);
> extern bool power_supply_battery_info_has_prop(struct power_supply_battery_info *info,
> enum power_supply_property psp);
> extern int power_supply_battery_info_get_prop(struct power_supply_battery_info *info,
>
> --
> 2.55.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2026-09-09 19:52 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 15:41 [PATCH v2 0/4] power: supply: Fix probe time race against driver teardown and battery parsing Alexey Charkov
2026-09-09 15:41 ` [PATCH v2 1/4] power: supply: core: prevent unregistering a power supply while a callback runs Alexey Charkov
2026-09-09 15:41 ` [PATCH v2 2/4] power: supply: core: Allow getting battery info before psy is registered Alexey Charkov
2026-09-09 19:52 ` Sebastian Reichel [this message]
2026-09-10 9:53 ` Alexey Charkov
2026-09-09 15:41 ` [PATCH v2 3/4] power: supply: bq257xx: Use psy directly instead of driver data Alexey Charkov
2026-09-09 15:41 ` [PATCH v2 4/4] power: supply: bq257xx: Parse battery info before registering power supply Alexey Charkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aqG3p_GKtncRCRI8@venus \
--to=sebastian.reichel@collabora.com \
--cc=alchark@flipper.net \
--cc=b.zolnierkie@samsung.com \
--cc=krzk@kernel.org \
--cc=lee@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=macromorgan@hotmail.com \
--cc=pavel@ucw.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.