]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: i2c: lm3560: Fix v4l2 subdev registration
authorSvyatoslav Ryhel <clamor95@gmail.com>
Wed, 6 May 2026 06:48:43 +0000 (09:48 +0300)
committerSakari Ailus <sakari.ailus@linux.intel.com>
Fri, 15 May 2026 12:00:44 +0000 (15:00 +0300)
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>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
drivers/media/i2c/lm3560.c

index f4cc844f4e3cc902f0ae8d82c298c1f51a15243e..edfb07587cab5bba9bc5d6b516c96dcd0f60a7c1 100644 (file)
@@ -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[] = {