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", ®);
- 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
next 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.