media: i2c: ov8865: Program the sensor on stream start

The sensor registers are only written in the runtime PM resume
handler; ov8865_set_fmt() merely stores the requested mode, relying on
the sensor being runtime suspended between uses so that the next
resume applies it.

That assumption breaks when something keeps the sensor powered. On
IPU3 platforms, ipu_bridge instantiates the VCM device with a
DL_FLAG_PM_RUNTIME device link to the sensor, so a userspace process
holding the VCM subdev open (e.g. wireplumber's camera monitor) pins
the sensor runtime-active. A subsequent set_fmt() then never reaches
the hardware: the sensor keeps streaming the mode programmed on the
last resume while the CSI-2 receiver expects the newly negotiated
format.

On a Surface Book 2 (IPU3, ov8865 + dw9719 VCM), requesting the
3264x2448 mode while the hardware was left programmed for the
1632x1224 binned mode makes ipu3-cio2 report "frame sync error" and
"payload length is 10340352, received 2585088" (exactly one binned
frame) for every frame, and the inverse case stalls the stream after
a single frame. Camera applications end up displaying one bogus frame
forever.

Program the sensor configuration and apply the control values on
stream start instead, where the negotiated mode is always current,
and only write the configuration in the runtime PM resume handler
when resuming with the stream already started.

Signed-off-by: Jurison Murati <eng.juri@gmail.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
This commit is contained in:
Jurison Murati 2026-06-10 12:22:37 +02:00 committed by Sakari Ailus
parent 3fe797a12b
commit 4e1446ac16

View File

@ -2609,7 +2609,7 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
{
struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
struct ov8865_state *state = &sensor->state;
int ret;
int ret = 0;
if (enable) {
ret = pm_runtime_resume_and_get(sensor->dev);
@ -2618,7 +2618,23 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
}
mutex_lock(&sensor->mutex);
ret = ov8865_sw_standby(sensor, !enable);
/*
* The sensor may have been kept powered by something else (e.g. the
* VCM's runtime PM device link on IPU3 platforms), in which case
* runtime resume did not run and the hardware may still be
* configured for a previous mode. Always program the negotiated
* configuration on stream start.
*/
if (enable) {
ret = ov8865_sensor_init(sensor);
if (!ret)
ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
}
if (!ret)
ret = ov8865_sw_standby(sensor, !enable);
mutex_unlock(&sensor->mutex);
if (ret || !enable)
@ -2914,15 +2930,15 @@ static int ov8865_resume(struct device *dev)
if (ret)
goto complete;
ret = ov8865_sensor_init(sensor);
if (ret)
goto error_power;
ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
if (ret)
goto error_power;
if (state->streaming) {
ret = ov8865_sensor_init(sensor);
if (ret)
goto error_power;
ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
if (ret)
goto error_power;
ret = ov8865_sw_standby(sensor, false);
if (ret)
goto error_power;