media: ov6650: Fix missing frame interval enumeration support
authorJanusz Krzysztofik <jmkrzyszt@gmail.com>
Mon, 4 May 2020 17:10:12 +0000 (19:10 +0200)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Fri, 28 Jan 2022 18:32:48 +0000 (19:32 +0100)
According to v4l2-compliance utility, a video device which supports
V4L2_CAP_TIMEPERFRAME via .vidioc_s_parm() operation should also
support .vidioc_enum_frameintervals().  If the former is implemented
via a call to v4l2_s_parm_cap() which in turn calls a subdevice
.s_frame_interval() pad operation, the video device may want to
implement the latter by passing frame interval enumeration requests to
the subdevice .enum_frame_intervals() video operation.  If that
operation is not supported by the subdevice and failure is returned by
the video device, the compliance test issues a warning.

Implement the missing pad operation.  Enumerate frame intervals
possible to be set via pixel clock adjustment, as implemented by
.s_frame_interval(), but not exceeding a reasonable maximum of 1
second.

[Sakari Ailus: Rebased on mbus config pad op patches]

Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/i2c/ov6650.c

index 9887f48..d9c1548 100644 (file)
@@ -764,6 +764,33 @@ static int ov6650_enum_mbus_code(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int ov6650_enum_frame_interval(struct v4l2_subdev *sd,
+                                   struct v4l2_subdev_state *sd_state,
+                                   struct v4l2_subdev_frame_interval_enum *fie)
+{
+       int i;
+
+       /* enumerate supported frame intervals not exceeding 1 second */
+       if (fie->index > CLKRC_DIV_MASK ||
+           GET_CLKRC_DIV(fie->index) > FRAME_RATE_MAX)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(ov6650_codes); i++)
+               if (fie->code == ov6650_codes[i])
+                       break;
+       if (i == ARRAY_SIZE(ov6650_codes))
+               return -EINVAL;
+
+       if (!fie->width || fie->width > W_CIF ||
+           !fie->height || fie->height > H_CIF)
+               return -EINVAL;
+
+       fie->interval.numerator = GET_CLKRC_DIV(fie->index);
+       fie->interval.denominator = FRAME_RATE_MAX;
+
+       return 0;
+}
+
 static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
                                   struct v4l2_subdev_frame_interval *ival)
 {
@@ -976,12 +1003,13 @@ static const struct v4l2_subdev_video_ops ov6650_video_ops = {
 };
 
 static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
-       .enum_mbus_code = ov6650_enum_mbus_code,
-       .get_selection  = ov6650_get_selection,
-       .set_selection  = ov6650_set_selection,
-       .get_fmt        = ov6650_get_fmt,
-       .set_fmt        = ov6650_set_fmt,
-       .get_mbus_config = ov6650_get_mbus_config,
+       .enum_mbus_code         = ov6650_enum_mbus_code,
+       .enum_frame_interval    = ov6650_enum_frame_interval,
+       .get_selection          = ov6650_get_selection,
+       .set_selection          = ov6650_set_selection,
+       .get_fmt                = ov6650_get_fmt,
+       .set_fmt                = ov6650_set_fmt,
+       .get_mbus_config        = ov6650_get_mbus_config,
 };
 
 static const struct v4l2_subdev_ops ov6650_subdev_ops = {