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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®