media: i2c: ov9282: Add external FSIN trigger snapshot mode

This patch adds support for external FSIN-triggered snapshot mode
to the OmniVision OV9282 sensor driver. It enables frame capture
synchronized with an external hardware trigger signal.

Signed-off-by: Omer Faruk Edemen <ofedemen@lectrontech.com>
This commit is contained in:
Omer Faruk Edemen
2025-09-08 10:06:23 +03:00
committed by Phil Elwell
parent 3de77969df
commit e9a6531171

View File

@@ -74,6 +74,14 @@
#define OV9282_REG_MIPI_CTRL00 0x4800
#define OV9282_GATED_CLOCK BIT(5)
/* Trigger mode registers */
#define OV9282_REG_POWER_CTRL 0x4F00
#define OV9282_REG_LOW_POWER_MODE_CTRL 0x3030
#define OV9282_REG_NUM_FRAME_ON_TRIG 0x303F
#define OV9282_REG_SLEEP_PERIOD_CTRL0 0x302C
#define OV9282_REG_SLEEP_PERIOD_CTRL3 0x302F
#define OV9282_REG_TIMING_23 0x3823
/* Input clock rate */
#define OV9282_INCLK_RATE 24000000
@@ -196,6 +204,7 @@ struct ov9282 {
const struct ov9282_mode *cur_mode;
u32 code;
struct mutex mutex;
int trigger_mode;
};
static const s64 link_freq[] = {
@@ -956,6 +965,52 @@ static int ov9282_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
/**
* ov9282_apply_trigger_config() - Configure sensor for FSIN external trigger mode
* @ov9282: pointer to ov9282 device
*
* Return: 0 on success, error code otherwise.
*/
static int ov9282_apply_trigger_config(struct ov9282 *ov9282)
{
int ret;
ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT,
1, OV9282_MODE_STANDBY);
if (ret)
return ret;
/* Low power mode */
ret = ov9282_write_reg(ov9282, OV9282_REG_POWER_CTRL, 1, 0x01);
if (ret)
return ret;
/* External trigger snapshot */
ret = ov9282_write_reg(ov9282, OV9282_REG_LOW_POWER_MODE_CTRL, 1, 0x04);
if (ret)
return ret;
/* 1 frame per trigger */
ret = ov9282_write_reg(ov9282, OV9282_REG_NUM_FRAME_ON_TRIG, 1, 0x01);
if (ret)
return ret;
ret = ov9282_write_reg(ov9282, OV9282_REG_SLEEP_PERIOD_CTRL0, 1, 0x00);
if (ret)
return ret;
ret = ov9282_write_reg(ov9282, OV9282_REG_SLEEP_PERIOD_CTRL3, 1, 0x7F);
if (ret)
return ret;
/* No auto wake */
ret = ov9282_write_reg(ov9282, OV9282_REG_TIMING_23, 1, 0x00);
if (ret)
return ret;
return 0;
}
/**
* ov9282_start_streaming() - Start sensor stream
* @ov9282: pointer to ov9282 device
@@ -1007,15 +1062,26 @@ static int ov9282_start_streaming(struct ov9282 *ov9282)
return ret;
}
/* Start streaming */
ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT,
1, OV9282_MODE_STREAMING);
if (ret) {
dev_err(ov9282->dev, "fail to start streaming");
return ret;
/* Configure FSIN external trigger mode */
if (ov9282->trigger_mode > 0) {
ret = ov9282_apply_trigger_config(ov9282);
if (ret) {
dev_err(ov9282->dev, "failed to config external trigger mode");
return ret;
}
/* stay in standby mode and wait for trigger signal */
ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT,
1, OV9282_MODE_STANDBY);
} else {
/* Start streaming */
ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT,
1, OV9282_MODE_STREAMING);
}
return 0;
if (ret)
dev_err(ov9282->dev, "fail to start streaming");
return ret;
}
/**
@@ -1400,6 +1466,7 @@ static int ov9282_probe(struct i2c_client *client)
{
struct ov9282 *ov9282;
int ret;
u32 trig_mod;
ov9282 = devm_kzalloc(&client->dev, sizeof(*ov9282), GFP_KERNEL);
if (!ov9282)
@@ -1439,6 +1506,10 @@ static int ov9282_probe(struct i2c_client *client)
ov9282->code = MEDIA_BUS_FMT_Y10_1X10;
ov9282->vblank = ov9282->cur_mode->vblank;
ret = of_property_read_u32(client->dev.of_node,
"trigger-mode", &trig_mod);
ov9282->trigger_mode = (ret == 0) ? trig_mod : -1;
ret = ov9282_init_controls(ov9282);
if (ret) {
dev_err(ov9282->dev, "failed to init controls: %d", ret);