Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * V4L2 flash LED sub-device registration helpers.
0004  *
0005  *  Copyright (C) 2015 Samsung Electronics Co., Ltd
0006  *  Author: Jacek Anaszewski <j.anaszewski@samsung.com>
0007  */
0008 
0009 #include <linux/led-class-flash.h>
0010 #include <linux/module.h>
0011 #include <linux/mutex.h>
0012 #include <linux/property.h>
0013 #include <linux/slab.h>
0014 #include <linux/types.h>
0015 #include <media/v4l2-flash-led-class.h>
0016 
0017 #define has_flash_op(v4l2_flash, op)                \
0018     (v4l2_flash && v4l2_flash->ops && v4l2_flash->ops->op)
0019 
0020 #define call_flash_op(v4l2_flash, op, arg)          \
0021         (has_flash_op(v4l2_flash, op) ?         \
0022             v4l2_flash->ops->op(v4l2_flash, arg) :  \
0023             -EINVAL)
0024 
0025 enum ctrl_init_data_id {
0026     LED_MODE,
0027     TORCH_INTENSITY,
0028     FLASH_INTENSITY,
0029     INDICATOR_INTENSITY,
0030     FLASH_TIMEOUT,
0031     STROBE_SOURCE,
0032     /*
0033      * Only above values are applicable to
0034      * the 'ctrls' array in the struct v4l2_flash.
0035      */
0036     FLASH_STROBE,
0037     STROBE_STOP,
0038     STROBE_STATUS,
0039     FLASH_FAULT,
0040     NUM_FLASH_CTRLS,
0041 };
0042 
0043 static enum led_brightness __intensity_to_led_brightness(
0044                     struct v4l2_ctrl *ctrl, s32 intensity)
0045 {
0046     intensity -= ctrl->minimum;
0047     intensity /= (u32) ctrl->step;
0048 
0049     /*
0050      * Indicator LEDs, unlike torch LEDs, are turned on/off basing on
0051      * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
0052      * Therefore it must be possible to set it to 0 level which in
0053      * the LED subsystem reflects LED_OFF state.
0054      */
0055     if (ctrl->minimum)
0056         ++intensity;
0057 
0058     return intensity;
0059 }
0060 
0061 static s32 __led_brightness_to_intensity(struct v4l2_ctrl *ctrl,
0062                      enum led_brightness brightness)
0063 {
0064     /*
0065      * Indicator LEDs, unlike torch LEDs, are turned on/off basing on
0066      * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
0067      * Do not decrement brightness read from the LED subsystem for
0068      * indicator LED as it may equal 0. For torch LEDs this function
0069      * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
0070      * brightness read is guaranteed to be greater than 0. In the mode
0071      * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used.
0072      */
0073     if (ctrl->id != V4L2_CID_FLASH_INDICATOR_INTENSITY)
0074         --brightness;
0075 
0076     return (brightness * ctrl->step) + ctrl->minimum;
0077 }
0078 
0079 static int v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
0080                      struct v4l2_ctrl *ctrl)
0081 {
0082     struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
0083     struct led_classdev *led_cdev;
0084     enum led_brightness brightness;
0085 
0086     if (has_flash_op(v4l2_flash, intensity_to_led_brightness))
0087         brightness = call_flash_op(v4l2_flash,
0088                     intensity_to_led_brightness,
0089                     ctrl->val);
0090     else
0091         brightness = __intensity_to_led_brightness(ctrl, ctrl->val);
0092     /*
0093      * In case a LED Flash class driver provides ops for custom
0094      * brightness <-> intensity conversion, it also must have defined
0095      * related v4l2 control step == 1. In such a case a backward conversion
0096      * from led brightness to v4l2 intensity is required to find out the
0097      * the aligned intensity value.
0098      */
0099     if (has_flash_op(v4l2_flash, led_brightness_to_intensity))
0100         ctrl->val = call_flash_op(v4l2_flash,
0101                     led_brightness_to_intensity,
0102                     brightness);
0103 
0104     if (ctrl == ctrls[TORCH_INTENSITY]) {
0105         if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
0106             return 0;
0107 
0108         if (WARN_ON_ONCE(!v4l2_flash->fled_cdev))
0109             return -EINVAL;
0110 
0111         led_cdev = &v4l2_flash->fled_cdev->led_cdev;
0112     } else {
0113         if (WARN_ON_ONCE(!v4l2_flash->iled_cdev))
0114             return -EINVAL;
0115 
0116         led_cdev = v4l2_flash->iled_cdev;
0117     }
0118 
0119     return led_set_brightness_sync(led_cdev, brightness);
0120 }
0121 
0122 static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash,
0123                     struct v4l2_ctrl *ctrl)
0124 {
0125     struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
0126     struct led_classdev *led_cdev;
0127     int ret;
0128 
0129     if (ctrl == ctrls[TORCH_INTENSITY]) {
0130         /*
0131          * Update torch brightness only if in TORCH_MODE. In other modes
0132          * torch led is turned off, which would spuriously inform the
0133          * user space that V4L2_CID_FLASH_TORCH_INTENSITY control value
0134          * has changed to 0.
0135          */
0136         if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
0137             return 0;
0138 
0139         if (WARN_ON_ONCE(!v4l2_flash->fled_cdev))
0140             return -EINVAL;
0141 
0142         led_cdev = &v4l2_flash->fled_cdev->led_cdev;
0143     } else {
0144         if (WARN_ON_ONCE(!v4l2_flash->iled_cdev))
0145             return -EINVAL;
0146 
0147         led_cdev = v4l2_flash->iled_cdev;
0148     }
0149 
0150     ret = led_update_brightness(led_cdev);
0151     if (ret < 0)
0152         return ret;
0153 
0154     if (has_flash_op(v4l2_flash, led_brightness_to_intensity))
0155         ctrl->val = call_flash_op(v4l2_flash,
0156                         led_brightness_to_intensity,
0157                         led_cdev->brightness);
0158     else
0159         ctrl->val = __led_brightness_to_intensity(ctrl,
0160                         led_cdev->brightness);
0161 
0162     return 0;
0163 }
0164 
0165 static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
0166 {
0167     struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
0168     struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
0169     bool is_strobing;
0170     int ret;
0171 
0172     switch (c->id) {
0173     case V4L2_CID_FLASH_TORCH_INTENSITY:
0174     case V4L2_CID_FLASH_INDICATOR_INTENSITY:
0175         return v4l2_flash_update_led_brightness(v4l2_flash, c);
0176     }
0177 
0178     if (!fled_cdev)
0179         return -EINVAL;
0180 
0181     switch (c->id) {
0182     case V4L2_CID_FLASH_INTENSITY:
0183         ret = led_update_flash_brightness(fled_cdev);
0184         if (ret < 0)
0185             return ret;
0186         /*
0187          * No conversion is needed as LED Flash class also uses
0188          * microamperes for flash intensity units.
0189          */
0190         c->val = fled_cdev->brightness.val;
0191         return 0;
0192     case V4L2_CID_FLASH_STROBE_STATUS:
0193         ret = led_get_flash_strobe(fled_cdev, &is_strobing);
0194         if (ret < 0)
0195             return ret;
0196         c->val = is_strobing;
0197         return 0;
0198     case V4L2_CID_FLASH_FAULT:
0199         /* LED faults map directly to V4L2 flash faults */
0200         return led_get_flash_fault(fled_cdev, &c->val);
0201     default:
0202         return -EINVAL;
0203     }
0204 }
0205 
0206 static bool __software_strobe_mode_inactive(struct v4l2_ctrl **ctrls)
0207 {
0208     return ((ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH) ||
0209         (ctrls[STROBE_SOURCE] && (ctrls[STROBE_SOURCE]->val !=
0210                 V4L2_FLASH_STROBE_SOURCE_SOFTWARE)));
0211 }
0212 
0213 static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
0214 {
0215     struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
0216     struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
0217     struct led_classdev *led_cdev;
0218     struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
0219     bool external_strobe;
0220     int ret = 0;
0221 
0222     switch (c->id) {
0223     case V4L2_CID_FLASH_TORCH_INTENSITY:
0224     case V4L2_CID_FLASH_INDICATOR_INTENSITY:
0225         return v4l2_flash_set_led_brightness(v4l2_flash, c);
0226     }
0227 
0228     if (!fled_cdev)
0229         return -EINVAL;
0230 
0231     led_cdev = &fled_cdev->led_cdev;
0232 
0233     switch (c->id) {
0234     case V4L2_CID_FLASH_LED_MODE:
0235         switch (c->val) {
0236         case V4L2_FLASH_LED_MODE_NONE:
0237             led_set_brightness_sync(led_cdev, LED_OFF);
0238             return led_set_flash_strobe(fled_cdev, false);
0239         case V4L2_FLASH_LED_MODE_FLASH:
0240             /* Turn the torch LED off */
0241             led_set_brightness_sync(led_cdev, LED_OFF);
0242             if (ctrls[STROBE_SOURCE]) {
0243                 external_strobe = (ctrls[STROBE_SOURCE]->val ==
0244                     V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
0245 
0246                 ret = call_flash_op(v4l2_flash,
0247                         external_strobe_set,
0248                         external_strobe);
0249             }
0250             return ret;
0251         case V4L2_FLASH_LED_MODE_TORCH:
0252             if (ctrls[STROBE_SOURCE]) {
0253                 ret = call_flash_op(v4l2_flash,
0254                         external_strobe_set,
0255                         false);
0256                 if (ret < 0)
0257                     return ret;
0258             }
0259             /* Stop flash strobing */
0260             ret = led_set_flash_strobe(fled_cdev, false);
0261             if (ret < 0)
0262                 return ret;
0263 
0264             return v4l2_flash_set_led_brightness(v4l2_flash,
0265                                  ctrls[TORCH_INTENSITY]);
0266         }
0267         break;
0268     case V4L2_CID_FLASH_STROBE_SOURCE:
0269         external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
0270         /*
0271          * For some hardware arrangements setting strobe source may
0272          * affect torch mode. Therefore, if not in the flash mode,
0273          * cache only this setting. It will be applied upon switching
0274          * to flash mode.
0275          */
0276         if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH)
0277             return 0;
0278 
0279         return call_flash_op(v4l2_flash, external_strobe_set,
0280                     external_strobe);
0281     case V4L2_CID_FLASH_STROBE:
0282         if (__software_strobe_mode_inactive(ctrls))
0283             return -EBUSY;
0284         return led_set_flash_strobe(fled_cdev, true);
0285     case V4L2_CID_FLASH_STROBE_STOP:
0286         if (__software_strobe_mode_inactive(ctrls))
0287             return -EBUSY;
0288         return led_set_flash_strobe(fled_cdev, false);
0289     case V4L2_CID_FLASH_TIMEOUT:
0290         /*
0291          * No conversion is needed as LED Flash class also uses
0292          * microseconds for flash timeout units.
0293          */
0294         return led_set_flash_timeout(fled_cdev, c->val);
0295     case V4L2_CID_FLASH_INTENSITY:
0296         /*
0297          * No conversion is needed as LED Flash class also uses
0298          * microamperes for flash intensity units.
0299          */
0300         return led_set_flash_brightness(fled_cdev, c->val);
0301     }
0302 
0303     return -EINVAL;
0304 }
0305 
0306 static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = {
0307     .g_volatile_ctrl = v4l2_flash_g_volatile_ctrl,
0308     .s_ctrl = v4l2_flash_s_ctrl,
0309 };
0310 
0311 static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting *s,
0312                 struct v4l2_ctrl_config *c)
0313 {
0314     c->min = s->min;
0315     c->max = s->max;
0316     c->step = s->step;
0317     c->def = s->val;
0318 }
0319 
0320 static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
0321               struct v4l2_flash_config *flash_cfg,
0322               struct v4l2_flash_ctrl_data *ctrl_init_data)
0323 {
0324     struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
0325     struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
0326     struct v4l2_ctrl_config *ctrl_cfg;
0327     u32 mask;
0328 
0329     /* Init INDICATOR_INTENSITY ctrl data */
0330     if (v4l2_flash->iled_cdev) {
0331         ctrl_init_data[INDICATOR_INTENSITY].cid =
0332                     V4L2_CID_FLASH_INDICATOR_INTENSITY;
0333         ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
0334         __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity,
0335                       ctrl_cfg);
0336         ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
0337         ctrl_cfg->min = 0;
0338         ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
0339                   V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
0340     }
0341 
0342     if (!led_cdev || WARN_ON(!(led_cdev->flags & LED_DEV_CAP_FLASH)))
0343         return;
0344 
0345     /* Init FLASH_FAULT ctrl data */
0346     if (flash_cfg->flash_faults) {
0347         ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT;
0348         ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config;
0349         ctrl_cfg->id = V4L2_CID_FLASH_FAULT;
0350         ctrl_cfg->max = flash_cfg->flash_faults;
0351         ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
0352                   V4L2_CTRL_FLAG_READ_ONLY;
0353     }
0354 
0355     /* Init FLASH_LED_MODE ctrl data */
0356     mask = 1 << V4L2_FLASH_LED_MODE_NONE |
0357            1 << V4L2_FLASH_LED_MODE_TORCH;
0358     if (led_cdev->flags & LED_DEV_CAP_FLASH)
0359         mask |= 1 << V4L2_FLASH_LED_MODE_FLASH;
0360 
0361     ctrl_init_data[LED_MODE].cid = V4L2_CID_FLASH_LED_MODE;
0362     ctrl_cfg = &ctrl_init_data[LED_MODE].config;
0363     ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE;
0364     ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH;
0365     ctrl_cfg->menu_skip_mask = ~mask;
0366     ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE;
0367     ctrl_cfg->flags = 0;
0368 
0369     /* Init TORCH_INTENSITY ctrl data */
0370     ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY;
0371     ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
0372     __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, ctrl_cfg);
0373     ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
0374     ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
0375               V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
0376 
0377     /* Init FLASH_STROBE ctrl data */
0378     ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE;
0379     ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
0380     ctrl_cfg->id = V4L2_CID_FLASH_STROBE;
0381 
0382     /* Init STROBE_STOP ctrl data */
0383     ctrl_init_data[STROBE_STOP].cid = V4L2_CID_FLASH_STROBE_STOP;
0384     ctrl_cfg = &ctrl_init_data[STROBE_STOP].config;
0385     ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP;
0386 
0387     /* Init FLASH_STROBE_SOURCE ctrl data */
0388     if (flash_cfg->has_external_strobe) {
0389         mask = (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE) |
0390                (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
0391         ctrl_init_data[STROBE_SOURCE].cid =
0392                     V4L2_CID_FLASH_STROBE_SOURCE;
0393         ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config;
0394         ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE;
0395         ctrl_cfg->max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
0396         ctrl_cfg->menu_skip_mask = ~mask;
0397         ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
0398     }
0399 
0400     /* Init STROBE_STATUS ctrl data */
0401     if (has_flash_op(fled_cdev, strobe_get)) {
0402         ctrl_init_data[STROBE_STATUS].cid =
0403                     V4L2_CID_FLASH_STROBE_STATUS;
0404         ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config;
0405         ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS;
0406         ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
0407                   V4L2_CTRL_FLAG_READ_ONLY;
0408     }
0409 
0410     /* Init FLASH_TIMEOUT ctrl data */
0411     if (has_flash_op(fled_cdev, timeout_set)) {
0412         ctrl_init_data[FLASH_TIMEOUT].cid = V4L2_CID_FLASH_TIMEOUT;
0413         ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config;
0414         __lfs_to_v4l2_ctrl_config(&fled_cdev->timeout, ctrl_cfg);
0415         ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT;
0416     }
0417 
0418     /* Init FLASH_INTENSITY ctrl data */
0419     if (has_flash_op(fled_cdev, flash_brightness_set)) {
0420         ctrl_init_data[FLASH_INTENSITY].cid = V4L2_CID_FLASH_INTENSITY;
0421         ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config;
0422         __lfs_to_v4l2_ctrl_config(&fled_cdev->brightness, ctrl_cfg);
0423         ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY;
0424         ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
0425                   V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
0426     }
0427 }
0428 
0429 static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash,
0430                 struct v4l2_flash_config *flash_cfg)
0431 
0432 {
0433     struct v4l2_flash_ctrl_data *ctrl_init_data;
0434     struct v4l2_ctrl *ctrl;
0435     struct v4l2_ctrl_config *ctrl_cfg;
0436     int i, ret, num_ctrls = 0;
0437 
0438     v4l2_flash->ctrls = devm_kcalloc(v4l2_flash->sd.dev,
0439                     STROBE_SOURCE + 1,
0440                     sizeof(*v4l2_flash->ctrls),
0441                     GFP_KERNEL);
0442     if (!v4l2_flash->ctrls)
0443         return -ENOMEM;
0444 
0445     /* allocate memory dynamically so as not to exceed stack frame size */
0446     ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data),
0447                     GFP_KERNEL);
0448     if (!ctrl_init_data)
0449         return -ENOMEM;
0450 
0451     __fill_ctrl_init_data(v4l2_flash, flash_cfg, ctrl_init_data);
0452 
0453     for (i = 0; i < NUM_FLASH_CTRLS; ++i)
0454         if (ctrl_init_data[i].cid)
0455             ++num_ctrls;
0456 
0457     v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
0458 
0459     for (i = 0; i < NUM_FLASH_CTRLS; ++i) {
0460         ctrl_cfg = &ctrl_init_data[i].config;
0461         if (!ctrl_init_data[i].cid)
0462             continue;
0463 
0464         if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE ||
0465             ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE)
0466             ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl,
0467                         &v4l2_flash_ctrl_ops,
0468                         ctrl_cfg->id,
0469                         ctrl_cfg->max,
0470                         ctrl_cfg->menu_skip_mask,
0471                         ctrl_cfg->def);
0472         else
0473             ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
0474                         &v4l2_flash_ctrl_ops,
0475                         ctrl_cfg->id,
0476                         ctrl_cfg->min,
0477                         ctrl_cfg->max,
0478                         ctrl_cfg->step,
0479                         ctrl_cfg->def);
0480 
0481         if (ctrl)
0482             ctrl->flags |= ctrl_cfg->flags;
0483 
0484         if (i <= STROBE_SOURCE)
0485             v4l2_flash->ctrls[i] = ctrl;
0486     }
0487 
0488     kfree(ctrl_init_data);
0489 
0490     if (v4l2_flash->hdl.error) {
0491         ret = v4l2_flash->hdl.error;
0492         goto error_free_handler;
0493     }
0494 
0495     v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
0496 
0497     v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl;
0498 
0499     return 0;
0500 
0501 error_free_handler:
0502     v4l2_ctrl_handler_free(&v4l2_flash->hdl);
0503     return ret;
0504 }
0505 
0506 static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash)
0507 {
0508     struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
0509     struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
0510     int ret = 0;
0511 
0512     if (ctrls[TORCH_INTENSITY]) {
0513         ret = v4l2_flash_set_led_brightness(v4l2_flash,
0514                             ctrls[TORCH_INTENSITY]);
0515         if (ret < 0)
0516             return ret;
0517     }
0518 
0519     if (ctrls[INDICATOR_INTENSITY]) {
0520         ret = v4l2_flash_set_led_brightness(v4l2_flash,
0521                             ctrls[INDICATOR_INTENSITY]);
0522         if (ret < 0)
0523             return ret;
0524     }
0525 
0526     if (ctrls[FLASH_TIMEOUT]) {
0527         if (WARN_ON_ONCE(!fled_cdev))
0528             return -EINVAL;
0529 
0530         ret = led_set_flash_timeout(fled_cdev,
0531                     ctrls[FLASH_TIMEOUT]->val);
0532         if (ret < 0)
0533             return ret;
0534     }
0535 
0536     if (ctrls[FLASH_INTENSITY]) {
0537         if (WARN_ON_ONCE(!fled_cdev))
0538             return -EINVAL;
0539 
0540         ret = led_set_flash_brightness(fled_cdev,
0541                     ctrls[FLASH_INTENSITY]->val);
0542         if (ret < 0)
0543             return ret;
0544     }
0545 
0546     /*
0547      * For some hardware arrangements setting strobe source may affect
0548      * torch mode. Synchronize strobe source setting only if not in torch
0549      * mode. For torch mode case it will get synchronized upon switching
0550      * to flash mode.
0551      */
0552     if (ctrls[STROBE_SOURCE] &&
0553         ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
0554         ret = call_flash_op(v4l2_flash, external_strobe_set,
0555                     ctrls[STROBE_SOURCE]->val);
0556 
0557     return ret;
0558 }
0559 
0560 /*
0561  * V4L2 subdev internal operations
0562  */
0563 
0564 static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
0565 {
0566     struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
0567     struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
0568     struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
0569     struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
0570     int ret = 0;
0571 
0572     if (!v4l2_fh_is_singular(&fh->vfh))
0573         return 0;
0574 
0575     if (led_cdev) {
0576         mutex_lock(&led_cdev->led_access);
0577 
0578         led_sysfs_disable(led_cdev);
0579         led_trigger_remove(led_cdev);
0580 
0581         mutex_unlock(&led_cdev->led_access);
0582     }
0583 
0584     if (led_cdev_ind) {
0585         mutex_lock(&led_cdev_ind->led_access);
0586 
0587         led_sysfs_disable(led_cdev_ind);
0588         led_trigger_remove(led_cdev_ind);
0589 
0590         mutex_unlock(&led_cdev_ind->led_access);
0591     }
0592 
0593     ret = __sync_device_with_v4l2_controls(v4l2_flash);
0594     if (ret < 0)
0595         goto out_sync_device;
0596 
0597     return 0;
0598 out_sync_device:
0599     if (led_cdev) {
0600         mutex_lock(&led_cdev->led_access);
0601         led_sysfs_enable(led_cdev);
0602         mutex_unlock(&led_cdev->led_access);
0603     }
0604 
0605     if (led_cdev_ind) {
0606         mutex_lock(&led_cdev_ind->led_access);
0607         led_sysfs_enable(led_cdev_ind);
0608         mutex_unlock(&led_cdev_ind->led_access);
0609     }
0610 
0611     return ret;
0612 }
0613 
0614 static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
0615 {
0616     struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
0617     struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
0618     struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
0619     struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
0620     int ret = 0;
0621 
0622     if (!v4l2_fh_is_singular(&fh->vfh))
0623         return 0;
0624 
0625     if (led_cdev) {
0626         mutex_lock(&led_cdev->led_access);
0627 
0628         if (v4l2_flash->ctrls[STROBE_SOURCE])
0629             ret = v4l2_ctrl_s_ctrl(
0630                 v4l2_flash->ctrls[STROBE_SOURCE],
0631                 V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
0632         led_sysfs_enable(led_cdev);
0633 
0634         mutex_unlock(&led_cdev->led_access);
0635     }
0636 
0637     if (led_cdev_ind) {
0638         mutex_lock(&led_cdev_ind->led_access);
0639         led_sysfs_enable(led_cdev_ind);
0640         mutex_unlock(&led_cdev_ind->led_access);
0641     }
0642 
0643     return ret;
0644 }
0645 
0646 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
0647     .open = v4l2_flash_open,
0648     .close = v4l2_flash_close,
0649 };
0650 
0651 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops;
0652 
0653 static struct v4l2_flash *__v4l2_flash_init(
0654     struct device *dev, struct fwnode_handle *fwn,
0655     struct led_classdev_flash *fled_cdev, struct led_classdev *iled_cdev,
0656     const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config)
0657 {
0658     struct v4l2_flash *v4l2_flash;
0659     struct v4l2_subdev *sd;
0660     int ret;
0661 
0662     if (!config)
0663         return ERR_PTR(-EINVAL);
0664 
0665     v4l2_flash = devm_kzalloc(dev, sizeof(*v4l2_flash), GFP_KERNEL);
0666     if (!v4l2_flash)
0667         return ERR_PTR(-ENOMEM);
0668 
0669     sd = &v4l2_flash->sd;
0670     v4l2_flash->fled_cdev = fled_cdev;
0671     v4l2_flash->iled_cdev = iled_cdev;
0672     v4l2_flash->ops = ops;
0673     sd->dev = dev;
0674     sd->fwnode = fwn ? fwn : dev_fwnode(dev);
0675     v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
0676     sd->internal_ops = &v4l2_flash_subdev_internal_ops;
0677     sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
0678     strscpy(sd->name, config->dev_name, sizeof(sd->name));
0679 
0680     ret = media_entity_pads_init(&sd->entity, 0, NULL);
0681     if (ret < 0)
0682         return ERR_PTR(ret);
0683 
0684     sd->entity.function = MEDIA_ENT_F_FLASH;
0685 
0686     ret = v4l2_flash_init_controls(v4l2_flash, config);
0687     if (ret < 0)
0688         goto err_init_controls;
0689 
0690     fwnode_handle_get(sd->fwnode);
0691 
0692     ret = v4l2_async_register_subdev(sd);
0693     if (ret < 0)
0694         goto err_async_register_sd;
0695 
0696     return v4l2_flash;
0697 
0698 err_async_register_sd:
0699     fwnode_handle_put(sd->fwnode);
0700     v4l2_ctrl_handler_free(sd->ctrl_handler);
0701 err_init_controls:
0702     media_entity_cleanup(&sd->entity);
0703 
0704     return ERR_PTR(ret);
0705 }
0706 
0707 struct v4l2_flash *v4l2_flash_init(
0708     struct device *dev, struct fwnode_handle *fwn,
0709     struct led_classdev_flash *fled_cdev,
0710     const struct v4l2_flash_ops *ops,
0711     struct v4l2_flash_config *config)
0712 {
0713     return __v4l2_flash_init(dev, fwn, fled_cdev, NULL, ops, config);
0714 }
0715 EXPORT_SYMBOL_GPL(v4l2_flash_init);
0716 
0717 struct v4l2_flash *v4l2_flash_indicator_init(
0718     struct device *dev, struct fwnode_handle *fwn,
0719     struct led_classdev *iled_cdev,
0720     struct v4l2_flash_config *config)
0721 {
0722     return __v4l2_flash_init(dev, fwn, NULL, iled_cdev, NULL, config);
0723 }
0724 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init);
0725 
0726 void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
0727 {
0728     struct v4l2_subdev *sd;
0729 
0730     if (IS_ERR_OR_NULL(v4l2_flash))
0731         return;
0732 
0733     sd = &v4l2_flash->sd;
0734 
0735     v4l2_async_unregister_subdev(sd);
0736 
0737     fwnode_handle_put(sd->fwnode);
0738 
0739     v4l2_ctrl_handler_free(sd->ctrl_handler);
0740     media_entity_cleanup(&sd->entity);
0741 }
0742 EXPORT_SYMBOL_GPL(v4l2_flash_release);
0743 
0744 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
0745 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
0746 MODULE_LICENSE("GPL v2");