linux/drivers/media/platform/exynos4-is/fimc-isp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
   4 *
   5 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
   6 *
   7 * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
   8 *          Younghwan Joo <yhwan.joo@samsung.com>
   9 */
  10#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
  11
  12#include <linux/device.h>
  13#include <linux/errno.h>
  14#include <linux/kernel.h>
  15#include <linux/list.h>
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18#include <linux/printk.h>
  19#include <linux/pm_runtime.h>
  20#include <linux/slab.h>
  21#include <linux/types.h>
  22#include <media/v4l2-device.h>
  23
  24#include "media-dev.h"
  25#include "fimc-isp-video.h"
  26#include "fimc-is-command.h"
  27#include "fimc-is-param.h"
  28#include "fimc-is-regs.h"
  29#include "fimc-is.h"
  30
  31int fimc_isp_debug;
  32module_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR);
  33
  34static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
  35        {
  36                .fourcc         = V4L2_PIX_FMT_SGRBG8,
  37                .depth          = { 8 },
  38                .color          = FIMC_FMT_RAW8,
  39                .memplanes      = 1,
  40                .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
  41        }, {
  42                .fourcc         = V4L2_PIX_FMT_SGRBG10,
  43                .depth          = { 10 },
  44                .color          = FIMC_FMT_RAW10,
  45                .memplanes      = 1,
  46                .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
  47        }, {
  48                .fourcc         = V4L2_PIX_FMT_SGRBG12,
  49                .depth          = { 12 },
  50                .color          = FIMC_FMT_RAW12,
  51                .memplanes      = 1,
  52                .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
  53        },
  54};
  55
  56/**
  57 * fimc_isp_find_format - lookup color format by fourcc or media bus code
  58 * @pixelformat: fourcc to match, ignored if null
  59 * @mbus_code: media bus code to match, ignored if null
  60 * @index: index to the fimc_isp_formats array, ignored if negative
  61 */
  62const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat,
  63                                        const u32 *mbus_code, int index)
  64{
  65        const struct fimc_fmt *fmt, *def_fmt = NULL;
  66        unsigned int i;
  67        int id = 0;
  68
  69        if (index >= (int)ARRAY_SIZE(fimc_isp_formats))
  70                return NULL;
  71
  72        for (i = 0; i < ARRAY_SIZE(fimc_isp_formats); ++i) {
  73                fmt = &fimc_isp_formats[i];
  74                if (pixelformat && fmt->fourcc == *pixelformat)
  75                        return fmt;
  76                if (mbus_code && fmt->mbus_code == *mbus_code)
  77                        return fmt;
  78                if (index == id)
  79                        def_fmt = fmt;
  80                id++;
  81        }
  82        return def_fmt;
  83}
  84
  85void fimc_isp_irq_handler(struct fimc_is *is)
  86{
  87        is->i2h_cmd.args[0] = mcuctl_read(is, MCUCTL_REG_ISSR(20));
  88        is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21));
  89
  90        fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP);
  91        fimc_isp_video_irq_handler(is);
  92
  93        wake_up(&is->irq_queue);
  94}
  95
  96/* Capture subdev media entity operations */
  97static int fimc_is_link_setup(struct media_entity *entity,
  98                                const struct media_pad *local,
  99                                const struct media_pad *remote, u32 flags)
 100{
 101        return 0;
 102}
 103
 104static const struct media_entity_operations fimc_is_subdev_media_ops = {
 105        .link_setup = fimc_is_link_setup,
 106};
 107
 108static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
 109                                struct v4l2_subdev_state *sd_state,
 110                                struct v4l2_subdev_mbus_code_enum *code)
 111{
 112        const struct fimc_fmt *fmt;
 113
 114        fmt = fimc_isp_find_format(NULL, NULL, code->index);
 115        if (!fmt)
 116                return -EINVAL;
 117        code->code = fmt->mbus_code;
 118        return 0;
 119}
 120
 121static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
 122                                   struct v4l2_subdev_state *sd_state,
 123                                   struct v4l2_subdev_format *fmt)
 124{
 125        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
 126        struct v4l2_mbus_framefmt *mf = &fmt->format;
 127
 128        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 129                *mf = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
 130                return 0;
 131        }
 132
 133        mf->colorspace = V4L2_COLORSPACE_SRGB;
 134
 135        mutex_lock(&isp->subdev_lock);
 136
 137        if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
 138                /* ISP OTF input image format */
 139                *mf = isp->sink_fmt;
 140        } else {
 141                /* ISP OTF output image format */
 142                *mf = isp->src_fmt;
 143
 144                if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
 145                        mf->colorspace = V4L2_COLORSPACE_JPEG;
 146                        mf->code = MEDIA_BUS_FMT_YUV10_1X30;
 147                }
 148        }
 149
 150        mutex_unlock(&isp->subdev_lock);
 151
 152        isp_dbg(1, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n", __func__,
 153                fmt->pad, mf->code, mf->width, mf->height);
 154
 155        return 0;
 156}
 157
 158static void __isp_subdev_try_format(struct fimc_isp *isp,
 159                                    struct v4l2_subdev_state *sd_state,
 160                                    struct v4l2_subdev_format *fmt)
 161{
 162        struct v4l2_mbus_framefmt *mf = &fmt->format;
 163        struct v4l2_mbus_framefmt *format;
 164
 165        mf->colorspace = V4L2_COLORSPACE_SRGB;
 166
 167        if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
 168                v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN,
 169                                FIMC_ISP_SINK_WIDTH_MAX, 0,
 170                                &mf->height, FIMC_ISP_SINK_HEIGHT_MIN,
 171                                FIMC_ISP_SINK_HEIGHT_MAX, 0, 0);
 172                mf->code = MEDIA_BUS_FMT_SGRBG10_1X10;
 173        } else {
 174                if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
 175                        format = v4l2_subdev_get_try_format(&isp->subdev,
 176                                                            sd_state,
 177                                                            FIMC_ISP_SD_PAD_SINK);
 178                else
 179                        format = &isp->sink_fmt;
 180
 181                /* Allow changing format only on sink pad */
 182                mf->width = format->width - FIMC_ISP_CAC_MARGIN_WIDTH;
 183                mf->height = format->height - FIMC_ISP_CAC_MARGIN_HEIGHT;
 184
 185                if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
 186                        mf->code = MEDIA_BUS_FMT_YUV10_1X30;
 187                        mf->colorspace = V4L2_COLORSPACE_JPEG;
 188                } else {
 189                        mf->code = format->code;
 190                }
 191        }
 192}
 193
 194static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
 195                                   struct v4l2_subdev_state *sd_state,
 196                                   struct v4l2_subdev_format *fmt)
 197{
 198        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
 199        struct fimc_is *is = fimc_isp_to_is(isp);
 200        struct v4l2_mbus_framefmt *mf = &fmt->format;
 201        int ret = 0;
 202
 203        isp_dbg(1, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
 204                 __func__, fmt->pad, mf->code, mf->width, mf->height);
 205
 206        mutex_lock(&isp->subdev_lock);
 207        __isp_subdev_try_format(isp, sd_state, fmt);
 208
 209        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 210                mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
 211                *mf = fmt->format;
 212
 213                /* Propagate format to the source pads */
 214                if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
 215                        struct v4l2_subdev_format format = *fmt;
 216                        unsigned int pad;
 217
 218                        for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
 219                                        pad < FIMC_ISP_SD_PADS_NUM; pad++) {
 220                                format.pad = pad;
 221                                __isp_subdev_try_format(isp, sd_state,
 222                                                        &format);
 223                                mf = v4l2_subdev_get_try_format(sd, sd_state,
 224                                                                pad);
 225                                *mf = format.format;
 226                        }
 227                }
 228        } else {
 229                if (sd->entity.stream_count == 0) {
 230                        if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
 231                                struct v4l2_subdev_format format = *fmt;
 232
 233                                isp->sink_fmt = *mf;
 234
 235                                format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
 236                                __isp_subdev_try_format(isp, sd_state,
 237                                                        &format);
 238
 239                                isp->src_fmt = format.format;
 240                                __is_set_frame_size(is, &isp->src_fmt);
 241                        } else {
 242                                isp->src_fmt = *mf;
 243                        }
 244                } else {
 245                        ret = -EBUSY;
 246                }
 247        }
 248
 249        mutex_unlock(&isp->subdev_lock);
 250        return ret;
 251}
 252
 253static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
 254{
 255        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
 256        struct fimc_is *is = fimc_isp_to_is(isp);
 257        int ret;
 258
 259        isp_dbg(1, sd, "%s: on: %d\n", __func__, on);
 260
 261        if (!test_bit(IS_ST_INIT_DONE, &is->state))
 262                return -EBUSY;
 263
 264        fimc_is_mem_barrier();
 265
 266        if (on) {
 267                if (__get_pending_param_count(is)) {
 268                        ret = fimc_is_itf_s_param(is, true);
 269                        if (ret < 0)
 270                                return ret;
 271                }
 272
 273                isp_dbg(1, sd, "changing mode to %d\n", is->config_index);
 274
 275                ret = fimc_is_itf_mode_change(is);
 276                if (ret)
 277                        return -EINVAL;
 278
 279                clear_bit(IS_ST_STREAM_ON, &is->state);
 280                fimc_is_hw_stream_on(is);
 281                ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1,
 282                                         FIMC_IS_CONFIG_TIMEOUT);
 283                if (ret < 0) {
 284                        v4l2_err(sd, "stream on timeout\n");
 285                        return ret;
 286                }
 287        } else {
 288                clear_bit(IS_ST_STREAM_OFF, &is->state);
 289                fimc_is_hw_stream_off(is);
 290                ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
 291                                         FIMC_IS_CONFIG_TIMEOUT);
 292                if (ret < 0) {
 293                        v4l2_err(sd, "stream off timeout\n");
 294                        return ret;
 295                }
 296                is->setfile.sub_index = 0;
 297        }
 298
 299        return 0;
 300}
 301
 302static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
 303{
 304        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
 305        struct fimc_is *is = fimc_isp_to_is(isp);
 306        int ret = 0;
 307
 308        pr_debug("on: %d\n", on);
 309
 310        if (on) {
 311                ret = pm_runtime_resume_and_get(&is->pdev->dev);
 312                if (ret < 0)
 313                        return ret;
 314
 315                set_bit(IS_ST_PWR_ON, &is->state);
 316
 317                ret = fimc_is_start_firmware(is);
 318                if (ret < 0) {
 319                        v4l2_err(sd, "firmware booting failed\n");
 320                        pm_runtime_put(&is->pdev->dev);
 321                        return ret;
 322                }
 323                set_bit(IS_ST_PWR_SUBIP_ON, &is->state);
 324
 325                ret = fimc_is_hw_initialize(is);
 326        } else {
 327                /* Close sensor */
 328                if (!test_bit(IS_ST_PWR_ON, &is->state)) {
 329                        fimc_is_hw_close_sensor(is, 0);
 330
 331                        ret = fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 0,
 332                                                 FIMC_IS_CONFIG_TIMEOUT);
 333                        if (ret < 0) {
 334                                v4l2_err(sd, "sensor close timeout\n");
 335                                return ret;
 336                        }
 337                }
 338
 339                /* SUB IP power off */
 340                if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) {
 341                        fimc_is_hw_subip_power_off(is);
 342                        ret = fimc_is_wait_event(is, IS_ST_PWR_SUBIP_ON, 0,
 343                                                 FIMC_IS_CONFIG_TIMEOUT);
 344                        if (ret < 0) {
 345                                v4l2_err(sd, "sub-IP power off timeout\n");
 346                                return ret;
 347                        }
 348                }
 349
 350                fimc_is_cpu_set_power(is, 0);
 351                pm_runtime_put_sync(&is->pdev->dev);
 352
 353                clear_bit(IS_ST_PWR_ON, &is->state);
 354                clear_bit(IS_ST_INIT_DONE, &is->state);
 355                is->state = 0;
 356                is->config[is->config_index].p_region_index[0] = 0;
 357                is->config[is->config_index].p_region_index[1] = 0;
 358                set_bit(IS_ST_IDLE, &is->state);
 359                wmb();
 360        }
 361
 362        return ret;
 363}
 364
 365static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
 366                                struct v4l2_subdev_fh *fh)
 367{
 368        struct v4l2_mbus_framefmt *format;
 369        struct v4l2_mbus_framefmt fmt = {
 370                .colorspace = V4L2_COLORSPACE_SRGB,
 371                .code = fimc_isp_formats[0].mbus_code,
 372                .width = DEFAULT_PREVIEW_STILL_WIDTH + FIMC_ISP_CAC_MARGIN_WIDTH,
 373                .height = DEFAULT_PREVIEW_STILL_HEIGHT + FIMC_ISP_CAC_MARGIN_HEIGHT,
 374                .field = V4L2_FIELD_NONE,
 375        };
 376
 377        format = v4l2_subdev_get_try_format(sd, fh->state,
 378                                            FIMC_ISP_SD_PAD_SINK);
 379        *format = fmt;
 380
 381        format = v4l2_subdev_get_try_format(sd, fh->state,
 382                                            FIMC_ISP_SD_PAD_SRC_FIFO);
 383        fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
 384        fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
 385        *format = fmt;
 386
 387        format = v4l2_subdev_get_try_format(sd, fh->state,
 388                                            FIMC_ISP_SD_PAD_SRC_DMA);
 389        *format = fmt;
 390
 391        return 0;
 392}
 393
 394static int fimc_isp_subdev_registered(struct v4l2_subdev *sd)
 395{
 396        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
 397        int ret;
 398
 399        /* Use pipeline object allocated by the media device. */
 400        isp->video_capture.ve.pipe = v4l2_get_subdev_hostdata(sd);
 401
 402        ret = fimc_isp_video_device_register(isp, sd->v4l2_dev,
 403                        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 404        if (ret < 0)
 405                isp->video_capture.ve.pipe = NULL;
 406
 407        return ret;
 408}
 409
 410static void fimc_isp_subdev_unregistered(struct v4l2_subdev *sd)
 411{
 412        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
 413
 414        fimc_isp_video_device_unregister(isp,
 415                        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 416}
 417
 418static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = {
 419        .registered = fimc_isp_subdev_registered,
 420        .unregistered = fimc_isp_subdev_unregistered,
 421        .open = fimc_isp_subdev_open,
 422};
 423
 424static const struct v4l2_subdev_pad_ops fimc_is_subdev_pad_ops = {
 425        .enum_mbus_code = fimc_is_subdev_enum_mbus_code,
 426        .get_fmt = fimc_isp_subdev_get_fmt,
 427        .set_fmt = fimc_isp_subdev_set_fmt,
 428};
 429
 430static const struct v4l2_subdev_video_ops fimc_is_subdev_video_ops = {
 431        .s_stream = fimc_isp_subdev_s_stream,
 432};
 433
 434static const struct v4l2_subdev_core_ops fimc_is_core_ops = {
 435        .s_power = fimc_isp_subdev_s_power,
 436};
 437
 438static const struct v4l2_subdev_ops fimc_is_subdev_ops = {
 439        .core = &fimc_is_core_ops,
 440        .video = &fimc_is_subdev_video_ops,
 441        .pad = &fimc_is_subdev_pad_ops,
 442};
 443
 444static int __ctrl_set_white_balance(struct fimc_is *is, int value)
 445{
 446        switch (value) {
 447        case V4L2_WHITE_BALANCE_AUTO:
 448                __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
 449                break;
 450        case V4L2_WHITE_BALANCE_DAYLIGHT:
 451                __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
 452                                        ISP_AWB_ILLUMINATION_DAYLIGHT);
 453                break;
 454        case V4L2_WHITE_BALANCE_CLOUDY:
 455                __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
 456                                        ISP_AWB_ILLUMINATION_CLOUDY);
 457                break;
 458        case V4L2_WHITE_BALANCE_INCANDESCENT:
 459                __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
 460                                        ISP_AWB_ILLUMINATION_TUNGSTEN);
 461                break;
 462        case V4L2_WHITE_BALANCE_FLUORESCENT:
 463                __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
 464                                        ISP_AWB_ILLUMINATION_FLUORESCENT);
 465                break;
 466        default:
 467                return -EINVAL;
 468        }
 469
 470        return 0;
 471}
 472
 473static int __ctrl_set_aewb_lock(struct fimc_is *is,
 474                                      struct v4l2_ctrl *ctrl)
 475{
 476        bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
 477        bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
 478        struct isp_param *isp = &is->is_p_region->parameter.isp;
 479        int cmd, ret;
 480
 481        cmd = ae_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START;
 482        isp->aa.cmd = cmd;
 483        isp->aa.target = ISP_AA_TARGET_AE;
 484        fimc_is_set_param_bit(is, PARAM_ISP_AA);
 485        is->af.ae_lock_state = ae_lock;
 486        wmb();
 487
 488        ret = fimc_is_itf_s_param(is, false);
 489        if (ret < 0)
 490                return ret;
 491
 492        cmd = awb_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START;
 493        isp->aa.cmd = cmd;
 494        isp->aa.target = ISP_AA_TARGET_AE;
 495        fimc_is_set_param_bit(is, PARAM_ISP_AA);
 496        is->af.awb_lock_state = awb_lock;
 497        wmb();
 498
 499        return fimc_is_itf_s_param(is, false);
 500}
 501
 502/* Supported manual ISO values */
 503static const s64 iso_qmenu[] = {
 504        50, 100, 200, 400, 800,
 505};
 506
 507static int __ctrl_set_iso(struct fimc_is *is, int value)
 508{
 509        unsigned int idx, iso;
 510
 511        if (value == V4L2_ISO_SENSITIVITY_AUTO) {
 512                __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
 513                return 0;
 514        }
 515        idx = is->isp.ctrls.iso->val;
 516        if (idx >= ARRAY_SIZE(iso_qmenu))
 517                return -EINVAL;
 518
 519        iso = iso_qmenu[idx];
 520        __is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso);
 521        return 0;
 522}
 523
 524static int __ctrl_set_metering(struct fimc_is *is, unsigned int value)
 525{
 526        unsigned int val;
 527
 528        switch (value) {
 529        case V4L2_EXPOSURE_METERING_AVERAGE:
 530                val = ISP_METERING_COMMAND_AVERAGE;
 531                break;
 532        case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
 533                val = ISP_METERING_COMMAND_CENTER;
 534                break;
 535        case V4L2_EXPOSURE_METERING_SPOT:
 536                val = ISP_METERING_COMMAND_SPOT;
 537                break;
 538        case V4L2_EXPOSURE_METERING_MATRIX:
 539                val = ISP_METERING_COMMAND_MATRIX;
 540                break;
 541        default:
 542                return -EINVAL;
 543        }
 544
 545        __is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val);
 546        return 0;
 547}
 548
 549static int __ctrl_set_afc(struct fimc_is *is, int value)
 550{
 551        switch (value) {
 552        case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
 553                __is_set_isp_afc(is, ISP_AFC_COMMAND_DISABLE, 0);
 554                break;
 555        case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
 556                __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 50);
 557                break;
 558        case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
 559                __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 60);
 560                break;
 561        case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
 562                __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
 563                break;
 564        default:
 565                return -EINVAL;
 566        }
 567
 568        return 0;
 569}
 570
 571static int __ctrl_set_image_effect(struct fimc_is *is, int value)
 572{
 573        static const u8 effects[][2] = {
 574                { V4L2_COLORFX_NONE,     ISP_IMAGE_EFFECT_DISABLE },
 575                { V4L2_COLORFX_BW,       ISP_IMAGE_EFFECT_MONOCHROME },
 576                { V4L2_COLORFX_SEPIA,    ISP_IMAGE_EFFECT_SEPIA },
 577                { V4L2_COLORFX_NEGATIVE, ISP_IMAGE_EFFECT_NEGATIVE_MONO },
 578                { 16 /* TODO */,         ISP_IMAGE_EFFECT_NEGATIVE_COLOR },
 579        };
 580        int i;
 581
 582        for (i = 0; i < ARRAY_SIZE(effects); i++) {
 583                if (effects[i][0] != value)
 584                        continue;
 585
 586                __is_set_isp_effect(is, effects[i][1]);
 587                return 0;
 588        }
 589
 590        return -EINVAL;
 591}
 592
 593static int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl)
 594{
 595        struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl);
 596        struct fimc_is *is = fimc_isp_to_is(isp);
 597        bool set_param = true;
 598        int ret = 0;
 599
 600        switch (ctrl->id) {
 601        case V4L2_CID_CONTRAST:
 602                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST,
 603                                    ctrl->val);
 604                break;
 605
 606        case V4L2_CID_SATURATION:
 607                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION,
 608                                    ctrl->val);
 609                break;
 610
 611        case V4L2_CID_SHARPNESS:
 612                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS,
 613                                    ctrl->val);
 614                break;
 615
 616        case V4L2_CID_EXPOSURE_ABSOLUTE:
 617                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE,
 618                                    ctrl->val);
 619                break;
 620
 621        case V4L2_CID_BRIGHTNESS:
 622                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS,
 623                                    ctrl->val);
 624                break;
 625
 626        case V4L2_CID_HUE:
 627                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE,
 628                                    ctrl->val);
 629                break;
 630
 631        case V4L2_CID_EXPOSURE_METERING:
 632                ret = __ctrl_set_metering(is, ctrl->val);
 633                break;
 634
 635        case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
 636                ret = __ctrl_set_white_balance(is, ctrl->val);
 637                break;
 638
 639        case V4L2_CID_3A_LOCK:
 640                ret = __ctrl_set_aewb_lock(is, ctrl);
 641                set_param = false;
 642                break;
 643
 644        case V4L2_CID_ISO_SENSITIVITY_AUTO:
 645                ret = __ctrl_set_iso(is, ctrl->val);
 646                break;
 647
 648        case V4L2_CID_POWER_LINE_FREQUENCY:
 649                ret = __ctrl_set_afc(is, ctrl->val);
 650                break;
 651
 652        case V4L2_CID_COLORFX:
 653                __ctrl_set_image_effect(is, ctrl->val);
 654                break;
 655
 656        default:
 657                ret = -EINVAL;
 658                break;
 659        }
 660
 661        if (ret < 0) {
 662                v4l2_err(&isp->subdev, "Failed to set control: %s (%d)\n",
 663                                                ctrl->name, ctrl->val);
 664                return ret;
 665        }
 666
 667        if (set_param && test_bit(IS_ST_STREAM_ON, &is->state))
 668                return fimc_is_itf_s_param(is, true);
 669
 670        return 0;
 671}
 672
 673static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = {
 674        .s_ctrl = fimc_is_s_ctrl,
 675};
 676
 677static void __isp_subdev_set_default_format(struct fimc_isp *isp)
 678{
 679        struct fimc_is *is = fimc_isp_to_is(isp);
 680
 681        isp->sink_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH +
 682                                FIMC_ISP_CAC_MARGIN_WIDTH;
 683        isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT +
 684                                FIMC_ISP_CAC_MARGIN_HEIGHT;
 685        isp->sink_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10;
 686
 687        isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
 688        isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
 689        isp->src_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10;
 690        __is_set_frame_size(is, &isp->src_fmt);
 691}
 692
 693int fimc_isp_subdev_create(struct fimc_isp *isp)
 694{
 695        const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops;
 696        struct v4l2_ctrl_handler *handler = &isp->ctrls.handler;
 697        struct v4l2_subdev *sd = &isp->subdev;
 698        struct fimc_isp_ctrls *ctrls = &isp->ctrls;
 699        int ret;
 700
 701        mutex_init(&isp->subdev_lock);
 702
 703        v4l2_subdev_init(sd, &fimc_is_subdev_ops);
 704
 705        sd->owner = THIS_MODULE;
 706        sd->grp_id = GRP_ID_FIMC_IS;
 707        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 708        snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
 709
 710        sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
 711        isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
 712        isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE;
 713        isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE;
 714        ret = media_entity_pads_init(&sd->entity, FIMC_ISP_SD_PADS_NUM,
 715                                isp->subdev_pads);
 716        if (ret)
 717                return ret;
 718
 719        v4l2_ctrl_handler_init(handler, 20);
 720
 721        ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION,
 722                                                -2, 2, 1, 0);
 723        ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS,
 724                                                -4, 4, 1, 0);
 725        ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST,
 726                                                -2, 2, 1, 0);
 727        ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS,
 728                                                -2, 2, 1, 0);
 729        ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE,
 730                                                -2, 2, 1, 0);
 731
 732        ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops,
 733                                        V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
 734                                        8, ~0x14e, V4L2_WHITE_BALANCE_AUTO);
 735
 736        ctrls->exposure = v4l2_ctrl_new_std(handler, ops,
 737                                        V4L2_CID_EXPOSURE_ABSOLUTE,
 738                                        -4, 4, 1, 0);
 739
 740        ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops,
 741                                        V4L2_CID_EXPOSURE_METERING, 3,
 742                                        ~0xf, V4L2_EXPOSURE_METERING_AVERAGE);
 743
 744        v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY,
 745                                        V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
 746                                        V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
 747        /* ISO sensitivity */
 748        ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops,
 749                        V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0,
 750                        V4L2_ISO_SENSITIVITY_AUTO);
 751
 752        ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops,
 753                        V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
 754                        ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
 755
 756        ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops,
 757                                        V4L2_CID_3A_LOCK, 0, 0x3, 0, 0);
 758
 759        /* TODO: Add support for NEGATIVE_COLOR option */
 760        ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX,
 761                        V4L2_COLORFX_SET_CBCR + 1, ~0x1000f, V4L2_COLORFX_NONE);
 762
 763        if (handler->error) {
 764                media_entity_cleanup(&sd->entity);
 765                return handler->error;
 766        }
 767
 768        v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso,
 769                        V4L2_ISO_SENSITIVITY_MANUAL, false);
 770
 771        sd->ctrl_handler = handler;
 772        sd->internal_ops = &fimc_is_subdev_internal_ops;
 773        sd->entity.ops = &fimc_is_subdev_media_ops;
 774        v4l2_set_subdevdata(sd, isp);
 775
 776        __isp_subdev_set_default_format(isp);
 777
 778        return 0;
 779}
 780
 781void fimc_isp_subdev_destroy(struct fimc_isp *isp)
 782{
 783        struct v4l2_subdev *sd = &isp->subdev;
 784
 785        v4l2_device_unregister_subdev(sd);
 786        media_entity_cleanup(&sd->entity);
 787        v4l2_ctrl_handler_free(&isp->ctrls.handler);
 788        v4l2_set_subdevdata(sd, NULL);
 789}
 790