leds: bd2606mvv: Fix device child node usage in bd2606mvv_probe()
The current implementation accesses the `child` fwnode handle outside of
fwnode_for_each_available_child_node() without incrementing its
refcount. Add the missing call to `fwnode_handle_get(child)`.
The cleanup process where `child` is accessed is not right either
because a single call to `fwnode_handle_put()` is carried out in case of
an error, ignoring unasigned nodes at the point when the error happens.
Keep `child` inside of the first loop, and use the helper pointer that
receives references via `fwnode_handle_get()` to handle the child nodes
within the second loop.
Moreover, the iterated nodes are direct children of the device node,
and the `device_for_each_child_node()` macro accounts for child node
availability. By restricting `child` to live within that loop, the
scoped version of it can be used to simplify the error handling.
`fwnode_for_each_available_child_node()` is meant to access the child
nodes of an fwnode, and therefore not direct child nodes of the device
node.
Use `device_for_each_child_node_scoped()` to indicate device's direct
child nodes.
Fixes: 8325642d27
("leds: bd2606mvv: Driver for the Rohm 6 Channel i2c LED driver")
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://lore.kernel.org/r/20240721-device_for_each_child_node-available-v2-3-f33748fd8b2d@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
parent
29357f8a8c
commit
ffbf1fcb42
@ -69,16 +69,14 @@ static const struct regmap_config bd2606mvv_regmap = {
|
|||||||
|
|
||||||
static int bd2606mvv_probe(struct i2c_client *client)
|
static int bd2606mvv_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct fwnode_handle *np, *child;
|
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct bd2606mvv_priv *priv;
|
struct bd2606mvv_priv *priv;
|
||||||
struct fwnode_handle *led_fwnodes[BD2606_MAX_LEDS] = { 0 };
|
struct fwnode_handle *led_fwnodes[BD2606_MAX_LEDS] = { 0 };
|
||||||
int active_pairs[BD2606_MAX_LEDS / 2] = { 0 };
|
int active_pairs[BD2606_MAX_LEDS / 2] = { 0 };
|
||||||
int err, reg;
|
int err, reg;
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
np = dev_fwnode(dev);
|
if (!dev_fwnode(dev))
|
||||||
if (!np)
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
@ -94,20 +92,18 @@ static int bd2606mvv_probe(struct i2c_client *client)
|
|||||||
|
|
||||||
i2c_set_clientdata(client, priv);
|
i2c_set_clientdata(client, priv);
|
||||||
|
|
||||||
fwnode_for_each_available_child_node(np, child) {
|
device_for_each_child_node_scoped(dev, child) {
|
||||||
struct bd2606mvv_led *led;
|
struct bd2606mvv_led *led;
|
||||||
|
|
||||||
err = fwnode_property_read_u32(child, "reg", ®);
|
err = fwnode_property_read_u32(child, "reg", ®);
|
||||||
if (err) {
|
if (err)
|
||||||
fwnode_handle_put(child);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg]) {
|
if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg])
|
||||||
fwnode_handle_put(child);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
led = &priv->leds[reg];
|
led = &priv->leds[reg];
|
||||||
led_fwnodes[reg] = child;
|
led_fwnodes[reg] = fwnode_handle_get(child);
|
||||||
active_pairs[reg / 2]++;
|
active_pairs[reg / 2]++;
|
||||||
led->priv = priv;
|
led->priv = priv;
|
||||||
led->led_no = reg;
|
led->led_no = reg;
|
||||||
@ -130,7 +126,8 @@ static int bd2606mvv_probe(struct i2c_client *client)
|
|||||||
&priv->leds[i].ldev,
|
&priv->leds[i].ldev,
|
||||||
&init_data);
|
&init_data);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fwnode_handle_put(child);
|
for (j = i; j < BD2606_MAX_LEDS; j++)
|
||||||
|
fwnode_handle_put(led_fwnodes[j]);
|
||||||
return dev_err_probe(dev, err,
|
return dev_err_probe(dev, err,
|
||||||
"couldn't register LED %s\n",
|
"couldn't register LED %s\n",
|
||||||
priv->leds[i].ldev.name);
|
priv->leds[i].ldev.name);
|
||||||
|
Loading…
Reference in New Issue
Block a user