From 3e0d014bd078a40c89e4d320c0ecbc2c0eed8f4f Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 6 May 2020 20:33:05 +0800 Subject: [PATCH] media: i2c: imx347 fixed exposure issue Fix HDR frame rate, correct Tline support conversion gain control Change-Id: I7c9c8a6b81206f46d2d3f3f4e0580e7831b32fd3 Signed-off-by: Zefa Chen --- drivers/media/i2c/imx347.c | 123 ++++++++++++++++++++++++--------- include/uapi/linux/rk-preisp.h | 12 ++++ 2 files changed, 103 insertions(+), 32 deletions(-) diff --git a/drivers/media/i2c/imx347.c b/drivers/media/i2c/imx347.c index f1ba135b5414..342406f0a1c9 100644 --- a/drivers/media/i2c/imx347.c +++ b/drivers/media/i2c/imx347.c @@ -5,6 +5,7 @@ * Copyright (C) 2020 Fuzhou Rockchip Electronics Co., Ltd. * * V0.0X01.0X00 first version + * V0.0X01.0X01 add conversion gain control */ #include @@ -26,7 +27,7 @@ #include #include -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN @@ -95,6 +96,10 @@ #define IMX347_FETCH_VTS_M(VAL) (((VAL) >> 8) & 0xFF) #define IMX347_FETCH_VTS_L(VAL) ((VAL) & 0xFF) +#define IMX347_GROUP_HOLD_REG 0x3001 +#define IMX347_GROUP_HOLD_START 0x01 +#define IMX347_GROUP_HOLD_END 0x00 + #define IMX347_VTS_REG_L 0x3030 #define IMX347_VTS_REG_M 0x3031 #define IMX347_VTS_REG_H 0x3032 @@ -706,7 +711,7 @@ static const struct imx347_mode supported_modes[] = { .height = 1536, .max_fps = { .numerator = 10000, - .denominator = 250000, + .denominator = 250000 * 2, }, .exp_def = 0x0240, .hts_def = 0x02ee * 4, @@ -739,7 +744,7 @@ static const struct imx347_mode supported_modes[] = { .height = 1538, .max_fps = { .numerator = 10000, - .denominator = 250000, + .denominator = 250000 * 2, }, .exp_def = 0x0240, .hts_def = 0x02ee * 4, @@ -901,7 +906,7 @@ static int imx347_set_fmt(struct v4l2_subdev *sd, imx347->cur_pixel_rate = IMX347_10BIT_LINEAR_PIXEL_RATE; else if (mode->hdr_mode == HDR_X2) imx347->cur_pixel_rate = IMX347_10BIT_HDR2_PIXEL_RATE; - imx347->cur_link_freq = MIPI_FREQ_594M; + imx347->cur_link_freq = 1; clk_disable_unprepare(imx347->xvclk); ret = clk_set_rate(imx347->xvclk, IMX347_XVCLK_FREQ_37M); if (ret < 0) @@ -913,7 +918,7 @@ static int imx347_set_fmt(struct v4l2_subdev *sd, dev_err(dev, "Failed to enable xvclk\n"); } else { imx347->cur_pixel_rate = IMX347_12BIT_PIXEL_RATE; - imx347->cur_link_freq = MIPI_FREQ_360M; + imx347->cur_link_freq = 0; clk_disable_unprepare(imx347->xvclk); ret = clk_set_rate(imx347->xvclk, IMX347_XVCLK_FREQ_24M); if (ret < 0) @@ -924,10 +929,10 @@ static int imx347_set_fmt(struct v4l2_subdev *sd, if (ret < 0) dev_err(dev, "Failed to enable xvclk\n"); } - __v4l2_ctrl_s_ctrl_int64(imx347->pixel_rate, - imx347->cur_pixel_rate); - __v4l2_ctrl_s_ctrl(imx347->link_freq, - imx347->cur_link_freq); + v4l2_ctrl_s_ctrl_int64(imx347->pixel_rate, + imx347->cur_pixel_rate); + v4l2_ctrl_s_ctrl(imx347->link_freq, + imx347->cur_link_freq); } mutex_unlock(&imx347->mutex); @@ -1065,6 +1070,7 @@ static int imx347_set_hdrae(struct imx347 *imx347, int rhs1_change_limit; int ret = 0; u32 fsc = imx347->cur_vts * 2; + u8 cg_mode = 0; if (!imx347->has_init_exp && !imx347->streaming) { imx347->init_hdrae_exp = *ae; @@ -1087,26 +1093,19 @@ static int imx347_set_hdrae(struct imx347 *imx347, //2 stagger l_a_gain = m_a_gain; l_exp_time = m_exp_time; + cg_mode = ae->middle_cg_mode; } - //long gain and short gain - if (l_a_gain > 100) { - l_a_gain -= 27; //8.1db - s_a_gain = (s_a_gain < 27) ? 0 : (s_a_gain - 27); - if (!g_isHCG) { - gain_switch = 0x01 | 0x100; - g_isHCG = true; - } - } else if (l_a_gain < 44) { - if (g_isHCG) { - gain_switch = 0x00 | 0x100; - g_isHCG = false; - } - } else { - if (g_isHCG) { - l_a_gain -= 27; - s_a_gain = (s_a_gain < 27) ? 0 : (s_a_gain - 27); - } + if (!g_isHCG && cg_mode == GAIN_MODE_HCG) { + gain_switch = 0x01 | 0x100; + g_isHCG = true; + } else if (g_isHCG && cg_mode == GAIN_MODE_LCG) { + gain_switch = 0x00 | 0x100; + g_isHCG = false; } + ret = imx347_write_reg(client, + IMX347_GROUP_HOLD_REG, + IMX347_REG_VALUE_08BIT, + IMX347_GROUP_HOLD_START); //gain effect n+1 ret |= imx347_write_reg(client, IMX347_LF_GAIN_REG_H, @@ -1216,6 +1215,40 @@ static int imx347_set_hdrae(struct imx347 *imx347, IMX347_LF_EXPO_REG_H, IMX347_REG_VALUE_08BIT, IMX347_FETCH_EXP_H(shr0)); + ret |= imx347_write_reg(client, + IMX347_GROUP_HOLD_REG, + IMX347_REG_VALUE_08BIT, + IMX347_GROUP_HOLD_END); + return ret; +} + +static int imx347_set_conversion_gain(struct imx347 *imx347, u32 *cg) +{ + int ret = 0; + struct i2c_client *client = imx347->client; + int cur_cg = *cg; + u32 gain_switch = 0; + + if (g_isHCG && cur_cg == GAIN_MODE_LCG) { + gain_switch = 0x00 | 0x100; + g_isHCG = false; + } else if (!g_isHCG && cur_cg == GAIN_MODE_HCG) { + gain_switch = 0x01 | 0x100; + g_isHCG = true; + } + ret = imx347_write_reg(client, + IMX347_GROUP_HOLD_REG, + IMX347_REG_VALUE_08BIT, + IMX347_GROUP_HOLD_START); + if (gain_switch & 0x100) + ret |= imx347_write_reg(client, + IMX347_GAIN_SWITCH_REG, + IMX347_REG_VALUE_08BIT, + gain_switch & 0xff); + ret |= imx347_write_reg(client, + IMX347_GROUP_HOLD_REG, + IMX347_REG_VALUE_08BIT, + IMX347_GROUP_HOLD_END); return ret; } @@ -1264,6 +1297,9 @@ static long imx347_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 1, h); } break; + case RKMODULE_SET_CONVERSION_GAIN: + ret = imx347_set_conversion_gain(imx347, (u32 *)arg); + break; default: ret = -ENOIOCTLCMD; break; @@ -1282,6 +1318,7 @@ static long imx347_compat_ioctl32(struct v4l2_subdev *sd, struct rkmodule_hdr_cfg *hdr; struct preisp_hdrae_exp_s *hdrae; long ret; + u32 cg = 0; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -1344,6 +1381,11 @@ static long imx347_compat_ioctl32(struct v4l2_subdev *sd, ret = imx347_ioctl(sd, cmd, hdrae); kfree(hdrae); break; + case RKMODULE_SET_CONVERSION_GAIN: + ret = copy_from_user(&cg, up, sizeof(cg)); + if (!ret) + ret = imx347_ioctl(sd, cmd, &cg); + break; default: ret = -ENOIOCTLCMD; break; @@ -1353,11 +1395,28 @@ static long imx347_compat_ioctl32(struct v4l2_subdev *sd, } #endif +static int imx347_init_conversion_gain(struct imx347 *imx347) +{ + int ret = 0; + struct i2c_client *client = imx347->client; + + ret = imx347_write_reg(client, + IMX347_GAIN_SWITCH_REG, + IMX347_REG_VALUE_08BIT, + 0X00); + if (!ret) + g_isHCG = false; + return ret; +} + static int __imx347_start_stream(struct imx347 *imx347) { int ret; ret = imx347_write_array(imx347->client, imx347->cur_mode->reg_list); + if (ret) + return ret; + ret = imx347_init_conversion_gain(imx347); if (ret) return ret; /* In case these controls are set before streaming */ @@ -1768,9 +1827,9 @@ static int imx347_initialize_controls(struct imx347 *imx347) imx347->link_freq = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, - 0, 0, link_freq_menu_items); + 1, 0, link_freq_menu_items); if (imx347->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) { - imx347->cur_link_freq = MIPI_FREQ_594M; + imx347->cur_link_freq = 1; if (imx347->cur_mode->hdr_mode == NO_HDR) imx347->cur_pixel_rate = IMX347_10BIT_LINEAR_PIXEL_RATE; @@ -1778,12 +1837,12 @@ static int imx347_initialize_controls(struct imx347 *imx347) imx347->cur_pixel_rate = IMX347_10BIT_HDR2_PIXEL_RATE; } else { - imx347->cur_link_freq = MIPI_FREQ_360M; + imx347->cur_link_freq = 0; imx347->cur_pixel_rate = IMX347_12BIT_PIXEL_RATE; } - __v4l2_ctrl_s_ctrl(imx347->link_freq, - imx347->cur_link_freq); + v4l2_ctrl_s_ctrl(imx347->link_freq, + imx347->cur_link_freq); imx347->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, IMX347_10BIT_HDR2_PIXEL_RATE, 1, imx347->cur_pixel_rate); diff --git a/include/uapi/linux/rk-preisp.h b/include/uapi/linux/rk-preisp.h index fa07c7cd5644..8e5cffc4c7c7 100644 --- a/include/uapi/linux/rk-preisp.h +++ b/include/uapi/linux/rk-preisp.h @@ -57,6 +57,15 @@ struct preisp_hdrae_para_s { int lsc_table[PREISP_LSCTBL_SIZE]; }; +/* + * enum cg_mode_e conversion gain + * + */ +enum cg_mode_e { + GAIN_MODE_LCG, + GAIN_MODE_HCG, +}; + /** * struct preisp_hdrae_exp_s - hdrae exposure * @@ -74,6 +83,9 @@ struct preisp_hdrae_exp_s { unsigned int middle_gain_val; unsigned int short_exp_val; unsigned int short_gain_val; + unsigned char long_cg_mode; + unsigned char middle_cg_mode; + unsigned char short_cg_mode; }; #endif /* _UAPI_RKPREISP_H */