root/drivers/media/platform/exynos4-is/fimc-isp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fimc_isp_find_format
  2. fimc_isp_irq_handler
  3. fimc_is_link_setup
  4. fimc_is_subdev_enum_mbus_code
  5. fimc_isp_subdev_get_fmt
  6. __isp_subdev_try_format
  7. fimc_isp_subdev_set_fmt
  8. fimc_isp_subdev_s_stream
  9. fimc_isp_subdev_s_power
  10. fimc_isp_subdev_open
  11. fimc_isp_subdev_registered
  12. fimc_isp_subdev_unregistered
  13. __ctrl_set_white_balance
  14. __ctrl_set_aewb_lock
  15. __ctrl_set_iso
  16. __ctrl_set_metering
  17. __ctrl_set_afc
  18. __ctrl_set_image_effect
  19. fimc_is_s_ctrl
  20. __isp_subdev_set_default_format
  21. fimc_isp_subdev_create
  22. fimc_isp_subdev_destroy

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

/* [<][>][^][v][top][bottom][index][help] */