[PATCH v5 2/6] media: i2c: lm3560: Fix v4l2 subdev registration

Svyatoslav Ryhel
2026-05-03T16:45:00Z

The existing driver does not call media subdev registration, making it
invisible to the media framework. Since the LM3560 supports two
independent LEDs, register each LED as a separate media entity.

Because registering LEDs before device initialization may cause access
attempts before the hardware is ready, lm3560_init_device has been moved
before the subdevice initializations.

An additional helper, lm3560_subdev_cleanup, was added to release LED0 if
the initialization of LED1 fails, and to deregister both LEDs in the
remove function.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/media/i2c/lm3560.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index f4cc844f4e3c..edfb07587cab 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -364,8 +364,15 @@ static int lm3560_subdev_init(struct lm3560_flash *flash,
goto err_out;
flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH;

- return rval;
+ rval = v4l2_async_register_subdev(&flash->subdev_led[led_no]);
+ if (rval < 0) {
+ dev_err(flash->dev, "failed to register V4L2 subdev");
+ goto error_out_media;
+ }

+ return rval;
+error_out_media:
+ media_entity_cleanup(&flash->subdev_led[led_no].entity);
err_out:
v4l2_ctrl_handler_free(&flash->ctrls_led[led_no]);
return rval;
@@ -391,6 +398,14 @@ static int lm3560_init_device(struct lm3560_flash *flash)
return rval;
}

+static void lm3560_subdev_cleanup(struct lm3560_flash *flash,
+ enum lm3560_led_id led_no)
+{
+ v4l2_async_unregister_subdev(&flash->subdev_led[led_no]);
+ v4l2_ctrl_handler_free(&flash->ctrls_led[led_no]);
+ media_entity_cleanup(&flash->subdev_led[led_no].entity);
+}
+
static int lm3560_probe(struct i2c_client *client)
{
struct lm3560_flash *flash;
@@ -425,17 +440,19 @@ static int lm3560_probe(struct i2c_client *client)
flash->dev = &client->dev;
mutex_init(&flash->lock);

- rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");
+ rval = lm3560_init_device(flash);
if (rval < 0)
return rval;

- rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");
+ rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");
if (rval < 0)
return rval;

- rval = lm3560_init_device(flash);
- if (rval < 0)
+ rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");
+ if (rval < 0) {
+ lm3560_subdev_cleanup(flash, LM3560_LED0);
return rval;
+ }

i2c_set_clientdata(client, flash);

@@ -447,11 +464,8 @@ static void lm3560_remove(struct i2c_client *client)
struct lm3560_flash *flash = i2c_get_clientdata(client);
unsigned int i;

- for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) {
- v4l2_device_unregister_subdev(&flash->subdev_led[i]);
- v4l2_ctrl_handler_free(&flash->ctrls_led[i]);
- media_entity_cleanup(&flash->subdev_led[i].entity);
- }
+ for (i = LM3560_LED0; i < LM3560_LED_MAX; i++)
+ lm3560_subdev_cleanup(flash, i);
}

static const struct i2c_device_id lm3560_id_table[] = {
--
2.51.0