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/of.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->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 28enum 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 46static 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 64static 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 82static 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(&v4l2_flash->fled_cdev->led_cdev, 111 brightness); 112 } else { 113 led_set_brightness(&v4l2_flash->iled_cdev->led_cdev, 114 brightness); 115 } 116} 117 118static 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->led_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 154static 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 189static 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 196static 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->led_cdev; 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(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(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 283static 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 288static 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 297static 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 const struct led_flash_ops *fled_cdev_ops = fled_cdev->ops; 303 struct led_classdev *led_cdev = &fled_cdev->led_cdev; 304 struct v4l2_ctrl_config *ctrl_cfg; 305 u32 mask; 306 307 /* Init FLASH_FAULT ctrl data */ 308 if (flash_cfg->flash_faults) { 309 ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT; 310 ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config; 311 ctrl_cfg->id = V4L2_CID_FLASH_FAULT; 312 ctrl_cfg->max = flash_cfg->flash_faults; 313 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 314 V4L2_CTRL_FLAG_READ_ONLY; 315 } 316 317 /* Init FLASH_LED_MODE ctrl data */ 318 mask = 1 << V4L2_FLASH_LED_MODE_NONE | 319 1 << V4L2_FLASH_LED_MODE_TORCH; 320 if (led_cdev->flags & LED_DEV_CAP_FLASH) 321 mask |= 1 << V4L2_FLASH_LED_MODE_FLASH; 322 323 ctrl_init_data[LED_MODE].cid = V4L2_CID_FLASH_LED_MODE; 324 ctrl_cfg = &ctrl_init_data[LED_MODE].config; 325 ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE; 326 ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH; 327 ctrl_cfg->menu_skip_mask = ~mask; 328 ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE; 329 ctrl_cfg->flags = 0; 330 331 /* Init TORCH_INTENSITY ctrl data */ 332 ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY; 333 ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config; 334 __lfs_to_v4l2_ctrl_config(&flash_cfg->torch_intensity, ctrl_cfg); 335 ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY; 336 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 337 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 338 339 /* Init INDICATOR_INTENSITY ctrl data */ 340 if (v4l2_flash->iled_cdev) { 341 ctrl_init_data[INDICATOR_INTENSITY].cid = 342 V4L2_CID_FLASH_INDICATOR_INTENSITY; 343 ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config; 344 __lfs_to_v4l2_ctrl_config(&flash_cfg->indicator_intensity, 345 ctrl_cfg); 346 ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY; 347 ctrl_cfg->min = 0; 348 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 349 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 350 } 351 352 if (!(led_cdev->flags & LED_DEV_CAP_FLASH)) 353 return; 354 355 /* Init FLASH_STROBE ctrl data */ 356 ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE; 357 ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config; 358 ctrl_cfg->id = V4L2_CID_FLASH_STROBE; 359 360 /* Init STROBE_STOP ctrl data */ 361 ctrl_init_data[STROBE_STOP].cid = V4L2_CID_FLASH_STROBE_STOP; 362 ctrl_cfg = &ctrl_init_data[STROBE_STOP].config; 363 ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP; 364 365 /* Init FLASH_STROBE_SOURCE ctrl data */ 366 if (flash_cfg->has_external_strobe) { 367 mask = (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE) | 368 (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 369 ctrl_init_data[STROBE_SOURCE].cid = 370 V4L2_CID_FLASH_STROBE_SOURCE; 371 ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config; 372 ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE; 373 ctrl_cfg->max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; 374 ctrl_cfg->menu_skip_mask = ~mask; 375 ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; 376 } 377 378 /* Init STROBE_STATUS ctrl data */ 379 if (fled_cdev_ops->strobe_get) { 380 ctrl_init_data[STROBE_STATUS].cid = 381 V4L2_CID_FLASH_STROBE_STATUS; 382 ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config; 383 ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS; 384 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 385 V4L2_CTRL_FLAG_READ_ONLY; 386 } 387 388 /* Init FLASH_TIMEOUT ctrl data */ 389 if (fled_cdev_ops->timeout_set) { 390 ctrl_init_data[FLASH_TIMEOUT].cid = V4L2_CID_FLASH_TIMEOUT; 391 ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config; 392 __lfs_to_v4l2_ctrl_config(&fled_cdev->timeout, ctrl_cfg); 393 ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT; 394 } 395 396 /* Init FLASH_INTENSITY ctrl data */ 397 if (fled_cdev_ops->flash_brightness_set) { 398 ctrl_init_data[FLASH_INTENSITY].cid = V4L2_CID_FLASH_INTENSITY; 399 ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config; 400 __lfs_to_v4l2_ctrl_config(&fled_cdev->brightness, ctrl_cfg); 401 ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY; 402 ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 403 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 404 } 405} 406 407static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash, 408 struct v4l2_flash_config *flash_cfg) 409 410{ 411 struct v4l2_flash_ctrl_data *ctrl_init_data; 412 struct v4l2_ctrl *ctrl; 413 struct v4l2_ctrl_config *ctrl_cfg; 414 int i, ret, num_ctrls = 0; 415 416 v4l2_flash->ctrls = devm_kzalloc(v4l2_flash->sd.dev, 417 sizeof(*v4l2_flash->ctrls) * 418 (STROBE_SOURCE + 1), 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 478error_free_handler: 479 v4l2_ctrl_handler_free(&v4l2_flash->hdl); 480 return ret; 481} 482 483static 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 v4l2_flash_set_led_brightness(v4l2_flash, ctrls[TORCH_INTENSITY]); 490 491 if (ctrls[INDICATOR_INTENSITY]) 492 v4l2_flash_set_led_brightness(v4l2_flash, 493 ctrls[INDICATOR_INTENSITY]); 494 495 if (ctrls[FLASH_TIMEOUT]) { 496 ret = led_set_flash_timeout(fled_cdev, 497 ctrls[FLASH_TIMEOUT]->val); 498 if (ret < 0) 499 return ret; 500 } 501 502 if (ctrls[FLASH_INTENSITY]) { 503 ret = led_set_flash_brightness(fled_cdev, 504 ctrls[FLASH_INTENSITY]->val); 505 if (ret < 0) 506 return ret; 507 } 508 509 /* 510 * For some hardware arrangements setting strobe source may affect 511 * torch mode. Synchronize strobe source setting only if not in torch 512 * mode. For torch mode case it will get synchronized upon switching 513 * to flash mode. 514 */ 515 if (ctrls[STROBE_SOURCE] && 516 ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) 517 ret = call_flash_op(v4l2_flash, external_strobe_set, 518 ctrls[STROBE_SOURCE]->val); 519 520 return ret; 521} 522 523/* 524 * V4L2 subdev internal operations 525 */ 526 527static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 528{ 529 struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); 530 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 531 struct led_classdev *led_cdev = &fled_cdev->led_cdev; 532 struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev; 533 struct led_classdev *led_cdev_ind = NULL; 534 int ret = 0; 535 536 if (!v4l2_fh_is_singular(&fh->vfh)) 537 return 0; 538 539 mutex_lock(&led_cdev->led_access); 540 541 led_sysfs_disable(led_cdev); 542 led_trigger_remove(led_cdev); 543 544 mutex_unlock(&led_cdev->led_access); 545 546 if (iled_cdev) { 547 led_cdev_ind = &iled_cdev->led_cdev; 548 549 mutex_lock(&led_cdev_ind->led_access); 550 551 led_sysfs_disable(led_cdev_ind); 552 led_trigger_remove(led_cdev_ind); 553 554 mutex_unlock(&led_cdev_ind->led_access); 555 } 556 557 ret = __sync_device_with_v4l2_controls(v4l2_flash); 558 if (ret < 0) 559 goto out_sync_device; 560 561 return 0; 562out_sync_device: 563 mutex_lock(&led_cdev->led_access); 564 led_sysfs_enable(led_cdev); 565 mutex_unlock(&led_cdev->led_access); 566 567 if (led_cdev_ind) { 568 mutex_lock(&led_cdev_ind->led_access); 569 led_sysfs_enable(led_cdev_ind); 570 mutex_unlock(&led_cdev_ind->led_access); 571 } 572 573 return ret; 574} 575 576static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 577{ 578 struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); 579 struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 580 struct led_classdev *led_cdev = &fled_cdev->led_cdev; 581 struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev; 582 int ret = 0; 583 584 if (!v4l2_fh_is_singular(&fh->vfh)) 585 return 0; 586 587 mutex_lock(&led_cdev->led_access); 588 589 if (v4l2_flash->ctrls[STROBE_SOURCE]) 590 ret = v4l2_ctrl_s_ctrl(v4l2_flash->ctrls[STROBE_SOURCE], 591 V4L2_FLASH_STROBE_SOURCE_SOFTWARE); 592 led_sysfs_enable(led_cdev); 593 594 mutex_unlock(&led_cdev->led_access); 595 596 if (iled_cdev) { 597 struct led_classdev *led_cdev_ind = &iled_cdev->led_cdev; 598 599 mutex_lock(&led_cdev_ind->led_access); 600 led_sysfs_enable(led_cdev_ind); 601 mutex_unlock(&led_cdev_ind->led_access); 602 } 603 604 return ret; 605} 606 607static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = { 608 .open = v4l2_flash_open, 609 .close = v4l2_flash_close, 610}; 611 612static const struct v4l2_subdev_core_ops v4l2_flash_core_ops = { 613 .queryctrl = v4l2_subdev_queryctrl, 614 .querymenu = v4l2_subdev_querymenu, 615}; 616 617static const struct v4l2_subdev_ops v4l2_flash_subdev_ops = { 618 .core = &v4l2_flash_core_ops, 619}; 620 621struct v4l2_flash *v4l2_flash_init( 622 struct device *dev, struct device_node *of_node, 623 struct led_classdev_flash *fled_cdev, 624 struct led_classdev_flash *iled_cdev, 625 const struct v4l2_flash_ops *ops, 626 struct v4l2_flash_config *config) 627{ 628 struct v4l2_flash *v4l2_flash; 629 struct led_classdev *led_cdev; 630 struct v4l2_subdev *sd; 631 int ret; 632 633 if (!fled_cdev || !ops || !config) 634 return ERR_PTR(-EINVAL); 635 636 led_cdev = &fled_cdev->led_cdev; 637 638 v4l2_flash = devm_kzalloc(led_cdev->dev, sizeof(*v4l2_flash), 639 GFP_KERNEL); 640 if (!v4l2_flash) 641 return ERR_PTR(-ENOMEM); 642 643 sd = &v4l2_flash->sd; 644 v4l2_flash->fled_cdev = fled_cdev; 645 v4l2_flash->iled_cdev = iled_cdev; 646 v4l2_flash->ops = ops; 647 sd->dev = dev; 648 sd->of_node = of_node; 649 v4l2_subdev_init(sd, &v4l2_flash_subdev_ops); 650 sd->internal_ops = &v4l2_flash_subdev_internal_ops; 651 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 652 strlcpy(sd->name, config->dev_name, sizeof(sd->name)); 653 654 ret = media_entity_init(&sd->entity, 0, NULL, 0); 655 if (ret < 0) 656 return ERR_PTR(ret); 657 658 sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; 659 660 ret = v4l2_flash_init_controls(v4l2_flash, config); 661 if (ret < 0) 662 goto err_init_controls; 663 664 if (sd->of_node) 665 of_node_get(sd->of_node); 666 else 667 of_node_get(led_cdev->dev->of_node); 668 669 ret = v4l2_async_register_subdev(sd); 670 if (ret < 0) 671 goto err_async_register_sd; 672 673 return v4l2_flash; 674 675err_async_register_sd: 676 of_node_put(led_cdev->dev->of_node); 677 v4l2_ctrl_handler_free(sd->ctrl_handler); 678err_init_controls: 679 media_entity_cleanup(&sd->entity); 680 681 return ERR_PTR(ret); 682} 683EXPORT_SYMBOL_GPL(v4l2_flash_init); 684 685void v4l2_flash_release(struct v4l2_flash *v4l2_flash) 686{ 687 struct v4l2_subdev *sd; 688 struct led_classdev *led_cdev; 689 690 if (IS_ERR_OR_NULL(v4l2_flash)) 691 return; 692 693 sd = &v4l2_flash->sd; 694 led_cdev = &v4l2_flash->fled_cdev->led_cdev; 695 696 v4l2_async_unregister_subdev(sd); 697 698 if (sd->of_node) 699 of_node_put(sd->of_node); 700 else 701 of_node_put(led_cdev->dev->of_node); 702 703 v4l2_ctrl_handler_free(sd->ctrl_handler); 704 media_entity_cleanup(&sd->entity); 705} 706EXPORT_SYMBOL_GPL(v4l2_flash_release); 707 708MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); 709MODULE_DESCRIPTION("V4L2 Flash sub-device helpers"); 710MODULE_LICENSE("GPL v2"); 711