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