Re: [PATCH v1] power_supply: Add a helper function to retrieve psy array from phandle

From: Sebastian Reichel
Date: Mon Apr 13 2020 - 18:29:59 EST


Hi,

On Tue, Apr 07, 2020 at 02:12:43PM -0700, Badhri Jagan Sridharan wrote:
> power_supply_get_by_phandle retrieves power_supply object based on
> phandle. However, when multiple power_supply objects are registered
> by the same parent device the first power_supply object's reference
> is returned. This varies according to probe order. Add a helper to
> return all the power_supply object's reference.
>
> The caller has to provide the power_supply pointer array.
> -EOVERFLOW is returned when the size of the array is not enough to
> pass back all the power_supply objects.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@xxxxxxxxxx>
> ---

This patchset is incomplete, it is missing a mainline user.

-- Sebastian

> drivers/power/supply/power_supply_core.c | 78 ++++++++++++++++++++++++
> include/linux/power_supply.h | 9 +++
> 2 files changed, 87 insertions(+)
>
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index 1a9a9fae73d32..e7bab4661ba13 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -32,6 +32,13 @@ EXPORT_SYMBOL_GPL(power_supply_notifier);
>
> static struct device_type power_supply_dev_type;
>
> +struct match_device_node_array_param {
> + struct device_node *parent_of_node;
> + struct power_supply **psy;
> + ssize_t psy_size;
> + ssize_t psy_count;
> +};
> +
> #define POWER_SUPPLY_DEFERRED_REGISTER_TIME msecs_to_jiffies(10)
>
> static bool __power_supply_is_supplied_by(struct power_supply *supplier,
> @@ -522,6 +529,77 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np,
> }
> EXPORT_SYMBOL_GPL(power_supply_get_by_phandle);
>
> +static int power_supply_match_device_node_array(struct device *dev,
> + void *data)
> +{
> + struct match_device_node_array_param *param =
> + (struct match_device_node_array_param *)data;
> + struct power_supply **psy = param->psy;
> + ssize_t size = param->psy_size;
> + ssize_t *count = &param->psy_count;
> +
> + if (!dev->parent || dev->parent->of_node != param->parent_of_node)
> + return 0;
> +
> + if (*count >= size)
> + return -EOVERFLOW;
> +
> + psy[*count] = dev_get_drvdata(dev);
> + atomic_inc(&psy[*count]->use_cnt);
> + (*count)++;
> +
> + return 0;
> +}
> +
> +/**
> + * power_supply_get_by_phandle_array() - Similar to
> + * power_supply_get_by_phandle but returns an array of power supply
> + * objects which are associated with the phandle.
> + * @np: Pointer to device node holding phandle property.
> + * @property: Name of property holding a power supply name.
> + * @psy: Array of power_supply pointers provided by the client which is
> + * filled by power_supply_get_by_phandle_array.
> + * @size: size of power_supply pointer array.
> + *
> + * If power supply was found, it increases reference count for the
> + * internal power supply's device. The user should power_supply_put()
> + * after usage.
> + *
> + * Return: On success returns the number of power supply objects filled
> + * in the @psy array.
> + * -EOVERFLOW when size of @psy array is not suffice.
> + * -EINVAL when @psy is NULL or @size is 0.
> + * -ENODEV when matching device_node is not found.
> + */
> +int power_supply_get_by_phandle_array(struct device_node *np,
> + const char *property,
> + struct power_supply **psy,
> + ssize_t size)
> +{
> + struct device_node *power_supply_np;
> + int ret;
> + struct match_device_node_array_param param;
> +
> + if (psy == NULL || size == 0)
> + return -EINVAL;
> +
> + power_supply_np = of_parse_phandle(np, property, 0);
> + if (!power_supply_np)
> + return -ENODEV;
> +
> + param.parent_of_node = power_supply_np;
> + param.psy = psy;
> + param.psy_size = size;
> + param.psy_count = 0;
> + ret = class_for_each_device(power_supply_class, NULL, &param,
> + power_supply_match_device_node_array);
> +
> + of_node_put(power_supply_np);
> +
> + return param.psy_count;
> +}
> +EXPORT_SYMBOL_GPL(power_supply_get_by_phandle_array);
> +
> static void devm_power_supply_put(struct device *dev, void *res)
> {
> struct power_supply **psy = res;
> diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> index dcd5a71e6c677..8c1478a480674 100644
> --- a/include/linux/power_supply.h
> +++ b/include/linux/power_supply.h
> @@ -366,12 +366,21 @@ extern void power_supply_put(struct power_supply *psy);
> #ifdef CONFIG_OF
> extern struct power_supply *power_supply_get_by_phandle(struct device_node *np,
> const char *property);
> +extern int power_supply_get_by_phandle_array(struct device_node *np,
> + const char *property,
> + struct power_supply **psy,
> + ssize_t size);
> extern struct power_supply *devm_power_supply_get_by_phandle(
> struct device *dev, const char *property);
> #else /* !CONFIG_OF */
> static inline struct power_supply *
> power_supply_get_by_phandle(struct device_node *np, const char *property)
> { return NULL; }
> +static int power_supply_get_by_phandle_array(struct device_node *np,
> + const char *property,
> + struct power_supply **psy,
> + int size)
> +{ return 0; }
> static inline struct power_supply *
> devm_power_supply_get_by_phandle(struct device *dev, const char *property)
> { return NULL; }
> --
> 2.26.0.292.g33ef6b2f38-goog
>

Attachment: signature.asc
Description: PGP signature