// SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020 MediaTek Inc. #include #include #include "kd_imgsensor_define_v4l2.h" #include "adaptor.h" #include "adaptor-i2c.h" #include "adaptor-ctrls.h" #include "adaptor-common-ctrl.h" #include "adaptor-fsync-ctrls.h" #include "adaptor-hw.h" #include "adaptor-trace.h" #define ctrl_to_ctx(ctrl) \ container_of(ctrl->handler, struct adaptor_ctx, ctrls) #define sizeof_u32(__struct_name__) (sizeof(__struct_name__) / sizeof(u32)) #define sizeof_u16(__struct_name__) (sizeof(__struct_name__) / sizeof(u16)) #ifdef V4L2_CID_PD_PIXEL_REGION static int g_pd_pixel_region(struct adaptor_ctx *ctx, struct v4l2_ctrl *ctrl) { struct SET_PD_BLOCK_INFO_T pd; struct v4l2_ctrl_image_pd_pixel_region region; union feature_para para; u32 i, len = 0; para.u64[0] = ctx->cur_mode->id; para.u64[1] = (u64)&pd; memset(&pd, 0, sizeof(pd)); subdrv_call(ctx, feature_control, SENSOR_FEATURE_GET_PDAF_INFO, para.u8, &len); if (!pd.i4BlockNumX || !pd.i4BlockNumY) return -EINVAL; region.offset_x = pd.i4OffsetX; region.offset_y = pd.i4OffsetY; region.pitch_x = pd.i4PitchX; region.pitch_y = pd.i4PitchY; region.pair_num = pd.i4PairNum; region.subblk_w = pd.i4SubBlkW; region.subblk_h = pd.i4SubBlkH; for (i = 0; i < ARRAY_SIZE(region.posL); i++) { region.posL[i][0] = pd.i4PosL[i][0]; region.posL[i][1] = pd.i4PosL[i][1]; region.posR[i][0] = pd.i4PosR[i][0]; region.posR[i][1] = pd.i4PosR[i][1]; } region.blk_num_x = pd.i4BlockNumX; region.blk_num_y = pd.i4BlockNumY; region.mirror_flip = pd.iMirrorFlip; region.crop_x = pd.i4Crop[ctx->cur_mode->id][0]; region.crop_y = pd.i4Crop[ctx->cur_mode->id][1]; memcpy(ctrl->p_new.p_image_pd_pixel_region, ®ion, sizeof(region)); return 0; } #endif static void dump_perframe_info(struct adaptor_ctx *ctx, struct mtk_hdr_ae *ae_ctrl) { dev_info(ctx->dev, "[%s][%s] sensor_idx %d, req id %d, sof_cnt:%u, exposure[LLLE->SSSE] %d %d %d %d %d ana_gain[LLLE->SSSE] %d %d %d %d %d, w(%d/%d/%d/%d/%d,%d/%d/%d/%d/%d) sub_tag:%u, fl:%u, min_fl:%u, flick_en:%u, mode:(line_time:%u, margin:%u, scen:%u; STG:(readout_l:%u, read_margin:%u, ext_fl:%u, fast_mode:%u))\n", ctx->sd.name, (ctx->subdrv) ? (ctx->subdrv->name) : "null", ctx->idx, ae_ctrl->req_id, ctx->sof_cnt, ae_ctrl->exposure.le_exposure, ae_ctrl->exposure.me_exposure, ae_ctrl->exposure.se_exposure, ae_ctrl->exposure.sse_exposure, ae_ctrl->exposure.ssse_exposure, ae_ctrl->gain.le_gain, ae_ctrl->gain.me_gain, ae_ctrl->gain.se_gain, ae_ctrl->gain.sse_gain, ae_ctrl->gain.ssse_gain, ae_ctrl->w_exposure.le_exposure, ae_ctrl->w_exposure.me_exposure, ae_ctrl->w_exposure.se_exposure, ae_ctrl->w_exposure.sse_exposure, ae_ctrl->w_exposure.ssse_exposure, ae_ctrl->w_gain.le_gain, ae_ctrl->w_gain.me_gain, ae_ctrl->w_gain.se_gain, ae_ctrl->w_gain.sse_gain, ae_ctrl->w_gain.ssse_gain, ae_ctrl->subsample_tags, ctx->subctx.frame_length, ctx->subctx.min_frame_length, ctx->subctx.autoflicker_en, CALC_LINE_TIME_IN_NS(ctx->subctx.pclk, ctx->subctx.line_length), ctx->subctx.margin, ctx->subctx.current_scenario_id, ctx->subctx.readout_length, ctx->subctx.read_margin, ctx->subctx.extend_frame_length_en, ctx->subctx.fast_mode_on); } static int set_hdr_exposure_tri(struct adaptor_ctx *ctx, struct mtk_hdr_exposure *info) { union feature_para para; u32 len = 0; int ret = 0; para.u64[0] = info->le_exposure; para.u64[1] = info->me_exposure; para.u64[2] = info->se_exposure; ret = chk_s_exp_with_fl_by_fsync_mgr(ctx, info->arr, 3); if (!ret) { /* NOT enable frame-sync || using HW sync solution */ subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_HDR_TRI_SHUTTER, para.u8, &len); } notify_fsync_mgr_set_shutter(ctx, info->arr, 3, ret); return 0; } static void get_dispatch_gain(struct adaptor_ctx *ctx, u32 tgain, u32 *again, u32 *dgain) { int i; u32 ag = tgain; u32 dg = 0; u32 dig_gain_step = ctx->subctx.s_ctx.dig_gain_step; u32 *ana_gain_table = ctx->subctx.s_ctx.ana_gain_table; u32 ana_gain_table_size = ctx->subctx.s_ctx.ana_gain_table_size; u32 ana_gain_table_cnt = 0; if (dig_gain_step && ana_gain_table && (tgain > ana_gain_table[0])) { ana_gain_table_cnt = (ana_gain_table_size / sizeof(ana_gain_table[0])); for (i = 1; i < ana_gain_table_cnt; i++) { if (ana_gain_table[i] > tgain) { ag = ana_gain_table[i - 1]; dg = (u32) ((u64)tgain * BASE_DGAIN / ag); break; } } if (i == ana_gain_table_cnt) { ag = ana_gain_table[i - 1]; dg = (u32) ((u64)tgain * BASE_DGAIN / ag); } } if (again) *again = ag; if (dgain) *dgain = dg; #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "again tlb cnt = %u sz(%u), gain(t/a/d) = %u / %u / %u\n", ana_gain_table_cnt, ana_gain_table_size, tgain, ag, dg); #endif } static int set_hdr_gain_tri(struct adaptor_ctx *ctx, struct mtk_hdr_gain *info) { union feature_para para; u32 len = 0; u32 again_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0}; u32 dgain_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0}; get_dispatch_gain(ctx, info->le_gain, again_exp, dgain_exp); get_dispatch_gain(ctx, info->me_gain, again_exp + 1, dgain_exp + 1); get_dispatch_gain(ctx, info->se_gain, again_exp + 2, dgain_exp + 2); // Set dig gain para.u64[0] = (u64)dgain_exp; para.u64[1] = 3; para.u64[2] = 0; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_MULTI_DIG_GAIN, para.u8, &len); // Set ana gain para.u64[0] = again_exp[0]; para.u64[1] = again_exp[1]; para.u64[2] = again_exp[2]; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_HDR_TRI_GAIN, para.u8, &len); return 0; } static int set_hdr_exposure_dual(struct adaptor_ctx *ctx, struct mtk_hdr_exposure *info) { union feature_para para; u32 len = 0; int ret = 0; para.u64[0] = info->le_exposure; para.u64[1] = info->me_exposure; // temporailly workaround, 2 exp should be NE/SE ret = chk_s_exp_with_fl_by_fsync_mgr(ctx, info->arr, 2); if (!ret) { /* NOT enable frame-sync || using HW sync solution */ subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_HDR_SHUTTER, para.u8, &len); } notify_fsync_mgr_set_shutter(ctx, info->arr, 2, ret); return 0; } static int set_hdr_gain_dual(struct adaptor_ctx *ctx, struct mtk_hdr_gain *info) { union feature_para para; u32 len = 0; u32 again_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0}; u32 dgain_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0}; get_dispatch_gain(ctx, info->le_gain, again_exp, dgain_exp); // temporailly workaround, 2 exp should be NE/SE get_dispatch_gain(ctx, info->me_gain, again_exp + 1, dgain_exp + 1); // Set dig gain para.u64[0] = (u64)dgain_exp; para.u64[1] = 2; para.u64[2] = 0; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_MULTI_DIG_GAIN, para.u8, &len); // Set ana gain para.u64[0] = again_exp[0]; para.u64[1] = again_exp[1]; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_DUAL_GAIN, para.u8, &len); return 0; } static int do_set_ae_ctrl(struct adaptor_ctx *ctx, struct mtk_hdr_ae *ae_ctrl) { union feature_para para; u32 len = 0, exp_count = 0, scenario_exp_cnt = 0; #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "[%s]+\n", __func__); #endif /* update ctx req id */ ctx->req_id = ae_ctrl->req_id; ctx->subctx.ae_ctrl_gph_en = 1; while (exp_count < IMGSENSOR_STAGGER_EXPOSURE_CNT && ae_ctrl->exposure.arr[exp_count] != 0) exp_count++; /* get scenario exp_cnt */ scenario_exp_cnt = g_scenario_exposure_cnt(ctx, ctx->cur_mode->id); if (scenario_exp_cnt != exp_count) { dev_info(ctx->dev, "warn: scenario_exp_cnt=%u, but ae_exp_count=%u\n", scenario_exp_cnt, exp_count); exp_count = scenario_exp_cnt; } switch (exp_count) { case 3: { ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_exposure_tri"); set_hdr_exposure_tri(ctx, &ae_ctrl->exposure); ADAPTOR_SYSTRACE_END(); ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_gain_tri"); set_hdr_gain_tri(ctx, &ae_ctrl->gain); ADAPTOR_SYSTRACE_END(); } break; case 2: { ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_exposure_dual"); set_hdr_exposure_dual(ctx, &ae_ctrl->exposure); ADAPTOR_SYSTRACE_END(); ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_gain_dual"); set_hdr_gain_dual(ctx, &ae_ctrl->gain); ADAPTOR_SYSTRACE_END(); } break; case 1: default: { u32 fsync_exp[1] = {0}; /* needed by fsync set_shutter */ int ret = 0; u32 again_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0}; u32 dgain_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0}; /* notify subsample tags if set */ if (ae_ctrl->subsample_tags) { notify_fsync_mgr_subsample_tag(ctx, ae_ctrl->subsample_tags); } ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_exposure"); fsync_exp[0] = ae_ctrl->exposure.le_exposure; ret = chk_s_exp_with_fl_by_fsync_mgr(ctx, fsync_exp, 1); if (!ret) { /* NOT enable frame-sync || using HW sync solution */ para.u64[0] = ae_ctrl->exposure.le_exposure; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_ESHUTTER, para.u8, &len); } notify_fsync_mgr_set_shutter(ctx, fsync_exp, 1, ret); ADAPTOR_SYSTRACE_END(); get_dispatch_gain(ctx, ae_ctrl->gain.le_gain, again_exp, dgain_exp); // Set dig gain para.u64[0] = (u64)dgain_exp; para.u64[1] = 1; para.u64[2] = 0; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_MULTI_DIG_GAIN, para.u8, &len); // Set ana gain para.u64[0] = again_exp[0]; para.u64[1] = 0; para.u64[2] = 0; ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_gain"); subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_GAIN, para.u8, &len); ADAPTOR_SYSTRACE_END(); } break; } if (ae_ctrl->actions & IMGSENSOR_EXTEND_FRAME_LENGTH_TO_DOL) { para.u64[0] = 0; ADAPTOR_SYSTRACE_BEGIN("imgsensor::set_extend_frame_length"); subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_SEAMLESS_EXTEND_FRAME_LENGTH, para.u8, &len); ADAPTOR_SYSTRACE_END(); notify_fsync_mgr_set_extend_framelength(ctx, para.u64[0]); } ctx->exposure->val = ae_ctrl->exposure.le_exposure; ctx->analogue_gain->val = ae_ctrl->gain.le_gain; ctx->subctx.ae_ctrl_gph_en = 0; dump_perframe_info(ctx, ae_ctrl); #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "[%s]-\n", __func__); #endif return 0; } static int s_ae_ctrl(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); struct mtk_hdr_ae *ae_ctrl = ctrl->p_new.p; memcpy(&ctx->ae_memento, ae_ctrl, sizeof(ctx->ae_memento)); if (!ctx->is_streaming) { /* update timeout value upon streaming off */ ctx->shutter_for_timeout = ctx->ae_memento.exposure.le_exposure; if (ctx->cur_mode->fine_intg_line) ctx->shutter_for_timeout /= 1000; dev_info(ctx->dev, "%s streaming off, set restore ae_ctrl later\n", __func__); return 0; } return do_set_ae_ctrl(ctx, ae_ctrl); } static int _sensor_reset_s_stream(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); u64 data[4]; u32 len; //dev_info(ctx->dev, "%s val: %d, stream_off_state: %d\n", // __func__, ctrl->val, // ctx->is_sensor_reset_stream_off); if (ctrl->val && ctx->is_sensor_reset_stream_off) { subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_STREAMING_RESUME, (u8 *)data, &len); ctx->is_sensor_reset_stream_off = 0; } else if (!ctrl->val) { ctx->is_sensor_reset_stream_off = 1; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_STREAMING_SUSPEND, (u8 *)data, &len); } return 0; } static int g_volatile_temperature(struct adaptor_ctx *ctx, struct v4l2_ctrl *ctrl) { union feature_para para; u32 len = 0; if (ctx->is_streaming) { subdrv_call(ctx, feature_control, SENSOR_FEATURE_GET_TEMPERATURE_VALUE, para.u8, &len); if (len) *ctrl->p_new.p_s32 = para.u32[0]; } else *ctrl->p_new.p_s32 = THERMAL_TEMP_INVALID; return 0; } static int _get_frame_desc(struct adaptor_ctx *ctx, unsigned int pad, struct mtk_mbus_frame_desc *fd) { /* default -1 is the same as subdrv_call get_frame_desc */ int ret = -1; // struct adaptor_ctx *ctx = to_ctx(sd); u64 desc_visited = 0x0; int write_to = 0, i = -1, j = 0; while (i < SENSOR_SCENARIO_ID_MAX) { struct mtk_mbus_frame_desc fd_tmp = {0}; u32 scenario_id = (-1 == i) ? ctx->cur_mode->id : ctx->seamless_scenarios[i]; if (scenario_id == SENSOR_SCENARIO_ID_NONE) break; ret = subdrv_call(ctx, get_frame_desc, scenario_id, &fd_tmp); if (!ret) { for (j = 0; write_to < MTK_FRAME_DESC_ENTRY_MAX && j < fd_tmp.num_entries; ++j) { if (desc_visited & ((u64)(0x1) << fd_tmp.entry[j].bus.csi2.user_data_desc)) continue; dev_info(ctx->dev, "[%s] scenario %u desc %d/%d/%d/%d\n", __func__, scenario_id, fd_tmp.entry[j].bus.csi2.user_data_desc, i, j, fd_tmp.num_entries); memcpy(&fd->entry[write_to++], &fd_tmp.entry[j], sizeof(struct mtk_mbus_frame_desc_entry)); desc_visited |= ((u64)(0x1) << fd_tmp.entry[j].bus.csi2.user_data_desc); } } ++i; } fd->num_entries = write_to; fd->type = MTK_MBUS_FRAME_DESC_TYPE_CSI2; return ret; } static const char * const state_names[] = { ADAPTOR_STATE_NAMES }; static int _aov_switch_i2c_bus_scl_aux(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); int ret = 0; enum mtk_cam_sensor_i2c_bus_scl aux = (enum mtk_cam_sensor_i2c_bus_scl)ctrl->val; // aux as aux function number corresponding to gpio table. switch (aux) { case SCL4: { if ((ctx->state[STATE_SCL_AP] == NULL) || IS_ERR(ctx->state[STATE_SCL_AP])) { dev_info(ctx->dev, "[%s] no such state(%s)(fail)\n", __func__, state_names[STATE_SCL_AP]); return -EINVAL; } ret = pinctrl_select_state(ctx->pinctrl, ctx->state[STATE_SCL_AP]); if (ret < 0) { dev_info(ctx->dev, "[%s] select(%s)(fail)\n", __func__, state_names[STATE_SCL_AP]); return ret; } dev_info(ctx->dev, "[%s] select(%s)(correct)\n", __func__, state_names[STATE_SCL_AP]); ctx->aov_i2c_bus_scl_switch_en = 0; } break; case SCL7: { if ((ctx->state[STATE_SCL_SCP] == NULL) || IS_ERR(ctx->state[STATE_SCL_SCP])) { dev_info(ctx->dev, "[%s] no such state(%s)(fail)\n", __func__, state_names[STATE_SCL_SCP]); return -EINVAL; } ret = pinctrl_select_state(ctx->pinctrl, ctx->state[STATE_SCL_SCP]); if (ret < 0) { dev_info(ctx->dev, "[%s] select(%s)(fail)\n", __func__, state_names[STATE_SCL_SCP]); return ret; } dev_info(ctx->dev, "[%s] select(%s)(correct)\n", __func__, state_names[STATE_SCL_SCP]); ctx->aov_i2c_bus_scl_switch_en = 1; } break; default: dev_info(ctx->dev, "[%s] i2c bus aux function not support(%d)\n", __func__, ctrl->val); return -EINVAL; } return 0; } static int _aov_switch_i2c_bus_sda_aux(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); int ret = 0; enum mtk_cam_sensor_i2c_bus_sda aux = (enum mtk_cam_sensor_i2c_bus_sda)ctrl->val; // aux as aux function number corresponding to gpio table. switch (aux) { case SDA4: { if ((ctx->state[STATE_SDA_AP] == NULL) || IS_ERR(ctx->state[STATE_SDA_AP])) { dev_info(ctx->dev, "[%s] no such state(%s)(fail)\n", __func__, state_names[STATE_SDA_AP]); return -EINVAL; } ret = pinctrl_select_state(ctx->pinctrl, ctx->state[STATE_SDA_AP]); if (ret < 0) { dev_info(ctx->dev, "[%s] select(%s)(fail)\n", __func__, state_names[STATE_SDA_AP]); return ret; } dev_info(ctx->dev, "[%s] select(%s)(correct)\n", __func__, state_names[STATE_SDA_AP]); ctx->aov_i2c_bus_sda_switch_en = 0; } break; case SDA7: { if ((ctx->state[STATE_SDA_SCP] == NULL) || IS_ERR(ctx->state[STATE_SDA_SCP])) { dev_info(ctx->dev, "[%s] no such state(%s)(fail)\n", __func__, state_names[STATE_SDA_SCP]); return -EINVAL; } ret = pinctrl_select_state(ctx->pinctrl, ctx->state[STATE_SDA_SCP]); if (ret < 0) { dev_info(ctx->dev, "[%s] select(%s)(fail)\n", __func__, state_names[STATE_SDA_SCP]); return ret; } dev_info(ctx->dev, "[%s] select(%s)(correct)\n", __func__, state_names[STATE_SDA_SCP]); ctx->aov_i2c_bus_sda_switch_en = 1; } break; default: dev_info(ctx->dev, "[%s] i2c bus aux function not support(%d)\n", __func__, ctrl->val); return -EINVAL; } return 0; } static int _aov_switch_rx_param(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); enum mtk_cam_seninf_csi_clk_for_param csi_clk = (enum mtk_cam_seninf_csi_clk_for_param)ctrl->val; union feature_para para; u32 len; struct sensor_mode *mode; u32 i = 0; switch (csi_clk) { case CSI_CLK_130: para.u32[0] = 130; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_AOV_CSI_CLK, para.u8, &len); dev_info(ctx->dev, "[%s] csi clk select(%u)\n", __func__, csi_clk); /* update mode csi_param */ for (i = SENSOR_SCENARIO_ID_MIN; i < SENSOR_SCENARIO_ID_MAX; i++) { mode = &ctx->mode[i]; mode->id = i; subdrv_call(ctx, get_csi_param, mode->id, &mode->csi_param); } dev_info(ctx->dev, "[%s] update mode csi_param(done)\n", __func__); break; case CSI_CLK_242: para.u32[0] = 242; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_AOV_CSI_CLK, para.u8, &len); dev_info(ctx->dev, "[%s] csi clk select(%u)\n", __func__, csi_clk); /* update mode csi_param */ for (i = SENSOR_SCENARIO_ID_MIN; i < SENSOR_SCENARIO_ID_MAX; i++) { mode = &ctx->mode[i]; mode->id = i; subdrv_call(ctx, get_csi_param, mode->id, &mode->csi_param); } dev_info(ctx->dev, "[%s] update mode csi_param(done)\n", __func__); break; default: dev_info(ctx->dev, "[%s] csi clk not support(%d)\n", __func__, ctrl->val); return -EINVAL; } return 0; } static int _aov_switch_pm_ops(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); enum mtk_cam_sensor_pm_ops pm_ops = (enum mtk_cam_sensor_pm_ops)ctrl->val; switch (pm_ops) { case AOV_PM_RELAX: if (ctx->aov_pm_ops_flag == 1) { ctx->aov_pm_ops_flag = 0; __pm_relax(ctx->sensor_ws); dev_info(ctx->dev, "[%s] switch to __pm_relax(correct),pm_ops_flag(%d)\n", __func__, ctx->aov_pm_ops_flag); } else dev_info(ctx->dev, "[%s] switch to __pm_relax(no need),pm_ops_flag(%d)\n", __func__, ctx->aov_pm_ops_flag); break; case AOV_PM_STAY_AWAKE: if (ctx->aov_pm_ops_flag == 0) { ctx->aov_pm_ops_flag = 1; __pm_stay_awake(ctx->sensor_ws); dev_info(ctx->dev, "[%s] switch to __pm_stay_awake(correct),pm_ops_flag(%d)\n", __func__, ctx->aov_pm_ops_flag); } else dev_info(ctx->dev, "[%s] switch to __pm_stay_awake(no need),pm_ops_flag(%d)\n", __func__, ctx->aov_pm_ops_flag); break; case AOV_ABNORMAL_FORCE_SENSOR_PWR_OFF: adaptor_hw_power_off(ctx); dev_info(ctx->dev, "[%s] adaptor_hw_power_off(done)", __func__); break; case AOV_ABNORMAL_FORCE_SENSOR_PWR_ON: adaptor_hw_power_on(ctx); dev_info(ctx->dev, "[%s] adaptor_hw_power_on(done)", __func__); break; default: dev_info(ctx->dev, "[%s] function not support(%d)\n", __func__, ctrl->val); return -EINVAL; } return 0; } static u32 get_line_d(struct adaptor_ctx *ctx, u64 linetime_in_ns_readout, u64 linetime_in_ns) { u32 line_d = 0; if (linetime_in_ns > 0) { line_d = ((linetime_in_ns_readout / linetime_in_ns) + (linetime_in_ns_readout % linetime_in_ns > 0 ? 1 : 0)); } if (!line_d) line_d = 1; #if IMGSENSOR_LOG_MORE adaptor_logd(ctx, "%llu|%llu|%u\n", linetime_in_ns_readout, linetime_in_ns, line_d); #endif return line_d; } u32 get_mode_vb(struct adaptor_ctx *ctx, const struct sensor_mode *mode) { u32 vb, line_d = 1; if (mode->linetime_in_ns_readout > mode->linetime_in_ns) { line_d = get_line_d(ctx, mode->linetime_in_ns_readout, mode->linetime_in_ns); vb = (mode->fll / line_d) - mode->height; } else { vb = mode->fll - mode->height; } adaptor_logd(ctx, "vb %u|%llu|%llu|%u|%u\n", vb, mode->linetime_in_ns_readout, mode->linetime_in_ns, mode->fll, line_d); return vb; } static int ext_ctrl(struct adaptor_ctx *ctx, struct v4l2_ctrl *ctrl, struct sensor_mode *mode) { int ret = 0; if (mode == NULL) return -EINVAL; switch (ctrl->id) { case V4L2_CID_MTK_SENSOR_IDX: ctrl->val = ctx->idx; break; case V4L2_CID_MTK_SOF_TIMEOUT_VALUE: if (ctx->shutter_for_timeout != 0) { u64 tmp = mode->linetime_in_ns * ctx->shutter_for_timeout; ctrl->val = tmp / 1000; } dev_info(ctx->dev, "[%s][%s] sof timeout value in us %d|%llu|%d|%d\n", __func__, (ctx->subdrv) ? (ctx->subdrv->name) : "null", ctx->shutter_for_timeout, mode->linetime_in_ns, ctrl->val, 10000000 / mode->max_framerate); if (ctrl->val < (10000000 / mode->max_framerate)) ctrl->val = 10000000 / mode->max_framerate; break; case V4L2_CID_VBLANK: ctrl->val = get_mode_vb(ctx, mode); break; case V4L2_CID_HBLANK: ctrl->val = (((mode->linetime_in_ns_readout * mode->mipi_pixel_rate)/1000000000) - mode->width); if (ctrl->val < 1) ctrl->val = 1; break; case V4L2_CID_MTK_SENSOR_PIXEL_RATE: ctrl->val = mode->mipi_pixel_rate; break; case V4L2_CID_MTK_CUST_SENSOR_PIXEL_RATE: ctrl->val = mode->cust_pixel_rate; break; case V4L2_CID_MTK_STAGGER_INFO: { struct mtk_stagger_info *info = ctrl->p_new.p; g_stagger_info(ctx, mode->id, info); } break; case V4L2_CID_MTK_FRAME_DESC: { struct mtk_mbus_frame_desc *fd = ctrl->p_new.p; _get_frame_desc(ctx, 0, fd); } break; case V4L2_CID_MTK_CSI_PARAM: { struct mtk_csi_param *csi_param = ctrl->p_new.p; if (csi_param) { csi_param->cphy_settle = mode->csi_param.cphy_settle; csi_param->dphy_clk_settle = mode->csi_param.dphy_clk_settle; csi_param->dphy_data_settle = mode->csi_param.dphy_data_settle; csi_param->dphy_trail = mode->csi_param.dphy_trail; csi_param->legacy_phy = mode->csi_param.legacy_phy; csi_param->not_fixed_trail_settle = mode->csi_param.not_fixed_trail_settle; csi_param->dphy_csi2_resync_dmy_cycle = mode->csi_param.dphy_csi2_resync_dmy_cycle; if (!mode->csi_param.not_fixed_dphy_settle) csi_param->not_fixed_dphy_settle = 0; else csi_param->not_fixed_dphy_settle = mode->csi_param.not_fixed_dphy_settle; } } break; case V4L2_CID_MTK_SENSOR_RESET_BY_USER: ctrl->val = mode->esd_reset_by_user; break; default: break; } return ret; } static int imgsensor_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { int ret = 0; struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); switch (ctrl->id) { #ifdef V4L2_CID_PD_PIXEL_REGION case V4L2_CID_PD_PIXEL_REGION: ret = g_pd_pixel_region(ctx, ctrl); break; #endif case V4L2_CID_MTK_TEMPERATURE: ret = g_volatile_temperature(ctx, ctrl); break; default: ret = ext_ctrl(ctx, ctrl, ctx->cur_mode); break; } return ret; } static int imgsensor_try_ctrl(struct v4l2_ctrl *ctrl) { int ret = 0; struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); switch (ctrl->id) { case V4L2_CID_MAX_EXP_TIME: { struct mtk_stagger_max_exp_time *info = ctrl->p_new.p; g_max_exposure(ctx, ctx->try_format_mode->id, info); } break; case V4L2_CID_STAGGER_TARGET_SCENARIO: { struct mtk_stagger_target_scenario *info = ctrl->p_new.p; g_stagger_scenario(ctx, ctx->try_format_mode->id, info); } break; case V4L2_CID_MTK_SENSOR_STATIC_PARAM: { struct mtk_sensor_static_param *info = ctrl->p_new.p; u32 val, len; union feature_para para; if (info->scenario_id < ctx->mode_cnt) { struct sensor_mode *mode = &ctx->mode[info->scenario_id]; para.u64[0] = info->scenario_id; para.u64[1] = (u64)&val; subdrv_call(ctx, feature_control, SENSOR_FEATURE_GET_DEFAULT_FRAME_RATE_BY_SCENARIO, para.u8, &len); info->fps = val / 10; info->vblank = get_mode_vb(ctx, mode); info->hblank = (((mode->linetime_in_ns_readout * mode->mipi_pixel_rate)/1000000000) - mode->width); if (info->hblank < 1) info->hblank = 1; info->pixelrate = mode->mipi_pixel_rate; info->cust_pixelrate = mode->cust_pixel_rate; info->grab_h = mode->height; info->grab_w = mode->width; } adaptor_logd(ctx, "%s [scenario %d]:fps: %d vb: %d hb: %d pixelrate: %d cust_pixel_rate: %d, w %d, h %d\n", __func__, info->scenario_id, info->fps, info->vblank, info->hblank, info->pixelrate, info->cust_pixelrate, info->grab_w, info->grab_h); } break; default: ret = ext_ctrl(ctx, ctrl, ctx->try_format_mode); break; } return ret; } #ifdef IMGSENSOR_DEBUG static void proc_debug_cmd(struct adaptor_ctx *ctx, char *text) { dev_info(ctx->dev, "%s\n", text); if (!strcmp(text, "unregister_subdev")) v4l2_async_unregister_subdev(&ctx->sd); } #endif static int imgsensor_set_ctrl(struct v4l2_ctrl *ctrl) { struct adaptor_ctx *ctx = ctrl_to_ctx(ctrl); struct device *dev = ctx->dev; union feature_para para; int ret = 0; u32 len; int i; /* * Applying V4L2 control value only happens * when power is up for streaming */ if (pm_runtime_get_if_in_use(dev) == 0) return 0; ADAPTOR_SYSTRACE_BEGIN("SensorWorker::%s %d", __func__, ctrl->id); switch (ctrl->id) { case V4L2_CID_UPDATE_SOF_CNT: subdrv_call(ctx, update_sof_cnt, (u64)ctrl->val); break; case V4L2_CID_VSYNC_NOTIFY: /* update ctx sof cnt */ ctx->sof_cnt = ctrl->val; subdrv_call(ctx, vsync_notify, (u64)ctrl->val); notify_fsync_mgr_vsync(ctx); /* update timeout value upon vsync*/ ctx->shutter_for_timeout = ctx->exposure->val; if (ctx->cur_mode->fine_intg_line) ctx->shutter_for_timeout /= 1000; break; case V4L2_CID_ANALOGUE_GAIN: para.u64[0] = ctrl->val; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_GAIN, para.u8, &len); break; case V4L2_CID_EXPOSURE: { u32 fsync_exp[1] = {0}; /* needed by fsync set_shutter */ para.u64[0] = ctrl->val; fsync_exp[0] = (u32)para.u64[0]; ret = chk_s_exp_with_fl_by_fsync_mgr(ctx, fsync_exp, 1); if (!ret) { /* NOT enable frame-sync || using HW sync solution */ subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_ESHUTTER, para.u8, &len); } notify_fsync_mgr_set_shutter(ctx, fsync_exp, 1, ret); } break; case V4L2_CID_MTK_STAGGER_AE_CTRL: { struct mtk_hdr_ae *ae_ctrl = ctrl->p_new.p; ADAPTOR_SYSTRACE_BEGIN("SensorWorker::s_ae_ctrl %d", ae_ctrl->req_id); s_ae_ctrl(ctrl); ADAPTOR_SYSTRACE_END(); } break; case V4L2_CID_EXPOSURE_ABSOLUTE: { u32 fsync_exp[1] = {0}; /* needed by fsync set_shutter */ __u32 fine_integ_time = 0; para.u64[0] = (u64)(ctrl->val) * 100000; do_div(para.u64[0], ctx->cur_mode->linetime_in_ns); /* read fine integ time*/ fine_integ_time = g_sensor_fine_integ_line(ctx, ctx->cur_mode->id); if (fine_integ_time > 0) para.u64[0] = para.u64[0] * 1000; fsync_exp[0] = (u32)para.u64[0]; ret = chk_s_exp_with_fl_by_fsync_mgr(ctx, fsync_exp, 1); if (!ret) { /* NOT enable frame-sync || using HW sync solution */ subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_ESHUTTER, para.u8, &len); } notify_fsync_mgr_set_shutter(ctx, fsync_exp, 1, ret); } break; case V4L2_CID_VBLANK: para.u64[0] = ctx->exposure->val; para.u64[1] = (u32) ((u64)(ctx->cur_mode->height + ctrl->val) * get_line_d(ctx, ctx->cur_mode->linetime_in_ns_readout, ctx->cur_mode->linetime_in_ns)); para.u64[2] = 0; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_FRAMELENGTH, para.u8, &len); break; case V4L2_CID_TEST_PATTERN: // dev_dbg(dev, "V4L2_SET_TEST_PATTERN (mode:%d)", ctrl->val); para.u8[0] = ctrl->val; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_TEST_PATTERN, para.u8, &len); break; case V4L2_CID_MTK_ANTI_FLICKER: para.u16[0] = ctrl->val; para.u16[1] = 0; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_AUTO_FLICKER_MODE, para.u8, &len); notify_fsync_mgr_update_auto_flicker_mode(ctx, (u64)ctrl->val); break; case V4L2_CID_FRAME_SYNC: dev_info(dev, "V4L2_CID_FRAME_SYNC (set_sync), idx:%d, value:%d(%#x)\n", ctx->idx, ctrl->val, ctrl->val); notify_fsync_mgr_set_sync(ctx, (u64)ctrl->val); break; case V4L2_CID_FSYNC_ASYNC_MASTER: dev_info(dev, "V4L2_CID_FSYNC_ASYNC_MASTER, idx:%d, value:%d\n", ctx->idx, ctrl->val); notify_fsync_mgr_set_async_master(ctx, ctrl->val); break; case V4L2_CID_FSYNC_MAP_ID: notify_fsync_mgr_update_tg(ctx, (u64)ctrl->val); break; case V4L2_CID_FSYNC_LISTEN_TARGET: notify_fsync_mgr_update_target_tg(ctx, (u64)ctrl->val); dev_info(dev, "V4L2_CID_FSYNC_LISTEN_TARGET (update_tg), idx:%d, value:%d\n", ctx->idx, ctrl->val); break; case V4L2_CID_MTK_AWB_GAIN: { struct mtk_awb_gain *info = ctrl->p_new.p; struct SET_SENSOR_AWB_GAIN awb_gain = { .ABS_GAIN_GR = info->abs_gain_gr, .ABS_GAIN_R = info->abs_gain_r, .ABS_GAIN_B = info->abs_gain_b, .ABS_GAIN_GB = info->abs_gain_gb, }; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_AWB_GAIN, (u8 *)&awb_gain, &len); } break; case V4L2_CID_MTK_SHUTTER_GAIN_SYNC: { struct mtk_shutter_gain_sync *info = ctrl->p_new.p; u32 fsync_exp[1] = {0}; /* needed by fsync set_shutter */ para.u64[0] = info->shutter; fsync_exp[0] = (u32)para.u64[0]; ret = chk_s_exp_with_fl_by_fsync_mgr(ctx, fsync_exp, 1); if (!ret) { /* NOT enable frame-sync || using HW sync solution */ subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_ESHUTTER, para.u8, &len); } notify_fsync_mgr_set_shutter(ctx, fsync_exp, 1, ret); para.u64[0] = info->gain; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_GAIN, para.u8, &len); } break; case V4L2_CID_MTK_DUAL_GAIN: { struct mtk_dual_gain *info = ctrl->p_new.p; struct mtk_hdr_gain dual_gain; dual_gain.le_gain = info->le_gain; dual_gain.se_gain = info->se_gain; set_hdr_gain_dual(ctx, &dual_gain); } break; case V4L2_CID_MTK_IHDR_SHUTTER_GAIN: { struct mtk_ihdr_shutter_gain *info = ctrl->p_new.p; para.u64[0] = info->le_shutter; para.u64[1] = info->se_shutter; para.u64[2] = info->gain; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_IHDR_SHUTTER_GAIN, para.u8, &len); } break; case V4L2_CID_MTK_HDR_SHUTTER: { struct mtk_hdr_exposure *info = ctrl->p_new.p; set_hdr_exposure_dual(ctx, info); } break; case V4L2_CID_MTK_SHUTTER_FRAME_LENGTH: { struct mtk_shutter_frame_length *info = ctrl->p_new.p; para.u64[0] = info->shutter; para.u64[1] = info->frame_length; para.u64[2] = info->auto_extend_en; // TODO: remove CID } break; case V4L2_CID_MTK_PDFOCUS_AREA: { struct mtk_pdfocus_area *info = ctrl->p_new.p; para.u64[0] = info->pos; para.u64[1] = info->size; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_PDFOCUS_AREA, para.u8, &len); } break; case V4L2_CID_MTK_HDR_ATR: { struct mtk_hdr_atr *info = ctrl->p_new.p; para.u64[0] = info->limit_gain; para.u64[1] = info->ltc_rate; para.u64[2] = info->post_gain; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_HDR_ATR, para.u8, &len); } break; case V4L2_CID_MTK_HDR_TRI_SHUTTER: { struct mtk_hdr_exposure *info = ctrl->p_new.p; set_hdr_exposure_tri(ctx, info); } break; case V4L2_CID_MTK_HDR_TRI_GAIN: { struct mtk_hdr_gain *info = ctrl->p_new.p; set_hdr_gain_tri(ctx, info); } break; case V4L2_CID_MTK_MAX_FPS: para.u64[0] = ctx->cur_mode->id; para.u64[1] = ctrl->val; subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_MAX_FRAME_RATE_BY_SCENARIO, para.u8, &len); notify_fsync_mgr_update_min_fl(ctx); break; case V4L2_CID_SEAMLESS_SCENARIOS: { struct mtk_seamless_target_scenarios *info = ctrl->p_new.p; /* reset seamless_scenarios */ for (i = SENSOR_SCENARIO_ID_MIN; i < SENSOR_SCENARIO_ID_MAX; i++) ctx->seamless_scenarios[i] = SENSOR_SCENARIO_ID_NONE; ret = copy_from_user( &ctx->seamless_scenarios, info->target_scenario_ids, min(sizeof(ctx->seamless_scenarios), info->count * sizeof(*info->target_scenario_ids))); /* returns number of bytes that could not be copied */ /* On success, this will be zero */ if (ret != 0) { dev_info(dev, "[V4L2_CID_SEAMLESS_SCENARIOS] copy_from_user has some error, ret:%d\n", ret); } } break; case V4L2_CID_START_SEAMLESS_SWITCH: { struct mtk_seamless_switch_param *info = ctrl->p_new.p; u32 fsync_exp[5] = {0}; /* preventing drv modified exp value */ u32 orig_scen_id = ctx->subctx.current_scenario_id; u32 orig_readout_time_us = (ctx->mode[orig_scen_id].height *ctx->mode[orig_scen_id].linetime_in_ns_readout /1000); u64 time_boot = ktime_get_boottime_ns(); u64 time_mono = ktime_get_ns(); /* copy original input data for fsync using */ memcpy(fsync_exp, &info->ae_ctrl[0].exposure.arr, sizeof(fsync_exp)); para.u64[0] = info->target_scenario_id; para.u64[1] = (uintptr_t)&info->ae_ctrl[0]; para.u64[2] = (uintptr_t)&info->ae_ctrl[1]; dev_info(dev, "seamless scen(%u => %u) s[%u %u %u %u %u] g[%u %u %u %u %u] s1[%u %u %u %u %u] g1[%u %u %u %u %u] %llu|%llu\n", orig_scen_id, info->target_scenario_id, info->ae_ctrl[0].exposure.arr[0], info->ae_ctrl[0].exposure.arr[1], info->ae_ctrl[0].exposure.arr[2], info->ae_ctrl[0].exposure.arr[3], info->ae_ctrl[0].exposure.arr[4], info->ae_ctrl[0].gain.arr[0], info->ae_ctrl[0].gain.arr[1], info->ae_ctrl[0].gain.arr[2], info->ae_ctrl[0].gain.arr[3], info->ae_ctrl[0].gain.arr[4], info->ae_ctrl[1].exposure.arr[0], info->ae_ctrl[1].exposure.arr[1], info->ae_ctrl[1].exposure.arr[2], info->ae_ctrl[1].exposure.arr[3], info->ae_ctrl[1].exposure.arr[4], info->ae_ctrl[1].gain.arr[0], info->ae_ctrl[1].gain.arr[1], info->ae_ctrl[1].gain.arr[2], info->ae_ctrl[1].gain.arr[3], info->ae_ctrl[1].gain.arr[4], time_boot, time_mono); if (info->target_scenario_id == 0 && info->ae_ctrl[0].exposure.arr[0] == 0 && info->ae_ctrl[0].gain.arr[0] == 0 && info->ae_ctrl[1].exposure.arr[0] == 0 && info->ae_ctrl[1].gain.arr[0] == 0) { dev_info(dev, "V4L2_CID_START_SEAMLESS_SWITCH %u invalid value\n", info->target_scenario_id); break; } subdrv_call(ctx, feature_control, SENSOR_FEATURE_SEAMLESS_SWITCH, para.u8, &len); notify_fsync_mgr_seamless_switch(ctx, fsync_exp, IMGSENSOR_STAGGER_EXPOSURE_CNT, orig_readout_time_us, info->target_scenario_id); /*store ae ctrl for ESD reset*/ memset(&ctx->ae_memento, 0, sizeof(ctx->ae_memento)); memcpy(&ctx->ae_memento, &info->ae_ctrl[0], sizeof(ctx->ae_memento)); /* update timeout value upon seamless switch*/ ctx->exposure->val = info->ae_ctrl[0].exposure.arr[0]; ctx->shutter_for_timeout = info->ae_ctrl[0].exposure.arr[0]; if (ctx->cur_mode->fine_intg_line) ctx->shutter_for_timeout /= 1000; if (info->target_scenario_id < MODE_MAXCNT) ctx->cur_mode = &ctx->mode[info->target_scenario_id]; else { dev_info(dev, "[%s] err info->target_scenario_id %d >= MODE_MAXCNT\n", __func__, info->target_scenario_id); } } break; #ifdef IMGSENSOR_DEBUG case V4L2_CID_MTK_DEBUG_CMD: proc_debug_cmd(ctx, ctrl->p_new.p_char); break; #endif case V4L2_CID_MTK_SENSOR_POWER: dev_dbg(dev, "V4L2_CID_MTK_SENSOR_POWER val = %d\n", ctrl->val); if (ctrl->val) adaptor_hw_power_on(ctx); else adaptor_hw_power_off(ctx); break; case V4L2_CID_MTK_MSTREAM_MODE: dev_info(dev, "V4L2_CID_MTK_MSTREAM_MODE, idx:%d, value:%d\n", ctx->idx, ctrl->val); notify_fsync_mgr_mstream_en(ctx, ctrl->val); break; case V4L2_CID_MTK_N_1_MODE: { struct mtk_n_1_mode *info = ctrl->p_new.p; dev_info(dev, "V4L2_CID_MTK_N_1_MODE, idx:%d, n:%u, en:%u\n", ctx->idx, info->n, info->en); notify_fsync_mgr_n_1_en(ctx, info->n, info->en); } break; case V4L2_CID_MTK_SENSOR_TEST_PATTERN_DATA: //struct mtk_test_pattern_data *info = ctrl->p_new.p; // dev_dbg(dev, "V4L2_SET_TEST_PATTERN_DATA R(%x),Gr(%x),Gb(%x),B(%x)", // info->Channel_R, // info->Channel_Gr, // info->Channel_Gb, // info->Channel_B); subdrv_call(ctx, feature_control, SENSOR_FEATURE_SET_TEST_PATTERN_DATA, ctrl->p_new.p, &len); break; case V4L2_CID_MTK_SENSOR_RESET: { MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT image_window; MSDK_SENSOR_CONFIG_STRUCT sensor_config_data; //dev_info(dev, "V4L2_CID_MTK_SENSOR_RESET\n"); if (adaptor_hw_sensor_reset(ctx) < 0) break; ctx->is_sensor_reset_stream_off = 1; subdrv_call(ctx, open); subdrv_call(ctx, control, ctx->cur_mode->id, &image_window, &sensor_config_data); restore_ae_ctrl(ctx); /* update timeout value after reset*/ ctx->shutter_for_timeout = ctx->exposure->val; if (ctx->cur_mode->fine_intg_line) ctx->shutter_for_timeout /= 1000; _sensor_reset_s_stream(ctrl); //dev_info(dev, "exit V4L2_CID_MTK_SENSOR_RESET\n"); } break; case V4L2_CID_MTK_SENSOR_INIT: //dev_info(dev, "V4L2_CID_MTK_SENSOR_INIT val = %d\n", ctrl->val); if (ctrl->val) adaptor_sensor_init(ctx); break; case V4L2_CID_MTK_SENSOR_RESET_S_STREAM: _sensor_reset_s_stream(ctrl); break; case V4L2_CID_MTK_AOV_SWITCH_I2C_BUS_SCL_AUX: ret = _aov_switch_i2c_bus_scl_aux(ctrl); if (ret < 0) dev_info(dev, "[%s] _aov_switch_i2c_bus_scl_aux(fail),ret(%d)\n", __func__, ret); else dev_info(dev, "[%s] _aov_switch_i2c_bus_scl_aux(correct),ret(%d)\n", __func__, ret); break; case V4L2_CID_MTK_AOV_SWITCH_I2C_BUS_SDA_AUX: ret = _aov_switch_i2c_bus_sda_aux(ctrl); if (ret < 0) dev_info(dev, "[%s] _aov_switch_i2c_bus_sda_aux(fail),ret(%d)\n", __func__, ret); else dev_info(dev, "[%s] _aov_switch_i2c_bus_sda_aux(correct),ret(%d)\n", __func__, ret); break; case V4L2_CID_MTK_AOV_SWITCH_RX_PARAM: ret = _aov_switch_rx_param(ctrl); dev_info(dev, "[%s] _aov_switch_rx_param(correct),ret(%d)\n", __func__, ret); break; case V4L2_CID_MTK_AOV_SWITCH_PM_OPS: ret = _aov_switch_pm_ops(ctrl); dev_info(dev, "[%s] _aov_switch_pm_ops(correct),ret(%d)\n", __func__, ret); break; case V4L2_CID_MTK_AOV_SWITCH_MCLK_ULPOSC: dev_dbg(dev, "V4L2_CID_MTK_AOV_SWITCH_MCLK_ULPOSC val(%d)\n", ctrl->val); if (ctrl->val) ctx->aov_mclk_ulposc_flag = 1; else ctx->aov_mclk_ulposc_flag = 0; break; } ADAPTOR_SYSTRACE_END(); pm_runtime_put(dev); return ret; } static const struct v4l2_ctrl_ops ctrl_ops = { .g_volatile_ctrl = imgsensor_g_volatile_ctrl, .try_ctrl = imgsensor_try_ctrl, .s_ctrl = imgsensor_set_ctrl, }; static const char * const test_pattern_menu[] = { "Disabled", "Solid Color", "COLOR_BARS", "COLOR_BARS_FADE_TO_GRAY", "PN9", "BLACK", }; #ifdef V4L2_CID_PD_PIXEL_REGION static const struct v4l2_ctrl_config cfg_pd_pixel_region = { .ops = &ctrl_ops, .id = V4L2_CID_PD_PIXEL_REGION, .type = V4L2_CTRL_TYPE_IMAGE_PD_PIXEL_REGION, }; #endif #ifdef V4L2_CID_CAMERA_SENSOR_LOCATION static const struct v4l2_ctrl_config cfg_location = { .ops = &ctrl_ops, .id = V4L2_CID_CAMERA_SENSOR_LOCATION, .name = "location", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_READ_ONLY, .max = 2, .step = 1, }; #endif #ifdef V4L2_CID_CAMERA_SENSOR_ROTATION static const struct v4l2_ctrl_config cfg_rotation = { .ops = &ctrl_ops, .id = V4L2_CID_CAMERA_SENSOR_ROTATION, .name = "rotation", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_READ_ONLY, .max = 360, .step = 1, }; #endif static const struct v4l2_ctrl_config cust_vol_cfgs[] = { { .ops = &ctrl_ops, .id = V4L2_CID_MTK_TEMPERATURE, .name = "temperature", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, .max = 0x7fffffff, .step = 1, } }; static const struct v4l2_ctrl_config cfg_anti_flicker = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_ANTI_FLICKER, .name = "anti_flicker", .type = V4L2_CTRL_TYPE_BOOLEAN, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_frame_sync = { .ops = &ctrl_ops, .id = V4L2_CID_FRAME_SYNC, .name = "frame_sync", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0x7fffffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_fsync_async_master = { .ops = &ctrl_ops, .id = V4L2_CID_FSYNC_ASYNC_MASTER, .name = "fsync_async_master", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .def = 255, // FrameSync::MASTER_IDX_NONE .max = 0x7fffffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_fsync_map_id = { .ops = &ctrl_ops, .id = V4L2_CID_FSYNC_MAP_ID, .name = "fsync_map_id", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_fsync_listen_target = { .ops = &ctrl_ops, .id = V4L2_CID_FSYNC_LISTEN_TARGET, .name = "fsync_listen_target", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_vsync_notify = { .ops = &ctrl_ops, .id = V4L2_CID_VSYNC_NOTIFY, .name = "vsync_notify", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0x7fffffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_update_sof_cnt = { .ops = &ctrl_ops, .id = V4L2_CID_UPDATE_SOF_CNT, .name = "update_sof_cnt", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0x7fffffff, .step = 1, }; static struct v4l2_ctrl_config cfg_ae_ctrl = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_STAGGER_AE_CTRL, .name = "ae_ctrl", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_hdr_ae)}, }; static struct v4l2_ctrl_config cfg_fd_ctrl = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_FRAME_DESC, .name = "frame_des_ctrl", .type = V4L2_CTRL_TYPE_U32, //.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_mbus_frame_desc)}, }; static struct v4l2_ctrl_config cfg_csi_param_ctrl = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_CSI_PARAM, .name = "mtk_csi_param", .type = V4L2_CTRL_TYPE_U32, //.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_csi_param)}, }; static const struct v4l2_ctrl_config cfg_awb_gain = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_AWB_GAIN, .name = "awb_gain", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_awb_gain)}, }; /* force to apply repeated settings for frame-sync mode */ static const struct v4l2_ctrl_config cfg_shutter_gain_sync = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SHUTTER_GAIN_SYNC, .name = "shutter_gain_sync", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_shutter_gain_sync)}, }; static const struct v4l2_ctrl_config cfg_dual_gain = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_DUAL_GAIN, .name = "dual_gain", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_dual_gain)}, }; static const struct v4l2_ctrl_config cfg_ihdr_shutter_gain = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_IHDR_SHUTTER_GAIN, .name = "ihdr_shutter_gain", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_ihdr_shutter_gain)}, }; static const struct v4l2_ctrl_config cfg_hdr_shutter = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_HDR_SHUTTER, .name = "hdr_shutter", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_hdr_exposure)}, }; static const struct v4l2_ctrl_config cfg_shutter_frame_length = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SHUTTER_FRAME_LENGTH, .name = "shutter_frame_length", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_shutter_frame_length)}, }; static const struct v4l2_ctrl_config cfg_pdfocus_area = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_PDFOCUS_AREA, .name = "pdfocus_area", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_pdfocus_area)}, }; static const struct v4l2_ctrl_config cfg_hdr_atr = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_HDR_ATR, .name = "hdr_atr", .type = V4L2_CTRL_TYPE_U32, .max = 0xffff, .step = 1, .dims = {sizeof_u32(struct mtk_hdr_atr)}, }; static const struct v4l2_ctrl_config cfg_hdr_tri_shutter = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_HDR_TRI_SHUTTER, .name = "hdr_tri_shutter", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_hdr_exposure)}, }; static const struct v4l2_ctrl_config cfg_hdr_tri_gain = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_HDR_TRI_GAIN, .name = "hdr_tri_gain", .type = V4L2_CTRL_TYPE_U32, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_hdr_gain)}, }; static const struct v4l2_ctrl_config cfg_max_fps = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_MAX_FPS, .name = "max_fps", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_pixel_rate = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_PIXEL_RATE, .name = "pixel rate", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0x7fffffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_cust_pixel_rate = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_CUST_SENSOR_PIXEL_RATE, .name = "customized pixel rate", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0x7fffffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_sof_timeout_value = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SOF_TIMEOUT_VALUE, .name = "sof timeout value", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0x7fffffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_seamless_scenario = { .ops = &ctrl_ops, .id = V4L2_CID_SEAMLESS_SCENARIOS, .name = "seamless scenario", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_seamless_target_scenarios)}, }; static const struct v4l2_ctrl_config cfg_stagger_info = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_STAGGER_INFO, .name = "stagger info", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0xffff, .step = 1, .dims = {sizeof_u32(struct mtk_stagger_info)}, }; static const struct v4l2_ctrl_config cfg_stagger_scenario = { .ops = &ctrl_ops, .id = V4L2_CID_STAGGER_TARGET_SCENARIO, .name = "stagger scenario", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0xffff, .step = 1, .dims = {sizeof_u32(struct mtk_stagger_target_scenario)}, }; static const struct v4l2_ctrl_config cfg_stagger_max_exp_time = { .ops = &ctrl_ops, .id = V4L2_CID_MAX_EXP_TIME, .name = "maximum exposure time", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0xffff, .step = 1, .dims = {sizeof_u32(struct mtk_stagger_max_exp_time)}, }; static const struct v4l2_ctrl_config cfg_static_param = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_STATIC_PARAM, .name = "static param by scenario", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0xffff, .step = 1, .dims = {sizeof_u32(struct mtk_sensor_static_param)}, }; static const struct v4l2_ctrl_config cfg_start_seamless_switch = { .ops = &ctrl_ops, .id = V4L2_CID_START_SEAMLESS_SWITCH, .name = "start_seamless_switch", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_seamless_switch_param)}, }; static const struct v4l2_ctrl_config cfg_test_pattern_data = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_TEST_PATTERN_DATA, .name = "test_pattern_data", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffffffff, .step = 1, .dims = {sizeof_u32(struct mtk_test_pattern_data)}, }; #ifdef IMGSENSOR_DEBUG static const struct v4l2_ctrl_config cfg_debug_cmd = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_DEBUG_CMD, .name = "debug_cmd", .type = V4L2_CTRL_TYPE_STRING, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 64, .step = 1, }; #endif static const struct v4l2_ctrl_config cfg_sensor_power = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_POWER, .name = "sensor_power", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_sensor_reset = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_RESET, .name = "sensor_reset", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_mstream_mode = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_MSTREAM_MODE, .name = "mstream_mode", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .def = 0, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_n_1_mode = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_N_1_MODE, .name = "n_1_mode", .type = V4L2_CTRL_TYPE_U32, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, .dims = {sizeof_u32(struct mtk_n_1_mode)}, }; static const struct v4l2_ctrl_config cfg_sensor_init = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_INIT, .name = "sensor_init", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_sensor_reset_s_stream = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_RESET_S_STREAM, .name = "sensor_reset_s_stream", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_sensor_reset_by_user = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_RESET_BY_USER, .name = "sensor_reset_by_user", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 1, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_sensor_idx = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_SENSOR_IDX, .name = "sensor idx", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_VOLATILE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_aov_switch_i2c_bus_scl_aux = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_AOV_SWITCH_I2C_BUS_SCL_AUX, .name = "aov_switch_i2c_bus_scl_aux", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_aov_switch_i2c_bus_sda_aux = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_AOV_SWITCH_I2C_BUS_SDA_AUX, .name = "aov_switch_i2c_bus_sda_aux", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_aov_switch_rx_param = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_AOV_SWITCH_RX_PARAM, .name = "aov_switch_rx_param", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_aov_switch_pm_ops = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_AOV_SWITCH_PM_OPS, .name = "aov_pm_ops", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 0xffff, .step = 1, }; static const struct v4l2_ctrl_config cfg_mtkcam_aov_switch_mclk_ulposc = { .ops = &ctrl_ops, .id = V4L2_CID_MTK_AOV_SWITCH_MCLK_ULPOSC, .name = "aov_switch_mclk_ulposc", .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, .max = 1, .step = 1, }; void adaptor_sensor_init(struct adaptor_ctx *ctx) { #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "[%s][%s]+\n", __func__, (ctx->subdrv) ? (ctx->subdrv->name) : "null"); #endif if (ctx && !ctx->is_sensor_inited) { subdrv_call(ctx, open); ctx->is_sensor_inited = 1; } #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "[%s][%s]-\n", __func__, (ctx->subdrv) ? (ctx->subdrv->name) : "null"); #endif } void restore_ae_ctrl(struct adaptor_ctx *ctx) { #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "[%s][%s]+\n", __func__, (ctx->subdrv) ? (ctx->subdrv->name) : "null"); #endif if (!ctx->ae_memento.exposure.le_exposure || !ctx->ae_memento.gain.le_gain) { return; } // dev_dbg(ctx->dev, "%s\n", __func__); do_set_ae_ctrl(ctx, &ctx->ae_memento); #if IMGSENSOR_LOG_MORE dev_info(ctx->dev, "[%s][%s]-\n", __func__, (ctx->subdrv) ? (ctx->subdrv->name) : "null"); #endif } int adaptor_init_ctrls(struct adaptor_ctx *ctx) { int i, ret; s64 min, max, step, def; const struct sensor_mode *cur_mode; struct v4l2_ctrl_handler *ctrl_hdlr; struct v4l2_ctrl_config cfg; ctrl_hdlr = &ctx->ctrls; ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); if (ret) return ret; ctrl_hdlr->lock = &ctx->mutex; cur_mode = ctx->cur_mode; /* pixel rate */ min = max = def = cur_mode->mipi_pixel_rate; ctx->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_PIXEL_RATE, min, max, 1, def); /* pixel rate for try control*/ v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_pixel_rate, NULL); /* pixel rate for special output timing*/ v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_cust_pixel_rate, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_sof_timeout_value, NULL); /* hblank */ min = max = def = cur_mode->llp - cur_mode->width; ctx->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_HBLANK, min, max, 1, def); if (ctx->hblank) ctx->hblank->flags |= V4L2_CTRL_FLAG_VOLATILE; /* vblank */ min = def = get_mode_vb(ctx, cur_mode); max = ctx->subctx.max_frame_length - cur_mode->height; ctx->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_VBLANK, min, max, 1, def); if (ctx->vblank) ctx->vblank->flags |= V4L2_CTRL_FLAG_VOLATILE; /* ae ctrl */ ctx->hdr_ae_ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_ae_ctrl, NULL); if (ctx->hdr_ae_ctrl) ctx->hdr_ae_ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; /* exposure */ min = ctx->subctx.exposure_min; max = ctx->subctx.exposure_max; step = ctx->subctx.exposure_step; def = ctx->subctx.exposure_def; ctx->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_EXPOSURE, min, max, step, def); if (ctx->exposure) ctx->exposure->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; min = ctx->subctx.ana_gain_min; max = ctx->subctx.ana_gain_max; step = ctx->subctx.ana_gain_step; def = ctx->subctx.ana_gain_def; ctx->analogue_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_ANALOGUE_GAIN, min, max, step, def); if (ctx->analogue_gain) ctx->analogue_gain->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; /* exposure_absolute: in 100 us */ min = min * cur_mode->linetime_in_ns; do_div(min, 100000); max = max * cur_mode->linetime_in_ns; do_div(max, 100000); def = def * cur_mode->linetime_in_ns; do_div(def, 100000); ctx->exposure_abs = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_EXPOSURE_ABSOLUTE, min, max, 1, def); if (ctx->exposure_abs) ctx->exposure_abs->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; /* test pattern */ ctx->test_pattern = v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern_menu) - 1, 0, 0, test_pattern_menu); if (ctx->test_pattern) ctx->test_pattern->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; /* hflip */ def = ctx->subctx.is_hflip; ctx->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, def); if (ctx->hflip) ctx->hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* vflip */ def = ctx->subctx.is_vflip; ctx->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, def); if (ctx->vflip) ctx->vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; #ifdef V4L2_CID_PD_PIXEL_REGION ctx->pd_pixel_region = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_pd_pixel_region, NULL); if (ctx->pd_pixel_region) { ctx->pd_pixel_region->flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE; } #endif memset(&cfg, 0, sizeof(cfg)); #ifdef V4L2_CID_CAMERA_SENSOR_LOCATION memcpy(&cfg, &cfg_location, sizeof(cfg)); cfg.def = ctx->location; v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_location, NULL); #endif #ifdef V4L2_CID_CAMERA_SENSOR_ROTATION memcpy(&cfg, &cfg_rotation, sizeof(cfg)); cfg.def = ctx->rotation; v4l2_ctrl_new_custom(ctrl_hdlr, &cfg, NULL); #endif /* custom volatile configs */ for (i = 0; i < ARRAY_SIZE(cust_vol_cfgs); i++) v4l2_ctrl_new_custom(&ctx->ctrls, &cust_vol_cfgs[i], NULL); /* custom anti-flicker */ ctx->anti_flicker = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_anti_flicker, NULL); /* custom frame-sync */ ctx->frame_sync = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_frame_sync, NULL); /* custom frame-sync - async master */ ctx->fsync_async_master = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_fsync_async_master, NULL); /* custom awb gain */ ctx->awb_gain = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_awb_gain, NULL); /* custom shutter-gain-sync */ ctx->shutter_gain_sync = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_shutter_gain_sync, NULL); /* custom dual-gain */ if (ctx->subctx.hdr_cap & (HDR_CAP_MVHDR | HDR_CAP_ZHDR)) { ctx->dual_gain = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_dual_gain, NULL); } /* custom ihdr-shutter-gain */ if (ctx->subctx.hdr_cap & HDR_CAP_IHDR) { ctx->ihdr_shutter_gain = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_ihdr_shutter_gain, NULL); } /* custom hdr-shutter */ ctx->hdr_shutter = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_hdr_shutter, NULL); /* custom shutter-frame-length */ ctx->shutter_frame_length = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_shutter_frame_length, NULL); /* custom pdfocus-area */ if (ctx->subctx.pdaf_cap & PDAF_CAP_PDFOCUS_AREA) { ctx->pdfocus_area = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_pdfocus_area, NULL); } /* custom hdr-atr */ if (ctx->subctx.hdr_cap & HDR_CAP_ATR) { ctx->hdr_atr = v4l2_ctrl_new_custom( &ctx->ctrls, &cfg_hdr_atr, NULL); } /* custom hdr-tri-shutter/gain */ if (ctx->subctx.hdr_cap & HDR_CAP_3HDR) { ctx->hdr_tri_shutter = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_hdr_tri_shutter, NULL); ctx->hdr_tri_gain = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_hdr_tri_gain, NULL); } /* max fps */ max = def = cur_mode->max_framerate; memcpy(&cfg, &cfg_max_fps, sizeof(cfg)); cfg.min = 1; cfg.max = max; cfg.def = def; ctx->max_fps = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg, NULL); /* update fsync map id (cammux idx) */ ctx->fsync_map_id = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_fsync_map_id, NULL); /* * update fsync listen target (the id vsync listen to), this is * replacment of fsync_map_id */ ctx->fsync_listen_target = v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_fsync_listen_target, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_vsync_notify, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_update_sof_cnt, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_stagger_info, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_stagger_scenario, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_stagger_max_exp_time, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_start_seamless_switch, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_static_param, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_seamless_scenario, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_fd_ctrl, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_csi_param_ctrl, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_test_pattern_data, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_sensor_idx, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_aov_switch_i2c_bus_scl_aux, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_aov_switch_i2c_bus_sda_aux, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_aov_switch_rx_param, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_aov_switch_pm_ops, NULL); v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_mtkcam_aov_switch_mclk_ulposc, NULL); #ifdef IMGSENSOR_DEBUG v4l2_ctrl_new_custom(&ctx->ctrls, &cfg_debug_cmd, NULL); #endif v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_sensor_power, NULL); v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_mstream_mode, NULL); v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_n_1_mode, NULL); v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_sensor_reset, NULL); v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_sensor_init, NULL); v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_sensor_reset_s_stream, NULL); v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_sensor_reset_by_user, NULL); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; dev_err(ctx->dev, "control init failed: %d\n", ret); goto error; } ctx->sd.ctrl_handler = ctrl_hdlr; return 0; error: v4l2_ctrl_handler_free(ctrl_hdlr); return ret; }