[SRU][N:linux-xilinx][PATCH v2 04/14] drivers: media: imx708: Enable long exposure mode

Stewart Hore stewart.hore at canonical.com
Sun Oct 19 04:15:25 UTC 2025


From: Naushir Patuck <naush at raspberrypi.com>

BugLink: https://bugs.launchpad.net/bugs/2127886

Enable long exposure modes by using the long exposure shift register setting
in the imx708 sensor.

Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
(cherry picked from commit 888ab334c66113a1b311c412c7e7ce97555d73f2 rpi-6.6.y)
Signed-off-by: Juerg Haefliger <juerg.haefliger at canonical.com>
(cherry picked from commit 485b06374c1b256af2321036ab6591bb4b3cd051 noble:linux-raspi)
Signed-off-by: Stewart Hore <stewart.hore at canonical.com>
---
 drivers/media/i2c/imx708.c | 41 +++++++++++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/imx708.c b/drivers/media/i2c/imx708.c
index 83f6fbbe7408..49af75c1df36 100644
--- a/drivers/media/i2c/imx708.c
+++ b/drivers/media/i2c/imx708.c
@@ -44,6 +44,10 @@
 #define IMX708_REG_FRAME_LENGTH		0x0340
 #define IMX708_FRAME_LENGTH_MAX		0xffff

+/* Long exposure multiplier */
+#define IMX708_LONG_EXP_SHIFT_MAX	7
+#define IMX708_LONG_EXP_SHIFT_REG	0x3100
+
 /* Exposure control */
 #define IMX708_REG_EXPOSURE		0x0202
 #define IMX708_EXPOSURE_OFFSET		48
@@ -806,6 +810,9 @@ struct imx708 {

 	/* 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 imx708 *to_imx708(struct v4l2_subdev *_sd)
@@ -994,7 +1001,8 @@ static int imx708_set_exposure(struct imx708 *imx708, unsigned int val)
 	 * will automatically divide the medium and short ones by 4,16.
 	 */
 	ret = imx708_write_reg(imx708, IMX708_REG_EXPOSURE,
-			       IMX708_REG_VALUE_16BIT, val);
+			       IMX708_REG_VALUE_16BIT,
+			       val >> imx708->long_exp_shift);

 	return ret;
 }
@@ -1027,18 +1035,42 @@ static int imx708_set_analogue_gain(struct imx708 *imx708, unsigned int val)
 	return ret;
 }

+static int imx708_set_frame_length(struct imx708 *imx708, unsigned int val)
+{
+	int ret = 0;
+
+	imx708->long_exp_shift = 0;
+
+	while (val > IMX708_FRAME_LENGTH_MAX) {
+		imx708->long_exp_shift++;
+		val >>= 1;
+	}
+
+	ret = imx708_write_reg(imx708, IMX708_REG_FRAME_LENGTH,
+			       IMX708_REG_VALUE_16BIT, val);
+	if (ret)
+		return ret;
+
+	return imx708_write_reg(imx708, IMX708_LONG_EXP_SHIFT_REG,
+				IMX708_REG_VALUE_08BIT, imx708->long_exp_shift);
+}
+
 static void imx708_set_framing_limits(struct imx708 *imx708)
 {
 	unsigned int hblank;
 	const struct imx708_mode *mode = imx708->mode;

+	/* Default to no long exposure multiplier */
+	imx708->long_exp_shift = 0;
+
 	__v4l2_ctrl_modify_range(imx708->pixel_rate,
 				 mode->pixel_rate, mode->pixel_rate,
 				 1, mode->pixel_rate);

 	/* Update limits and set FPS to default */
 	__v4l2_ctrl_modify_range(imx708->vblank, mode->vblank_min,
-				 IMX708_FRAME_LENGTH_MAX - mode->height,
+				 ((1 << IMX708_LONG_EXP_SHIFT_MAX) *
+					IMX708_FRAME_LENGTH_MAX) - mode->height,
 				 1, mode->vblank_default);

 	/*
@@ -1112,9 +1144,8 @@ static int imx708_set_ctrl(struct v4l2_ctrl *ctrl)
 				       imx708->vflip->val << 1);
 		break;
 	case V4L2_CID_VBLANK:
-		ret = imx708_write_reg(imx708, IMX708_REG_FRAME_LENGTH,
-				       IMX708_REG_VALUE_16BIT,
-				       imx708->mode->height + ctrl->val);
+		ret = imx708_set_frame_length(imx708,
+					      imx708->mode->height + ctrl->val);
 		break;
 	case V4L2_CID_NOTIFY_GAINS:
 		ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_BLUE,
--
2.48.1




More information about the kernel-team mailing list