]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: i2c: ov9282: implement try_ctrl for strobe_duration
authorRichard Leitner <richard.leitner@linux.dev>
Tue, 9 Dec 2025 22:44:42 +0000 (23:44 +0100)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Fri, 16 Jan 2026 13:08:53 +0000 (14:08 +0100)
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 <richard.leitner@linux.dev>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/i2c/ov9282.c

index 92da28f248a4e2c9c828a21901637637faaca8ec..3c74d65fe3125daf7e405f84743a37cf5e84d7a2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/math.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #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,
 };
 
 /**