From 9e93e6ba458d05764863f522d6e383ac00c7e9af Mon Sep 17 00:00:00 2001 From: Hu Kejun Date: Mon, 11 Jun 2018 16:19:08 +0800 Subject: [PATCH] camera: rockchip: merge modification of rv1108 isp11 camera: rockchip: add sensor ioctl and max gain. 1. add RK_VIDIOC_SENSOR_CONFIGINFO; 2. add RK_VIDIOC_SENSOR_REG_ACCESS; 3. add max_exp_gain_h/max_exp_gain_l; camera: rockchip: merge isp11: rockchip: v0.1.7 isp11: rockchip: v0.1.7 1. Direct config isp lsc table size in cifisp_lsc_config. Because active_lsc_width is not same with isp register after isp reset. 2. Support separate config sensor gain and shutter time for some sensor which gain and shutter isn't valid at the same time. for example ov2710. ov4689:v0.1.0; ov2710:v0.1.1; imx323:v0.1.0; camera: rockchip: Support v4l2 subdev api ov2710: v0.1.2 ov4689: v0.1.1 imx323: v0.1.2 camera: rockchip: add lock for stream/aec hold reg in AEC will affect stream reg, if asynchronous. camera: rockchip: fix sensor timing if fps changed, vts changed, update to timing. camera: rockchip: support set flip api camera: rockchip: support get flip api camera: rockchip: fix release bug should be free pdata at the end camera: rockchip: imx323 fix s_fmt failed for imx323 v0.1.2; camera: rockchip: fix s_frame_interval failed fix s_frame_interval failed when frame interval is match active config frame interval. camera: rockchip: imx,aptina,ov Check xxx_camera_module_init return value in PLTFRM_CIFCAM_ATTACH camera: rockchip: release sensor if init fail camera: rockchip: imx,aptina,ov support mirror/flip conifg in dts for imx323/ov4689 camera: rockchip: add s_frame_interval/g_frame_interval camera: rockchip: ov, aptina, imx add s_frame_interval/g_frame_interval camera: rockchip: imx,ov,aptina 1.imx,ov: fix g_timing error if s_frame_interval before stream_on, because vts_cur is update in stream_on; 2.aptina: fix compile error; camera: rockchip: imx,ov,aptina 1. fix calc vts wrong in xxx_camera_module_s_stream Change-Id: I5a6e75f2ce3c50d69c51af9792232c60b6982128 Signed-off-by: Hu Kejun --- .../rockchip/adv7181_v4l2-i2c-subdev.c | 15 +- .../soc_camera/rockchip/adv_camera_module.c | 237 ++++++++++++-- .../soc_camera/rockchip/adv_camera_module.h | 17 +- .../rockchip/aptina_camera_module.c | 298 ++++++++++++++---- .../rockchip/aptina_camera_module.h | 20 +- .../rockchip/imx323_v4l2-i2c-subdev.c | 73 +++-- .../soc_camera/rockchip/imx_camera_module.c | 239 ++++++++++++-- .../soc_camera/rockchip/imx_camera_module.h | 20 +- .../rockchip/nt99230_v4l2-i2c-subdev.c | 29 +- .../rockchip/ov13850_v4l2-i2c-subdev.c | 63 ++-- .../rockchip/ov2710_v4l2-i2c-subdev.c | 51 +-- .../rockchip/ov4689_v4l2-i2c-subdev.c | 60 ++-- .../rockchip/ov7675_v4l2-i2c-subdev.c | 21 +- .../rockchip/ov7750_v4l2-i2c-subdev.c | 44 ++- .../rockchip/ov8858_v4l2-i2c-subdev.c | 54 ++-- .../soc_camera/rockchip/ov_camera_module.c | 235 ++++++++++++-- .../soc_camera/rockchip/ov_camera_module.h | 17 +- .../soc_camera/rockchip/rk_camera_module.c | 167 +++++++++- .../rockchip/tc358749xbg_v4l2-i2c-subdev.c | 23 +- .../soc_camera/rockchip/tc_camera_module.c | 242 ++++++++++++-- .../soc_camera/rockchip/tc_camera_module.h | 17 +- .../rk_isp10_platform_camera_module.h | 9 + include/media/v4l2-config_rockchip.h | 2 + 23 files changed, 1602 insertions(+), 351 deletions(-) diff --git a/drivers/media/i2c/soc_camera/rockchip/adv7181_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/adv7181_v4l2-i2c-subdev.c index 5908294b73e7..332521bb330e 100644 --- a/drivers/media/i2c/soc_camera/rockchip/adv7181_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/adv7181_v4l2-i2c-subdev.c @@ -132,6 +132,8 @@ static struct adv_camera_module_config adv7181_configs[] = { / sizeof(adv7180_cvbs_30fps[0]), .v_blanking_time_us = 0, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, .ignore_measurement_check = 1, PLTFRM_CAM_ITF_DVP_CFG( PLTFRM_CAM_ITF_BT656_8I, @@ -160,6 +162,8 @@ static struct adv_camera_module_config adv7181_configs[] = { / sizeof(adv7180_cvbs_30fps[0]), .v_blanking_time_us = 0, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, .ignore_measurement_check = 1, PLTFRM_CAM_ITF_DVP_CFG( PLTFRM_CAM_ITF_BT656_8I, @@ -228,6 +232,8 @@ static int adv7181_g_timings(struct adv_camera_module *cam_mod, cam_mod->active_config->frm_intrvl.interval.denominator * vts * timings->line_length_pck; + timings->frame_length_lines = vts; + return ret; err: adv_camera_module_pr_err(cam_mod, @@ -397,6 +403,7 @@ static struct v4l2_subdev_core_ops adv7181_camera_module_core_ops = { static struct v4l2_subdev_video_ops adv7181_camera_module_video_ops = { .s_frame_interval = adv_camera_module_s_frame_interval, + .g_frame_interval = adv_camera_module_g_frame_interval, .s_stream = adv_camera_module_s_stream }; @@ -425,7 +432,13 @@ static struct adv_camera_module_custom_config adv7181_custom_config = { .check_camera_id = adv7181_check_camera_id, .configs = adv7181_configs, .num_configs = ARRAY_SIZE(adv7181_configs), - .power_up_delays_ms = {5, 30, 30} + .power_up_delays_ms = {5, 30, 30}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static ssize_t adv7181_debugfs_reg_write( diff --git a/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.c b/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.c index 034c12143015..96ba4f824e31 100644 --- a/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.c +++ b/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.c @@ -47,8 +47,6 @@ static void adv_camera_module_reset( cam_mod->exp_config.auto_exp = false; cam_mod->exp_config.auto_gain = false; cam_mod->wb_config.auto_wb = false; - cam_mod->hflip = false; - cam_mod->vflip = false; cam_mod->auto_adjust_fps = true; cam_mod->rotation = 0; cam_mod->ctrl_updt = 0; @@ -306,6 +304,10 @@ int adv_camera_module_s_fmt(struct v4l2_subdev *sd, adv_camera_module_set_active_config(cam_mod, adv_camera_module_find_config(cam_mod, fmt, &cam_mod->frm_intrvl)); + } else { + adv_camera_module_set_active_config(cam_mod, + adv_camera_module_find_config(cam_mod, + fmt, NULL)); } return 0; err: @@ -346,6 +348,8 @@ int adv_camera_module_s_frame_interval( struct adv_camera_module *cam_mod = to_adv_camera_module(sd); unsigned long gcdiv; struct v4l2_subdev_frame_interval norm_interval; + struct adv_camera_module_config *config; + unsigned int vts; int ret = 0; if ((interval->interval.denominator == 0) || @@ -372,22 +376,62 @@ int adv_camera_module_s_frame_interval( norm_interval.interval.denominator = interval->interval.denominator / gcdiv; - if (IS_ERR_OR_NULL(adv_camera_module_find_config(cam_mod, - NULL, &norm_interval))) { - pltfrm_camera_module_pr_err(&cam_mod->sd, - "frame interval %d/%d not supported\n", - interval->interval.numerator, - interval->interval.denominator); - ret = -EINVAL; - goto err; + if (!cam_mod->frm_fmt_valid) + goto end; + config = adv_camera_module_find_config( + cam_mod, + &cam_mod->active_config->frm_fmt, + &norm_interval); + + if (!IS_ERR_OR_NULL(config) && (config != cam_mod->active_config)) { + adv_camera_module_set_active_config(cam_mod, config); + if (cam_mod->state == ADV_CAMERA_MODULE_STREAMING) { + cam_mod->custom.stop_streaming(cam_mod); + adv_camera_module_write_config(cam_mod); + cam_mod->custom.start_streaming(cam_mod); + } + } else { + if (IS_ERR_OR_NULL(cam_mod->active_config)) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "no active sensor configuration"); + ret = -EFAULT; + goto err; + } + if (cam_mod->active_config->frm_intrvl.interval.denominator < + norm_interval.interval.denominator) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "%dx%d@%dfps isn't support!", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + norm_interval.interval.denominator); + ret = -EFAULT; + goto err; + } + if (!cam_mod->custom.s_vts) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "custom.s_vts isn't support!"); + ret = -EFAULT; + goto err; + } + + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= norm_interval.interval.denominator; + cam_mod->vts_cur = vts; + + if (cam_mod->state != ADV_CAMERA_MODULE_STREAMING) + goto end; + + cam_mod->custom.s_vts(cam_mod, vts); } + +end: cam_mod->frm_intrvl_valid = true; cam_mod->frm_intrvl = norm_interval; - if (cam_mod->frm_fmt_valid) { - adv_camera_module_set_active_config(cam_mod, - adv_camera_module_find_config(cam_mod, - &cam_mod->frm_fmt, interval)); - } + cam_mod->auto_adjust_fps = false; return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, @@ -395,12 +439,34 @@ int adv_camera_module_s_frame_interval( return ret; } +int adv_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct adv_camera_module *cam_mod = to_adv_camera_module(sd); + + if (cam_mod->active_config) { + if (cam_mod->state == ADV_CAMERA_MODULE_STREAMING) { + if (cam_mod->frm_intrvl_valid) { + *interval = cam_mod->frm_intrvl; + return 0; + } else { + *interval = cam_mod->active_config->frm_intrvl; + return 0; + } + } + } + + return -EFAULT; +} + /* ======================================================================== */ int adv_camera_module_s_stream(struct v4l2_subdev *sd, int enable) { int ret = 0; struct adv_camera_module *cam_mod = to_adv_camera_module(sd); + unsigned int vts; pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable); @@ -429,6 +495,29 @@ int adv_camera_module_s_stream(struct v4l2_subdev *sd, int enable) ret = cam_mod->custom.start_streaming(cam_mod); if (IS_ERR_VALUE(ret)) goto err; + + if (cam_mod->frm_intrvl_valid) { + if ((cam_mod->frm_intrvl.interval.numerator != + cam_mod->active_config->frm_intrvl.interval.numerator) || + (cam_mod->frm_intrvl.interval.denominator != + cam_mod->active_config->frm_intrvl.interval.denominator)) { + if (cam_mod->frm_intrvl.interval.denominator > + cam_mod->active_config->frm_intrvl.interval.denominator) { + pltfrm_camera_module_pr_warn(&cam_mod->sd, + "sensor is not support stream: %dx%d@(%d/%d)fps!\n", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + cam_mod->frm_intrvl.interval.denominator, + cam_mod->frm_intrvl.interval.numerator); + goto end; + } + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= cam_mod->frm_intrvl.interval.denominator; + cam_mod->custom.s_vts(cam_mod, vts); + } + } + if (!cam_mod->inited && cam_mod->update_config) cam_mod->inited = true; cam_mod->update_config = false; @@ -473,6 +562,7 @@ int adv_camera_module_s_stream(struct v4l2_subdev *sd, int enable) msleep(wait_ms + 1); } +end: cam_mod->state_before_suspend = cam_mod->state; return 0; @@ -584,6 +674,22 @@ int adv_camera_module_g_ctrl(struct v4l2_subdev *sd, return 0; } + if (ctrl->id == V4L2_CID_HFLIP) { + ctrl->value = cam_mod->hflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_HFLIP %d\n", + ctrl->value); + return 0; + } + + if (ctrl->id == V4L2_CID_VFLIP) { + ctrl->value = cam_mod->vflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_VFLIP %d\n", + ctrl->value); + return 0; + } + if (IS_ERR_OR_NULL(cam_mod->active_config)) { pltfrm_camera_module_pr_err(&cam_mod->sd, "no active configuration\n"); @@ -670,10 +776,6 @@ int adv_camera_module_g_ctrl(struct v4l2_subdev *sd, "V4L2_CID_FOCUS_ABSOLUTE %d\n", ctrl->value); break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - /* TBD */ - /* fallthrough */ default: pltfrm_camera_module_pr_debug(&cam_mod->sd, "failed, unknown ctrl %d\n", ctrl->id); @@ -813,12 +915,14 @@ int adv_camera_module_s_ext_ctrls( cam_mod->hflip = true; else cam_mod->hflip = false; + cam_mod->flip_flg = true; break; case V4L2_CID_VFLIP: if (ctrl->value) cam_mod->vflip = true; else cam_mod->vflip = false; + cam_mod->flip_flg = true; break; default: pltfrm_camera_module_pr_warn(&cam_mod->sd, @@ -896,7 +1000,8 @@ long adv_camera_module_ioctl(struct v4l2_subdev *sd, void *arg) { struct adv_camera_module *cam_mod = to_adv_camera_module(sd); - int ret; + int ret, i; + unsigned int flag, val; pltfrm_camera_module_pr_debug(&cam_mod->sd, "cmd: 0x%x\n", cmd); @@ -937,9 +1042,10 @@ long adv_camera_module_ioctl(struct v4l2_subdev *sd, timings->fine_integration_time_min = adv_timings.fine_integration_time_min; - if (cam_mod->custom.g_exposure_valid_frame) - timings->exposure_valid_frame[0] = - cam_mod->custom.g_exposure_valid_frame(cam_mod); + timings->exposure_valid_frame[0] = + cam_mod->custom.exposure_valid_frame[0]; + timings->exposure_valid_frame[1] = + cam_mod->custom.exposure_valid_frame[1]; if (cam_mod->exp_config.exp_time) timings->exp_time = cam_mod->exp_config.exp_time; else @@ -948,7 +1054,52 @@ long adv_camera_module_ioctl(struct v4l2_subdev *sd, timings->gain = cam_mod->exp_config.gain; else timings->gain = adv_timings.gain; + + if (cam_mod->active_config) { + timings->max_exp_gain_h = cam_mod->active_config->max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->active_config->max_exp_gain_l; + } else { + timings->max_exp_gain_h = cam_mod->custom.configs[0].max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->custom.configs[0].max_exp_gain_l; + } return ret; + } else if (cmd == RK_VIDIOC_SENSOR_CONFIGINFO) { + struct sensor_config_info_s *sensor_config = (struct sensor_config_info_s *)arg; + + sensor_config->config_num = cam_mod->custom.num_configs; + for (i = 0; i < cam_mod->custom.num_configs; i++) { + if (i >= SENSOR_CONFIG_NUM) + break; + sensor_config->sensor_fmt[i] = + pltfrm_camera_module_pix_fmt2csi2_dt(cam_mod->custom.configs[i].frm_fmt.code); + sensor_config->reso[i].width = cam_mod->custom.configs[i].frm_fmt.width; + sensor_config->reso[i].height = cam_mod->custom.configs[i].frm_fmt.height; + } + return 0; + } else if (cmd == RK_VIDIOC_SENSOR_REG_ACCESS) { + struct sensor_reg_rw_s *sensor_rw = (struct sensor_reg_rw_s *)arg; + + if (sensor_rw->reg_access_mode == SENSOR_READ_MODE) { + for (i = 0; i < cam_mod->custom.configs[0].reg_table_num_entries; i++) { + flag = cam_mod->custom.configs[0].reg_table[i].flag; + if (flag != PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) + break; + } + if (flag == PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) { + pltfrm_camera_module_pr_err(&cam_mod->sd, + "Can not get sensor reg type.\n"); + return -EINVAL; + } + sensor_rw->reg_addr_len = PLTFRM_CAMERA_MODULE_REG_LEN(flag); + sensor_rw->reg_data_len = PLTFRM_CAMERA_MODULE_DATA_LEN(flag); + pltfrm_camera_module_read_reg_ex(&cam_mod->sd, 1, flag, sensor_rw->addr, &val); + sensor_rw->data = val; + } else { + flag = (sensor_rw->reg_addr_len << PLTFRM_CAMERA_MODULE_REG_LEN_BIT); + flag |= (sensor_rw->reg_data_len << PLTFRM_CAMERA_MODULE_DATA_LEN_BIT); + pltfrm_camera_module_write_reg_ex(&cam_mod->sd, flag, sensor_rw->addr, sensor_rw->data); + } + return 0; } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) { struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg; struct adv_camera_module_config *config; @@ -969,10 +1120,14 @@ long adv_camera_module_ioctl(struct v4l2_subdev *sd, pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg); return 0; } else if (cmd == PLTFRM_CIFCAM_ATTACH) { - adv_camera_module_init(cam_mod, &cam_mod->custom); - pltfrm_camera_module_pr_err(&cam_mod->sd, "test\n"); - pltfrm_camera_module_ioctl(sd, cmd, arg); - return adv_camera_module_attach(cam_mod); + ret = adv_camera_module_init(cam_mod, &cam_mod->custom); + if (!IS_ERR_VALUE(ret)) { + pltfrm_camera_module_ioctl(sd, cmd, arg); + return adv_camera_module_attach(cam_mod); + } else { + adv_camera_module_release(cam_mod); + return ret; + } } ret = pltfrm_camera_module_ioctl(sd, cmd, arg); @@ -984,7 +1139,22 @@ long adv_camera_module_ioctl(struct v4l2_subdev *sd, int adv_camera_module_get_flip_mirror( struct adv_camera_module *cam_mod) { - return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + int mode = 0; + + if (!cam_mod->flip_flg) + return -1; + + if (cam_mod->hflip) + mode |= ADV_MIRROR_BIT_MASK; + else + mode &= ~ADV_MIRROR_BIT_MASK; + + if (cam_mod->vflip) + mode |= ADV_FLIP_BIT_MASK; + else + mode &= ~ADV_FLIP_BIT_MASK; + + return mode; } /* ======================================================================== */ @@ -1156,9 +1326,13 @@ int adv_camera_module_init(struct adv_camera_module *cam_mod, struct adv_camera_module_custom_config *custom) { int ret = 0; + int mode = 0; pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); + cam_mod->hflip = false; + cam_mod->vflip = false; + cam_mod->flip_flg = false; adv_camera_module_reset(cam_mod); if (IS_ERR_OR_NULL(custom->start_streaming) || @@ -1186,6 +1360,13 @@ int adv_camera_module_init(struct adv_camera_module *cam_mod, goto err; } + mode = pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + if (mode != -1) { + cam_mod->hflip = mode & ADV_MIRROR_BIT_MASK ? true : false; + cam_mod->vflip = mode & ADV_FLIP_BIT_MASK ? true : false; + cam_mod->flip_flg = true; + } + return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, diff --git a/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.h b/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.h index 85b7442ff224..392ba60be313 100644 --- a/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.h +++ b/drivers/media/i2c/soc_camera/rockchip/adv_camera_module.h @@ -30,8 +30,8 @@ #define ADV_CAMERA_MODULE_REG_TYPE_TIMEOUT PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT #define adv_camera_module_csi_config #define adv_camera_module_reg pltfrm_camera_module_reg -#define ADV_FLIP_BIT_MASK 0x2 -#define ADV_MIRROR_BIT_MASK 0x1 +#define ADV_FLIP_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_FLIP_BIT) +#define ADV_MIRROR_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_MIRROR_BIT) #define ADV_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01 #define ADV_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02 @@ -90,7 +90,8 @@ struct adv_camera_module_config { struct adv_camera_module_timings timings; bool soft_reset; bool ignore_measurement_check; - + u8 max_exp_gain_h; + u8 max_exp_gain_l; struct pltfrm_cam_itf itf_cfg; }; @@ -156,7 +157,8 @@ struct adv_camera_module_custom_config { int (*g_ctrl)(struct adv_camera_module *cam_mod, u32 ctrl_id); int (*g_timings)(struct adv_camera_module *cam_mod, struct adv_camera_module_timings *timings); - int (*g_exposure_valid_frame)(struct adv_camera_module *cam_mod); + int (*s_vts)(struct adv_camera_module *cam_mod, + u32 vts); int (*s_ext_ctrls)(struct adv_camera_module *cam_mod, struct adv_camera_module_ext_ctrls *ctrls); int (*set_flip)( @@ -168,6 +170,7 @@ struct adv_camera_module_custom_config { struct adv_camera_module_config *configs; u32 num_configs; u32 power_up_delays_ms[3]; + unsigned short exposure_valid_frame[2]; void *priv; }; @@ -199,9 +202,11 @@ struct adv_camera_module { bool frm_intrvl_valid; bool hflip; bool vflip; + bool flip_flg; u32 rotation; void *pltfm_data; bool inited; + struct mutex lock; }; #define adv_camera_module_pr_info(cam_mod, fmt, arg...) \ @@ -245,6 +250,10 @@ int adv_camera_module_s_frame_interval( struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); +int adv_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval); + int adv_camera_module_s_stream( struct v4l2_subdev *sd, int enable); diff --git a/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.c b/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.c index 79a63caa7bbb..2aed92387b2d 100644 --- a/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.c +++ b/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.c @@ -51,8 +51,6 @@ void aptina_camera_module_reset( cam_mod->exp_config.auto_exp = false; cam_mod->exp_config.auto_gain = false; cam_mod->wb_config.auto_wb = false; - cam_mod->hflip = false; - cam_mod->vflip = false; cam_mod->auto_adjust_fps = true; cam_mod->rotation = 0; cam_mod->ctrl_updt = 0; @@ -484,6 +482,10 @@ int aptina_camera_module_s_fmt(struct v4l2_subdev *sd, aptina_camera_module_set_active_config(cam_mod, aptina_camera_module_find_config(cam_mod, fmt, &cam_mod->frm_intrvl)); + } else { + aptina_camera_module_set_active_config(cam_mod, + aptina_camera_module_find_config(cam_mod, + fmt, NULL)); } return 0; err: @@ -525,6 +527,9 @@ int aptina_camera_module_s_frame_interval( unsigned long gcdiv; struct v4l2_subdev_frame_interval norm_interval; int ret = 0; + struct aptina_camera_module_config *config; + unsigned int vts; + pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); if ((interval->interval.denominator == 0) || @@ -551,22 +556,63 @@ int aptina_camera_module_s_frame_interval( norm_interval.interval.denominator = interval->interval.denominator / gcdiv; - if (IS_ERR_OR_NULL(aptina_camera_module_find_config(cam_mod, - NULL, &norm_interval))) { - pltfrm_camera_module_pr_err(&cam_mod->sd, - "frame interval %d/%d not supported\n", - interval->interval.numerator, - interval->interval.denominator); - ret = -EINVAL; - goto err; + if (!cam_mod->frm_fmt_valid) + goto end; + + config = aptina_camera_module_find_config( + cam_mod, + &cam_mod->active_config->frm_fmt, + &norm_interval); + + if (!IS_ERR_OR_NULL(config) && (config != cam_mod->active_config)) { + aptina_camera_module_set_active_config(cam_mod, config); + if (cam_mod->state == APTINA_CAMERA_MODULE_STREAMING) { + cam_mod->custom.stop_streaming(cam_mod); + aptina_camera_module_write_config(cam_mod); + cam_mod->custom.start_streaming(cam_mod); + } + } else { + if (IS_ERR_OR_NULL(cam_mod->active_config)) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "no active sensor configuration"); + ret = -EFAULT; + goto err; + } + if (cam_mod->active_config->frm_intrvl.interval.denominator < + norm_interval.interval.denominator) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "%dx%d@%dfps isn't support!", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + norm_interval.interval.denominator); + ret = -EFAULT; + goto err; + } + if (!cam_mod->custom.s_vts) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "custom.s_vts isn't support!"); + ret = -EFAULT; + goto err; + } + + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= norm_interval.interval.denominator; + cam_mod->vts_cur = vts; + + if (cam_mod->state != APTINA_CAMERA_MODULE_STREAMING) + goto end; + + cam_mod->custom.s_vts(cam_mod, vts); } + +end: cam_mod->frm_intrvl_valid = true; cam_mod->frm_intrvl = norm_interval; - if (cam_mod->frm_fmt_valid) { - aptina_camera_module_set_active_config(cam_mod, - aptina_camera_module_find_config(cam_mod, - &cam_mod->frm_fmt, interval)); - } + cam_mod->auto_adjust_fps = false; return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, @@ -574,12 +620,34 @@ int aptina_camera_module_s_frame_interval( return ret; } +int aptina_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd); + + if (cam_mod->active_config) { + if (cam_mod->state == APTINA_CAMERA_MODULE_STREAMING) { + if (cam_mod->frm_intrvl_valid) { + *interval = cam_mod->frm_intrvl; + return 0; + } else { + *interval = cam_mod->active_config->frm_intrvl; + return 0; + } + } + } + + return -EFAULT; +} + /* ======================================================================== */ int aptina_camera_module_s_stream(struct v4l2_subdev *sd, int enable) { int ret = 0; struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd); + unsigned int vts; pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable); @@ -600,9 +668,6 @@ int aptina_camera_module_s_stream(struct v4l2_subdev *sd, int enable) goto err; } - if (!IS_ERR_OR_NULL(cam_mod->custom.set_flip)) - cam_mod->custom.set_flip(cam_mod); - if (cam_mod->update_config) { ret = aptina_camera_module_write_config(cam_mod); if (IS_ERR_VALUE(ret)) @@ -612,6 +677,29 @@ int aptina_camera_module_s_stream(struct v4l2_subdev *sd, int enable) ret = cam_mod->custom.start_streaming(cam_mod); if (IS_ERR_VALUE(ret)) goto err; + + if (cam_mod->frm_intrvl_valid) { + if ((cam_mod->frm_intrvl.interval.numerator != + cam_mod->active_config->frm_intrvl.interval.numerator) || + (cam_mod->frm_intrvl.interval.denominator != + cam_mod->active_config->frm_intrvl.interval.denominator)) { + if (cam_mod->frm_intrvl.interval.denominator > + cam_mod->active_config->frm_intrvl.interval.denominator) { + pltfrm_camera_module_pr_warn(&cam_mod->sd, + "sensor is not support stream: %dx%d@(%d/%d)fps!\n", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + cam_mod->frm_intrvl.interval.denominator, + cam_mod->frm_intrvl.interval.numerator); + goto end; + } + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= cam_mod->frm_intrvl.interval.denominator; + cam_mod->custom.s_vts(cam_mod, vts); + } + } + cam_mod->update_config = false; cam_mod->ctrl_updt = 0; mdelay(cam_mod->custom.power_up_delays_ms[2]); @@ -644,6 +732,7 @@ int aptina_camera_module_s_stream(struct v4l2_subdev *sd, int enable) msleep(wait_ms + 1); } +end: cam_mod->state_before_suspend = cam_mod->state; return 0; @@ -674,43 +763,43 @@ int aptina_camera_module_s_power(struct v4l2_subdev *sd, int on) } if (cam_mod->state == APTINA_CAMERA_MODULE_HW_STANDBY) { ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_PWR, - PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); + PLTFRM_CAMERA_MODULE_PIN_PWR, + PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); msleep(20); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_PD, - PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_PD, + PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); msleep(20); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_RESET, - PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_RESET, + PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); msleep(20); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_RESET, - PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_RESET, + PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); msleep(20); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_RESET, - PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_RESET, + PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); msleep(20); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_PD, - PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_PD, + PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); msleep(20); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_PD, - PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_PD, + PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE); msleep(20); if (!IS_ERR_VALUE(ret)) { @@ -742,19 +831,19 @@ int aptina_camera_module_s_power(struct v4l2_subdev *sd, int on) } if (cam_mod->state == APTINA_CAMERA_MODULE_SW_STANDBY) { ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_PD, - PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_PD, + PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_RESET, - PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_RESET, + PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); ret = pltfrm_camera_module_set_pin_state( - &cam_mod->sd, - PLTFRM_CAMERA_MODULE_PIN_PWR, - PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); + &cam_mod->sd, + PLTFRM_CAMERA_MODULE_PIN_PWR, + PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE); if (!IS_ERR_VALUE(ret)) cam_mod->state = @@ -805,6 +894,22 @@ int aptina_camera_module_g_ctrl(struct v4l2_subdev *sd, return 0; } + if (ctrl->id == V4L2_CID_HFLIP) { + ctrl->value = cam_mod->hflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_HFLIP %d\n", + ctrl->value); + return 0; + } + + if (ctrl->id == V4L2_CID_VFLIP) { + ctrl->value = cam_mod->vflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_VFLIP %d\n", + ctrl->value); + return 0; + } + if (IS_ERR_OR_NULL(cam_mod->active_config)) { pltfrm_camera_module_pr_err(&cam_mod->sd, "no active configuration\n"); @@ -897,10 +1002,6 @@ int aptina_camera_module_g_ctrl(struct v4l2_subdev *sd, "V4L2_CID_FOCUS_ABSOLUTE %d\n", ctrl->value); break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - /* TBD */ - /* fallthrough */ default: pltfrm_camera_module_pr_debug(&cam_mod->sd, "failed, unknown ctrl %d\n", ctrl->id); @@ -1038,12 +1139,14 @@ int aptina_camera_module_s_ext_ctrls( cam_mod->hflip = true; else cam_mod->hflip = false; + cam_mod->flip_flg = true; break; case V4L2_CID_VFLIP: if (ctrl->value) cam_mod->vflip = true; else cam_mod->vflip = false; + cam_mod->flip_flg = true; break; default: pltfrm_camera_module_pr_warn(&cam_mod->sd, @@ -1124,7 +1227,8 @@ long aptina_camera_module_ioctl(struct v4l2_subdev *sd, void *arg) { struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd); - int ret; + int ret, i; + unsigned int flag, val; pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); @@ -1176,16 +1280,60 @@ long aptina_camera_module_ioctl(struct v4l2_subdev *sd, timings->fine_integration_time_min = aptina_timings.fine_integration_time_min; - if (cam_mod->custom.g_exposure_valid_frame) - timings->exposure_valid_frame = - cam_mod->custom.g_exposure_valid_frame(cam_mod); + timings->exposure_valid_frame[0] = + cam_mod->custom.exposure_valid_frame[0]; + timings->exposure_valid_frame[1] = + cam_mod->custom.exposure_valid_frame[1]; /* *timings->exp_time = cam_mod->exp_config.exp_time; *timings->gain = cam_mod->exp_config.gain; */ - + if (cam_mod->active_config) { + timings->max_exp_gain_h = cam_mod->active_config->max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->active_config->max_exp_gain_l; + } else { + timings->max_exp_gain_h = cam_mod->custom.configs[0].max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->custom.configs[0].max_exp_gain_l; + } return ret; + } else if (cmd == RK_VIDIOC_SENSOR_CONFIGINFO) { + struct sensor_config_info_s *sensor_config = (struct sensor_config_info_s *)arg; + + sensor_config->config_num = cam_mod->custom.num_configs; + for (i = 0; i < cam_mod->custom.num_configs; i++) { + if (i >= SENSOR_CONFIG_NUM) + break; + sensor_config->sensor_fmt[i] = + pltfrm_camera_module_pix_fmt2csi2_dt(cam_mod->custom.configs[i].frm_fmt.code); + sensor_config->reso[i].width = cam_mod->custom.configs[i].frm_fmt.width; + sensor_config->reso[i].height = cam_mod->custom.configs[i].frm_fmt.height; + } + return 0; + } else if (cmd == RK_VIDIOC_SENSOR_REG_ACCESS) { + struct sensor_reg_rw_s *sensor_rw = (struct sensor_reg_rw_s *)arg; + + if (sensor_rw->reg_access_mode == SENSOR_READ_MODE) { + for (i = 0; i < cam_mod->custom.configs[0].reg_table_num_entries; i++) { + flag = cam_mod->custom.configs[0].reg_table[i].flag; + if (flag != PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) + break; + } + if (flag == PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) { + pltfrm_camera_module_pr_err(&cam_mod->sd, + "Can not get sensor reg type.\n"); + return -EINVAL; + } + sensor_rw->reg_addr_len = PLTFRM_CAMERA_MODULE_REG_LEN(flag); + sensor_rw->reg_data_len = PLTFRM_CAMERA_MODULE_DATA_LEN(flag); + pltfrm_camera_module_read_reg_ex(&cam_mod->sd, 1, flag, sensor_rw->addr, &val); + sensor_rw->data = val; + } else { + flag = (sensor_rw->reg_addr_len << PLTFRM_CAMERA_MODULE_REG_LEN_BIT); + flag |= (sensor_rw->reg_data_len << PLTFRM_CAMERA_MODULE_DATA_LEN_BIT); + pltfrm_camera_module_write_reg_ex(&cam_mod->sd, flag, sensor_rw->addr, sensor_rw->data); + } + return 0; } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) { struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg; struct aptina_camera_module_config *config; @@ -1205,9 +1353,14 @@ long aptina_camera_module_ioctl(struct v4l2_subdev *sd, pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg); return 0; } else if (cmd == PLTFRM_CIFCAM_ATTACH) { - aptina_camera_module_init(cam_mod, &cam_mod->custom); - pltfrm_camera_module_ioctl(sd, cmd, arg); - return aptina_camera_module_attach(cam_mod); + ret = aptina_camera_module_init(cam_mod, &cam_mod->custom); + if (!IS_ERR_VALUE(ret)) { + pltfrm_camera_module_ioctl(sd, cmd, arg); + return aptina_camera_module_attach(cam_mod); + } else { + aptina_camera_module_release(cam_mod); + return ret; + } } ret = pltfrm_camera_module_ioctl(sd, cmd, arg); @@ -1276,7 +1429,22 @@ static int aptina_camera_module_s_flip(struct aptina_camera_module *cam_mod) int aptina_camera_module_get_flip_mirror( struct aptina_camera_module *cam_mod) { - return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + int mode = 0; + + if (!cam_mod->flip_flg) + return -1; + + if (cam_mod->hflip) + mode |= APTINA_MIRROR_BIT_MASK; + else + mode &= ~APTINA_MIRROR_BIT_MASK; + + if (cam_mod->vflip) + mode |= APTINA_FLIP_BIT_MASK; + else + mode &= ~APTINA_FLIP_BIT_MASK; + + return mode; } int aptina_camera_module_enum_frameintervals( @@ -1373,9 +1541,13 @@ int aptina_camera_module_init(struct aptina_camera_module *cam_mod, struct aptina_camera_module_custom_config *custom) { int ret = 0; + int mode = 0; pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); + cam_mod->hflip = false; + cam_mod->vflip = false; + cam_mod->flip_flg = false; aptina_camera_module_reset(cam_mod); if (IS_ERR_OR_NULL(custom->start_streaming) || @@ -1415,6 +1587,12 @@ int aptina_camera_module_init(struct aptina_camera_module *cam_mod, *} */ + mode = pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + if (mode != -1) { + cam_mod->hflip = mode & APTINA_MIRROR_BIT_MASK ? true : false; + cam_mod->vflip = mode & APTINA_FLIP_BIT_MASK ? true : false; + cam_mod->flip_flg = true; + } return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, diff --git a/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.h b/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.h index 9f053051cb9c..415f74d464af 100644 --- a/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.h +++ b/drivers/media/i2c/soc_camera/rockchip/aptina_camera_module.h @@ -31,8 +31,8 @@ PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT #define aptina_camera_module_csi_config #define aptina_camera_module_reg pltfrm_camera_module_reg -#define APTINA_FLIP_BIT_MASK 0x2 -#define APTINA_MIRROR_BIT_MASK 0x1 +#define APTINA_FLIP_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_FLIP_BIT) +#define APTINA_MIRROR_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_MIRROR_BIT) #define APTINA_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01 #define APTINA_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02 @@ -88,6 +88,8 @@ struct aptina_camera_module_config { struct aptina_camera_module_timings timings; bool soft_reset; bool ignore_measurement_check; + u8 max_exp_gain_h; + u8 max_exp_gain_l; struct pltfrm_cam_itf itf_cfg; }; @@ -153,14 +155,19 @@ struct aptina_camera_module_custom_config { int (*g_ctrl)(struct aptina_camera_module *cam_mod, u32 ctrl_id); int (*g_timings)(struct aptina_camera_module *cam_mod, struct aptina_camera_module_timings *timings); + int (*s_vts)(struct aptina_camera_module *cam_mod, + u32 vts); int (*s_ext_ctrls)(struct aptina_camera_module *cam_mod, struct aptina_camera_module_ext_ctrls *ctrls); - int (*set_flip)(struct aptina_camera_module *cam_mod); + int (*set_flip)(struct aptina_camera_module *cam_mod, + struct pltfrm_camera_module_reg reglist[], + int len); struct aptina_camera_module_config *configs; int (*init_common)(struct aptina_camera_module *cam_mod); int (*g_exposure_valid_frame)(struct aptina_camera_module *cam_mod); u32 num_configs; u32 power_up_delays_ms[3]; + unsigned short exposure_valid_frame[2]; void *priv; struct aptina_camera_module_timings timings; }; @@ -178,6 +185,7 @@ struct aptina_camera_module { enum aptina_camera_module_state state_before_suspend; struct aptina_camera_module_config *active_config; u32 ctrl_updt; + u32 vts_cur; u32 vts_min; bool auto_adjust_fps; bool update_config; @@ -185,9 +193,11 @@ struct aptina_camera_module { bool frm_intrvl_valid; bool hflip; bool vflip; + bool flip_flg; u32 rotation; void *pltfm_data; bool inited; + struct mutex lock; }; #define aptina_camera_module_pr_info(cam_mod, fmt, arg...) \ @@ -238,6 +248,10 @@ int aptina_camera_module_s_frame_interval( struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); +int aptina_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval); + int aptina_camera_module_s_stream( struct v4l2_subdev *sd, int enable); diff --git a/drivers/media/i2c/soc_camera/rockchip/imx323_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/imx323_v4l2-i2c-subdev.c index b39afa63851b..94c428357411 100644 --- a/drivers/media/i2c/soc_camera/rockchip/imx323_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/imx323_v4l2-i2c-subdev.c @@ -124,6 +124,8 @@ static struct imx_camera_module_config imx323_configs[] = { sizeof(imx323_init_tab_1920_1080_30fps) / sizeof(imx323_init_tab_1920_1080_30fps[0]), .v_blanking_time_us = 5000, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_DVP_CFG( PLTFRM_CAM_ITF_BT601_12, PLTFRM_CAM_SIGNAL_HIGH_LEVEL, @@ -170,10 +172,9 @@ static int imx323_auto_adjust_fps(struct imx_camera_module *cam_mod, int ret; u32 vts; - if ((cam_mod->exp_config.exp_time + IMX323_COARSE_INTG_TIME_MAX_MARGIN) + if ((exp_time + IMX323_COARSE_INTG_TIME_MAX_MARGIN) > cam_mod->vts_min) - vts = cam_mod->exp_config.exp_time + - IMX323_COARSE_INTG_TIME_MAX_MARGIN; + vts = exp_time + IMX323_COARSE_INTG_TIME_MAX_MARGIN; else vts = cam_mod->vts_min; ret = imx_camera_module_write_reg(cam_mod, @@ -181,12 +182,14 @@ static int imx323_auto_adjust_fps(struct imx_camera_module *cam_mod, ret |= imx_camera_module_write_reg(cam_mod, IMX323_TIMING_VTS_HIGH_REG, (vts >> 8) & 0xFF); - if (IS_ERR_VALUE(ret)) + if (IS_ERR_VALUE(ret)) { imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); - else - imx_camera_module_pr_debug(cam_mod, + } else { + imx_camera_module_pr_info(cam_mod, "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min); + cam_mod->vts_cur = vts; + } return ret; } @@ -240,6 +243,7 @@ static int imx323_write_aec(struct imx_camera_module *cam_mod) a_gain = a_gain * cam_mod->exp_config.gain_percent / 100; + mutex_lock(&cam_mod->lock); if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps) ret = imx323_auto_adjust_fps(cam_mod, cam_mod->exp_config.exp_time); @@ -258,6 +262,7 @@ static int imx323_write_aec(struct imx_camera_module *cam_mod) if (!cam_mod->auto_adjust_fps) ret |= imx323_set_vts(cam_mod, cam_mod->exp_config.vts_value); + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -373,6 +378,8 @@ static int imx323_g_timings(struct imx_camera_module *cam_mod, * vts * timings->line_length_pck; + timings->frame_length_lines = vts; + return ret; err: imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); @@ -381,9 +388,12 @@ static int imx323_g_timings(struct imx_camera_module *cam_mod, /*--------------------------------------------------------------------------*/ -static int imx323_set_flip(struct imx_camera_module *cam_mod) +static int imx323_set_flip( + struct imx_camera_module *cam_mod, + struct pltfrm_camera_module_reg reglist[], + int len) { - int mode = 0; + int i, mode = 0; u16 orientation = 0; mode = imx_camera_module_get_flip_mirror(cam_mod); @@ -394,15 +404,14 @@ static int imx323_set_flip(struct imx_camera_module *cam_mod) } if (!IS_ERR_OR_NULL(cam_mod->active_config)) { - if (mode == IMX_FLIP_BIT_MASK) - orientation = IMX323_ORIENTATION_V; - else if (mode == IMX_MIRROR_BIT_MASK) - orientation = IMX323_ORIENTATION_H; - else if (mode == (IMX_MIRROR_BIT_MASK | IMX_FLIP_BIT_MASK)) - orientation = IMX323_ORIENTATION_H | - IMX323_ORIENTATION_V; - else - orientation = 0; + if (PLTFRM_CAMERA_MODULE_IS_MIRROR(mode)) + orientation |= 0x01; + if (PLTFRM_CAMERA_MODULE_IS_FLIP(mode)) + orientation |= 0x02; + for (i = 0; i < len; i++) { + if (reglist[i].reg == IMX323_ORIENTATION_REG) + reglist[i].val = orientation; + } } return 0; @@ -443,14 +452,8 @@ static int imx323_s_ext_ctrls(struct imx_camera_module *cam_mod, { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = imx323_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = imx323_write_aec(cam_mod); else ret = -EINVAL; @@ -474,7 +477,10 @@ static int imx323_start_streaming(struct imx_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; - if (IS_ERR_VALUE(imx_camera_module_write_reg(cam_mod, 0x0100, 1))) + mutex_lock(&cam_mod->lock); + ret = imx_camera_module_write_reg(cam_mod, 0x0100, 1); + mutex_unlock(&cam_mod->lock); + if (IS_ERR_VALUE(ret)) goto err; msleep(25); @@ -494,7 +500,9 @@ static int imx323_stop_streaming(struct imx_camera_module *cam_mod) imx_camera_module_pr_debug(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = imx_camera_module_write_reg(cam_mod, 0x0100, 0); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -553,6 +561,7 @@ static struct v4l2_subdev_core_ops imx323_camera_module_core_ops = { static struct v4l2_subdev_video_ops imx323_camera_module_video_ops = { .s_frame_interval = imx_camera_module_s_frame_interval, + .g_frame_interval = imx_camera_module_g_frame_interval, .s_stream = imx_camera_module_s_stream }; @@ -577,9 +586,16 @@ static struct imx_camera_module_custom_config imx323_custom_config = { .g_timings = imx323_g_timings, .check_camera_id = imx323_check_camera_id, .set_flip = imx323_set_flip, + .s_vts = imx323_auto_adjust_fps, .configs = imx323_configs, .num_configs = ARRAY_SIZE(imx323_configs), - .power_up_delays_ms = {5, 20, 0} + .power_up_delays_ms = {5, 20, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int imx323_probe( @@ -590,8 +606,10 @@ static int imx323_probe( imx323_filltimings(&imx323_custom_config); v4l2_i2c_subdev_init(&imx323.sd, client, &imx323_camera_module_ops); + imx323.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx323.custom = imx323_custom_config; + mutex_init(&imx323.lock); dev_info(&client->dev, "probing successful\n"); return 0; } @@ -605,6 +623,7 @@ static int imx323_remove(struct i2c_client *client) if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); imx_camera_module_release(cam_mod); dev_info(&client->dev, "removed\n"); diff --git a/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.c b/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.c index 217151826903..8cccfe425de3 100644 --- a/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.c +++ b/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.c @@ -45,8 +45,6 @@ static void imx_camera_module_reset( cam_mod->exp_config.auto_exp = false; cam_mod->exp_config.auto_gain = false; cam_mod->wb_config.auto_wb = false; - cam_mod->hflip = false; - cam_mod->vflip = false; cam_mod->auto_adjust_fps = true; cam_mod->rotation = 0; cam_mod->ctrl_updt = 0; @@ -194,7 +192,8 @@ static int imx_camera_module_write_config( } if (!IS_ERR_OR_NULL(cam_mod->custom.set_flip)) - cam_mod->custom.set_flip(cam_mod); + cam_mod->custom.set_flip(cam_mod, + reg_table, reg_table_num_entries); ret = pltfrm_camera_module_write_reglist(&cam_mod->sd, reg_table, reg_table_num_entries); @@ -284,6 +283,10 @@ int imx_camera_module_s_fmt(struct v4l2_subdev *sd, imx_camera_module_set_active_config(cam_mod, imx_camera_module_find_config(cam_mod, fmt, &cam_mod->frm_intrvl)); + } else { + imx_camera_module_set_active_config(cam_mod, + imx_camera_module_find_config(cam_mod, + fmt, NULL)); } return 0; err: @@ -324,6 +327,8 @@ int imx_camera_module_s_frame_interval( struct imx_camera_module *cam_mod = to_imx_camera_module(sd); unsigned long gcdiv; struct v4l2_subdev_frame_interval norm_interval; + struct imx_camera_module_config *config; + unsigned int vts; int ret = 0; if ((interval->interval.denominator == 0) || @@ -350,22 +355,62 @@ int imx_camera_module_s_frame_interval( norm_interval.interval.denominator = interval->interval.denominator / gcdiv; - if (IS_ERR_OR_NULL(imx_camera_module_find_config(cam_mod, - NULL, &norm_interval))) { - pltfrm_camera_module_pr_err(&cam_mod->sd, - "frame interval %d/%d not supported\n", - interval->interval.numerator, - interval->interval.denominator); - ret = -EINVAL; - goto err; + if (!cam_mod->frm_fmt_valid) + goto end; + config = imx_camera_module_find_config( + cam_mod, + &cam_mod->active_config->frm_fmt, + &norm_interval); + if (!IS_ERR_OR_NULL(config) && (config != cam_mod->active_config)) { + imx_camera_module_set_active_config(cam_mod, config); + if (cam_mod->state == IMX_CAMERA_MODULE_STREAMING) { + cam_mod->custom.stop_streaming(cam_mod); + imx_camera_module_write_config(cam_mod); + cam_mod->custom.start_streaming(cam_mod); + } + } else { + if (IS_ERR_OR_NULL(cam_mod->active_config)) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "no active sensor configuration"); + ret = -EFAULT; + goto err; + } + if (cam_mod->active_config->frm_intrvl.interval.denominator < + norm_interval.interval.denominator) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "%dx%d@%dfps isn't support!", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + norm_interval.interval.denominator); + ret = -EFAULT; + goto err; + } + + if (!cam_mod->custom.s_vts) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "custom.s_vts isn't support!"); + ret = -EFAULT; + goto err; + } + + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= norm_interval.interval.denominator; + cam_mod->vts_cur = vts; + + if (cam_mod->state != IMX_CAMERA_MODULE_STREAMING) + goto end; + + cam_mod->custom.s_vts(cam_mod, vts); } + +end: cam_mod->frm_intrvl_valid = true; cam_mod->frm_intrvl = norm_interval; - if (cam_mod->frm_fmt_valid) { - imx_camera_module_set_active_config(cam_mod, - imx_camera_module_find_config(cam_mod, - &cam_mod->frm_fmt, interval)); - } + cam_mod->auto_adjust_fps = false; return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, @@ -373,12 +418,34 @@ int imx_camera_module_s_frame_interval( return ret; } +int imx_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct imx_camera_module *cam_mod = to_imx_camera_module(sd); + + if (cam_mod->active_config) { + if (cam_mod->state == IMX_CAMERA_MODULE_STREAMING) { + if (cam_mod->frm_intrvl_valid) { + *interval = cam_mod->frm_intrvl; + return 0; + } else { + *interval = cam_mod->active_config->frm_intrvl; + return 0; + } + } + } + + return -EFAULT; +} + /* ======================================================================== */ int imx_camera_module_s_stream(struct v4l2_subdev *sd, int enable) { int ret = 0; struct imx_camera_module *cam_mod = to_imx_camera_module(sd); + unsigned int vts; pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable); @@ -407,12 +474,36 @@ int imx_camera_module_s_stream(struct v4l2_subdev *sd, int enable) ret = cam_mod->custom.start_streaming(cam_mod); if (IS_ERR_VALUE(ret)) goto err; + + if (cam_mod->frm_intrvl_valid) { + if ((cam_mod->frm_intrvl.interval.numerator != + cam_mod->active_config->frm_intrvl.interval.numerator) || + (cam_mod->frm_intrvl.interval.denominator != + cam_mod->active_config->frm_intrvl.interval.denominator)) { + if (cam_mod->frm_intrvl.interval.denominator > + cam_mod->active_config->frm_intrvl.interval.denominator) { + pltfrm_camera_module_pr_warn(&cam_mod->sd, + "sensor is not support stream: %dx%d@(%d/%d)fps!\n", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + cam_mod->frm_intrvl.interval.denominator, + cam_mod->frm_intrvl.interval.numerator); + goto end; + } + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= cam_mod->frm_intrvl.interval.denominator; + cam_mod->custom.s_vts(cam_mod, vts); + } + } + if (!cam_mod->inited && cam_mod->update_config) cam_mod->inited = true; cam_mod->update_config = false; cam_mod->ctrl_updt = 0; mdelay(cam_mod->custom.power_up_delays_ms[2]); cam_mod->state = IMX_CAMERA_MODULE_STREAMING; + } else { int pclk; int wait_ms; @@ -451,6 +542,7 @@ int imx_camera_module_s_stream(struct v4l2_subdev *sd, int enable) msleep(wait_ms + 1); } +end: cam_mod->state_before_suspend = cam_mod->state; return 0; @@ -558,6 +650,22 @@ int imx_camera_module_g_ctrl(struct v4l2_subdev *sd, return 0; } + if (ctrl->id == V4L2_CID_HFLIP) { + ctrl->value = cam_mod->hflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_HFLIP %d\n", + ctrl->value); + return 0; + } + + if (ctrl->id == V4L2_CID_VFLIP) { + ctrl->value = cam_mod->vflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_VFLIP %d\n", + ctrl->value); + return 0; + } + if (IS_ERR_OR_NULL(cam_mod->active_config)) { pltfrm_camera_module_pr_err(&cam_mod->sd, "no active configuration\n"); @@ -644,10 +752,6 @@ int imx_camera_module_g_ctrl(struct v4l2_subdev *sd, "V4L2_CID_FOCUS_ABSOLUTE %d\n", ctrl->value); break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - /* TBD */ - /* fallthrough */ default: pltfrm_camera_module_pr_debug(&cam_mod->sd, "failed, unknown ctrl %d\n", ctrl->id); @@ -787,12 +891,14 @@ int imx_camera_module_s_ext_ctrls( cam_mod->hflip = true; else cam_mod->hflip = false; + cam_mod->flip_flg = true; break; case V4L2_CID_VFLIP: if (ctrl->value) cam_mod->vflip = true; else cam_mod->vflip = false; + cam_mod->flip_flg = true; break; default: pltfrm_camera_module_pr_warn(&cam_mod->sd, @@ -871,7 +977,8 @@ long imx_camera_module_ioctl(struct v4l2_subdev *sd, void *arg) { struct imx_camera_module *cam_mod = to_imx_camera_module(sd); - int ret; + int ret, i; + unsigned int flag, val; pltfrm_camera_module_pr_debug(&cam_mod->sd, "cmd: 0x%x\n", cmd); @@ -916,9 +1023,10 @@ long imx_camera_module_ioctl(struct v4l2_subdev *sd, timings->fine_integration_time_min = imx_timings.fine_integration_time_min; - if (cam_mod->custom.g_exposure_valid_frame) - timings->exposure_valid_frame[0] = - cam_mod->custom.g_exposure_valid_frame(cam_mod); + timings->exposure_valid_frame[0] = + cam_mod->custom.exposure_valid_frame[0]; + timings->exposure_valid_frame[1] = + cam_mod->custom.exposure_valid_frame[1]; timings->exp_time = cam_mod->exp_config.exp_time; timings->gain = cam_mod->exp_config.gain; @@ -931,7 +1039,52 @@ long imx_camera_module_ioctl(struct v4l2_subdev *sd, timings->gain = cam_mod->exp_config.gain; else timings->gain = imx_timings.gain; + + if (cam_mod->active_config) { + timings->max_exp_gain_h = cam_mod->active_config->max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->active_config->max_exp_gain_l; + } else { + timings->max_exp_gain_h = cam_mod->custom.configs[0].max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->custom.configs[0].max_exp_gain_l; + } return ret; + } else if (cmd == RK_VIDIOC_SENSOR_CONFIGINFO) { + struct sensor_config_info_s *sensor_config = (struct sensor_config_info_s *)arg; + + sensor_config->config_num = cam_mod->custom.num_configs; + for (i = 0; i < cam_mod->custom.num_configs; i++) { + if (i >= SENSOR_CONFIG_NUM) + break; + sensor_config->sensor_fmt[i] = + pltfrm_camera_module_pix_fmt2csi2_dt(cam_mod->custom.configs[i].frm_fmt.code); + sensor_config->reso[i].width = cam_mod->custom.configs[i].frm_fmt.width; + sensor_config->reso[i].height = cam_mod->custom.configs[i].frm_fmt.height; + } + return 0; + } else if (cmd == RK_VIDIOC_SENSOR_REG_ACCESS) { + struct sensor_reg_rw_s *sensor_rw = (struct sensor_reg_rw_s *)arg; + + if (sensor_rw->reg_access_mode == SENSOR_READ_MODE) { + for (i = 0; i < cam_mod->custom.configs[0].reg_table_num_entries; i++) { + flag = cam_mod->custom.configs[0].reg_table[i].flag; + if (flag != PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) + break; + } + if (flag == PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) { + pltfrm_camera_module_pr_err(&cam_mod->sd, + "Can not get sensor reg type.\n"); + return -EINVAL; + } + sensor_rw->reg_addr_len = PLTFRM_CAMERA_MODULE_REG_LEN(flag); + sensor_rw->reg_data_len = PLTFRM_CAMERA_MODULE_DATA_LEN(flag); + pltfrm_camera_module_read_reg_ex(&cam_mod->sd, 1, flag, sensor_rw->addr, &val); + sensor_rw->data = val; + } else { + flag = (sensor_rw->reg_addr_len << PLTFRM_CAMERA_MODULE_REG_LEN_BIT); + flag |= (sensor_rw->reg_data_len << PLTFRM_CAMERA_MODULE_DATA_LEN_BIT); + pltfrm_camera_module_write_reg_ex(&cam_mod->sd, flag, sensor_rw->addr, sensor_rw->data); + } + return 0; } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) { struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg; struct imx_camera_module_config *config; @@ -952,9 +1105,14 @@ long imx_camera_module_ioctl(struct v4l2_subdev *sd, pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg); return 0; } else if (cmd == PLTFRM_CIFCAM_ATTACH) { - imx_camera_module_init(cam_mod, &cam_mod->custom); - pltfrm_camera_module_ioctl(sd, cmd, arg); - return imx_camera_module_attach(cam_mod); + ret = imx_camera_module_init(cam_mod, &cam_mod->custom); + if (!IS_ERR_VALUE(ret)) { + pltfrm_camera_module_ioctl(sd, cmd, arg); + return imx_camera_module_attach(cam_mod); + } else { + imx_camera_module_release(cam_mod); + return ret; + } } ret = pltfrm_camera_module_ioctl(sd, cmd, arg); @@ -966,7 +1124,22 @@ long imx_camera_module_ioctl(struct v4l2_subdev *sd, int imx_camera_module_get_flip_mirror( struct imx_camera_module *cam_mod) { - return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + int mode = 0; + + if (!cam_mod->flip_flg) + return -1; + + if (cam_mod->hflip) + mode |= IMX_MIRROR_BIT_MASK; + else + mode &= ~IMX_MIRROR_BIT_MASK; + + if (cam_mod->vflip) + mode |= IMX_FLIP_BIT_MASK; + else + mode &= ~IMX_FLIP_BIT_MASK; + + return mode; } /* ======================================================================== */ @@ -1065,9 +1238,13 @@ int imx_camera_module_init(struct imx_camera_module *cam_mod, struct imx_camera_module_custom_config *custom) { int ret = 0; + int mode = 0; pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); + cam_mod->hflip = false; + cam_mod->vflip = false; + cam_mod->flip_flg = false; imx_camera_module_reset(cam_mod); if (IS_ERR_OR_NULL(custom->start_streaming) || @@ -1095,6 +1272,12 @@ int imx_camera_module_init(struct imx_camera_module *cam_mod, goto err; } + mode = pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + if (mode != -1) { + cam_mod->hflip = mode & IMX_MIRROR_BIT_MASK ? true : false; + cam_mod->vflip = mode & IMX_FLIP_BIT_MASK ? true : false; + cam_mod->flip_flg = true; + } return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, diff --git a/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.h b/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.h index ffd135ab672f..d0f691d8fddd 100644 --- a/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.h +++ b/drivers/media/i2c/soc_camera/rockchip/imx_camera_module.h @@ -30,8 +30,8 @@ #define imx_camera_module_csi_config #define imx_camera_module_reg pltfrm_camera_module_reg -#define IMX_FLIP_BIT_MASK 0x2 -#define IMX_MIRROR_BIT_MASK 0x1 +#define IMX_FLIP_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_FLIP_BIT) +#define IMX_MIRROR_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_MIRROR_BIT) #define IMX_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01 #define IMX_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02 @@ -88,6 +88,8 @@ struct imx_camera_module_config { struct imx_camera_module_timings timings; bool soft_reset; bool ignore_measurement_check; + u8 max_exp_gain_h; + u8 max_exp_gain_l; struct pltfrm_cam_itf itf_cfg; }; @@ -153,14 +155,18 @@ struct imx_camera_module_custom_config { int (*g_ctrl)(struct imx_camera_module *cam_mod, u32 ctrl_id); int (*g_timings)(struct imx_camera_module *cam_mod, struct imx_camera_module_timings *timings); - int (*g_exposure_valid_frame)(struct imx_camera_module *cam_mod); + int (*s_vts)(struct imx_camera_module *cam_mod, + u32 vts); int (*s_ext_ctrls)(struct imx_camera_module *cam_mod, struct imx_camera_module_ext_ctrls *ctrls); - int (*set_flip)(struct imx_camera_module *cam_mod); + int (*set_flip)(struct imx_camera_module *cam_mod, + struct pltfrm_camera_module_reg reglist[], + int len); int (*init_common)(struct imx_camera_module *cam_mod); struct imx_camera_module_config *configs; u32 num_configs; u32 power_up_delays_ms[3]; + unsigned short exposure_valid_frame[2]; void *priv; }; @@ -192,9 +198,11 @@ struct imx_camera_module { bool frm_intrvl_valid; bool hflip; bool vflip; + bool flip_flg; u32 rotation; void *pltfm_data; bool inited; + struct mutex lock; }; #define imx_camera_module_pr_info(cam_mod, fmt, arg...) \ @@ -239,6 +247,10 @@ int imx_camera_module_s_frame_interval( struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); +int imx_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval); + int imx_camera_module_s_stream( struct v4l2_subdev *sd, int enable); diff --git a/drivers/media/i2c/soc_camera/rockchip/nt99230_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/nt99230_v4l2-i2c-subdev.c index a8d9200f97fd..cb88fb06c6f5 100644 --- a/drivers/media/i2c/soc_camera/rockchip/nt99230_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/nt99230_v4l2-i2c-subdev.c @@ -570,6 +570,8 @@ static struct ov_camera_module_config NT99230_configs[] = { sizeof(NT99230_init_tab_1920_1080_30fps_raw) / sizeof(NT99230_init_tab_1920_1080_30fps_raw[0]), .v_blanking_time_us = 4052, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, .ignore_measurement_check = 1, PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 450, 24000000) } @@ -650,6 +652,7 @@ static int NT99230_write_aec(struct ov_camera_module *cam_mod) u32 a_gain = cam_mod->exp_config.gain; u32 exp_time = cam_mod->exp_config.exp_time; + mutex_lock(&cam_mod->lock); if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps) ret = NT99230_auto_adjust_fps(cam_mod, cam_mod->exp_config.exp_time); @@ -659,6 +662,7 @@ static int NT99230_write_aec(struct ov_camera_module *cam_mod) if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) ret = ov_camera_module_write_reg(cam_mod, NT99230_AEC_UPDATE_ADDRESS, NT99230_AEC_UPDATE_DATA); + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -866,14 +870,8 @@ static int NT99230_s_ext_ctrls(struct ov_camera_module *cam_mod, { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = NT99230_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if (ctrls->count == 2 && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = NT99230_write_aec(cam_mod); else ret = -EINVAL; @@ -897,7 +895,9 @@ static int NT99230_start_streaming(struct ov_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x3021, 0x02); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; msleep(25); @@ -916,7 +916,9 @@ static int NT99230_stop_streaming(struct ov_camera_module *cam_mod) ov_camera_module_pr_info(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x3021, 0x00);; + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -976,6 +978,7 @@ static struct v4l2_subdev_core_ops NT99230_camera_module_core_ops = { static struct v4l2_subdev_video_ops NT99230_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -1003,7 +1006,13 @@ static struct ov_camera_module_custom_config NT99230_custom_config = { .check_camera_id = NT99230_check_camera_id, .configs = NT99230_configs, .num_configs = sizeof(NT99230_configs) / sizeof(NT99230_configs[0]), - .power_up_delays_ms = {5, 30, 0} + .power_up_delays_ms = {5, 30, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int NT99230_probe( @@ -1025,6 +1034,7 @@ static int NT99230_probe( tmp_NT99230->custom = NT99230_custom_config; num_cameras++; + mutex_init(&tmp_NT99230->lock); dev_info(&client->dev, "probing successful\n"); return 0; } @@ -1041,6 +1051,7 @@ static int NT99230_remove( if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); ov_camera_module_release(cam_mod); dev_info(&client->dev, "removed\n"); diff --git a/drivers/media/i2c/soc_camera/rockchip/ov13850_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/ov13850_v4l2-i2c-subdev.c index a16a520fd993..7394ef3ce80a 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov13850_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov13850_v4l2-i2c-subdev.c @@ -1308,6 +1308,8 @@ static struct ov_camera_module_config ov13850_configs[] = { sizeof(ov13850_regs_2112_1568_30fps_twolane_r2a) / sizeof(ov13850_regs_2112_1568_30fps_twolane_r2a[0]), .v_blanking_time_us = 5000, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 600, ov13850_EXT_CLK) }, @@ -1332,6 +1334,8 @@ static struct ov_camera_module_config ov13850_configs[] = { sizeof(ov13850_regs_4224_3136_7fps_twolane_r2a) / sizeof(ov13850_regs_4224_3136_7fps_twolane_r2a[0]), .v_blanking_time_us = 5000, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 600, ov13850_EXT_CLK) } }; @@ -1358,6 +1362,8 @@ static struct ov_camera_module_config ov13850_onelane_configs[] = { sizeof(ov13850_init_tab_2112_1568_15fps) / sizeof(ov13850_init_tab_2112_1568_15fps[0]), .v_blanking_time_us = 5000, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 1, 640, ov13850_EXT_CLK) } }; @@ -1394,11 +1400,9 @@ static int ov13850_auto_adjust_fps(struct ov_camera_module *cam_mod, int ret; u32 vts; - if ((cam_mod->exp_config.exp_time + - ov13850_COARSE_INTG_TIME_MAX_MARGIN) - > cam_mod->vts_min) - vts = cam_mod->exp_config.exp_time + - ov13850_COARSE_INTG_TIME_MAX_MARGIN; + if ((exp_time + ov13850_COARSE_INTG_TIME_MAX_MARGIN) + > cam_mod->vts_min) + vts = exp_time + ov13850_COARSE_INTG_TIME_MAX_MARGIN; else vts = cam_mod->vts_min; ret = ov_camera_module_write_reg(cam_mod, @@ -1407,13 +1411,15 @@ static int ov13850_auto_adjust_fps(struct ov_camera_module *cam_mod, ov13850_TIMING_VTS_HIGH_REG, (vts >> 8) & 0xFF); - if (IS_ERR_VALUE(ret)) + if (IS_ERR_VALUE(ret)) { ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); - else - ov_camera_module_pr_debug(cam_mod, + } else { + ov_camera_module_pr_info(cam_mod, "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min); + cam_mod->vts_cur = vts; + } return ret; } @@ -1468,6 +1474,7 @@ static int ov13850_write_aec(struct ov_camera_module *cam_mod) a_gain = a_gain * cam_mod->exp_config.gain_percent / 100; + mutex_lock(&cam_mod->lock); if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) ret = ov_camera_module_write_reg(cam_mod, ov13850_AEC_GROUP_UPDATE_ADDRESS, @@ -1500,6 +1507,7 @@ static int ov13850_write_aec(struct ov_camera_module *cam_mod) ov13850_AEC_GROUP_UPDATE_ADDRESS, ov13850_AEC_GROUP_UPDATE_END_LAUNCH); } + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -1648,23 +1656,28 @@ static int ov13850_g_timings(struct ov_camera_module *cam_mod, struct ov_camera_module_timings *timings) { int ret = 0; + unsigned int vts; if (IS_ERR_OR_NULL(cam_mod->active_config)) goto err; *timings = cam_mod->active_config->timings; + vts = (!cam_mod->vts_cur) ? + timings->frame_length_lines : + cam_mod->vts_cur; if (cam_mod->frm_intrvl_valid) timings->vt_pix_clk_freq_hz = cam_mod->frm_intrvl.interval.denominator - * timings->frame_length_lines + * vts * timings->line_length_pck; else timings->vt_pix_clk_freq_hz = cam_mod->active_config->frm_intrvl.interval.denominator - * timings->frame_length_lines + * vts * timings->line_length_pck; + timings->frame_length_lines = vts; return ret; err: ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); @@ -1771,13 +1784,8 @@ static int ov13850_s_ext_ctrls(struct ov_camera_module *cam_mod, int ret = 0; /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = ov13850_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = ov13850_write_aec(cam_mod); else ret = -EINVAL; @@ -1801,7 +1809,10 @@ static int ov13850_start_streaming(struct ov_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; - if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1))) + mutex_lock(&cam_mod->lock); + ret = ov_camera_module_write_reg(cam_mod, 0x0100, 1); + mutex_unlock(&cam_mod->lock); + if (IS_ERR_VALUE(ret)) goto err; msleep(25); @@ -1821,7 +1832,9 @@ static int ov13850_stop_streaming(struct ov_camera_module *cam_mod) ov_camera_module_pr_debug(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -1881,6 +1894,7 @@ static struct v4l2_subdev_core_ops ov13850_camera_module_core_ops = { static struct v4l2_subdev_video_ops ov13850_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -1904,6 +1918,7 @@ static struct ov_camera_module_custom_config ov13850_custom_config = { .g_ctrl = ov13850_g_ctrl, .g_timings = ov13850_g_timings, .check_camera_id = ov13850_check_camera_id, + .s_vts = ov13850_auto_adjust_fps, .set_flip = ov13850_set_flip, #ifdef OV13850_ONE_LANE .configs = ov13850_onelane_configs, @@ -1913,7 +1928,13 @@ static struct ov_camera_module_custom_config ov13850_custom_config = { .configs = ov13850_configs, .num_configs = ARRAY_SIZE(ov13850_configs), #endif - .power_up_delays_ms = {5, 20, 0} + .power_up_delays_ms = {5, 20, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int ov13850_probe(struct i2c_client *client, @@ -1923,9 +1944,10 @@ static int ov13850_probe(struct i2c_client *client, ov13850_filltimings(&ov13850_custom_config); v4l2_i2c_subdev_init(&ov13850.sd, client, &ov13850_camera_module_ops); - + ov13850.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov13850.custom = ov13850_custom_config; + mutex_init(&ov13850.lock); dev_info(&client->dev, "probing successful\n"); return 0; } @@ -1939,6 +1961,7 @@ static int ov13850_remove(struct i2c_client *client) if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); ov_camera_module_release(cam_mod); dev_info(&client->dev, "removed\n"); diff --git a/drivers/media/i2c/soc_camera/rockchip/ov2710_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/ov2710_v4l2-i2c-subdev.c index 3a1b7878885a..0b600a95b4c7 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov2710_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov2710_v4l2-i2c-subdev.c @@ -236,6 +236,8 @@ static struct ov_camera_module_config ov2710_configs[] = { sizeof(ov2710_init_tab_1920_1080_30fps) / sizeof(ov2710_init_tab_1920_1080_30fps[0]), .v_blanking_time_us = 3078, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, .ignore_measurement_check = 1, PLTFRM_CAM_ITF_MIPI_CFG(0, 1, 800, 24000000) } @@ -325,18 +327,12 @@ static int OV2710_auto_adjust_fps(struct ov_camera_module *cam_mod, int ret; u32 vts; - if ((cam_mod->exp_config.exp_time + OV2710_COARSE_INTG_TIME_MAX_MARGIN) + if ((exp_time + OV2710_COARSE_INTG_TIME_MAX_MARGIN) > cam_mod->vts_min) - vts = cam_mod->exp_config.exp_time + - OV2710_COARSE_INTG_TIME_MAX_MARGIN; + vts = exp_time + OV2710_COARSE_INTG_TIME_MAX_MARGIN; else vts = cam_mod->vts_min; - /* - * if (cam_mod->fps_ctrl > 0 && cam_mod->fps_ctrl < 100) - * vts = vts * 100 / cam_mod->fps_ctrl; - */ - if (vts > 0xfff) vts = 0xfff; else @@ -349,13 +345,15 @@ static int OV2710_auto_adjust_fps(struct ov_camera_module *cam_mod, OV2710_TIMING_VTS_HIGH_REG, (vts >> 8) & 0x0F); - if (IS_ERR_VALUE(ret)) + if (IS_ERR_VALUE(ret)) { ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); - else - ov_camera_module_pr_debug(cam_mod, + } else { + ov_camera_module_pr_info(cam_mod, "updated vts = 0x%x,vts_min=0x%x\n", vts, cam_mod->vts_min); + cam_mod->vts_cur = vts; + } return ret; } @@ -409,6 +407,7 @@ static int ov2710_write_aec(struct ov_camera_module *cam_mod) a_gain = a_gain * cam_mod->exp_config.gain_percent / 100; + mutex_lock(&cam_mod->lock); if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) ret = ov_camera_module_write_reg(cam_mod, OV2710_AEC_GROUP_UPDATE_ADDRESS, @@ -441,6 +440,7 @@ static int ov2710_write_aec(struct ov_camera_module *cam_mod) OV2710_AEC_GROUP_UPDATE_ADDRESS, OV2710_AEC_GROUP_UPDATE_END_LAUNCH); } + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -657,6 +657,7 @@ static int ov2710_g_timings(struct ov_camera_module *cam_mod, cam_mod->active_config->frm_intrvl.interval.denominator * vts * timings->line_length_pck; + timings->frame_length_lines = vts; return ret; err: ov_camera_module_pr_err(cam_mod, @@ -709,14 +710,8 @@ static int ov2710_s_ext_ctrls(struct ov_camera_module *cam_mod, { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = ov2710_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - (ctrls->ctrls[0].id == V4L2_CID_GAIN || - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE || - ctrls->ctrls[1].id == V4L2_CID_GAIN || - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE)) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = ov2710_write_aec(cam_mod); else ret = -EINVAL; @@ -741,9 +736,12 @@ static int ov2710_start_streaming(struct ov_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; ov_camera_module_pr_debug(cam_mod, "=====streaming on ===\n"); + + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x3008, 0x02); ret |= ov_camera_module_write_reg(cam_mod, 0x4201, 0x00); ret |= ov_camera_module_write_reg(cam_mod, 0x4202, 0x00); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -762,9 +760,11 @@ static int ov2710_stop_streaming(struct ov_camera_module *cam_mod) int ret = 0; ov_camera_module_pr_debug(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x3008, 0x42); ret |= ov_camera_module_write_reg(cam_mod, 0x4201, 0x00); ret |= ov_camera_module_write_reg(cam_mod, 0x4202, 0x0f); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -848,6 +848,7 @@ static struct v4l2_subdev_core_ops ov2710_camera_module_core_ops = { static struct v4l2_subdev_video_ops ov2710_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -874,9 +875,16 @@ static struct ov_camera_module_custom_config ov2710_custom_config = { .g_timings = ov2710_g_timings, .set_flip = ov2710_set_flip, .check_camera_id = ov2710_check_camera_id, + .s_vts = OV2710_auto_adjust_fps, .configs = ov2710_configs, .num_configs = ARRAY_SIZE(ov2710_configs), - .power_up_delays_ms = {5, 30, 30} + .power_up_delays_ms = {5, 30, 30}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 2} }; static int ov2710_probe( @@ -889,8 +897,10 @@ static int ov2710_probe( v4l2_i2c_subdev_init(&ov2710.sd, client, &ov2710_camera_module_ops); + ov2710.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov2710.custom = ov2710_custom_config; + mutex_init(&ov2710.lock); dev_info(&client->dev, "probing successful\n"); return 0; } @@ -907,6 +917,7 @@ static int ov2710_remove( if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); ov_camera_module_release(cam_mod); dev_info(&client->dev, "removed\n"); diff --git a/drivers/media/i2c/soc_camera/rockchip/ov4689_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/ov4689_v4l2-i2c-subdev.c index 12c554e6fb6a..f327446ccd45 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov4689_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov4689_v4l2-i2c-subdev.c @@ -365,6 +365,8 @@ static struct ov_camera_module_config ov4689_configs[] = { sizeof(ov4689_init_tab_2688_1520_30fps) / sizeof(ov4689_init_tab_2688_1520_30fps[0]), .v_blanking_time_us = 5000, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 999, ov4689_EXT_CLK) } }; @@ -402,11 +404,9 @@ static int ov4689_auto_adjust_fps(struct ov_camera_module *cam_mod, int ret; u32 vts; - if ((cam_mod->exp_config.exp_time + - ov4689_COARSE_INTG_TIME_MAX_MARGIN) - > cam_mod->vts_min) - vts = cam_mod->exp_config.exp_time + - ov4689_COARSE_INTG_TIME_MAX_MARGIN; + if ((exp_time + ov4689_COARSE_INTG_TIME_MAX_MARGIN) + > cam_mod->vts_min) + vts = exp_time + ov4689_COARSE_INTG_TIME_MAX_MARGIN; else vts = cam_mod->vts_min; ret = ov_camera_module_write_reg(cam_mod, @@ -415,13 +415,15 @@ static int ov4689_auto_adjust_fps(struct ov_camera_module *cam_mod, ov4689_TIMING_VTS_HIGH_REG, (vts >> 8) & 0xFF); - if (IS_ERR_VALUE(ret)) + if (IS_ERR_VALUE(ret)) { ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); - else - ov_camera_module_pr_debug(cam_mod, + } else { + ov_camera_module_pr_info(cam_mod, "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min); + cam_mod->vts_cur = vts; + } return ret; } @@ -474,6 +476,7 @@ static int ov4689_write_aec(struct ov_camera_module *cam_mod) a_gain = a_gain * cam_mod->exp_config.gain_percent / 100; + mutex_lock(&cam_mod->lock); if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) ret = ov_camera_module_write_reg(cam_mod, ov4689_AEC_GROUP_UPDATE_ADDRESS, @@ -506,6 +509,7 @@ static int ov4689_write_aec(struct ov_camera_module *cam_mod) ov4689_AEC_GROUP_UPDATE_ADDRESS, ov4689_AEC_GROUP_UPDATE_END_LAUNCH); } + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -654,23 +658,28 @@ static int ov4689_g_timings(struct ov_camera_module *cam_mod, struct ov_camera_module_timings *timings) { int ret = 0; + unsigned int vts; if (IS_ERR_OR_NULL(cam_mod->active_config)) goto err; *timings = cam_mod->active_config->timings; + vts = (!cam_mod->vts_cur) ? + timings->frame_length_lines : + cam_mod->vts_cur; if (cam_mod->frm_intrvl_valid) timings->vt_pix_clk_freq_hz = cam_mod->frm_intrvl.interval.denominator - * timings->frame_length_lines + * vts * timings->line_length_pck; else timings->vt_pix_clk_freq_hz = cam_mod->active_config->frm_intrvl.interval.denominator - * timings->frame_length_lines + * vts * timings->line_length_pck; + timings->frame_length_lines = vts; return ret; err: ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); @@ -777,14 +786,8 @@ static int ov4689_s_ext_ctrls(struct ov_camera_module *cam_mod, { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = ov4689_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = ov4689_write_aec(cam_mod); else ret = -EINVAL; @@ -808,7 +811,10 @@ static int ov4689_start_streaming(struct ov_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; - if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1))) + mutex_lock(&cam_mod->lock); + ret = ov_camera_module_write_reg(cam_mod, 0x0100, 1); + mutex_unlock(&cam_mod->lock); + if (IS_ERR_VALUE(ret)) goto err; msleep(25); @@ -828,7 +834,9 @@ static int ov4689_stop_streaming(struct ov_camera_module *cam_mod) ov_camera_module_pr_debug(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -888,6 +896,7 @@ static struct v4l2_subdev_core_ops ov4689_camera_module_core_ops = { static struct v4l2_subdev_video_ops ov4689_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -912,9 +921,16 @@ static struct ov_camera_module_custom_config ov4689_custom_config = { .g_timings = ov4689_g_timings, .check_camera_id = ov4689_check_camera_id, .set_flip = ov4689_set_flip, + .s_vts = ov4689_auto_adjust_fps, .configs = ov4689_configs, .num_configs = ARRAY_SIZE(ov4689_configs), - .power_up_delays_ms = {5, 20, 0} + .power_up_delays_ms = {5, 20, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int ov4689_probe( @@ -925,9 +941,10 @@ static int ov4689_probe( ov4689_filltimings(&ov4689_custom_config); v4l2_i2c_subdev_init(&ov4689.sd, client, &ov4689_camera_module_ops); - + ov4689.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov4689.custom = ov4689_custom_config; + mutex_init(&ov4689.lock); dev_info(&client->dev, "probing successful\n"); return 0; } @@ -941,6 +958,7 @@ static int ov4689_remove(struct i2c_client *client) if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); ov_camera_module_release(cam_mod); dev_info(&client->dev, "removed\n"); diff --git a/drivers/media/i2c/soc_camera/rockchip/ov7675_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/ov7675_v4l2-i2c-subdev.c index a3b0a12a7a1b..b4559fe4f198 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov7675_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov7675_v4l2-i2c-subdev.c @@ -285,6 +285,8 @@ static struct ov_camera_module_config ov7675_configs[] = { sizeof(ov7675_init_tab_640_480_30fps) / sizeof(ov7675_init_tab_640_480_30fps[0]), .v_blanking_time_us = 1000, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_DVP_CFG( PLTFRM_CAM_ITF_BT601_8, PLTFRM_CAM_SIGNAL_HIGH_LEVEL, @@ -371,14 +373,8 @@ static int ov7675_s_ext_ctrls(struct ov_camera_module *cam_mod, ov_camera_module_pr_info(cam_mod, "\n"); - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = ov7675_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = ov7675_write_aec(cam_mod); else ret = -EINVAL; @@ -483,6 +479,7 @@ static struct v4l2_subdev_core_ops ov7675_camera_module_core_ops = { static struct v4l2_subdev_video_ops ov7675_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -509,7 +506,13 @@ static struct ov_camera_module_custom_config ov7675_custom_config = { .set_flip = ov7675_set_flip, .configs = ov7675_configs, .num_configs = ARRAY_SIZE(ov7675_configs), - .power_up_delays_ms = {20, 20, 0} + .power_up_delays_ms = {20, 20, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int ov7675_probe( diff --git a/drivers/media/i2c/soc_camera/rockchip/ov7750_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/ov7750_v4l2-i2c-subdev.c index 190df0f1792a..6d396bbf3efe 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov7750_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov7750_v4l2-i2c-subdev.c @@ -334,6 +334,8 @@ static struct ov_camera_module_config ov7750_configs[] = { .reg_diff_table = NULL, .reg_diff_table_num_entries = 0, .v_blanking_time_us = 7251, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 1, 800, 24000000) } }; @@ -373,10 +375,9 @@ static int ov7750_auto_adjust_fps(struct ov_camera_module *cam_mod, int ret; u32 vts; - if ((cam_mod->exp_config.exp_time + ov7750_COARSE_INTG_TIME_MAX_MARGIN) + if ((exp_time + ov7750_COARSE_INTG_TIME_MAX_MARGIN) > cam_mod->vts_min) - vts = cam_mod->exp_config.exp_time + - ov7750_COARSE_INTG_TIME_MAX_MARGIN; + vts = exp_time + ov7750_COARSE_INTG_TIME_MAX_MARGIN; else vts = cam_mod->vts_min; ret = ov_camera_module_write_reg(cam_mod, @@ -390,7 +391,7 @@ static int ov7750_auto_adjust_fps(struct ov_camera_module *cam_mod, ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); } else { - ov_camera_module_pr_debug(cam_mod, + ov_camera_module_pr_info(cam_mod, "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min); cam_mod->vts_cur = vts; } @@ -448,6 +449,8 @@ static int ov7750_write_aec(struct ov_camera_module *cam_mod) a_gain = a_gain > 0x7ff ? 0x7ff : a_gain; a_gain = a_gain * cam_mod->exp_config.gain_percent / 100; exp_time = cam_mod->exp_config.exp_time << 4; + + mutex_lock(&cam_mod->lock); if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) ret = ov_camera_module_write_reg(cam_mod, ov7750_AEC_GROUP_UPDATE_ADDRESS, @@ -480,6 +483,7 @@ static int ov7750_write_aec(struct ov_camera_module *cam_mod) ov7750_AEC_GROUP_UPDATE_ADDRESS, ov7750_AEC_GROUP_UPDATE_END_LAUNCH); } + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -698,6 +702,7 @@ static int ov7750_g_timings(struct ov_camera_module *cam_mod, cam_mod->active_config->frm_intrvl.interval.denominator * vts * timings->line_length_pck; + timings->frame_length_lines = vts; return ret; err: ov_camera_module_pr_err(cam_mod, @@ -735,14 +740,8 @@ static int ov7750_s_ext_ctrls(struct ov_camera_module *cam_mod, { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = ov7750_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = ov7750_write_aec(cam_mod); else ret = -EINVAL; @@ -828,7 +827,10 @@ static int ov7750_start_streaming(struct ov_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; - if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1))) + mutex_lock(&cam_mod->lock); + ret = ov_camera_module_write_reg(cam_mod, 0x0100, 1); + mutex_unlock(&cam_mod->lock); + if (IS_ERR_VALUE(ret)) goto err; msleep(25); @@ -846,7 +848,9 @@ static int ov7750_stop_streaming(struct ov_camera_module *cam_mod) ov_camera_module_pr_debug(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -905,6 +909,7 @@ static struct v4l2_subdev_core_ops ov7750_camera_module_core_ops = { static struct v4l2_subdev_video_ops ov7750_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -928,10 +933,17 @@ static struct ov_camera_module_custom_config ov7750_custom_config = { .g_ctrl = ov7750_g_ctrl, .g_timings = ov7750_g_timings, .check_camera_id = ov7750_check_camera_id, + .s_vts = ov7750_auto_adjust_fps, .set_flip = ov7750_set_flip, .configs = ov7750_configs, .num_configs = ARRAY_SIZE(ov7750_configs), - .power_up_delays_ms = {5, 20, 0} + .power_up_delays_ms = {5, 20, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int ov7750_probe( @@ -942,9 +954,10 @@ static int ov7750_probe( ov7750_filltimings(&ov7750_custom_config); v4l2_i2c_subdev_init(&ov7750.sd, client, &ov7750_camera_module_ops); - + ov7750.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov7750.custom = ov7750_custom_config; + mutex_init(&ov7750.lock); dev_info(&client->dev, "probing successful\n"); return 0; } @@ -958,6 +971,7 @@ static int ov7750_remove(struct i2c_client *client) if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); ov_camera_module_release(cam_mod); dev_info(&client->dev, "removed\n"); diff --git a/drivers/media/i2c/soc_camera/rockchip/ov8858_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/ov8858_v4l2-i2c-subdev.c index 60bd0ea5e2f2..51680bd7f55c 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov8858_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov8858_v4l2-i2c-subdev.c @@ -1122,6 +1122,8 @@ static struct ov_camera_module_config ov8858_configs[] = { .reg_diff_table = NULL, .reg_diff_table_num_entries = 0, .v_blanking_time_us = 7251, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 4, 481, 24000000) } }; @@ -1148,6 +1150,8 @@ static struct ov_camera_module_config ov8858_configs_R1A[] = { sizeof(ov8858_init_tab_1632_1224_30fps_R1A) / sizeof(ov8858_init_tab_1632_1224_30fps_R1A[0]), .v_blanking_time_us = 6579, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 720, 24000000) }, { @@ -1171,6 +1175,8 @@ static struct ov_camera_module_config ov8858_configs_R1A[] = { sizeof(ov8858_init_tab_3264_2448_15fps_R1A) / sizeof(ov8858_init_tab_3264_2448_15fps_R1A[0]), .v_blanking_time_us = 6579, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 720, 24000000) } }; @@ -1214,10 +1220,9 @@ static int ov8858_auto_adjust_fps(struct ov_camera_module *cam_mod, int ret; u32 vts; - if ((cam_mod->exp_config.exp_time + ov8858_COARSE_INTG_TIME_MAX_MARGIN) + if ((exp_time + ov8858_COARSE_INTG_TIME_MAX_MARGIN) > cam_mod->vts_min) - vts = cam_mod->exp_config.exp_time + - ov8858_COARSE_INTG_TIME_MAX_MARGIN; + vts = exp_time + ov8858_COARSE_INTG_TIME_MAX_MARGIN; else vts = cam_mod->vts_min; ret = ov_camera_module_write_reg(cam_mod, @@ -1231,7 +1236,7 @@ static int ov8858_auto_adjust_fps(struct ov_camera_module *cam_mod, ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret); } else { - ov_camera_module_pr_debug(cam_mod, + ov_camera_module_pr_info(cam_mod, "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min); cam_mod->vts_cur = vts; } @@ -1290,6 +1295,8 @@ static int ov8858_write_aec(struct ov_camera_module *cam_mod) a_gain = a_gain > 0x7ff ? 0x7ff : a_gain; a_gain = a_gain * cam_mod->exp_config.gain_percent / 100; exp_time = cam_mod->exp_config.exp_time << 4; + + mutex_lock(&cam_mod->lock); if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) ret = ov_camera_module_write_reg(cam_mod, ov8858_AEC_GROUP_UPDATE_ADDRESS, @@ -1322,6 +1329,7 @@ static int ov8858_write_aec(struct ov_camera_module *cam_mod) ov8858_AEC_GROUP_UPDATE_ADDRESS, ov8858_AEC_GROUP_UPDATE_END_LAUNCH); } + mutex_unlock(&cam_mod->lock); } if (IS_ERR_VALUE(ret)) @@ -1543,6 +1551,8 @@ static int ov8858_g_timings(struct ov_camera_module *cam_mod, cam_mod->active_config->frm_intrvl.interval.denominator * vts * timings->line_length_pck; + timings->frame_length_lines = vts; + return ret; err: ov_camera_module_pr_err(cam_mod, @@ -1584,14 +1594,8 @@ static int ov8858_s_ext_ctrls(struct ov_camera_module *cam_mod, { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = ov8858_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - ((ctrls->ctrls[0].id == V4L2_CID_GAIN && - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) || - (ctrls->ctrls[1].id == V4L2_CID_GAIN && - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE))) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = ov8858_write_aec(cam_mod); else ret = -EINVAL; @@ -1685,7 +1689,10 @@ static int ov8858_start_streaming(struct ov_camera_module *cam_mod) if (IS_ERR_VALUE(ret)) goto err; - if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1))) + mutex_lock(&cam_mod->lock); + ret = ov_camera_module_write_reg(cam_mod, 0x0100, 1); + mutex_unlock(&cam_mod->lock); + if (IS_ERR_VALUE(ret)) goto err; msleep(25); @@ -1705,7 +1712,9 @@ static int ov8858_stop_streaming(struct ov_camera_module *cam_mod) ov_camera_module_pr_debug(cam_mod, "\n"); + mutex_lock(&cam_mod->lock); ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0); + mutex_unlock(&cam_mod->lock); if (IS_ERR_VALUE(ret)) goto err; @@ -2095,11 +2104,6 @@ static int ov8858_check_camera_id(struct ov_camera_module *cam_mod) return ret; } -static int ov8858_g_exposure_valid_frame(struct ov_camera_module *cam_mod) -{ - return ov8858_EXP_VALID_FRAMES; -} - /* ======================================================================== */ /* This part is platform dependent */ /* ======================================================================== */ @@ -2114,6 +2118,7 @@ static struct v4l2_subdev_core_ops ov8858_camera_module_core_ops = { static struct v4l2_subdev_video_ops ov8858_camera_module_video_ops = { .s_frame_interval = ov_camera_module_s_frame_interval, + .g_frame_interval = ov_camera_module_g_frame_interval, .s_stream = ov_camera_module_s_stream }; @@ -2137,11 +2142,17 @@ static struct ov_camera_module_custom_config ov8858_custom_config = { .g_ctrl = ov8858_g_ctrl, .g_timings = ov8858_g_timings, .check_camera_id = ov8858_check_camera_id, - .g_exposure_valid_frame = ov8858_g_exposure_valid_frame, + .s_vts = ov8858_auto_adjust_fps, .read_otp = ov8858_otp_read, .configs = ov8858_configs, .num_configs = ARRAY_SIZE(ov8858_configs), - .power_up_delays_ms = {5, 20, 0} + .power_up_delays_ms = {5, 20, 0}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int ov8858_probe( @@ -2151,8 +2162,10 @@ static int ov8858_probe( dev_info(&client->dev, "probing...\n"); ov8858_filltimings(&ov8858_custom_config); v4l2_i2c_subdev_init(&ov8858.sd, client, &ov8858_camera_module_ops); + ov8858.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov8858.custom = ov8858_custom_config; + mutex_init(&ov8858.lock); dev_info(&client->dev, "probing successful\n"); return 0; @@ -2167,6 +2180,7 @@ static int ov8858_remove(struct i2c_client *client) if (!client->adapter) return -ENODEV; /* our client isn't attached */ + mutex_destroy(&cam_mod->lock); ov_camera_module_release(cam_mod); kfree(otp_ptr); diff --git a/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.c b/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.c index f58c0a84b78c..b29bf6c314bc 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.c +++ b/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.c @@ -45,8 +45,6 @@ static void ov_camera_module_reset( cam_mod->exp_config.auto_exp = false; cam_mod->exp_config.auto_gain = false; cam_mod->wb_config.auto_wb = false; - cam_mod->hflip = false; - cam_mod->vflip = false; cam_mod->auto_adjust_fps = true; cam_mod->rotation = 0; cam_mod->ctrl_updt = 0; @@ -304,6 +302,10 @@ int ov_camera_module_s_fmt(struct v4l2_subdev *sd, ov_camera_module_set_active_config(cam_mod, ov_camera_module_find_config(cam_mod, fmt, &cam_mod->frm_intrvl)); + } else { + ov_camera_module_set_active_config(cam_mod, + ov_camera_module_find_config(cam_mod, + fmt, NULL)); } return 0; err: @@ -344,6 +346,8 @@ int ov_camera_module_s_frame_interval( struct ov_camera_module *cam_mod = to_ov_camera_module(sd); unsigned long gcdiv; struct v4l2_subdev_frame_interval norm_interval; + struct ov_camera_module_config *config; + unsigned int vts; int ret = 0; if ((interval->interval.denominator == 0) || @@ -370,22 +374,62 @@ int ov_camera_module_s_frame_interval( norm_interval.interval.denominator = interval->interval.denominator / gcdiv; - if (IS_ERR_OR_NULL(ov_camera_module_find_config(cam_mod, - NULL, &norm_interval))) { - pltfrm_camera_module_pr_err(&cam_mod->sd, - "frame interval %d/%d not supported\n", - interval->interval.numerator, - interval->interval.denominator); - ret = -EINVAL; - goto err; + if (!cam_mod->frm_fmt_valid) + goto end; + config = ov_camera_module_find_config( + cam_mod, + &cam_mod->active_config->frm_fmt, + &norm_interval); + + if (!IS_ERR_OR_NULL(config) && (config != cam_mod->active_config)) { + ov_camera_module_set_active_config(cam_mod, config); + if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) { + cam_mod->custom.stop_streaming(cam_mod); + ov_camera_module_write_config(cam_mod); + cam_mod->custom.start_streaming(cam_mod); + } + } else { + if (IS_ERR_OR_NULL(cam_mod->active_config)) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "no active sensor configuration"); + ret = -EFAULT; + goto err; + } + if (cam_mod->active_config->frm_intrvl.interval.denominator < + norm_interval.interval.denominator) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "%dx%d@%dfps isn't support!", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + norm_interval.interval.denominator); + ret = -EFAULT; + goto err; + } + if (!cam_mod->custom.s_vts) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "custom.s_vts isn't support!"); + ret = -EFAULT; + goto err; + } + + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= norm_interval.interval.denominator; + cam_mod->vts_cur = vts; + + if (cam_mod->state != OV_CAMERA_MODULE_STREAMING) + goto end; + + cam_mod->custom.s_vts(cam_mod, vts); } + +end: cam_mod->frm_intrvl_valid = true; cam_mod->frm_intrvl = norm_interval; - if (cam_mod->frm_fmt_valid) { - ov_camera_module_set_active_config(cam_mod, - ov_camera_module_find_config(cam_mod, - &cam_mod->frm_fmt, interval)); - } + cam_mod->auto_adjust_fps = false; return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, @@ -393,12 +437,34 @@ int ov_camera_module_s_frame_interval( return ret; } +int ov_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov_camera_module *cam_mod = to_ov_camera_module(sd); + + if (cam_mod->active_config) { + if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) { + if (cam_mod->frm_intrvl_valid) { + *interval = cam_mod->frm_intrvl; + return 0; + } else { + *interval = cam_mod->active_config->frm_intrvl; + return 0; + } + } + } + + return -EFAULT; +} + /* ======================================================================== */ int ov_camera_module_s_stream(struct v4l2_subdev *sd, int enable) { int ret = 0; struct ov_camera_module *cam_mod = to_ov_camera_module(sd); + unsigned int vts; pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable); @@ -427,6 +493,29 @@ int ov_camera_module_s_stream(struct v4l2_subdev *sd, int enable) ret = cam_mod->custom.start_streaming(cam_mod); if (IS_ERR_VALUE(ret)) goto err; + + if (cam_mod->frm_intrvl_valid) { + if ((cam_mod->frm_intrvl.interval.numerator != + cam_mod->active_config->frm_intrvl.interval.numerator) || + (cam_mod->frm_intrvl.interval.denominator != + cam_mod->active_config->frm_intrvl.interval.denominator)) { + if (cam_mod->frm_intrvl.interval.denominator > + cam_mod->active_config->frm_intrvl.interval.denominator) { + pltfrm_camera_module_pr_warn(&cam_mod->sd, + "sensor is not support stream: %dx%d@(%d/%d)fps!\n", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + cam_mod->frm_intrvl.interval.denominator, + cam_mod->frm_intrvl.interval.numerator); + goto end; + } + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= cam_mod->frm_intrvl.interval.denominator; + cam_mod->custom.s_vts(cam_mod, vts); + } + } + if (!cam_mod->inited && cam_mod->update_config) cam_mod->inited = true; cam_mod->update_config = false; @@ -471,6 +560,7 @@ int ov_camera_module_s_stream(struct v4l2_subdev *sd, int enable) msleep(wait_ms + 1); } +end: cam_mod->state_before_suspend = cam_mod->state; return 0; @@ -582,6 +672,22 @@ int ov_camera_module_g_ctrl(struct v4l2_subdev *sd, return 0; } + if (ctrl->id == V4L2_CID_HFLIP) { + ctrl->value = cam_mod->hflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_HFLIP %d\n", + ctrl->value); + return 0; + } + + if (ctrl->id == V4L2_CID_VFLIP) { + ctrl->value = cam_mod->vflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_VFLIP %d\n", + ctrl->value); + return 0; + } + if (IS_ERR_OR_NULL(cam_mod->active_config)) { pltfrm_camera_module_pr_err(&cam_mod->sd, "no active configuration\n"); @@ -668,10 +774,6 @@ int ov_camera_module_g_ctrl(struct v4l2_subdev *sd, "V4L2_CID_FOCUS_ABSOLUTE %d\n", ctrl->value); break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - /* TBD */ - /* fallthrough */ default: pltfrm_camera_module_pr_debug(&cam_mod->sd, "failed, unknown ctrl %d\n", ctrl->id); @@ -811,12 +913,14 @@ int ov_camera_module_s_ext_ctrls( cam_mod->hflip = true; else cam_mod->hflip = false; + cam_mod->flip_flg = true; break; case V4L2_CID_VFLIP: if (ctrl->value) cam_mod->vflip = true; else cam_mod->vflip = false; + cam_mod->flip_flg = true; break; default: pltfrm_camera_module_pr_warn(&cam_mod->sd, @@ -894,7 +998,8 @@ long ov_camera_module_ioctl(struct v4l2_subdev *sd, void *arg) { struct ov_camera_module *cam_mod = to_ov_camera_module(sd); - int ret; + int ret, i; + unsigned int flag, val; pltfrm_camera_module_pr_debug(&cam_mod->sd, "cmd: 0x%x\n", cmd); @@ -935,9 +1040,10 @@ long ov_camera_module_ioctl(struct v4l2_subdev *sd, timings->fine_integration_time_min = ov_timings.fine_integration_time_min; - if (cam_mod->custom.g_exposure_valid_frame) - timings->exposure_valid_frame[0] = - cam_mod->custom.g_exposure_valid_frame(cam_mod); + timings->exposure_valid_frame[0] = + cam_mod->custom.exposure_valid_frame[0]; + timings->exposure_valid_frame[1] = + cam_mod->custom.exposure_valid_frame[1]; if (cam_mod->exp_config.exp_time) timings->exp_time = cam_mod->exp_config.exp_time; else @@ -946,7 +1052,52 @@ long ov_camera_module_ioctl(struct v4l2_subdev *sd, timings->gain = cam_mod->exp_config.gain; else timings->gain = ov_timings.gain; + + if (cam_mod->active_config) { + timings->max_exp_gain_h = cam_mod->active_config->max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->active_config->max_exp_gain_l; + } else { + timings->max_exp_gain_h = cam_mod->custom.configs[0].max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->custom.configs[0].max_exp_gain_l; + } return ret; + } else if (cmd == RK_VIDIOC_SENSOR_CONFIGINFO) { + struct sensor_config_info_s *sensor_config = (struct sensor_config_info_s *)arg; + + sensor_config->config_num = cam_mod->custom.num_configs; + for (i = 0; i < cam_mod->custom.num_configs; i++) { + if (i >= SENSOR_CONFIG_NUM) + break; + sensor_config->sensor_fmt[i] = + pltfrm_camera_module_pix_fmt2csi2_dt(cam_mod->custom.configs[i].frm_fmt.code); + sensor_config->reso[i].width = cam_mod->custom.configs[i].frm_fmt.width; + sensor_config->reso[i].height = cam_mod->custom.configs[i].frm_fmt.height; + } + return 0; + } else if (cmd == RK_VIDIOC_SENSOR_REG_ACCESS) { + struct sensor_reg_rw_s *sensor_rw = (struct sensor_reg_rw_s *)arg; + + if (sensor_rw->reg_access_mode == SENSOR_READ_MODE) { + for (i = 0; i < cam_mod->custom.configs[0].reg_table_num_entries; i++) { + flag = cam_mod->custom.configs[0].reg_table[i].flag; + if (flag != PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) + break; + } + if (flag == PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) { + pltfrm_camera_module_pr_err(&cam_mod->sd, + "Can not get sensor reg type.\n"); + return -EINVAL; + } + sensor_rw->reg_addr_len = PLTFRM_CAMERA_MODULE_REG_LEN(flag); + sensor_rw->reg_data_len = PLTFRM_CAMERA_MODULE_DATA_LEN(flag); + pltfrm_camera_module_read_reg_ex(&cam_mod->sd, 1, flag, sensor_rw->addr, &val); + sensor_rw->data = val; + } else { + flag = (sensor_rw->reg_addr_len << PLTFRM_CAMERA_MODULE_REG_LEN_BIT); + flag |= (sensor_rw->reg_data_len << PLTFRM_CAMERA_MODULE_DATA_LEN_BIT); + pltfrm_camera_module_write_reg_ex(&cam_mod->sd, flag, sensor_rw->addr, sensor_rw->data); + } + return 0; } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) { struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg; struct ov_camera_module_config *config; @@ -967,9 +1118,14 @@ long ov_camera_module_ioctl(struct v4l2_subdev *sd, pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg); return 0; } else if (cmd == PLTFRM_CIFCAM_ATTACH) { - ov_camera_module_init(cam_mod, &cam_mod->custom); - pltfrm_camera_module_ioctl(sd, cmd, arg); - return ov_camera_module_attach(cam_mod); + ret = ov_camera_module_init(cam_mod, &cam_mod->custom); + if (!IS_ERR_VALUE(ret)) { + pltfrm_camera_module_ioctl(sd, cmd, arg); + return ov_camera_module_attach(cam_mod); + } else { + ov_camera_module_release(cam_mod); + return ret; + } } ret = pltfrm_camera_module_ioctl(sd, cmd, arg); @@ -981,7 +1137,22 @@ long ov_camera_module_ioctl(struct v4l2_subdev *sd, int ov_camera_module_get_flip_mirror( struct ov_camera_module *cam_mod) { - return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + int mode = 0; + + if (!cam_mod->flip_flg) + return -1; + + if (cam_mod->hflip) + mode |= OV_MIRROR_BIT_MASK; + else + mode &= ~OV_MIRROR_BIT_MASK; + + if (cam_mod->vflip) + mode |= OV_FLIP_BIT_MASK; + else + mode &= ~OV_FLIP_BIT_MASK; + + return mode; } /* ======================================================================== */ @@ -1078,9 +1249,13 @@ int ov_camera_module_init(struct ov_camera_module *cam_mod, struct ov_camera_module_custom_config *custom) { int ret = 0; + int mode = 0; pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); + cam_mod->hflip = false; + cam_mod->vflip = false; + cam_mod->flip_flg = false; ov_camera_module_reset(cam_mod); if (IS_ERR_OR_NULL(custom->start_streaming) || @@ -1108,6 +1283,12 @@ int ov_camera_module_init(struct ov_camera_module *cam_mod, goto err; } + mode = pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + if (mode != -1) { + cam_mod->hflip = mode & OV_MIRROR_BIT_MASK ? true : false; + cam_mod->vflip = mode & OV_FLIP_BIT_MASK ? true : false; + cam_mod->flip_flg = true; + } return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, diff --git a/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.h b/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.h index 139406248cd5..11644dc47834 100644 --- a/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.h +++ b/drivers/media/i2c/soc_camera/rockchip/ov_camera_module.h @@ -30,8 +30,8 @@ #define OV_CAMERA_MODULE_REG_TYPE_TIMEOUT PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT #define ov_camera_module_csi_config #define ov_camera_module_reg pltfrm_camera_module_reg -#define OV_FLIP_BIT_MASK 0x2 -#define OV_MIRROR_BIT_MASK 0x1 +#define OV_FLIP_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_FLIP_BIT) +#define OV_MIRROR_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_MIRROR_BIT) #define OV_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01 #define OV_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02 @@ -90,7 +90,8 @@ struct ov_camera_module_config { struct ov_camera_module_timings timings; bool soft_reset; bool ignore_measurement_check; - + u8 max_exp_gain_h; + u8 max_exp_gain_l; struct pltfrm_cam_itf itf_cfg; }; @@ -156,7 +157,8 @@ struct ov_camera_module_custom_config { int (*g_ctrl)(struct ov_camera_module *cam_mod, u32 ctrl_id); int (*g_timings)(struct ov_camera_module *cam_mod, struct ov_camera_module_timings *timings); - int (*g_exposure_valid_frame)(struct ov_camera_module *cam_mod); + int (*s_vts)(struct ov_camera_module *cam_mod, + u32 vts); int (*s_ext_ctrls)(struct ov_camera_module *cam_mod, struct ov_camera_module_ext_ctrls *ctrls); int (*set_flip)( @@ -168,6 +170,7 @@ struct ov_camera_module_custom_config { struct ov_camera_module_config *configs; u32 num_configs; u32 power_up_delays_ms[3]; + unsigned short exposure_valid_frame[2]; void *priv; }; @@ -199,10 +202,12 @@ struct ov_camera_module { bool frm_intrvl_valid; bool hflip; bool vflip; + bool flip_flg; u32 rotation; void *pltfm_data; bool inited; bool as_master; + struct mutex lock; }; #define ov_camera_module_pr_info(cam_mod, fmt, arg...) \ @@ -247,6 +252,10 @@ int ov_camera_module_s_frame_interval( struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); +int ov_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval); + int ov_camera_module_s_stream( struct v4l2_subdev *sd, int enable); diff --git a/drivers/media/i2c/soc_camera/rockchip/rk_camera_module.c b/drivers/media/i2c/soc_camera/rockchip/rk_camera_module.c index 4ac9eaab06ea..dccfd4fd916a 100644 --- a/drivers/media/i2c/soc_camera/rockchip/rk_camera_module.c +++ b/drivers/media/i2c/soc_camera/rockchip/rk_camera_module.c @@ -80,6 +80,20 @@ const char *PLTFRM_CAMERA_MODULE_PIN_RESET = OF_OV_GPIO_RESET; #define I2C_M_WR 0 #define I2C_MSG_MAX 300 #define I2C_DATA_MAX (I2C_MSG_MAX * 3) +#define CSI2_DT_YUV420_8b (0x18) +#define CSI2_DT_YUV420_10b (0x19) +#define CSI2_DT_YUV422_8b (0x1E) +#define CSI2_DT_YUV422_10b (0x1F) +#define CSI2_DT_RGB444 (0x20) +#define CSI2_DT_RGB555 (0x21) +#define CSI2_DT_RGB565 (0x22) +#define CSI2_DT_RGB666 (0x23) +#define CSI2_DT_RGB888 (0x24) +#define CSI2_DT_RAW6 (0x28) +#define CSI2_DT_RAW7 (0x29) +#define CSI2_DT_RAW8 (0x2A) +#define CSI2_DT_RAW10 (0x2B) +#define CSI2_DT_RAW12 (0x2C) struct pltfrm_camera_module_gpio { int pltfrm_gpio; @@ -885,10 +899,9 @@ static int pltfrm_camera_module_write_reglist_node( } reg_table_num_entries /= 12; - reg_table = (struct pltfrm_camera_module_reg *) - kmalloc(reg_table_num_entries * - sizeof(struct pltfrm_camera_module_reg), - GFP_KERNEL); + reg_table = kmalloc_array(reg_table_num_entries, + sizeof(struct pltfrm_camera_module_reg), + GFP_KERNEL); if (IS_ERR_OR_NULL(reg_table)) { pltfrm_camera_module_pr_err(sd, "memory allocation failed\n"); @@ -1662,7 +1675,6 @@ int pltfrm_camera_module_init( void **pldata) { int ret = 0; - struct i2c_client *client = v4l2_get_subdevdata(sd); struct pltfrm_camera_module_data *pdata; pltfrm_camera_module_pr_debug(sd, "\n"); @@ -1675,13 +1687,11 @@ int pltfrm_camera_module_init( } ret = pltfrm_camera_module_init_gpio(sd); - if (ret) { + if (ret) pltfrm_camera_module_pr_err(sd, "GPIO initialization failed (%d)\n", ret); - devm_kfree(&client->dev, pdata); - } else { + else *(struct pltfrm_camera_module_data **)pldata = pdata; - } return ret; } @@ -1710,8 +1720,18 @@ void pltfrm_camera_module_release( devm_regulator_put( pdata->regulators.regulator[i].regulator); } + + if (!IS_ERR_OR_NULL(pdata->regulators.regulator)) { + devm_kfree(&client->dev, + pdata->regulators.regulator); + pdata->regulators.regulator = NULL; + } if (pdata->pinctrl) devm_pinctrl_put(pdata->pinctrl); + if (!IS_ERR_OR_NULL(pdata)) { + devm_kfree(&client->dev, pdata); + pdata = NULL; + } } /* ======================================================================== */ @@ -1840,5 +1860,134 @@ int pltfrm_camera_module_get_flip_mirror( return mode; } + +int pltfrm_camera_module_pix_fmt2csi2_dt(int src_pix_fmt) +{ + int ret = 0; + + switch (src_pix_fmt) { + case MEDIA_BUS_FMT_RGB444_1X12: + case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE: + case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE: + ret = CSI2_DT_RGB444; + break; + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: + ret = CSI2_DT_RGB555; + break; + case MEDIA_BUS_FMT_RGB565_1X16: + case MEDIA_BUS_FMT_BGR565_2X8_BE: + case MEDIA_BUS_FMT_BGR565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + ret = CSI2_DT_RGB565; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + ret = CSI2_DT_RGB666; + break; + case MEDIA_BUS_FMT_RBG888_1X24: + case MEDIA_BUS_FMT_BGR888_1X24: + case MEDIA_BUS_FMT_GBR888_1X24: + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB888_2X12_BE: + case MEDIA_BUS_FMT_RGB888_2X12_LE: + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + case MEDIA_BUS_FMT_ARGB8888_1X32: + case MEDIA_BUS_FMT_RGB888_1X32_PADHI: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB121212_1X36: + case MEDIA_BUS_FMT_RGB161616_1X48: + ret = CSI2_DT_RGB888; + break; + case MEDIA_BUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_UV8_1X8: + case MEDIA_BUS_FMT_UYVY8_1_5X8: + case MEDIA_BUS_FMT_VYUY8_1_5X8: + case MEDIA_BUS_FMT_YUYV8_1_5X8: + case MEDIA_BUS_FMT_YVYU8_1_5X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + ret = CSI2_DT_YUV420_8b; + break; + case MEDIA_BUS_FMT_Y10_1X10: + case MEDIA_BUS_FMT_UYVY10_2X10: + case MEDIA_BUS_FMT_VYUY10_2X10: + case MEDIA_BUS_FMT_YUYV10_2X10: + case MEDIA_BUS_FMT_YVYU10_2X10: + ret = CSI2_DT_YUV420_10b; + break; + case MEDIA_BUS_FMT_Y12_1X12: + case MEDIA_BUS_FMT_UYVY12_2X12: + case MEDIA_BUS_FMT_VYUY12_2X12: + case MEDIA_BUS_FMT_YUYV12_2X12: + case MEDIA_BUS_FMT_YVYU12_2X12: + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_VYUY8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YVYU8_1X16: + case MEDIA_BUS_FMT_YDYUYDYV8_1X16: + ret = CSI2_DT_YUV422_8b; + break; + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_VYUY10_1X20: + case MEDIA_BUS_FMT_YUYV10_1X20: + case MEDIA_BUS_FMT_YVYU10_1X20: + case MEDIA_BUS_FMT_VUY8_1X24: + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYVY12_1X24: + case MEDIA_BUS_FMT_VYUY12_1X24: + case MEDIA_BUS_FMT_YUYV12_1X24: + case MEDIA_BUS_FMT_YVYU12_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_AYUV8_1X32: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_YUV16_1X48: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + ret = CSI2_DT_YUV422_10b; + break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + ret = CSI2_DT_RAW8; + break; + case MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8: + case MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8: + case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: + case MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8: + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + ret = CSI2_DT_RAW10; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + ret = CSI2_DT_RAW12; + break; + default: + break; + } + return ret; +} + #endif diff --git a/drivers/media/i2c/soc_camera/rockchip/tc358749xbg_v4l2-i2c-subdev.c b/drivers/media/i2c/soc_camera/rockchip/tc358749xbg_v4l2-i2c-subdev.c index e93961638c61..3e30160f32dc 100644 --- a/drivers/media/i2c/soc_camera/rockchip/tc358749xbg_v4l2-i2c-subdev.c +++ b/drivers/media/i2c/soc_camera/rockchip/tc358749xbg_v4l2-i2c-subdev.c @@ -448,6 +448,8 @@ static struct tc_camera_module_config tc358749xbg_configs[] = { sizeof(tc358749xbg_init_tab_1920_1080_60fps) / sizeof(tc358749xbg_init_tab_1920_1080_60fps[0]), .v_blanking_time_us = 3078, + .max_exp_gain_h = 16, + .max_exp_gain_l = 0, .ignore_measurement_check = 1, PLTFRM_CAM_ITF_MIPI_CFG(0, 4, 800, 24000000) } @@ -649,6 +651,8 @@ static int tc358749xbg_g_timings( cam_mod->active_config->frm_intrvl.interval.denominator * vts * timings->line_length_pck; + timings->frame_length_lines = vts; + return ret; err: tc_camera_module_pr_err(cam_mod, @@ -704,14 +708,8 @@ static int tc358749xbg_s_ext_ctrls( { int ret = 0; - /* Handles only exposure and gain together special case. */ - if (ctrls->count == 1) - ret = tc358749xbg_s_ctrl(cam_mod, ctrls->ctrls[0].id); - else if ((ctrls->count >= 3) && - (ctrls->ctrls[0].id == V4L2_CID_GAIN || - ctrls->ctrls[0].id == V4L2_CID_EXPOSURE || - ctrls->ctrls[1].id == V4L2_CID_GAIN || - ctrls->ctrls[1].id == V4L2_CID_EXPOSURE)) + if ((ctrls->ctrls[0].id == V4L2_CID_GAIN || + ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)) ret = tc358749xbg_write_aec(cam_mod); else ret = -EINVAL; @@ -798,6 +796,7 @@ static struct v4l2_subdev_core_ops tc358749xbg_camera_module_core_ops = { static struct v4l2_subdev_video_ops tc358749xbg_camera_module_video_ops = { .s_frame_interval = tc_camera_module_s_frame_interval, + .g_frame_interval = tc_camera_module_g_frame_interval, .s_stream = tc_camera_module_s_stream }; @@ -826,7 +825,13 @@ static struct tc_camera_module_custom_config tc358749xbg_custom_config = { .s_power = tc358749xbg_s_power, .configs = tc358749xbg_configs, .num_configs = ARRAY_SIZE(tc358749xbg_configs), - .power_up_delays_ms = {5, 30, 30} + .power_up_delays_ms = {5, 30, 30}, + /* + *0: Exposure time valid fileds; + *1: Exposure gain valid fileds; + *(2 fileds == 1 frames) + */ + .exposure_valid_frame = {4, 4} }; static int test_parse_dts( diff --git a/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.c b/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.c index 229444c1eed5..2fc97149be55 100644 --- a/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.c +++ b/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.c @@ -51,8 +51,6 @@ static void tc_camera_module_reset( cam_mod->exp_config.auto_exp = false; cam_mod->exp_config.auto_gain = false; cam_mod->wb_config.auto_wb = false; - cam_mod->hflip = false; - cam_mod->vflip = false; cam_mod->auto_adjust_fps = true; cam_mod->rotation = 0; cam_mod->ctrl_updt = 0; @@ -308,6 +306,10 @@ int tc_camera_module_s_fmt(struct v4l2_subdev *sd, tc_camera_module_set_active_config(cam_mod, tc_camera_module_find_config(cam_mod, fmt, &cam_mod->frm_intrvl)); + } else { + tc_camera_module_set_active_config(cam_mod, + tc_camera_module_find_config(cam_mod, + fmt, NULL)); } return 0; err: @@ -348,6 +350,8 @@ int tc_camera_module_s_frame_interval( struct tc_camera_module *cam_mod = to_tc_camera_module(sd); unsigned long gcdiv; struct v4l2_subdev_frame_interval norm_interval; + struct tc_camera_module_config *config; + unsigned int vts; int ret = 0; if ((interval->interval.denominator == 0) || @@ -374,22 +378,65 @@ int tc_camera_module_s_frame_interval( norm_interval.interval.denominator = interval->interval.denominator / gcdiv; - if (IS_ERR_OR_NULL(tc_camera_module_find_config(cam_mod, - NULL, &norm_interval))) { - pltfrm_camera_module_pr_err(&cam_mod->sd, - "frame interval %d/%d not supported\n", - interval->interval.numerator, - interval->interval.denominator); - ret = -EINVAL; - goto err; + config = tc_camera_module_find_config(cam_mod, + NULL, &norm_interval); + + if (!cam_mod->frm_fmt_valid) + goto end; + config = tc_camera_module_find_config( + cam_mod, + &cam_mod->active_config->frm_fmt, + &norm_interval); + + if (!IS_ERR_OR_NULL(config) && (config != cam_mod->active_config)) { + tc_camera_module_set_active_config(cam_mod, config); + if (cam_mod->state == TC_CAMERA_MODULE_STREAMING) { + cam_mod->custom.enable_stream(cam_mod, false); + tc_camera_module_write_config(cam_mod); + cam_mod->custom.enable_stream(cam_mod, true); + } + } else { + if (IS_ERR_OR_NULL(cam_mod->active_config)) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "no active sensor configuration"); + ret = -EFAULT; + goto err; + } + if (cam_mod->active_config->frm_intrvl.interval.denominator < + norm_interval.interval.denominator) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "%dx%d@%dfps isn't support!", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + norm_interval.interval.denominator); + ret = -EFAULT; + goto err; + } + if (!cam_mod->custom.s_vts) { + pltfrm_camera_module_pr_err( + &cam_mod->sd, + "custom.s_vts isn't support!"); + ret = -EFAULT; + goto err; + } + + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= norm_interval.interval.denominator; + cam_mod->vts_cur = vts; + + if (cam_mod->state != TC_CAMERA_MODULE_STREAMING) + goto end; + + cam_mod->custom.s_vts(cam_mod, vts); } + +end: cam_mod->frm_intrvl_valid = true; cam_mod->frm_intrvl = norm_interval; - if (cam_mod->frm_fmt_valid) { - tc_camera_module_set_active_config(cam_mod, - tc_camera_module_find_config(cam_mod, - &cam_mod->frm_fmt, interval)); - } + cam_mod->auto_adjust_fps = false; return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, @@ -397,12 +444,34 @@ int tc_camera_module_s_frame_interval( return ret; } +int tc_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct tc_camera_module *cam_mod = to_tc_camera_module(sd); + + if (cam_mod->active_config) { + if (cam_mod->state == TC_CAMERA_MODULE_STREAMING) { + if (cam_mod->frm_intrvl_valid) { + *interval = cam_mod->frm_intrvl; + return 0; + } else { + *interval = cam_mod->active_config->frm_intrvl; + return 0; + } + } + } + + return -EFAULT; +} + /* ======================================================================== */ int tc_camera_module_s_stream(struct v4l2_subdev *sd, int enable) { int ret = 0; struct tc_camera_module *cam_mod = to_tc_camera_module(sd); + unsigned int vts; pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable); @@ -431,6 +500,29 @@ int tc_camera_module_s_stream(struct v4l2_subdev *sd, int enable) ret = cam_mod->custom.enable_stream(cam_mod, true); if (IS_ERR_VALUE(ret)) goto err; + + if (cam_mod->frm_intrvl_valid) { + if ((cam_mod->frm_intrvl.interval.numerator != + cam_mod->active_config->frm_intrvl.interval.numerator) || + (cam_mod->frm_intrvl.interval.denominator != + cam_mod->active_config->frm_intrvl.interval.denominator)) { + if (cam_mod->frm_intrvl.interval.denominator > + cam_mod->active_config->frm_intrvl.interval.denominator) { + pltfrm_camera_module_pr_warn(&cam_mod->sd, + "sensor is not support stream: %dx%d@(%d/%d)fps!\n", + cam_mod->active_config->frm_fmt.width, + cam_mod->active_config->frm_fmt.height, + cam_mod->frm_intrvl.interval.denominator, + cam_mod->frm_intrvl.interval.numerator); + goto end; + } + vts = cam_mod->active_config->timings.frame_length_lines; + vts *= cam_mod->active_config->frm_intrvl.interval.denominator; + vts /= cam_mod->frm_intrvl.interval.denominator; + cam_mod->custom.s_vts(cam_mod, vts); + } + } + if (!cam_mod->inited && cam_mod->update_config) cam_mod->inited = true; cam_mod->update_config = false; @@ -475,6 +567,7 @@ int tc_camera_module_s_stream(struct v4l2_subdev *sd, int enable) msleep(wait_ms + 1); } +end: cam_mod->state_before_suspend = cam_mod->state; return 0; @@ -589,6 +682,22 @@ int tc_camera_module_g_ctrl(struct v4l2_subdev *sd, return 0; } + if (ctrl->id == V4L2_CID_HFLIP) { + ctrl->value = cam_mod->hflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_HFLIP %d\n", + ctrl->value); + return 0; + } + + if (ctrl->id == V4L2_CID_VFLIP) { + ctrl->value = cam_mod->vflip; + pltfrm_camera_module_pr_debug(&cam_mod->sd, + "V4L2_CID_VFLIP %d\n", + ctrl->value); + return 0; + } + if (ctrl->id == V4L2_CID_FLASH_LED_MODE) { ctrl->value = cam_mod->exp_config.flash_mode; pltfrm_camera_module_pr_debug(&cam_mod->sd, @@ -683,10 +792,6 @@ int tc_camera_module_g_ctrl(struct v4l2_subdev *sd, "V4L2_CID_FOCUS_ABSOLUTE %d\n", ctrl->value); break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - /* TBD */ - /* fallthrough */ default: pltfrm_camera_module_pr_debug(&cam_mod->sd, "failed, unknown ctrl %d\n", ctrl->id); @@ -835,12 +940,14 @@ int tc_camera_module_s_ext_ctrls( cam_mod->hflip = true; else cam_mod->hflip = false; + cam_mod->flip_flg = true; break; case V4L2_CID_VFLIP: if (ctrl->value) cam_mod->vflip = true; else cam_mod->vflip = false; + cam_mod->flip_flg = true; break; default: pltfrm_camera_module_pr_warn( @@ -920,7 +1027,8 @@ long tc_camera_module_ioctl(struct v4l2_subdev *sd, void *arg) { struct tc_camera_module *cam_mod = to_tc_camera_module(sd); - int ret; + int ret, i; + unsigned int flag, val; pltfrm_camera_module_pr_debug(&cam_mod->sd, "cmd: 0x%x\n", cmd); @@ -963,9 +1071,10 @@ long tc_camera_module_ioctl(struct v4l2_subdev *sd, timings->fine_integration_time_min = tc_timings.fine_integration_time_min; - if (cam_mod->custom.g_exposure_valid_frame) - timings->exposure_valid_frame[0] = - cam_mod->custom.g_exposure_valid_frame(cam_mod); + timings->exposure_valid_frame[0] = + cam_mod->custom.exposure_valid_frame[0]; + timings->exposure_valid_frame[1] = + cam_mod->custom.exposure_valid_frame[1]; if (cam_mod->exp_config.exp_time) timings->exp_time = cam_mod->exp_config.exp_time; else @@ -974,7 +1083,52 @@ long tc_camera_module_ioctl(struct v4l2_subdev *sd, timings->gain = cam_mod->exp_config.gain; else timings->gain = tc_timings.gain; + + if (cam_mod->active_config) { + timings->max_exp_gain_h = cam_mod->active_config->max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->active_config->max_exp_gain_l; + } else { + timings->max_exp_gain_h = cam_mod->custom.configs[0].max_exp_gain_h; + timings->max_exp_gain_l = cam_mod->custom.configs[0].max_exp_gain_l; + } return ret; + } else if (cmd == RK_VIDIOC_SENSOR_CONFIGINFO) { + struct sensor_config_info_s *sensor_config = (struct sensor_config_info_s *)arg; + + sensor_config->config_num = cam_mod->custom.num_configs; + for (i = 0; i < cam_mod->custom.num_configs; i++) { + if (i >= SENSOR_CONFIG_NUM) + break; + sensor_config->sensor_fmt[i] = + pltfrm_camera_module_pix_fmt2csi2_dt(cam_mod->custom.configs[i].frm_fmt.code); + sensor_config->reso[i].width = cam_mod->custom.configs[i].frm_fmt.width; + sensor_config->reso[i].height = cam_mod->custom.configs[i].frm_fmt.height; + } + return 0; + } else if (cmd == RK_VIDIOC_SENSOR_REG_ACCESS) { + struct sensor_reg_rw_s *sensor_rw = (struct sensor_reg_rw_s *)arg; + + if (sensor_rw->reg_access_mode == SENSOR_READ_MODE) { + for (i = 0; i < cam_mod->custom.configs[0].reg_table_num_entries; i++) { + flag = cam_mod->custom.configs[0].reg_table[i].flag; + if (flag != PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) + break; + } + if (flag == PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT) { + pltfrm_camera_module_pr_err(&cam_mod->sd, + "Can not get sensor reg type.\n"); + return -EINVAL; + } + sensor_rw->reg_addr_len = PLTFRM_CAMERA_MODULE_REG_LEN(flag); + sensor_rw->reg_data_len = PLTFRM_CAMERA_MODULE_DATA_LEN(flag); + pltfrm_camera_module_read_reg_ex(&cam_mod->sd, 1, flag, sensor_rw->addr, &val); + sensor_rw->data = val; + } else { + flag = (sensor_rw->reg_addr_len << PLTFRM_CAMERA_MODULE_REG_LEN_BIT); + flag |= (sensor_rw->reg_data_len << PLTFRM_CAMERA_MODULE_DATA_LEN_BIT); + pltfrm_camera_module_write_reg_ex(&cam_mod->sd, flag, sensor_rw->addr, sensor_rw->data); + } + return 0; } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) { struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg; struct tc_camera_module_config *config; @@ -995,9 +1149,14 @@ long tc_camera_module_ioctl(struct v4l2_subdev *sd, pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg); return 0; } else if (cmd == PLTFRM_CIFCAM_ATTACH) { - tc_camera_module_init(cam_mod, &cam_mod->custom); - pltfrm_camera_module_ioctl(sd, cmd, arg); - return tc_camera_module_attach(cam_mod); + ret = tc_camera_module_init(cam_mod, &cam_mod->custom); + if (!IS_ERR_VALUE(ret)) { + pltfrm_camera_module_ioctl(sd, cmd, arg); + return tc_camera_module_attach(cam_mod); + } else { + tc_camera_module_release(cam_mod); + return ret; + } } ret = pltfrm_camera_module_ioctl(sd, cmd, arg); @@ -1009,7 +1168,22 @@ long tc_camera_module_ioctl(struct v4l2_subdev *sd, int tc_camera_module_get_flip_mirror( struct tc_camera_module *cam_mod) { - return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + int mode = 0; + + if (!cam_mod->flip_flg) + return -1; + + if (cam_mod->hflip) + mode |= TC_MIRROR_BIT_MASK; + else + mode &= ~TC_MIRROR_BIT_MASK; + + if (cam_mod->vflip) + mode |= TC_FLIP_BIT_MASK; + else + mode &= ~TC_FLIP_BIT_MASK; + + return mode; } /* ======================================================================== */ @@ -1038,7 +1212,7 @@ int tc_camera_module_enum_frameintervals( /* ======================================================================== */ static int tc_camera_module_i2c_write(struct v4l2_subdev *sd, u16 reg, - u8 *values, u32 len) + u8 *values, u32 len) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret, i; @@ -1082,7 +1256,7 @@ static int tc_camera_module_i2c_write(struct v4l2_subdev *sd, u16 reg, /* ======================================================================== */ static int tc_camera_module_i2c_read(struct v4l2_subdev *sd, u16 reg, - u32 *value, u32 len) + u32 *value, u32 len) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; @@ -1261,9 +1435,13 @@ int tc_camera_module_init(struct tc_camera_module *cam_mod, struct tc_camera_module_custom_config *custom) { int ret = 0; + int mode = 0; pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n"); + cam_mod->hflip = false; + cam_mod->vflip = false; + cam_mod->flip_flg = false; tc_camera_module_reset(cam_mod); if (IS_ERR_OR_NULL(custom->s_ctrl) || @@ -1289,6 +1467,12 @@ int tc_camera_module_init(struct tc_camera_module *cam_mod, goto err; } + mode = pltfrm_camera_module_get_flip_mirror(&cam_mod->sd); + if (mode != -1) { + cam_mod->hflip = mode & TC_MIRROR_BIT_MASK ? true : false; + cam_mod->vflip = mode & TC_FLIP_BIT_MASK ? true : false; + cam_mod->flip_flg = true; + } return 0; err: pltfrm_camera_module_pr_err(&cam_mod->sd, diff --git a/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.h b/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.h index 2cb594df2cad..673f6c284bf4 100644 --- a/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.h +++ b/drivers/media/i2c/soc_camera/rockchip/tc_camera_module.h @@ -34,8 +34,8 @@ #define TC_CAMERA_MOUDLE_REG_VALUE_LEN_16BIT 2 #define TC_CAMERA_MOUDLE_REG_VALUE_LEN_32BIT 4 #define tc_camera_module_csi_config -#define TC_FLIP_BIT_MASK 0x2 -#define TC_MIRROR_BIT_MASK 0x1 +#define TC_FLIP_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_FLIP_BIT) +#define TC_MIRROR_BIT_MASK (1 << PLTFRM_CAMERA_MODULE_MIRROR_BIT) #define TC_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01 #define TC_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02 @@ -101,7 +101,8 @@ struct tc_camera_module_config { struct tc_camera_module_timings timings; bool soft_reset; bool ignore_measurement_check; - + u8 max_exp_gain_h; + u8 max_exp_gain_l; struct pltfrm_cam_itf itf_cfg; }; @@ -165,7 +166,8 @@ struct tc_camera_module_custom_config { int (*g_ctrl)(struct tc_camera_module *cam_mod, u32 ctrl_id); int (*g_timings)(struct tc_camera_module *cam_mod, struct tc_camera_module_timings *timings); - int (*g_exposure_valid_frame)(struct tc_camera_module *cam_mod); + int (*s_vts)(struct tc_camera_module *cam_mod, + u32 vts); int (*s_ext_ctrls)(struct tc_camera_module *cam_mod, struct tc_camera_module_ext_ctrls *ctrls); int (*set_flip)( @@ -179,6 +181,7 @@ struct tc_camera_module_custom_config { struct tc_camera_module_config *configs; u32 num_configs; u32 power_up_delays_ms[3]; + unsigned short exposure_valid_frame[2]; void *priv; }; @@ -210,9 +213,11 @@ struct tc_camera_module { bool frm_intrvl_valid; bool hflip; bool vflip; + bool flip_flg; u32 rotation; void *pltfm_data; bool inited; + struct mutex lock; }; struct tc35x_priv { @@ -286,6 +291,10 @@ int tc_camera_module_s_frame_interval( struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); +int tc_camera_module_g_frame_interval( + struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval); + int tc_camera_module_s_stream( struct v4l2_subdev *sd, int enable); diff --git a/include/linux/platform_data/rk_isp10_platform_camera_module.h b/include/linux/platform_data/rk_isp10_platform_camera_module.h index 154694d42c66..41c6c03dd488 100644 --- a/include/linux/platform_data/rk_isp10_platform_camera_module.h +++ b/include/linux/platform_data/rk_isp10_platform_camera_module.h @@ -46,6 +46,13 @@ #define PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT 0x01 #define PLTFRM_CAMERA_MODULE_REG_TYPE_DATA_SINGLE 0x1100 +#define PLTFRM_CAMERA_MODULE_MIRROR_BIT 0 +#define PLTFRM_CAMERA_MODULE_FLIP_BIT 1 +#define PLTFRM_CAMERA_MODULE_IS_MIRROR(a) \ + ((a & PLTFRM_CAMERA_MODULE_MIRROR_BIT) == PLTFRM_CAMERA_MODULE_MIRROR_BIT) +#define PLTFRM_CAMERA_MODULE_IS_FLIP(a) \ + ((a & PLTFRM_CAMERA_MODULE_FLIP_BIT) == PLTFRM_CAMERA_MODULE_FLIP_BIT) + extern const char *PLTFRM_CAMERA_MODULE_PIN_PD; extern const char *PLTFRM_CAMERA_MODULE_PIN_PWR; extern const char *PLTFRM_CAMERA_MODULE_PIN_FLASH; @@ -143,6 +150,8 @@ const char *pltfrm_dev_string(struct v4l2_subdev *sd); int pltfrm_camera_module_get_flip_mirror( struct v4l2_subdev *sd); +int pltfrm_camera_module_pix_fmt2csi2_dt(int src_pix_fmt); + #define pltfrm_camera_module_pr_debug(dev, fmt, arg...) \ pr_debug("%s.%s: " fmt, \ pltfrm_dev_string(dev), __func__, ## arg) diff --git a/include/media/v4l2-config_rockchip.h b/include/media/v4l2-config_rockchip.h index 0f2cfb6b3c5a..e5550903dcdb 100644 --- a/include/media/v4l2-config_rockchip.h +++ b/include/media/v4l2-config_rockchip.h @@ -56,6 +56,8 @@ struct isp_supplemental_sensor_mode_data { unsigned char exposure_valid_frame[2]; int exp_time; unsigned short gain; + unsigned char max_exp_gain_h; + unsigned char max_exp_gain_l; }; struct camera_module_info_s {