diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.10/950-0485-media-i2c-imx477-Add-very-long-exposure-control-to-t.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.10/950-0485-media-i2c-imx477-Add-very-long-exposure-control-to-t.patch | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.10/950-0485-media-i2c-imx477-Add-very-long-exposure-control-to-t.patch b/target/linux/bcm27xx/patches-5.10/950-0485-media-i2c-imx477-Add-very-long-exposure-control-to-t.patch new file mode 100644 index 0000000000..1ad1f5ddbd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.10/950-0485-media-i2c-imx477-Add-very-long-exposure-control-to-t.patch @@ -0,0 +1,126 @@ +From 973d774838b036ceef91e09a7994558c793b4d8a Mon Sep 17 00:00:00 2001 +From: Naushir Patuck <naush@raspberrypi.com> +Date: Wed, 10 Feb 2021 10:50:32 +0000 +Subject: [PATCH] media: i2c: imx477: Add very long exposure control to + the driver + +Add support for very long exposures by using the exposure multiplier +register. Userland does not need to pass any additional controls to +enable long exposures, it simply requests a larger vblank to extend the +exposure control range appropriately. + +Currently, since hblank is fixed, a maximum of approximately 124 seconds +of exposure time can be used. In a future change, hblank could also be +controlled in userland to give over 200 seconds of exposure time. + +Signed-off-by: Naushir Patuck <naush@raspberrypi.com> +--- + drivers/media/i2c/imx477.c | 47 +++++++++++++++++++++++++++++++++----- + 1 file changed, 41 insertions(+), 6 deletions(-) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -44,6 +44,10 @@ + #define IMX477_REG_FRAME_LENGTH 0x0340 + #define IMX477_FRAME_LENGTH_MAX 0xffdc + ++/* Long exposure multiplier */ ++#define IMX477_LONG_EXP_SHIFT_MAX 7 ++#define IMX477_LONG_EXP_SHIFT_REG 0x3100 ++ + /* Exposure control */ + #define IMX477_REG_EXPOSURE 0x0202 + #define IMX477_EXPOSURE_OFFSET 22 +@@ -1097,6 +1101,9 @@ struct imx477 { + + /* Rewrite common registers on stream on? */ + bool common_regs_written; ++ ++ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ ++ unsigned int long_exp_shift; + }; + + static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd) +@@ -1285,13 +1292,33 @@ static void imx477_adjust_exposure_range + + /* Honour the VBLANK limits when setting exposure. */ + exposure_max = imx477->mode->height + imx477->vblank->val - +- IMX477_EXPOSURE_OFFSET; ++ (IMX477_EXPOSURE_OFFSET << imx477->long_exp_shift); + exposure_def = min(exposure_max, imx477->exposure->val); + __v4l2_ctrl_modify_range(imx477->exposure, imx477->exposure->minimum, + exposure_max, imx477->exposure->step, + exposure_def); + } + ++static int imx477_set_frame_length(struct imx477 *imx477, unsigned int val) ++{ ++ int ret = 0; ++ ++ imx477->long_exp_shift = 0; ++ ++ while (val > IMX477_FRAME_LENGTH_MAX) { ++ imx477->long_exp_shift++; ++ val >>= 1; ++ } ++ ++ ret = imx477_write_reg(imx477, IMX477_REG_FRAME_LENGTH, ++ IMX477_REG_VALUE_16BIT, val); ++ if (ret) ++ return ret; ++ ++ return imx477_write_reg(imx477, IMX477_LONG_EXP_SHIFT_REG, ++ IMX477_REG_VALUE_08BIT, imx477->long_exp_shift); ++} ++ + static int imx477_set_ctrl(struct v4l2_ctrl *ctrl) + { + struct imx477 *imx477 = +@@ -1299,6 +1326,10 @@ static int imx477_set_ctrl(struct v4l2_c + struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); + int ret = 0; + ++ /* ++ * The VBLANK control may change the limits of usable exposure, so check ++ * and adjust if necessary. ++ */ + if (ctrl->id == V4L2_CID_VBLANK) + imx477_adjust_exposure_range(imx477, ctrl); + +@@ -1316,7 +1347,8 @@ static int imx477_set_ctrl(struct v4l2_c + break; + case V4L2_CID_EXPOSURE: + ret = imx477_write_reg(imx477, IMX477_REG_EXPOSURE, +- IMX477_REG_VALUE_16BIT, ctrl->val); ++ IMX477_REG_VALUE_16BIT, ctrl->val >> ++ imx477->long_exp_shift); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = imx477_write_reg(imx477, IMX477_REG_DIGITAL_GAIN, +@@ -1350,9 +1382,8 @@ static int imx477_set_ctrl(struct v4l2_c + imx477->vflip->val << 1); + break; + case V4L2_CID_VBLANK: +- ret = imx477_write_reg(imx477, IMX477_REG_FRAME_LENGTH, +- IMX477_REG_VALUE_16BIT, +- imx477->mode->height + ctrl->val); ++ ret = imx477_set_frame_length(imx477, ++ imx477->mode->height + ctrl->val); + break; + default: + dev_info(&client->dev, +@@ -1521,9 +1552,13 @@ static void imx477_set_framing_limits(st + frm_length_default = + imx477_get_frame_length(mode, &mode->timeperframe_default); + ++ /* Default to no long exposure multiplier. */ ++ imx477->long_exp_shift = 0; ++ + /* Update limits and set FPS to default */ + __v4l2_ctrl_modify_range(imx477->vblank, frm_length_min - mode->height, +- IMX477_FRAME_LENGTH_MAX - mode->height, ++ ((1 << IMX477_LONG_EXP_SHIFT_MAX) * ++ IMX477_FRAME_LENGTH_MAX) - mode->height, + 1, frm_length_default - mode->height); + + /* Setting this will adjust the exposure limits as well. */ |