Linux Audio

Check our new training course

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