aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.10/950-0485-media-i2c-imx477-Add-very-long-exposure-control-to-t.patch
diff options
context:
space:
mode:
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.patch126
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. */