media: i2c: ov9282: implement try_ctrl for strobe_duration

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>
This commit is contained in:
Richard Leitner 2025-12-09 23:44:42 +01:00 committed by Hans Verkuil
parent 84ec7597ae
commit b95d8058a2

View 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>
@ -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,
};
/**