ANDROID: 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 returned power_supply object's reference 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. Patch was sent to mainline linux, however, was deemed incomplete due to lack of mainline user. Link: https://lore.kernel.org/linux-pm/20200407211243.247362-1-badhri@google.com/T/ Bug: 161416774 Bug: 167486462 Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Change-Id: I6d9c52edb4472e73fc2d3c8eb32a41bec8bbde2a
This commit is contained in:
committed by
Alistair Delva
parent
2bd29a1007
commit
dea1a925f6
@@ -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 = ¶m->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 || !size)
|
||||
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, ¶m,
|
||||
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;
|
||||
|
||||
@@ -379,12 +379,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; }
|
||||
|
||||
Reference in New Issue
Block a user