All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rosen Penev <rosenp@gmail.com>
To: linux-leds@vger.kernel.org
Cc: Lee Jones <lee@kernel.org>, Pavel Machek <pavel@kernel.org>,
	linux-kernel@vger.kernel.org (open list)
Subject: [PATCH v2] leds: pca955x: drop platform data and allocate LEDs with the device
Date: Mon,  5 Oct 2026 13:09:06 -0700	[thread overview]
Message-ID: <20261005200906.188636-1-rosenp@gmail.com> (raw)

struct pca955x_platform_data has been private to this driver since
commit ed1f4b9676a8 ("leds: pca955x: add device tree support"), so
nothing can pass it in through dev_get_platdata() and it only serves
as an intermediate copy of the per-LED type, default state and fwnode.
That copy is a full array of struct pca955x_led, the same runtime
structure that struct pca955x already holds, so the data is stored
twice.

Remove the platform data and parse the child firmware nodes directly
into pca955x->leds[]. Make leds[] a flexible array member so it is
allocated together with struct pca955x. This removes three
allocations and the num_leds sanity check, which could no longer
fail.

struct pca955x_led moves above struct pca955x, as a flexible array
member needs the complete element type.

Assisted-by: LLM
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 v2: remove platform_data.
 drivers/leds/leds-pca955x.c | 94 ++++++++++++-------------------------
 1 file changed, 31 insertions(+), 63 deletions(-)

diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 273383351ba0..e4af7a3b639f 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -79,6 +79,17 @@ struct pca955x_chipdef {
 	int			blink_div;	/* PSC divider */
 };
 
