2020-04-07 21:14:47

by Badhri Jagan Sridharan

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

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 <[email protected]>
---
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


2020-04-15 03:04:06

by Sebastian Reichel

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

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 <[email protected]>
> ---

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
>


Attachments:
(No filename) (5.41 kB)
signature.asc (849.00 B)
Download all attachments