1/*
2 * V4L2 flash LED sub-device registration helpers.
3 *
4 *	Copyright (C) 2015 Samsung Electronics Co., Ltd
5 *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
6 *
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.
10 */
11
12#include <linux/led-class-flash.h>
13#include <linux/module.h>
14#include <linux/mutex.h>
15#include <linux/of.h>
16#include <linux/slab.h>
17#include <linux/types.h>
18#include <media/v4l2-flash-led-class.h>
19
20#define has_flash_op(v4l2_flash, op)				\
21	(v4l2_flash && v4l2_flash->ops->op)
22
23#define call_flash_op(v4l2_flash, op, arg)			\
24		(has_flash_op(v4l2_flash, op) ?			\
25			v4l2_flash->ops->op(v4l2_flash, arg) :	\
26			-EINVAL)
27
28enum ctrl_init_data_id {
29	LED_MODE,
30	TORCH_INTENSITY,
31	FLASH_INTENSITY,
32	INDICATOR_INTENSITY,
33	FLASH_TIMEOUT,
34	STROBE_SOURCE,
35	/*
36	 * Only above values are applicable to
37	 * the 'ctrls' array in the struct v4l2_flash.
38	 */
39	FLASH_STROBE,
40	STROBE_STOP,
41	STROBE_STATUS,
42	FLASH_FAULT,
43	NUM_FLASH_CTRLS,
44};
45
46static enum led_brightness __intensity_to_led_brightness(
47					struct v4l2_ctrl *ctrl, s32 intensity)
48{
49	intensity -= ctrl->minimum;
50	intensity /= (u32) ctrl->step;
51
52	/*
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.
57	 */
58	if (ctrl->minimum)
59		++intensity;
60
61	return intensity;
62}
63
64static s32 __led_brightness_to_intensity(struct v4l2_ctrl *ctrl,
65					 enum led_brightness brightness)
66{
67	/*
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.
75	 */
76	if (ctrl->id != V4L2_CID_FLASH_INDICATOR_INTENSITY)
77		--brightness;
78
79	return (brightness * ctrl->step) + ctrl->minimum;
80}
81
82static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
83					struct v4l2_ctrl *ctrl)
84{
85	struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
86	enum led_brightness brightness;
87
88	if (has_flash_op(v4l2_flash, intensity_to_led_brightness))
89		brightness = call_flash_op(v4l2_flash,
90					intensity_to_led_brightness,
91					ctrl->val);
92	else
93		brightness = __intensity_to_led_brightness(ctrl, ctrl->val);
94	/*
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.
100	 */
101	if (has_flash_op(v4l2_flash, led_brightness_to_intensity))
102		ctrl->val = call_flash_op(v4l2_flash,
103					led_brightness_to_intensity,
104					brightness);
105
106	if (ctrl == ctrls[TORCH_INTENSITY]) {
107		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
108			return;
109
110		led_set_brightness(&v4l2_flash->fled_cdev->led_cdev,
111					brightness);
112	} else {
113		led_set_brightness(&v4l2_flash->iled_cdev->led_cdev,
114					brightness);
115	}
116}
117
118static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash,
119					struct v4l2_ctrl *ctrl)
120{
121	struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
122	struct led_classdev *led_cdev;
123	int ret;
124
125	if (ctrl == ctrls[TORCH_INTENSITY]) {
126		/*
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
130		 * has changed to 0.
131		 */
132		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
133			return 0;
134		led_cdev = &v4l2_flash->fled_cdev->led_cdev;
135	} else {
136		led_cdev = &v4l2_flash->iled_cdev->led_cdev;
137	}
138
139	ret = led_update_brightness(led_cdev);
140	if (ret < 0)
141		return ret;
142
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);
147	else
148		ctrl->val = __led_brightness_to_intensity(ctrl,
149						led_cdev->brightness);
150
151	return 0;
152}
153
154static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
155{
156	struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
157	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
158	bool is_strobing;
159	int ret;
160
161	switch (c->id) {
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);
167		if (ret < 0)
168			return ret;
169		/*
170		 * No conversion is needed as LED Flash class also uses
171		 * microamperes for flash intensity units.
172		 */
173		c->val = fled_cdev->brightness.val;
174		return 0;
175	case V4L2_CID_FLASH_STROBE_STATUS:
176		ret = led_get_flash_strobe(fled_cdev, &is_strobing);
177		if (ret < 0)
178			return ret;
179		c->val = is_strobing;
180		return 0;
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);
184	default:
185		return -EINVAL;
186	}
187}
188
189static bool __software_strobe_mode_inactive(struct v4l2_ctrl **ctrls)
190{
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)));
194}
195
196static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
197{
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;
203	int ret = 0;
204
205	switch (c->id) {
206	case V4L2_CID_FLASH_LED_MODE:
207		switch (c->val) {
208		case V4L2_FLASH_LED_MODE_NONE:
209			led_set_brightness(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(led_cdev, LED_OFF);
214			if (ctrls[STROBE_SOURCE]) {
215				external_strobe = (ctrls[STROBE_SOURCE]->val ==
216					V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
217
218				ret = call_flash_op(v4l2_flash,
219						external_strobe_set,
220						external_strobe);
221			}
222			return ret;
223		case V4L2_FLASH_LED_MODE_TORCH:
224			if (ctrls[STROBE_SOURCE]) {
225				ret = call_flash_op(v4l2_flash,
226						external_strobe_set,
227						false);
228				if (ret < 0)
229					return ret;
230			}
231			/* Stop flash strobing */
232			ret = led_set_flash_strobe(fled_cdev, false);
233			if (ret < 0)
234				return ret;
235
236			v4l2_flash_set_led_brightness(v4l2_flash,
237							ctrls[TORCH_INTENSITY]);
238			return 0;
239		}
240		break;
241	case V4L2_CID_FLASH_STROBE_SOURCE:
242		external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
243		/*
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
247		 * to flash mode.
248		 */
249		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH)
250			return 0;
251
252		return call_flash_op(v4l2_flash, external_strobe_set,
253					external_strobe);
254	case V4L2_CID_FLASH_STROBE:
255		if (__software_strobe_mode_inactive(ctrls))
256			return -EBUSY;
257		return led_set_flash_strobe(fled_cdev, true);
258	case V4L2_CID_FLASH_STROBE_STOP:
259		if (__software_strobe_mode_inactive(ctrls))
260			return -EBUSY;
261		return led_set_flash_strobe(fled_cdev, false);
262	case V4L2_CID_FLASH_TIMEOUT:
263		/*
264		 * No conversion is needed as LED Flash class also uses
265		 * microseconds for flash timeout units.
266		 */
267		return led_set_flash_timeout(fled_cdev, c->val);
268	case V4L2_CID_FLASH_INTENSITY:
269		/*
270		 * No conversion is needed as LED Flash class also uses
271		 * microamperes for flash intensity units.
272		 */
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);
277		return 0;
278	}
279
280	return -EINVAL;
281}
282
283static 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,
286};
287
288static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting *s,
289				struct v4l2_ctrl_config *c)
290{
291	c->min = s->min;
292	c->max = s->max;
293	c->step = s->step;
294	c->def = s->val;
295}
296
297static 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)
300{
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;
305	u32 mask;
306
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;
315	}
316
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;
322
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;
329	ctrl_cfg->flags = 0;
330
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;
338
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,
345					  ctrl_cfg);
346		ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
347		ctrl_cfg->min = 0;
348		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
349				  V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
350	}
351
352	if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
353		return;
354
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;
359
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;
364
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;
376	}
377
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;
386	}
387
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;
394	}
395
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;
404	}
405}
406
407static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash,
408				struct v4l2_flash_config *flash_cfg)
409
410{
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;
415
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)
420		return -ENOMEM;
421
422	/* allocate memory dynamically so as not to exceed stack frame size */
423	ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data),
424					GFP_KERNEL);
425	if (!ctrl_init_data)
426		return -ENOMEM;
427
428	__fill_ctrl_init_data(v4l2_flash, flash_cfg, ctrl_init_data);
429
430	for (i = 0; i < NUM_FLASH_CTRLS; ++i)
431		if (ctrl_init_data[i].cid)
432			++num_ctrls;
433
434	v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
435
436	for (i = 0; i < NUM_FLASH_CTRLS; ++i) {
437		ctrl_cfg = &ctrl_init_data[i].config;
438		if (!ctrl_init_data[i].cid)
439			continue;
440
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,
445						ctrl_cfg->id,
446						ctrl_cfg->max,
447						ctrl_cfg->menu_skip_mask,
448						ctrl_cfg->def);
449		else
450			ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
451						&v4l2_flash_ctrl_ops,
452						ctrl_cfg->id,
453						ctrl_cfg->min,
454						ctrl_cfg->max,
455						ctrl_cfg->step,
456						ctrl_cfg->def);
457
458		if (ctrl)
459			ctrl->flags |= ctrl_cfg->flags;
460
461		if (i <= STROBE_SOURCE)
462			v4l2_flash->ctrls[i] = ctrl;
463	}
464
465	kfree(ctrl_init_data);
466
467	if (v4l2_flash->hdl.error) {
468		ret = v4l2_flash->hdl.error;
469		goto error_free_handler;
470	}
471
472	v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
473
474	v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl;
475
476	return 0;
477
478error_free_handler:
479	v4l2_ctrl_handler_free(&v4l2_flash->hdl);
480	return ret;
481}
482
483static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash)
484{
485	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
486	struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
487	int ret = 0;
488
489	v4l2_flash_set_led_brightness(v4l2_flash, ctrls[TORCH_INTENSITY]);
490
491	if (ctrls[INDICATOR_INTENSITY])
492		v4l2_flash_set_led_brightness(v4l2_flash,
493						ctrls[INDICATOR_INTENSITY]);
494
495	if (ctrls[FLASH_TIMEOUT]) {
496		ret = led_set_flash_timeout(fled_cdev,
497					ctrls[FLASH_TIMEOUT]->val);
498		if (ret < 0)
499			return ret;
500	}
501
502	if (ctrls[FLASH_INTENSITY]) {
503		ret = led_set_flash_brightness(fled_cdev,
504					ctrls[FLASH_INTENSITY]->val);
505		if (ret < 0)
506			return ret;
507	}
508
509	/*
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
513	 * to flash mode.
514	 */
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);
519
520	return ret;
521}
522
523/*
524 * V4L2 subdev internal operations
525 */
526
527static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
528{
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;
534	int ret = 0;
535
536	if (!v4l2_fh_is_singular(&fh->vfh))
537		return 0;
538
539	mutex_lock(&led_cdev->led_access);
540
541	led_sysfs_disable(led_cdev);
542	led_trigger_remove(led_cdev);
543
544	mutex_unlock(&led_cdev->led_access);
545
546	if (iled_cdev) {
547		led_cdev_ind = &iled_cdev->led_cdev;
548
549		mutex_lock(&led_cdev_ind->led_access);
550
551		led_sysfs_disable(led_cdev_ind);
552		led_trigger_remove(led_cdev_ind);
553
554		mutex_unlock(&led_cdev_ind->led_access);
555	}
556
557	ret = __sync_device_with_v4l2_controls(v4l2_flash);
558	if (ret < 0)
559		goto out_sync_device;
560
561	return 0;
562out_sync_device:
563	mutex_lock(&led_cdev->led_access);
564	led_sysfs_enable(led_cdev);
565	mutex_unlock(&led_cdev->led_access);
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->led_cdev;
581	struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev;
582	int ret = 0;
583
584	if (!v4l2_fh_is_singular(&fh->vfh))
585		return 0;
586
587	mutex_lock(&led_cdev->led_access);
588
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);
593
594	mutex_unlock(&led_cdev->led_access);
595
596	if (iled_cdev) {
597		struct led_classdev *led_cdev_ind = &iled_cdev->led_cdev;
598
599		mutex_lock(&led_cdev_ind->led_access);
600		led_sysfs_enable(led_cdev_ind);
601		mutex_unlock(&led_cdev_ind->led_access);
602	}
603
604	return ret;
605}
606
607static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
608	.open = v4l2_flash_open,
609	.close = v4l2_flash_close,
610};
611
612static const struct v4l2_subdev_core_ops v4l2_flash_core_ops = {
613	.queryctrl = v4l2_subdev_queryctrl,
614	.querymenu = v4l2_subdev_querymenu,
615};
616
617static const struct v4l2_subdev_ops v4l2_flash_subdev_ops = {
618	.core = &v4l2_flash_core_ops,
619};
620
621struct v4l2_flash *v4l2_flash_init(
622	struct device *dev, struct device_node *of_node,
623	struct led_classdev_flash *fled_cdev,
624	struct led_classdev_flash *iled_cdev,
625	const struct v4l2_flash_ops *ops,
626	struct v4l2_flash_config *config)
627{
628	struct v4l2_flash *v4l2_flash;
629	struct led_classdev *led_cdev;
630	struct v4l2_subdev *sd;
631	int ret;
632
633	if (!fled_cdev || !ops || !config)
634		return ERR_PTR(-EINVAL);
635
636	led_cdev = &fled_cdev->led_cdev;
637
638	v4l2_flash = devm_kzalloc(led_cdev->dev, sizeof(*v4l2_flash),
639					GFP_KERNEL);
640	if (!v4l2_flash)
641		return ERR_PTR(-ENOMEM);
642
643	sd = &v4l2_flash->sd;
644	v4l2_flash->fled_cdev = fled_cdev;
645	v4l2_flash->iled_cdev = iled_cdev;
646	v4l2_flash->ops = ops;
647	sd->dev = dev;
648	sd->of_node = of_node;
649	v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
650	sd->internal_ops = &v4l2_flash_subdev_internal_ops;
651	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
652	strlcpy(sd->name, config->dev_name, sizeof(sd->name));
653
654	ret = media_entity_init(&sd->entity, 0, NULL, 0);
655	if (ret < 0)
656		return ERR_PTR(ret);
657
658	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
659
660	ret = v4l2_flash_init_controls(v4l2_flash, config);
661	if (ret < 0)
662		goto err_init_controls;
663
664	if (sd->of_node)
665		of_node_get(sd->of_node);
666	else
667		of_node_get(led_cdev->dev->of_node);
668
669	ret = v4l2_async_register_subdev(sd);
670	if (ret < 0)
671		goto err_async_register_sd;
672
673	return v4l2_flash;
674
675err_async_register_sd:
676	of_node_put(led_cdev->dev->of_node);
677	v4l2_ctrl_handler_free(sd->ctrl_handler);
678err_init_controls:
679	media_entity_cleanup(&sd->entity);
680
681	return ERR_PTR(ret);
682}
683EXPORT_SYMBOL_GPL(v4l2_flash_init);
684
685void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
686{
687	struct v4l2_subdev *sd;
688	struct led_classdev *led_cdev;
689
690	if (IS_ERR_OR_NULL(v4l2_flash))
691		return;
692
693	sd = &v4l2_flash->sd;
694	led_cdev = &v4l2_flash->fled_cdev->led_cdev;
695
696	v4l2_async_unregister_subdev(sd);
697
698	if (sd->of_node)
699		of_node_put(sd->of_node);
700	else
701		of_node_put(led_cdev->dev->of_node);
702
703	v4l2_ctrl_handler_free(sd->ctrl_handler);
704	media_entity_cleanup(&sd->entity);
705}
706EXPORT_SYMBOL_GPL(v4l2_flash_release);
707
708MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
709MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
710MODULE_LICENSE("GPL v2");
711