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
reply other threads:[~2026-10-05 20:09 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®