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