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_kzalloc(v4l2_flash
->sd
.dev
,
416 sizeof(*v4l2_flash
->ctrls
) *
417 (STROBE_SOURCE
+ 1), GFP_KERNEL
);
418 if (!v4l2_flash
->ctrls
)
421 /* allocate memory dynamically so as not to exceed stack frame size */
422 ctrl_init_data
= kcalloc(NUM_FLASH_CTRLS
, sizeof(*ctrl_init_data
),
427 __fill_ctrl_init_data(v4l2_flash
, flash_cfg
, ctrl_init_data
);
429 for (i
= 0; i
< NUM_FLASH_CTRLS
; ++i
)
430 if (ctrl_init_data
[i
].cid
)
433 v4l2_ctrl_handler_init(&v4l2_flash
->hdl
, num_ctrls
);
435 for (i
= 0; i
< NUM_FLASH_CTRLS
; ++i
) {
436 ctrl_cfg
= &ctrl_init_data
[i
].config
;
437 if (!ctrl_init_data
[i
].cid
)
440 if (ctrl_cfg
->id
== V4L2_CID_FLASH_LED_MODE
||
441 ctrl_cfg
->id
== V4L2_CID_FLASH_STROBE_SOURCE
)
442 ctrl
= v4l2_ctrl_new_std_menu(&v4l2_flash
->hdl
,
443 &v4l2_flash_ctrl_ops
,
446 ctrl_cfg
->menu_skip_mask
,
449 ctrl
= v4l2_ctrl_new_std(&v4l2_flash
->hdl
,
450 &v4l2_flash_ctrl_ops
,
458 ctrl
->flags
|= ctrl_cfg
->flags
;
460 if (i
<= STROBE_SOURCE
)
461 v4l2_flash
->ctrls
[i
] = ctrl
;
464 kfree(ctrl_init_data
);
466 if (v4l2_flash
->hdl
.error
) {
467 ret
= v4l2_flash
->hdl
.error
;
468 goto error_free_handler
;
471 v4l2_ctrl_handler_setup(&v4l2_flash
->hdl
);
473 v4l2_flash
->sd
.ctrl_handler
= &v4l2_flash
->hdl
;
478 v4l2_ctrl_handler_free(&v4l2_flash
->hdl
);
482 static int __sync_device_with_v4l2_controls(struct v4l2_flash
*v4l2_flash
)
484 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
485 struct v4l2_ctrl
**ctrls
= v4l2_flash
->ctrls
;
488 if (ctrls
[TORCH_INTENSITY
])
489 v4l2_flash_set_led_brightness(v4l2_flash
,
490 ctrls
[TORCH_INTENSITY
]);
492 if (ctrls
[INDICATOR_INTENSITY
])
493 v4l2_flash_set_led_brightness(v4l2_flash
,
494 ctrls
[INDICATOR_INTENSITY
]);
496 if (ctrls
[FLASH_TIMEOUT
]) {
497 ret
= led_set_flash_timeout(fled_cdev
,
498 ctrls
[FLASH_TIMEOUT
]->val
);
503 if (ctrls
[FLASH_INTENSITY
]) {
504 ret
= led_set_flash_brightness(fled_cdev
,
505 ctrls
[FLASH_INTENSITY
]->val
);
511 * For some hardware arrangements setting strobe source may affect
512 * torch mode. Synchronize strobe source setting only if not in torch
513 * mode. For torch mode case it will get synchronized upon switching
516 if (ctrls
[STROBE_SOURCE
] &&
517 ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
518 ret
= call_flash_op(v4l2_flash
, external_strobe_set
,
519 ctrls
[STROBE_SOURCE
]->val
);
525 * V4L2 subdev internal operations
528 static int v4l2_flash_open(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
530 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
531 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
532 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
533 struct led_classdev
*led_cdev_ind
= v4l2_flash
->iled_cdev
;
536 if (!v4l2_fh_is_singular(&fh
->vfh
))
540 mutex_lock(&led_cdev
->led_access
);
542 led_sysfs_disable(led_cdev
);
543 led_trigger_remove(led_cdev
);
545 mutex_unlock(&led_cdev
->led_access
);
549 mutex_lock(&led_cdev_ind
->led_access
);
551 led_sysfs_disable(led_cdev_ind
);
552 led_trigger_remove(led_cdev_ind
);
554 mutex_unlock(&led_cdev_ind
->led_access
);
557 ret
= __sync_device_with_v4l2_controls(v4l2_flash
);
559 goto out_sync_device
;
564 mutex_lock(&led_cdev
->led_access
);
565 led_sysfs_enable(led_cdev
);
566 mutex_unlock(&led_cdev
->led_access
);
570 mutex_lock(&led_cdev_ind
->led_access
);
571 led_sysfs_enable(led_cdev_ind
);
572 mutex_unlock(&led_cdev_ind
->led_access
);
578 static int v4l2_flash_close(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
580 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
581 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
582 struct led_classdev
*led_cdev
= fled_cdev
? &fled_cdev
->led_cdev
: NULL
;
583 struct led_classdev
*led_cdev_ind
= v4l2_flash
->iled_cdev
;
586 if (!v4l2_fh_is_singular(&fh
->vfh
))
590 mutex_lock(&led_cdev
->led_access
);
592 if (v4l2_flash
->ctrls
[STROBE_SOURCE
])
593 ret
= v4l2_ctrl_s_ctrl(
594 v4l2_flash
->ctrls
[STROBE_SOURCE
],
595 V4L2_FLASH_STROBE_SOURCE_SOFTWARE
);
596 led_sysfs_enable(led_cdev
);
598 mutex_unlock(&led_cdev
->led_access
);
602 mutex_lock(&led_cdev_ind
->led_access
);
603 led_sysfs_enable(led_cdev_ind
);
604 mutex_unlock(&led_cdev_ind
->led_access
);
610 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops
= {
611 .open
= v4l2_flash_open
,
612 .close
= v4l2_flash_close
,
615 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops
;
617 static struct v4l2_flash
*__v4l2_flash_init(
618 struct device
*dev
, struct fwnode_handle
*fwn
,
619 struct led_classdev_flash
*fled_cdev
, struct led_classdev
*iled_cdev
,
620 const struct v4l2_flash_ops
*ops
, struct v4l2_flash_config
*config
)
622 struct v4l2_flash
*v4l2_flash
;
623 struct v4l2_subdev
*sd
;
627 return ERR_PTR(-EINVAL
);
629 v4l2_flash
= devm_kzalloc(dev
, sizeof(*v4l2_flash
), GFP_KERNEL
);
631 return ERR_PTR(-ENOMEM
);
633 sd
= &v4l2_flash
->sd
;
634 v4l2_flash
->fled_cdev
= fled_cdev
;
635 v4l2_flash
->iled_cdev
= iled_cdev
;
636 v4l2_flash
->ops
= ops
;
638 sd
->fwnode
= fwn
? fwn
: dev_fwnode(dev
);
639 v4l2_subdev_init(sd
, &v4l2_flash_subdev_ops
);
640 sd
->internal_ops
= &v4l2_flash_subdev_internal_ops
;
641 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
642 strlcpy(sd
->name
, config
->dev_name
, sizeof(sd
->name
));
644 ret
= media_entity_pads_init(&sd
->entity
, 0, NULL
);
648 sd
->entity
.function
= MEDIA_ENT_F_FLASH
;
650 ret
= v4l2_flash_init_controls(v4l2_flash
, config
);
652 goto err_init_controls
;
654 fwnode_handle_get(sd
->fwnode
);
656 ret
= v4l2_async_register_subdev(sd
);
658 goto err_async_register_sd
;
662 err_async_register_sd
:
663 fwnode_handle_put(sd
->fwnode
);
664 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
666 media_entity_cleanup(&sd
->entity
);
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
)
677 return __v4l2_flash_init(dev
, fwn
, fled_cdev
, NULL
, ops
, config
);
679 EXPORT_SYMBOL_GPL(v4l2_flash_init
);
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
)
686 return __v4l2_flash_init(dev
, fwn
, NULL
, iled_cdev
, NULL
, config
);
688 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init
);
690 void v4l2_flash_release(struct v4l2_flash
*v4l2_flash
)
692 struct v4l2_subdev
*sd
;
694 if (IS_ERR_OR_NULL(v4l2_flash
))
697 sd
= &v4l2_flash
->sd
;
699 v4l2_async_unregister_subdev(sd
);
701 fwnode_handle_put(sd
->fwnode
);
703 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
704 media_entity_cleanup(&sd
->entity
);
706 EXPORT_SYMBOL_GPL(v4l2_flash_release
);
708 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
709 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
710 MODULE_LICENSE("GPL v2");