From 04e18d5d237f55890ed5f3f61392d429ffeb76e1 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 23 Jun 2025 15:06:08 +0800 Subject: [PATCH] media: i2c: sc132gs fixes some error 1.fixes exposure range 2.add digital again support 3.update init setting 4.fixes testpattern operation error Change-Id: I8f6060965cfc994e555a169e437e106803970470 Signed-off-by: Zefa Chen --- drivers/media/i2c/sc132gs.c | 213 ++++++++++++++++++++++++------------ 1 file changed, 142 insertions(+), 71 deletions(-) diff --git a/drivers/media/i2c/sc132gs.c b/drivers/media/i2c/sc132gs.c index 627d050d5f36..4c9f48999009 100644 --- a/drivers/media/i2c/sc132gs.c +++ b/drivers/media/i2c/sc132gs.c @@ -50,21 +50,23 @@ #define SC132GS_MODE_SW_STANDBY 0x0 #define SC132GS_MODE_STREAMING BIT(0) -#define SC132GS_REG_EXPOSURE 0x3e01 -#define SC132GS_EXPOSURE_MIN 6 +#define SC132GS_REG_EXPOSURE 0x3e00 +#define SC132GS_EXPOSURE_MIN 1 #define SC132GS_EXPOSURE_STEP 1 #define SC132GS_VTS_MAX 0xffff #define SC132GS_REG_COARSE_AGAIN 0x3e08 #define SC132GS_REG_FINE_AGAIN 0x3e09 +#define SC132GS_REG_COARSE_DGAIN 0x3e06 +#define SC132GS_REG_FINE_DGAIN 0x3e07 + #define ANALOG_GAIN_MIN 0x20 -#define ANALOG_GAIN_MAX 0x391 +#define ANALOG_GAIN_MAX 0x6c80 #define ANALOG_GAIN_STEP 1 #define ANALOG_GAIN_DEFAULT 0x20 #define SC132GS_REG_TEST_PATTERN 0x4501 -#define SC132GS_TEST_PATTERN_ENABLE 0xcc -#define SC132GS_TEST_PATTERN_DISABLE 0xc4 +#define SC132GS_TEST_PATTERN_BIT_MASK BIT(3) #define SC132GS_REG_VTS 0x320e @@ -285,18 +287,18 @@ static const struct regval sc132gs_2lane_10bit_regs[] = { {0x3018, 0x32}, {0x3019, 0x0c}, {0x301a, 0xb4}, - {0x3031, 0x0a}, + {0x301f, 0x51}, {0x3032, 0x60}, {0x3038, 0x44}, {0x3207, 0x17}, - {0x320c, 0x05}, - {0x320d, 0xdc}, - {0x320e, 0x09}, - {0x320f, 0x60}, + {0x320c, 0x02}, + {0x320d, 0xee}, + {0x320e, 0x05}, + {0x320f, 0x78}, {0x3250, 0xcc}, {0x3251, 0x02}, - {0x3252, 0x09}, - {0x3253, 0x5b}, + {0x3252, 0x05}, + {0x3253, 0x73}, {0x3254, 0x05}, {0x3255, 0x3b}, {0x3306, 0x78}, @@ -331,18 +333,22 @@ static const struct regval sc132gs_2lane_10bit_regs[] = { {0x363b, 0x48}, {0x363c, 0x83}, {0x363d, 0x10}, - {0x36ea, 0x38}, - {0x36fa, 0x25}, - {0x36fb, 0x05}, - {0x36fd, 0x04}, + {0x36ea, 0x36}, + {0x36eb, 0x04}, + {0x36ec, 0x13}, + {0x36ed, 0x24}, + {0x36fa, 0x2b}, + {0x36fb, 0x1b}, + {0x36fc, 0x11}, + {0x36fd, 0x34}, {0x3900, 0x11}, {0x3901, 0x05}, {0x3902, 0xc5}, {0x3904, 0x04}, {0x3908, 0x91}, {0x391e, 0x00}, - {0x3e01, 0x11}, - {0x3e02, 0x20}, + {0x3e01, 0x4e}, + {0x3e02, 0xc0}, {0x3e09, 0x20}, {0x3e0e, 0xd2}, {0x3e14, 0xb0}, @@ -350,7 +356,7 @@ static const struct regval sc132gs_2lane_10bit_regs[] = { {0x3e26, 0x20}, {0x4418, 0x38}, {0x4503, 0x10}, - {0x4837, 0x21}, + {0x4837, 0x35}, {0x5000, 0x0e}, {0x540c, 0x51}, {0x550f, 0x38}, @@ -381,8 +387,13 @@ static const struct regval sc132gs_2lane_10bit_regs[] = { //{0x3221, ((0x3 << 1)|(0x3 << 5))}, //PLL set - {0x36e9, 0x20}, - {0x36f9, 0x24}, + {0x36e9, 0x54}, + {0x36f9, 0x50}, + {0x0100, 0x01}, + + //gain >= 2 + {0x33fa, 0x02}, + {0x3317, 0x14}, {REG_NULL, 0x00}, }; @@ -395,14 +406,14 @@ static const struct sc132gs_mode supported_modes[] = { .numerator = 10000, .denominator = 300000, }, - .exp_def = 0x0148, - .hts_def = 0x06a0, - .vts_def = 0x084a, + .exp_def = 0x04ec, + .hts_def = 0x02ee*2, + .vts_def = 0x0578, .link_freq_index = LINK_FREQ_180M_INDEX, .pixel_rate = PIXEL_RATE_WITH_180M, .reg_list = sc132gs_2lane_10bit_regs, .lanes = 2, - .bus_fmt = MEDIA_BUS_FMT_Y10_1X10, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, }, { @@ -644,15 +655,19 @@ static int sc132gs_enum_frame_sizes(struct v4l2_subdev *sd, static int sc132gs_enable_test_pattern(struct sc132gs *sc132gs, u32 pattern) { - u32 val; + u32 val = 0; + int ret = 0; + ret = sc132gs_read_reg(sc132gs->client, SC132GS_REG_TEST_PATTERN, + SC132GS_REG_VALUE_08BIT, &val); if (pattern) - val = (pattern - 1) | SC132GS_TEST_PATTERN_ENABLE; + val |= SC132GS_TEST_PATTERN_BIT_MASK; else - val = SC132GS_TEST_PATTERN_DISABLE; + val &= ~SC132GS_TEST_PATTERN_BIT_MASK; - return sc132gs_write_reg(sc132gs->client, SC132GS_REG_TEST_PATTERN, - SC132GS_REG_VALUE_08BIT, val); + ret |= sc132gs_write_reg(sc132gs->client, SC132GS_REG_TEST_PATTERN, + SC132GS_REG_VALUE_08BIT, val); + return ret; } static void sc132gs_get_module_inf(struct sc132gs *sc132gs, @@ -737,50 +752,75 @@ static long sc132gs_compat_ioctl32(struct v4l2_subdev *sd, static int sc132gs_set_ctrl_gain(struct sc132gs *sc132gs, u32 a_gain) { int ret = 0; - u32 coarse_again, fine_again, fine_again_reg, coarse_again_reg; + u32 fine_again_reg, coarse_again_reg, fine_dgain_reg, coarse_dgain_reg; if (a_gain < 0x20) a_gain = 0x20; - if (a_gain > 0x391) - a_gain = 0x391; + if (a_gain > 0x6c80) + a_gain = 0x6c80; if (a_gain < 0x3a) {/*1x~1.813*/ - fine_again = a_gain; - coarse_again = 0x03; - fine_again_reg = fine_again & 0x3f; - coarse_again_reg = coarse_again & 0x3F; - if (fine_again_reg >= 0x39) - fine_again_reg = 0x39; - } else if (a_gain < 0x72) {/*1.813~3.568x*/ - fine_again = (a_gain - 0x3a) * 1000 / 1755 + 0x20; - coarse_again = 0x23; - if (fine_again > 0x3f) - fine_again = 0x3f; - fine_again_reg = fine_again & 0x3f; - coarse_again_reg = coarse_again & 0x3F; + fine_again_reg = a_gain; + coarse_again_reg = 0x03; + fine_dgain_reg = 0x80; + coarse_dgain_reg = 0x00; + } else if (a_gain < 0x74) {/*1.813~3.568x*/ + fine_again_reg = a_gain * 0x20 / 0x3a; + coarse_again_reg = 0x23; + fine_dgain_reg = 0x80; + coarse_dgain_reg = 0x00; } else if (a_gain < 0xe8) { /*3.568x~7.250x*/ - fine_again = (a_gain - 0x72) * 1000 / 3682 + 0x20; - coarse_again = 0x27; - if (fine_again > 0x3f) - fine_again = 0x3f; - fine_again_reg = fine_again & 0x3f; - coarse_again_reg = coarse_again & 0x3F; + fine_again_reg = a_gain * 0x20 / 0x74; + coarse_again_reg = 0x27; + fine_dgain_reg = 0x80; + coarse_dgain_reg = 0x00; } else if (a_gain < 0x1d0) { /*7.250x~14.5x*/ - fine_again = (a_gain - 0xe8) * 100 / 725 + 0x20; - coarse_again = 0x2f; - if (fine_again > 0x3f) - fine_again = 0x3f; - fine_again_reg = fine_again & 0x3f; - coarse_again_reg = coarse_again & 0x3F; - } else { /*14.5x~28.547*/ - fine_again = (a_gain - 0x1d0) * 1000 / 14047 + 0x20; - coarse_again = 0x3f; - if (fine_again > 0x3f) - fine_again = 0x3f; - fine_again_reg = fine_again & 0x3f; - coarse_again_reg = coarse_again & 0x3F; + fine_again_reg = a_gain * 0x20 / 0xe8; + coarse_again_reg = 0x2f; + fine_dgain_reg = 0x80; + coarse_dgain_reg = 0x00; + } else if (a_gain < 0x3a0) { /*14.5x~28.547x*/ + fine_again_reg = a_gain * 0x20 / 0x1d0; + coarse_again_reg = 0x3f; + fine_dgain_reg = 0x80; + coarse_dgain_reg = 0x00; + } else if (a_gain < 0x740) { /*again:28.547x, dgain: 1x~2x*/ + fine_again_reg = 0x3f ; + coarse_again_reg = 0x3f; + fine_dgain_reg = a_gain * 0x8 / 0x3a; + if(fine_dgain_reg < 0x80) fine_dgain_reg =0x80; + else fine_dgain_reg = fine_dgain_reg & 0xfc; + coarse_dgain_reg = 0x00; + } else if (a_gain < 0xe80) { /*again:28.547x, dgain: 2x~4x*/ + fine_again_reg = 0x3f ; + coarse_again_reg = 0x3f; + fine_dgain_reg = a_gain * 0x8 / 0x74; + if(fine_dgain_reg < 0x80) fine_dgain_reg =0x80; + else fine_dgain_reg = fine_dgain_reg & 0xfc; + coarse_dgain_reg = 0x01; + } else if (a_gain < 0x1d00) { /*again:28.547x, dgain: 4x~8x*/ + fine_again_reg = 0x3f ; + coarse_again_reg = 0x3f; + fine_dgain_reg = a_gain * 0x8 / 0xe8; + if(fine_dgain_reg < 0x80) fine_dgain_reg =0x80; + else fine_dgain_reg = fine_dgain_reg & 0xfc; + coarse_dgain_reg = 0x03; + } else if (a_gain < 0x3a00) { /*again:28.547x, dgain: 8x~16x*/ + fine_again_reg = 0x3f ; + coarse_again_reg = 0x3f; + fine_dgain_reg = a_gain * 0x8 / 0x1d0; + if(fine_dgain_reg < 0x80) fine_dgain_reg =0x80; + else fine_dgain_reg = fine_dgain_reg & 0xfc; + coarse_dgain_reg = 0x07; + } else { /*again:28.547x, dgain: 16x~31.5x*/ + fine_again_reg = 0x3f ; + coarse_again_reg = 0x3f; + fine_dgain_reg = a_gain * 0x8 / 0x3a0; + if(fine_dgain_reg < 0x80) fine_dgain_reg =0x80; + else fine_dgain_reg = fine_dgain_reg & 0xfc; + coarse_dgain_reg = 0x0f; } - ret |= sc132gs_write_reg(sc132gs->client, + ret = sc132gs_write_reg(sc132gs->client, SC132GS_REG_COARSE_AGAIN, SC132GS_REG_VALUE_08BIT, coarse_again_reg); @@ -788,6 +828,34 @@ static int sc132gs_set_ctrl_gain(struct sc132gs *sc132gs, u32 a_gain) SC132GS_REG_FINE_AGAIN, SC132GS_REG_VALUE_08BIT, fine_again_reg); + ret |= sc132gs_write_reg(sc132gs->client, + SC132GS_REG_COARSE_DGAIN, + SC132GS_REG_VALUE_08BIT, + coarse_dgain_reg); + ret |= sc132gs_write_reg(sc132gs->client, + SC132GS_REG_FINE_DGAIN, + SC132GS_REG_VALUE_08BIT, + fine_dgain_reg); + if (a_gain < 0x40) { + ret |= sc132gs_write_reg(sc132gs->client, + 0x33fa, + SC132GS_REG_VALUE_08BIT, + 0x01); + ret |= sc132gs_write_reg(sc132gs->client, + 0x3317, + SC132GS_REG_VALUE_08BIT, + 0xf0); + } else { + ret |= sc132gs_write_reg(sc132gs->client, + 0x33fa, + SC132GS_REG_VALUE_08BIT, + 0x02); + ret |= sc132gs_write_reg(sc132gs->client, + 0x3317, + SC132GS_REG_VALUE_08BIT, + 0x0a); + } + return ret; } @@ -1110,7 +1178,7 @@ static int sc132gs_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = sc132gs->cur_mode->height + ctrl->val - 6; + max = sc132gs->cur_mode->height + ctrl->val - 8; __v4l2_ctrl_modify_range(sc132gs->exposure, sc132gs->exposure->minimum, max, sc132gs->exposure->step, @@ -1125,10 +1193,13 @@ static int sc132gs_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE: /* 4 least significant bits of expsoure are fractional part */ ret = sc132gs_write_reg(sc132gs->client, SC132GS_REG_EXPOSURE, - SC132GS_REG_VALUE_16BIT, ctrl->val << 4); + SC132GS_REG_VALUE_24BIT, ctrl->val << 4); + + dev_dbg(&client->dev, "set exposure 0x%x \n",ctrl->val); break; case V4L2_CID_ANALOGUE_GAIN: ret = sc132gs_set_ctrl_gain(sc132gs, ctrl->val); + dev_dbg(&client->dev, "set gain 0x%x \n",ctrl->val); break; case V4L2_CID_VBLANK: ret = sc132gs_write_reg(sc132gs->client, SC132GS_REG_VTS, @@ -1136,8 +1207,8 @@ static int sc132gs_set_ctrl(struct v4l2_ctrl *ctrl) ctrl->val + sc132gs->cur_mode->height); if (!ret) sc132gs->cur_vts = ctrl->val + sc132gs->cur_mode->height; - sc132gs_modify_fps_info(sc132gs); - break; + if (sc132gs->cur_vts != sc132gs->cur_mode->vts_def) + sc132gs_modify_fps_info(sc132gs); break; case V4L2_CID_TEST_PATTERN: ret = sc132gs_enable_test_pattern(sc132gs, ctrl->val); @@ -1195,7 +1266,7 @@ static int sc132gs_initialize_controls(struct sc132gs *sc132gs) SC132GS_VTS_MAX - mode->height, 1, vblank_def); - exposure_max = mode->vts_def - 6; + exposure_max = mode->vts_def - 8; sc132gs->exposure = v4l2_ctrl_new_std(handler, &sc132gs_ctrl_ops, V4L2_CID_EXPOSURE, SC132GS_EXPOSURE_MIN, exposure_max, SC132GS_EXPOSURE_STEP,