Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 8325642d2757 ("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>

authored by

Javier Carrasco and committed by
Lee Jones
ffbf1fcb 29357f8a

+10 -13
+10 -13
drivers/leds/leds-bd2606mvv.c
··· 69 69 70 70 static int bd2606mvv_probe(struct i2c_client *client) 71 71 { 72 - struct fwnode_handle *np, *child; 73 72 struct device *dev = &client->dev; 74 73 struct bd2606mvv_priv *priv; 75 74 struct fwnode_handle *led_fwnodes[BD2606_MAX_LEDS] = { 0 }; 76 75 int active_pairs[BD2606_MAX_LEDS / 2] = { 0 }; 77 76 int err, reg; 78 - int i; 77 + int i, j; 79 78 80 - np = dev_fwnode(dev); 81 - if (!np) 79 + if (!dev_fwnode(dev)) 82 80 return -ENODEV; 83 81 84 82 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ··· 92 94 93 95 i2c_set_clientdata(client, priv); 94 96 95 - fwnode_for_each_available_child_node(np, child) { 97 + device_for_each_child_node_scoped(dev, child) { 96 98 struct bd2606mvv_led *led; 97 99 98 100 err = fwnode_property_read_u32(child, "reg", &reg); 99 - if (err) { 100 - fwnode_handle_put(child); 101 + if (err) 101 102 return err; 102 - } 103 - if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg]) { 104 - fwnode_handle_put(child); 103 + 104 + if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg]) 105 105 return -EINVAL; 106 - } 106 + 107 107 led = &priv->leds[reg]; 108 - led_fwnodes[reg] = child; 108 + led_fwnodes[reg] = fwnode_handle_get(child); 109 109 active_pairs[reg / 2]++; 110 110 led->priv = priv; 111 111 led->led_no = reg; ··· 126 130 &priv->leds[i].ldev, 127 131 &init_data); 128 132 if (err < 0) { 129 - fwnode_handle_put(child); 133 + for (j = i; j < BD2606_MAX_LEDS; j++) 134 + fwnode_handle_put(led_fwnodes[j]); 130 135 return dev_err_probe(dev, err, 131 136 "couldn't register LED %s\n", 132 137 priv->leds[i].ldev.name);