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