1 // SPDX-License-Identifier: GPL-2.0-only
3 * V4L2 flash LED sub-device registration helpers.
5 * Copyright (C) 2015 Samsung Electronics Co., Ltd
6 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
9 #include <linux/led-class-flash.h>
10 #include <linux/module.h>
11 #include <linux/mutex.h>
12 #include <linux/property.h>
13 #include <linux/slab.h>
14 #include <linux/types.h>
15 #include <media/v4l2-flash-led-class.h>
17 #define has_flash_op(v4l2_flash, op) \
18 (v4l2_flash && v4l2_flash->ops && v4l2_flash->ops->op)
20 #define call_flash_op(v4l2_flash, op, arg) \
21 (has_flash_op(v4l2_flash, op) ? \
22 v4l2_flash->ops->op(v4l2_flash, arg) : \
25 enum ctrl_init_data_id
{
33 * Only above values are applicable to
34 * the 'ctrls' array in the struct v4l2_flash.
43 static enum led_brightness
__intensity_to_led_brightness(
44 struct v4l2_ctrl
*ctrl
, s32 intensity
)
46 intensity
-= ctrl
->minimum
;
47 intensity
/= (u32
) ctrl
->step
;
50 * Indicator LEDs, unlike torch LEDs, are turned on/off basing on
51 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
52 * Therefore it must be possible to set it to 0 level which in
53 * the LED subsystem reflects LED_OFF state.
61 static s32
__led_brightness_to_intensity(struct v4l2_ctrl
*ctrl
,
62 enum led_brightness brightness
)
65 * Indicator LEDs, unlike torch LEDs, are turned on/off basing on
66 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
67 * Do not decrement brightness read from the LED subsystem for
68 * indicator LED as it may equal 0. For torch LEDs this function
69 * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
70 * brightness read is guaranteed to be greater than 0. In the mode
71 * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used.
73 if (ctrl
->id
!= V4L2_CID_FLASH_INDICATOR_INTENSITY
)
76 return (brightness
* ctrl
->step
) + ctrl
->minimum
;
79 static int v4l2_flash_set_led_brightness(struct v4l2_flash
*v4l2_flash
,
80 struct v4l2_ctrl
*ctrl
)
82 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
83 struct led_classdev
*led_cdev
;
84 enum led_brightness brightness
;
86 if (has_flash_op(v4l2_flash
, intensity_to_led_brightness
))
87 brightness
= call_flash_op(v4l2_flash
,
88 intensity_to_led_brightness
,
91 brightness
= __intensity_to_led_brightness(ctrl
, ctrl
->val
);
93 * In case a LED Flash class driver provides ops for custom
94 * brightness <-> intensity conversion, it also must have defined
95 * related v4l2 control step == 1. In such a case a backward conversion
96 * from led brightness to v4l2 intensity is required to find out the
97 * aligned intensity value.
99 if (has_flash_op(v4l2_flash
, led_brightness_to_intensity
))
100 ctrl
->val
= call_flash_op(v4l2_flash
,
101 led_brightness_to_intensity
,
104 if (ctrl
== ctrls
[TORCH_INTENSITY
]) {
105 if (ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
108 if (WARN_ON_ONCE(!v4l2_flash
->fled_cdev
))
111 led_cdev
= &v4l2_flash
->fled_cdev
->led_cdev
;
113 if (WARN_ON_ONCE(!v4l2_flash
->iled_cdev
))
116 led_cdev
= v4l2_flash
->iled_cdev
;
119 return led_set_brightness_sync(led_cdev
, brightness
);
122 static int v4l2_flash_update_led_brightness(struct v4l2_flash
*v4l2_flash
,
123 struct v4l2_ctrl
*ctrl
)
125 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
126 struct led_classdev
*led_cdev
;
129 if (ctrl
== ctrls
[TORCH_INTENSITY
]) {
131 * Update torch brightness only if in TORCH_MODE. In other modes
132 * torch led is turned off, which would spuriously inform the
133 * user space that V4L2_CID_FLASH_TORCH_INTENSITY control value
136 if (ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
139 if (WARN_ON_ONCE(!v4l2_flash
->fled_cdev
))
142 led_cdev
= &v4l2_flash
->fled_cdev
->led_cdev
;
144 if (WARN_ON_ONCE(!v4l2_flash
->iled_cdev
))
147 led_cdev
= v4l2_flash
->iled_cdev
;
150 ret
= led_update_brightness(led_cdev
);
154 if (has_flash_op(v4l2_flash
, led_brightness_to_intensity
))
155 ctrl
->val
= call_flash_op(v4l2_flash
,
156 led_brightness_to_intensity
,
157 led_cdev
->brightness
);
159 ctrl
->val
= __led_brightness_to_intensity(ctrl
,
160 led_cdev
->brightness
);
165 static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl
*c
)
167 struct v4l2_flash
*v4l2_flash
= v4l2_ctrl_to_v4l2_flash(c
);
168 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
173 case V4L2_CID_FLASH_TORCH_INTENSITY
:
174 case V4L2_CID_FLASH_INDICATOR_INTENSITY
:
175 return v4l2_flash_update_led_brightness(v4l2_flash
, c
);
182 case V4L2_CID_FLASH_INTENSITY
:
183 ret
= led_update_flash_brightness(fled_cdev
);
187 * No conversion is needed as LED Flash class also uses
188 * microamperes for flash intensity units.
190 c
->val
= fled_cdev
->brightness
.val
;
192 case V4L2_CID_FLASH_STROBE_STATUS
:
193 ret
= led_get_flash_strobe(fled_cdev
, &is_strobing
);
196 c
->val
= is_strobing
;
198 case V4L2_CID_FLASH_FAULT
:
199 /* LED faults map directly to V4L2 flash faults */
200 return led_get_flash_fault(fled_cdev
, &c
->val
);
206 static bool __software_strobe_mode_inactive(struct v4l2_ctrl
**ctrls
)
208 return ((ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_FLASH
) ||
209 (ctrls
[STROBE_SOURCE
] && (ctrls
[STROBE_SOURCE
]->val
!=
210 V4L2_FLASH_STROBE_SOURCE_SOFTWARE
)));
213 static int v4l2_flash_s_ctrl(struct v4l2_ctrl
*c
)
215 struct v4l2_flash
*v4l2_flash
= v4l2_ctrl_to_v4l2_flash(c
);
216 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
217 struct led_classdev
*led_cdev
;
218 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
219 bool external_strobe
;
223 case V4L2_CID_FLASH_TORCH_INTENSITY
:
224 case V4L2_CID_FLASH_INDICATOR_INTENSITY
:
225 return v4l2_flash_set_led_brightness(v4l2_flash
, c
);
231 led_cdev
= &fled_cdev
->led_cdev
;
234 case V4L2_CID_FLASH_LED_MODE
:
236 case V4L2_FLASH_LED_MODE_NONE
:
237 led_set_brightness_sync(led_cdev
, LED_OFF
);
238 return led_set_flash_strobe(fled_cdev
, false);
239 case V4L2_FLASH_LED_MODE_FLASH
:
240 /* Turn the torch LED off */
241 led_set_brightness_sync(led_cdev
, LED_OFF
);
242 if (ctrls
[STROBE_SOURCE
]) {
243 external_strobe
= (ctrls
[STROBE_SOURCE
]->val
==
244 V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
246 ret
= call_flash_op(v4l2_flash
,
251 case V4L2_FLASH_LED_MODE_TORCH
:
252 if (ctrls
[STROBE_SOURCE
]) {
253 ret
= call_flash_op(v4l2_flash
,
259 /* Stop flash strobing */
260 ret
= led_set_flash_strobe(fled_cdev
, false);
264 return v4l2_flash_set_led_brightness(v4l2_flash
,
265 ctrls
[TORCH_INTENSITY
]);
268 case V4L2_CID_FLASH_STROBE_SOURCE
:
269 external_strobe
= (c
->val
== V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
271 * For some hardware arrangements setting strobe source may
272 * affect torch mode. Therefore, if not in the flash mode,
273 * cache only this setting. It will be applied upon switching
276 if (ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_FLASH
)
279 return call_flash_op(v4l2_flash
, external_strobe_set
,
281 case V4L2_CID_FLASH_STROBE
:
282 if (__software_strobe_mode_inactive(ctrls
))
284 return led_set_flash_strobe(fled_cdev
, true);
285 case V4L2_CID_FLASH_STROBE_STOP
:
286 if (__software_strobe_mode_inactive(ctrls
))
288 return led_set_flash_strobe(fled_cdev
, false);
289 case V4L2_CID_FLASH_TIMEOUT
:
291 * No conversion is needed as LED Flash class also uses
292 * microseconds for flash timeout units.
294 return led_set_flash_timeout(fled_cdev
, c
->val
);
295 case V4L2_CID_FLASH_INTENSITY
:
297 * No conversion is needed as LED Flash class also uses
298 * microamperes for flash intensity units.
300 return led_set_flash_brightness(fled_cdev
, c
->val
);
306 static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops
= {
307 .g_volatile_ctrl
= v4l2_flash_g_volatile_ctrl
,
308 .s_ctrl
= v4l2_flash_s_ctrl
,
311 static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting
*s
,
312 struct v4l2_ctrl_config
*c
)
320 static void __fill_ctrl_init_data(struct v4l2_flash
*v4l2_flash
,
321 struct v4l2_flash_config
*flash_cfg
,
322 struct v4l2_flash_ctrl_data
*ctrl_init_data
)
324 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
325 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
326 struct v4l2_ctrl_config
*ctrl_cfg
;
329 /* Init INDICATOR_INTENSITY ctrl data */
330 if (v4l2_flash
->iled_cdev
) {
331 ctrl_init_data
[INDICATOR_INTENSITY
].cid
=
332 V4L2_CID_FLASH_INDICATOR_INTENSITY
;
333 ctrl_cfg
= &ctrl_init_data
[INDICATOR_INTENSITY
].config
;
334 __lfs_to_v4l2_ctrl_config(&flash_cfg
->intensity
,
336 ctrl_cfg
->id
= V4L2_CID_FLASH_INDICATOR_INTENSITY
;
338 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
339 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
342 if (!led_cdev
|| WARN_ON(!(led_cdev
->flags
& LED_DEV_CAP_FLASH
)))
345 /* Init FLASH_FAULT ctrl data */
346 if (flash_cfg
->flash_faults
) {
347 ctrl_init_data
[FLASH_FAULT
].cid
= V4L2_CID_FLASH_FAULT
;
348 ctrl_cfg
= &ctrl_init_data
[FLASH_FAULT
].config
;
349 ctrl_cfg
->id
= V4L2_CID_FLASH_FAULT
;
350 ctrl_cfg
->max
= flash_cfg
->flash_faults
;
351 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
352 V4L2_CTRL_FLAG_READ_ONLY
;
355 /* Init FLASH_LED_MODE ctrl data */
356 mask
= 1 << V4L2_FLASH_LED_MODE_NONE
|
357 1 << V4L2_FLASH_LED_MODE_TORCH
;
358 if (led_cdev
->flags
& LED_DEV_CAP_FLASH
)
359 mask
|= 1 << V4L2_FLASH_LED_MODE_FLASH
;
361 ctrl_init_data
[LED_MODE
].cid
= V4L2_CID_FLASH_LED_MODE
;
362 ctrl_cfg
= &ctrl_init_data
[LED_MODE
].config
;
363 ctrl_cfg
->id
= V4L2_CID_FLASH_LED_MODE
;
364 ctrl_cfg
->max
= V4L2_FLASH_LED_MODE_TORCH
;
365 ctrl_cfg
->menu_skip_mask
= ~mask
;
366 ctrl_cfg
->def
= V4L2_FLASH_LED_MODE_NONE
;
369 /* Init TORCH_INTENSITY ctrl data */
370 ctrl_init_data
[TORCH_INTENSITY
].cid
= V4L2_CID_FLASH_TORCH_INTENSITY
;
371 ctrl_cfg
= &ctrl_init_data
[TORCH_INTENSITY
].config
;
372 __lfs_to_v4l2_ctrl_config(&flash_cfg
->intensity
, ctrl_cfg
);
373 ctrl_cfg
->id
= V4L2_CID_FLASH_TORCH_INTENSITY
;
374 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
375 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
377 /* Init FLASH_STROBE ctrl data */
378 ctrl_init_data
[FLASH_STROBE
].cid
= V4L2_CID_FLASH_STROBE
;
379 ctrl_cfg
= &ctrl_init_data
[FLASH_STROBE
].config
;
380 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE
;
382 /* Init STROBE_STOP ctrl data */
383 ctrl_init_data
[STROBE_STOP
].cid
= V4L2_CID_FLASH_STROBE_STOP
;
384 ctrl_cfg
= &ctrl_init_data
[STROBE_STOP
].config
;
385 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_STOP
;
387 /* Init FLASH_STROBE_SOURCE ctrl data */
388 if (flash_cfg
->has_external_strobe
) {
389 mask
= (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE
) |
390 (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
391 ctrl_init_data
[STROBE_SOURCE
].cid
=
392 V4L2_CID_FLASH_STROBE_SOURCE
;
393 ctrl_cfg
= &ctrl_init_data
[STROBE_SOURCE
].config
;
394 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_SOURCE
;
395 ctrl_cfg
->max
= V4L2_FLASH_STROBE_SOURCE_EXTERNAL
;
396 ctrl_cfg
->menu_skip_mask
= ~mask
;
397 ctrl_cfg
->def
= V4L2_FLASH_STROBE_SOURCE_SOFTWARE
;
400 /* Init STROBE_STATUS ctrl data */
401 if (has_flash_op(fled_cdev
, strobe_get
)) {
402 ctrl_init_data
[STROBE_STATUS
].cid
=
403 V4L2_CID_FLASH_STROBE_STATUS
;
404 ctrl_cfg
= &ctrl_init_data
[STROBE_STATUS
].config
;
405 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_STATUS
;
406 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
407 V4L2_CTRL_FLAG_READ_ONLY
;
410 /* Init FLASH_TIMEOUT ctrl data */
411 if (has_flash_op(fled_cdev
, timeout_set
)) {
412 ctrl_init_data
[FLASH_TIMEOUT
].cid
= V4L2_CID_FLASH_TIMEOUT
;
413 ctrl_cfg
= &ctrl_init_data
[FLASH_TIMEOUT
].config
;
414 __lfs_to_v4l2_ctrl_config(&fled_cdev
->timeout
, ctrl_cfg
);
415 ctrl_cfg
->id
= V4L2_CID_FLASH_TIMEOUT
;
418 /* Init FLASH_INTENSITY ctrl data */
419 if (has_flash_op(fled_cdev
, flash_brightness_set
)) {
420 ctrl_init_data
[FLASH_INTENSITY
].cid
= V4L2_CID_FLASH_INTENSITY
;
421 ctrl_cfg
= &ctrl_init_data
[FLASH_INTENSITY
].config
;
422 __lfs_to_v4l2_ctrl_config(&fled_cdev
->brightness
, ctrl_cfg
);
423 ctrl_cfg
->id
= V4L2_CID_FLASH_INTENSITY
;
424 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
425 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
429 static int v4l2_flash_init_controls(struct v4l2_flash
*v4l2_flash
,
430 struct v4l2_flash_config
*flash_cfg
)
433 struct v4l2_flash_ctrl_data
*ctrl_init_data
;
434 struct v4l2_ctrl
*ctrl
;
435 struct v4l2_ctrl_config
*ctrl_cfg
;
436 int i
, ret
, num_ctrls
= 0;
438 v4l2_flash
->ctrls
= devm_kcalloc(v4l2_flash
->sd
.dev
,
440 sizeof(*v4l2_flash
->ctrls
),
442 if (!v4l2_flash
->ctrls
)
445 /* allocate memory dynamically so as not to exceed stack frame size */
446 ctrl_init_data
= kcalloc(NUM_FLASH_CTRLS
, sizeof(*ctrl_init_data
),
451 __fill_ctrl_init_data(v4l2_flash
, flash_cfg
, ctrl_init_data
);
453 for (i
= 0; i
< NUM_FLASH_CTRLS
; ++i
)
454 if (ctrl_init_data
[i
].cid
)
457 v4l2_ctrl_handler_init(&v4l2_flash
->hdl
, num_ctrls
);
459 for (i
= 0; i
< NUM_FLASH_CTRLS
; ++i
) {
460 ctrl_cfg
= &ctrl_init_data
[i
].config
;
461 if (!ctrl_init_data
[i
].cid
)
464 if (ctrl_cfg
->id
== V4L2_CID_FLASH_LED_MODE
||
465 ctrl_cfg
->id
== V4L2_CID_FLASH_STROBE_SOURCE
)
466 ctrl
= v4l2_ctrl_new_std_menu(&v4l2_flash
->hdl
,
467 &v4l2_flash_ctrl_ops
,
470 ctrl_cfg
->menu_skip_mask
,
473 ctrl
= v4l2_ctrl_new_std(&v4l2_flash
->hdl
,
474 &v4l2_flash_ctrl_ops
,
482 ctrl
->flags
|= ctrl_cfg
->flags
;
484 if (i
<= STROBE_SOURCE
)
485 v4l2_flash
->ctrls
[i
] = ctrl
;
488 kfree(ctrl_init_data
);
490 if (v4l2_flash
->hdl
.error
) {
491 ret
= v4l2_flash
->hdl
.error
;
492 goto error_free_handler
;
495 v4l2_ctrl_handler_setup(&v4l2_flash
->hdl
);
497 v4l2_flash
->sd
.ctrl_handler
= &v4l2_flash
->hdl
;
502 v4l2_ctrl_handler_free(&v4l2_flash
->hdl
);
506 static int __sync_device_with_v4l2_controls(struct v4l2_flash
*v4l2_flash
)
508 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
509 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
512 if (ctrls
[TORCH_INTENSITY
]) {
513 ret
= v4l2_flash_set_led_brightness(v4l2_flash
,
514 ctrls
[TORCH_INTENSITY
]);
519 if (ctrls
[INDICATOR_INTENSITY
]) {
520 ret
= v4l2_flash_set_led_brightness(v4l2_flash
,
521 ctrls
[INDICATOR_INTENSITY
]);
526 if (ctrls
[FLASH_TIMEOUT
]) {
527 if (WARN_ON_ONCE(!fled_cdev
))
530 ret
= led_set_flash_timeout(fled_cdev
,
531 ctrls
[FLASH_TIMEOUT
]->val
);
536 if (ctrls
[FLASH_INTENSITY
]) {
537 if (WARN_ON_ONCE(!fled_cdev
))
540 ret
= led_set_flash_brightness(fled_cdev
,
541 ctrls
[FLASH_INTENSITY
]->val
);
547 * For some hardware arrangements setting strobe source may affect
548 * torch mode. Synchronize strobe source setting only if not in torch
549 * mode. For torch mode case it will get synchronized upon switching
552 if (ctrls
[STROBE_SOURCE
] &&
553 ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
554 ret
= call_flash_op(v4l2_flash
, external_strobe_set
,
555 ctrls
[STROBE_SOURCE
]->val
);
561 * V4L2 subdev internal operations
564 static int v4l2_flash_open(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
566 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
567 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
568 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
569 struct led_classdev
*led_cdev_ind
= v4l2_flash
->iled_cdev
;
572 if (!v4l2_fh_is_singular(&fh
->vfh
))
576 mutex_lock(&led_cdev
->led_access
);
578 led_sysfs_disable(led_cdev
);
579 led_trigger_remove(led_cdev
);
581 mutex_unlock(&led_cdev
->led_access
);
585 mutex_lock(&led_cdev_ind
->led_access
);
587 led_sysfs_disable(led_cdev_ind
);
588 led_trigger_remove(led_cdev_ind
);
590 mutex_unlock(&led_cdev_ind
->led_access
);
593 ret
= __sync_device_with_v4l2_controls(v4l2_flash
);
595 goto out_sync_device
;
600 mutex_lock(&led_cdev
->led_access
);
601 led_sysfs_enable(led_cdev
);
602 mutex_unlock(&led_cdev
->led_access
);
606 mutex_lock(&led_cdev_ind
->led_access
);
607 led_sysfs_enable(led_cdev_ind
);
608 mutex_unlock(&led_cdev_ind
->led_access
);
614 static int v4l2_flash_close(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
616 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
617 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
618 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
619 struct led_classdev
*led_cdev_ind
= v4l2_flash
->iled_cdev
;
622 if (!v4l2_fh_is_singular(&fh
->vfh
))
626 mutex_lock(&led_cdev
->led_access
);
628 if (v4l2_flash
->ctrls
[STROBE_SOURCE
])
629 ret
= v4l2_ctrl_s_ctrl(
630 v4l2_flash
->ctrls
[STROBE_SOURCE
],
631 V4L2_FLASH_STROBE_SOURCE_SOFTWARE
);
632 led_sysfs_enable(led_cdev
);
634 mutex_unlock(&led_cdev
->led_access
);
638 mutex_lock(&led_cdev_ind
->led_access
);
639 led_sysfs_enable(led_cdev_ind
);
640 mutex_unlock(&led_cdev_ind
->led_access
);
646 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops
= {
647 .open
= v4l2_flash_open
,
648 .close
= v4l2_flash_close
,
651 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops
;
653 static struct v4l2_flash
*__v4l2_flash_init(
654 struct device
*dev
, struct fwnode_handle
*fwn
,
655 struct led_classdev_flash
*fled_cdev
, struct led_classdev
*iled_cdev
,
656 const struct v4l2_flash_ops
*ops
, struct v4l2_flash_config
*config
)
658 struct v4l2_flash
*v4l2_flash
;
659 struct v4l2_subdev
*sd
;
663 return ERR_PTR(-EINVAL
);
665 v4l2_flash
= devm_kzalloc(dev
, sizeof(*v4l2_flash
), GFP_KERNEL
);
667 return ERR_PTR(-ENOMEM
);
669 sd
= &v4l2_flash
->sd
;
670 v4l2_flash
->fled_cdev
= fled_cdev
;
671 v4l2_flash
->iled_cdev
= iled_cdev
;
672 v4l2_flash
->ops
= ops
;
674 sd
->fwnode
= fwn
? fwn
: dev_fwnode(dev
);
675 v4l2_subdev_init(sd
, &v4l2_flash_subdev_ops
);
676 sd
->internal_ops
= &v4l2_flash_subdev_internal_ops
;
677 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
678 strscpy(sd
->name
, config
->dev_name
, sizeof(sd
->name
));
680 ret
= media_entity_pads_init(&sd
->entity
, 0, NULL
);
684 sd
->entity
.function
= MEDIA_ENT_F_FLASH
;
686 ret
= v4l2_flash_init_controls(v4l2_flash
, config
);
688 goto err_init_controls
;
690 fwnode_handle_get(sd
->fwnode
);
692 ret
= v4l2_async_register_subdev(sd
);
694 goto err_async_register_sd
;
698 err_async_register_sd
:
699 fwnode_handle_put(sd
->fwnode
);
700 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
702 media_entity_cleanup(&sd
->entity
);
707 struct v4l2_flash
*v4l2_flash_init(
708 struct device
*dev
, struct fwnode_handle
*fwn
,
709 struct led_classdev_flash
*fled_cdev
,
710 const struct v4l2_flash_ops
*ops
,
711 struct v4l2_flash_config
*config
)
713 return __v4l2_flash_init(dev
, fwn
, fled_cdev
, NULL
, ops
, config
);
715 EXPORT_SYMBOL_GPL(v4l2_flash_init
);
717 struct v4l2_flash
*v4l2_flash_indicator_init(
718 struct device
*dev
, struct fwnode_handle
*fwn
,
719 struct led_classdev
*iled_cdev
,
720 struct v4l2_flash_config
*config
)
722 return __v4l2_flash_init(dev
, fwn
, NULL
, iled_cdev
, NULL
, config
);
724 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init
);
726 void v4l2_flash_release(struct v4l2_flash
*v4l2_flash
)
728 struct v4l2_subdev
*sd
;
730 if (IS_ERR_OR_NULL(v4l2_flash
))
733 sd
= &v4l2_flash
->sd
;
735 v4l2_async_unregister_subdev(sd
);
737 fwnode_handle_put(sd
->fwnode
);
739 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
740 media_entity_cleanup(&sd
->entity
);
742 EXPORT_SYMBOL_GPL(v4l2_flash_release
);
744 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
745 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
746 MODULE_LICENSE("GPL v2");