@@ -2,6 +2,7 @@
// Copyright (c) 2022 Intel Corporation.
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -602,41 +603,45 @@ static void ov02c10_stop_streaming(struct ov02c10 *ov02c10)
cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 0, NULL);
}
-static int ov02c10_set_stream(struct v4l2_subdev *sd, int enable)
+static int ov02c10_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
{
- struct ov02c10 *ov02c10 = to_ov02c10(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
+ struct ov02c10 *ov02c10 = to_ov02c10(sd);
+ int ret;
- if (ov02c10->streaming == enable)
- return 0;
+ guard(mutex)(&ov02c10->mutex);
- mutex_lock(&ov02c10->mutex);
- if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
- mutex_unlock(&ov02c10->mutex);
- return ret;
- }
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret)
+ return ret;
- ret = ov02c10_start_streaming(ov02c10);
- if (ret) {
- enable = 0;
- ov02c10_stop_streaming(ov02c10);
- pm_runtime_put(&client->dev);
- }
- } else {
- ov02c10_stop_streaming(ov02c10);
+ ret = ov02c10_start_streaming(ov02c10);
+ if (ret == 0)
+ ov02c10->streaming = true;
+ else
pm_runtime_put(&client->dev);
- }
-
- ov02c10->streaming = enable;
- mutex_unlock(&ov02c10->mutex);
return ret;
}
+static int ov02c10_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov02c10 *ov02c10 = to_ov02c10(sd);
+
+ guard(mutex)(&ov02c10->mutex);
+
+ ov02c10_stop_streaming(ov02c10);
+ ov02c10->streaming = false;
+ pm_runtime_put(&client->dev);
+
+ return 0;
+}
+
/* This function tries to get power control resources */
static int ov02c10_get_pm_resources(struct device *dev)
{
@@ -836,7 +841,7 @@ static int ov02c10_init_state(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops ov02c10_video_ops = {
- .s_stream = ov02c10_set_stream,
+ .s_stream = v4l2_subdev_s_stream_helper,
};
static const struct v4l2_subdev_pad_ops ov02c10_pad_ops = {
@@ -844,6 +849,8 @@ static const struct v4l2_subdev_pad_ops ov02c10_pad_ops = {
.get_fmt = ov02c10_get_format,
.enum_mbus_code = ov02c10_enum_mbus_code,
.enum_frame_size = ov02c10_enum_frame_size,
+ .enable_streams = ov02c10_enable_streams,
+ .disable_streams = ov02c10_disable_streams,
};
static const struct v4l2_subdev_ops ov02c10_subdev_ops = {
Switch from s_stream() to enable_streams() and disable_streams() pad operations. They are preferred and required for streams support. Note this also stops calling ov02c10_stop_streaming() on enable_streams() errors. If ov02c10_start_streaming() fails OV02C10_REG_STREAM_CONTROL bit 0 will have never been set so there is no need to clear it on errors. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- drivers/media/i2c/ov02c10.c | 59 +++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 26 deletions(-)