[PATCH v4 13/15] media: i2c: os05b10: keep exposure default in sync with the active mode on VBLANK changes
From: Tarang Raval
Date: Fri Oct 30 2026 - 06:43:47 EST
Update vblank through the control path on mode changes so exposure
limits and default values are recalculated consistently from the
active mode.
Signed-off-by: Tarang Raval <tarang.raval@xxxxxxxxxxxxxxxxx>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@xxxxxxxxxx>
---
drivers/media/i2c/os05b10.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 48c406b2e544..507d714fbd21 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -751,13 +752,23 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct os05b10 *os05b10 = container_of_const(ctrl->handler,
struct os05b10, handler);
+ const struct os05b10_mode *mode_list;
struct v4l2_subdev_state *state;
+ const struct os05b10_mode *mode;
struct v4l2_mbus_framefmt *fmt;
+ unsigned int num_modes;
int vts, ret;
state = v4l2_subdev_get_locked_active_state(&os05b10->sd);
fmt = v4l2_subdev_state_get_format(state, 0);
+ ret = get_mode_table(os05b10, fmt->code, &mode_list, &num_modes);
+ if (ret)
+ return ret;
+
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->width, fmt->height);
+
if (ctrl->id == V4L2_CID_VBLANK) {
/* Honour the VBLANK limits when setting exposure. */
s64 max = fmt->height + ctrl->val - OS05B10_EXPOSURE_MARGIN;
@@ -765,7 +776,7 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
ret = __v4l2_ctrl_modify_range(os05b10->exposure,
os05b10->exposure->minimum, max,
os05b10->exposure->step,
- os05b10->exposure->default_value);
+ min_t(s64, mode->exp, max));
if (ret)
return ret;
}
@@ -851,15 +862,19 @@ static int os05b10_set_framing_limits(struct os05b10 *os05b10,
vblank = mode->vts - mode->height;
vblank_max = OS05B10_VTS_MAX - mode->height;
- ret = __v4l2_ctrl_modify_range(os05b10->vblank, 0, vblank_max, 1,
+ ret = __v4l2_ctrl_modify_range(os05b10->vblank, vblank, vblank_max, 1,
vblank);
if (ret)
return ret;
max_exp = mode->vts - OS05B10_EXPOSURE_MARGIN;
- return __v4l2_ctrl_modify_range(os05b10->exposure,
- OS05B10_EXPOSURE_MIN, max_exp,
- OS05B10_EXPOSURE_STEP, mode->exp);
+ ret = __v4l2_ctrl_modify_range(os05b10->exposure,
+ OS05B10_EXPOSURE_MIN, max_exp,
+ OS05B10_EXPOSURE_STEP, mode->exp);
+ if (ret)
+ return ret;
+
+ return __v4l2_ctrl_s_ctrl(os05b10->vblank, vblank);
}
static int os05b10_set_pad_format(struct v4l2_subdev *sd,
--
2.34.1