162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com> 862306a36Sopenharmony_ci * Younghwan Joo <yhwan.joo@samsung.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/list.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/printk.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <media/v4l2-device.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "media-dev.h" 2562306a36Sopenharmony_ci#include "fimc-isp-video.h" 2662306a36Sopenharmony_ci#include "fimc-is-command.h" 2762306a36Sopenharmony_ci#include "fimc-is-param.h" 2862306a36Sopenharmony_ci#include "fimc-is-regs.h" 2962306a36Sopenharmony_ci#include "fimc-is.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint fimc_isp_debug; 3262306a36Sopenharmony_cimodule_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = { 3562306a36Sopenharmony_ci { 3662306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG8, 3762306a36Sopenharmony_ci .depth = { 8 }, 3862306a36Sopenharmony_ci .color = FIMC_FMT_RAW8, 3962306a36Sopenharmony_ci .memplanes = 1, 4062306a36Sopenharmony_ci .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, 4162306a36Sopenharmony_ci }, { 4262306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG10, 4362306a36Sopenharmony_ci .depth = { 10 }, 4462306a36Sopenharmony_ci .color = FIMC_FMT_RAW10, 4562306a36Sopenharmony_ci .memplanes = 1, 4662306a36Sopenharmony_ci .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 4762306a36Sopenharmony_ci }, { 4862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG12, 4962306a36Sopenharmony_ci .depth = { 12 }, 5062306a36Sopenharmony_ci .color = FIMC_FMT_RAW12, 5162306a36Sopenharmony_ci .memplanes = 1, 5262306a36Sopenharmony_ci .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 5362306a36Sopenharmony_ci }, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/** 5762306a36Sopenharmony_ci * fimc_isp_find_format - lookup color format by fourcc or media bus code 5862306a36Sopenharmony_ci * @pixelformat: fourcc to match, ignored if null 5962306a36Sopenharmony_ci * @mbus_code: media bus code to match, ignored if null 6062306a36Sopenharmony_ci * @index: index to the fimc_isp_formats array, ignored if negative 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ciconst struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat, 6362306a36Sopenharmony_ci const u32 *mbus_code, int index) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci const struct fimc_fmt *fmt, *def_fmt = NULL; 6662306a36Sopenharmony_ci unsigned int i; 6762306a36Sopenharmony_ci int id = 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (index >= (int)ARRAY_SIZE(fimc_isp_formats)) 7062306a36Sopenharmony_ci return NULL; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fimc_isp_formats); ++i) { 7362306a36Sopenharmony_ci fmt = &fimc_isp_formats[i]; 7462306a36Sopenharmony_ci if (pixelformat && fmt->fourcc == *pixelformat) 7562306a36Sopenharmony_ci return fmt; 7662306a36Sopenharmony_ci if (mbus_code && fmt->mbus_code == *mbus_code) 7762306a36Sopenharmony_ci return fmt; 7862306a36Sopenharmony_ci if (index == id) 7962306a36Sopenharmony_ci def_fmt = fmt; 8062306a36Sopenharmony_ci id++; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci return def_fmt; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_civoid fimc_isp_irq_handler(struct fimc_is *is) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci is->i2h_cmd.args[0] = mcuctl_read(is, MCUCTL_REG_ISSR(20)); 8862306a36Sopenharmony_ci is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21)); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP); 9162306a36Sopenharmony_ci fimc_isp_video_irq_handler(is); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci wake_up(&is->irq_queue); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Capture subdev media entity operations */ 9762306a36Sopenharmony_cistatic int fimc_is_link_setup(struct media_entity *entity, 9862306a36Sopenharmony_ci const struct media_pad *local, 9962306a36Sopenharmony_ci const struct media_pad *remote, u32 flags) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const struct media_entity_operations fimc_is_subdev_media_ops = { 10562306a36Sopenharmony_ci .link_setup = fimc_is_link_setup, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, 10962306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 11062306a36Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci const struct fimc_fmt *fmt; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci fmt = fimc_isp_find_format(NULL, NULL, code->index); 11562306a36Sopenharmony_ci if (!fmt) 11662306a36Sopenharmony_ci return -EINVAL; 11762306a36Sopenharmony_ci code->code = fmt->mbus_code; 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, 12262306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 12362306a36Sopenharmony_ci struct v4l2_subdev_format *fmt) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct fimc_isp *isp = v4l2_get_subdevdata(sd); 12662306a36Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &fmt->format; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 12962306a36Sopenharmony_ci *mf = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci mf->colorspace = V4L2_COLORSPACE_SRGB; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci mutex_lock(&isp->subdev_lock); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 13862306a36Sopenharmony_ci /* ISP OTF input image format */ 13962306a36Sopenharmony_ci *mf = isp->sink_fmt; 14062306a36Sopenharmony_ci } else { 14162306a36Sopenharmony_ci /* ISP OTF output image format */ 14262306a36Sopenharmony_ci *mf = isp->src_fmt; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) { 14562306a36Sopenharmony_ci mf->colorspace = V4L2_COLORSPACE_JPEG; 14662306a36Sopenharmony_ci mf->code = MEDIA_BUS_FMT_YUV10_1X30; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci mutex_unlock(&isp->subdev_lock); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci isp_dbg(1, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n", __func__, 15362306a36Sopenharmony_ci fmt->pad, mf->code, mf->width, mf->height); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void __isp_subdev_try_format(struct fimc_isp *isp, 15962306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 16062306a36Sopenharmony_ci struct v4l2_subdev_format *fmt) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &fmt->format; 16362306a36Sopenharmony_ci struct v4l2_mbus_framefmt *format; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci mf->colorspace = V4L2_COLORSPACE_SRGB; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 16862306a36Sopenharmony_ci v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN, 16962306a36Sopenharmony_ci FIMC_ISP_SINK_WIDTH_MAX, 0, 17062306a36Sopenharmony_ci &mf->height, FIMC_ISP_SINK_HEIGHT_MIN, 17162306a36Sopenharmony_ci FIMC_ISP_SINK_HEIGHT_MAX, 0, 0); 17262306a36Sopenharmony_ci mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; 17362306a36Sopenharmony_ci } else { 17462306a36Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 17562306a36Sopenharmony_ci format = v4l2_subdev_get_try_format(&isp->subdev, 17662306a36Sopenharmony_ci sd_state, 17762306a36Sopenharmony_ci FIMC_ISP_SD_PAD_SINK); 17862306a36Sopenharmony_ci else 17962306a36Sopenharmony_ci format = &isp->sink_fmt; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Allow changing format only on sink pad */ 18262306a36Sopenharmony_ci mf->width = format->width - FIMC_ISP_CAC_MARGIN_WIDTH; 18362306a36Sopenharmony_ci mf->height = format->height - FIMC_ISP_CAC_MARGIN_HEIGHT; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) { 18662306a36Sopenharmony_ci mf->code = MEDIA_BUS_FMT_YUV10_1X30; 18762306a36Sopenharmony_ci mf->colorspace = V4L2_COLORSPACE_JPEG; 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci mf->code = format->code; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, 19562306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 19662306a36Sopenharmony_ci struct v4l2_subdev_format *fmt) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct fimc_isp *isp = v4l2_get_subdevdata(sd); 19962306a36Sopenharmony_ci struct fimc_is *is = fimc_isp_to_is(isp); 20062306a36Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &fmt->format; 20162306a36Sopenharmony_ci int ret = 0; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci isp_dbg(1, sd, "%s: pad%d: code: 0x%x, %dx%d\n", 20462306a36Sopenharmony_ci __func__, fmt->pad, mf->code, mf->width, mf->height); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci mutex_lock(&isp->subdev_lock); 20762306a36Sopenharmony_ci __isp_subdev_try_format(isp, sd_state, fmt); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 21062306a36Sopenharmony_ci mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); 21162306a36Sopenharmony_ci *mf = fmt->format; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Propagate format to the source pads */ 21462306a36Sopenharmony_ci if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 21562306a36Sopenharmony_ci struct v4l2_subdev_format format = *fmt; 21662306a36Sopenharmony_ci unsigned int pad; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci for (pad = FIMC_ISP_SD_PAD_SRC_FIFO; 21962306a36Sopenharmony_ci pad < FIMC_ISP_SD_PADS_NUM; pad++) { 22062306a36Sopenharmony_ci format.pad = pad; 22162306a36Sopenharmony_ci __isp_subdev_try_format(isp, sd_state, 22262306a36Sopenharmony_ci &format); 22362306a36Sopenharmony_ci mf = v4l2_subdev_get_try_format(sd, sd_state, 22462306a36Sopenharmony_ci pad); 22562306a36Sopenharmony_ci *mf = format.format; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci } else { 22962306a36Sopenharmony_ci if (!media_entity_is_streaming(&sd->entity)) { 23062306a36Sopenharmony_ci if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { 23162306a36Sopenharmony_ci struct v4l2_subdev_format format = *fmt; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci isp->sink_fmt = *mf; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci format.pad = FIMC_ISP_SD_PAD_SRC_DMA; 23662306a36Sopenharmony_ci __isp_subdev_try_format(isp, sd_state, 23762306a36Sopenharmony_ci &format); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci isp->src_fmt = format.format; 24062306a36Sopenharmony_ci __is_set_frame_size(is, &isp->src_fmt); 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci isp->src_fmt = *mf; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci } else { 24562306a36Sopenharmony_ci ret = -EBUSY; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci mutex_unlock(&isp->subdev_lock); 25062306a36Sopenharmony_ci return ret; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct fimc_isp *isp = v4l2_get_subdevdata(sd); 25662306a36Sopenharmony_ci struct fimc_is *is = fimc_isp_to_is(isp); 25762306a36Sopenharmony_ci int ret; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci isp_dbg(1, sd, "%s: on: %d\n", __func__, on); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!test_bit(IS_ST_INIT_DONE, &is->state)) 26262306a36Sopenharmony_ci return -EBUSY; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci fimc_is_mem_barrier(); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (on) { 26762306a36Sopenharmony_ci if (__get_pending_param_count(is)) { 26862306a36Sopenharmony_ci ret = fimc_is_itf_s_param(is, true); 26962306a36Sopenharmony_ci if (ret < 0) 27062306a36Sopenharmony_ci return ret; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci isp_dbg(1, sd, "changing mode to %d\n", is->config_index); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = fimc_is_itf_mode_change(is); 27662306a36Sopenharmony_ci if (ret) 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci clear_bit(IS_ST_STREAM_ON, &is->state); 28062306a36Sopenharmony_ci fimc_is_hw_stream_on(is); 28162306a36Sopenharmony_ci ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1, 28262306a36Sopenharmony_ci FIMC_IS_CONFIG_TIMEOUT); 28362306a36Sopenharmony_ci if (ret < 0) { 28462306a36Sopenharmony_ci v4l2_err(sd, "stream on timeout\n"); 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci } else { 28862306a36Sopenharmony_ci clear_bit(IS_ST_STREAM_OFF, &is->state); 28962306a36Sopenharmony_ci fimc_is_hw_stream_off(is); 29062306a36Sopenharmony_ci ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1, 29162306a36Sopenharmony_ci FIMC_IS_CONFIG_TIMEOUT); 29262306a36Sopenharmony_ci if (ret < 0) { 29362306a36Sopenharmony_ci v4l2_err(sd, "stream off timeout\n"); 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci is->setfile.sub_index = 0; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct fimc_isp *isp = v4l2_get_subdevdata(sd); 30562306a36Sopenharmony_ci struct fimc_is *is = fimc_isp_to_is(isp); 30662306a36Sopenharmony_ci int ret = 0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci pr_debug("on: %d\n", on); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (on) { 31162306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&is->pdev->dev); 31262306a36Sopenharmony_ci if (ret < 0) 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci set_bit(IS_ST_PWR_ON, &is->state); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci ret = fimc_is_start_firmware(is); 31862306a36Sopenharmony_ci if (ret < 0) { 31962306a36Sopenharmony_ci v4l2_err(sd, "firmware booting failed\n"); 32062306a36Sopenharmony_ci pm_runtime_put(&is->pdev->dev); 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci set_bit(IS_ST_PWR_SUBIP_ON, &is->state); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ret = fimc_is_hw_initialize(is); 32662306a36Sopenharmony_ci } else { 32762306a36Sopenharmony_ci /* Close sensor */ 32862306a36Sopenharmony_ci if (!test_bit(IS_ST_PWR_ON, &is->state)) { 32962306a36Sopenharmony_ci fimc_is_hw_close_sensor(is, 0); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ret = fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 0, 33262306a36Sopenharmony_ci FIMC_IS_CONFIG_TIMEOUT); 33362306a36Sopenharmony_ci if (ret < 0) { 33462306a36Sopenharmony_ci v4l2_err(sd, "sensor close timeout\n"); 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* SUB IP power off */ 34062306a36Sopenharmony_ci if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) { 34162306a36Sopenharmony_ci fimc_is_hw_subip_power_off(is); 34262306a36Sopenharmony_ci ret = fimc_is_wait_event(is, IS_ST_PWR_SUBIP_ON, 0, 34362306a36Sopenharmony_ci FIMC_IS_CONFIG_TIMEOUT); 34462306a36Sopenharmony_ci if (ret < 0) { 34562306a36Sopenharmony_ci v4l2_err(sd, "sub-IP power off timeout\n"); 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci fimc_is_cpu_set_power(is, 0); 35162306a36Sopenharmony_ci pm_runtime_put_sync(&is->pdev->dev); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci clear_bit(IS_ST_PWR_ON, &is->state); 35462306a36Sopenharmony_ci clear_bit(IS_ST_INIT_DONE, &is->state); 35562306a36Sopenharmony_ci is->state = 0; 35662306a36Sopenharmony_ci is->config[is->config_index].p_region_index[0] = 0; 35762306a36Sopenharmony_ci is->config[is->config_index].p_region_index[1] = 0; 35862306a36Sopenharmony_ci set_bit(IS_ST_IDLE, &is->state); 35962306a36Sopenharmony_ci wmb(); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int fimc_isp_subdev_open(struct v4l2_subdev *sd, 36662306a36Sopenharmony_ci struct v4l2_subdev_fh *fh) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct v4l2_mbus_framefmt *format; 36962306a36Sopenharmony_ci struct v4l2_mbus_framefmt fmt = { 37062306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 37162306a36Sopenharmony_ci .code = fimc_isp_formats[0].mbus_code, 37262306a36Sopenharmony_ci .width = DEFAULT_PREVIEW_STILL_WIDTH + FIMC_ISP_CAC_MARGIN_WIDTH, 37362306a36Sopenharmony_ci .height = DEFAULT_PREVIEW_STILL_HEIGHT + FIMC_ISP_CAC_MARGIN_HEIGHT, 37462306a36Sopenharmony_ci .field = V4L2_FIELD_NONE, 37562306a36Sopenharmony_ci }; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci format = v4l2_subdev_get_try_format(sd, fh->state, 37862306a36Sopenharmony_ci FIMC_ISP_SD_PAD_SINK); 37962306a36Sopenharmony_ci *format = fmt; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci format = v4l2_subdev_get_try_format(sd, fh->state, 38262306a36Sopenharmony_ci FIMC_ISP_SD_PAD_SRC_FIFO); 38362306a36Sopenharmony_ci fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; 38462306a36Sopenharmony_ci fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; 38562306a36Sopenharmony_ci *format = fmt; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci format = v4l2_subdev_get_try_format(sd, fh->state, 38862306a36Sopenharmony_ci FIMC_ISP_SD_PAD_SRC_DMA); 38962306a36Sopenharmony_ci *format = fmt; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int fimc_isp_subdev_registered(struct v4l2_subdev *sd) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct fimc_isp *isp = v4l2_get_subdevdata(sd); 39762306a36Sopenharmony_ci int ret; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Use pipeline object allocated by the media device. */ 40062306a36Sopenharmony_ci isp->video_capture.ve.pipe = v4l2_get_subdev_hostdata(sd); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci ret = fimc_isp_video_device_register(isp, sd->v4l2_dev, 40362306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 40462306a36Sopenharmony_ci if (ret < 0) 40562306a36Sopenharmony_ci isp->video_capture.ve.pipe = NULL; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic void fimc_isp_subdev_unregistered(struct v4l2_subdev *sd) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct fimc_isp *isp = v4l2_get_subdevdata(sd); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci fimc_isp_video_device_unregister(isp, 41562306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = { 41962306a36Sopenharmony_ci .registered = fimc_isp_subdev_registered, 42062306a36Sopenharmony_ci .unregistered = fimc_isp_subdev_unregistered, 42162306a36Sopenharmony_ci .open = fimc_isp_subdev_open, 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops fimc_is_subdev_pad_ops = { 42562306a36Sopenharmony_ci .enum_mbus_code = fimc_is_subdev_enum_mbus_code, 42662306a36Sopenharmony_ci .get_fmt = fimc_isp_subdev_get_fmt, 42762306a36Sopenharmony_ci .set_fmt = fimc_isp_subdev_set_fmt, 42862306a36Sopenharmony_ci}; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops fimc_is_subdev_video_ops = { 43162306a36Sopenharmony_ci .s_stream = fimc_isp_subdev_s_stream, 43262306a36Sopenharmony_ci}; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic const struct v4l2_subdev_core_ops fimc_is_core_ops = { 43562306a36Sopenharmony_ci .s_power = fimc_isp_subdev_s_power, 43662306a36Sopenharmony_ci}; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic const struct v4l2_subdev_ops fimc_is_subdev_ops = { 43962306a36Sopenharmony_ci .core = &fimc_is_core_ops, 44062306a36Sopenharmony_ci .video = &fimc_is_subdev_video_ops, 44162306a36Sopenharmony_ci .pad = &fimc_is_subdev_pad_ops, 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int __ctrl_set_white_balance(struct fimc_is *is, int value) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci switch (value) { 44762306a36Sopenharmony_ci case V4L2_WHITE_BALANCE_AUTO: 44862306a36Sopenharmony_ci __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case V4L2_WHITE_BALANCE_DAYLIGHT: 45162306a36Sopenharmony_ci __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, 45262306a36Sopenharmony_ci ISP_AWB_ILLUMINATION_DAYLIGHT); 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci case V4L2_WHITE_BALANCE_CLOUDY: 45562306a36Sopenharmony_ci __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, 45662306a36Sopenharmony_ci ISP_AWB_ILLUMINATION_CLOUDY); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case V4L2_WHITE_BALANCE_INCANDESCENT: 45962306a36Sopenharmony_ci __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, 46062306a36Sopenharmony_ci ISP_AWB_ILLUMINATION_TUNGSTEN); 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci case V4L2_WHITE_BALANCE_FLUORESCENT: 46362306a36Sopenharmony_ci __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, 46462306a36Sopenharmony_ci ISP_AWB_ILLUMINATION_FLUORESCENT); 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci default: 46762306a36Sopenharmony_ci return -EINVAL; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int __ctrl_set_aewb_lock(struct fimc_is *is, 47462306a36Sopenharmony_ci struct v4l2_ctrl *ctrl) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; 47762306a36Sopenharmony_ci bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; 47862306a36Sopenharmony_ci struct isp_param *isp = &is->is_p_region->parameter.isp; 47962306a36Sopenharmony_ci int cmd, ret; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci cmd = ae_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START; 48262306a36Sopenharmony_ci isp->aa.cmd = cmd; 48362306a36Sopenharmony_ci isp->aa.target = ISP_AA_TARGET_AE; 48462306a36Sopenharmony_ci fimc_is_set_param_bit(is, PARAM_ISP_AA); 48562306a36Sopenharmony_ci is->af.ae_lock_state = ae_lock; 48662306a36Sopenharmony_ci wmb(); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci ret = fimc_is_itf_s_param(is, false); 48962306a36Sopenharmony_ci if (ret < 0) 49062306a36Sopenharmony_ci return ret; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci cmd = awb_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START; 49362306a36Sopenharmony_ci isp->aa.cmd = cmd; 49462306a36Sopenharmony_ci isp->aa.target = ISP_AA_TARGET_AE; 49562306a36Sopenharmony_ci fimc_is_set_param_bit(is, PARAM_ISP_AA); 49662306a36Sopenharmony_ci is->af.awb_lock_state = awb_lock; 49762306a36Sopenharmony_ci wmb(); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return fimc_is_itf_s_param(is, false); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/* Supported manual ISO values */ 50362306a36Sopenharmony_cistatic const s64 iso_qmenu[] = { 50462306a36Sopenharmony_ci 50, 100, 200, 400, 800, 50562306a36Sopenharmony_ci}; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int __ctrl_set_iso(struct fimc_is *is, int value) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci unsigned int idx, iso; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (value == V4L2_ISO_SENSITIVITY_AUTO) { 51262306a36Sopenharmony_ci __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0); 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci idx = is->isp.ctrls.iso->val; 51662306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(iso_qmenu)) 51762306a36Sopenharmony_ci return -EINVAL; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci iso = iso_qmenu[idx]; 52062306a36Sopenharmony_ci __is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso); 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int __ctrl_set_metering(struct fimc_is *is, unsigned int value) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci unsigned int val; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci switch (value) { 52962306a36Sopenharmony_ci case V4L2_EXPOSURE_METERING_AVERAGE: 53062306a36Sopenharmony_ci val = ISP_METERING_COMMAND_AVERAGE; 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: 53362306a36Sopenharmony_ci val = ISP_METERING_COMMAND_CENTER; 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci case V4L2_EXPOSURE_METERING_SPOT: 53662306a36Sopenharmony_ci val = ISP_METERING_COMMAND_SPOT; 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case V4L2_EXPOSURE_METERING_MATRIX: 53962306a36Sopenharmony_ci val = ISP_METERING_COMMAND_MATRIX; 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci default: 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci __is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val); 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic int __ctrl_set_afc(struct fimc_is *is, int value) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci switch (value) { 55262306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: 55362306a36Sopenharmony_ci __is_set_isp_afc(is, ISP_AFC_COMMAND_DISABLE, 0); 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: 55662306a36Sopenharmony_ci __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 50); 55762306a36Sopenharmony_ci break; 55862306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: 55962306a36Sopenharmony_ci __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 60); 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: 56262306a36Sopenharmony_ci __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0); 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci default: 56562306a36Sopenharmony_ci return -EINVAL; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int __ctrl_set_image_effect(struct fimc_is *is, int value) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci static const u8 effects[][2] = { 57462306a36Sopenharmony_ci { V4L2_COLORFX_NONE, ISP_IMAGE_EFFECT_DISABLE }, 57562306a36Sopenharmony_ci { V4L2_COLORFX_BW, ISP_IMAGE_EFFECT_MONOCHROME }, 57662306a36Sopenharmony_ci { V4L2_COLORFX_SEPIA, ISP_IMAGE_EFFECT_SEPIA }, 57762306a36Sopenharmony_ci { V4L2_COLORFX_NEGATIVE, ISP_IMAGE_EFFECT_NEGATIVE_MONO }, 57862306a36Sopenharmony_ci { 16 /* TODO */, ISP_IMAGE_EFFECT_NEGATIVE_COLOR }, 57962306a36Sopenharmony_ci }; 58062306a36Sopenharmony_ci int i; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(effects); i++) { 58362306a36Sopenharmony_ci if (effects[i][0] != value) 58462306a36Sopenharmony_ci continue; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci __is_set_isp_effect(is, effects[i][1]); 58762306a36Sopenharmony_ci return 0; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return -EINVAL; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl); 59662306a36Sopenharmony_ci struct fimc_is *is = fimc_isp_to_is(isp); 59762306a36Sopenharmony_ci bool set_param = true; 59862306a36Sopenharmony_ci int ret = 0; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci switch (ctrl->id) { 60162306a36Sopenharmony_ci case V4L2_CID_CONTRAST: 60262306a36Sopenharmony_ci __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, 60362306a36Sopenharmony_ci ctrl->val); 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci case V4L2_CID_SATURATION: 60762306a36Sopenharmony_ci __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION, 60862306a36Sopenharmony_ci ctrl->val); 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci case V4L2_CID_SHARPNESS: 61262306a36Sopenharmony_ci __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS, 61362306a36Sopenharmony_ci ctrl->val); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci case V4L2_CID_EXPOSURE_ABSOLUTE: 61762306a36Sopenharmony_ci __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE, 61862306a36Sopenharmony_ci ctrl->val); 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 62262306a36Sopenharmony_ci __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS, 62362306a36Sopenharmony_ci ctrl->val); 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci case V4L2_CID_HUE: 62762306a36Sopenharmony_ci __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, 62862306a36Sopenharmony_ci ctrl->val); 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci case V4L2_CID_EXPOSURE_METERING: 63262306a36Sopenharmony_ci ret = __ctrl_set_metering(is, ctrl->val); 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: 63662306a36Sopenharmony_ci ret = __ctrl_set_white_balance(is, ctrl->val); 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci case V4L2_CID_3A_LOCK: 64062306a36Sopenharmony_ci ret = __ctrl_set_aewb_lock(is, ctrl); 64162306a36Sopenharmony_ci set_param = false; 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci case V4L2_CID_ISO_SENSITIVITY_AUTO: 64562306a36Sopenharmony_ci ret = __ctrl_set_iso(is, ctrl->val); 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY: 64962306a36Sopenharmony_ci ret = __ctrl_set_afc(is, ctrl->val); 65062306a36Sopenharmony_ci break; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci case V4L2_CID_COLORFX: 65362306a36Sopenharmony_ci __ctrl_set_image_effect(is, ctrl->val); 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci ret = -EINVAL; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (ret < 0) { 66262306a36Sopenharmony_ci v4l2_err(&isp->subdev, "Failed to set control: %s (%d)\n", 66362306a36Sopenharmony_ci ctrl->name, ctrl->val); 66462306a36Sopenharmony_ci return ret; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (set_param && test_bit(IS_ST_STREAM_ON, &is->state)) 66862306a36Sopenharmony_ci return fimc_is_itf_s_param(is, true); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = { 67462306a36Sopenharmony_ci .s_ctrl = fimc_is_s_ctrl, 67562306a36Sopenharmony_ci}; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic void __isp_subdev_set_default_format(struct fimc_isp *isp) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct fimc_is *is = fimc_isp_to_is(isp); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci isp->sink_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH + 68262306a36Sopenharmony_ci FIMC_ISP_CAC_MARGIN_WIDTH; 68362306a36Sopenharmony_ci isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT + 68462306a36Sopenharmony_ci FIMC_ISP_CAC_MARGIN_HEIGHT; 68562306a36Sopenharmony_ci isp->sink_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; 68862306a36Sopenharmony_ci isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; 68962306a36Sopenharmony_ci isp->src_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10; 69062306a36Sopenharmony_ci __is_set_frame_size(is, &isp->src_fmt); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ciint fimc_isp_subdev_create(struct fimc_isp *isp) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops; 69662306a36Sopenharmony_ci struct v4l2_ctrl_handler *handler = &isp->ctrls.handler; 69762306a36Sopenharmony_ci struct v4l2_subdev *sd = &isp->subdev; 69862306a36Sopenharmony_ci struct fimc_isp_ctrls *ctrls = &isp->ctrls; 69962306a36Sopenharmony_ci int ret; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci mutex_init(&isp->subdev_lock); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci v4l2_subdev_init(sd, &fimc_is_subdev_ops); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci sd->owner = THIS_MODULE; 70662306a36Sopenharmony_ci sd->grp_id = GRP_ID_FIMC_IS; 70762306a36Sopenharmony_ci sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 70862306a36Sopenharmony_ci snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP"); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; 71162306a36Sopenharmony_ci isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 71262306a36Sopenharmony_ci isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE; 71362306a36Sopenharmony_ci isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE; 71462306a36Sopenharmony_ci ret = media_entity_pads_init(&sd->entity, FIMC_ISP_SD_PADS_NUM, 71562306a36Sopenharmony_ci isp->subdev_pads); 71662306a36Sopenharmony_ci if (ret) 71762306a36Sopenharmony_ci return ret; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci v4l2_ctrl_handler_init(handler, 20); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION, 72262306a36Sopenharmony_ci -2, 2, 1, 0); 72362306a36Sopenharmony_ci ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS, 72462306a36Sopenharmony_ci -4, 4, 1, 0); 72562306a36Sopenharmony_ci ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST, 72662306a36Sopenharmony_ci -2, 2, 1, 0); 72762306a36Sopenharmony_ci ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS, 72862306a36Sopenharmony_ci -2, 2, 1, 0); 72962306a36Sopenharmony_ci ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE, 73062306a36Sopenharmony_ci -2, 2, 1, 0); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops, 73362306a36Sopenharmony_ci V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, 73462306a36Sopenharmony_ci 8, ~0x14e, V4L2_WHITE_BALANCE_AUTO); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci ctrls->exposure = v4l2_ctrl_new_std(handler, ops, 73762306a36Sopenharmony_ci V4L2_CID_EXPOSURE_ABSOLUTE, 73862306a36Sopenharmony_ci -4, 4, 1, 0); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops, 74162306a36Sopenharmony_ci V4L2_CID_EXPOSURE_METERING, 3, 74262306a36Sopenharmony_ci ~0xf, V4L2_EXPOSURE_METERING_AVERAGE); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY, 74562306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 74662306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_AUTO); 74762306a36Sopenharmony_ci /* ISO sensitivity */ 74862306a36Sopenharmony_ci ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops, 74962306a36Sopenharmony_ci V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0, 75062306a36Sopenharmony_ci V4L2_ISO_SENSITIVITY_AUTO); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops, 75362306a36Sopenharmony_ci V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, 75462306a36Sopenharmony_ci ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops, 75762306a36Sopenharmony_ci V4L2_CID_3A_LOCK, 0, 0x3, 0, 0); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* TODO: Add support for NEGATIVE_COLOR option */ 76062306a36Sopenharmony_ci ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX, 76162306a36Sopenharmony_ci V4L2_COLORFX_SET_CBCR + 1, ~0x1000f, V4L2_COLORFX_NONE); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (handler->error) { 76462306a36Sopenharmony_ci media_entity_cleanup(&sd->entity); 76562306a36Sopenharmony_ci return handler->error; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 76962306a36Sopenharmony_ci V4L2_ISO_SENSITIVITY_MANUAL, false); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci sd->ctrl_handler = handler; 77262306a36Sopenharmony_ci sd->internal_ops = &fimc_is_subdev_internal_ops; 77362306a36Sopenharmony_ci sd->entity.ops = &fimc_is_subdev_media_ops; 77462306a36Sopenharmony_ci v4l2_set_subdevdata(sd, isp); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci __isp_subdev_set_default_format(isp); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_civoid fimc_isp_subdev_destroy(struct fimc_isp *isp) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct v4l2_subdev *sd = &isp->subdev; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci v4l2_device_unregister_subdev(sd); 78662306a36Sopenharmony_ci media_entity_cleanup(&sd->entity); 78762306a36Sopenharmony_ci v4l2_ctrl_handler_free(&isp->ctrls.handler); 78862306a36Sopenharmony_ci v4l2_set_subdevdata(sd, NULL); 78962306a36Sopenharmony_ci} 790