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