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_state *sd_state, 110 struct v4l2_subdev_mbus_code_enum *code) 111 { 112 const struct fimc_fmt *fmt; 113 114 fmt = fimc_isp_find_format(NULL, NULL, code->index); 115 if (!fmt) 116 return -EINVAL; 117 code->code = fmt->mbus_code; 118 return 0; 119 } 120 121 static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, 122 struct v4l2_subdev_state *sd_state, 123 struct v4l2_subdev_format *fmt) 124 { 125 struct fimc_isp *isp = v4l2_get_subdevdata(sd); 126 struct v4l2_mbus_framefmt *mf = &fmt->format; 127 128 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 129 *mf = *v4l2_subdev_state_get_format(sd_state, fmt->pad); 130 return 0; 131 } 132 133 mf->colorspace = V4L2_COLORSPACE_SRGB; 134 135 mutex_lock(&isp->subdev_lock); 136 137 if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 138 /* ISP OTF input image format */ 139 *mf = isp->sink_fmt; 140 } else { 141 /* ISP OTF output image format */ 142 *mf = isp->src_fmt; 143 144 if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) { 145 mf->colorspace = V4L2_COLORSPACE_JPEG; 146 mf->code = MEDIA_BUS_FMT_YUV10_1X30; 147 } 148 } 149 150 mutex_unlock(&isp->subdev_lock); 151 152 isp_dbg(1, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n", __func__, 153 fmt->pad, mf->code, mf->width, mf->height); 154 155 return 0; 156 } 157 158 static void __isp_subdev_try_format(struct fimc_isp *isp, 159 struct v4l2_subdev_state *sd_state, 160 struct v4l2_subdev_format *fmt) 161 { 162 struct v4l2_mbus_framefmt *mf = &fmt->format; 163 struct v4l2_mbus_framefmt *format; 164 165 mf->colorspace = V4L2_COLORSPACE_SRGB; 166 167 if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 168 v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN, 169 FIMC_ISP_SINK_WIDTH_MAX, 0, 170 &mf->height, FIMC_ISP_SINK_HEIGHT_MIN, 171 FIMC_ISP_SINK_HEIGHT_MAX, 0, 0); 172 mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; 173 } else { 174 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 175 format = v4l2_subdev_state_get_format(sd_state, 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_state *sd_state, 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, sd_state, fmt); 207 208 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 209 mf = v4l2_subdev_state_get_format(sd_state, 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, sd_state, 221 &format); 222 mf = v4l2_subdev_state_get_format(sd_state, 223 pad); 224 *mf = format.format; 225 } 226 } 227 } else { 228 if (!media_entity_is_streaming(&sd->entity)) { 229 if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 230 struct v4l2_subdev_format format = *fmt; 231 232 isp->sink_fmt = *mf; 233 234 format.pad = FIMC_ISP_SD_PAD_SRC_DMA; 235 __isp_subdev_try_format(isp, sd_state, 236 &format); 237 238 isp->src_fmt = format.format; 239 __is_set_frame_size(is, &isp->src_fmt); 240 } else { 241 isp->src_fmt = *mf; 242 } 243 } else { 244 ret = -EBUSY; 245 } 246 } 247 248 mutex_unlock(&isp->subdev_lock); 249 return ret; 250 } 251 252 static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on) 253 { 254 struct fimc_isp *isp = v4l2_get_subdevdata(sd); 255 struct fimc_is *is = fimc_isp_to_is(isp); 256 int ret; 257 258 isp_dbg(1, sd, "%s: on: %d\n", __func__, on); 259 260 if (!test_bit(IS_ST_INIT_DONE, &is->state)) 261 return -EBUSY; 262 263 fimc_is_mem_barrier(); 264 265 if (on) { 266 if (__get_pending_param_count(is)) { 267 ret = fimc_is_itf_s_param(is, true); 268 if (ret < 0) 269 return ret; 270 } 271 272 isp_dbg(1, sd, "changing mode to %d\n", is->config_index); 273 274 ret = fimc_is_itf_mode_change(is); 275 if (ret) 276 return -EINVAL; 277 278 clear_bit(IS_ST_STREAM_ON, &is->state); 279 fimc_is_hw_stream_on(is); 280 ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1, 281 FIMC_IS_CONFIG_TIMEOUT); 282 if (ret < 0) { 283 v4l2_err(sd, "stream on timeout\n"); 284 return ret; 285 } 286 } else { 287 clear_bit(IS_ST_STREAM_OFF, &is->state); 288 fimc_is_hw_stream_off(is); 289 ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1, 290 FIMC_IS_CONFIG_TIMEOUT); 291 if (ret < 0) { 292 v4l2_err(sd, "stream off timeout\n"); 293 return ret; 294 } 295 is->setfile.sub_index = 0; 296 } 297 298 return 0; 299 } 300 301 static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on) 302 { 303 struct fimc_isp *isp = v4l2_get_subdevdata(sd); 304 struct fimc_is *is = fimc_isp_to_is(isp); 305 int ret = 0; 306 307 pr_debug("on: %d\n", on); 308 309 if (on) { 310 ret = pm_runtime_resume_and_get(&is->pdev->dev); 311 if (ret < 0) 312 return ret; 313 314 set_bit(IS_ST_PWR_ON, &is->state); 315 316 ret = fimc_is_start_firmware(is); 317 if (ret < 0) { 318 v4l2_err(sd, "firmware booting failed\n"); 319 pm_runtime_put(&is->pdev->dev); 320 return ret; 321 } 322 set_bit(IS_ST_PWR_SUBIP_ON, &is->state); 323 324 ret = fimc_is_hw_initialize(is); 325 } else { 326 /* Close sensor */ 327 if (!test_bit(IS_ST_PWR_ON, &is->state)) { 328 fimc_is_hw_close_sensor(is, 0); 329 330 ret = fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 0, 331 FIMC_IS_CONFIG_TIMEOUT); 332 if (ret < 0) { 333 v4l2_err(sd, "sensor close timeout\n"); 334 return ret; 335 } 336 } 337 338 /* SUB IP power off */ 339 if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) { 340 fimc_is_hw_subip_power_off(is); 341 ret = fimc_is_wait_event(is, IS_ST_PWR_SUBIP_ON, 0, 342 FIMC_IS_CONFIG_TIMEOUT); 343 if (ret < 0) { 344 v4l2_err(sd, "sub-IP power off timeout\n"); 345 return ret; 346 } 347 } 348 349 fimc_is_cpu_set_power(is, 0); 350 pm_runtime_put_sync(&is->pdev->dev); 351 352 clear_bit(IS_ST_PWR_ON, &is->state); 353 clear_bit(IS_ST_INIT_DONE, &is->state); 354 is->state = 0; 355 is->config[is->config_index].p_region_index[0] = 0; 356 is->config[is->config_index].p_region_index[1] = 0; 357 set_bit(IS_ST_IDLE, &is->state); 358 wmb(); 359 } 360 361 return ret; 362 } 363 364 static int fimc_isp_subdev_open(struct v4l2_subdev *sd, 365 struct v4l2_subdev_fh *fh) 366 { 367 struct v4l2_mbus_framefmt *format; 368 struct v4l2_mbus_framefmt fmt = { 369 .colorspace = V4L2_COLORSPACE_SRGB, 370 .code = fimc_isp_formats[0].mbus_code, 371 .width = DEFAULT_PREVIEW_STILL_WIDTH + FIMC_ISP_CAC_MARGIN_WIDTH, 372 .height = DEFAULT_PREVIEW_STILL_HEIGHT + FIMC_ISP_CAC_MARGIN_HEIGHT, 373 .field = V4L2_FIELD_NONE, 374 }; 375 376 format = v4l2_subdev_state_get_format(fh->state, FIMC_ISP_SD_PAD_SINK); 377 *format = fmt; 378 379 format = v4l2_subdev_state_get_format(fh->state, 380 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_state_get_format(fh->state, 386 FIMC_ISP_SD_PAD_SRC_DMA); 387 *format = fmt; 388 389 return 0; 390 } 391 392 static 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 408 static 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 416 static 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 422 static 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 428 static const struct v4l2_subdev_video_ops fimc_is_subdev_video_ops = { 429 .s_stream = fimc_isp_subdev_s_stream, 430 }; 431 432 static const struct v4l2_subdev_core_ops fimc_is_core_ops = { 433 .s_power = fimc_isp_subdev_s_power, 434 }; 435 436 static const 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 442 static 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 471 static 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 */ 501 static const s64 iso_qmenu[] = { 502 50, 100, 200, 400, 800, 503 }; 504 505 static 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 522 static 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 547 static 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 569 static 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 591 static 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 671 static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = { 672 .s_ctrl = fimc_is_s_ctrl, 673 }; 674 675 static 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 691 int 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 779 void 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