mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
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:
parent
84ec7597ae
commit
b95d8058a2
|
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user