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