From b95d8058a2786a8b42e32f383f8df45097675d00 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Tue, 9 Dec 2025 23:44:42 +0100 Subject: [PATCH] media: i2c: ov9282: implement try_ctrl for strobe_duration MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit As the granularity of the hardware supported values is lower than the control value, implement a try_ctrl() function for V4L2_CID_FLASH_DURATION. This function calculates the nearest possible µs strobe duration for the given value and returns it back to the caller. Signed-off-by: Richard Leitner Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9282.c | 53 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 92da28f248a4e..3c74d65fe3125 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,8 @@ #define OV9282_REG_MIN 0x00 #define OV9282_REG_MAX 0xfffff +#define OV9282_STROBE_SPAN_FACTOR 192 + static const char * const ov9282_supply_names[] = { "avdd", /* Analog power */ "dovdd", /* Digital I/O power */ @@ -691,7 +694,7 @@ static int ov9282_set_ctrl_flash_strobe_oe(struct ov9282 *ov9282, bool enable) return ov9282_write_reg(ov9282, OV9282_REG_OUTPUT_ENABLE6, 1, current_val); } -static int ov9282_set_ctrl_flash_duration(struct ov9282 *ov9282, u32 value) +static u32 ov9282_us_to_flash_duration(struct ov9282 *ov9282, u32 value) { /* * Calculate "strobe_frame_span" increments from a given value (µs). @@ -702,7 +705,26 @@ static int ov9282_set_ctrl_flash_duration(struct ov9282 *ov9282, u32 value) * The formula below is interpolated from different modes/framerates * and should work quite well for most settings. */ - u32 val = value * 192 / (ov9282->cur_mode->width + ov9282->hblank_ctrl->val); + u32 frame_width = ov9282->cur_mode->width + ov9282->hblank_ctrl->val; + + return value * OV9282_STROBE_SPAN_FACTOR / frame_width; +} + +static u32 ov9282_flash_duration_to_us(struct ov9282 *ov9282, u32 value) +{ + /* + * Calculate back to microseconds from "strobe_frame_span" increments. + * As the calculation in ov9282_us_to_flash_duration uses an integer + * divison round up here. + */ + u32 frame_width = ov9282->cur_mode->width + ov9282->hblank_ctrl->val; + + return DIV_ROUND_UP(value * frame_width, OV9282_STROBE_SPAN_FACTOR); +} + +static int ov9282_set_ctrl_flash_duration(struct ov9282 *ov9282, u32 value) +{ + u32 val = ov9282_us_to_flash_duration(ov9282, value); int ret; ret = ov9282_write_reg(ov9282, OV9282_REG_STROBE_FRAME_SPAN, 1, @@ -806,9 +828,36 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl) return ret; } +static int ov9282_try_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov9282 *ov9282 = + container_of_const(ctrl->handler, struct ov9282, ctrl_handler); + + if (ctrl->id == V4L2_CID_FLASH_DURATION) { + u32 us = ctrl->val; + u32 fd = ov9282_us_to_flash_duration(ov9282, us); + + /* get nearest strobe_duration value */ + u32 us0 = ov9282_flash_duration_to_us(ov9282, fd); + u32 us1 = ov9282_flash_duration_to_us(ov9282, fd + 1); + + if (abs(us1 - us) < abs(us - us0)) + ctrl->val = us1; + else + ctrl->val = us0; + + if (us != ctrl->val) + dev_dbg(ov9282->dev, "using next valid strobe_duration %u instead of %u\n", + ctrl->val, us); + } + + return 0; +} + /* V4l2 subdevice control ops*/ static const struct v4l2_ctrl_ops ov9282_ctrl_ops = { .s_ctrl = ov9282_set_ctrl, + .try_ctrl = ov9282_try_ctrl, }; /** -- 2.47.3