[PATCH 05/21] leds: pca955x: Take a reference on the child firmware node

From: Lee Jones

Date: Wed Oct 21 2026 - 08:45:44 EST


pca955x_get_pdata() caches each child fwnode in led->fwnode while
iterating over the device's child nodes with
device_for_each_child_node(), which drops its reference on each child
node when advancing to the next iteration or finishing the loop.
Because the LED core stores init_data.fwnode via device_set_node()
without taking an additional reference of its own, dynamically
allocated firmware nodes can be freed before or while the LED class
device uses them.

Acquire a reference with fwnode_handle_get() when caching child in
led->fwnode and register a devm action to release it when the device is
unbound or probe fails.

Fixes: 7c4815929276 ("leds: pca955x: Let the core process the fwnode")
Closes: https://sashiko.dev/#/bug/linux-a78a30d3-e8c1-43eb-af6c-c26279dc21e7
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Lee Jones <lee@xxxxxxxxxx>
---
drivers/leds/leds-pca955x.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 273383351ba0..70043e0e6f08 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -530,12 +530,16 @@ static int pca955x_gpio_direction_output(struct gpio_chip *gc,
}
#endif /* CONFIG_LEDS_PCA955X_GPIO */

+static void pca955x_fwnode_put(void *data)
+{
+ fwnode_handle_put(data);
+}
+
static struct pca955x_platform_data *
pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
{
struct pca955x_platform_data *pdata;
struct pca955x_led *led;
- struct fwnode_handle *child;
int count;

count = device_get_child_node_count(&client->dev);
@@ -552,7 +556,7 @@ pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
if (!pdata->leds)
return ERR_PTR(-ENOMEM);

- device_for_each_child_node(&client->dev, child) {
+ device_for_each_child_node_scoped(&client->dev, child) {
u32 reg;
int res;

@@ -561,8 +565,17 @@ pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
continue;

led = &pdata->leds[reg];
+ if (led->fwnode)
+ devm_release_action(&client->dev, pca955x_fwnode_put,
+ led->fwnode);
led->type = PCA955X_TYPE_LED;
- led->fwnode = child;
+ led->fwnode = fwnode_handle_get(child);
+
+ res = devm_add_action_or_reset(&client->dev, pca955x_fwnode_put,
+ led->fwnode);
+ if (res)
+ return ERR_PTR(res);
+
led->default_state = led_init_default_state_get(child);

fwnode_property_read_u32(child, "type", &led->type);
--
2.56.0.218.g1ec904b173-goog