linux/drivers/media/v4l2-core/v4l2-flash-led-class.c
<<
>>
Prefs
   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