<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From 6b0cce78e4c84189c93ad0fbad7b8d08439135d4 Mon Sep 17 00:00:00 2001
From: Naushir Patuck &lt;naush@raspberrypi.com&gt;
Date: Tue, 14 Mar 2023 12:56:14 +0000
Subject: [PATCH] media: i2c: imx296: Add helper for hblank control

Add a helper function to setup the horizontal blanking control. Update
the control limits on set_format as the horizontal blanking time must
remain constant regardless of sensor output width.

Signed-off-by: Naushir Patuck &lt;naush@raspberrypi.com&gt;
---
 drivers/media/i2c/imx296.c | 44 ++++++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 14 deletions(-)

--- a/drivers/media/i2c/imx296.c
+++ b/drivers/media/i2c/imx296.c
@@ -384,10 +384,36 @@ static const struct v4l2_ctrl_ops imx296
 	.s_ctrl = imx296_s_ctrl,
 };
 
+static void imx296_setup_hblank(struct imx296 *sensor, unsigned int width)
+{
+	/*
+	 * Horizontal blanking is controlled through the HMAX register, which
+	 * contains a line length in contains a line length in units of an
+	 * internal 74.25 MHz clock derived from the INCLK. The HMAX value is
+	 * currently fixed to 1100, convert it to a number of pixels based on
+	 * the nominal pixel rate.
+	 *
+	 * Horizontal blanking is fixed, regardless of the crop width, so
+	 * ensure the hblank limits are adjusted to account for this.
+	 */
+	unsigned int hblank = 1100 * 1188000000ULL / 10 / 74250000 - width;
+
+	if (!sensor-&gt;hblank) {
+		sensor-&gt;hblank = v4l2_ctrl_new_std(&amp;sensor-&gt;ctrls,
+						   &amp;imx296_ctrl_ops,
+						   V4L2_CID_HBLANK, hblank,
+						   hblank, 1, hblank);
+		if (sensor-&gt;hblank)
+			sensor-&gt;hblank-&gt;flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	} else {
+		__v4l2_ctrl_modify_range(sensor-&gt;hblank, hblank, hblank, 1,
+					 hblank);
+	}
+}
+
 static int imx296_ctrls_init(struct imx296 *sensor)
 {
 	struct v4l2_fwnode_device_properties props;
-	unsigned int hblank;
 	int ret;
 
 	ret = v4l2_fwnode_device_parse(sensor-&gt;dev, &amp;props);
@@ -402,19 +428,7 @@ static int imx296_ctrls_init(struct imx2
 			  V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN,
 			  IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN);
 
-	/*
-	 * Horizontal blanking is controlled through the HMAX register, which
-	 * contains a line length in INCK clock units. The INCK frequency is
-	 * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100,
-	 * convert it to a number of pixels based on the nominal pixel rate.
-	 */
-	hblank = 1100 * 1188000000ULL / 10 / 74250000
-	       - IMX296_PIXEL_ARRAY_WIDTH;
-	sensor-&gt;hblank = v4l2_ctrl_new_std(&amp;sensor-&gt;ctrls, &amp;imx296_ctrl_ops,
-					   V4L2_CID_HBLANK, hblank, hblank, 1,
-					   hblank);
-	if (sensor-&gt;hblank)
-		sensor-&gt;hblank-&gt;flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	imx296_setup_hblank(sensor, IMX296_PIXEL_ARRAY_WIDTH);
 
 	sensor-&gt;vblank = v4l2_ctrl_new_std(&amp;sensor-&gt;ctrls, &amp;imx296_ctrl_ops,
 					   V4L2_CID_VBLANK, 30,
@@ -739,6 +753,8 @@ static int imx296_set_format(struct v4l2
 		format-&gt;height = crop-&gt;height;
 	}
 
+	imx296_setup_hblank(sensor, format-&gt;width);
+
 	format-&gt;code = sensor-&gt;mono ? MEDIA_BUS_FMT_Y10_1X10
 		     : MEDIA_BUS_FMT_SBGGR10_1X10;
 	format-&gt;field = V4L2_FIELD_NONE;
</pre></body></html>