Skip to content

Commit 503dd28

Browse files
Sakari Ailusmchehab
authored andcommitted
media: v4l2-flash-led-class: Create separate sub-devices for indicators
The V4L2 flash interface allows controlling multiple LEDs through a single sub-devices if, and only if, these LEDs are of different types. This approach scales badly for flash controllers that drive multiple flash LEDs or for LED specific associations. Essentially, the original assumption of a LED driver chip that drives a single flash LED and an indicator LED is no longer valid. Address the matter by registering one sub-device per LED. Signed-off-by: Sakari Ailus <[email protected]> Reviewed-by: Jacek Anaszewski <[email protected]> Acked-by: Pavel Machek <[email protected]> Reviewed-by: Rui Miguel Silva <[email protected]> (for greybus/light) Acked-by: Hans Verkuil <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 428359c commit 503dd28

File tree

5 files changed

+117
-67
lines changed

5 files changed

+117
-67
lines changed

drivers/leds/leds-aat1290.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ static void aat1290_init_v4l2_flash_config(struct aat1290_led *led,
432432
strlcpy(v4l2_sd_cfg->dev_name, led_cdev->name,
433433
sizeof(v4l2_sd_cfg->dev_name));
434434

435-
s = &v4l2_sd_cfg->torch_intensity;
435+
s = &v4l2_sd_cfg->intensity;
436436
s->min = led->mm_current_scale[0];
437437
s->max = led_cfg->max_mm_current;
438438
s->step = 1;
@@ -504,7 +504,7 @@ static int aat1290_led_probe(struct platform_device *pdev)
504504

505505
/* Create V4L2 Flash subdev. */
506506
led->v4l2_flash = v4l2_flash_init(dev, of_fwnode_handle(sub_node),
507-
fled_cdev, NULL, &v4l2_flash_ops,
507+
fled_cdev, &v4l2_flash_ops,
508508
&v4l2_sd_cfg);
509509
if (IS_ERR(led->v4l2_flash)) {
510510
ret = PTR_ERR(led->v4l2_flash);

drivers/leds/leds-max77693.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ static void max77693_init_v4l2_flash_config(struct max77693_sub_led *sub_led,
856856
"%s %d-%04x", sub_led->fled_cdev.led_cdev.name,
857857
i2c_adapter_id(i2c->adapter), i2c->addr);
858858

859-
s = &v4l2_sd_cfg->torch_intensity;
859+
s = &v4l2_sd_cfg->intensity;
860860
s->min = TORCH_IOUT_MIN;
861861
s->max = sub_led->fled_cdev.led_cdev.max_brightness * TORCH_IOUT_STEP;
862862
s->step = TORCH_IOUT_STEP;
@@ -931,7 +931,7 @@ static int max77693_register_led(struct max77693_sub_led *sub_led,
931931

932932
/* Register in the V4L2 subsystem. */
933933
sub_led->v4l2_flash = v4l2_flash_init(dev, of_fwnode_handle(sub_node),
934-
fled_cdev, NULL, &v4l2_flash_ops,
934+
fled_cdev, &v4l2_flash_ops,
935935
&v4l2_sd_cfg);
936936
if (IS_ERR(sub_led->v4l2_flash)) {
937937
ret = PTR_ERR(sub_led->v4l2_flash);

drivers/media/v4l2-core/v4l2-flash-led-class.c

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
197197
{
198198
struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
199199
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
200-
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
200+
struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
201201
struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
202202
bool external_strobe;
203203
int ret = 0;
@@ -299,10 +299,26 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
299299
struct v4l2_flash_ctrl_data *ctrl_init_data)
300300
{
301301
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
302-
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
302+
struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
303303
struct v4l2_ctrl_config *ctrl_cfg;
304304
u32 mask;
305305

306+
/* Init INDICATOR_INTENSITY ctrl data */
307+
if (v4l2_flash->iled_cdev) {
308+
ctrl_init_data[INDICATOR_INTENSITY].cid =
309+
V4L2_CID_FLASH_INDICATOR_INTENSITY;
310+
ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
311+
__lfs_to_v4l2_ctrl_config(&flash_cfg->intensity,
312+
ctrl_cfg);
313+
ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
314+
ctrl_cfg->min = 0;
315+
ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
316+
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
317+
}
318+
319+
if (!led_cdev || WARN_ON(!(led_cdev->flags & LED_DEV_CAP_FLASH)))
320+
return;
321+
306322
/* Init FLASH_FAULT ctrl data */
307323
if (flash_cfg->flash_faults) {
308324
ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT;
@@ -330,27 +346,11 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
330346
/* Init TORCH_INTENSITY ctrl data */
331347
ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY;
332348
ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
333-
__lfs_to_v4l2_ctrl_config(&flash_cfg->torch_intensity, ctrl_cfg);
349+
__lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, ctrl_cfg);
334350
ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
335351
ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
336352
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
337353

338-
/* Init INDICATOR_INTENSITY ctrl data */
339-
if (v4l2_flash->iled_cdev) {
340-
ctrl_init_data[INDICATOR_INTENSITY].cid =
341-
V4L2_CID_FLASH_INDICATOR_INTENSITY;
342-
ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
343-
__lfs_to_v4l2_ctrl_config(&flash_cfg->indicator_intensity,
344-
ctrl_cfg);
345-
ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
346-
ctrl_cfg->min = 0;
347-
ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
348-
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
349-
}
350-
351-
if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
352-
return;
353-
354354
/* Init FLASH_STROBE ctrl data */
355355
ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE;
356356
ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
@@ -485,7 +485,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash)
485485
struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
486486
int ret = 0;
487487

488-
v4l2_flash_set_led_brightness(v4l2_flash, ctrls[TORCH_INTENSITY]);
488+
if (ctrls[TORCH_INTENSITY])
489+
v4l2_flash_set_led_brightness(v4l2_flash,
490+
ctrls[TORCH_INTENSITY]);
489491

490492
if (ctrls[INDICATOR_INTENSITY])
491493
v4l2_flash_set_led_brightness(v4l2_flash,
@@ -527,19 +529,21 @@ static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
527529
{
528530
struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
529531
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
530-
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
532+
struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
531533
struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
532534
int ret = 0;
533535

534536
if (!v4l2_fh_is_singular(&fh->vfh))
535537
return 0;
536538

537-
mutex_lock(&led_cdev->led_access);
539+
if (led_cdev) {
540+
mutex_lock(&led_cdev->led_access);
538541

539-
led_sysfs_disable(led_cdev);
540-
led_trigger_remove(led_cdev);
542+
led_sysfs_disable(led_cdev);
543+
led_trigger_remove(led_cdev);
541544

542-
mutex_unlock(&led_cdev->led_access);
545+
mutex_unlock(&led_cdev->led_access);
546+
}
543547

544548
if (led_cdev_ind) {
545549
mutex_lock(&led_cdev_ind->led_access);
@@ -556,9 +560,11 @@ static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
556560

557561
return 0;
558562
out_sync_device:
559-
mutex_lock(&led_cdev->led_access);
560-
led_sysfs_enable(led_cdev);
561-
mutex_unlock(&led_cdev->led_access);
563+
if (led_cdev) {
564+
mutex_lock(&led_cdev->led_access);
565+
led_sysfs_enable(led_cdev);
566+
mutex_unlock(&led_cdev->led_access);
567+
}
562568

563569
if (led_cdev_ind) {
564570
mutex_lock(&led_cdev_ind->led_access);
@@ -573,21 +579,24 @@ static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
573579
{
574580
struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
575581
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
576-
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
582+
struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
577583
struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
578584
int ret = 0;
579585

580586
if (!v4l2_fh_is_singular(&fh->vfh))
581587
return 0;
582588

583-
mutex_lock(&led_cdev->led_access);
589+
if (led_cdev) {
590+
mutex_lock(&led_cdev->led_access);
584591

585-
if (v4l2_flash->ctrls[STROBE_SOURCE])
586-
ret = v4l2_ctrl_s_ctrl(v4l2_flash->ctrls[STROBE_SOURCE],
592+
if (v4l2_flash->ctrls[STROBE_SOURCE])
593+
ret = v4l2_ctrl_s_ctrl(
594+
v4l2_flash->ctrls[STROBE_SOURCE],
587595
V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
588-
led_sysfs_enable(led_cdev);
596+
led_sysfs_enable(led_cdev);
589597

590-
mutex_unlock(&led_cdev->led_access);
598+
mutex_unlock(&led_cdev->led_access);
599+
}
591600

592601
if (led_cdev_ind) {
593602
mutex_lock(&led_cdev_ind->led_access);
@@ -605,25 +614,19 @@ static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
605614

606615
static const struct v4l2_subdev_ops v4l2_flash_subdev_ops;
607616

608-
struct v4l2_flash *v4l2_flash_init(
617+
static struct v4l2_flash *__v4l2_flash_init(
609618
struct device *dev, struct fwnode_handle *fwn,
610-
struct led_classdev_flash *fled_cdev,
611-
struct led_classdev *iled_cdev,
612-
const struct v4l2_flash_ops *ops,
613-
struct v4l2_flash_config *config)
619+
struct led_classdev_flash *fled_cdev, struct led_classdev *iled_cdev,
620+
const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config)
614621
{
615622
struct v4l2_flash *v4l2_flash;
616-
struct led_classdev *led_cdev;
617623
struct v4l2_subdev *sd;
618624
int ret;
619625

620-
if (!fled_cdev || !config)
626+
if (!config)
621627
return ERR_PTR(-EINVAL);
622628

623-
led_cdev = &fled_cdev->led_cdev;
624-
625-
v4l2_flash = devm_kzalloc(led_cdev->dev, sizeof(*v4l2_flash),
626-
GFP_KERNEL);
629+
v4l2_flash = devm_kzalloc(dev, sizeof(*v4l2_flash), GFP_KERNEL);
627630
if (!v4l2_flash)
628631
return ERR_PTR(-ENOMEM);
629632

@@ -632,7 +635,7 @@ struct v4l2_flash *v4l2_flash_init(
632635
v4l2_flash->iled_cdev = iled_cdev;
633636
v4l2_flash->ops = ops;
634637
sd->dev = dev;
635-
sd->fwnode = fwn ? fwn : dev_fwnode(led_cdev->dev);
638+
sd->fwnode = fwn ? fwn : dev_fwnode(dev);
636639
v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
637640
sd->internal_ops = &v4l2_flash_subdev_internal_ops;
638641
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -664,8 +667,26 @@ struct v4l2_flash *v4l2_flash_init(
664667

665668
return ERR_PTR(ret);
666669
}
670+
671+
struct v4l2_flash *v4l2_flash_init(
672+
struct device *dev, struct fwnode_handle *fwn,
673+
struct led_classdev_flash *fled_cdev,
674+
const struct v4l2_flash_ops *ops,
675+
struct v4l2_flash_config *config)
676+
{
677+
return __v4l2_flash_init(dev, fwn, fled_cdev, NULL, ops, config);
678+
}
667679
EXPORT_SYMBOL_GPL(v4l2_flash_init);
668680

681+
struct v4l2_flash *v4l2_flash_indicator_init(
682+
struct device *dev, struct fwnode_handle *fwn,
683+
struct led_classdev *iled_cdev,
684+
struct v4l2_flash_config *config)
685+
{
686+
return __v4l2_flash_init(dev, fwn, NULL, iled_cdev, NULL, config);
687+
}
688+
EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init);
689+
669690
void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
670691
{
671692
struct v4l2_subdev *sd;

drivers/staging/greybus/light.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct gb_light {
5858
bool ready;
5959
#if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS)
6060
struct v4l2_flash *v4l2_flash;
61+
struct v4l2_flash *v4l2_flash_ind;
6162
#endif
6263
};
6364

@@ -534,20 +535,20 @@ static int gb_lights_light_v4l2_register(struct gb_light *light)
534535
{
535536
struct gb_connection *connection = get_conn_from_light(light);
536537
struct device *dev = &connection->bundle->dev;
537-
struct v4l2_flash_config sd_cfg = { {0} };
538+
struct v4l2_flash_config sd_cfg = { {0} }, sd_cfg_ind = { {0} };
538539
struct led_classdev_flash *fled;
539540
struct led_classdev *iled = NULL;
540541
struct gb_channel *channel_torch, *channel_ind, *channel_flash;
541542

542543
channel_torch = get_channel_from_mode(light, GB_CHANNEL_MODE_TORCH);
543544
if (channel_torch)
544545
__gb_lights_channel_v4l2_config(&channel_torch->intensity_uA,
545-
&sd_cfg.torch_intensity);
546+
&sd_cfg.intensity);
546547

547548
channel_ind = get_channel_from_mode(light, GB_CHANNEL_MODE_INDICATOR);
548549
if (channel_ind) {
549550
__gb_lights_channel_v4l2_config(&channel_ind->intensity_uA,
550-
&sd_cfg.indicator_intensity);
551+
&sd_cfg_ind.intensity);
551552
iled = &channel_ind->fled.led_cdev;
552553
}
553554

@@ -557,6 +558,8 @@ static int gb_lights_light_v4l2_register(struct gb_light *light)
557558
fled = &channel_flash->fled;
558559

559560
snprintf(sd_cfg.dev_name, sizeof(sd_cfg.dev_name), "%s", light->name);
561+
snprintf(sd_cfg_ind.dev_name, sizeof(sd_cfg_ind.dev_name),
562+
"%s indicator", light->name);
560563

561564
/* Set the possible values to faults, in our case all faults */
562565
sd_cfg.flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT |
@@ -565,16 +568,26 @@ static int gb_lights_light_v4l2_register(struct gb_light *light)
565568
LED_FAULT_UNDER_VOLTAGE | LED_FAULT_INPUT_VOLTAGE |
566569
LED_FAULT_LED_OVER_TEMPERATURE;
567570

568-
light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, iled,
569-
&v4l2_flash_ops, &sd_cfg);
571+
light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, &v4l2_flash_ops,
572+
&sd_cfg);
570573
if (IS_ERR(light->v4l2_flash))
571574
return PTR_ERR(light->v4l2_flash);
572575

576+
if (channel_ind) {
577+
light->v4l2_flash_ind =
578+
v4l2_flash_indicator_init(dev, NULL, iled, &sd_cfg_ind);
579+
if (IS_ERR(light->v4l2_flash_ind)) {
580+
v4l2_flash_release(light->v4l2_flash);
581+
return PTR_ERR(light->v4l2_flash_ind);
582+
}
583+
}
584+
573585
return 0;
574586
}
575587

576588
static void gb_lights_light_v4l2_unregister(struct gb_light *light)
577589
{
590+
v4l2_flash_release(light->v4l2_flash_ind);
578591
v4l2_flash_release(light->v4l2_flash);
579592
}
580593
#else

include/media/v4l2-flash-led-class.h

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ struct v4l2_flash_ops {
5656
* struct v4l2_flash_config - V4L2 Flash sub-device initialization data
5757
* @dev_name: the name of the media entity,
5858
* unique in the system
59-
* @torch_intensity: constraints for the LED in torch mode
60-
* @indicator_intensity: constraints for the indicator LED
59+
* @intensity: non-flash strobe constraints for the LED
6160
* @flash_faults: bitmask of flash faults that the LED flash class
6261
* device can report; corresponding LED_FAULT* bit
6362
* definitions are available in the header file
@@ -66,8 +65,7 @@ struct v4l2_flash_ops {
6665
*/
6766
struct v4l2_flash_config {
6867
char dev_name[32];
69-
struct led_flash_setting torch_intensity;
70-
struct led_flash_setting indicator_intensity;
68+
struct led_flash_setting intensity;
7169
u32 flash_faults;
7270
unsigned int has_external_strobe:1;
7371
};
@@ -110,8 +108,6 @@ static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c)
110108
* @dev: flash device, e.g. an I2C device
111109
* @fwn: fwnode_handle of the LED, may be NULL if the same as device's
112110
* @fled_cdev: LED flash class device to wrap
113-
* @iled_cdev: LED flash class device representing indicator LED associated
114-
* with fled_cdev, may be NULL
115111
* @ops: V4L2 Flash device ops
116112
* @config: initialization data for V4L2 Flash sub-device
117113
*
@@ -124,9 +120,24 @@ static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c)
124120
struct v4l2_flash *v4l2_flash_init(
125121
struct device *dev, struct fwnode_handle *fwn,
126122
struct led_classdev_flash *fled_cdev,
127-
struct led_classdev *iled_cdev,
128-
const struct v4l2_flash_ops *ops,
129-
struct v4l2_flash_config *config);
123+
const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config);
124+
125+
/**
126+
* v4l2_flash_indicator_init - initialize V4L2 indicator sub-device
127+
* @dev: flash device, e.g. an I2C device
128+
* @fwn: fwnode_handle of the LED, may be NULL if the same as device's
129+
* @iled_cdev: LED flash class device representing the indicator LED
130+
* @config: initialization data for V4L2 Flash sub-device
131+
*
132+
* Create V4L2 Flash sub-device wrapping given LED subsystem device.
133+
*
134+
* Returns: A valid pointer, or, when an error occurs, the return
135+
* value is encoded using ERR_PTR(). Use IS_ERR() to check and
136+
* PTR_ERR() to obtain the numeric return value.
137+
*/
138+
struct v4l2_flash *v4l2_flash_indicator_init(
139+
struct device *dev, struct fwnode_handle *fwn,
140+
struct led_classdev *iled_cdev, struct v4l2_flash_config *config);
130141

131142
/**
132143
* v4l2_flash_release - release V4L2 Flash sub-device
@@ -140,9 +151,14 @@ void v4l2_flash_release(struct v4l2_flash *v4l2_flash);
140151
static inline struct v4l2_flash *v4l2_flash_init(
141152
struct device *dev, struct fwnode_handle *fwn,
142153
struct led_classdev_flash *fled_cdev,
143-
struct led_classdev *iled_cdev,
144-
const struct v4l2_flash_ops *ops,
145-
struct v4l2_flash_config *config)
154+
const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config)
155+
{
156+
return NULL;
157+
}
158+
159+
static inline struct v4l2_flash *v4l2_flash_indicator_init(
160+
struct device *dev, struct fwnode_handle *fwn,
161+
struct led_classdev *iled_cdev, struct v4l2_flash_config *config)
146162
{
147163
return NULL;
148164
}

0 commit comments

Comments
 (0)