Merge tag 'drm-fixes-2021-05-14' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / drivers / media / v4l2-core / v4l2-flash-led-class.c
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         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
115 static 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
151 static 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
186 static 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
193 static 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
280 static 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
285 static 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
294 static 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
403 static 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
475 error_free_handler:
476         v4l2_ctrl_handler_free(&v4l2_flash->hdl);
477         return ret;
478 }
479
480 static 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
526 static 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;
560 out_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
576 static 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
608 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
609         .open = v4l2_flash_open,
610         .close = v4l2_flash_close,
611 };
612
613 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops;
614
615 static 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
660 err_async_register_sd:
661         fwnode_handle_put(sd->fwnode);
662         v4l2_ctrl_handler_free(sd->ctrl_handler);
663 err_init_controls:
664         media_entity_cleanup(&sd->entity);
665
666         return ERR_PTR(ret);
667 }
668
669 struct 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 }
677 EXPORT_SYMBOL_GPL(v4l2_flash_init);
678
679 struct 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 }
686 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init);
687
688 void 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 }
704 EXPORT_SYMBOL_GPL(v4l2_flash_release);
705
706 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
707 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
708 MODULE_LICENSE("GPL v2");