xref: /openbmc/linux/drivers/media/v4l2-core/v4l2-flash-led-class.c (revision a40eba9b26f70c7a967647a05ce0ef84e82140ba)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * V4L2 flash LED sub-device registration helpers.
4  *
5  *	Copyright (C) 2015 Samsung Electronics Co., Ltd
6  *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
7  */
8 
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>
16 
17 #define has_flash_op(v4l2_flash, op)				\
18 	(v4l2_flash && v4l2_flash->ops && v4l2_flash->ops->op)
19 
20 #define call_flash_op(v4l2_flash, op, arg)			\
21 		(has_flash_op(v4l2_flash, op) ?			\
22 			v4l2_flash->ops->op(v4l2_flash, arg) :	\
23 			-EINVAL)
24 
25 enum ctrl_init_data_id {
26 	LED_MODE,
27 	TORCH_INTENSITY,
28 	FLASH_INTENSITY,
29 	INDICATOR_INTENSITY,
30 	FLASH_TIMEOUT,
31 	STROBE_SOURCE,
32 	/*
33 	 * Only above values are applicable to
34 	 * the 'ctrls' array in the struct v4l2_flash.
35 	 */
36 	FLASH_STROBE,
37 	STROBE_STOP,
38 	STROBE_STATUS,
39 	FLASH_FAULT,
40 	NUM_FLASH_CTRLS,
41 };
42 
43 static enum led_brightness __intensity_to_led_brightness(
44 					struct v4l2_ctrl *ctrl, s32 intensity)
45 {
46 	intensity -= ctrl->minimum;
47 	intensity /= (u32) ctrl->step;
48 
49 	/*
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.
54 	 */
55 	if (ctrl->minimum)
56 		++intensity;
57 
58 	return intensity;
59 }
60 
61 static s32 __led_brightness_to_intensity(struct v4l2_ctrl *ctrl,
62 					 enum led_brightness brightness)
63 {
64 	/*
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.
72 	 */
73 	if (ctrl->id != V4L2_CID_FLASH_INDICATOR_INTENSITY)
74 		--brightness;
75 
76 	return (brightness * ctrl->step) + ctrl->minimum;
77 }
78 
79 static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
80 					struct v4l2_ctrl *ctrl)
81 {
82 	struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
83 	struct led_classdev *led_cdev;
84 	enum led_brightness brightness;
85 
86 	if (has_flash_op(v4l2_flash, intensity_to_led_brightness))
87 		brightness = call_flash_op(v4l2_flash,
88 					intensity_to_led_brightness,
89 					ctrl->val);
90 	else
91 		brightness = __intensity_to_led_brightness(ctrl, ctrl->val);
92 	/*
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 	 * the aligned intensity value.
98 	 */
99 	if (has_flash_op(v4l2_flash, led_brightness_to_intensity))
100 		ctrl->val = call_flash_op(v4l2_flash,
101 					led_brightness_to_intensity,
102 					brightness);
103 
104 	if (ctrl == ctrls[TORCH_INTENSITY]) {
105 		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
106 			return;
107 
108 		if (WARN_ON_ONCE(!v4l2_flash->fled_cdev))
109 			return;
110 
111 		led_cdev = &v4l2_flash->fled_cdev->led_cdev;
112 	} else {
113 		if (WARN_ON_ONCE(!v4l2_flash->iled_cdev))
114 			return;
115 
116 		led_cdev = v4l2_flash->iled_cdev;
117 	}
118 
119 	led_set_brightness_sync(led_cdev, brightness);
120 }
121 
122 static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash,
123 					struct v4l2_ctrl *ctrl)
124 {
125 	struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
126 	struct led_classdev *led_cdev;
127 	int ret;
128 
129 	if (ctrl == ctrls[TORCH_INTENSITY]) {
130 		/*
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
134 		 * has changed to 0.
135 		 */
136 		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
137 			return 0;
138 
139 		if (WARN_ON_ONCE(!v4l2_flash->fled_cdev))
140 			return -EINVAL;
141 
142 		led_cdev = &v4l2_flash->fled_cdev->led_cdev;
143 	} else {
144 		if (WARN_ON_ONCE(!v4l2_flash->iled_cdev))
145 			return -EINVAL;
146 
147 		led_cdev = v4l2_flash->iled_cdev;
148 	}
149 
150 	ret = led_update_brightness(led_cdev);
151 	if (ret < 0)
152 		return ret;
153 
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);
158 	else
159 		ctrl->val = __led_brightness_to_intensity(ctrl,
160 						led_cdev->brightness);
161 
162 	return 0;
163 }
164 
165 static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
166 {
167 	struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
168 	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
169 	bool is_strobing;
170 	int ret;
171 
172 	switch (c->id) {
173 	case V4L2_CID_FLASH_TORCH_INTENSITY:
174 	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
175 		return v4l2_flash_update_led_brightness(v4l2_flash, c);
176 	}
177 
178 	if (!fled_cdev)
179 		return -EINVAL;
180 
181 	switch (c->id) {
182 	case V4L2_CID_FLASH_INTENSITY:
183 		ret = led_update_flash_brightness(fled_cdev);
184 		if (ret < 0)
185 			return ret;
186 		/*
187 		 * No conversion is needed as LED Flash class also uses
188 		 * microamperes for flash intensity units.
189 		 */
190 		c->val = fled_cdev->brightness.val;
191 		return 0;
192 	case V4L2_CID_FLASH_STROBE_STATUS:
193 		ret = led_get_flash_strobe(fled_cdev, &is_strobing);
194 		if (ret < 0)
195 			return ret;
196 		c->val = is_strobing;
197 		return 0;
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);
201 	default:
202 		return -EINVAL;
203 	}
204 }
205 
206 static bool __software_strobe_mode_inactive(struct v4l2_ctrl **ctrls)
207 {
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)));
211 }
212 
213 static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
214 {
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;
220 	int ret = 0;
221 
222 	switch (c->id) {
223 	case V4L2_CID_FLASH_TORCH_INTENSITY:
224 	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
225 		v4l2_flash_set_led_brightness(v4l2_flash, c);
226 		return 0;
227 	}
228 
229 	if (!fled_cdev)
230 		return -EINVAL;
231 
232 	led_cdev = &fled_cdev->led_cdev;
233 
234 	switch (c->id) {
235 	case V4L2_CID_FLASH_LED_MODE:
236 		switch (c->val) {
237 		case V4L2_FLASH_LED_MODE_NONE:
238 			led_set_brightness_sync(led_cdev, LED_OFF);
239 			return led_set_flash_strobe(fled_cdev, false);
240 		case V4L2_FLASH_LED_MODE_FLASH:
241 			/* Turn the torch LED off */
242 			led_set_brightness_sync(led_cdev, LED_OFF);
243 			if (ctrls[STROBE_SOURCE]) {
244 				external_strobe = (ctrls[STROBE_SOURCE]->val ==
245 					V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
246 
247 				ret = call_flash_op(v4l2_flash,
248 						external_strobe_set,
249 						external_strobe);
250 			}
251 			return ret;
252 		case V4L2_FLASH_LED_MODE_TORCH:
253 			if (ctrls[STROBE_SOURCE]) {
254 				ret = call_flash_op(v4l2_flash,
255 						external_strobe_set,
256 						false);
257 				if (ret < 0)
258 					return ret;
259 			}
260 			/* Stop flash strobing */
261 			ret = led_set_flash_strobe(fled_cdev, false);
262 			if (ret < 0)
263 				return ret;
264 
265 			v4l2_flash_set_led_brightness(v4l2_flash,
266 							ctrls[TORCH_INTENSITY]);
267 			return 0;
268 		}
269 		break;
270 	case V4L2_CID_FLASH_STROBE_SOURCE:
271 		external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
272 		/*
273 		 * For some hardware arrangements setting strobe source may
274 		 * affect torch mode. Therefore, if not in the flash mode,
275 		 * cache only this setting. It will be applied upon switching
276 		 * to flash mode.
277 		 */
278 		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH)
279 			return 0;
280 
281 		return call_flash_op(v4l2_flash, external_strobe_set,
282 					external_strobe);
283 	case V4L2_CID_FLASH_STROBE:
284 		if (__software_strobe_mode_inactive(ctrls))
285 			return -EBUSY;
286 		return led_set_flash_strobe(fled_cdev, true);
287 	case V4L2_CID_FLASH_STROBE_STOP:
288 		if (__software_strobe_mode_inactive(ctrls))
289 			return -EBUSY;
290 		return led_set_flash_strobe(fled_cdev, false);
291 	case V4L2_CID_FLASH_TIMEOUT:
292 		/*
293 		 * No conversion is needed as LED Flash class also uses
294 		 * microseconds for flash timeout units.
295 		 */
296 		return led_set_flash_timeout(fled_cdev, c->val);
297 	case V4L2_CID_FLASH_INTENSITY:
298 		/*
299 		 * No conversion is needed as LED Flash class also uses
300 		 * microamperes for flash intensity units.
301 		 */
302 		return led_set_flash_brightness(fled_cdev, c->val);
303 	}
304 
305 	return -EINVAL;
306 }
307 
308 static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = {
309 	.g_volatile_ctrl = v4l2_flash_g_volatile_ctrl,
310 	.s_ctrl = v4l2_flash_s_ctrl,
311 };
312 
313 static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting *s,
314 				struct v4l2_ctrl_config *c)
315 {
316 	c->min = s->min;
317 	c->max = s->max;
318 	c->step = s->step;
319 	c->def = s->val;
320 }
321 
322 static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
323 			  struct v4l2_flash_config *flash_cfg,
324 			  struct v4l2_flash_ctrl_data *ctrl_init_data)
325 {
326 	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
327 	struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
328 	struct v4l2_ctrl_config *ctrl_cfg;
329 	u32 mask;
330 
331 	/* Init INDICATOR_INTENSITY ctrl data */
332 	if (v4l2_flash->iled_cdev) {
333 		ctrl_init_data[INDICATOR_INTENSITY].cid =
334 					V4L2_CID_FLASH_INDICATOR_INTENSITY;
335 		ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
336 		__lfs_to_v4l2_ctrl_config(&flash_cfg->intensity,
337 					  ctrl_cfg);
338 		ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
339 		ctrl_cfg->min = 0;
340 		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
341 				  V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
342 	}
343 
344 	if (!led_cdev || WARN_ON(!(led_cdev->flags & LED_DEV_CAP_FLASH)))
345 		return;
346 
347 	/* Init FLASH_FAULT ctrl data */
348 	if (flash_cfg->flash_faults) {
349 		ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT;
350 		ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config;
351 		ctrl_cfg->id = V4L2_CID_FLASH_FAULT;
352 		ctrl_cfg->max = flash_cfg->flash_faults;
353 		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
354 				  V4L2_CTRL_FLAG_READ_ONLY;
355 	}
356 
357 	/* Init FLASH_LED_MODE ctrl data */
358 	mask = 1 << V4L2_FLASH_LED_MODE_NONE |
359 	       1 << V4L2_FLASH_LED_MODE_TORCH;
360 	if (led_cdev->flags & LED_DEV_CAP_FLASH)
361 		mask |= 1 << V4L2_FLASH_LED_MODE_FLASH;
362 
363 	ctrl_init_data[LED_MODE].cid = V4L2_CID_FLASH_LED_MODE;
364 	ctrl_cfg = &ctrl_init_data[LED_MODE].config;
365 	ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE;
366 	ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH;
367 	ctrl_cfg->menu_skip_mask = ~mask;
368 	ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE;
369 	ctrl_cfg->flags = 0;
370 
371 	/* Init TORCH_INTENSITY ctrl data */
372 	ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY;
373 	ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
374 	__lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, ctrl_cfg);
375 	ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
376 	ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
377 			  V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
378 
379 	/* Init FLASH_STROBE ctrl data */
380 	ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE;
381 	ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
382 	ctrl_cfg->id = V4L2_CID_FLASH_STROBE;
383 
384 	/* Init STROBE_STOP ctrl data */
385 	ctrl_init_data[STROBE_STOP].cid = V4L2_CID_FLASH_STROBE_STOP;
386 	ctrl_cfg = &ctrl_init_data[STROBE_STOP].config;
387 	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP;
388 
389 	/* Init FLASH_STROBE_SOURCE ctrl data */
390 	if (flash_cfg->has_external_strobe) {
391 		mask = (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE) |
392 		       (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
393 		ctrl_init_data[STROBE_SOURCE].cid =
394 					V4L2_CID_FLASH_STROBE_SOURCE;
395 		ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config;
396 		ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE;
397 		ctrl_cfg->max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
398 		ctrl_cfg->menu_skip_mask = ~mask;
399 		ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
400 	}
401 
402 	/* Init STROBE_STATUS ctrl data */
403 	if (has_flash_op(fled_cdev, strobe_get)) {
404 		ctrl_init_data[STROBE_STATUS].cid =
405 					V4L2_CID_FLASH_STROBE_STATUS;
406 		ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config;
407 		ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS;
408 		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
409 				  V4L2_CTRL_FLAG_READ_ONLY;
410 	}
411 
412 	/* Init FLASH_TIMEOUT ctrl data */
413 	if (has_flash_op(fled_cdev, timeout_set)) {
414 		ctrl_init_data[FLASH_TIMEOUT].cid = V4L2_CID_FLASH_TIMEOUT;
415 		ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config;
416 		__lfs_to_v4l2_ctrl_config(&fled_cdev->timeout, ctrl_cfg);
417 		ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT;
418 	}
419 
420 	/* Init FLASH_INTENSITY ctrl data */
421 	if (has_flash_op(fled_cdev, flash_brightness_set)) {
422 		ctrl_init_data[FLASH_INTENSITY].cid = V4L2_CID_FLASH_INTENSITY;
423 		ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config;
424 		__lfs_to_v4l2_ctrl_config(&fled_cdev->brightness, ctrl_cfg);
425 		ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY;
426 		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
427 				  V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
428 	}
429 }
430 
431 static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash,
432 				struct v4l2_flash_config *flash_cfg)
433 
434 {
435 	struct v4l2_flash_ctrl_data *ctrl_init_data;
436 	struct v4l2_ctrl *ctrl;
437 	struct v4l2_ctrl_config *ctrl_cfg;
438 	int i, ret, num_ctrls = 0;
439 
440 	v4l2_flash->ctrls = devm_kcalloc(v4l2_flash->sd.dev,
441 					STROBE_SOURCE + 1,
442 					sizeof(*v4l2_flash->ctrls),
443 					GFP_KERNEL);
444 	if (!v4l2_flash->ctrls)
445 		return -ENOMEM;
446 
447 	/* allocate memory dynamically so as not to exceed stack frame size */
448 	ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data),
449 					GFP_KERNEL);
450 	if (!ctrl_init_data)
451 		return -ENOMEM;
452 
453 	__fill_ctrl_init_data(v4l2_flash, flash_cfg, ctrl_init_data);
454 
455 	for (i = 0; i < NUM_FLASH_CTRLS; ++i)
456 		if (ctrl_init_data[i].cid)
457 			++num_ctrls;
458 
459 	v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
460 
461 	for (i = 0; i < NUM_FLASH_CTRLS; ++i) {
462 		ctrl_cfg = &ctrl_init_data[i].config;
463 		if (!ctrl_init_data[i].cid)
464 			continue;
465 
466 		if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE ||
467 		    ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE)
468 			ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl,
469 						&v4l2_flash_ctrl_ops,
470 						ctrl_cfg->id,
471 						ctrl_cfg->max,
472 						ctrl_cfg->menu_skip_mask,
473 						ctrl_cfg->def);
474 		else
475 			ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
476 						&v4l2_flash_ctrl_ops,
477 						ctrl_cfg->id,
478 						ctrl_cfg->min,
479 						ctrl_cfg->max,
480 						ctrl_cfg->step,
481 						ctrl_cfg->def);
482 
483 		if (ctrl)
484 			ctrl->flags |= ctrl_cfg->flags;
485 
486 		if (i <= STROBE_SOURCE)
487 			v4l2_flash->ctrls[i] = ctrl;
488 	}
489 
490 	kfree(ctrl_init_data);
491 
492 	if (v4l2_flash->hdl.error) {
493 		ret = v4l2_flash->hdl.error;
494 		goto error_free_handler;
495 	}
496 
497 	v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
498 
499 	v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl;
500 
501 	return 0;
502 
503 error_free_handler:
504 	v4l2_ctrl_handler_free(&v4l2_flash->hdl);
505 	return ret;
506 }
507 
508 static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash)
509 {
510 	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
511 	struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
512 	int ret = 0;
513 
514 	if (ctrls[TORCH_INTENSITY])
515 		v4l2_flash_set_led_brightness(v4l2_flash,
516 					      ctrls[TORCH_INTENSITY]);
517 
518 	if (ctrls[INDICATOR_INTENSITY])
519 		v4l2_flash_set_led_brightness(v4l2_flash,
520 						ctrls[INDICATOR_INTENSITY]);
521 
522 	if (ctrls[FLASH_TIMEOUT]) {
523 		if (WARN_ON_ONCE(!fled_cdev))
524 			return -EINVAL;
525 
526 		ret = led_set_flash_timeout(fled_cdev,
527 					ctrls[FLASH_TIMEOUT]->val);
528 		if (ret < 0)
529 			return ret;
530 	}
531 
532 	if (ctrls[FLASH_INTENSITY]) {
533 		if (WARN_ON_ONCE(!fled_cdev))
534 			return -EINVAL;
535 
536 		ret = led_set_flash_brightness(fled_cdev,
537 					ctrls[FLASH_INTENSITY]->val);
538 		if (ret < 0)
539 			return ret;
540 	}
541 
542 	/*
543 	 * For some hardware arrangements setting strobe source may affect
544 	 * torch mode. Synchronize strobe source setting only if not in torch
545 	 * mode. For torch mode case it will get synchronized upon switching
546 	 * to flash mode.
547 	 */
548 	if (ctrls[STROBE_SOURCE] &&
549 	    ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
550 		ret = call_flash_op(v4l2_flash, external_strobe_set,
551 					ctrls[STROBE_SOURCE]->val);
552 
553 	return ret;
554 }
555 
556 /*
557  * V4L2 subdev internal operations
558  */
559 
560 static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
561 {
562 	struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
563 	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
564 	struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
565 	struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
566 	int ret = 0;
567 
568 	if (!v4l2_fh_is_singular(&fh->vfh))
569 		return 0;
570 
571 	if (led_cdev) {
572 		mutex_lock(&led_cdev->led_access);
573 
574 		led_sysfs_disable(led_cdev);
575 		led_trigger_remove(led_cdev);
576 
577 		mutex_unlock(&led_cdev->led_access);
578 	}
579 
580 	if (led_cdev_ind) {
581 		mutex_lock(&led_cdev_ind->led_access);
582 
583 		led_sysfs_disable(led_cdev_ind);
584 		led_trigger_remove(led_cdev_ind);
585 
586 		mutex_unlock(&led_cdev_ind->led_access);
587 	}
588 
589 	ret = __sync_device_with_v4l2_controls(v4l2_flash);
590 	if (ret < 0)
591 		goto out_sync_device;
592 
593 	return 0;
594 out_sync_device:
595 	if (led_cdev) {
596 		mutex_lock(&led_cdev->led_access);
597 		led_sysfs_enable(led_cdev);
598 		mutex_unlock(&led_cdev->led_access);
599 	}
600 
601 	if (led_cdev_ind) {
602 		mutex_lock(&led_cdev_ind->led_access);
603 		led_sysfs_enable(led_cdev_ind);
604 		mutex_unlock(&led_cdev_ind->led_access);
605 	}
606 
607 	return ret;
608 }
609 
610 static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
611 {
612 	struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
613 	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
614 	struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
615 	struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
616 	int ret = 0;
617 
618 	if (!v4l2_fh_is_singular(&fh->vfh))
619 		return 0;
620 
621 	if (led_cdev) {
622 		mutex_lock(&led_cdev->led_access);
623 
624 		if (v4l2_flash->ctrls[STROBE_SOURCE])
625 			ret = v4l2_ctrl_s_ctrl(
626 				v4l2_flash->ctrls[STROBE_SOURCE],
627 				V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
628 		led_sysfs_enable(led_cdev);
629 
630 		mutex_unlock(&led_cdev->led_access);
631 	}
632 
633 	if (led_cdev_ind) {
634 		mutex_lock(&led_cdev_ind->led_access);
635 		led_sysfs_enable(led_cdev_ind);
636 		mutex_unlock(&led_cdev_ind->led_access);
637 	}
638 
639 	return ret;
640 }
641 
642 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
643 	.open = v4l2_flash_open,
644 	.close = v4l2_flash_close,
645 };
646 
647 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops;
648 
649 static struct v4l2_flash *__v4l2_flash_init(
650 	struct device *dev, struct fwnode_handle *fwn,
651 	struct led_classdev_flash *fled_cdev, struct led_classdev *iled_cdev,
652 	const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config)
653 {
654 	struct v4l2_flash *v4l2_flash;
655 	struct v4l2_subdev *sd;
656 	int ret;
657 
658 	if (!config)
659 		return ERR_PTR(-EINVAL);
660 
661 	v4l2_flash = devm_kzalloc(dev, sizeof(*v4l2_flash), GFP_KERNEL);
662 	if (!v4l2_flash)
663 		return ERR_PTR(-ENOMEM);
664 
665 	sd = &v4l2_flash->sd;
666 	v4l2_flash->fled_cdev = fled_cdev;
667 	v4l2_flash->iled_cdev = iled_cdev;
668 	v4l2_flash->ops = ops;
669 	sd->dev = dev;
670 	sd->fwnode = fwn ? fwn : dev_fwnode(dev);
671 	v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
672 	sd->internal_ops = &v4l2_flash_subdev_internal_ops;
673 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
674 	strscpy(sd->name, config->dev_name, sizeof(sd->name));
675 
676 	ret = media_entity_pads_init(&sd->entity, 0, NULL);
677 	if (ret < 0)
678 		return ERR_PTR(ret);
679 
680 	sd->entity.function = MEDIA_ENT_F_FLASH;
681 
682 	ret = v4l2_flash_init_controls(v4l2_flash, config);
683 	if (ret < 0)
684 		goto err_init_controls;
685 
686 	fwnode_handle_get(sd->fwnode);
687 
688 	ret = v4l2_async_register_subdev(sd);
689 	if (ret < 0)
690 		goto err_async_register_sd;
691 
692 	return v4l2_flash;
693 
694 err_async_register_sd:
695 	fwnode_handle_put(sd->fwnode);
696 	v4l2_ctrl_handler_free(sd->ctrl_handler);
697 err_init_controls:
698 	media_entity_cleanup(&sd->entity);
699 
700 	return ERR_PTR(ret);
701 }
702 
703 struct v4l2_flash *v4l2_flash_init(
704 	struct device *dev, struct fwnode_handle *fwn,
705 	struct led_classdev_flash *fled_cdev,
706 	const struct v4l2_flash_ops *ops,
707 	struct v4l2_flash_config *config)
708 {
709 	return __v4l2_flash_init(dev, fwn, fled_cdev, NULL, ops, config);
710 }
711 EXPORT_SYMBOL_GPL(v4l2_flash_init);
712 
713 struct v4l2_flash *v4l2_flash_indicator_init(
714 	struct device *dev, struct fwnode_handle *fwn,
715 	struct led_classdev *iled_cdev,
716 	struct v4l2_flash_config *config)
717 {
718 	return __v4l2_flash_init(dev, fwn, NULL, iled_cdev, NULL, config);
719 }
720 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init);
721 
722 void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
723 {
724 	struct v4l2_subdev *sd;
725 
726 	if (IS_ERR_OR_NULL(v4l2_flash))
727 		return;
728 
729 	sd = &v4l2_flash->sd;
730 
731 	v4l2_async_unregister_subdev(sd);
732 
733 	fwnode_handle_put(sd->fwnode);
734 
735 	v4l2_ctrl_handler_free(sd->ctrl_handler);
736 	media_entity_cleanup(&sd->entity);
737 }
738 EXPORT_SYMBOL_GPL(v4l2_flash_release);
739 
740 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
741 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
742 MODULE_LICENSE("GPL v2");
743