<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From 700a1a11144c9b18b9da3d900a1d8bfa30a195a8 Mon Sep 17 00:00:00 2001
From: David Plowman &lt;david.plowman@raspberrypi.com&gt;
Date: Wed, 22 Mar 2023 12:01:57 +0000
Subject: [PATCH] drivers: media: i2c: imx708: Fix WIDE_DYNAMIC_RANGE
 control with long exposure

Setting V4L2_CID_WIDE_DYNAMIC_RANGE was causing the long exposure
shift count to be reset, which is incorrect if the user has already
changed the frame length to cause it to have a non-zero value.

Because it only updates control ranges and doesn't set any registers,
the control can also be applied when the sensor is not powered on.

Signed-off-by: David Plowman &lt;david.plowman@raspberrypi.com&gt;
---
 drivers/media/i2c/imx708.c | 45 ++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 17 deletions(-)

--- a/drivers/media/i2c/imx708.c
+++ b/drivers/media/i2c/imx708.c
@@ -171,7 +171,7 @@ struct imx708_mode {
 	/* Not all modes have the same exposure lines step. */
 	u32 exposure_lines_step;
 
-	/* HDR flag, currently not used at runtime */
+	/* HDR flag, used for checking if the current mode is HDR */
 	bool hdr;
 };
 
@@ -1060,9 +1060,6 @@ static void imx708_set_framing_limits(st
 	unsigned int hblank;
 	const struct imx708_mode *mode = imx708-&gt;mode;
 
-	/* Default to no long exposure multiplier */
-	imx708-&gt;long_exp_shift = 0;
-
 	__v4l2_ctrl_modify_range(imx708-&gt;pixel_rate,
 				 mode-&gt;pixel_rate, mode-&gt;pixel_rate,
 				 1, mode-&gt;pixel_rate);
@@ -1091,12 +1088,33 @@ static int imx708_set_ctrl(struct v4l2_c
 	unsigned int code, num_modes;
 	int ret = 0;
 
-	/*
-	 * The VBLANK control may change the limits of usable exposure, so check
-	 * and adjust if necessary.
-	 */
-	if (ctrl-&gt;id == V4L2_CID_VBLANK)
+	switch (ctrl-&gt;id) {
+	case V4L2_CID_VBLANK:
+		/*
+		 * The VBLANK control may change the limits of usable exposure,
+		 * so check and adjust if necessary.
+		 */
 		imx708_adjust_exposure_range(imx708, ctrl);
+		break;
+
+	case V4L2_CID_WIDE_DYNAMIC_RANGE:
+		/*
+		 * The WIDE_DYNAMIC_RANGE control can also be applied immediately
+		 * as it doesn't set any registers. Don't do anything if the mode
+		 * already matches.
+		 */
+		if (imx708-&gt;mode &amp;&amp; imx708-&gt;mode-&gt;hdr != ctrl-&gt;val) {
+			code = imx708_get_format_code(imx708);
+			get_mode_table(code, &amp;mode_list, &amp;num_modes, ctrl-&gt;val);
+			imx708-&gt;mode = v4l2_find_nearest_size(mode_list,
+							      num_modes,
+							      width, height,
+							      imx708-&gt;mode-&gt;width,
+							      imx708-&gt;mode-&gt;height);
+			imx708_set_framing_limits(imx708);
+		}
+		break;
+	}
 
 	/*
 	 * Applying V4L2 control value only happens
@@ -1158,14 +1176,7 @@ static int imx708_set_ctrl(struct v4l2_c
 				       imx708-&gt;notify_gains-&gt;p_new.p_u32[3]);
 		break;
 	case V4L2_CID_WIDE_DYNAMIC_RANGE:
-		code = imx708_get_format_code(imx708);
-		get_mode_table(code, &amp;mode_list, &amp;num_modes, ctrl-&gt;val);
-		imx708-&gt;mode = v4l2_find_nearest_size(mode_list,
-						      num_modes,
-						      width, height,
-						      imx708-&gt;mode-&gt;width,
-						      imx708-&gt;mode-&gt;height);
-		imx708_set_framing_limits(imx708);
+		/* Already handled above. */
 		break;
 	default:
 		dev_info(&amp;client-&gt;dev,
</pre></body></html>