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