0001
0002
0003
0004
0005
0006
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
0034
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
0051
0052
0053
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
0066
0067
0068
0069
0070
0071
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
0094
0095
0096
0097
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
0132
0133
0134
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
0188
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
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
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
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
0272
0273
0274
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
0292
0293
0294 return led_set_flash_timeout(fled_cdev, c->val);
0295 case V4L2_CID_FLASH_INTENSITY:
0296
0297
0298
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
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
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
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
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
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
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
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
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
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
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
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
0548
0549
0550
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
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");