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 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; 107 108 if (WARN_ON_ONCE(!v4l2_flash->fled_cdev)) 109 return; 110 111 led_cdev = &v4l2_flash->fled_cdev->led_cdev; 112 } else { 113 if (WARN_ON_ONCE(!v4l2_flash->iled_cdev)) 114 return; 115 116 led_cdev = v4l2_flash->iled_cdev; 117 } 118 119 led_set_brightness_sync(led_cdev, brightness); 120 } 121 122 static 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 165 static 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 206 static 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 213 static 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 v4l2_flash_set_led_brightness(v4l2_flash, c); 226 return 0; 227 } 228 229 if (!fled_cdev) 230 return -EINVAL; 231 232 led_cdev = &fled_cdev->led_cdev; 233 234 switch (c->id) { 235 case V4L2_CID_FLASH_LED_MODE: 236 switch (c->val) { 237 case V4L2_FLASH_LED_MODE_NONE: 238 led_set_brightness_sync(led_cdev, LED_OFF); 239 return led_set_flash_strobe(fled_cdev, false); 240 case V4L2_FLASH_LED_MODE_FLASH: 241 /* Turn the torch LED off */ 242 led_set_brightness_sync(led_cdev, LED_OFF); 243 if (ctrls[STROBE_SOURCE]) { 244 external_strobe = (ctrls[STROBE_SOURCE]->val == 245 V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 246 247 ret = call_flash_op(v4l2_flash, 248 external_strobe_set, 249 external_strobe); 250 } 251 return ret; 252 case V4L2_FLASH_LED_MODE_TORCH: 253 if (ctrls[STROBE_SOURCE]) { 254 ret = call_flash_op(v4l2_flash, 255 external_strobe_set, 256 false); 257 if (ret < 0) 258 return ret; 259 } 260 /* Stop flash strobing */ 261 ret = led_set_flash_strobe(fled_cdev, false); 262 if (ret < 0) 263 return ret; 264 265 v4l2_flash_set_led_brightness(v4l2_flash, 266 ctrls[TORCH_INTENSITY]); 267 return 0; 268 } 269 break; 270 case V4L2_CID_FLASH_STROBE_SOURCE: 271 external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 272 /* 273 * For some hardware arrangements setting strobe source may 274 * affect torch mode. Therefore, if not in the flash mode, 275 * cache only this setting. It will be applied upon switching 276 * to flash mode. 277 */ 278 if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH) 279 return 0; 280 281 return call_flash_op(v4l2_flash, external_strobe_set, 282 external_strobe); 283 case V4L2_CID_FLASH_STROBE: 284 if (__software_strobe_mode_inactive(ctrls)) 285 return -EBUSY; 286 return led_set_flash_strobe(fled_cdev, true); 287 case V4L2_CID_FLASH_STROBE_STOP: 288 if (__software_strobe_mode_inactive(ctrls)) 289 return -EBUSY; 290 return led_set_flash_strobe(fled_cdev, false); 291 case V4L2_CID_FLASH_TIMEOUT: 292 /* 293 * No conversion is needed as LED Flash class also uses 294 * microseconds for flash timeout units. 295 */ 296 return led_set_flash_timeout(fled_cdev, c->val); 297 case V4L2_CID_FLASH_INTENSITY: 298 /* 299 * No conversion is needed as LED Flash class also uses 300 * microamperes for flash intensity units. 301 */ 302 return led_set_flash_brightness(fled_cdev, c->val); 303 } 304 305 return -EINVAL; 306 } 307 308 static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = { 309 .g_volatile_ctrl = v4l2_flash_g_volatile_ctrl, 310 .s_ctrl = v4l2_flash_s_ctrl, 311 }; 312 313 static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting *s, 314 struct v4l2_ctrl_config *c) 315 { 316 c->min = s->min; 317 c->max = s->max; 318 c->step = s->step; 319 c->def = s->val; 320 } 321 322 static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, 323 struct v4l2_flash_config *flash_cfg, 324 struct v4l2_flash_ctrl_data *ctrl_init_data) 325 { 326 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 327 struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; 328 struct v4l2_ctrl_config *ctrl_cfg; 329 u32 mask; 330 331 /* Init INDICATOR_INTENSITY ctrl data */ 332 if (v4l2_flash->iled_cdev) { 333 ctrl_init_data[INDICATOR_INTENSITY].cid = 334 V4L2_CID_FLASH_INDICATOR_INTENSITY; 335 ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config; 336 __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, 337 ctrl_cfg); 338 ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY; 339 ctrl_cfg->min = 0; 340 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 341 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 342 } 343 344 if (!led_cdev || WARN_ON(!(led_cdev->flags & LED_DEV_CAP_FLASH))) 345 return; 346 347 /* Init FLASH_FAULT ctrl data */ 348 if (flash_cfg->flash_faults) { 349 ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT; 350 ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config; 351 ctrl_cfg->id = V4L2_CID_FLASH_FAULT; 352 ctrl_cfg->max = flash_cfg->flash_faults; 353 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 354 V4L2_CTRL_FLAG_READ_ONLY; 355 } 356 357 /* Init FLASH_LED_MODE ctrl data */ 358 mask = 1 << V4L2_FLASH_LED_MODE_NONE | 359 1 << V4L2_FLASH_LED_MODE_TORCH; 360 if (led_cdev->flags & LED_DEV_CAP_FLASH) 361 mask |= 1 << V4L2_FLASH_LED_MODE_FLASH; 362 363 ctrl_init_data[LED_MODE].cid = V4L2_CID_FLASH_LED_MODE; 364 ctrl_cfg = &ctrl_init_data[LED_MODE].config; 365 ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE; 366 ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH; 367 ctrl_cfg->menu_skip_mask = ~mask; 368 ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE; 369 ctrl_cfg->flags = 0; 370 371 /* Init TORCH_INTENSITY ctrl data */ 372 ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY; 373 ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config; 374 __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, ctrl_cfg); 375 ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY; 376 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 377 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 378 379 /* Init FLASH_STROBE ctrl data */ 380 ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE; 381 ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config; 382 ctrl_cfg->id = V4L2_CID_FLASH_STROBE; 383 384 /* Init STROBE_STOP ctrl data */ 385 ctrl_init_data[STROBE_STOP].cid = V4L2_CID_FLASH_STROBE_STOP; 386 ctrl_cfg = &ctrl_init_data[STROBE_STOP].config; 387 ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP; 388 389 /* Init FLASH_STROBE_SOURCE ctrl data */ 390 if (flash_cfg->has_external_strobe) { 391 mask = (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE) | 392 (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 393 ctrl_init_data[STROBE_SOURCE].cid = 394 V4L2_CID_FLASH_STROBE_SOURCE; 395 ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config; 396 ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE; 397 ctrl_cfg->max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; 398 ctrl_cfg->menu_skip_mask = ~mask; 399 ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; 400 } 401 402 /* Init STROBE_STATUS ctrl data */ 403 if (has_flash_op(fled_cdev, strobe_get)) { 404 ctrl_init_data[STROBE_STATUS].cid = 405 V4L2_CID_FLASH_STROBE_STATUS; 406 ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config; 407 ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS; 408 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 409 V4L2_CTRL_FLAG_READ_ONLY; 410 } 411 412 /* Init FLASH_TIMEOUT ctrl data */ 413 if (has_flash_op(fled_cdev, timeout_set)) { 414 ctrl_init_data[FLASH_TIMEOUT].cid = V4L2_CID_FLASH_TIMEOUT; 415 ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config; 416 __lfs_to_v4l2_ctrl_config(&fled_cdev->timeout, ctrl_cfg); 417 ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT; 418 } 419 420 /* Init FLASH_INTENSITY ctrl data */ 421 if (has_flash_op(fled_cdev, flash_brightness_set)) { 422 ctrl_init_data[FLASH_INTENSITY].cid = V4L2_CID_FLASH_INTENSITY; 423 ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config; 424 __lfs_to_v4l2_ctrl_config(&fled_cdev->brightness, ctrl_cfg); 425 ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY; 426 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 427 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 428 } 429 } 430 431 static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash, 432 struct v4l2_flash_config *flash_cfg) 433 434 { 435 struct v4l2_flash_ctrl_data *ctrl_init_data; 436 struct v4l2_ctrl *ctrl; 437 struct v4l2_ctrl_config *ctrl_cfg; 438 int i, ret, num_ctrls = 0; 439 440 v4l2_flash->ctrls = devm_kcalloc(v4l2_flash->sd.dev, 441 STROBE_SOURCE + 1, 442 sizeof(*v4l2_flash->ctrls), 443 GFP_KERNEL); 444 if (!v4l2_flash->ctrls) 445 return -ENOMEM; 446 447 /* allocate memory dynamically so as not to exceed stack frame size */ 448 ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data), 449 GFP_KERNEL); 450 if (!ctrl_init_data) 451 return -ENOMEM; 452 453 __fill_ctrl_init_data(v4l2_flash, flash_cfg, ctrl_init_data); 454 455 for (i = 0; i < NUM_FLASH_CTRLS; ++i) 456 if (ctrl_init_data[i].cid) 457 ++num_ctrls; 458 459 v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls); 460 461 for (i = 0; i < NUM_FLASH_CTRLS; ++i) { 462 ctrl_cfg = &ctrl_init_data[i].config; 463 if (!ctrl_init_data[i].cid) 464 continue; 465 466 if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE || 467 ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE) 468 ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl, 469 &v4l2_flash_ctrl_ops, 470 ctrl_cfg->id, 471 ctrl_cfg->max, 472 ctrl_cfg->menu_skip_mask, 473 ctrl_cfg->def); 474 else 475 ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, 476 &v4l2_flash_ctrl_ops, 477 ctrl_cfg->id, 478 ctrl_cfg->min, 479 ctrl_cfg->max, 480 ctrl_cfg->step, 481 ctrl_cfg->def); 482 483 if (ctrl) 484 ctrl->flags |= ctrl_cfg->flags; 485 486 if (i <= STROBE_SOURCE) 487 v4l2_flash->ctrls[i] = ctrl; 488 } 489 490 kfree(ctrl_init_data); 491 492 if (v4l2_flash->hdl.error) { 493 ret = v4l2_flash->hdl.error; 494 goto error_free_handler; 495 } 496 497 v4l2_ctrl_handler_setup(&v4l2_flash->hdl); 498 499 v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl; 500 501 return 0; 502 503 error_free_handler: 504 v4l2_ctrl_handler_free(&v4l2_flash->hdl); 505 return ret; 506 } 507 508 static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) 509 { 510 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 511 struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; 512 int ret = 0; 513 514 if (ctrls[TORCH_INTENSITY]) 515 v4l2_flash_set_led_brightness(v4l2_flash, 516 ctrls[TORCH_INTENSITY]); 517 518 if (ctrls[INDICATOR_INTENSITY]) 519 v4l2_flash_set_led_brightness(v4l2_flash, 520 ctrls[INDICATOR_INTENSITY]); 521 522 if (ctrls[FLASH_TIMEOUT]) { 523 if (WARN_ON_ONCE(!fled_cdev)) 524 return -EINVAL; 525 526 ret = led_set_flash_timeout(fled_cdev, 527 ctrls[FLASH_TIMEOUT]->val); 528 if (ret < 0) 529 return ret; 530 } 531 532 if (ctrls[FLASH_INTENSITY]) { 533 if (WARN_ON_ONCE(!fled_cdev)) 534 return -EINVAL; 535 536 ret = led_set_flash_brightness(fled_cdev, 537 ctrls[FLASH_INTENSITY]->val); 538 if (ret < 0) 539 return ret; 540 } 541 542 /* 543 * For some hardware arrangements setting strobe source may affect 544 * torch mode. Synchronize strobe source setting only if not in torch 545 * mode. For torch mode case it will get synchronized upon switching 546 * to flash mode. 547 */ 548 if (ctrls[STROBE_SOURCE] && 549 ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) 550 ret = call_flash_op(v4l2_flash, external_strobe_set, 551 ctrls[STROBE_SOURCE]->val); 552 553 return ret; 554 } 555 556 /* 557 * V4L2 subdev internal operations 558 */ 559 560 static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 561 { 562 struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); 563 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 564 struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; 565 struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev; 566 int ret = 0; 567 568 if (!v4l2_fh_is_singular(&fh->vfh)) 569 return 0; 570 571 if (led_cdev) { 572 mutex_lock(&led_cdev->led_access); 573 574 led_sysfs_disable(led_cdev); 575 led_trigger_remove(led_cdev); 576 577 mutex_unlock(&led_cdev->led_access); 578 } 579 580 if (led_cdev_ind) { 581 mutex_lock(&led_cdev_ind->led_access); 582 583 led_sysfs_disable(led_cdev_ind); 584 led_trigger_remove(led_cdev_ind); 585 586 mutex_unlock(&led_cdev_ind->led_access); 587 } 588 589 ret = __sync_device_with_v4l2_controls(v4l2_flash); 590 if (ret < 0) 591 goto out_sync_device; 592 593 return 0; 594 out_sync_device: 595 if (led_cdev) { 596 mutex_lock(&led_cdev->led_access); 597 led_sysfs_enable(led_cdev); 598 mutex_unlock(&led_cdev->led_access); 599 } 600 601 if (led_cdev_ind) { 602 mutex_lock(&led_cdev_ind->led_access); 603 led_sysfs_enable(led_cdev_ind); 604 mutex_unlock(&led_cdev_ind->led_access); 605 } 606 607 return ret; 608 } 609 610 static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 611 { 612 struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); 613 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 614 struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; 615 struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev; 616 int ret = 0; 617 618 if (!v4l2_fh_is_singular(&fh->vfh)) 619 return 0; 620 621 if (led_cdev) { 622 mutex_lock(&led_cdev->led_access); 623 624 if (v4l2_flash->ctrls[STROBE_SOURCE]) 625 ret = v4l2_ctrl_s_ctrl( 626 v4l2_flash->ctrls[STROBE_SOURCE], 627 V4L2_FLASH_STROBE_SOURCE_SOFTWARE); 628 led_sysfs_enable(led_cdev); 629 630 mutex_unlock(&led_cdev->led_access); 631 } 632 633 if (led_cdev_ind) { 634 mutex_lock(&led_cdev_ind->led_access); 635 led_sysfs_enable(led_cdev_ind); 636 mutex_unlock(&led_cdev_ind->led_access); 637 } 638 639 return ret; 640 } 641 642 static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = { 643 .open = v4l2_flash_open, 644 .close = v4l2_flash_close, 645 }; 646 647 static const struct v4l2_subdev_ops v4l2_flash_subdev_ops; 648 649 static struct v4l2_flash *__v4l2_flash_init( 650 struct device *dev, struct fwnode_handle *fwn, 651 struct led_classdev_flash *fled_cdev, struct led_classdev *iled_cdev, 652 const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config) 653 { 654 struct v4l2_flash *v4l2_flash; 655 struct v4l2_subdev *sd; 656 int ret; 657 658 if (!config) 659 return ERR_PTR(-EINVAL); 660 661 v4l2_flash = devm_kzalloc(dev, sizeof(*v4l2_flash), GFP_KERNEL); 662 if (!v4l2_flash) 663 return ERR_PTR(-ENOMEM); 664 665 sd = &v4l2_flash->sd; 666 v4l2_flash->fled_cdev = fled_cdev; 667 v4l2_flash->iled_cdev = iled_cdev; 668 v4l2_flash->ops = ops; 669 sd->dev = dev; 670 sd->fwnode = fwn ? fwn : dev_fwnode(dev); 671 v4l2_subdev_init(sd, &v4l2_flash_subdev_ops); 672 sd->internal_ops = &v4l2_flash_subdev_internal_ops; 673 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 674 strscpy(sd->name, config->dev_name, sizeof(sd->name)); 675 676 ret = media_entity_pads_init(&sd->entity, 0, NULL); 677 if (ret < 0) 678 return ERR_PTR(ret); 679 680 sd->entity.function = MEDIA_ENT_F_FLASH; 681 682 ret = v4l2_flash_init_controls(v4l2_flash, config); 683 if (ret < 0) 684 goto err_init_controls; 685 686 fwnode_handle_get(sd->fwnode); 687 688 ret = v4l2_async_register_subdev(sd); 689 if (ret < 0) 690 goto err_async_register_sd; 691 692 return v4l2_flash; 693 694 err_async_register_sd: 695 fwnode_handle_put(sd->fwnode); 696 v4l2_ctrl_handler_free(sd->ctrl_handler); 697 err_init_controls: 698 media_entity_cleanup(&sd->entity); 699 700 return ERR_PTR(ret); 701 } 702 703 struct v4l2_flash *v4l2_flash_init( 704 struct device *dev, struct fwnode_handle *fwn, 705 struct led_classdev_flash *fled_cdev, 706 const struct v4l2_flash_ops *ops, 707 struct v4l2_flash_config *config) 708 { 709 return __v4l2_flash_init(dev, fwn, fled_cdev, NULL, ops, config); 710 } 711 EXPORT_SYMBOL_GPL(v4l2_flash_init); 712 713 struct v4l2_flash *v4l2_flash_indicator_init( 714 struct device *dev, struct fwnode_handle *fwn, 715 struct led_classdev *iled_cdev, 716 struct v4l2_flash_config *config) 717 { 718 return __v4l2_flash_init(dev, fwn, NULL, iled_cdev, NULL, config); 719 } 720 EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init); 721 722 void v4l2_flash_release(struct v4l2_flash *v4l2_flash) 723 { 724 struct v4l2_subdev *sd; 725 726 if (IS_ERR_OR_NULL(v4l2_flash)) 727 return; 728 729 sd = &v4l2_flash->sd; 730 731 v4l2_async_unregister_subdev(sd); 732 733 fwnode_handle_put(sd->fwnode); 734 735 v4l2_ctrl_handler_free(sd->ctrl_handler); 736 media_entity_cleanup(&sd->entity); 737 } 738 EXPORT_SYMBOL_GPL(v4l2_flash_release); 739 740 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); 741 MODULE_DESCRIPTION("V4L2 Flash sub-device helpers"); 742 MODULE_LICENSE("GPL v2"); 743