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>
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->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
->led_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
->led_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
->led_cdev
;
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 const struct led_flash_ops
*fled_cdev_ops
= fled_cdev
->ops
;
303 struct led_classdev
*led_cdev
= &fled_cdev
->led_cdev
;
304 struct v4l2_ctrl_config
*ctrl_cfg
;
307 /* Init FLASH_FAULT ctrl data */
308 if (flash_cfg
->flash_faults
) {
309 ctrl_init_data
[FLASH_FAULT
].cid
= V4L2_CID_FLASH_FAULT
;
310 ctrl_cfg
= &ctrl_init_data
[FLASH_FAULT
].config
;
311 ctrl_cfg
->id
= V4L2_CID_FLASH_FAULT
;
312 ctrl_cfg
->max
= flash_cfg
->flash_faults
;
313 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
314 V4L2_CTRL_FLAG_READ_ONLY
;
317 /* Init FLASH_LED_MODE ctrl data */
318 mask
= 1 << V4L2_FLASH_LED_MODE_NONE
|
319 1 << V4L2_FLASH_LED_MODE_TORCH
;
320 if (led_cdev
->flags
& LED_DEV_CAP_FLASH
)
321 mask
|= 1 << V4L2_FLASH_LED_MODE_FLASH
;
323 ctrl_init_data
[LED_MODE
].cid
= V4L2_CID_FLASH_LED_MODE
;
324 ctrl_cfg
= &ctrl_init_data
[LED_MODE
].config
;
325 ctrl_cfg
->id
= V4L2_CID_FLASH_LED_MODE
;
326 ctrl_cfg
->max
= V4L2_FLASH_LED_MODE_TORCH
;
327 ctrl_cfg
->menu_skip_mask
= ~mask
;
328 ctrl_cfg
->def
= V4L2_FLASH_LED_MODE_NONE
;
331 /* Init TORCH_INTENSITY ctrl data */
332 ctrl_init_data
[TORCH_INTENSITY
].cid
= V4L2_CID_FLASH_TORCH_INTENSITY
;
333 ctrl_cfg
= &ctrl_init_data
[TORCH_INTENSITY
].config
;
334 __lfs_to_v4l2_ctrl_config(&flash_cfg
->torch_intensity
, ctrl_cfg
);
335 ctrl_cfg
->id
= V4L2_CID_FLASH_TORCH_INTENSITY
;
336 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
337 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
339 /* Init INDICATOR_INTENSITY ctrl data */
340 if (v4l2_flash
->iled_cdev
) {
341 ctrl_init_data
[INDICATOR_INTENSITY
].cid
=
342 V4L2_CID_FLASH_INDICATOR_INTENSITY
;
343 ctrl_cfg
= &ctrl_init_data
[INDICATOR_INTENSITY
].config
;
344 __lfs_to_v4l2_ctrl_config(&flash_cfg
->indicator_intensity
,
346 ctrl_cfg
->id
= V4L2_CID_FLASH_INDICATOR_INTENSITY
;
348 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
349 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
352 if (!(led_cdev
->flags
& LED_DEV_CAP_FLASH
))
355 /* Init FLASH_STROBE ctrl data */
356 ctrl_init_data
[FLASH_STROBE
].cid
= V4L2_CID_FLASH_STROBE
;
357 ctrl_cfg
= &ctrl_init_data
[FLASH_STROBE
].config
;
358 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE
;
360 /* Init STROBE_STOP ctrl data */
361 ctrl_init_data
[STROBE_STOP
].cid
= V4L2_CID_FLASH_STROBE_STOP
;
362 ctrl_cfg
= &ctrl_init_data
[STROBE_STOP
].config
;
363 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_STOP
;
365 /* Init FLASH_STROBE_SOURCE ctrl data */
366 if (flash_cfg
->has_external_strobe
) {
367 mask
= (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE
) |
368 (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL
);
369 ctrl_init_data
[STROBE_SOURCE
].cid
=
370 V4L2_CID_FLASH_STROBE_SOURCE
;
371 ctrl_cfg
= &ctrl_init_data
[STROBE_SOURCE
].config
;
372 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_SOURCE
;
373 ctrl_cfg
->max
= V4L2_FLASH_STROBE_SOURCE_EXTERNAL
;
374 ctrl_cfg
->menu_skip_mask
= ~mask
;
375 ctrl_cfg
->def
= V4L2_FLASH_STROBE_SOURCE_SOFTWARE
;
378 /* Init STROBE_STATUS ctrl data */
379 if (fled_cdev_ops
->strobe_get
) {
380 ctrl_init_data
[STROBE_STATUS
].cid
=
381 V4L2_CID_FLASH_STROBE_STATUS
;
382 ctrl_cfg
= &ctrl_init_data
[STROBE_STATUS
].config
;
383 ctrl_cfg
->id
= V4L2_CID_FLASH_STROBE_STATUS
;
384 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
385 V4L2_CTRL_FLAG_READ_ONLY
;
388 /* Init FLASH_TIMEOUT ctrl data */
389 if (fled_cdev_ops
->timeout_set
) {
390 ctrl_init_data
[FLASH_TIMEOUT
].cid
= V4L2_CID_FLASH_TIMEOUT
;
391 ctrl_cfg
= &ctrl_init_data
[FLASH_TIMEOUT
].config
;
392 __lfs_to_v4l2_ctrl_config(&fled_cdev
->timeout
, ctrl_cfg
);
393 ctrl_cfg
->id
= V4L2_CID_FLASH_TIMEOUT
;
396 /* Init FLASH_INTENSITY ctrl data */
397 if (fled_cdev_ops
->flash_brightness_set
) {
398 ctrl_init_data
[FLASH_INTENSITY
].cid
= V4L2_CID_FLASH_INTENSITY
;
399 ctrl_cfg
= &ctrl_init_data
[FLASH_INTENSITY
].config
;
400 __lfs_to_v4l2_ctrl_config(&fled_cdev
->brightness
, ctrl_cfg
);
401 ctrl_cfg
->id
= V4L2_CID_FLASH_INTENSITY
;
402 ctrl_cfg
->flags
= V4L2_CTRL_FLAG_VOLATILE
|
403 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE
;
407 static int v4l2_flash_init_controls(struct v4l2_flash
*v4l2_flash
,
408 struct v4l2_flash_config
*flash_cfg
)
411 struct v4l2_flash_ctrl_data
*ctrl_init_data
;
412 struct v4l2_ctrl
*ctrl
;
413 struct v4l2_ctrl_config
*ctrl_cfg
;
414 int i
, ret
, num_ctrls
= 0;
416 v4l2_flash
->ctrls
= devm_kzalloc(v4l2_flash
->sd
.dev
,
417 sizeof(*v4l2_flash
->ctrls
) *
418 (STROBE_SOURCE
+ 1), GFP_KERNEL
);
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 v4l2_flash_set_led_brightness(v4l2_flash
, ctrls
[TORCH_INTENSITY
]);
491 if (ctrls
[INDICATOR_INTENSITY
])
492 v4l2_flash_set_led_brightness(v4l2_flash
,
493 ctrls
[INDICATOR_INTENSITY
]);
495 if (ctrls
[FLASH_TIMEOUT
]) {
496 ret
= led_set_flash_timeout(fled_cdev
,
497 ctrls
[FLASH_TIMEOUT
]->val
);
502 if (ctrls
[FLASH_INTENSITY
]) {
503 ret
= led_set_flash_brightness(fled_cdev
,
504 ctrls
[FLASH_INTENSITY
]->val
);
510 * For some hardware arrangements setting strobe source may affect
511 * torch mode. Synchronize strobe source setting only if not in torch
512 * mode. For torch mode case it will get synchronized upon switching
515 if (ctrls
[STROBE_SOURCE
] &&
516 ctrls
[LED_MODE
]->val
!= V4L2_FLASH_LED_MODE_TORCH
)
517 ret
= call_flash_op(v4l2_flash
, external_strobe_set
,
518 ctrls
[STROBE_SOURCE
]->val
);
524 * V4L2 subdev internal operations
527 static int v4l2_flash_open(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
529 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
530 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
531 struct led_classdev
*led_cdev
= &fled_cdev
->led_cdev
;
532 struct led_classdev_flash
*iled_cdev
= v4l2_flash
->iled_cdev
;
533 struct led_classdev
*led_cdev_ind
= NULL
;
536 if (!v4l2_fh_is_singular(&fh
->vfh
))
539 mutex_lock(&led_cdev
->led_access
);
541 led_sysfs_disable(led_cdev
);
542 led_trigger_remove(led_cdev
);
544 mutex_unlock(&led_cdev
->led_access
);
547 led_cdev_ind
= &iled_cdev
->led_cdev
;
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
;
563 mutex_lock(&led_cdev
->led_access
);
564 led_sysfs_enable(led_cdev
);
565 mutex_unlock(&led_cdev
->led_access
);
568 mutex_lock(&led_cdev_ind
->led_access
);
569 led_sysfs_enable(led_cdev_ind
);
570 mutex_unlock(&led_cdev_ind
->led_access
);
576 static int v4l2_flash_close(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
578 struct v4l2_flash
*v4l2_flash
= v4l2_subdev_to_v4l2_flash(sd
);
579 struct led_classdev_flash
*fled_cdev
= v4l2_flash
->fled_cdev
;
580 struct led_classdev
*led_cdev
= &fled_cdev
->led_cdev
;
581 struct led_classdev_flash
*iled_cdev
= v4l2_flash
->iled_cdev
;
584 if (!v4l2_fh_is_singular(&fh
->vfh
))
587 mutex_lock(&led_cdev
->led_access
);
589 if (v4l2_flash
->ctrls
[STROBE_SOURCE
])
590 ret
= v4l2_ctrl_s_ctrl(v4l2_flash
->ctrls
[STROBE_SOURCE
],
591 V4L2_FLASH_STROBE_SOURCE_SOFTWARE
);
592 led_sysfs_enable(led_cdev
);
594 mutex_unlock(&led_cdev
->led_access
);
597 struct led_classdev
*led_cdev_ind
= &iled_cdev
->led_cdev
;
599 mutex_lock(&led_cdev_ind
->led_access
);
600 led_sysfs_enable(led_cdev_ind
);
601 mutex_unlock(&led_cdev_ind
->led_access
);
607 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops
= {
608 .open
= v4l2_flash_open
,
609 .close
= v4l2_flash_close
,
612 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops
;
614 struct v4l2_flash
*v4l2_flash_init(
615 struct device
*dev
, struct device_node
*of_node
,
616 struct led_classdev_flash
*fled_cdev
,
617 struct led_classdev_flash
*iled_cdev
,
618 const struct v4l2_flash_ops
*ops
,
619 struct v4l2_flash_config
*config
)
621 struct v4l2_flash
*v4l2_flash
;
622 struct led_classdev
*led_cdev
;
623 struct v4l2_subdev
*sd
;
626 if (!fled_cdev
|| !ops
|| !config
)
627 return ERR_PTR(-EINVAL
);
629 led_cdev
= &fled_cdev
->led_cdev
;
631 v4l2_flash
= devm_kzalloc(led_cdev
->dev
, sizeof(*v4l2_flash
),
634 return ERR_PTR(-ENOMEM
);
636 sd
= &v4l2_flash
->sd
;
637 v4l2_flash
->fled_cdev
= fled_cdev
;
638 v4l2_flash
->iled_cdev
= iled_cdev
;
639 v4l2_flash
->ops
= ops
;
641 sd
->of_node
= of_node
? of_node
: led_cdev
->dev
->of_node
;
642 v4l2_subdev_init(sd
, &v4l2_flash_subdev_ops
);
643 sd
->internal_ops
= &v4l2_flash_subdev_internal_ops
;
644 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
645 strlcpy(sd
->name
, config
->dev_name
, sizeof(sd
->name
));
647 ret
= media_entity_pads_init(&sd
->entity
, 0, NULL
);
651 sd
->entity
.function
= MEDIA_ENT_F_FLASH
;
653 ret
= v4l2_flash_init_controls(v4l2_flash
, config
);
655 goto err_init_controls
;
657 of_node_get(sd
->of_node
);
659 ret
= v4l2_async_register_subdev(sd
);
661 goto err_async_register_sd
;
665 err_async_register_sd
:
666 of_node_put(sd
->of_node
);
667 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
669 media_entity_cleanup(&sd
->entity
);
673 EXPORT_SYMBOL_GPL(v4l2_flash_init
);
675 void v4l2_flash_release(struct v4l2_flash
*v4l2_flash
)
677 struct v4l2_subdev
*sd
;
679 if (IS_ERR_OR_NULL(v4l2_flash
))
682 sd
= &v4l2_flash
->sd
;
684 v4l2_async_unregister_subdev(sd
);
686 of_node_put(sd
->of_node
);
688 v4l2_ctrl_handler_free(sd
->ctrl_handler
);
689 media_entity_cleanup(&sd
->entity
);
691 EXPORT_SYMBOL_GPL(v4l2_flash_release
);
693 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
694 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
695 MODULE_LICENSE("GPL v2");