+struct pca955x_led {
+	struct pca955x	*pca955x;
+	struct led_classdev	led_cdev;
+	int			led_num;	/* 0 .. 15 potentially */
+	u32			type;
+	enum led_default_state	default_state;
+	struct fwnode_handle	*fwnode;
+};
+
+#define led_to_pca955x(l)	container_of(l, struct pca955x_led, led_cdev)
+
 static const struct pca955x_chipdef pca955x_chipdefs[] = {
 	[pca9550] = {
 		.bits		= 2,
@@ -114,7 +125,6 @@ static const struct pca955x_chipdef pca955x_chipdefs[] = {
 
 struct pca955x {
 	struct mutex lock;
-	struct pca955x_led *leds;
 	const struct pca955x_chipdef	*chipdef;
 	struct i2c_client	*client;
 	unsigned long active_blink;
@@ -123,22 +133,7 @@ struct pca955x {
 #ifdef CONFIG_LEDS_PCA955X_GPIO
 	struct gpio_chip gpio;
 #endif
-};
-
-struct pca955x_led {
-	struct pca955x	*pca955x;
-	struct led_classdev	led_cdev;
-	int			led_num;	/* 0 .. 15 potentially */
-	u32			type;
-	enum led_default_state	default_state;
-	struct fwnode_handle	*fwnode;
-};
-
-#define led_to_pca955x(l)	container_of(l, struct pca955x_led, led_cdev)
-
-struct pca955x_platform_data {
-	struct pca955x_led	*leds;
-	int			num_leds;
+	struct pca955x_led leds[];
 };
 
 /* 8 bits per input register */
@@ -530,37 +525,27 @@ static int pca955x_gpio_direction_output(struct gpio_chip *gc,
 }
 #endif /* CONFIG_LEDS_PCA955X_GPIO */
 
-static struct pca955x_platform_data *
-pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
+static int pca955x_parse_fwnode(struct pca955x *pca955x)
 {
-	struct pca955x_platform_data *pdata;
+	struct device *dev = &pca955x->client->dev;
+	u8 bits = pca955x->chipdef->bits;
 	struct pca955x_led *led;
 	struct fwnode_handle *child;
 	int count;
 
-	count = device_get_child_node_count(&client->dev);
-	if (count > chip->bits)
-		return ERR_PTR(-ENODEV);
-
-	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return ERR_PTR(-ENOMEM);
-
-	pdata->leds = devm_kcalloc(&client->dev,
-				   chip->bits, sizeof(struct pca955x_led),
-				   GFP_KERNEL);
-	if (!pdata->leds)
-		return ERR_PTR(-ENOMEM);
+	count = device_get_child_node_count(dev);
+	if (count > bits)
+		return -ENODEV;
 
-	device_for_each_child_node(&client->dev, child) {
+	device_for_each_child_node(dev, child) {
 		u32 reg;
 		int res;
 
 		res = fwnode_property_read_u32(child, "reg", &reg);
-		if ((res != 0) || (reg >= chip->bits))
+		if ((res != 0) || (reg >= bits))
 			continue;
 
-		led = &pdata->leds[reg];
+		led = &pca955x->leds[reg];
 		led->type = PCA955X_TYPE_LED;
 		led->fwnode = child;
 		led->default_state = led_init_default_state_get(child);
@@ -568,9 +553,7 @@ pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip)
 		fwnode_property_read_u32(child, "type", &led->type);
 	}
 
-	pdata->num_leds = chip->bits;
-
-	return pdata;
+	return 0;
 }
 
 static int pca955x_probe(struct i2c_client *client)
@@ -584,7 +567,6 @@ static int pca955x_probe(struct i2c_client *client)
 	u8 i, nls, psc0;
 	u8 ls1[4];
 	u8 ls2[4];
-	struct pca955x_platform_data *pdata;
 	bool keep_psc0 = false;
 	bool set_default_label = false;
 	char default_label[4];
@@ -595,12 +577,6 @@ static int pca955x_probe(struct i2c_client *client)
 		return dev_err_probe(&client->dev, -ENODEV, "unknown chip\n");
 
 	adapter = client->adapter;
-	pdata = dev_get_platdata(&client->dev);
-	if (!pdata) {
-		pdata =	pca955x_get_pdata(client, chip);
-		if (IS_ERR(pdata))
-			return PTR_ERR(pdata);
-	}
 
 	/* Make sure the slave address / chip type combo given is possible */
 	if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) !=
@@ -616,22 +592,11 @@ static int pca955x_probe(struct i2c_client *client)
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
-	if (pdata->num_leds != chip->bits) {
-		dev_err(&client->dev,
-			"board info claims %d LEDs on a %u-bit chip\n",
-			pdata->num_leds, chip->bits);
-		return -ENODEV;
-	}
-
-	pca955x = devm_kzalloc(&client->dev, sizeof(*pca955x), GFP_KERNEL);
+	pca955x = devm_kzalloc(&client->dev,
+			       struct_size(pca955x, leds, chip->bits), GFP_KERNEL);
 	if (!pca955x)
 		return -ENOMEM;
 
-	pca955x->leds = devm_kcalloc(&client->dev, chip->bits,
-				     sizeof(*pca955x_led), GFP_KERNEL);
-	if (!pca955x->leds)
-		return -ENOMEM;
-
 	i2c_set_clientdata(client, pca955x);
 
 	mutex_init(&pca955x->lock);
@@ -639,6 +604,10 @@ static int pca955x_probe(struct i2c_client *client)
 	pca955x->chipdef = chip;
 	pca955x->blink_period = PCA955X_BLINK_DEFAULT_MS;
 
+	err = pca955x_parse_fwnode(pca955x);
+	if (err)
+		return err;
+
 	init_data.devname_mandatory = false;
 	init_data.devicename = "pca955x";
 
@@ -657,7 +626,6 @@ static int pca955x_probe(struct i2c_client *client)
 		pca955x_led = &pca955x->leds[i];
 		pca955x_led->led_num = i;
 		pca955x_led->pca955x = pca955x;
-		pca955x_led->type = pdata->leds[i].type;
 
 		switch (pca955x_led->type) {
 		case PCA955X_TYPE_NONE:
@@ -671,16 +639,16 @@ static int pca955x_probe(struct i2c_client *client)
 			led->brightness_get = pca955x_led_get;
 			led->blink_set = pca955x_led_blink;
 
-			if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF)
+			if (pca955x_led->default_state == LEDS_DEFSTATE_OFF)
 				ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_OFF);
-			else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON)
+			else if (pca955x_led->default_state == LEDS_DEFSTATE_ON)
 				ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_ON);
 			else if (pca955x_ledstate(ls2[reg], bit) == PCA955X_LS_BLINK0) {
 				keep_psc0 = true;
 				set_bit(i, &pca955x->active_blink);
 			}
 
-			init_data.fwnode = pdata->leds[i].fwnode;
+			init_data.fwnode = pca955x_led->fwnode;
 
 			if (is_of_node(init_data.fwnode)) {
 				if (to_of_node(init_data.fwnode)->name[0] ==
-- 
2.56.0


             reply	other threads:[~2026-10-05 20:09 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05 20:09 Rosen Penev [this message]
2026-10-05 20:15 ` [PATCH v2] leds: pca955x: drop platform data and allocate LEDs with the device sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261005200906.188636-1-rosenp@gmail.com \
    --to=rosenp@gmail.com \
    --cc=lee@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=pavel@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.