2 * V4L2 flash LED sub-device registration helpers.
4 * Copyright (C) 2015 Samsung Electronics Co., Ltd
5 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/led-class-flash.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/property.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <media/v4l2-flash-led-class.h>
20 #define has_flash_op(v4l2_flash, op) \
21 (v4l2_flash && v4l2_flash->ops && v4l2_flash->ops->op)
23 #define call_flash_op(v4l2_flash, op, arg) \
24 (has_flash_op(v4l2_flash, op) ? \
25 v4l2_flash->ops->op(v4l2_flash, arg) : \
28 enum ctrl_init_data_id
{
36 * Only above values are applicable to
37 * the 'ctrls' array in the struct v4l2_flash.
46 static enum led_brightness
__intensity_to_led_brightness(
47 struct v4l2_ctrl
*ctrl
, s32 intensity
)
49 intensity
-= ctrl
->minimum
;
50 intensity
/= (u32
) ctrl
->step
;
53 * Indicator LEDs, unlike torch LEDs, are turned on/off basing on
54 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
55 * Therefore it must be possible to set it to 0 level which in
56 * the LED subsystem reflects LED_OFF state.
64 static s32
__led_brightness_to_intensity(struct v4l2_ctrl
*ctrl
,
65 enum led_brightness brightness
)
68 * Indicator LEDs, unlike torch LEDs, are turned on/off basing on
69 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
70 * Do not decrement brightness read from the LED subsystem for
71 * indicator LED as it may equal 0. For torch LEDs this function
72 * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
73 * brightness read is guaranteed to be greater than 0. In the mode
74 * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used.
76 if (ctrl
->id
!= V4L2_CID_FLASH_INDICATOR_INTENSITY
)
79 return (brightness
* ctrl
->step
) + ctrl
->minimum
;
82 static void v4l2_flash_set_led_brightness(struct v4l2_flash
*v4l2_flash
,
83 struct v4l2_ctrl
*ctrl
)
85 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
86 enum led_brightness brightness
;
88 if (has_flash_op(v4l2_flash
, intensity_to_led_brightness
))
89 brightness
= call_flash_op(v4l2_flash
,
90 intensity_to_led_brightness
,
93 brightness
= __intensity_to_led_brightness(ctrl
, ctrl
->val
);
95 * In case a LED Flash class driver provides ops for custom
96 * brightness <-> intensity conversion, it also must have defined
97 * related v4l2 control step == 1. In such a case a backward conversion
98 * from led brightness to v4l2 intensity is required to find out the
99 * the aligned intensity value.
101 if (has_flash_op(v4l2_flash
, led_brightness_to_intensity
))
102 ctrl
->val
= call_flash_op(v4l2_flash
,
103 led_brightness_to_intensity
,
106 if (ctrl
== ctrls
[TORCH_INTENSITY
]) {
107 if (ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
110 led_set_brightness_sync(&v4l2_flash
->fled_cdev
->led_cdev
,
113 led_set_brightness_sync(v4l2_flash
->iled_cdev
,
118 static int v4l2_flash_update_led_brightness(struct v4l2_flash
*v4l2_flash
,
119 struct v4l2_ctrl
*ctrl
)
121 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
122 struct led_classdev
*led_cdev
;
125 if (ctrl
== ctrls
[TORCH_INTENSITY
]) {
127 * Update torch brightness only if in TORCH_MODE. In other modes
128 * torch led is turned off, which would spuriously inform the
129 * user space that V4L2_CID_FLASH_TORCH_INTENSITY control value
132 if (ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
134 led_cdev
= &v4l2_flash
->fled_cdev
->led_cdev
;
136 led_cdev
= v4l2_flash
->iled_cdev
;
139 ret
= led_update_brightness(led_cdev
);
143 if (has_flash_op(v4l2_flash
, led_brightness_to_intensity
))
144 ctrl
->val
= call_flash_op(v4l2_flash
,
145 led_brightness_to_intensity
,
146 led_cdev
->brightness
);
148 ctrl
->val
= __led_brightness_to_intensity(ctrl
,
149 led_cdev
->brightness
);
154 static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl
*c
)
156 struct v4l2_flash
*v4l2_flash
= v4l2_ctrl_to_v4l2_flash(c
);
157 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
162 case V4L2_CID_FLASH_TORCH_INTENSITY
:
163 case V4L2_CID_FLASH_INDICATOR_INTENSITY
:
164 return v4l2_flash_update_led_brightness(v4l2_flash
, c
);
165 case V4L2_CID_FLASH_INTENSITY
:
166 ret
= led_update_flash_brightness(fled_cdev
);
170 * No conversion is needed as LED Flash class also uses
171 * microamperes for flash intensity units.
173 c
->val
= fled_cdev
->brightness
.val
;
175 case V4L2_CID_FLASH_STROBE_STATUS
:
176 ret
= led_get_flash_strobe(fled_cdev
, &is_strobing
);
179 c
->val
= is_strobing
;
181 case V4L2_CID_FLASH_FAULT
:
182 /* LED faults map directly to V4L2 flash faults */
183 return led_get_flash_fault(fled_cdev
, &c
->val
);
189 static bool __software_strobe_mode_inactive(struct v4l2_ctrl
**ctrls
)
191 return ((ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_FLASH
) ||
192 (ctrls
[STROBE_SOURCE
] && (ctrls
[STROBE_SOURCE
]->val
!=
193 V4L2_FLASH_STROBE_SOURCE_SOFTWARE
)));
196 static int v4l2_flash_s_ctrl(struct v4l2_ctrl
*c
)
198 struct v4l2_flash
*v4l2_flash
= v4l2_ctrl_to_v4l2_flash(c
);
199 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
200 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
201 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
202 bool external_strobe
;
206 case V4L2_CID_FLASH_LED_MODE
:
208 case V4L2_FLASH_LED_MODE_NONE
:
209 led_set_brightness_sync(led_cdev
, LED_OFF
);
210 return led_set_flash_strobe(fled_cdev
, false);
211 case V4L2_FLASH_LED_MODE_FLASH
:
212 /* Turn the torch LED off */
213 led_set_brightness_sync(led_cdev
, LED_OFF
);
214 if (ctrls
[STROBE_SOURCE
]) {
215 external_strobe
= (ctrls
[STROBE_SOURCE
]->val
==
216 V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
218 ret
= call_flash_op(v4l2_flash
,
223 case V4L2_FLASH_LED_MODE_TORCH
:
224 if (ctrls
[STROBE_SOURCE
]) {
225 ret
= call_flash_op(v4l2_flash
,
231 /* Stop flash strobing */
232 ret
= led_set_flash_strobe(fled_cdev
, false);
236 v4l2_flash_set_led_brightness(v4l2_flash
,
237 ctrls
[TORCH_INTENSITY
]);
241 case V4L2_CID_FLASH_STROBE_SOURCE
:
242 external_strobe
= (c
->val
== V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
244 * For some hardware arrangements setting strobe source may
245 * affect torch mode. Therefore, if not in the flash mode,
246 * cache only this setting. It will be applied upon switching
249 if (ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_FLASH
)
252 return call_flash_op(v4l2_flash
, external_strobe_set
,
254 case V4L2_CID_FLASH_STROBE
:
255 if (__software_strobe_mode_inactive(ctrls
))
257 return led_set_flash_strobe(fled_cdev
, true);
258 case V4L2_CID_FLASH_STROBE_STOP
:
259 if (__software_strobe_mode_inactive(ctrls
))
261 return led_set_flash_strobe(fled_cdev
, false);
262 case V4L2_CID_FLASH_TIMEOUT
:
264 * No conversion is needed as LED Flash class also uses
265 * microseconds for flash timeout units.
267 return led_set_flash_timeout(fled_cdev
, c
->val
);
268 case V4L2_CID_FLASH_INTENSITY
:
270 * No conversion is needed as LED Flash class also uses
271 * microamperes for flash intensity units.
273 return led_set_flash_brightness(fled_cdev
, c
->val
);
274 case V4L2_CID_FLASH_TORCH_INTENSITY
:
275 case V4L2_CID_FLASH_INDICATOR_INTENSITY
:
276 v4l2_flash_set_led_brightness(v4l2_flash
, c
);
283 static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops
= {
284 .g_volatile_ctrl
= v4l2_flash_g_volatile_ctrl
,
285 .s_ctrl
= v4l2_flash_s_ctrl
,
288 static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting
*s
,
289 struct v4l2_ctrl_config
*c
)
297 static void __fill_ctrl_init_data(struct v4l2_flash
*v4l2_flash
,
298 struct v4l2_flash_config
*flash_cfg
,
299 struct v4l2_flash_ctrl_data
*ctrl_init_data
)
301 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
302 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
303 struct v4l2_ctrl_config
*ctrl_cfg
;
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
,
313 ctrl_cfg
->id
= V4L2_CID_FLASH_INDICATOR_INTENSITY
;
315 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
316 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
319 if (!led_cdev
|| WARN_ON(!(led_cdev
->flags
& LED_DEV_CAP_FLASH
)))
322 /* Init FLASH_FAULT ctrl data */
323 if (flash_cfg
->flash_faults
) {
324 ctrl_init_data
[FLASH_FAULT
].cid
= V4L2_CID_FLASH_FAULT
;
325 ctrl_cfg
= &ctrl_init_data
[FLASH_FAULT
].config
;
326 ctrl_cfg
->id
= V4L2_CID_FLASH_FAULT
;
327 ctrl_cfg
->max
= flash_cfg
->flash_faults
;
328 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
329 V4L2_CTRL_FLAG_READ_ONLY
;
332 /* Init FLASH_LED_MODE ctrl data */
333 mask
= 1 << V4L2_FLASH_LED_MODE_NONE
|
334 1 << V4L2_FLASH_LED_MODE_TORCH
;
335 if (led_cdev
->flags
& LED_DEV_CAP_FLASH
)
336 mask
|= 1 << V4L2_FLASH_LED_MODE_FLASH
;
338 ctrl_init_data
[LED_MODE
].cid
= V4L2_CID_FLASH_LED_MODE
;
339 ctrl_cfg
= &ctrl_init_data
[LED_MODE
].config
;
340 ctrl_cfg
->id
= V4L2_CID_FLASH_LED_MODE
;
341 ctrl_cfg
->max
= V4L2_FLASH_LED_MODE_TORCH
;
342 ctrl_cfg
->menu_skip_mask
= ~mask
;
343 ctrl_cfg
->def
= V4L2_FLASH_LED_MODE_NONE
;
346 /* Init TORCH_INTENSITY ctrl data */
347 ctrl_init_data
[TORCH_INTENSITY
].cid
= V4L2_CID_FLASH_TORCH_INTENSITY
;
348 ctrl_cfg
= &ctrl_init_data
[TORCH_INTENSITY
].config
;
349 __lfs_to_v4l2_ctrl_config(&flash_cfg
->intensity
, ctrl_cfg
);
350 ctrl_cfg
->id
= V4L2_CID_FLASH_TORCH_INTENSITY
;
351 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
352 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
354 /* Init FLASH_STROBE ctrl data */
355 ctrl_init_data
[FLASH_STROBE
].cid
= V4L2_CID_FLASH_STROBE
;
356 ctrl_cfg
= &ctrl_init_data
[FLASH_STROBE
].config
;
357 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE
;
359 /* Init STROBE_STOP ctrl data */
360 ctrl_init_data
[STROBE_STOP
].cid
= V4L2_CID_FLASH_STROBE_STOP
;
361 ctrl_cfg
= &ctrl_init_data
[STROBE_STOP
].config
;
362 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_STOP
;
364 /* Init FLASH_STROBE_SOURCE ctrl data */
365 if (flash_cfg
->has_external_strobe
) {
366 mask
= (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE
) |
367 (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
368 ctrl_init_data
[STROBE_SOURCE
].cid
=
369 V4L2_CID_FLASH_STROBE_SOURCE
;
370 ctrl_cfg
= &ctrl_init_data
[STROBE_SOURCE
].config
;
371 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_SOURCE
;
372 ctrl_cfg
->max
= V4L2_FLASH_STROBE_SOURCE_EXTERNAL
;
373 ctrl_cfg
->menu_skip_mask
= ~mask
;
374 ctrl_cfg
->def
= V4L2_FLASH_STROBE_SOURCE_SOFTWARE
;
377 /* Init STROBE_STATUS ctrl data */
378 if (has_flash_op(fled_cdev
, strobe_get
)) {
379 ctrl_init_data
[STROBE_STATUS
].cid
=
380 V4L2_CID_FLASH_STROBE_STATUS
;
381 ctrl_cfg
= &ctrl_init_data
[STROBE_STATUS
].config
;
382 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_STATUS
;
383 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
384 V4L2_CTRL_FLAG_READ_ONLY
;
387 /* Init FLASH_TIMEOUT ctrl data */
388 if (has_flash_op(fled_cdev
, timeout_set
)) {
389 ctrl_init_data
[FLASH_TIMEOUT
].cid
= V4L2_CID_FLASH_TIMEOUT
;
390 ctrl_cfg
= &ctrl_init_data
[FLASH_TIMEOUT
].config
;
391 __lfs_to_v4l2_ctrl_config(&fled_cdev
->timeout
, ctrl_cfg
);
392 ctrl_cfg
->id
= V4L2_CID_FLASH_TIMEOUT
;
395 /* Init FLASH_INTENSITY ctrl data */
396 if (has_flash_op(fled_cdev
, flash_brightness_set
)) {
397 ctrl_init_data
[FLASH_INTENSITY
].cid
= V4L2_CID_FLASH_INTENSITY
;
398 ctrl_cfg
= &ctrl_init_data
[FLASH_INTENSITY
].config
;
399 __lfs_to_v4l2_ctrl_config(&fled_cdev
->brightness
, ctrl_cfg
);
400 ctrl_cfg
->id
= V4L2_CID_FLASH_INTENSITY
;
401 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
402 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
406 static int v4l2_flash_init_controls(struct v4l2_flash
*v4l2_flash
,
407 struct v4l2_flash_config
*flash_cfg
)
410 struct v4l2_flash_ctrl_data
*ctrl_init_data
;
411 struct v4l2_ctrl
*ctrl
;
412 struct v4l2_ctrl_config
*ctrl_cfg
;
413 int i
, ret
, num_ctrls
= 0;
415 v4l2_flash
->ctrls
= devm_kcalloc(v4l2_flash
->sd
.dev
,
417 sizeof(*v4l2_flash
->ctrls
),
419 if (!v4l2_flash
->ctrls
)
422 /* allocate memory dynamically so as not to exceed stack frame size */
423 ctrl_init_data
= kcalloc(NUM_FLASH_CTRLS
, sizeof(*ctrl_init_data
),
428 __fill_ctrl_init_data(v4l2_flash
, flash_cfg
, ctrl_init_data
);
430 for (i
= 0; i
< NUM_FLASH_CTRLS
; ++i
)
431 if (ctrl_init_data
[i
].cid
)
434 v4l2_ctrl_handler_init(&v4l2_flash
->hdl
, num_ctrls
);
436 for (i
= 0; i
< NUM_FLASH_CTRLS
; ++i
) {
437 ctrl_cfg
= &ctrl_init_data
[i
].config
;
438 if (!ctrl_init_data
[i
].cid
)
441 if (ctrl_cfg
->id
== V4L2_CID_FLASH_LED_MODE
||
442 ctrl_cfg
->id
== V4L2_CID_FLASH_STROBE_SOURCE
)
443 ctrl
= v4l2_ctrl_new_std_menu(&v4l2_flash
->hdl
,
444 &v4l2_flash_ctrl_ops
,
447 ctrl_cfg
->menu_skip_mask
,
450 ctrl
= v4l2_ctrl_new_std(&v4l2_flash
->hdl
,
451 &v4l2_flash_ctrl_ops
,
459 ctrl
->flags
|= ctrl_cfg
->flags
;
461 if (i
<= STROBE_SOURCE
)
462 v4l2_flash
->ctrls
[i
] = ctrl
;
465 kfree(ctrl_init_data
);
467 if (v4l2_flash
->hdl
.error
) {
468 ret
= v4l2_flash
->hdl
.error
;
469 goto error_free_handler
;
472 v4l2_ctrl_handler_setup(&v4l2_flash
->hdl
);
474 v4l2_flash
->sd
.ctrl_handler
= &v4l2_flash
->hdl
;
479 v4l2_ctrl_handler_free(&v4l2_flash
->hdl
);
483 static int __sync_device_with_v4l2_controls(struct v4l2_flash
*v4l2_flash
)
485 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
486 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
489 if (ctrls
[TORCH_INTENSITY
])
490 v4l2_flash_set_led_brightness(v4l2_flash
,
491 ctrls
[TORCH_INTENSITY
]);
493 if (ctrls
[INDICATOR_INTENSITY
])
494 v4l2_flash_set_led_brightness(v4l2_flash
,
495 ctrls
[INDICATOR_INTENSITY
]);
497 if (ctrls
[FLASH_TIMEOUT
]) {
498 ret
= led_set_flash_timeout(fled_cdev
,
499 ctrls
[FLASH_TIMEOUT
]->val
);
504 if (ctrls
[FLASH_INTENSITY
]) {
505 ret
= led_set_flash_brightness(fled_cdev
,
506 ctrls
[FLASH_INTENSITY
]->val
);
512 * For some hardware arrangements setting strobe source may affect
513 * torch mode. Synchronize strobe source setting only if not in torch
514 * mode. For torch mode case it will get synchronized upon switching
517 if (ctrls
[STROBE_SOURCE
] &&
518 ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
519 ret
= call_flash_op(v4l2_flash
, external_strobe_set
,
520 ctrls
[STROBE_SOURCE
]->val
);
526 * V4L2 subdev internal operations
529 static int v4l2_flash_open(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
531 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
532 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
533 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
534 struct led_classdev
*led_cdev_ind
= v4l2_flash
->iled_cdev
;
537 if (!v4l2_fh_is_singular(&fh
->vfh
))
541 mutex_lock(&led_cdev
->led_access
);
543 led_sysfs_disable(led_cdev
);
544 led_trigger_remove(led_cdev
);
546 mutex_unlock(&led_cdev
->led_access
);
550 mutex_lock(&led_cdev_ind
->led_access
);
552 led_sysfs_disable(led_cdev_ind
);
553 led_trigger_remove(led_cdev_ind
);
555 mutex_unlock(&led_cdev_ind
->led_access
);
558 ret
= __sync_device_with_v4l2_controls(v4l2_flash
);
560 goto out_sync_device
;
565 mutex_lock(&led_cdev
->led_access
);
566 led_sysfs_enable(led_cdev
);
567 mutex_unlock(&led_cdev
->led_access
);
571 mutex_lock(&led_cdev_ind
->led_access
);
572 led_sysfs_enable(led_cdev_ind
);
573 mutex_unlock(&led_cdev_ind
->led_access
);
579 static int v4l2_flash_close(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
581 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
582 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
583 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
584 struct led_classdev
*led_cdev_ind
= v4l2_flash
->iled_cdev
;
587 if (!v4l2_fh_is_singular(&fh
->vfh
))
591 mutex_lock(&led_cdev
->led_access
);
593 if (v4l2_flash
->ctrls
[STROBE_SOURCE
])
594 ret
= v4l2_ctrl_s_ctrl(
595 v4l2_flash
->ctrls
[STROBE_SOURCE
],
596 V4L2_FLASH_STROBE_SOURCE_SOFTWARE
);
597 led_sysfs_enable(led_cdev
);
599 mutex_unlock(&led_cdev
->led_access
);
603 mutex_lock(&led_cdev_ind
->led_access
);
604 led_sysfs_enable(led_cdev_ind
);
605 mutex_unlock(&led_cdev_ind
->led_access
);
611 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops
= {
612 .open
= v4l2_flash_open
,
613 .close
= v4l2_flash_close
,
616 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops
;
618 static struct v4l2_flash
*__v4l2_flash_init(
619 struct device
*dev
, struct fwnode_handle
*fwn
,
620 struct led_classdev_flash
*fled_cdev
, struct led_classdev
*iled_cdev
,
621 const struct v4l2_flash_ops
*ops
, struct v4l2_flash_config
*config
)
623 struct v4l2_flash
*v4l2_flash
;
624 struct v4l2_subdev
*sd
;
628 return ERR_PTR(-EINVAL
);
630 v4l2_flash
= devm_kzalloc(dev
, sizeof(*v4l2_flash
), GFP_KERNEL
);
632 return ERR_PTR(-ENOMEM
);
634 sd
= &v4l2_flash
->sd
;
635 v4l2_flash
->fled_cdev
= fled_cdev
;
636 v4l2_flash
->iled_cdev
= iled_cdev
;
637 v4l2_flash
->ops
= ops
;
639 sd
->fwnode
= fwn
? fwn
: dev_fwnode(dev
);
640 v4l2_subdev_init(sd
, &v4l2_flash_subdev_ops
);
641 sd
->internal_ops
= &v4l2_flash_subdev_internal_ops
;
642 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
643 strlcpy(sd
->name
, config
->dev_name
, sizeof(sd
->name
));
645 ret
= media_entity_pads_init(&sd
->entity
, 0, NULL
);
649 sd
->entity
.function
= MEDIA_ENT_F_FLASH
;
651 ret
= v4l2_flash_init_controls(v4l2_flash
, config
);
653 goto err_init_controls
;
655 fwnode_handle_get(sd
->fwnode
);
657 ret
= v4l2_async_register_subdev(sd
);
659 goto err_async_register_sd
;
663 err_async_register_sd
:
664 fwnode_handle_put(sd
->fwnode
);
665 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
667 media_entity_cleanup(&sd
->entity
);
672 struct v4l2_flash
*v4l2_flash_init(
673 struct device
*dev
, struct fwnode_handle
*fwn
,
674 struct led_classdev_flash
*fled_cdev
,
675 const struct v4l2_flash_ops
*ops
,
676 struct v4l2_flash_config
*config
)
678 return __v4l2_flash_init(dev
, fwn
, fled_cdev
, NULL
, ops
, config
);
680 EXPORT_SYMBOL_GPL(v4l2_flash_init
);
682 struct v4l2_flash
*v4l2_flash_indicator_init(
683 struct device
*dev
, struct fwnode_handle
*fwn
,
684 struct led_classdev
*iled_cdev
,
685 struct v4l2_flash_config
*config
)
687 return __v4l2_flash_init(dev
, fwn
, NULL
, iled_cdev
, NULL
, config
);
689 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init
);
691 void v4l2_flash_release(struct v4l2_flash
*v4l2_flash
)
693 struct v4l2_subdev
*sd
;
695 if (IS_ERR_OR_NULL(v4l2_flash
))
698 sd
= &v4l2_flash
->sd
;
700 v4l2_async_unregister_subdev(sd
);
702 fwnode_handle_put(sd
->fwnode
);
704 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
705 media_entity_cleanup(&sd
->entity
);
707 EXPORT_SYMBOL_GPL(v4l2_flash_release
);
709 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
710 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
711 MODULE_LICENSE("GPL v2");