[PATCH v4 15/15] media: i2c: os05b10: fix horizontal blanking calculation

From: Tarang Raval

Date: Fri Oct 30 2026 - 06:54:44 EST


The HTS register is not counted in output pixels, so "hts - width" is
meaningless: for every mode hts < width (e.g. 1744 vs 2592 for
2592x1944) and the u32 subtraction wraps. v4l2-compliance flags the
resulting HBLANK range:

fail: v4l2-test-controls.cpp(413): returned control value out of range

The timing generator counts lines in internal clock cycles that cover
several pixels. At 30 fps in the 2592x1944 mode (HTS 1744, VTS 2006) the
line timing is

HTS * VTS * fps = 1744 * 2006 * 30.01 ~= 105 MHz

which is half of the 210 MHz system clock. Use 4 pixels per cycle, which
gives an internal pixel rate of 105 MHz * 4 = 420 MPix/s.

Compute HBLANK as HTS * 4 - width, with a step of 4 pixels, and report
the fixed 420 MPix/s as PIXEL_RATE so that
fps = PIXEL_RATE / ((width + HBLANK) * (height + VBLANK)) holds. This
rate does not depend on the bit depth or the number of MIPI lanes, so
stop deriving it from the link frequency.

Fixes: 3aa9296a23ec4 ("media: i2c: add os05b10 image sensor driver")
Signed-off-by: Tarang Raval <tarang.raval@xxxxxxxxxxxxxxxxx>
---
drivers/media/i2c/os05b10.c | 38 +++++++++++++++++--------------------
1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 9284b21a92c7..4e87a9bd0f4d 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -113,6 +113,15 @@
#define OS05B10_LINK_FREQ_600MHZ (600 * HZ_PER_MHZ)
#define OS05B10_LINK_FREQ_750MHZ (750 * HZ_PER_MHZ)

+/*
+ * HTS is not counted in output pixels: the timing generator runs at half of
+ * the 210 MHz system clock and handles 4 pixels per cycle, giving an
+ * internal pixel rate of 105 MHz * 4 = 420 MPix/s. This is independent of
+ * the bit depth and of the number of MIPI lanes.
+ */
+#define OS05B10_PIXEL_RATE (420 * HZ_PER_MHZ)
+#define OS05B10_PIX_PER_CLK 4
+
static const struct v4l2_rect os05b10_native_area = {
.top = 0,
.left = 0,
@@ -872,9 +881,9 @@ static int os05b10_set_framing_limits(struct os05b10 *os05b10,
u32 hblank, vblank, vblank_max, max_exp;
int ret;

- hblank = mode->hts - mode->width;
- ret = __v4l2_ctrl_modify_range(os05b10->hblank, hblank, hblank, 1,
- hblank);
+ hblank = mode->hts * OS05B10_PIX_PER_CLK - mode->width;
+ ret = __v4l2_ctrl_modify_range(os05b10->hblank, hblank, hblank,
+ OS05B10_PIX_PER_CLK, hblank);
if (ret)
return ret;

@@ -1260,23 +1269,10 @@ static int os05b10_parse_endpoint(struct os05b10 *os05b10)
return ret;
}

-static u64 os05b10_pixel_rate(struct os05b10 *os05b10,
- const struct os05b10_mode *mode)
-{
- u64 link_freq = os05b10->link_frequencies[os05b10->link_freq_index];
- u64 pixel_rate = div_u64(link_freq * 2 * os05b10->data_lanes, mode->bpp);
-
- dev_dbg(os05b10->dev,
- "link_freq=%llu bpp=%u lanes=%u pixel_rate=%llu\n",
- link_freq, mode->bpp, os05b10->data_lanes, pixel_rate);
-
- return pixel_rate;
-}
-
static int os05b10_init_controls(struct os05b10 *os05b10)
{
const struct os05b10_mode *mode = &supported_modes_10bit[0];
- u64 hblank_def, vblank_def, exp_max, pixel_rate;
+ u64 hblank_def, vblank_def, exp_max;
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
struct v4l2_ctrl *link_freq;
@@ -1289,9 +1285,9 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
ctrl_hdlr = &os05b10->handler;
v4l2_ctrl_handler_init(ctrl_hdlr, 12);

- pixel_rate = os05b10_pixel_rate(os05b10, mode);
v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_PIXEL_RATE,
- pixel_rate, pixel_rate, 1, pixel_rate);
+ OS05B10_PIXEL_RATE, OS05B10_PIXEL_RATE, 1,
+ OS05B10_PIXEL_RATE);

link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &os05b10_ctrl_ops,
V4L2_CID_LINK_FREQ,
@@ -1299,10 +1295,10 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
os05b10->link_freq_index,
os05b10->link_frequencies);

- hblank_def = mode->hts - mode->width;
+ hblank_def = mode->hts * OS05B10_PIX_PER_CLK - mode->width;
os05b10->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK,
hblank_def, hblank_def,
- 1, hblank_def);
+ OS05B10_PIX_PER_CLK, hblank_def);

vblank_def = mode->vts - mode->height;
os05b10->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops,
--
2.34.1