All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations
@ 2023-12-05 14:08 Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval Laurent Pinchart
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Akinobu Mita, Andrzej Hajda, Daniel Scally, Hans Verkuil,
	Hans de Goede, Jacopo Mondi, Jonathan Hunter, Kieran Bingham,
	Lars-Peter Clausen, Leon Luo, Luca Ceresoli,
	Mauro Carvalho Chehab, Niklas Söderlund, Paul Elder,
	Pavel Machek, Philipp Zabel, Ricardo Ribalda, Rui Miguel Silva,
	Sakari Ailus, Sowjanya Komatineni, Steve Longerbeam,
	Sylwester Nawrocki, Thierry Reding, Tomi Valkeinen, linux-tegra

The subdev .[gs]_frame_interval are video operations, but they operate
on pads (and even on streams). Not only is this confusing, it causes
practical issues for drivers as the operations don't receive a subdev
state pointer, requiring manual state handling.

To improve the situation, turn the operations into pad operations, and
extend them to receive a state pointer like other pad operations.

While at it, rename the operations to .[gs]et_frame_interval at the same
time to match the naming scheme of other pad operations. This isn't
strictly necessary, but given that all drivers using those operations
need to be modified, handling the rename separately would generate more
churn for very little gain (if at all).

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> # for imx-media
---
 drivers/media/i2c/adv7180.c                   |  7 ++-
 drivers/media/i2c/et8ek8/et8ek8_driver.c      |  6 +-
 drivers/media/i2c/imx214.c                    |  9 +--
 drivers/media/i2c/imx274.c                    | 48 +++++---------
 drivers/media/i2c/max9286.c                   | 14 +++--
 drivers/media/i2c/mt9m111.c                   | 14 +++--
 drivers/media/i2c/mt9m114.c                   | 14 +++--
 drivers/media/i2c/mt9v011.c                   | 18 +++---
 drivers/media/i2c/mt9v111.c                   | 16 ++---
 drivers/media/i2c/ov2680.c                    |  7 ++-
 drivers/media/i2c/ov5640.c                    | 16 ++---
 drivers/media/i2c/ov5648.c                    | 59 ++++++++---------
 drivers/media/i2c/ov5693.c                    |  7 ++-
 drivers/media/i2c/ov6650.c                    | 16 ++---
 drivers/media/i2c/ov7251.c                    |  6 +-
 drivers/media/i2c/ov7670.c                    | 18 +++---
 drivers/media/i2c/ov772x.c                    | 14 +++--
 drivers/media/i2c/ov7740.c                    | 40 +++++-------
 drivers/media/i2c/ov8865.c                    | 51 +++++++--------
 drivers/media/i2c/ov9650.c                    | 14 +++--
 drivers/media/i2c/s5c73m3/s5c73m3-core.c      | 14 +++--
 drivers/media/i2c/s5k5baf.c                   | 20 +++---
 drivers/media/i2c/tvp514x.c                   | 29 +++------
 drivers/media/usb/em28xx/em28xx-video.c       |  6 +-
 drivers/media/v4l2-core/v4l2-common.c         |  8 +--
 drivers/media/v4l2-core/v4l2-subdev.c         | 63 +++++++++++--------
 .../media/atomisp/i2c/atomisp-gc0310.c        |  7 ++-
 .../media/atomisp/i2c/atomisp-gc2235.c        |  7 ++-
 .../media/atomisp/i2c/atomisp-mt9m114.c       |  7 ++-
 .../media/atomisp/i2c/atomisp-ov2722.c        |  7 ++-
 .../staging/media/atomisp/pci/atomisp_cmd.c   |  4 +-
 .../staging/media/atomisp/pci/atomisp_ioctl.c |  4 +-
 drivers/staging/media/imx/imx-ic-prp.c        | 14 +++--
 drivers/staging/media/imx/imx-ic-prpencvf.c   | 14 +++--
 drivers/staging/media/imx/imx-media-capture.c |  6 +-
 drivers/staging/media/imx/imx-media-csi.c     | 14 +++--
 drivers/staging/media/imx/imx-media-vdic.c    | 14 +++--
 drivers/staging/media/tegra-video/csi.c       |  9 +--
 include/media/v4l2-common.h                   |  4 +-
 include/media/v4l2-subdev.h                   | 22 ++++---
 40 files changed, 340 insertions(+), 327 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index e10811cce801..7ed86030fb5c 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -463,8 +463,9 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
 	return 0;
 }
 
-static int adv7180_g_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *fi)
+static int adv7180_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *fi)
 {
 	struct adv7180_state *state = to_state(sd);
 
@@ -913,7 +914,6 @@ static int adv7180_subscribe_event(struct v4l2_subdev *sd,
 static const struct v4l2_subdev_video_ops adv7180_video_ops = {
 	.s_std = adv7180_s_std,
 	.g_std = adv7180_g_std,
-	.g_frame_interval = adv7180_g_frame_interval,
 	.querystd = adv7180_querystd,
 	.g_input_status = adv7180_g_input_status,
 	.s_routing = adv7180_s_routing,
@@ -932,6 +932,7 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
 	.enum_mbus_code = adv7180_enum_mbus_code,
 	.set_fmt = adv7180_set_pad_format,
 	.get_fmt = adv7180_get_pad_format,
+	.get_frame_interval = adv7180_get_frame_interval,
 	.get_mbus_config = adv7180_get_mbus_config,
 };
 
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
index 63616dc5a02f..71fb5aebd3df 100644
--- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
+++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
@@ -1046,6 +1046,7 @@ static int et8ek8_set_pad_format(struct v4l2_subdev *subdev,
 }
 
 static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
@@ -1057,6 +1058,7 @@ static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
 }
 
 static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
@@ -1342,8 +1344,6 @@ static int et8ek8_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
 static const struct v4l2_subdev_video_ops et8ek8_video_ops = {
 	.s_stream = et8ek8_s_stream,
-	.g_frame_interval = et8ek8_get_frame_interval,
-	.s_frame_interval = et8ek8_set_frame_interval,
 };
 
 static const struct v4l2_subdev_core_ops et8ek8_core_ops = {
@@ -1356,6 +1356,8 @@ static const struct v4l2_subdev_pad_ops et8ek8_pad_ops = {
 	.enum_frame_interval = et8ek8_enum_frame_ival,
 	.get_fmt = et8ek8_get_pad_format,
 	.set_fmt = et8ek8_set_pad_format,
+	.get_frame_interval = et8ek8_get_frame_interval,
+	.set_frame_interval = et8ek8_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops et8ek8_ops = {
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 474c95572bf6..624efc8834f3 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -795,8 +795,9 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
 	return ret;
 }
 
-static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
-				   struct v4l2_subdev_frame_interval *fival)
+static int imx214_get_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fival)
 {
 	fival->interval.numerator = 1;
 	fival->interval.denominator = IMX214_FPS;
@@ -828,8 +829,6 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
 
 static const struct v4l2_subdev_video_ops imx214_video_ops = {
 	.s_stream = imx214_s_stream,
-	.g_frame_interval = imx214_g_frame_interval,
-	.s_frame_interval = imx214_g_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
@@ -839,6 +838,8 @@ static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
 	.get_fmt = imx214_get_format,
 	.set_fmt = imx214_set_format,
 	.get_selection = imx214_get_selection,
+	.get_frame_interval = imx214_get_frame_interval,
+	.set_frame_interval = imx214_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops imx214_subdev_ops = {
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index 8dc11c9ec1ee..4040c642a36f 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -594,8 +594,8 @@ static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl);
 static int imx274_set_exposure(struct stimx274 *priv, int val);
 static int imx274_set_vflip(struct stimx274 *priv, int val);
 static int imx274_set_test_pattern(struct stimx274 *priv, int val);
-static int imx274_set_frame_interval(struct stimx274 *priv,
-				     struct v4l2_fract frame_interval);
+static int __imx274_set_frame_interval(struct stimx274 *priv,
+				       struct v4l2_fract frame_interval);
 
 static inline void msleep_range(unsigned int delay_base)
 {
@@ -1327,17 +1327,9 @@ static int imx274_apply_trimming(struct stimx274 *imx274)
 	return err;
 }
 
-/**
- * imx274_g_frame_interval - Get the frame interval
- * @sd: Pointer to V4L2 Sub device structure
- * @fi: Pointer to V4l2 Sub device frame interval structure
- *
- * This function is used to get the frame interval.
- *
- * Return: 0 on success
- */
-static int imx274_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int imx274_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct stimx274 *imx274 = to_imx274(sd);
 
@@ -1349,17 +1341,9 @@ static int imx274_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-/**
- * imx274_s_frame_interval - Set the frame interval
- * @sd: Pointer to V4L2 Sub device structure
- * @fi: Pointer to V4l2 Sub device frame interval structure
- *
- * This function is used to set the frame intervavl.
- *
- * Return: 0 on success
- */
-static int imx274_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int imx274_set_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct stimx274 *imx274 = to_imx274(sd);
 	struct v4l2_ctrl *ctrl = imx274->ctrls.exposure;
@@ -1371,7 +1355,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd,
 		return ret;
 
 	mutex_lock(&imx274->lock);
-	ret = imx274_set_frame_interval(imx274, fi->interval);
+	ret = __imx274_set_frame_interval(imx274, fi->interval);
 
 	if (!ret) {
 		fi->interval = imx274->frame_interval;
@@ -1466,8 +1450,8 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
 		 * are changed.
 		 * gain is not affected.
 		 */
-		ret = imx274_set_frame_interval(imx274,
-						imx274->frame_interval);
+		ret = __imx274_set_frame_interval(imx274,
+						  imx274->frame_interval);
 		if (ret)
 			goto fail;
 
@@ -1830,7 +1814,7 @@ static int imx274_set_frame_length(struct stimx274 *priv, u32 val)
 }
 
 /*
- * imx274_set_frame_interval - Function called when setting frame interval
+ * __imx274_set_frame_interval - Function called when setting frame interval
  * @priv: Pointer to device structure
  * @frame_interval: Variable for frame interval
  *
@@ -1839,8 +1823,8 @@ static int imx274_set_frame_length(struct stimx274 *priv, u32 val)
  *
  * Return: 0 on success
  */
-static int imx274_set_frame_interval(struct stimx274 *priv,
-				     struct v4l2_fract frame_interval)
+static int __imx274_set_frame_interval(struct stimx274 *priv,
+				       struct v4l2_fract frame_interval)
 {
 	int err;
 	u32 frame_length, req_frame_rate;
@@ -1927,11 +1911,11 @@ static const struct v4l2_subdev_pad_ops imx274_pad_ops = {
 	.set_fmt = imx274_set_fmt,
 	.get_selection = imx274_get_selection,
 	.set_selection = imx274_set_selection,
+	.get_frame_interval = imx274_get_frame_interval,
+	.set_frame_interval = imx274_set_frame_interval,
 };
 
 static const struct v4l2_subdev_video_ops imx274_video_ops = {
-	.g_frame_interval = imx274_g_frame_interval,
-	.s_frame_interval = imx274_s_frame_interval,
 	.s_stream = imx274_s_stream,
 };
 
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index ee11ae682d8d..7e8cb53d31c3 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -868,8 +868,9 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
 	return 0;
 }
 
-static int max9286_g_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *interval)
+static int max9286_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *interval)
 {
 	struct max9286_priv *priv = sd_to_max9286(sd);
 
@@ -881,8 +882,9 @@ static int max9286_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int max9286_s_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *interval)
+static int max9286_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *interval)
 {
 	struct max9286_priv *priv = sd_to_max9286(sd);
 
@@ -983,14 +985,14 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_video_ops max9286_video_ops = {
 	.s_stream	= max9286_s_stream,
-	.g_frame_interval = max9286_g_frame_interval,
-	.s_frame_interval = max9286_s_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
 	.enum_mbus_code = max9286_enum_mbus_code,
 	.get_fmt	= max9286_get_fmt,
 	.set_fmt	= max9286_set_fmt,
+	.get_frame_interval = max9286_get_frame_interval,
+	.set_frame_interval = max9286_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops max9286_subdev_ops = {
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 54a7a4c623ea..602954650f2e 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -1045,8 +1045,9 @@ static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
 #endif
 };
 
-static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int mt9m111_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *fi)
 {
 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
@@ -1055,8 +1056,9 @@ static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int mt9m111_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *fi)
 {
 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 	const struct mt9m111_mode_info *mode;
@@ -1151,8 +1153,6 @@ static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
 	.s_stream	= mt9m111_s_stream,
-	.g_frame_interval = mt9m111_g_frame_interval,
-	.s_frame_interval = mt9m111_s_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
@@ -1161,6 +1161,8 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
 	.set_selection	= mt9m111_set_selection,
 	.get_fmt	= mt9m111_get_fmt,
 	.set_fmt	= mt9m111_set_fmt,
+	.get_frame_interval = mt9m111_get_frame_interval,
+	.set_frame_interval = mt9m111_set_frame_interval,
 	.get_mbus_config = mt9m111_get_mbus_config,
 };
 
diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c
index 0a22f328981d..dcd94299787c 100644
--- a/drivers/media/i2c/mt9m114.c
+++ b/drivers/media/i2c/mt9m114.c
@@ -1585,8 +1585,9 @@ static int mt9m114_ifp_s_stream(struct v4l2_subdev *sd, int enable)
 	return ret;
 }
 
-static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd,
-					struct v4l2_subdev_frame_interval *interval)
+static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_subdev_frame_interval *interval)
 {
 	struct v4l2_fract *ival = &interval->interval;
 	struct mt9m114 *sensor = ifp_to_mt9m114(sd);
@@ -1601,8 +1602,9 @@ static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd,
-					struct v4l2_subdev_frame_interval *interval)
+static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_subdev_frame_interval *interval)
 {
 	struct v4l2_fract *ival = &interval->interval;
 	struct mt9m114 *sensor = ifp_to_mt9m114(sd);
@@ -1967,8 +1969,6 @@ static int mt9m114_ifp_registered(struct v4l2_subdev *sd)
 
 static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = {
 	.s_stream = mt9m114_ifp_s_stream,
-	.g_frame_interval = mt9m114_ifp_g_frame_interval,
-	.s_frame_interval = mt9m114_ifp_s_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = {
@@ -1979,6 +1979,8 @@ static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = {
 	.set_fmt = mt9m114_ifp_set_fmt,
 	.get_selection = mt9m114_ifp_get_selection,
 	.set_selection = mt9m114_ifp_set_selection,
+	.get_frame_interval = mt9m114_ifp_get_frame_interval,
+	.set_frame_interval = mt9m114_ifp_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops mt9m114_ifp_ops = {
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index d0924b4ac6fb..3485761428ba 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -362,8 +362,9 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *ival)
+static int mt9v011_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *ival)
 {
 	calc_fps(sd,
 		 &ival->interval.numerator,
@@ -372,8 +373,9 @@ static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int mt9v011_s_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *ival)
+static int mt9v011_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *ival)
 {
 	struct v4l2_fract *tpf = &ival->interval;
 	u16 speed;
@@ -455,19 +457,15 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
 #endif
 };
 
-static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
-	.g_frame_interval = mt9v011_g_frame_interval,
-	.s_frame_interval = mt9v011_s_frame_interval,
-};
-
 static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = {
 	.enum_mbus_code = mt9v011_enum_mbus_code,
 	.set_fmt = mt9v011_set_fmt,
+	.get_frame_interval = mt9v011_get_frame_interval,
+	.set_frame_interval = mt9v011_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops mt9v011_ops = {
 	.core  = &mt9v011_core_ops,
-	.video = &mt9v011_video_ops,
 	.pad   = &mt9v011_pad_ops,
 };
 
diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c
index b186e9160d94..496be67c971b 100644
--- a/drivers/media/i2c/mt9v111.c
+++ b/drivers/media/i2c/mt9v111.c
@@ -35,7 +35,7 @@
  * The IFP can produce several output image formats from the sensor core
  * output. This driver currently supports only YUYV format permutations.
  *
- * The driver allows manual frame rate control through s_frame_interval subdev
+ * The driver allows manual frame rate control through set_frame_interval subdev
  * operation or V4L2_CID_V/HBLANK controls, but it is known that the
  * auto-exposure algorithm might modify the programmed frame rate. While the
  * driver initially programs the sensor with auto-exposure and
@@ -719,8 +719,9 @@ static int mt9v111_s_stream(struct v4l2_subdev *subdev, int enable)
 	return ret;
 }
 
-static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *ival)
+static int mt9v111_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *ival)
 {
 	struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
 	struct v4l2_fract *tpf = &ival->interval;
@@ -771,8 +772,9 @@ static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int mt9v111_g_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *ival)
+static int mt9v111_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *ival)
 {
 	struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
 	struct v4l2_fract *tpf = &ival->interval;
@@ -962,8 +964,6 @@ static const struct v4l2_subdev_core_ops mt9v111_core_ops = {
 
 static const struct v4l2_subdev_video_ops mt9v111_video_ops = {
 	.s_stream		= mt9v111_s_stream,
-	.s_frame_interval	= mt9v111_s_frame_interval,
-	.g_frame_interval	= mt9v111_g_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops mt9v111_pad_ops = {
@@ -972,6 +972,8 @@ static const struct v4l2_subdev_pad_ops mt9v111_pad_ops = {
 	.enum_frame_interval	= mt9v111_enum_frame_interval,
 	.get_fmt		= mt9v111_get_format,
 	.set_fmt		= mt9v111_set_format,
+	.get_frame_interval	= mt9v111_get_frame_interval,
+	.set_frame_interval	= mt9v111_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops mt9v111_ops = {
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index d34d1972dcd9..e3ff64a9e6ca 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -552,7 +552,8 @@ static int ov2680_power_on(struct ov2680_dev *sensor)
 	return ret;
 }
 
-static int ov2680_s_g_frame_interval(struct v4l2_subdev *sd,
+static int ov2680_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -870,8 +871,6 @@ static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_video_ops ov2680_video_ops = {
-	.g_frame_interval	= ov2680_s_g_frame_interval,
-	.s_frame_interval	= ov2680_s_g_frame_interval,
 	.s_stream		= ov2680_s_stream,
 };
 
@@ -883,6 +882,8 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
 	.set_fmt		= ov2680_set_fmt,
 	.get_selection		= ov2680_get_selection,
 	.set_selection		= ov2680_set_selection,
+	.get_frame_interval	= ov2680_get_frame_interval,
+	.set_frame_interval	= ov2680_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov2680_subdev_ops = {
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 6fd98b8cb181..336bfd1ffd32 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -399,7 +399,7 @@ struct ov5640_mode_info {
 	const struct reg_value *reg_data;
 	u32 reg_data_size;
 
-	/* Used by s_frame_interval only. */
+	/* Used by set_frame_interval only. */
 	u32 max_fps;
 	u32 def_fps;
 };
@@ -3604,8 +3604,9 @@ static int ov5640_enum_frame_interval(
 	return 0;
 }
 
-static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int ov5640_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
 
@@ -3616,8 +3617,9 @@ static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int ov5640_set_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
 	const struct ov5640_mode_info *mode;
@@ -3770,8 +3772,6 @@ static const struct v4l2_subdev_core_ops ov5640_core_ops = {
 };
 
 static const struct v4l2_subdev_video_ops ov5640_video_ops = {
-	.g_frame_interval = ov5640_g_frame_interval,
-	.s_frame_interval = ov5640_s_frame_interval,
 	.s_stream = ov5640_s_stream,
 };
 
@@ -3780,6 +3780,8 @@ static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
 	.get_fmt = ov5640_get_fmt,
 	.set_fmt = ov5640_set_fmt,
 	.get_selection = ov5640_get_selection,
+	.get_frame_interval = ov5640_get_frame_interval,
+	.set_frame_interval = ov5640_set_frame_interval,
 	.enum_frame_size = ov5640_enum_frame_size,
 	.enum_frame_interval = ov5640_enum_frame_interval,
 };
diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c
index 13e6060d15d4..d0d7e9968f48 100644
--- a/drivers/media/i2c/ov5648.c
+++ b/drivers/media/i2c/ov5648.c
@@ -2158,37 +2158,8 @@ static int ov5648_s_stream(struct v4l2_subdev *subdev, int enable)
 	return 0;
 }
 
-static int ov5648_g_frame_interval(struct v4l2_subdev *subdev,
-				   struct v4l2_subdev_frame_interval *interval)
-{
-	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
-	const struct ov5648_mode *mode;
-	int ret = 0;
-
-	mutex_lock(&sensor->mutex);
-
-	mode = sensor->state.mode;
-
-	switch (sensor->state.mbus_code) {
-	case MEDIA_BUS_FMT_SBGGR8_1X8:
-		interval->interval = mode->frame_interval[0];
-		break;
-	case MEDIA_BUS_FMT_SBGGR10_1X10:
-		interval->interval = mode->frame_interval[1];
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	mutex_unlock(&sensor->mutex);
-
-	return ret;
-}
-
 static const struct v4l2_subdev_video_ops ov5648_subdev_video_ops = {
 	.s_stream		= ov5648_s_stream,
-	.g_frame_interval	= ov5648_g_frame_interval,
-	.s_frame_interval	= ov5648_g_frame_interval,
 };
 
 /* Subdev Pad Operations */
@@ -2297,6 +2268,34 @@ static int ov5648_set_fmt(struct v4l2_subdev *subdev,
 	return ret;
 }
 
+static int ov5648_get_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *interval)
+{
+	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
+	const struct ov5648_mode *mode;
+	int ret = 0;
+
+	mutex_lock(&sensor->mutex);
+
+	mode = sensor->state.mode;
+
+	switch (sensor->state.mbus_code) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+		interval->interval = mode->frame_interval[0];
+		break;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+		interval->interval = mode->frame_interval[1];
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&sensor->mutex);
+
+	return ret;
+}
+
 static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
 				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_subdev_frame_size_enum *size_enum)
@@ -2363,6 +2362,8 @@ static const struct v4l2_subdev_pad_ops ov5648_subdev_pad_ops = {
 	.enum_mbus_code		= ov5648_enum_mbus_code,
 	.get_fmt		= ov5648_get_fmt,
 	.set_fmt		= ov5648_set_fmt,
+	.get_frame_interval	= ov5648_get_frame_interval,
+	.set_frame_interval	= ov5648_get_frame_interval,
 	.enum_frame_size	= ov5648_enum_frame_size,
 	.enum_frame_interval	= ov5648_enum_frame_interval,
 };
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 205193baa06e..a65645811fbc 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1004,8 +1004,9 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
 	return ret;
 }
 
-static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *interval)
+static int ov5693_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *interval)
 {
 	struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
 	unsigned int framesize = OV5693_FIXED_PPL * (ov5693->mode.format.height +
@@ -1054,7 +1055,6 @@ static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_video_ops ov5693_video_ops = {
 	.s_stream = ov5693_s_stream,
-	.g_frame_interval = ov5693_g_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
@@ -1064,6 +1064,7 @@ static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
 	.set_fmt = ov5693_set_fmt,
 	.get_selection = ov5693_get_selection,
 	.set_selection = ov5693_set_selection,
+	.get_frame_interval = ov5693_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov5693_ops = {
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index bf1e7617ee08..a4dc45bdf3d7 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -197,7 +197,7 @@ struct ov6650 {
 	struct clk		*clk;
 	bool			half_scale;	/* scale down output by 2 */
 	struct v4l2_rect	rect;		/* sensor cropping window */
-	struct v4l2_fract	tpf;		/* as requested with s_frame_interval */
+	struct v4l2_fract	tpf;		/* as requested with set_frame_interval */
 	u32 code;
 };
 
@@ -799,8 +799,9 @@ static int ov6650_enum_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
+static int ov6650_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov6650 *priv = to_ov6650(client);
@@ -813,8 +814,9 @@ static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
+static int ov6650_set_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov6650 *priv = to_ov6650(client);
@@ -1006,8 +1008,6 @@ static int ov6650_get_mbus_config(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_video_ops ov6650_video_ops = {
 	.s_stream	= ov6650_s_stream,
-	.g_frame_interval = ov6650_g_frame_interval,
-	.s_frame_interval = ov6650_s_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
@@ -1017,6 +1017,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
 	.set_selection		= ov6650_set_selection,
 	.get_fmt		= ov6650_get_fmt,
 	.set_fmt		= ov6650_set_fmt,
+	.get_frame_interval	= ov6650_get_frame_interval,
+	.set_frame_interval	= ov6650_set_frame_interval,
 	.get_mbus_config	= ov6650_get_mbus_config,
 };
 
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index 897a0763df4a..10d6b5deed83 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -1386,6 +1386,7 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable)
 }
 
 static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov7251 *ov7251 = to_ov7251(subdev);
@@ -1398,6 +1399,7 @@ static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
 }
 
 static int ov7251_set_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov7251 *ov7251 = to_ov7251(subdev);
@@ -1436,8 +1438,6 @@ static int ov7251_set_frame_interval(struct v4l2_subdev *subdev,
 
 static const struct v4l2_subdev_video_ops ov7251_video_ops = {
 	.s_stream = ov7251_s_stream,
-	.g_frame_interval = ov7251_get_frame_interval,
-	.s_frame_interval = ov7251_set_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = {
@@ -1447,6 +1447,8 @@ static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = {
 	.get_fmt = ov7251_get_format,
 	.set_fmt = ov7251_set_format,
 	.get_selection = ov7251_get_selection,
+	.get_frame_interval = ov7251_get_frame_interval,
+	.set_frame_interval = ov7251_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov7251_subdev_ops = {
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 8164c0c433c5..463f20ece36e 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1154,8 +1154,9 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
  * Implement G/S_PARM.  There is a "high quality" mode we could try
  * to do someday; for now, we just do the frame rate tweak.
  */
-static int ov7670_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
+static int ov7670_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
 {
 	struct ov7670_info *info = to_state(sd);
 
@@ -1165,8 +1166,9 @@ static int ov7670_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov7670_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
+static int ov7670_set_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
 {
 	struct v4l2_fract *tpf = &ival->interval;
 	struct ov7670_info *info = to_state(sd);
@@ -1728,22 +1730,18 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
 #endif
 };
 
-static const struct v4l2_subdev_video_ops ov7670_video_ops = {
-	.s_frame_interval = ov7670_s_frame_interval,
-	.g_frame_interval = ov7670_g_frame_interval,
-};
-
 static const struct v4l2_subdev_pad_ops ov7670_pad_ops = {
 	.enum_frame_interval = ov7670_enum_frame_interval,
 	.enum_frame_size = ov7670_enum_frame_size,
 	.enum_mbus_code = ov7670_enum_mbus_code,
 	.get_fmt = ov7670_get_fmt,
 	.set_fmt = ov7670_set_fmt,
+	.get_frame_interval = ov7670_get_frame_interval,
+	.set_frame_interval = ov7670_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov7670_ops = {
 	.core = &ov7670_core_ops,
-	.video = &ov7670_video_ops,
 	.pad = &ov7670_pad_ops,
 };
 
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index e397f7531e1d..a14a25946c5b 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -717,8 +717,9 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
 	return 0;
 }
 
-static int ov772x_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
+static int ov772x_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
 {
 	struct ov772x_priv *priv = to_ov772x(sd);
 	struct v4l2_fract *tpf = &ival->interval;
@@ -729,8 +730,9 @@ static int ov772x_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov772x_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
+static int ov772x_set_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
 {
 	struct ov772x_priv *priv = to_ov772x(sd);
 	struct v4l2_fract *tpf = &ival->interval;
@@ -1349,8 +1351,6 @@ static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
 	.s_stream		= ov772x_s_stream,
-	.s_frame_interval	= ov772x_s_frame_interval,
-	.g_frame_interval	= ov772x_g_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
@@ -1359,6 +1359,8 @@ static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
 	.get_selection		= ov772x_get_selection,
 	.get_fmt		= ov772x_get_fmt,
 	.set_fmt		= ov772x_set_fmt,
+	.get_frame_interval	= ov772x_get_frame_interval,
+	.set_frame_interval	= ov772x_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov772x_subdev_ops = {
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 9c13ff5fe9fa..47b1b14d8796 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -638,34 +638,8 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
 	return ret;
 }
 
-static int ov7740_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
-{
-	struct v4l2_fract *tpf = &ival->interval;
-
-
-	tpf->numerator = 1;
-	tpf->denominator = 60;
-
-	return 0;
-}
-
-static int ov7740_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *ival)
-{
-	struct v4l2_fract *tpf = &ival->interval;
-
-
-	tpf->numerator = 1;
-	tpf->denominator = 60;
-
-	return 0;
-}
-
 static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
 	.s_stream = ov7740_set_stream,
-	.s_frame_interval = ov7740_s_frame_interval,
-	.g_frame_interval = ov7740_g_frame_interval,
 };
 
 static const struct reg_sequence ov7740_format_yuyv[] = {
@@ -852,12 +826,26 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static int ov7740_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *ival)
+{
+	struct v4l2_fract *tpf = &ival->interval;
+
+	tpf->numerator = 1;
+	tpf->denominator = 60;
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
 	.enum_frame_interval = ov7740_enum_frame_interval,
 	.enum_frame_size = ov7740_enum_frame_size,
 	.enum_mbus_code = ov7740_enum_mbus_code,
 	.get_fmt = ov7740_get_fmt,
 	.set_fmt = ov7740_set_fmt,
+	.get_frame_interval = ov7740_get_frame_interval,
+	.set_frame_interval = ov7740_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov7740_subdev_ops = {
diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c
index fb19ab0c2a9d..02a595281c49 100644
--- a/drivers/media/i2c/ov8865.c
+++ b/drivers/media/i2c/ov8865.c
@@ -2640,33 +2640,8 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
 	return 0;
 }
 
-static int ov8865_g_frame_interval(struct v4l2_subdev *subdev,
-				   struct v4l2_subdev_frame_interval *interval)
-{
-	struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
-	const struct ov8865_mode *mode;
-	unsigned int framesize;
-	unsigned int fps;
-
-	mutex_lock(&sensor->mutex);
-
-	mode = sensor->state.mode;
-	framesize = mode->hts * (mode->output_size_y +
-				 sensor->ctrls.vblank->val);
-	fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize);
-
-	interval->interval.numerator = 1;
-	interval->interval.denominator = fps;
-
-	mutex_unlock(&sensor->mutex);
-
-	return 0;
-}
-
 static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = {
 	.s_stream		= ov8865_s_stream,
-	.g_frame_interval	= ov8865_g_frame_interval,
-	.s_frame_interval	= ov8865_g_frame_interval,
 };
 
 /* Subdev Pad Operations */
@@ -2862,6 +2837,30 @@ static int ov8865_get_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
+static int ov8865_get_frame_interval(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *interval)
+{
+	struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
+	const struct ov8865_mode *mode;
+	unsigned int framesize;
+	unsigned int fps;
+
+	mutex_lock(&sensor->mutex);
+
+	mode = sensor->state.mode;
+	framesize = mode->hts * (mode->output_size_y +
+				 sensor->ctrls.vblank->val);
+	fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize);
+
+	interval->interval.numerator = 1;
+	interval->interval.denominator = fps;
+
+	mutex_unlock(&sensor->mutex);
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = {
 	.enum_mbus_code		= ov8865_enum_mbus_code,
 	.get_fmt		= ov8865_get_fmt,
@@ -2869,6 +2868,8 @@ static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = {
 	.enum_frame_size	= ov8865_enum_frame_size,
 	.get_selection		= ov8865_get_selection,
 	.set_selection		= ov8865_get_selection,
+	.get_frame_interval	= ov8865_get_frame_interval,
+	.set_frame_interval	= ov8865_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov8865_subdev_ops = {
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 753f6222102a..f528892c893f 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1101,8 +1101,9 @@ static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov965x_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int ov965x_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov965x *ov965x = to_ov965x(sd);
 
@@ -1148,8 +1149,9 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x,
 	return 0;
 }
 
-static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int ov965x_set_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *fi)
 {
 	struct ov965x *ov965x = to_ov965x(sd);
 	int ret;
@@ -1373,12 +1375,12 @@ static const struct v4l2_subdev_pad_ops ov965x_pad_ops = {
 	.enum_frame_size = ov965x_enum_frame_sizes,
 	.get_fmt = ov965x_get_fmt,
 	.set_fmt = ov965x_set_fmt,
+	.get_frame_interval = ov965x_get_frame_interval,
+	.set_frame_interval = ov965x_set_frame_interval,
 };
 
 static const struct v4l2_subdev_video_ops ov965x_video_ops = {
 	.s_stream = ov965x_s_stream,
-	.g_frame_interval = ov965x_g_frame_interval,
-	.s_frame_interval = ov965x_s_frame_interval,
 
 };
 
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 8f9b5713daf7..73ca50f49812 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -866,8 +866,9 @@ static void s5c73m3_try_format(struct s5c73m3 *state,
 	s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code);
 }
 
-static int s5c73m3_oif_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int s5c73m3_oif_get_frame_interval(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_subdev_frame_interval *fi)
 {
 	struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
 
@@ -915,8 +916,9 @@ static int __s5c73m3_set_frame_interval(struct s5c73m3 *state,
 	return 0;
 }
 
-static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int s5c73m3_oif_set_frame_interval(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_subdev_frame_interval *fi)
 {
 	struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
 	int ret;
@@ -1497,6 +1499,8 @@ static const struct v4l2_subdev_pad_ops s5c73m3_oif_pad_ops = {
 	.enum_frame_interval	= s5c73m3_oif_enum_frame_interval,
 	.get_fmt		= s5c73m3_oif_get_fmt,
 	.set_fmt		= s5c73m3_oif_set_fmt,
+	.get_frame_interval	= s5c73m3_oif_get_frame_interval,
+	.set_frame_interval	= s5c73m3_oif_set_frame_interval,
 	.get_frame_desc		= s5c73m3_oif_get_frame_desc,
 	.set_frame_desc		= s5c73m3_oif_set_frame_desc,
 };
@@ -1508,8 +1512,6 @@ static const struct v4l2_subdev_core_ops s5c73m3_oif_core_ops = {
 
 static const struct v4l2_subdev_video_ops s5c73m3_oif_video_ops = {
 	.s_stream		= s5c73m3_oif_s_stream,
-	.g_frame_interval	= s5c73m3_oif_g_frame_interval,
-	.s_frame_interval	= s5c73m3_oif_s_frame_interval,
 };
 
 static const struct v4l2_subdev_ops oif_subdev_ops = {
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 03ccfb0e1e11..2fd1ecfeb086 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -1118,8 +1118,9 @@ static int s5k5baf_s_stream(struct v4l2_subdev *sd, int on)
 	return ret;
 }
 
-static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int s5k5baf_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *fi)
 {
 	struct s5k5baf *state = to_s5k5baf(sd);
 
@@ -1131,8 +1132,8 @@ static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static void s5k5baf_set_frame_interval(struct s5k5baf *state,
-				       struct v4l2_subdev_frame_interval *fi)
+static void __s5k5baf_set_frame_interval(struct s5k5baf *state,
+					 struct v4l2_subdev_frame_interval *fi)
 {
 	struct v4l2_fract *i = &fi->interval;
 
@@ -1155,13 +1156,14 @@ static void s5k5baf_set_frame_interval(struct s5k5baf *state,
 			  state->fiv);
 }
 
-static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *fi)
+static int s5k5baf_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *fi)
 {
 	struct s5k5baf *state = to_s5k5baf(sd);
 
 	mutex_lock(&state->lock);
-	s5k5baf_set_frame_interval(state, fi);
+	__s5k5baf_set_frame_interval(state, fi);
 	mutex_unlock(&state->lock);
 	return 0;
 }
@@ -1526,11 +1528,11 @@ static const struct v4l2_subdev_pad_ops s5k5baf_pad_ops = {
 	.set_fmt		= s5k5baf_set_fmt,
 	.get_selection		= s5k5baf_get_selection,
 	.set_selection		= s5k5baf_set_selection,
+	.get_frame_interval	= s5k5baf_get_frame_interval,
+	.set_frame_interval	= s5k5baf_set_frame_interval,
 };
 
 static const struct v4l2_subdev_video_ops s5k5baf_video_ops = {
-	.g_frame_interval	= s5k5baf_g_frame_interval,
-	.s_frame_interval	= s5k5baf_s_frame_interval,
 	.s_stream		= s5k5baf_s_stream,
 };
 
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index c37f605cb75f..dee0cf992379 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -738,16 +738,10 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
 	return err;
 }
 
-/**
- * tvp514x_g_frame_interval() - V4L2 decoder interface handler
- * @sd: pointer to standard V4L2 sub-device structure
- * @ival: pointer to a v4l2_subdev_frame_interval structure
- *
- * Returns the decoder's video CAPTURE parameters.
- */
 static int
-tvp514x_g_frame_interval(struct v4l2_subdev *sd,
-			 struct v4l2_subdev_frame_interval *ival)
+tvp514x_get_frame_interval(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_state *sd_state,
+			   struct v4l2_subdev_frame_interval *ival)
 {
 	struct tvp514x_decoder *decoder = to_decoder(sd);
 	enum tvp514x_std current_std;
@@ -762,17 +756,10 @@ tvp514x_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-/**
- * tvp514x_s_frame_interval() - V4L2 decoder interface handler
- * @sd: pointer to standard V4L2 sub-device structure
- * @ival: pointer to a v4l2_subdev_frame_interval structure
- *
- * Configures the decoder to use the input parameters, if possible. If
- * not possible, returns the appropriate error code.
- */
 static int
-tvp514x_s_frame_interval(struct v4l2_subdev *sd,
-			 struct v4l2_subdev_frame_interval *ival)
+tvp514x_set_frame_interval(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_state *sd_state,
+			   struct v4l2_subdev_frame_interval *ival)
 {
 	struct tvp514x_decoder *decoder = to_decoder(sd);
 	struct v4l2_fract *timeperframe;
@@ -940,8 +927,6 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
 	.s_std = tvp514x_s_std,
 	.s_routing = tvp514x_s_routing,
 	.querystd = tvp514x_querystd,
-	.g_frame_interval = tvp514x_g_frame_interval,
-	.s_frame_interval = tvp514x_s_frame_interval,
 	.s_stream = tvp514x_s_stream,
 };
 
@@ -949,6 +934,8 @@ static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = {
 	.enum_mbus_code = tvp514x_enum_mbus_code,
 	.get_fmt = tvp514x_get_pad_format,
 	.set_fmt = tvp514x_set_pad_format,
+	.get_frame_interval = tvp514x_get_frame_interval,
+	.set_frame_interval = tvp514x_set_frame_interval,
 };
 
 static const struct v4l2_subdev_ops tvp514x_ops = {
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 25e0620deff1..4aef584e21da 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1607,7 +1607,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
 	p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
 	if (dev->is_webcam) {
 		rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
-						video, g_frame_interval, &ival);
+						pad, get_frame_interval, NULL,
+						&ival);
 		if (!rc)
 			p->parm.capture.timeperframe = ival.interval;
 	} else {
@@ -1639,7 +1640,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
 	p->parm.capture.readbuffers = EM28XX_MIN_BUF;
 	p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
 	rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0,
-					video, s_frame_interval, &ival);
+					pad, set_frame_interval, NULL,
+					&ival);
 	if (!rc)
 		p->parm.capture.timeperframe = ival.interval;
 	return rc;
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index e9e7e70fa24e..273d83de2a87 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -195,9 +195,9 @@ int v4l2_g_parm_cap(struct video_device *vdev,
 
 	if (vdev->device_caps & V4L2_CAP_READWRITE)
 		a->parm.capture.readbuffers = 2;
-	if (v4l2_subdev_has_op(sd, video, g_frame_interval))
+	if (v4l2_subdev_has_op(sd, pad, get_frame_interval))
 		a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-	ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
+	ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
 	if (!ret)
 		a->parm.capture.timeperframe = ival.interval;
 	return ret;
@@ -222,9 +222,9 @@ int v4l2_s_parm_cap(struct video_device *vdev,
 	else
 		a->parm.capture.readbuffers = 0;
 
-	if (v4l2_subdev_has_op(sd, video, g_frame_interval))
+	if (v4l2_subdev_has_op(sd, pad, get_frame_interval))
 		a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-	ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
+	ret = v4l2_subdev_call_state_active(sd, pad, set_frame_interval, &ival);
 	if (!ret)
 		a->parm.capture.timeperframe = ival.interval;
 	return ret;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 4fbefe4cd714..08c908988f7d 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -245,29 +245,6 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
 	       sd->ops->pad->enum_frame_size(sd, state, fse);
 }
 
-static inline int check_frame_interval(struct v4l2_subdev *sd,
-				       struct v4l2_subdev_frame_interval *fi)
-{
-	if (!fi)
-		return -EINVAL;
-
-	return check_pad(sd, fi->pad);
-}
-
-static int call_g_frame_interval(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_frame_interval *fi)
-{
-	return check_frame_interval(sd, fi) ? :
-	       sd->ops->video->g_frame_interval(sd, fi);
-}
-
-static int call_s_frame_interval(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_frame_interval *fi)
-{
-	return check_frame_interval(sd, fi) ? :
-	       sd->ops->video->s_frame_interval(sd, fi);
-}
-
 static int call_enum_frame_interval(struct v4l2_subdev *sd,
 				    struct v4l2_subdev_state *state,
 				    struct v4l2_subdev_frame_interval_enum *fie)
@@ -307,6 +284,34 @@ static int call_set_selection(struct v4l2_subdev *sd,
 	       sd->ops->pad->set_selection(sd, state, sel);
 }
 
+static inline int check_frame_interval(struct v4l2_subdev *sd,
+				       struct v4l2_subdev_state *state,
+				       struct v4l2_subdev_frame_interval *fi)
+{
+	if (!fi)
+		return -EINVAL;
+
+	return check_pad(sd, fi->pad) ? :
+	       check_state(sd, state, V4L2_SUBDEV_FORMAT_ACTIVE, fi->pad,
+			   fi->stream);
+}
+
+static int call_get_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state,
+				   struct v4l2_subdev_frame_interval *fi)
+{
+	return check_frame_interval(sd, state, fi) ? :
+	       sd->ops->pad->get_frame_interval(sd, state, fi);
+}
+
+static int call_set_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state,
+				   struct v4l2_subdev_frame_interval *fi)
+{
+	return check_frame_interval(sd, state, fi) ? :
+	       sd->ops->pad->set_frame_interval(sd, state, fi);
+}
+
 static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
 			       struct v4l2_mbus_frame_desc *fd)
 {
@@ -479,6 +484,8 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
 	.enum_frame_interval	= call_enum_frame_interval_state,
 	.get_selection		= call_get_selection_state,
 	.set_selection		= call_set_selection_state,
+	.get_frame_interval	= call_get_frame_interval,
+	.set_frame_interval	= call_set_frame_interval,
 	.get_edid		= call_get_edid,
 	.set_edid		= call_set_edid,
 	.dv_timings_cap		= call_dv_timings_cap,
@@ -488,8 +495,6 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
 };
 
 static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
-	.g_frame_interval	= call_g_frame_interval,
-	.s_frame_interval	= call_s_frame_interval,
 	.s_stream		= call_s_stream,
 };
 
@@ -531,6 +536,10 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
 	case VIDIOC_SUBDEV_S_SELECTION:
 		which = ((struct v4l2_subdev_selection *)arg)->which;
 		break;
+	case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
+	case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
+		which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		break;
 	case VIDIOC_SUBDEV_G_ROUTING:
 	case VIDIOC_SUBDEV_S_ROUTING:
 		which = ((struct v4l2_subdev_routing *)arg)->which;
@@ -781,7 +790,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
 			fi->stream = 0;
 
 		memset(fi->reserved, 0, sizeof(fi->reserved));
-		return v4l2_subdev_call(sd, video, g_frame_interval, arg);
+		return v4l2_subdev_call(sd, pad, get_frame_interval, state, fi);
 	}
 
 	case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
@@ -794,7 +803,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
 			fi->stream = 0;
 
 		memset(fi->reserved, 0, sizeof(fi->reserved));
-		return v4l2_subdev_call(sd, video, s_frame_interval, arg);
+		return v4l2_subdev_call(sd, pad, set_frame_interval, state, fi);
 	}
 
 	case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 5d89e4c1b0c2..006e8adac47b 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -496,8 +496,9 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
 	return ret;
 }
 
-static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *interval)
+static int gc0310_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *interval)
 {
 	interval->interval.numerator = 1;
 	interval->interval.denominator = GC0310_FPS;
@@ -545,7 +546,6 @@ static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
 
 static const struct v4l2_subdev_video_ops gc0310_video_ops = {
 	.s_stream = gc0310_s_stream,
-	.g_frame_interval = gc0310_g_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
@@ -553,6 +553,7 @@ static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
 	.enum_frame_size = gc0310_enum_frame_size,
 	.get_fmt = gc0310_get_fmt,
 	.set_fmt = gc0310_set_fmt,
+	.get_frame_interval = gc0310_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops gc0310_ops = {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index 9c20fe915238..aa257322a700 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -698,8 +698,9 @@ static int gc2235_s_config(struct v4l2_subdev *sd,
 	return ret;
 }
 
-static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *interval)
+static int gc2235_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *interval)
 {
 	struct gc2235_device *dev = to_gc2235_sensor(sd);
 
@@ -754,7 +755,6 @@ static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = {
 
 static const struct v4l2_subdev_video_ops gc2235_video_ops = {
 	.s_stream = gc2235_s_stream,
-	.g_frame_interval = gc2235_g_frame_interval,
 };
 
 static const struct v4l2_subdev_core_ops gc2235_core_ops = {
@@ -767,6 +767,7 @@ static const struct v4l2_subdev_pad_ops gc2235_pad_ops = {
 	.enum_frame_size = gc2235_enum_frame_size,
 	.get_fmt = gc2235_get_fmt,
 	.set_fmt = gc2235_set_fmt,
+	.get_frame_interval = gc2235_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops gc2235_ops = {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index 8105365fbb2a..459c5b8233ce 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -1388,8 +1388,9 @@ static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value)
 	return !!err;
 }
 
-static int mt9m114_g_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *interval)
+static int mt9m114_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *interval)
 {
 	struct mt9m114_device *dev = to_mt9m114_sensor(sd);
 
@@ -1479,7 +1480,6 @@ static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
 
 static const struct v4l2_subdev_video_ops mt9m114_video_ops = {
 	.s_stream = mt9m114_s_stream,
-	.g_frame_interval = mt9m114_g_frame_interval,
 };
 
 static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = {
@@ -1498,6 +1498,7 @@ static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = {
 	.get_fmt = mt9m114_get_fmt,
 	.set_fmt = mt9m114_set_fmt,
 	.set_selection = mt9m114_s_exposure_selection,
+	.get_frame_interval = mt9m114_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops mt9m114_ops = {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 1de63c82cce1..b3ef04d7ccca 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -845,8 +845,9 @@ static int ov2722_s_config(struct v4l2_subdev *sd,
 	return ret;
 }
 
-static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_frame_interval *interval)
+static int ov2722_get_frame_interval(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_frame_interval *interval)
 {
 	struct ov2722_device *dev = to_ov2722_sensor(sd);
 
@@ -901,7 +902,6 @@ static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = {
 
 static const struct v4l2_subdev_video_ops ov2722_video_ops = {
 	.s_stream = ov2722_s_stream,
-	.g_frame_interval = ov2722_g_frame_interval,
 };
 
 static const struct v4l2_subdev_core_ops ov2722_core_ops = {
@@ -914,6 +914,7 @@ static const struct v4l2_subdev_pad_ops ov2722_pad_ops = {
 	.enum_frame_size = ov2722_enum_frame_size,
 	.get_fmt = ov2722_get_fmt,
 	.set_fmt = ov2722_set_fmt,
+	.get_frame_interval = ov2722_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops ov2722_ops = {
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index 759233a7ba50..f44e6412f4e3 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -105,8 +105,8 @@ static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd)
 	unsigned short fps = 0;
 	int ret;
 
-	ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
-			       video, g_frame_interval, &fi);
+	ret = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
+					    pad, get_frame_interval, &fi);
 
 	if (!ret && fi.interval.numerator)
 		fps = fi.interval.denominator / fi.interval.numerator;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index 09c0091b920f..01b7fa9b56a2 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -1739,8 +1739,8 @@ static int atomisp_s_parm(struct file *file, void *fh,
 
 		fi.interval = parm->parm.capture.timeperframe;
 
-		rval = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
-					video, s_frame_interval, &fi);
+		rval = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
+						     pad, set_frame_interval, &fi);
 		if (!rval)
 			parm->parm.capture.timeperframe = fi.interval;
 
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index 8bd9be49cc08..fb96f87e664e 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -393,8 +393,9 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
 	return ret;
 }
 
-static int prp_g_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int prp_get_frame_interval(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_interval *fi)
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
@@ -408,8 +409,9 @@ static int prp_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int prp_s_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int prp_set_frame_interval(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_interval *fi)
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
@@ -451,12 +453,12 @@ static const struct v4l2_subdev_pad_ops prp_pad_ops = {
 	.enum_mbus_code = prp_enum_mbus_code,
 	.get_fmt = prp_get_fmt,
 	.set_fmt = prp_set_fmt,
+	.get_frame_interval = prp_get_frame_interval,
+	.set_frame_interval = prp_set_frame_interval,
 	.link_validate = prp_link_validate,
 };
 
 static const struct v4l2_subdev_video_ops prp_video_ops = {
-	.g_frame_interval = prp_g_frame_interval,
-	.s_frame_interval = prp_s_frame_interval,
 	.s_stream = prp_s_stream,
 };
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 04878f07eeba..7bfe433cd322 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -1203,8 +1203,9 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
 	return ret;
 }
 
-static int prp_g_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int prp_get_frame_interval(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_interval *fi)
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
@@ -1218,8 +1219,9 @@ static int prp_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int prp_s_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int prp_set_frame_interval(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_interval *fi)
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
@@ -1300,11 +1302,11 @@ static const struct v4l2_subdev_pad_ops prp_pad_ops = {
 	.enum_frame_size = prp_enum_frame_size,
 	.get_fmt = prp_get_fmt,
 	.set_fmt = prp_set_fmt,
+	.get_frame_interval = prp_get_frame_interval,
+	.set_frame_interval = prp_set_frame_interval,
 };
 
 static const struct v4l2_subdev_video_ops prp_video_ops = {
-	.g_frame_interval = prp_g_frame_interval,
-	.s_frame_interval = prp_s_frame_interval,
 	.s_stream = prp_s_stream,
 };
 
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index ce02199e7b1b..c944fb131b0a 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -511,7 +511,8 @@ static int capture_legacy_g_parm(struct file *file, void *fh,
 	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	ret = v4l2_subdev_call(priv->src_sd, video, g_frame_interval, &fi);
+	ret = v4l2_subdev_call_state_active(priv->src_sd, pad,
+					    get_frame_interval, &fi);
 	if (ret < 0)
 		return ret;
 
@@ -534,7 +535,8 @@ static int capture_legacy_s_parm(struct file *file, void *fh,
 		return -EINVAL;
 
 	fi.interval = a->parm.capture.timeperframe;
-	ret = v4l2_subdev_call(priv->src_sd, video, s_frame_interval, &fi);
+	ret = v4l2_subdev_call_state_active(priv->src_sd, pad,
+					    set_frame_interval, &fi);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 2fc94011fe4d..4308fdc9b58e 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -902,8 +902,9 @@ static const struct csi_skip_desc *csi_find_best_skip(struct v4l2_fract *in,
  * V4L2 subdev operations.
  */
 
-static int csi_g_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int csi_get_frame_interval(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_interval *fi)
 {
 	struct csi_priv *priv = v4l2_get_subdevdata(sd);
 
@@ -919,8 +920,9 @@ static int csi_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int csi_s_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int csi_set_frame_interval(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_frame_interval *fi)
 {
 	struct csi_priv *priv = v4l2_get_subdevdata(sd);
 	struct v4l2_fract *input_fi;
@@ -1860,8 +1862,6 @@ static const struct v4l2_subdev_core_ops csi_core_ops = {
 };
 
 static const struct v4l2_subdev_video_ops csi_video_ops = {
-	.g_frame_interval = csi_g_frame_interval,
-	.s_frame_interval = csi_s_frame_interval,
 	.s_stream = csi_s_stream,
 };
 
@@ -1873,6 +1873,8 @@ static const struct v4l2_subdev_pad_ops csi_pad_ops = {
 	.set_fmt = csi_set_fmt,
 	.get_selection = csi_get_selection,
 	.set_selection = csi_set_selection,
+	.get_frame_interval = csi_get_frame_interval,
+	.set_frame_interval = csi_set_frame_interval,
 	.link_validate = csi_link_validate,
 };
 
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index 810b38ea3ab9..a51b37679239 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -780,8 +780,9 @@ static int vdic_link_validate(struct v4l2_subdev *sd,
 	return ret;
 }
 
-static int vdic_g_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int vdic_get_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *sd_state,
+				   struct v4l2_subdev_frame_interval *fi)
 {
 	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 
@@ -797,8 +798,9 @@ static int vdic_g_frame_interval(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int vdic_s_frame_interval(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *fi)
+static int vdic_set_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *sd_state,
+				   struct v4l2_subdev_frame_interval *fi)
 {
 	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 	struct v4l2_fract *input_fi, *output_fi;
@@ -885,12 +887,12 @@ static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
 	.enum_mbus_code = vdic_enum_mbus_code,
 	.get_fmt = vdic_get_fmt,
 	.set_fmt = vdic_set_fmt,
+	.get_frame_interval = vdic_get_frame_interval,
+	.set_frame_interval = vdic_set_frame_interval,
 	.link_validate = vdic_link_validate,
 };
 
 static const struct v4l2_subdev_video_ops vdic_video_ops = {
-	.g_frame_interval = vdic_g_frame_interval,
-	.s_frame_interval = vdic_s_frame_interval,
 	.s_stream = vdic_s_stream,
 };
 
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 0d94115b9bbb..b1b666179be5 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -222,8 +222,9 @@ static int csi_set_format(struct v4l2_subdev *subdev,
 /*
  * V4L2 Subdevice Video Operations
  */
-static int tegra_csi_g_frame_interval(struct v4l2_subdev *subdev,
-				      struct v4l2_subdev_frame_interval *vfi)
+static int tegra_csi_get_frame_interval(struct v4l2_subdev *subdev,
+					struct v4l2_subdev_state *sd_state,
+					struct v4l2_subdev_frame_interval *vfi)
 {
 	struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
 
@@ -430,8 +431,6 @@ static int tegra_csi_s_stream(struct v4l2_subdev *subdev, int enable)
  */
 static const struct v4l2_subdev_video_ops tegra_csi_video_ops = {
 	.s_stream = tegra_csi_s_stream,
-	.g_frame_interval = tegra_csi_g_frame_interval,
-	.s_frame_interval = tegra_csi_g_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
@@ -440,6 +439,8 @@ static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
 	.enum_frame_interval	= csi_enum_frameintervals,
 	.get_fmt		= csi_get_format,
 	.set_fmt		= csi_set_format,
+	.get_frame_interval	= tegra_csi_get_frame_interval,
+	.set_frame_interval	= tegra_csi_get_frame_interval,
 };
 
 static const struct v4l2_subdev_ops tegra_csi_ops = {
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index d278836fd9cb..acf5be24a5ca 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -425,7 +425,7 @@ __v4l2_find_nearest_size(const void *array, size_t array_size,
 
 /**
  * v4l2_g_parm_cap - helper routine for vidioc_g_parm to fill this in by
- *      calling the g_frame_interval op of the given subdev. It only works
+ *      calling the get_frame_interval op of the given subdev. It only works
  *      for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
  *      function name.
  *
@@ -438,7 +438,7 @@ int v4l2_g_parm_cap(struct video_device *vdev,
 
 /**
  * v4l2_s_parm_cap - helper routine for vidioc_s_parm to fill this in by
- *      calling the s_frame_interval op of the given subdev. It only works
+ *      calling the set_frame_interval op of the given subdev. It only works
  *      for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
  *      function name.
  *
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 8b08f6640dee..b2dbaa739afa 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -452,12 +452,6 @@ enum v4l2_subdev_pre_streamon_flags {
  *
  * @g_pixelaspect: callback to return the pixelaspect ratio.
  *
- * @g_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
- *		      ioctl handler code.
- *
- * @s_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
- *		      ioctl handler code.
- *
  * @s_dv_timings: Set custom dv timings in the sub device. This is used
  *	when sub device is capable of setting detailed timing information
  *	in the hardware to generate/detect the video signal.
@@ -496,10 +490,6 @@ struct v4l2_subdev_video_ops {
 	int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
 	int (*s_stream)(struct v4l2_subdev *sd, int enable);
 	int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect);
-	int (*g_frame_interval)(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *interval);
-	int (*s_frame_interval)(struct v4l2_subdev *sd,
-				struct v4l2_subdev_frame_interval *interval);
 	int (*s_dv_timings)(struct v4l2_subdev *sd,
 			struct v4l2_dv_timings *timings);
 	int (*g_dv_timings)(struct v4l2_subdev *sd,
@@ -787,6 +777,12 @@ struct v4l2_subdev_state {
  *
  * @set_selection: callback for VIDIOC_SUBDEV_S_SELECTION() ioctl handler code.
  *
+ * @get_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
+ *			ioctl handler code.
+ *
+ * @set_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
+ *			ioctl handler code.
+ *
  * @get_edid: callback for VIDIOC_SUBDEV_G_EDID() ioctl handler code.
  *
  * @set_edid: callback for VIDIOC_SUBDEV_S_EDID() ioctl handler code.
@@ -856,6 +852,12 @@ struct v4l2_subdev_pad_ops {
 	int (*set_selection)(struct v4l2_subdev *sd,
 			     struct v4l2_subdev_state *state,
 			     struct v4l2_subdev_selection *sel);
+	int (*get_frame_interval)(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_frame_interval *interval);
+	int (*set_frame_interval)(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_frame_interval *interval);
 	int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
 	int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
 	int (*dv_timings_cap)(struct v4l2_subdev *sd,

base-commit: bec3db03911bd85da29c1c8ee556162153002c9a
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
@ 2023-12-05 14:08 ` Laurent Pinchart
  2023-12-06  8:58   ` Hans Verkuil
  2023-12-05 14:08 ` [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state Laurent Pinchart
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Akinobu Mita, Andrzej Hajda, Daniel Scally, Hans Verkuil,
	Hans de Goede, Jacopo Mondi, Jonathan Hunter, Kieran Bingham,
	Lars-Peter Clausen, Leon Luo, Luca Ceresoli,
	Mauro Carvalho Chehab, Niklas Söderlund, Paul Elder,
	Pavel Machek, Philipp Zabel, Ricardo Ribalda, Rui Miguel Silva,
	Sakari Ailus, Sowjanya Komatineni, Steve Longerbeam,
	Sylwester Nawrocki, Thierry Reding, Tomi Valkeinen, linux-tegra

Due to a historical mishap, the v4l2_subdev_frame_interval structure
is the only part of the V4L2 subdev userspace API that doesn't contain a
'which' field. This prevents trying frame intervals using the subdev
'TRY' state mechanism.

Adding a 'which' field is simple as the structure has 8 reserved fields.
This would however break userspace as the field is currently set to 0,
corresponding to V4L2_SUBDEV_FORMAT_TRY, while the corresponding ioctls
currently operate on the 'ACTIVE' state. We thus need to add a new
subdev client cap, V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL, to indicate
that userspace is aware of this new field.

All drivers that implement the subdev .get_frame_interval() and
.set_frame_interval() operations are updated to return -EINVAL when
operating on the TRY state, preserving the current behaviour.

While at it, fix a bad copy&paste in the documentation of the struct
v4l2_subdev_frame_interval_enum 'which' field.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> # for imx-media
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 .../media/v4l/vidioc-subdev-g-client-cap.rst  |  5 ++++
 .../v4l/vidioc-subdev-g-frame-interval.rst    | 17 ++++++++-----
 drivers/media/i2c/adv7180.c                   |  3 +++
 drivers/media/i2c/et8ek8/et8ek8_driver.c      |  6 +++++
 drivers/media/i2c/imx214.c                    |  3 +++
 drivers/media/i2c/imx274.c                    |  6 +++++
 drivers/media/i2c/max9286.c                   |  6 +++++
 drivers/media/i2c/mt9m111.c                   |  6 +++++
 drivers/media/i2c/mt9m114.c                   |  6 +++++
 drivers/media/i2c/mt9v011.c                   |  6 +++++
 drivers/media/i2c/mt9v111.c                   |  6 +++++
 drivers/media/i2c/ov2680.c                    |  3 +++
 drivers/media/i2c/ov5640.c                    |  6 +++++
 drivers/media/i2c/ov5648.c                    |  3 +++
 drivers/media/i2c/ov5693.c                    |  3 +++
 drivers/media/i2c/ov6650.c                    |  6 +++++
 drivers/media/i2c/ov7251.c                    |  6 +++++
 drivers/media/i2c/ov7670.c                    |  4 +++
 drivers/media/i2c/ov772x.c                    |  6 +++++
 drivers/media/i2c/ov8865.c                    |  3 +++
 drivers/media/i2c/ov9650.c                    |  6 +++++
 drivers/media/i2c/s5c73m3/s5c73m3-core.c      |  6 +++++
 drivers/media/i2c/s5k5baf.c                   |  6 +++++
 drivers/media/i2c/tvp514x.c                   |  4 +++
 drivers/media/v4l2-core/v4l2-subdev.c         | 25 ++++++++++++-------
 .../media/atomisp/i2c/atomisp-gc0310.c        |  3 +++
 .../media/atomisp/i2c/atomisp-gc2235.c        |  3 +++
 .../media/atomisp/i2c/atomisp-mt9m114.c       |  3 +++
 .../media/atomisp/i2c/atomisp-ov2722.c        |  3 +++
 drivers/staging/media/imx/imx-ic-prp.c        |  6 +++++
 drivers/staging/media/imx/imx-ic-prpencvf.c   |  6 +++++
 drivers/staging/media/imx/imx-media-csi.c     |  6 +++++
 drivers/staging/media/imx/imx-media-vdic.c    |  6 +++++
 drivers/staging/media/tegra-video/csi.c       |  3 +++
 include/uapi/linux/v4l2-subdev.h              | 13 ++++++++--
 35 files changed, 192 insertions(+), 17 deletions(-)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst
index 20f12a1cc0f7..f168140ebd59 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst
@@ -71,6 +71,11 @@ is unknown to the kernel.
         of 'stream' fields (referring to the stream number) with various
         ioctls. If this is not set (which is the default), the 'stream' fields
         will be forced to 0 by the kernel.
+    * - ``V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL``
+      - The client is aware of the :c:type:`v4l2_subdev_frame_interval`
+        ``which`` field. If this is not set (which is the default), the
+        ``which`` field is forced to ``V4L2_SUBDEV_FORMAT_ACTIVE`` by the
+        kernel.
 
 Return Value
 ============
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
index 842f962d2aea..41e0e2c8ecc3 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
@@ -58,8 +58,9 @@ struct
 contains the current frame interval as would be returned by a
 ``VIDIOC_SUBDEV_G_FRAME_INTERVAL`` call.
 
-Calling ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` on a subdev device node that has been
-registered in read-only mode is not allowed. An error is returned and the errno
+If the subdev device node has been registered in read-only mode, calls to
+``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` are only valid if the ``which`` field is set
+to ``V4L2_SUBDEV_FORMAT_TRY``, otherwise an error is returned and the errno
 variable is set to ``-EPERM``.
 
 Drivers must not return an error solely because the requested interval
@@ -93,7 +94,11 @@ the same sub-device is not defined.
       - ``stream``
       - Stream identifier.
     * - __u32
-      - ``reserved``\ [8]
+      - ``which``
+      - Active or try frame interval, from enum
+	:ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
+    * - __u32
+      - ``reserved``\ [7]
       - Reserved for future extensions. Applications and drivers must set
 	the array to zero.
 
@@ -114,9 +119,9 @@ EBUSY
 EINVAL
     The struct
     :c:type:`v4l2_subdev_frame_interval`
-    ``pad`` references a non-existing pad, or the pad doesn't support
-    frame intervals.
+    ``pad`` references a non-existing pad, the ``which`` field references a
+    non-existing frame interval, or the pad doesn't support frame intervals.
 
 EPERM
     The ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` ioctl has been called on a read-only
-    subdevice.
+    subdevice and the ``which`` field is set to ``V4L2_SUBDEV_FORMAT_ACTIVE``.
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 7ed86030fb5c..e1eec9f86539 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -469,6 +469,9 @@ static int adv7180_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct adv7180_state *state = to_state(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (state->curr_norm & V4L2_STD_525_60) {
 		fi->interval.numerator = 1001;
 		fi->interval.denominator = 30000;
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
index 71fb5aebd3df..359ed943533c 100644
--- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
+++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
@@ -1051,6 +1051,9 @@ static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
 {
 	struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	memset(fi, 0, sizeof(*fi));
 	fi->interval = sensor->current_reglist->mode.timeperframe;
 
@@ -1064,6 +1067,9 @@ static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev,
 	struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
 	struct et8ek8_reglist *reglist;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	reglist = et8ek8_reglist_find_mode_ival(&meta_reglist,
 						sensor->current_reglist,
 						&fi->interval);
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 624efc8834f3..80d14bc6f1ca 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -799,6 +799,9 @@ static int imx214_get_frame_interval(struct v4l2_subdev *subdev,
 				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *fival)
 {
+	if (fival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	fival->interval.numerator = 1;
 	fival->interval.denominator = IMX214_FPS;
 
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index 4040c642a36f..9f9fb3c488e2 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -1333,6 +1333,9 @@ static int imx274_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct stimx274 *imx274 = to_imx274(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	fi->interval = imx274->frame_interval;
 	dev_dbg(&imx274->client->dev, "%s frame rate = %d / %d\n",
 		__func__, imx274->frame_interval.numerator,
@@ -1350,6 +1353,9 @@ static int imx274_set_frame_interval(struct v4l2_subdev *sd,
 	int min, max, def;
 	int ret;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	ret = pm_runtime_resume_and_get(&imx274->client->dev);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 7e8cb53d31c3..16f81479d411 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -874,6 +874,9 @@ static int max9286_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct max9286_priv *priv = sd_to_max9286(sd);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (interval->pad != MAX9286_SRC_PAD)
 		return -EINVAL;
 
@@ -888,6 +891,9 @@ static int max9286_set_frame_interval(struct v4l2_subdev *sd,
 {
 	struct max9286_priv *priv = sd_to_max9286(sd);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (interval->pad != MAX9286_SRC_PAD)
 		return -EINVAL;
 
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 602954650f2e..a30c17594b8e 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -1051,6 +1051,9 @@ static int mt9m111_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	fi->interval = mt9m111->frame_interval;
 
 	return 0;
@@ -1068,6 +1071,9 @@ static int mt9m111_set_frame_interval(struct v4l2_subdev *sd,
 	if (mt9m111->is_streaming)
 		return -EBUSY;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad != 0)
 		return -EINVAL;
 
diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c
index dcd94299787c..5e0d85b3d158 100644
--- a/drivers/media/i2c/mt9m114.c
+++ b/drivers/media/i2c/mt9m114.c
@@ -1592,6 +1592,9 @@ static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *ival = &interval->interval;
 	struct mt9m114 *sensor = ifp_to_mt9m114(sd);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(sensor->ifp.hdl.lock);
 
 	ival->numerator = 1;
@@ -1610,6 +1613,9 @@ static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd,
 	struct mt9m114 *sensor = ifp_to_mt9m114(sd);
 	int ret = 0;
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(sensor->ifp.hdl.lock);
 
 	if (ival->numerator != 0 && ival->denominator != 0)
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 3485761428ba..bc8c0591e4ae 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -366,6 +366,9 @@ static int mt9v011_get_frame_interval(struct v4l2_subdev *sd,
 				      struct v4l2_subdev_state *sd_state,
 				      struct v4l2_subdev_frame_interval *ival)
 {
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	calc_fps(sd,
 		 &ival->interval.numerator,
 		 &ival->interval.denominator);
@@ -380,6 +383,9 @@ static int mt9v011_set_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *tpf = &ival->interval;
 	u16 speed;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	speed = calc_speed(sd, tpf->numerator, tpf->denominator);
 
 	mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed);
diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c
index 496be67c971b..b62624771e7b 100644
--- a/drivers/media/i2c/mt9v111.c
+++ b/drivers/media/i2c/mt9v111.c
@@ -730,6 +730,9 @@ static int mt9v111_set_frame_interval(struct v4l2_subdev *sd,
 			   tpf->denominator;
 	unsigned int max_fps;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (!tpf->numerator)
 		tpf->numerator = 1;
 
@@ -779,6 +782,9 @@ static int mt9v111_get_frame_interval(struct v4l2_subdev *sd,
 	struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
 	struct v4l2_fract *tpf = &ival->interval;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&mt9v111->stream_mutex);
 
 	tpf->numerator = 1;
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index e3ff64a9e6ca..5455e7afd1b3 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -558,6 +558,9 @@ static int ov2680_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct ov2680_dev *sensor = to_ov2680_dev(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&sensor->lock);
 	fi->interval = sensor->mode.frame_interval;
 	mutex_unlock(&sensor->lock);
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 336bfd1ffd32..2d75a67a3aff 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -3610,6 +3610,9 @@ static int ov5640_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&sensor->lock);
 	fi->interval = sensor->frame_interval;
 	mutex_unlock(&sensor->lock);
@@ -3625,6 +3628,9 @@ static int ov5640_set_frame_interval(struct v4l2_subdev *sd,
 	const struct ov5640_mode_info *mode;
 	int frame_rate, ret = 0;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad != 0)
 		return -EINVAL;
 
diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c
index d0d7e9968f48..f02a7e263aee 100644
--- a/drivers/media/i2c/ov5648.c
+++ b/drivers/media/i2c/ov5648.c
@@ -2276,6 +2276,9 @@ static int ov5648_get_frame_interval(struct v4l2_subdev *subdev,
 	const struct ov5648_mode *mode;
 	int ret = 0;
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&sensor->mutex);
 
 	mode = sensor->state.mode;
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index a65645811fbc..ce49176560d4 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1013,6 +1013,9 @@ static int ov5693_get_frame_interval(struct v4l2_subdev *sd,
 				 ov5693->ctrls.vblank->val);
 	unsigned int fps = DIV_ROUND_CLOSEST(OV5693_PIXEL_RATE, framesize);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	interval->interval.numerator = 1;
 	interval->interval.denominator = fps;
 
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index a4dc45bdf3d7..4ef2b7db315e 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -806,6 +806,9 @@ static int ov6650_get_frame_interval(struct v4l2_subdev *sd,
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov6650 *priv = to_ov6650(client);
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	ival->interval = priv->tpf;
 
 	dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
@@ -823,6 +826,9 @@ static int ov6650_set_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *tpf = &ival->interval;
 	int div, ret;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (tpf->numerator == 0 || tpf->denominator == 0)
 		div = 1;  /* Reset to full rate */
 	else
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index 10d6b5deed83..08f5f2d0538d 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -1391,6 +1391,9 @@ static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
 {
 	struct ov7251 *ov7251 = to_ov7251(subdev);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&ov7251->lock);
 	fi->interval = ov7251->current_mode->timeperframe;
 	mutex_unlock(&ov7251->lock);
@@ -1406,6 +1409,9 @@ static int ov7251_set_frame_interval(struct v4l2_subdev *subdev,
 	const struct ov7251_mode_info *new_mode;
 	int ret = 0;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&ov7251->lock);
 	new_mode = ov7251_find_mode_by_ival(ov7251, &fi->interval);
 
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 463f20ece36e..7874a8dd7cf0 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1160,6 +1160,8 @@ static int ov7670_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct ov7670_info *info = to_state(sd);
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
 
 	info->devtype->get_framerate(sd, &ival->interval);
 
@@ -1173,6 +1175,8 @@ static int ov7670_set_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *tpf = &ival->interval;
 	struct ov7670_info *info = to_state(sd);
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
 
 	return info->devtype->set_framerate(sd, tpf);
 }
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index a14a25946c5b..d9a73871f7a3 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -724,6 +724,9 @@ static int ov772x_get_frame_interval(struct v4l2_subdev *sd,
 	struct ov772x_priv *priv = to_ov772x(sd);
 	struct v4l2_fract *tpf = &ival->interval;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	tpf->numerator = 1;
 	tpf->denominator = priv->fps;
 
@@ -739,6 +742,9 @@ static int ov772x_set_frame_interval(struct v4l2_subdev *sd,
 	unsigned int fps;
 	int ret = 0;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&priv->lock);
 
 	if (priv->streaming) {
diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c
index 02a595281c49..7a25dcd900f2 100644
--- a/drivers/media/i2c/ov8865.c
+++ b/drivers/media/i2c/ov8865.c
@@ -2846,6 +2846,9 @@ static int ov8865_get_frame_interval(struct v4l2_subdev *subdev,
 	unsigned int framesize;
 	unsigned int fps;
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&sensor->mutex);
 
 	mode = sensor->state.mode;
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index f528892c893f..08be6c4fc6d5 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1107,6 +1107,9 @@ static int ov965x_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct ov965x *ov965x = to_ov965x(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&ov965x->lock);
 	fi->interval = ov965x->fiv->interval;
 	mutex_unlock(&ov965x->lock);
@@ -1156,6 +1159,9 @@ static int ov965x_set_frame_interval(struct v4l2_subdev *sd,
 	struct ov965x *ov965x = to_ov965x(sd);
 	int ret;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
 		 fi->interval.numerator, fi->interval.denominator);
 
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 73ca50f49812..71a51794ced4 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -872,6 +872,9 @@ static int s5c73m3_oif_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad != OIF_SOURCE_PAD)
 		return -EINVAL;
 
@@ -923,6 +926,9 @@ static int s5c73m3_oif_set_frame_interval(struct v4l2_subdev *sd,
 	struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
 	int ret;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad != OIF_SOURCE_PAD)
 		return -EINVAL;
 
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 2fd1ecfeb086..6b1a2c4946a9 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -1124,6 +1124,9 @@ static int s5k5baf_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct s5k5baf *state = to_s5k5baf(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&state->lock);
 	fi->interval.numerator = state->fiv;
 	fi->interval.denominator = 10000;
@@ -1162,6 +1165,9 @@ static int s5k5baf_set_frame_interval(struct v4l2_subdev *sd,
 {
 	struct s5k5baf *state = to_s5k5baf(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&state->lock);
 	__s5k5baf_set_frame_interval(state, fi);
 	mutex_unlock(&state->lock);
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index dee0cf992379..ae073a532eda 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -746,6 +746,8 @@ tvp514x_get_frame_interval(struct v4l2_subdev *sd,
 	struct tvp514x_decoder *decoder = to_decoder(sd);
 	enum tvp514x_std current_std;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
 
 	/* get the current standard */
 	current_std = decoder->current_std;
@@ -765,6 +767,8 @@ tvp514x_set_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *timeperframe;
 	enum tvp514x_std current_std;
 
+	if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
 
 	timeperframe = &ival->interval;
 
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 08c908988f7d..4cbe4024ff67 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -291,9 +291,8 @@ static inline int check_frame_interval(struct v4l2_subdev *sd,
 	if (!fi)
 		return -EINVAL;
 
-	return check_pad(sd, fi->pad) ? :
-	       check_state(sd, state, V4L2_SUBDEV_FORMAT_ACTIVE, fi->pad,
-			   fi->stream);
+	return check_which(fi->which) ? : check_pad(sd, fi->pad) ? :
+	       check_state(sd, state, fi->which, fi->pad, fi->stream);
 }
 
 static int call_get_frame_interval(struct v4l2_subdev *sd,
@@ -537,9 +536,16 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
 		which = ((struct v4l2_subdev_selection *)arg)->which;
 		break;
 	case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
-	case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
-		which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
+		struct v4l2_subdev_frame_interval *fi = arg;
+
+		if (!(subdev_fh->client_caps &
+		      V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL))
+			fi->which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+		which = fi->which;
 		break;
+	}
 	case VIDIOC_SUBDEV_G_ROUTING:
 	case VIDIOC_SUBDEV_S_ROUTING:
 		which = ((struct v4l2_subdev_routing *)arg)->which;
@@ -796,12 +802,12 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
 	case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
 		struct v4l2_subdev_frame_interval *fi = arg;
 
-		if (ro_subdev)
-			return -EPERM;
-
 		if (!client_supports_streams)
 			fi->stream = 0;
 
+		if (fi->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
+			return -EPERM;
+
 		memset(fi->reserved, 0, sizeof(fi->reserved));
 		return v4l2_subdev_call(sd, pad, set_frame_interval, state, fi);
 	}
@@ -998,7 +1004,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
 			client_cap->capabilities &= ~V4L2_SUBDEV_CLIENT_CAP_STREAMS;
 
 		/* Filter out unsupported capabilities */
-		client_cap->capabilities &= V4L2_SUBDEV_CLIENT_CAP_STREAMS;
+		client_cap->capabilities &= (V4L2_SUBDEV_CLIENT_CAP_STREAMS |
+					     V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL);
 
 		subdev_fh->client_caps = client_cap->capabilities;
 
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 006e8adac47b..3a032e1a06f8 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -500,6 +500,9 @@ static int gc0310_get_frame_interval(struct v4l2_subdev *sd,
 				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_frame_interval *interval)
 {
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	interval->interval.numerator = 1;
 	interval->interval.denominator = GC0310_FPS;
 
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index aa257322a700..a2bbe2864049 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -704,6 +704,9 @@ static int gc2235_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct gc2235_device *dev = to_gc2235_sensor(sd);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	interval->interval.numerator = 1;
 	interval->interval.denominator = dev->res->fps;
 
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index 459c5b8233ce..b4be6d3120b1 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -1394,6 +1394,9 @@ static int mt9m114_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct mt9m114_device *dev = to_mt9m114_sensor(sd);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	interval->interval.numerator = 1;
 	interval->interval.denominator = mt9m114_res[dev->res].fps;
 
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index b3ef04d7ccca..64e1addfc1c5 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -851,6 +851,9 @@ static int ov2722_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct ov2722_device *dev = to_ov2722_sensor(sd);
 
+	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	interval->interval.numerator = 1;
 	interval->interval.denominator = dev->res->fps;
 
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index fb96f87e664e..26c758b67bf2 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -399,6 +399,9 @@ static int prp_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad >= PRP_NUM_PADS)
 		return -EINVAL;
 
@@ -415,6 +418,9 @@ static int prp_set_frame_interval(struct v4l2_subdev *sd,
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad >= PRP_NUM_PADS)
 		return -EINVAL;
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 7bfe433cd322..94a8ace3fa7f 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -1209,6 +1209,9 @@ static int prp_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad >= PRPENCVF_NUM_PADS)
 		return -EINVAL;
 
@@ -1225,6 +1228,9 @@ static int prp_set_frame_interval(struct v4l2_subdev *sd,
 {
 	struct prp_priv *priv = sd_to_priv(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad >= PRPENCVF_NUM_PADS)
 		return -EINVAL;
 
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 4308fdc9b58e..9af5a0d5ace4 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -908,6 +908,9 @@ static int csi_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct csi_priv *priv = v4l2_get_subdevdata(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad >= CSI_NUM_PADS)
 		return -EINVAL;
 
@@ -928,6 +931,9 @@ static int csi_set_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *input_fi;
 	int ret = 0;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&priv->lock);
 
 	input_fi = &priv->frame_interval[CSI_SINK_PAD];
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index a51b37679239..d34e11d925a1 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -786,6 +786,9 @@ static int vdic_get_frame_interval(struct v4l2_subdev *sd,
 {
 	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	if (fi->pad >= VDIC_NUM_PADS)
 		return -EINVAL;
 
@@ -806,6 +809,9 @@ static int vdic_set_frame_interval(struct v4l2_subdev *sd,
 	struct v4l2_fract *input_fi, *output_fi;
 	int ret = 0;
 
+	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	mutex_lock(&priv->lock);
 
 	input_fi = &priv->frame_interval[priv->active_input_pad];
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index b1b666179be5..a2ce8d025eaf 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -231,6 +231,9 @@ static int tegra_csi_get_frame_interval(struct v4l2_subdev *subdev,
 	if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
 		return -ENOIOCTLCMD;
 
+	if (vfi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return -EINVAL;
+
 	vfi->interval.numerator = 1;
 	vfi->interval.denominator = csi_chan->framerate;
 
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index f0fbb4a7c150..cc2717f734e7 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -116,13 +116,15 @@ struct v4l2_subdev_frame_size_enum {
  * @pad: pad number, as reported by the media API
  * @interval: frame interval in seconds
  * @stream: stream number, defined in subdev routing
+ * @which: interval type (from enum v4l2_subdev_format_whence)
  * @reserved: drivers and applications must zero this array
  */
 struct v4l2_subdev_frame_interval {
 	__u32 pad;
 	struct v4l2_fract interval;
 	__u32 stream;
-	__u32 reserved[8];
+	__u32 which;
+	__u32 reserved[7];
 };
 
 /**
@@ -133,7 +135,7 @@ struct v4l2_subdev_frame_interval {
  * @width: frame width in pixels
  * @height: frame height in pixels
  * @interval: frame interval in seconds
- * @which: format type (from enum v4l2_subdev_format_whence)
+ * @which: interval type (from enum v4l2_subdev_format_whence)
  * @stream: stream number, defined in subdev routing
  * @reserved: drivers and applications must zero this array
  */
@@ -241,6 +243,13 @@ struct v4l2_subdev_routing {
  */
 #define V4L2_SUBDEV_CLIENT_CAP_STREAMS		(1ULL << 0)
 
+/*
+ * The client is aware of the struct v4l2_subdev_frame_interval which field. If
+ * this is not set (which is the default), the which field is forced to
+ * V4L2_SUBDEV_FORMAT_ACTIVE by the kernel.
+ */
+#define V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL	(1U << 1)
+
 /**
  * struct v4l2_subdev_client_capability - Capabilities of the client accessing
  *					  the subdev
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval Laurent Pinchart
@ 2023-12-05 14:08 ` Laurent Pinchart
  2023-12-06  1:00   ` kernel test robot
  2023-12-06  3:06   ` kernel test robot
  2023-12-05 14:08 ` [PATCH v3 4/7] media: docs: uAPI: Clarify error documentation for invalid 'which' value Laurent Pinchart
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Hans Verkuil, Jacopo Mondi, Kieran Bingham, Mauro Carvalho Chehab,
	Paul Elder, Sakari Ailus, Tomi Valkeinen

Subdev states store all standard pad configuration data, except for
frame intervals. Fix it by adding interval fields in the
v4l2_subdev_pad_config and v4l2_subdev_stream_config structures, with
corresponding accessor functions and a helper function to implement the
.get_frame_interval() operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
Changes since v2:

- Remove WARN_ON() on invalid pad
- Add lockdep_assert_held()
---
 drivers/media/v4l2-core/v4l2-subdev.c | 52 +++++++++++++++++++++++++++
 include/media/v4l2-subdev.h           | 45 +++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 4cbe4024ff67..74a81b0df7ca 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -1651,6 +1651,42 @@ __v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state,
 }
 EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_compose);
 
+struct v4l2_fract *
+__v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
+				 unsigned int pad, u32 stream)
+{
+	struct v4l2_subdev_stream_configs *stream_configs;
+	unsigned int i;
+
+	if (WARN_ON(!state))
+		return NULL;
+
+	lockdep_assert_held(state->lock);
+
+	if (state->pads) {
+		if (stream)
+			return NULL;
+
+		if (pad >= state->sd->entity.num_pads)
+			return NULL;
+
+		return &state->pads[pad].interval;
+	}
+
+	lockdep_assert_held(state->lock);
+
+	stream_configs = &state->stream_configs;
+
+	for (i = 0; i < stream_configs->num_configs; ++i) {
+		if (stream_configs->configs[i].pad == pad &&
+		    stream_configs->configs[i].stream == stream)
+			return &stream_configs->configs[i].interval;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_interval);
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 
 static int
@@ -1717,6 +1753,22 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt);
 
+int v4l2_subdev_get_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state,
+				   struct v4l2_subdev_frame_interval *fi)
+{
+	struct v4l2_fract *interval;
+
+	interval = v4l2_subdev_state_get_interval(state, fi->pad, fi->stream);
+	if (!interval)
+		return -EINVAL;
+
+	fi->interval = *interval;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_get_frame_interval);
+
 int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
 			    struct v4l2_subdev_state *state,
 			    const struct v4l2_subdev_krouting *routing)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index b2dbaa739afa..e71ad55e7d04 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -681,11 +681,13 @@ struct v4l2_subdev_ir_ops {
  * @format: &struct v4l2_mbus_framefmt
  * @crop: &struct v4l2_rect to be used for crop
  * @compose: &struct v4l2_rect to be used for compose
+ * @interval: frame interval
  */
 struct v4l2_subdev_pad_config {
 	struct v4l2_mbus_framefmt format;
 	struct v4l2_rect crop;
 	struct v4l2_rect compose;
+	struct v4l2_fract interval;
 };
 
 /**
@@ -697,6 +699,7 @@ struct v4l2_subdev_pad_config {
  * @fmt: &struct v4l2_mbus_framefmt
  * @crop: &struct v4l2_rect to be used for crop
  * @compose: &struct v4l2_rect to be used for compose
+ * @interval: frame interval
  *
  * This structure stores configuration for a stream.
  */
@@ -708,6 +711,7 @@ struct v4l2_subdev_stream_config {
 	struct v4l2_mbus_framefmt fmt;
 	struct v4l2_rect crop;
 	struct v4l2_rect compose;
+	struct v4l2_fract interval;
 };
 
 /**
@@ -1494,6 +1498,24 @@ __v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state,
 int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
 			struct v4l2_subdev_format *format);
 
+/**
+ * v4l2_subdev_get_frame_interval() - Fill frame interval based on state
+ * @sd: subdevice
+ * @state: subdevice state
+ * @fi: pointer to &struct v4l2_subdev_frame_interval
+ *
+ * Fill @fi->interval field based on the information in the @fi struct.
+ *
+ * This function can be used by the subdev drivers which support active state to
+ * implement v4l2_subdev_pad_ops.get_frame_interval if the subdev driver does
+ * not need to do anything special in their get_frame_interval op.
+ *
+ * Returns 0 on success, error value otherwise.
+ */
+int v4l2_subdev_get_frame_interval(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state,
+				   struct v4l2_subdev_frame_interval *fi);
+
 /**
  * v4l2_subdev_set_routing() - Set given routing to subdev state
  * @sd: The subdevice
@@ -1539,6 +1561,29 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
 				     const struct v4l2_subdev_krouting *routing,
 				     const struct v4l2_mbus_framefmt *fmt);
 
+/**
+ * v4l2_subdev_state_get_interval() - Get pointer to a stream frame interval
+ * @state: subdevice state
+ * @pad: pad id
+ * @...: stream id (optional argument)
+ *
+ * This returns a pointer to the frame interval for the given pad + stream in
+ * the subdev state.
+ *
+ * For stream-unaware drivers the frame interval for the corresponding pad is
+ * returned. If the pad does not exist, NULL is returned.
+ */
+#define v4l2_subdev_state_get_interval(state, pad, ...)         \
+        __v4l2_subdev_state_get_interval_ ## __VA_OPT__(stream) \
+        (state, pad __VA_OPT__(,) __VA_ARGS__)
+#define __v4l2_subdev_state_get_interval_(state, pad)	\
+        __v4l2_subdev_state_get_interval(state, pad, 0)
+#define __v4l2_subdev_state_get_interval_stream(state, pad, stream)	\
+        __v4l2_subdev_state_get_interval(state, pad, stream)
+struct v4l2_fract *
+__v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
+				 unsigned int pad, u32 stream);
+
 /**
  * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream
  * @routing: routing used to find the opposite side
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/7] media: docs: uAPI: Clarify error documentation for invalid 'which' value
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state Laurent Pinchart
@ 2023-12-05 14:08 ` Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 5/7] media: docs: uAPI: Expand " Laurent Pinchart
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Hans Verkuil, Jacopo Mondi, Kieran Bingham, Mauro Carvalho Chehab,
	Paul Elder, Sakari Ailus, Tomi Valkeinen

Invalid values for the 'which' field of structures passed to multiple
subdev ioctls result in an EINVAL error being returned. The
documentation of the corresponding ioctls indicates this with sentences
such as the following:

    the ``which`` field references a non-existing format

This is confusing. Clarify the documentation.

Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../userspace-api/media/v4l/vidioc-subdev-g-crop.rst       | 7 +++----
 .../userspace-api/media/v4l/vidioc-subdev-g-fmt.rst        | 5 ++---
 .../media/v4l/vidioc-subdev-g-frame-interval.rst           | 7 +++----
 .../userspace-api/media/v4l/vidioc-subdev-g-selection.rst  | 7 +++----
 4 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst
index 1d267f7e7991..92d933631fda 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst
@@ -118,10 +118,9 @@ EBUSY
     ``VIDIOC_SUBDEV_S_CROP``
 
 EINVAL
-    The struct :c:type:`v4l2_subdev_crop` ``pad``
-    references a non-existing pad, the ``which`` field references a
-    non-existing format, or cropping is not supported on the given
-    subdev pad.
+    The struct :c:type:`v4l2_subdev_crop` ``pad`` references a non-existing pad,
+    the ``which`` field has an unsupported value, or cropping is not supported
+    on the given subdev pad.
 
 EPERM
     The ``VIDIOC_SUBDEV_S_CROP`` ioctl has been called on a read-only subdevice
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst
index ed253a1e44b7..4a2b4e4f0152 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst
@@ -140,9 +140,8 @@ EBUSY
     fix the problem first. Only returned by ``VIDIOC_SUBDEV_S_FMT``
 
 EINVAL
-    The struct :c:type:`v4l2_subdev_format`
-    ``pad`` references a non-existing pad, or the ``which`` field
-    references a non-existing format.
+    The struct :c:type:`v4l2_subdev_format` ``pad`` references a non-existing
+    pad, or the ``which`` field has an unsupported value.
 
 EPERM
     The ``VIDIOC_SUBDEV_S_FMT`` ioctl has been called on a read-only subdevice
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
index 41e0e2c8ecc3..c8022809ac35 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
@@ -117,10 +117,9 @@ EBUSY
     ``VIDIOC_SUBDEV_S_FRAME_INTERVAL``
 
 EINVAL
-    The struct
-    :c:type:`v4l2_subdev_frame_interval`
-    ``pad`` references a non-existing pad, the ``which`` field references a
-    non-existing frame interval, or the pad doesn't support frame intervals.
+    The struct :c:type:`v4l2_subdev_frame_interval` ``pad`` references a
+    non-existing pad, the ``which`` field has an unsupported value, or the pad
+    doesn't support frame intervals.
 
 EPERM
     The ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` ioctl has been called on a read-only
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst
index 6b629c19168c..19e6c3e9c06d 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst
@@ -116,10 +116,9 @@ EBUSY
     ``VIDIOC_SUBDEV_S_SELECTION``
 
 EINVAL
-    The struct :c:type:`v4l2_subdev_selection`
-    ``pad`` references a non-existing pad, the ``which`` field
-    references a non-existing format, or the selection target is not
-    supported on the given subdev pad.
+    The struct :c:type:`v4l2_subdev_selection` ``pad`` references a
+    non-existing pad, the ``which`` field has an unsupported value, or the
+    selection target is not supported on the given subdev pad.
 
 EPERM
     The ``VIDIOC_SUBDEV_S_SELECTION`` ioctl has been called on a read-only
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 5/7] media: docs: uAPI: Expand error documentation for invalid 'which' value
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
                   ` (2 preceding siblings ...)
  2023-12-05 14:08 ` [PATCH v3 4/7] media: docs: uAPI: Clarify error documentation for invalid 'which' value Laurent Pinchart
@ 2023-12-05 14:08 ` Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 6/7] media: docs: uAPI: Fix documentation of 'which' field for routing ioctls Laurent Pinchart
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Hans Verkuil, Jacopo Mondi, Kieran Bingham, Mauro Carvalho Chehab,
	Paul Elder, Sakari Ailus, Tomi Valkeinen

Multiple subdev ioctls that take a 'which' field do not document the
error returned when the field has an invalid value. Expand the
documentation to fix this.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../media/v4l/vidioc-subdev-enum-frame-interval.rst      | 9 ++++-----
 .../media/v4l/vidioc-subdev-enum-frame-size.rst          | 7 +++----
 .../media/v4l/vidioc-subdev-enum-mbus-code.rst           | 7 +++----
 .../userspace-api/media/v4l/vidioc-subdev-g-routing.rst  | 5 +++--
 4 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst
index 8def4c05d3da..c935bacc3bc2 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst
@@ -107,8 +107,7 @@ appropriately. The generic error codes are described at the
 :ref:`Generic Error Codes <gen-errors>` chapter.
 
 EINVAL
-    The struct
-    :c:type:`v4l2_subdev_frame_interval_enum`
-    ``pad`` references a non-existing pad, one of the ``code``,
-    ``width`` or ``height`` fields are invalid for the given pad or the
-    ``index`` field is out of bounds.
+    The struct :c:type:`v4l2_subdev_frame_interval_enum` ``pad`` references a
+    non-existing pad, the ``which`` field has an unsupported value, one of the
+    ``code``, ``width`` or ``height`` fields are invalid for the given pad, or
+    the ``index`` field is out of bounds.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst
index e3ae84df5486..65f0cfeca973 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst
@@ -126,7 +126,6 @@ appropriately. The generic error codes are described at the
 :ref:`Generic Error Codes <gen-errors>` chapter.
 
 EINVAL
-    The struct
-    :c:type:`v4l2_subdev_frame_size_enum`
-    ``pad`` references a non-existing pad, the ``code`` is invalid for
-    the given pad or the ``index`` field is out of bounds.
+    The struct :c:type:`v4l2_subdev_frame_size_enum` ``pad`` references a
+    non-existing pad, the ``which`` field has an unsupported value, the ``code``
+    is invalid for the given pad, or the ``index`` field is out of bounds.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst
index 4ad7dec27e25..3050966b199f 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst
@@ -158,7 +158,6 @@ appropriately. The generic error codes are described at the
 :ref:`Generic Error Codes <gen-errors>` chapter.
 
 EINVAL
-    The struct
-    :c:type:`v4l2_subdev_mbus_code_enum`
-    ``pad`` references a non-existing pad, or the ``index`` field is out
-    of bounds.
+    The struct :c:type:`v4l2_subdev_mbus_code_enum` ``pad`` references a
+    non-existing pad, the ``which`` field has an unsupported value, or the
+    ``index`` field is out of bounds.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
index 72677a280cd6..791c1e628d5c 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
@@ -140,8 +140,9 @@ ENOSPC
    all the available routes the subdevice exposes.
 
 EINVAL
-   The sink or source pad identifiers reference a non-existing pad, or reference
-   pads of different types (ie. the sink_pad identifiers refers to a source pad).
+   The sink or source pad identifiers reference a non-existing pad or reference
+   pads of different types (ie. the sink_pad identifiers refers to a source
+   pad), or the ``which`` field has an unsupported value.
 
 E2BIG
    The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/7] media: docs: uAPI: Fix documentation of 'which' field for routing ioctls
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
                   ` (3 preceding siblings ...)
  2023-12-05 14:08 ` [PATCH v3 5/7] media: docs: uAPI: Expand " Laurent Pinchart
@ 2023-12-05 14:08 ` Laurent Pinchart
  2023-12-05 14:08 ` [PATCH v3 7/7] media: i2c: thp7312: Store frame interval in subdev state Laurent Pinchart
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Hans Verkuil, Jacopo Mondi, Kieran Bingham, Mauro Carvalho Chehab,
	Paul Elder, Sakari Ailus, Tomi Valkeinen

The routing ioctls documentation incorrectly describes the 'which'
field, due to a bad copy & paste. Fix it.

Fixes: ea73eda50813 ("media: Documentation: Add GS_ROUTING documentation")
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../userspace-api/media/v4l/vidioc-subdev-g-routing.rst         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
index 791c1e628d5c..26b5004bfe6d 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
@@ -72,7 +72,7 @@ On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the
 
     * - __u32
       - ``which``
-      - Format to modified, from enum
+      - Routing table to be accessed, from enum
         :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
     * - struct :c:type:`v4l2_subdev_route`
       - ``routes[]``
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 7/7] media: i2c: thp7312: Store frame interval in subdev state
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
                   ` (4 preceding siblings ...)
  2023-12-05 14:08 ` [PATCH v3 6/7] media: docs: uAPI: Fix documentation of 'which' field for routing ioctls Laurent Pinchart
@ 2023-12-05 14:08 ` Laurent Pinchart
  2023-12-05 14:11 ` [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
  2023-12-06  3:52 ` kernel test robot
  7 siblings, 0 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:08 UTC (permalink / raw)
  To: linux-media
  Cc: Hans Verkuil, Jacopo Mondi, Kieran Bingham, Mauro Carvalho Chehab,
	Paul Elder, Sakari Ailus, Tomi Valkeinen

Use the newly added storage for frame interval in the subdev state to
simplify the driver.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 drivers/media/i2c/thp7312.c | 160 +++++++++++++++++++-----------------
 1 file changed, 86 insertions(+), 74 deletions(-)

diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c
index 3d46e428e0ac..2806887514dc 100644
--- a/drivers/media/i2c/thp7312.c
+++ b/drivers/media/i2c/thp7312.c
@@ -266,9 +266,6 @@ struct thp7312_device {
 	struct v4l2_ctrl_handler ctrl_handler;
 	bool ctrls_applied;
 
-	/* These are protected by v4l2 active state */
-	const struct thp7312_mode_info *current_mode;
-	const struct thp7312_frame_rate *current_rate;
 	s64 link_freq;
 
 	struct {
@@ -310,6 +307,47 @@ static inline struct thp7312_device *to_thp7312_dev(struct v4l2_subdev *sd)
 	return container_of(sd, struct thp7312_device, sd);
 }
 
+static const struct thp7312_mode_info *
+thp7312_find_mode(unsigned int width, unsigned int height, bool nearest)
+{
+	const struct thp7312_mode_info *mode;
+
+	mode = v4l2_find_nearest_size(thp7312_mode_info_data,
+				      ARRAY_SIZE(thp7312_mode_info_data),
+				      width, height, width, height);
+
+	if (!nearest && (mode->width != width || mode->height != height))
+		return NULL;
+
+	return mode;
+}
+
+static const struct thp7312_frame_rate *
+thp7312_find_rate(const struct thp7312_mode_info *mode, unsigned int fps,
+		  bool nearest)
+{
+	const struct thp7312_frame_rate *best_rate = NULL;
+	const struct thp7312_frame_rate *rate;
+	unsigned int best_delta = UINT_MAX;
+
+	if (!mode)
+		return NULL;
+
+	for (rate = mode->rates; rate->fps && best_delta; ++rate) {
+		unsigned int delta = abs(rate->fps - fps);
+
+		if (delta <= best_delta) {
+			best_delta = delta;
+			best_rate = rate;
+		}
+	}
+
+	if (!nearest && best_delta)
+		return NULL;
+
+	return best_rate;
+}
+
 /* -----------------------------------------------------------------------------
  * Device Access & Configuration
  */
@@ -442,17 +480,30 @@ static int thp7312_set_framefmt(struct thp7312_device *thp7312,
 static int thp7312_init_mode(struct thp7312_device *thp7312,
 			     struct v4l2_subdev_state *sd_state)
 {
+	const struct thp7312_mode_info *mode;
+	const struct thp7312_frame_rate *rate;
 	struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_fract *interval;
 	int ret;
 
+	/*
+	 * TODO: The mode and rate should be cached in the subdev state, once
+	 * support for extending states will be available.
+	 */
 	fmt = v4l2_subdev_state_get_format(sd_state, 0);
+	interval = v4l2_subdev_state_get_interval(sd_state, 0);
+
+	mode = thp7312_find_mode(fmt->width, fmt->height, false);
+	rate = thp7312_find_rate(mode, interval->denominator, false);
+
+	if (WARN_ON(!mode || !rate))
+		return -EINVAL;
 
 	ret = thp7312_set_framefmt(thp7312, fmt);
 	if (ret)
 		return ret;
 
-	return thp7312_change_mode(thp7312, thp7312->current_mode,
-				   thp7312->current_rate);
+	return thp7312_change_mode(thp7312, mode, rate);
 }
 
 static int thp7312_stream_enable(struct thp7312_device *thp7312, bool enable)
@@ -621,28 +672,6 @@ static bool thp7312_find_bus_code(u32 code)
 	return false;
 }
 
-static const struct thp7312_mode_info *
-thp7312_find_mode(unsigned int width, unsigned int height, bool nearest)
-{
-	const struct thp7312_mode_info *mode;
-
-	mode = v4l2_find_nearest_size(thp7312_mode_info_data,
-				      ARRAY_SIZE(thp7312_mode_info_data),
-				      width, height, width, height);
-
-	if (!nearest && (mode->width != width || mode->height != height))
-		return NULL;
-
-	return mode;
-}
-
-static void thp7312_set_frame_rate(struct thp7312_device *thp7312,
-				   const struct thp7312_frame_rate *rate)
-{
-	thp7312->link_freq = rate->link_freq;
-	thp7312->current_rate = rate;
-}
-
 static int thp7312_enum_mbus_code(struct v4l2_subdev *sd,
 				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_subdev_mbus_code_enum *code)
@@ -707,6 +736,7 @@ static int thp7312_set_fmt(struct v4l2_subdev *sd,
 	struct thp7312_device *thp7312 = to_thp7312_dev(sd);
 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
 	struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_fract *interval;
 	const struct thp7312_mode_info *mode;
 
 	if (!thp7312_find_bus_code(mbus_fmt->code))
@@ -726,37 +756,25 @@ static int thp7312_set_fmt(struct v4l2_subdev *sd,
 
 	*mbus_fmt = *fmt;
 
-	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
-		thp7312->current_mode = mode;
-		thp7312_set_frame_rate(thp7312, &mode->rates[0]);
-	}
+	interval = v4l2_subdev_state_get_interval(sd_state, 0);
+	interval->numerator = 1;
+	interval->denominator = mode->rates[0].fps;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		thp7312->link_freq = mode->rates[0].link_freq;
 
 	return 0;
 }
 
-static int thp7312_g_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *fi)
-{
-	struct thp7312_device *thp7312 = to_thp7312_dev(sd);
-	struct v4l2_subdev_state *sd_state;
-
-	sd_state = v4l2_subdev_lock_and_get_active_state(sd);
-	fi->interval.numerator = 1;
-	fi->interval.denominator = thp7312->current_rate->fps;
-	v4l2_subdev_unlock_state(sd_state);
-
-	return 0;
-}
-
-static int thp7312_s_frame_interval(struct v4l2_subdev *sd,
-				    struct v4l2_subdev_frame_interval *fi)
+static int thp7312_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *sd_state,
+				      struct v4l2_subdev_frame_interval *fi)
 {
 	struct thp7312_device *thp7312 = to_thp7312_dev(sd);
 	const struct thp7312_mode_info *mode;
-	const struct thp7312_frame_rate *best_rate = NULL;
 	const struct thp7312_frame_rate *rate;
-	struct v4l2_subdev_state *sd_state;
-	unsigned int best_delta = UINT_MAX;
+	const struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_fract *interval;
 	unsigned int fps;
 
 	/* Avoid divisions by 0, pick the highest frame if the interval is 0. */
@@ -764,25 +782,18 @@ static int thp7312_s_frame_interval(struct v4l2_subdev *sd,
 	    ? DIV_ROUND_CLOSEST(fi->interval.denominator, fi->interval.numerator)
 	    : UINT_MAX;
 
-	sd_state = v4l2_subdev_lock_and_get_active_state(sd);
+	fmt = v4l2_subdev_state_get_format(sd_state, 0);
+	mode = thp7312_find_mode(fmt->width, fmt->height, false);
+	rate = thp7312_find_rate(mode, fps, true);
 
-	mode = thp7312->current_mode;
+	interval = v4l2_subdev_state_get_interval(sd_state, 0);
+	interval->numerator = 1;
+	interval->denominator = rate->fps;
 
-	for (rate = mode->rates; rate->fps && best_delta; ++rate) {
-		unsigned int delta = abs(rate->fps - fps);
+	if (fi->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		thp7312->link_freq = rate->link_freq;
 
-		if (delta <= best_delta) {
-			best_delta = delta;
-			best_rate = rate;
-		}
-	}
-
-	thp7312_set_frame_rate(thp7312, best_rate);
-
-	v4l2_subdev_unlock_state(sd_state);
-
-	fi->interval.numerator = 1;
-	fi->interval.denominator = best_rate->fps;
+	fi->interval = *interval;
 
 	return 0;
 }
@@ -842,8 +853,10 @@ static int thp7312_init_state(struct v4l2_subdev *sd,
 {
 	const struct thp7312_mode_info *default_mode = &thp7312_mode_info_data[0];
 	struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_fract *interval;
 
 	fmt = v4l2_subdev_state_get_format(sd_state, 0);
+	interval = v4l2_subdev_state_get_interval(sd_state, 0);
 
 	/*
 	 * default init sequence initialize thp7312 to
@@ -858,6 +871,9 @@ static int thp7312_init_state(struct v4l2_subdev *sd,
 	fmt->height = default_mode->height;
 	fmt->field = V4L2_FIELD_NONE;
 
+	interval->numerator = 1;
+	interval->denominator = default_mode->rates[0].fps;
+
 	return 0;
 }
 
@@ -868,8 +884,6 @@ static const struct v4l2_subdev_core_ops thp7312_core_ops = {
 };
 
 static const struct v4l2_subdev_video_ops thp7312_video_ops = {
-	.g_frame_interval = thp7312_g_frame_interval,
-	.s_frame_interval = thp7312_s_frame_interval,
 	.s_stream = thp7312_s_stream,
 };
 
@@ -877,6 +891,8 @@ static const struct v4l2_subdev_pad_ops thp7312_pad_ops = {
 	.enum_mbus_code = thp7312_enum_mbus_code,
 	.get_fmt = v4l2_subdev_get_fmt,
 	.set_fmt = thp7312_set_fmt,
+	.get_frame_interval = v4l2_subdev_get_frame_interval,
+	.set_frame_interval = thp7312_set_frame_interval,
 	.enum_frame_size = thp7312_enum_frame_size,
 	.enum_frame_interval = thp7312_enum_frame_interval,
 };
@@ -1303,6 +1319,8 @@ static int thp7312_init_controls(struct thp7312_device *thp7312)
 			       V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
 			       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
 
+	thp7312->link_freq = thp7312_mode_info_data[0].rates[0].link_freq;
+
 	link_freq = v4l2_ctrl_new_int_menu(hdl, &thp7312_ctrl_ops,
 					   V4L2_CID_LINK_FREQ, 0, 0,
 					   &thp7312->link_freq);
@@ -2072,7 +2090,6 @@ static int thp7312_parse_dt(struct thp7312_device *thp7312)
 static int thp7312_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
-	struct v4l2_subdev_state *sd_state;
 	struct thp7312_device *thp7312;
 	int ret;
 
@@ -2148,11 +2165,6 @@ static int thp7312_probe(struct i2c_client *client)
 		goto err_free_ctrls;
 	}
 
-	sd_state = v4l2_subdev_lock_and_get_active_state(&thp7312->sd);
-	thp7312->current_mode = &thp7312_mode_info_data[0];
-	thp7312_set_frame_rate(thp7312, &thp7312->current_mode->rates[0]);
-	v4l2_subdev_unlock_state(sd_state);
-
 	/*
 	 * Enable runtime PM with autosuspend. As the device has been powered
 	 * manually, mark it as active, and increase the usage count without
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
                   ` (5 preceding siblings ...)
  2023-12-05 14:08 ` [PATCH v3 7/7] media: i2c: thp7312: Store frame interval in subdev state Laurent Pinchart
@ 2023-12-05 14:11 ` Laurent Pinchart
  2023-12-06  3:52 ` kernel test robot
  7 siblings, 0 replies; 12+ messages in thread
From: Laurent Pinchart @ 2023-12-05 14:11 UTC (permalink / raw)
  To: linux-media
  Cc: Akinobu Mita, Andrzej Hajda, Daniel Scally, Hans Verkuil,
	Hans de Goede, Jacopo Mondi, Jonathan Hunter, Kieran Bingham,
	Lars-Peter Clausen, Leon Luo, Luca Ceresoli,
	Mauro Carvalho Chehab, Niklas Söderlund, Paul Elder,
	Pavel Machek, Philipp Zabel, Ricardo Ribalda, Rui Miguel Silva,
	Sakari Ailus, Sowjanya Komatineni, Steve Longerbeam,
	Sylwester Nawrocki, Thierry Reding, Tomi Valkeinen, linux-tegra

It looks like I forgot to add a cover letter, sorry about that :-S
Here's what it would have read.


Hello,

This patch series improves frame interval handling in the V4L2 subdev
in-kernel and userspace APIs.

Frame interval are exposed to userspace on pads and streams, but the
frame interval handling is currently implemented through a v4l2_subdev
video operation, without involving the subdev state. This makes frame
intervals a second class citizen compared to formats and selection
rectangles.

Patch 1/7 starts by addressing the first issue, namely the frame
interval operations being video ops. This requires touching all the
drivers using frame intervals.

Patch 2/7 then adds a 'which' field to the subdev frame interval
userspace API, allowing frame intervals to be tried the same way formats
and selection rectangles can. Again, the same drivers need to be touched
to preserve their current behaviour.

Patch 3/7 adds support for storing the frame interval in the subdev
state, alongside the formats and selection rectangles, with similar
accessors and helper functions.

Patches 4/7 to 6/7 address small issues in the subdev uAPI documentation
that were raised during review of v2 or discovered when working on v3.

Finally, patch 7/7 demonstrates how this is used in drivers, with the
thp7312 driver serving as an example.

The series is based on the latest stage master branch.

Given the large number of drivers that this series touches, I would like
to get it merged in v6.8 without too much delay to avoid rebasing.


On Tue, Dec 05, 2023 at 04:08:04PM +0200, Laurent Pinchart wrote:
> The subdev .[gs]_frame_interval are video operations, but they operate
> on pads (and even on streams). Not only is this confusing, it causes
> practical issues for drivers as the operations don't receive a subdev
> state pointer, requiring manual state handling.
> 
> To improve the situation, turn the operations into pad operations, and
> extend them to receive a state pointer like other pad operations.
> 
> While at it, rename the operations to .[gs]et_frame_interval at the same
> time to match the naming scheme of other pad operations. This isn't
> strictly necessary, but given that all drivers using those operations
> need to be modified, handling the rename separately would generate more
> churn for very little gain (if at all).
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> # for imx-media
> ---
>  drivers/media/i2c/adv7180.c                   |  7 ++-
>  drivers/media/i2c/et8ek8/et8ek8_driver.c      |  6 +-
>  drivers/media/i2c/imx214.c                    |  9 +--
>  drivers/media/i2c/imx274.c                    | 48 +++++---------
>  drivers/media/i2c/max9286.c                   | 14 +++--
>  drivers/media/i2c/mt9m111.c                   | 14 +++--
>  drivers/media/i2c/mt9m114.c                   | 14 +++--
>  drivers/media/i2c/mt9v011.c                   | 18 +++---
>  drivers/media/i2c/mt9v111.c                   | 16 ++---
>  drivers/media/i2c/ov2680.c                    |  7 ++-
>  drivers/media/i2c/ov5640.c                    | 16 ++---
>  drivers/media/i2c/ov5648.c                    | 59 ++++++++---------
>  drivers/media/i2c/ov5693.c                    |  7 ++-
>  drivers/media/i2c/ov6650.c                    | 16 ++---
>  drivers/media/i2c/ov7251.c                    |  6 +-
>  drivers/media/i2c/ov7670.c                    | 18 +++---
>  drivers/media/i2c/ov772x.c                    | 14 +++--
>  drivers/media/i2c/ov7740.c                    | 40 +++++-------
>  drivers/media/i2c/ov8865.c                    | 51 +++++++--------
>  drivers/media/i2c/ov9650.c                    | 14 +++--
>  drivers/media/i2c/s5c73m3/s5c73m3-core.c      | 14 +++--
>  drivers/media/i2c/s5k5baf.c                   | 20 +++---
>  drivers/media/i2c/tvp514x.c                   | 29 +++------
>  drivers/media/usb/em28xx/em28xx-video.c       |  6 +-
>  drivers/media/v4l2-core/v4l2-common.c         |  8 +--
>  drivers/media/v4l2-core/v4l2-subdev.c         | 63 +++++++++++--------
>  .../media/atomisp/i2c/atomisp-gc0310.c        |  7 ++-
>  .../media/atomisp/i2c/atomisp-gc2235.c        |  7 ++-
>  .../media/atomisp/i2c/atomisp-mt9m114.c       |  7 ++-
>  .../media/atomisp/i2c/atomisp-ov2722.c        |  7 ++-
>  .../staging/media/atomisp/pci/atomisp_cmd.c   |  4 +-
>  .../staging/media/atomisp/pci/atomisp_ioctl.c |  4 +-
>  drivers/staging/media/imx/imx-ic-prp.c        | 14 +++--
>  drivers/staging/media/imx/imx-ic-prpencvf.c   | 14 +++--
>  drivers/staging/media/imx/imx-media-capture.c |  6 +-
>  drivers/staging/media/imx/imx-media-csi.c     | 14 +++--
>  drivers/staging/media/imx/imx-media-vdic.c    | 14 +++--
>  drivers/staging/media/tegra-video/csi.c       |  9 +--
>  include/media/v4l2-common.h                   |  4 +-
>  include/media/v4l2-subdev.h                   | 22 ++++---
>  40 files changed, 340 insertions(+), 327 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
> index e10811cce801..7ed86030fb5c 100644
> --- a/drivers/media/i2c/adv7180.c
> +++ b/drivers/media/i2c/adv7180.c
> @@ -463,8 +463,9 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
>  	return 0;
>  }
>  
> -static int adv7180_g_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *fi)
> +static int adv7180_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct adv7180_state *state = to_state(sd);
>  
> @@ -913,7 +914,6 @@ static int adv7180_subscribe_event(struct v4l2_subdev *sd,
>  static const struct v4l2_subdev_video_ops adv7180_video_ops = {
>  	.s_std = adv7180_s_std,
>  	.g_std = adv7180_g_std,
> -	.g_frame_interval = adv7180_g_frame_interval,
>  	.querystd = adv7180_querystd,
>  	.g_input_status = adv7180_g_input_status,
>  	.s_routing = adv7180_s_routing,
> @@ -932,6 +932,7 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
>  	.enum_mbus_code = adv7180_enum_mbus_code,
>  	.set_fmt = adv7180_set_pad_format,
>  	.get_fmt = adv7180_get_pad_format,
> +	.get_frame_interval = adv7180_get_frame_interval,
>  	.get_mbus_config = adv7180_get_mbus_config,
>  };
>  
> diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
> index 63616dc5a02f..71fb5aebd3df 100644
> --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
> +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
> @@ -1046,6 +1046,7 @@ static int et8ek8_set_pad_format(struct v4l2_subdev *subdev,
>  }
>  
>  static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
>  				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
> @@ -1057,6 +1058,7 @@ static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
>  }
>  
>  static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
>  				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
> @@ -1342,8 +1344,6 @@ static int et8ek8_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  
>  static const struct v4l2_subdev_video_ops et8ek8_video_ops = {
>  	.s_stream = et8ek8_s_stream,
> -	.g_frame_interval = et8ek8_get_frame_interval,
> -	.s_frame_interval = et8ek8_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_core_ops et8ek8_core_ops = {
> @@ -1356,6 +1356,8 @@ static const struct v4l2_subdev_pad_ops et8ek8_pad_ops = {
>  	.enum_frame_interval = et8ek8_enum_frame_ival,
>  	.get_fmt = et8ek8_get_pad_format,
>  	.set_fmt = et8ek8_set_pad_format,
> +	.get_frame_interval = et8ek8_get_frame_interval,
> +	.set_frame_interval = et8ek8_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops et8ek8_ops = {
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 474c95572bf6..624efc8834f3 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -795,8 +795,9 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
>  	return ret;
>  }
>  
> -static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
> -				   struct v4l2_subdev_frame_interval *fival)
> +static int imx214_get_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fival)
>  {
>  	fival->interval.numerator = 1;
>  	fival->interval.denominator = IMX214_FPS;
> @@ -828,8 +829,6 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
>  
>  static const struct v4l2_subdev_video_ops imx214_video_ops = {
>  	.s_stream = imx214_s_stream,
> -	.g_frame_interval = imx214_g_frame_interval,
> -	.s_frame_interval = imx214_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
> @@ -839,6 +838,8 @@ static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
>  	.get_fmt = imx214_get_format,
>  	.set_fmt = imx214_set_format,
>  	.get_selection = imx214_get_selection,
> +	.get_frame_interval = imx214_get_frame_interval,
> +	.set_frame_interval = imx214_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops imx214_subdev_ops = {
> diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
> index 8dc11c9ec1ee..4040c642a36f 100644
> --- a/drivers/media/i2c/imx274.c
> +++ b/drivers/media/i2c/imx274.c
> @@ -594,8 +594,8 @@ static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl);
>  static int imx274_set_exposure(struct stimx274 *priv, int val);
>  static int imx274_set_vflip(struct stimx274 *priv, int val);
>  static int imx274_set_test_pattern(struct stimx274 *priv, int val);
> -static int imx274_set_frame_interval(struct stimx274 *priv,
> -				     struct v4l2_fract frame_interval);
> +static int __imx274_set_frame_interval(struct stimx274 *priv,
> +				       struct v4l2_fract frame_interval);
>  
>  static inline void msleep_range(unsigned int delay_base)
>  {
> @@ -1327,17 +1327,9 @@ static int imx274_apply_trimming(struct stimx274 *imx274)
>  	return err;
>  }
>  
> -/**
> - * imx274_g_frame_interval - Get the frame interval
> - * @sd: Pointer to V4L2 Sub device structure
> - * @fi: Pointer to V4l2 Sub device frame interval structure
> - *
> - * This function is used to get the frame interval.
> - *
> - * Return: 0 on success
> - */
> -static int imx274_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int imx274_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct stimx274 *imx274 = to_imx274(sd);
>  
> @@ -1349,17 +1341,9 @@ static int imx274_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -/**
> - * imx274_s_frame_interval - Set the frame interval
> - * @sd: Pointer to V4L2 Sub device structure
> - * @fi: Pointer to V4l2 Sub device frame interval structure
> - *
> - * This function is used to set the frame intervavl.
> - *
> - * Return: 0 on success
> - */
> -static int imx274_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int imx274_set_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct stimx274 *imx274 = to_imx274(sd);
>  	struct v4l2_ctrl *ctrl = imx274->ctrls.exposure;
> @@ -1371,7 +1355,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd,
>  		return ret;
>  
>  	mutex_lock(&imx274->lock);
> -	ret = imx274_set_frame_interval(imx274, fi->interval);
> +	ret = __imx274_set_frame_interval(imx274, fi->interval);
>  
>  	if (!ret) {
>  		fi->interval = imx274->frame_interval;
> @@ -1466,8 +1450,8 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
>  		 * are changed.
>  		 * gain is not affected.
>  		 */
> -		ret = imx274_set_frame_interval(imx274,
> -						imx274->frame_interval);
> +		ret = __imx274_set_frame_interval(imx274,
> +						  imx274->frame_interval);
>  		if (ret)
>  			goto fail;
>  
> @@ -1830,7 +1814,7 @@ static int imx274_set_frame_length(struct stimx274 *priv, u32 val)
>  }
>  
>  /*
> - * imx274_set_frame_interval - Function called when setting frame interval
> + * __imx274_set_frame_interval - Function called when setting frame interval
>   * @priv: Pointer to device structure
>   * @frame_interval: Variable for frame interval
>   *
> @@ -1839,8 +1823,8 @@ static int imx274_set_frame_length(struct stimx274 *priv, u32 val)
>   *
>   * Return: 0 on success
>   */
> -static int imx274_set_frame_interval(struct stimx274 *priv,
> -				     struct v4l2_fract frame_interval)
> +static int __imx274_set_frame_interval(struct stimx274 *priv,
> +				       struct v4l2_fract frame_interval)
>  {
>  	int err;
>  	u32 frame_length, req_frame_rate;
> @@ -1927,11 +1911,11 @@ static const struct v4l2_subdev_pad_ops imx274_pad_ops = {
>  	.set_fmt = imx274_set_fmt,
>  	.get_selection = imx274_get_selection,
>  	.set_selection = imx274_set_selection,
> +	.get_frame_interval = imx274_get_frame_interval,
> +	.set_frame_interval = imx274_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_video_ops imx274_video_ops = {
> -	.g_frame_interval = imx274_g_frame_interval,
> -	.s_frame_interval = imx274_s_frame_interval,
>  	.s_stream = imx274_s_stream,
>  };
>  
> diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> index ee11ae682d8d..7e8cb53d31c3 100644
> --- a/drivers/media/i2c/max9286.c
> +++ b/drivers/media/i2c/max9286.c
> @@ -868,8 +868,9 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
>  	return 0;
>  }
>  
> -static int max9286_g_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *interval)
> +static int max9286_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct max9286_priv *priv = sd_to_max9286(sd);
>  
> @@ -881,8 +882,9 @@ static int max9286_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int max9286_s_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *interval)
> +static int max9286_set_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct max9286_priv *priv = sd_to_max9286(sd);
>  
> @@ -983,14 +985,14 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
>  
>  static const struct v4l2_subdev_video_ops max9286_video_ops = {
>  	.s_stream	= max9286_s_stream,
> -	.g_frame_interval = max9286_g_frame_interval,
> -	.s_frame_interval = max9286_s_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
>  	.enum_mbus_code = max9286_enum_mbus_code,
>  	.get_fmt	= max9286_get_fmt,
>  	.set_fmt	= max9286_set_fmt,
> +	.get_frame_interval = max9286_get_frame_interval,
> +	.set_frame_interval = max9286_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops max9286_subdev_ops = {
> diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> index 54a7a4c623ea..602954650f2e 100644
> --- a/drivers/media/i2c/mt9m111.c
> +++ b/drivers/media/i2c/mt9m111.c
> @@ -1045,8 +1045,9 @@ static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
>  #endif
>  };
>  
> -static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int mt9m111_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
>  
> @@ -1055,8 +1056,9 @@ static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int mt9m111_set_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
>  	const struct mt9m111_mode_info *mode;
> @@ -1151,8 +1153,6 @@ static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
>  
>  static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
>  	.s_stream	= mt9m111_s_stream,
> -	.g_frame_interval = mt9m111_g_frame_interval,
> -	.s_frame_interval = mt9m111_s_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
> @@ -1161,6 +1161,8 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
>  	.set_selection	= mt9m111_set_selection,
>  	.get_fmt	= mt9m111_get_fmt,
>  	.set_fmt	= mt9m111_set_fmt,
> +	.get_frame_interval = mt9m111_get_frame_interval,
> +	.set_frame_interval = mt9m111_set_frame_interval,
>  	.get_mbus_config = mt9m111_get_mbus_config,
>  };
>  
> diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c
> index 0a22f328981d..dcd94299787c 100644
> --- a/drivers/media/i2c/mt9m114.c
> +++ b/drivers/media/i2c/mt9m114.c
> @@ -1585,8 +1585,9 @@ static int mt9m114_ifp_s_stream(struct v4l2_subdev *sd, int enable)
>  	return ret;
>  }
>  
> -static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd,
> -					struct v4l2_subdev_frame_interval *interval)
> +static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd,
> +					  struct v4l2_subdev_state *sd_state,
> +					  struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct v4l2_fract *ival = &interval->interval;
>  	struct mt9m114 *sensor = ifp_to_mt9m114(sd);
> @@ -1601,8 +1602,9 @@ static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd,
> -					struct v4l2_subdev_frame_interval *interval)
> +static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd,
> +					  struct v4l2_subdev_state *sd_state,
> +					  struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct v4l2_fract *ival = &interval->interval;
>  	struct mt9m114 *sensor = ifp_to_mt9m114(sd);
> @@ -1967,8 +1969,6 @@ static int mt9m114_ifp_registered(struct v4l2_subdev *sd)
>  
>  static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = {
>  	.s_stream = mt9m114_ifp_s_stream,
> -	.g_frame_interval = mt9m114_ifp_g_frame_interval,
> -	.s_frame_interval = mt9m114_ifp_s_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = {
> @@ -1979,6 +1979,8 @@ static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = {
>  	.set_fmt = mt9m114_ifp_set_fmt,
>  	.get_selection = mt9m114_ifp_get_selection,
>  	.set_selection = mt9m114_ifp_set_selection,
> +	.get_frame_interval = mt9m114_ifp_get_frame_interval,
> +	.set_frame_interval = mt9m114_ifp_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops mt9m114_ifp_ops = {
> diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
> index d0924b4ac6fb..3485761428ba 100644
> --- a/drivers/media/i2c/mt9v011.c
> +++ b/drivers/media/i2c/mt9v011.c
> @@ -362,8 +362,9 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *ival)
> +static int mt9v011_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *ival)
>  {
>  	calc_fps(sd,
>  		 &ival->interval.numerator,
> @@ -372,8 +373,9 @@ static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int mt9v011_s_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *ival)
> +static int mt9v011_set_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct v4l2_fract *tpf = &ival->interval;
>  	u16 speed;
> @@ -455,19 +457,15 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
>  #endif
>  };
>  
> -static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
> -	.g_frame_interval = mt9v011_g_frame_interval,
> -	.s_frame_interval = mt9v011_s_frame_interval,
> -};
> -
>  static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = {
>  	.enum_mbus_code = mt9v011_enum_mbus_code,
>  	.set_fmt = mt9v011_set_fmt,
> +	.get_frame_interval = mt9v011_get_frame_interval,
> +	.set_frame_interval = mt9v011_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops mt9v011_ops = {
>  	.core  = &mt9v011_core_ops,
> -	.video = &mt9v011_video_ops,
>  	.pad   = &mt9v011_pad_ops,
>  };
>  
> diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c
> index b186e9160d94..496be67c971b 100644
> --- a/drivers/media/i2c/mt9v111.c
> +++ b/drivers/media/i2c/mt9v111.c
> @@ -35,7 +35,7 @@
>   * The IFP can produce several output image formats from the sensor core
>   * output. This driver currently supports only YUYV format permutations.
>   *
> - * The driver allows manual frame rate control through s_frame_interval subdev
> + * The driver allows manual frame rate control through set_frame_interval subdev
>   * operation or V4L2_CID_V/HBLANK controls, but it is known that the
>   * auto-exposure algorithm might modify the programmed frame rate. While the
>   * driver initially programs the sensor with auto-exposure and
> @@ -719,8 +719,9 @@ static int mt9v111_s_stream(struct v4l2_subdev *subdev, int enable)
>  	return ret;
>  }
>  
> -static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *ival)
> +static int mt9v111_set_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
>  	struct v4l2_fract *tpf = &ival->interval;
> @@ -771,8 +772,9 @@ static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int mt9v111_g_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *ival)
> +static int mt9v111_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
>  	struct v4l2_fract *tpf = &ival->interval;
> @@ -962,8 +964,6 @@ static const struct v4l2_subdev_core_ops mt9v111_core_ops = {
>  
>  static const struct v4l2_subdev_video_ops mt9v111_video_ops = {
>  	.s_stream		= mt9v111_s_stream,
> -	.s_frame_interval	= mt9v111_s_frame_interval,
> -	.g_frame_interval	= mt9v111_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops mt9v111_pad_ops = {
> @@ -972,6 +972,8 @@ static const struct v4l2_subdev_pad_ops mt9v111_pad_ops = {
>  	.enum_frame_interval	= mt9v111_enum_frame_interval,
>  	.get_fmt		= mt9v111_get_format,
>  	.set_fmt		= mt9v111_set_format,
> +	.get_frame_interval	= mt9v111_get_frame_interval,
> +	.set_frame_interval	= mt9v111_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops mt9v111_ops = {
> diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
> index d34d1972dcd9..e3ff64a9e6ca 100644
> --- a/drivers/media/i2c/ov2680.c
> +++ b/drivers/media/i2c/ov2680.c
> @@ -552,7 +552,8 @@ static int ov2680_power_on(struct ov2680_dev *sensor)
>  	return ret;
>  }
>  
> -static int ov2680_s_g_frame_interval(struct v4l2_subdev *sd,
> +static int ov2680_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
>  				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov2680_dev *sensor = to_ov2680_dev(sd);
> @@ -870,8 +871,6 @@ static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
>  };
>  
>  static const struct v4l2_subdev_video_ops ov2680_video_ops = {
> -	.g_frame_interval	= ov2680_s_g_frame_interval,
> -	.s_frame_interval	= ov2680_s_g_frame_interval,
>  	.s_stream		= ov2680_s_stream,
>  };
>  
> @@ -883,6 +882,8 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
>  	.set_fmt		= ov2680_set_fmt,
>  	.get_selection		= ov2680_get_selection,
>  	.set_selection		= ov2680_set_selection,
> +	.get_frame_interval	= ov2680_get_frame_interval,
> +	.set_frame_interval	= ov2680_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov2680_subdev_ops = {
> diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
> index 6fd98b8cb181..336bfd1ffd32 100644
> --- a/drivers/media/i2c/ov5640.c
> +++ b/drivers/media/i2c/ov5640.c
> @@ -399,7 +399,7 @@ struct ov5640_mode_info {
>  	const struct reg_value *reg_data;
>  	u32 reg_data_size;
>  
> -	/* Used by s_frame_interval only. */
> +	/* Used by set_frame_interval only. */
>  	u32 max_fps;
>  	u32 def_fps;
>  };
> @@ -3604,8 +3604,9 @@ static int ov5640_enum_frame_interval(
>  	return 0;
>  }
>  
> -static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int ov5640_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov5640_dev *sensor = to_ov5640_dev(sd);
>  
> @@ -3616,8 +3617,9 @@ static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int ov5640_set_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov5640_dev *sensor = to_ov5640_dev(sd);
>  	const struct ov5640_mode_info *mode;
> @@ -3770,8 +3772,6 @@ static const struct v4l2_subdev_core_ops ov5640_core_ops = {
>  };
>  
>  static const struct v4l2_subdev_video_ops ov5640_video_ops = {
> -	.g_frame_interval = ov5640_g_frame_interval,
> -	.s_frame_interval = ov5640_s_frame_interval,
>  	.s_stream = ov5640_s_stream,
>  };
>  
> @@ -3780,6 +3780,8 @@ static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
>  	.get_fmt = ov5640_get_fmt,
>  	.set_fmt = ov5640_set_fmt,
>  	.get_selection = ov5640_get_selection,
> +	.get_frame_interval = ov5640_get_frame_interval,
> +	.set_frame_interval = ov5640_set_frame_interval,
>  	.enum_frame_size = ov5640_enum_frame_size,
>  	.enum_frame_interval = ov5640_enum_frame_interval,
>  };
> diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c
> index 13e6060d15d4..d0d7e9968f48 100644
> --- a/drivers/media/i2c/ov5648.c
> +++ b/drivers/media/i2c/ov5648.c
> @@ -2158,37 +2158,8 @@ static int ov5648_s_stream(struct v4l2_subdev *subdev, int enable)
>  	return 0;
>  }
>  
> -static int ov5648_g_frame_interval(struct v4l2_subdev *subdev,
> -				   struct v4l2_subdev_frame_interval *interval)
> -{
> -	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
> -	const struct ov5648_mode *mode;
> -	int ret = 0;
> -
> -	mutex_lock(&sensor->mutex);
> -
> -	mode = sensor->state.mode;
> -
> -	switch (sensor->state.mbus_code) {
> -	case MEDIA_BUS_FMT_SBGGR8_1X8:
> -		interval->interval = mode->frame_interval[0];
> -		break;
> -	case MEDIA_BUS_FMT_SBGGR10_1X10:
> -		interval->interval = mode->frame_interval[1];
> -		break;
> -	default:
> -		ret = -EINVAL;
> -	}
> -
> -	mutex_unlock(&sensor->mutex);
> -
> -	return ret;
> -}
> -
>  static const struct v4l2_subdev_video_ops ov5648_subdev_video_ops = {
>  	.s_stream		= ov5648_s_stream,
> -	.g_frame_interval	= ov5648_g_frame_interval,
> -	.s_frame_interval	= ov5648_g_frame_interval,
>  };
>  
>  /* Subdev Pad Operations */
> @@ -2297,6 +2268,34 @@ static int ov5648_set_fmt(struct v4l2_subdev *subdev,
>  	return ret;
>  }
>  
> +static int ov5648_get_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *interval)
> +{
> +	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
> +	const struct ov5648_mode *mode;
> +	int ret = 0;
> +
> +	mutex_lock(&sensor->mutex);
> +
> +	mode = sensor->state.mode;
> +
> +	switch (sensor->state.mbus_code) {
> +	case MEDIA_BUS_FMT_SBGGR8_1X8:
> +		interval->interval = mode->frame_interval[0];
> +		break;
> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> +		interval->interval = mode->frame_interval[1];
> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	mutex_unlock(&sensor->mutex);
> +
> +	return ret;
> +}
> +
>  static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
>  				  struct v4l2_subdev_state *sd_state,
>  				  struct v4l2_subdev_frame_size_enum *size_enum)
> @@ -2363,6 +2362,8 @@ static const struct v4l2_subdev_pad_ops ov5648_subdev_pad_ops = {
>  	.enum_mbus_code		= ov5648_enum_mbus_code,
>  	.get_fmt		= ov5648_get_fmt,
>  	.set_fmt		= ov5648_set_fmt,
> +	.get_frame_interval	= ov5648_get_frame_interval,
> +	.set_frame_interval	= ov5648_get_frame_interval,
>  	.enum_frame_size	= ov5648_enum_frame_size,
>  	.enum_frame_interval	= ov5648_enum_frame_interval,
>  };
> diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
> index 205193baa06e..a65645811fbc 100644
> --- a/drivers/media/i2c/ov5693.c
> +++ b/drivers/media/i2c/ov5693.c
> @@ -1004,8 +1004,9 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
>  	return ret;
>  }
>  
> -static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *interval)
> +static int ov5693_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
>  	unsigned int framesize = OV5693_FIXED_PPL * (ov5693->mode.format.height +
> @@ -1054,7 +1055,6 @@ static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
>  
>  static const struct v4l2_subdev_video_ops ov5693_video_ops = {
>  	.s_stream = ov5693_s_stream,
> -	.g_frame_interval = ov5693_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
> @@ -1064,6 +1064,7 @@ static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
>  	.set_fmt = ov5693_set_fmt,
>  	.get_selection = ov5693_get_selection,
>  	.set_selection = ov5693_set_selection,
> +	.get_frame_interval = ov5693_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov5693_ops = {
> diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
> index bf1e7617ee08..a4dc45bdf3d7 100644
> --- a/drivers/media/i2c/ov6650.c
> +++ b/drivers/media/i2c/ov6650.c
> @@ -197,7 +197,7 @@ struct ov6650 {
>  	struct clk		*clk;
>  	bool			half_scale;	/* scale down output by 2 */
>  	struct v4l2_rect	rect;		/* sensor cropping window */
> -	struct v4l2_fract	tpf;		/* as requested with s_frame_interval */
> +	struct v4l2_fract	tpf;		/* as requested with set_frame_interval */
>  	u32 code;
>  };
>  
> @@ -799,8 +799,9 @@ static int ov6650_enum_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> +static int ov6650_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct i2c_client *client = v4l2_get_subdevdata(sd);
>  	struct ov6650 *priv = to_ov6650(client);
> @@ -813,8 +814,9 @@ static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> +static int ov6650_set_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct i2c_client *client = v4l2_get_subdevdata(sd);
>  	struct ov6650 *priv = to_ov6650(client);
> @@ -1006,8 +1008,6 @@ static int ov6650_get_mbus_config(struct v4l2_subdev *sd,
>  
>  static const struct v4l2_subdev_video_ops ov6650_video_ops = {
>  	.s_stream	= ov6650_s_stream,
> -	.g_frame_interval = ov6650_g_frame_interval,
> -	.s_frame_interval = ov6650_s_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
> @@ -1017,6 +1017,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
>  	.set_selection		= ov6650_set_selection,
>  	.get_fmt		= ov6650_get_fmt,
>  	.set_fmt		= ov6650_set_fmt,
> +	.get_frame_interval	= ov6650_get_frame_interval,
> +	.set_frame_interval	= ov6650_set_frame_interval,
>  	.get_mbus_config	= ov6650_get_mbus_config,
>  };
>  
> diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
> index 897a0763df4a..10d6b5deed83 100644
> --- a/drivers/media/i2c/ov7251.c
> +++ b/drivers/media/i2c/ov7251.c
> @@ -1386,6 +1386,7 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable)
>  }
>  
>  static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
>  				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov7251 *ov7251 = to_ov7251(subdev);
> @@ -1398,6 +1399,7 @@ static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
>  }
>  
>  static int ov7251_set_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
>  				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov7251 *ov7251 = to_ov7251(subdev);
> @@ -1436,8 +1438,6 @@ static int ov7251_set_frame_interval(struct v4l2_subdev *subdev,
>  
>  static const struct v4l2_subdev_video_ops ov7251_video_ops = {
>  	.s_stream = ov7251_s_stream,
> -	.g_frame_interval = ov7251_get_frame_interval,
> -	.s_frame_interval = ov7251_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = {
> @@ -1447,6 +1447,8 @@ static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = {
>  	.get_fmt = ov7251_get_format,
>  	.set_fmt = ov7251_set_format,
>  	.get_selection = ov7251_get_selection,
> +	.get_frame_interval = ov7251_get_frame_interval,
> +	.set_frame_interval = ov7251_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov7251_subdev_ops = {
> diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
> index 8164c0c433c5..463f20ece36e 100644
> --- a/drivers/media/i2c/ov7670.c
> +++ b/drivers/media/i2c/ov7670.c
> @@ -1154,8 +1154,9 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
>   * Implement G/S_PARM.  There is a "high quality" mode we could try
>   * to do someday; for now, we just do the frame rate tweak.
>   */
> -static int ov7670_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> +static int ov7670_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct ov7670_info *info = to_state(sd);
>  
> @@ -1165,8 +1166,9 @@ static int ov7670_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int ov7670_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> +static int ov7670_set_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct v4l2_fract *tpf = &ival->interval;
>  	struct ov7670_info *info = to_state(sd);
> @@ -1728,22 +1730,18 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
>  #endif
>  };
>  
> -static const struct v4l2_subdev_video_ops ov7670_video_ops = {
> -	.s_frame_interval = ov7670_s_frame_interval,
> -	.g_frame_interval = ov7670_g_frame_interval,
> -};
> -
>  static const struct v4l2_subdev_pad_ops ov7670_pad_ops = {
>  	.enum_frame_interval = ov7670_enum_frame_interval,
>  	.enum_frame_size = ov7670_enum_frame_size,
>  	.enum_mbus_code = ov7670_enum_mbus_code,
>  	.get_fmt = ov7670_get_fmt,
>  	.set_fmt = ov7670_set_fmt,
> +	.get_frame_interval = ov7670_get_frame_interval,
> +	.set_frame_interval = ov7670_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov7670_ops = {
>  	.core = &ov7670_core_ops,
> -	.video = &ov7670_video_ops,
>  	.pad = &ov7670_pad_ops,
>  };
>  
> diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
> index e397f7531e1d..a14a25946c5b 100644
> --- a/drivers/media/i2c/ov772x.c
> +++ b/drivers/media/i2c/ov772x.c
> @@ -717,8 +717,9 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
>  	return 0;
>  }
>  
> -static int ov772x_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> +static int ov772x_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct ov772x_priv *priv = to_ov772x(sd);
>  	struct v4l2_fract *tpf = &ival->interval;
> @@ -729,8 +730,9 @@ static int ov772x_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int ov772x_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> +static int ov772x_set_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct ov772x_priv *priv = to_ov772x(sd);
>  	struct v4l2_fract *tpf = &ival->interval;
> @@ -1349,8 +1351,6 @@ static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
>  
>  static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
>  	.s_stream		= ov772x_s_stream,
> -	.s_frame_interval	= ov772x_s_frame_interval,
> -	.g_frame_interval	= ov772x_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
> @@ -1359,6 +1359,8 @@ static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
>  	.get_selection		= ov772x_get_selection,
>  	.get_fmt		= ov772x_get_fmt,
>  	.set_fmt		= ov772x_set_fmt,
> +	.get_frame_interval	= ov772x_get_frame_interval,
> +	.set_frame_interval	= ov772x_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov772x_subdev_ops = {
> diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
> index 9c13ff5fe9fa..47b1b14d8796 100644
> --- a/drivers/media/i2c/ov7740.c
> +++ b/drivers/media/i2c/ov7740.c
> @@ -638,34 +638,8 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
>  	return ret;
>  }
>  
> -static int ov7740_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> -{
> -	struct v4l2_fract *tpf = &ival->interval;
> -
> -
> -	tpf->numerator = 1;
> -	tpf->denominator = 60;
> -
> -	return 0;
> -}
> -
> -static int ov7740_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *ival)
> -{
> -	struct v4l2_fract *tpf = &ival->interval;
> -
> -
> -	tpf->numerator = 1;
> -	tpf->denominator = 60;
> -
> -	return 0;
> -}
> -
>  static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
>  	.s_stream = ov7740_set_stream,
> -	.s_frame_interval = ov7740_s_frame_interval,
> -	.g_frame_interval = ov7740_g_frame_interval,
>  };
>  
>  static const struct reg_sequence ov7740_format_yuyv[] = {
> @@ -852,12 +826,26 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> +static int ov7740_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *ival)
> +{
> +	struct v4l2_fract *tpf = &ival->interval;
> +
> +	tpf->numerator = 1;
> +	tpf->denominator = 60;
> +
> +	return 0;
> +}
> +
>  static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
>  	.enum_frame_interval = ov7740_enum_frame_interval,
>  	.enum_frame_size = ov7740_enum_frame_size,
>  	.enum_mbus_code = ov7740_enum_mbus_code,
>  	.get_fmt = ov7740_get_fmt,
>  	.set_fmt = ov7740_set_fmt,
> +	.get_frame_interval = ov7740_get_frame_interval,
> +	.set_frame_interval = ov7740_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov7740_subdev_ops = {
> diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c
> index fb19ab0c2a9d..02a595281c49 100644
> --- a/drivers/media/i2c/ov8865.c
> +++ b/drivers/media/i2c/ov8865.c
> @@ -2640,33 +2640,8 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
>  	return 0;
>  }
>  
> -static int ov8865_g_frame_interval(struct v4l2_subdev *subdev,
> -				   struct v4l2_subdev_frame_interval *interval)
> -{
> -	struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
> -	const struct ov8865_mode *mode;
> -	unsigned int framesize;
> -	unsigned int fps;
> -
> -	mutex_lock(&sensor->mutex);
> -
> -	mode = sensor->state.mode;
> -	framesize = mode->hts * (mode->output_size_y +
> -				 sensor->ctrls.vblank->val);
> -	fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize);
> -
> -	interval->interval.numerator = 1;
> -	interval->interval.denominator = fps;
> -
> -	mutex_unlock(&sensor->mutex);
> -
> -	return 0;
> -}
> -
>  static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = {
>  	.s_stream		= ov8865_s_stream,
> -	.g_frame_interval	= ov8865_g_frame_interval,
> -	.s_frame_interval	= ov8865_g_frame_interval,
>  };
>  
>  /* Subdev Pad Operations */
> @@ -2862,6 +2837,30 @@ static int ov8865_get_selection(struct v4l2_subdev *subdev,
>  	return 0;
>  }
>  
> +static int ov8865_get_frame_interval(struct v4l2_subdev *subdev,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *interval)
> +{
> +	struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
> +	const struct ov8865_mode *mode;
> +	unsigned int framesize;
> +	unsigned int fps;
> +
> +	mutex_lock(&sensor->mutex);
> +
> +	mode = sensor->state.mode;
> +	framesize = mode->hts * (mode->output_size_y +
> +				 sensor->ctrls.vblank->val);
> +	fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize);
> +
> +	interval->interval.numerator = 1;
> +	interval->interval.denominator = fps;
> +
> +	mutex_unlock(&sensor->mutex);
> +
> +	return 0;
> +}
> +
>  static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = {
>  	.enum_mbus_code		= ov8865_enum_mbus_code,
>  	.get_fmt		= ov8865_get_fmt,
> @@ -2869,6 +2868,8 @@ static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = {
>  	.enum_frame_size	= ov8865_enum_frame_size,
>  	.get_selection		= ov8865_get_selection,
>  	.set_selection		= ov8865_get_selection,
> +	.get_frame_interval	= ov8865_get_frame_interval,
> +	.set_frame_interval	= ov8865_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov8865_subdev_ops = {
> diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
> index 753f6222102a..f528892c893f 100644
> --- a/drivers/media/i2c/ov9650.c
> +++ b/drivers/media/i2c/ov9650.c
> @@ -1101,8 +1101,9 @@ static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int ov965x_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int ov965x_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov965x *ov965x = to_ov965x(sd);
>  
> @@ -1148,8 +1149,9 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x,
>  	return 0;
>  }
>  
> -static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int ov965x_set_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct ov965x *ov965x = to_ov965x(sd);
>  	int ret;
> @@ -1373,12 +1375,12 @@ static const struct v4l2_subdev_pad_ops ov965x_pad_ops = {
>  	.enum_frame_size = ov965x_enum_frame_sizes,
>  	.get_fmt = ov965x_get_fmt,
>  	.set_fmt = ov965x_set_fmt,
> +	.get_frame_interval = ov965x_get_frame_interval,
> +	.set_frame_interval = ov965x_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_video_ops ov965x_video_ops = {
>  	.s_stream = ov965x_s_stream,
> -	.g_frame_interval = ov965x_g_frame_interval,
> -	.s_frame_interval = ov965x_s_frame_interval,
>  
>  };
>  
> diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> index 8f9b5713daf7..73ca50f49812 100644
> --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> @@ -866,8 +866,9 @@ static void s5c73m3_try_format(struct s5c73m3 *state,
>  	s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code);
>  }
>  
> -static int s5c73m3_oif_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int s5c73m3_oif_get_frame_interval(struct v4l2_subdev *sd,
> +					  struct v4l2_subdev_state *sd_state,
> +					  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
>  
> @@ -915,8 +916,9 @@ static int __s5c73m3_set_frame_interval(struct s5c73m3 *state,
>  	return 0;
>  }
>  
> -static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int s5c73m3_oif_set_frame_interval(struct v4l2_subdev *sd,
> +					  struct v4l2_subdev_state *sd_state,
> +					  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
>  	int ret;
> @@ -1497,6 +1499,8 @@ static const struct v4l2_subdev_pad_ops s5c73m3_oif_pad_ops = {
>  	.enum_frame_interval	= s5c73m3_oif_enum_frame_interval,
>  	.get_fmt		= s5c73m3_oif_get_fmt,
>  	.set_fmt		= s5c73m3_oif_set_fmt,
> +	.get_frame_interval	= s5c73m3_oif_get_frame_interval,
> +	.set_frame_interval	= s5c73m3_oif_set_frame_interval,
>  	.get_frame_desc		= s5c73m3_oif_get_frame_desc,
>  	.set_frame_desc		= s5c73m3_oif_set_frame_desc,
>  };
> @@ -1508,8 +1512,6 @@ static const struct v4l2_subdev_core_ops s5c73m3_oif_core_ops = {
>  
>  static const struct v4l2_subdev_video_ops s5c73m3_oif_video_ops = {
>  	.s_stream		= s5c73m3_oif_s_stream,
> -	.g_frame_interval	= s5c73m3_oif_g_frame_interval,
> -	.s_frame_interval	= s5c73m3_oif_s_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops oif_subdev_ops = {
> diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
> index 03ccfb0e1e11..2fd1ecfeb086 100644
> --- a/drivers/media/i2c/s5k5baf.c
> +++ b/drivers/media/i2c/s5k5baf.c
> @@ -1118,8 +1118,9 @@ static int s5k5baf_s_stream(struct v4l2_subdev *sd, int on)
>  	return ret;
>  }
>  
> -static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int s5k5baf_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct s5k5baf *state = to_s5k5baf(sd);
>  
> @@ -1131,8 +1132,8 @@ static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static void s5k5baf_set_frame_interval(struct s5k5baf *state,
> -				       struct v4l2_subdev_frame_interval *fi)
> +static void __s5k5baf_set_frame_interval(struct s5k5baf *state,
> +					 struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct v4l2_fract *i = &fi->interval;
>  
> @@ -1155,13 +1156,14 @@ static void s5k5baf_set_frame_interval(struct s5k5baf *state,
>  			  state->fiv);
>  }
>  
> -static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *fi)
> +static int s5k5baf_set_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct s5k5baf *state = to_s5k5baf(sd);
>  
>  	mutex_lock(&state->lock);
> -	s5k5baf_set_frame_interval(state, fi);
> +	__s5k5baf_set_frame_interval(state, fi);
>  	mutex_unlock(&state->lock);
>  	return 0;
>  }
> @@ -1526,11 +1528,11 @@ static const struct v4l2_subdev_pad_ops s5k5baf_pad_ops = {
>  	.set_fmt		= s5k5baf_set_fmt,
>  	.get_selection		= s5k5baf_get_selection,
>  	.set_selection		= s5k5baf_set_selection,
> +	.get_frame_interval	= s5k5baf_get_frame_interval,
> +	.set_frame_interval	= s5k5baf_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_video_ops s5k5baf_video_ops = {
> -	.g_frame_interval	= s5k5baf_g_frame_interval,
> -	.s_frame_interval	= s5k5baf_s_frame_interval,
>  	.s_stream		= s5k5baf_s_stream,
>  };
>  
> diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
> index c37f605cb75f..dee0cf992379 100644
> --- a/drivers/media/i2c/tvp514x.c
> +++ b/drivers/media/i2c/tvp514x.c
> @@ -738,16 +738,10 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
>  	return err;
>  }
>  
> -/**
> - * tvp514x_g_frame_interval() - V4L2 decoder interface handler
> - * @sd: pointer to standard V4L2 sub-device structure
> - * @ival: pointer to a v4l2_subdev_frame_interval structure
> - *
> - * Returns the decoder's video CAPTURE parameters.
> - */
>  static int
> -tvp514x_g_frame_interval(struct v4l2_subdev *sd,
> -			 struct v4l2_subdev_frame_interval *ival)
> +tvp514x_get_frame_interval(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_state *sd_state,
> +			   struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct tvp514x_decoder *decoder = to_decoder(sd);
>  	enum tvp514x_std current_std;
> @@ -762,17 +756,10 @@ tvp514x_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -/**
> - * tvp514x_s_frame_interval() - V4L2 decoder interface handler
> - * @sd: pointer to standard V4L2 sub-device structure
> - * @ival: pointer to a v4l2_subdev_frame_interval structure
> - *
> - * Configures the decoder to use the input parameters, if possible. If
> - * not possible, returns the appropriate error code.
> - */
>  static int
> -tvp514x_s_frame_interval(struct v4l2_subdev *sd,
> -			 struct v4l2_subdev_frame_interval *ival)
> +tvp514x_set_frame_interval(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_state *sd_state,
> +			   struct v4l2_subdev_frame_interval *ival)
>  {
>  	struct tvp514x_decoder *decoder = to_decoder(sd);
>  	struct v4l2_fract *timeperframe;
> @@ -940,8 +927,6 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
>  	.s_std = tvp514x_s_std,
>  	.s_routing = tvp514x_s_routing,
>  	.querystd = tvp514x_querystd,
> -	.g_frame_interval = tvp514x_g_frame_interval,
> -	.s_frame_interval = tvp514x_s_frame_interval,
>  	.s_stream = tvp514x_s_stream,
>  };
>  
> @@ -949,6 +934,8 @@ static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = {
>  	.enum_mbus_code = tvp514x_enum_mbus_code,
>  	.get_fmt = tvp514x_get_pad_format,
>  	.set_fmt = tvp514x_set_pad_format,
> +	.get_frame_interval = tvp514x_get_frame_interval,
> +	.set_frame_interval = tvp514x_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops tvp514x_ops = {
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 25e0620deff1..4aef584e21da 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -1607,7 +1607,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
>  	p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
>  	if (dev->is_webcam) {
>  		rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
> -						video, g_frame_interval, &ival);
> +						pad, get_frame_interval, NULL,
> +						&ival);
>  		if (!rc)
>  			p->parm.capture.timeperframe = ival.interval;
>  	} else {
> @@ -1639,7 +1640,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
>  	p->parm.capture.readbuffers = EM28XX_MIN_BUF;
>  	p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
>  	rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0,
> -					video, s_frame_interval, &ival);
> +					pad, set_frame_interval, NULL,
> +					&ival);
>  	if (!rc)
>  		p->parm.capture.timeperframe = ival.interval;
>  	return rc;
> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
> index e9e7e70fa24e..273d83de2a87 100644
> --- a/drivers/media/v4l2-core/v4l2-common.c
> +++ b/drivers/media/v4l2-core/v4l2-common.c
> @@ -195,9 +195,9 @@ int v4l2_g_parm_cap(struct video_device *vdev,
>  
>  	if (vdev->device_caps & V4L2_CAP_READWRITE)
>  		a->parm.capture.readbuffers = 2;
> -	if (v4l2_subdev_has_op(sd, video, g_frame_interval))
> +	if (v4l2_subdev_has_op(sd, pad, get_frame_interval))
>  		a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
> -	ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
> +	ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
>  	if (!ret)
>  		a->parm.capture.timeperframe = ival.interval;
>  	return ret;
> @@ -222,9 +222,9 @@ int v4l2_s_parm_cap(struct video_device *vdev,
>  	else
>  		a->parm.capture.readbuffers = 0;
>  
> -	if (v4l2_subdev_has_op(sd, video, g_frame_interval))
> +	if (v4l2_subdev_has_op(sd, pad, get_frame_interval))
>  		a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
> -	ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
> +	ret = v4l2_subdev_call_state_active(sd, pad, set_frame_interval, &ival);
>  	if (!ret)
>  		a->parm.capture.timeperframe = ival.interval;
>  	return ret;
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index 4fbefe4cd714..08c908988f7d 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -245,29 +245,6 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
>  	       sd->ops->pad->enum_frame_size(sd, state, fse);
>  }
>  
> -static inline int check_frame_interval(struct v4l2_subdev *sd,
> -				       struct v4l2_subdev_frame_interval *fi)
> -{
> -	if (!fi)
> -		return -EINVAL;
> -
> -	return check_pad(sd, fi->pad);
> -}
> -
> -static int call_g_frame_interval(struct v4l2_subdev *sd,
> -				 struct v4l2_subdev_frame_interval *fi)
> -{
> -	return check_frame_interval(sd, fi) ? :
> -	       sd->ops->video->g_frame_interval(sd, fi);
> -}
> -
> -static int call_s_frame_interval(struct v4l2_subdev *sd,
> -				 struct v4l2_subdev_frame_interval *fi)
> -{
> -	return check_frame_interval(sd, fi) ? :
> -	       sd->ops->video->s_frame_interval(sd, fi);
> -}
> -
>  static int call_enum_frame_interval(struct v4l2_subdev *sd,
>  				    struct v4l2_subdev_state *state,
>  				    struct v4l2_subdev_frame_interval_enum *fie)
> @@ -307,6 +284,34 @@ static int call_set_selection(struct v4l2_subdev *sd,
>  	       sd->ops->pad->set_selection(sd, state, sel);
>  }
>  
> +static inline int check_frame_interval(struct v4l2_subdev *sd,
> +				       struct v4l2_subdev_state *state,
> +				       struct v4l2_subdev_frame_interval *fi)
> +{
> +	if (!fi)
> +		return -EINVAL;
> +
> +	return check_pad(sd, fi->pad) ? :
> +	       check_state(sd, state, V4L2_SUBDEV_FORMAT_ACTIVE, fi->pad,
> +			   fi->stream);
> +}
> +
> +static int call_get_frame_interval(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *state,
> +				   struct v4l2_subdev_frame_interval *fi)
> +{
> +	return check_frame_interval(sd, state, fi) ? :
> +	       sd->ops->pad->get_frame_interval(sd, state, fi);
> +}
> +
> +static int call_set_frame_interval(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *state,
> +				   struct v4l2_subdev_frame_interval *fi)
> +{
> +	return check_frame_interval(sd, state, fi) ? :
> +	       sd->ops->pad->set_frame_interval(sd, state, fi);
> +}
> +
>  static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
>  			       struct v4l2_mbus_frame_desc *fd)
>  {
> @@ -479,6 +484,8 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
>  	.enum_frame_interval	= call_enum_frame_interval_state,
>  	.get_selection		= call_get_selection_state,
>  	.set_selection		= call_set_selection_state,
> +	.get_frame_interval	= call_get_frame_interval,
> +	.set_frame_interval	= call_set_frame_interval,
>  	.get_edid		= call_get_edid,
>  	.set_edid		= call_set_edid,
>  	.dv_timings_cap		= call_dv_timings_cap,
> @@ -488,8 +495,6 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
>  };
>  
>  static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
> -	.g_frame_interval	= call_g_frame_interval,
> -	.s_frame_interval	= call_s_frame_interval,
>  	.s_stream		= call_s_stream,
>  };
>  
> @@ -531,6 +536,10 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
>  	case VIDIOC_SUBDEV_S_SELECTION:
>  		which = ((struct v4l2_subdev_selection *)arg)->which;
>  		break;
> +	case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
> +	case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
> +		which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +		break;
>  	case VIDIOC_SUBDEV_G_ROUTING:
>  	case VIDIOC_SUBDEV_S_ROUTING:
>  		which = ((struct v4l2_subdev_routing *)arg)->which;
> @@ -781,7 +790,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
>  			fi->stream = 0;
>  
>  		memset(fi->reserved, 0, sizeof(fi->reserved));
> -		return v4l2_subdev_call(sd, video, g_frame_interval, arg);
> +		return v4l2_subdev_call(sd, pad, get_frame_interval, state, fi);
>  	}
>  
>  	case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
> @@ -794,7 +803,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
>  			fi->stream = 0;
>  
>  		memset(fi->reserved, 0, sizeof(fi->reserved));
> -		return v4l2_subdev_call(sd, video, s_frame_interval, arg);
> +		return v4l2_subdev_call(sd, pad, set_frame_interval, state, fi);
>  	}
>  
>  	case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
> diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
> index 5d89e4c1b0c2..006e8adac47b 100644
> --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
> +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
> @@ -496,8 +496,9 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
>  	return ret;
>  }
>  
> -static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *interval)
> +static int gc0310_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *interval)
>  {
>  	interval->interval.numerator = 1;
>  	interval->interval.denominator = GC0310_FPS;
> @@ -545,7 +546,6 @@ static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
>  
>  static const struct v4l2_subdev_video_ops gc0310_video_ops = {
>  	.s_stream = gc0310_s_stream,
> -	.g_frame_interval = gc0310_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
> @@ -553,6 +553,7 @@ static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
>  	.enum_frame_size = gc0310_enum_frame_size,
>  	.get_fmt = gc0310_get_fmt,
>  	.set_fmt = gc0310_set_fmt,
> +	.get_frame_interval = gc0310_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops gc0310_ops = {
> diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
> index 9c20fe915238..aa257322a700 100644
> --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
> +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
> @@ -698,8 +698,9 @@ static int gc2235_s_config(struct v4l2_subdev *sd,
>  	return ret;
>  }
>  
> -static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *interval)
> +static int gc2235_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct gc2235_device *dev = to_gc2235_sensor(sd);
>  
> @@ -754,7 +755,6 @@ static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = {
>  
>  static const struct v4l2_subdev_video_ops gc2235_video_ops = {
>  	.s_stream = gc2235_s_stream,
> -	.g_frame_interval = gc2235_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_core_ops gc2235_core_ops = {
> @@ -767,6 +767,7 @@ static const struct v4l2_subdev_pad_ops gc2235_pad_ops = {
>  	.enum_frame_size = gc2235_enum_frame_size,
>  	.get_fmt = gc2235_get_fmt,
>  	.set_fmt = gc2235_set_fmt,
> +	.get_frame_interval = gc2235_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops gc2235_ops = {
> diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
> index 8105365fbb2a..459c5b8233ce 100644
> --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
> +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
> @@ -1388,8 +1388,9 @@ static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value)
>  	return !!err;
>  }
>  
> -static int mt9m114_g_frame_interval(struct v4l2_subdev *sd,
> -				    struct v4l2_subdev_frame_interval *interval)
> +static int mt9m114_get_frame_interval(struct v4l2_subdev *sd,
> +				      struct v4l2_subdev_state *sd_state,
> +				      struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct mt9m114_device *dev = to_mt9m114_sensor(sd);
>  
> @@ -1479,7 +1480,6 @@ static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
>  
>  static const struct v4l2_subdev_video_ops mt9m114_video_ops = {
>  	.s_stream = mt9m114_s_stream,
> -	.g_frame_interval = mt9m114_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = {
> @@ -1498,6 +1498,7 @@ static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = {
>  	.get_fmt = mt9m114_get_fmt,
>  	.set_fmt = mt9m114_set_fmt,
>  	.set_selection = mt9m114_s_exposure_selection,
> +	.get_frame_interval = mt9m114_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops mt9m114_ops = {
> diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
> index 1de63c82cce1..b3ef04d7ccca 100644
> --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
> +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
> @@ -845,8 +845,9 @@ static int ov2722_s_config(struct v4l2_subdev *sd,
>  	return ret;
>  }
>  
> -static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
> -				   struct v4l2_subdev_frame_interval *interval)
> +static int ov2722_get_frame_interval(struct v4l2_subdev *sd,
> +				     struct v4l2_subdev_state *sd_state,
> +				     struct v4l2_subdev_frame_interval *interval)
>  {
>  	struct ov2722_device *dev = to_ov2722_sensor(sd);
>  
> @@ -901,7 +902,6 @@ static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = {
>  
>  static const struct v4l2_subdev_video_ops ov2722_video_ops = {
>  	.s_stream = ov2722_s_stream,
> -	.g_frame_interval = ov2722_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_core_ops ov2722_core_ops = {
> @@ -914,6 +914,7 @@ static const struct v4l2_subdev_pad_ops ov2722_pad_ops = {
>  	.enum_frame_size = ov2722_enum_frame_size,
>  	.get_fmt = ov2722_get_fmt,
>  	.set_fmt = ov2722_set_fmt,
> +	.get_frame_interval = ov2722_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops ov2722_ops = {
> diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
> index 759233a7ba50..f44e6412f4e3 100644
> --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
> +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
> @@ -105,8 +105,8 @@ static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd)
>  	unsigned short fps = 0;
>  	int ret;
>  
> -	ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
> -			       video, g_frame_interval, &fi);
> +	ret = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
> +					    pad, get_frame_interval, &fi);
>  
>  	if (!ret && fi.interval.numerator)
>  		fps = fi.interval.denominator / fi.interval.numerator;
> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
> index 09c0091b920f..01b7fa9b56a2 100644
> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
> @@ -1739,8 +1739,8 @@ static int atomisp_s_parm(struct file *file, void *fh,
>  
>  		fi.interval = parm->parm.capture.timeperframe;
>  
> -		rval = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
> -					video, s_frame_interval, &fi);
> +		rval = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
> +						     pad, set_frame_interval, &fi);
>  		if (!rval)
>  			parm->parm.capture.timeperframe = fi.interval;
>  
> diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
> index 8bd9be49cc08..fb96f87e664e 100644
> --- a/drivers/staging/media/imx/imx-ic-prp.c
> +++ b/drivers/staging/media/imx/imx-ic-prp.c
> @@ -393,8 +393,9 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
>  	return ret;
>  }
>  
> -static int prp_g_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int prp_get_frame_interval(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct prp_priv *priv = sd_to_priv(sd);
>  
> @@ -408,8 +409,9 @@ static int prp_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int prp_s_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int prp_set_frame_interval(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct prp_priv *priv = sd_to_priv(sd);
>  
> @@ -451,12 +453,12 @@ static const struct v4l2_subdev_pad_ops prp_pad_ops = {
>  	.enum_mbus_code = prp_enum_mbus_code,
>  	.get_fmt = prp_get_fmt,
>  	.set_fmt = prp_set_fmt,
> +	.get_frame_interval = prp_get_frame_interval,
> +	.set_frame_interval = prp_set_frame_interval,
>  	.link_validate = prp_link_validate,
>  };
>  
>  static const struct v4l2_subdev_video_ops prp_video_ops = {
> -	.g_frame_interval = prp_g_frame_interval,
> -	.s_frame_interval = prp_s_frame_interval,
>  	.s_stream = prp_s_stream,
>  };
>  
> diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
> index 04878f07eeba..7bfe433cd322 100644
> --- a/drivers/staging/media/imx/imx-ic-prpencvf.c
> +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
> @@ -1203,8 +1203,9 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
>  	return ret;
>  }
>  
> -static int prp_g_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int prp_get_frame_interval(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct prp_priv *priv = sd_to_priv(sd);
>  
> @@ -1218,8 +1219,9 @@ static int prp_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int prp_s_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int prp_set_frame_interval(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct prp_priv *priv = sd_to_priv(sd);
>  
> @@ -1300,11 +1302,11 @@ static const struct v4l2_subdev_pad_ops prp_pad_ops = {
>  	.enum_frame_size = prp_enum_frame_size,
>  	.get_fmt = prp_get_fmt,
>  	.set_fmt = prp_set_fmt,
> +	.get_frame_interval = prp_get_frame_interval,
> +	.set_frame_interval = prp_set_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_video_ops prp_video_ops = {
> -	.g_frame_interval = prp_g_frame_interval,
> -	.s_frame_interval = prp_s_frame_interval,
>  	.s_stream = prp_s_stream,
>  };
>  
> diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
> index ce02199e7b1b..c944fb131b0a 100644
> --- a/drivers/staging/media/imx/imx-media-capture.c
> +++ b/drivers/staging/media/imx/imx-media-capture.c
> @@ -511,7 +511,8 @@ static int capture_legacy_g_parm(struct file *file, void *fh,
>  	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>  		return -EINVAL;
>  
> -	ret = v4l2_subdev_call(priv->src_sd, video, g_frame_interval, &fi);
> +	ret = v4l2_subdev_call_state_active(priv->src_sd, pad,
> +					    get_frame_interval, &fi);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -534,7 +535,8 @@ static int capture_legacy_s_parm(struct file *file, void *fh,
>  		return -EINVAL;
>  
>  	fi.interval = a->parm.capture.timeperframe;
> -	ret = v4l2_subdev_call(priv->src_sd, video, s_frame_interval, &fi);
> +	ret = v4l2_subdev_call_state_active(priv->src_sd, pad,
> +					    set_frame_interval, &fi);
>  	if (ret < 0)
>  		return ret;
>  
> diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
> index 2fc94011fe4d..4308fdc9b58e 100644
> --- a/drivers/staging/media/imx/imx-media-csi.c
> +++ b/drivers/staging/media/imx/imx-media-csi.c
> @@ -902,8 +902,9 @@ static const struct csi_skip_desc *csi_find_best_skip(struct v4l2_fract *in,
>   * V4L2 subdev operations.
>   */
>  
> -static int csi_g_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int csi_get_frame_interval(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct csi_priv *priv = v4l2_get_subdevdata(sd);
>  
> @@ -919,8 +920,9 @@ static int csi_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int csi_s_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int csi_set_frame_interval(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct csi_priv *priv = v4l2_get_subdevdata(sd);
>  	struct v4l2_fract *input_fi;
> @@ -1860,8 +1862,6 @@ static const struct v4l2_subdev_core_ops csi_core_ops = {
>  };
>  
>  static const struct v4l2_subdev_video_ops csi_video_ops = {
> -	.g_frame_interval = csi_g_frame_interval,
> -	.s_frame_interval = csi_s_frame_interval,
>  	.s_stream = csi_s_stream,
>  };
>  
> @@ -1873,6 +1873,8 @@ static const struct v4l2_subdev_pad_ops csi_pad_ops = {
>  	.set_fmt = csi_set_fmt,
>  	.get_selection = csi_get_selection,
>  	.set_selection = csi_set_selection,
> +	.get_frame_interval = csi_get_frame_interval,
> +	.set_frame_interval = csi_set_frame_interval,
>  	.link_validate = csi_link_validate,
>  };
>  
> diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
> index 810b38ea3ab9..a51b37679239 100644
> --- a/drivers/staging/media/imx/imx-media-vdic.c
> +++ b/drivers/staging/media/imx/imx-media-vdic.c
> @@ -780,8 +780,9 @@ static int vdic_link_validate(struct v4l2_subdev *sd,
>  	return ret;
>  }
>  
> -static int vdic_g_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int vdic_get_frame_interval(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *sd_state,
> +				   struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
>  
> @@ -797,8 +798,9 @@ static int vdic_g_frame_interval(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int vdic_s_frame_interval(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *fi)
> +static int vdic_set_frame_interval(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *sd_state,
> +				   struct v4l2_subdev_frame_interval *fi)
>  {
>  	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
>  	struct v4l2_fract *input_fi, *output_fi;
> @@ -885,12 +887,12 @@ static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
>  	.enum_mbus_code = vdic_enum_mbus_code,
>  	.get_fmt = vdic_get_fmt,
>  	.set_fmt = vdic_set_fmt,
> +	.get_frame_interval = vdic_get_frame_interval,
> +	.set_frame_interval = vdic_set_frame_interval,
>  	.link_validate = vdic_link_validate,
>  };
>  
>  static const struct v4l2_subdev_video_ops vdic_video_ops = {
> -	.g_frame_interval = vdic_g_frame_interval,
> -	.s_frame_interval = vdic_s_frame_interval,
>  	.s_stream = vdic_s_stream,
>  };
>  
> diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> index 0d94115b9bbb..b1b666179be5 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -222,8 +222,9 @@ static int csi_set_format(struct v4l2_subdev *subdev,
>  /*
>   * V4L2 Subdevice Video Operations
>   */
> -static int tegra_csi_g_frame_interval(struct v4l2_subdev *subdev,
> -				      struct v4l2_subdev_frame_interval *vfi)
> +static int tegra_csi_get_frame_interval(struct v4l2_subdev *subdev,
> +					struct v4l2_subdev_state *sd_state,
> +					struct v4l2_subdev_frame_interval *vfi)
>  {
>  	struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
>  
> @@ -430,8 +431,6 @@ static int tegra_csi_s_stream(struct v4l2_subdev *subdev, int enable)
>   */
>  static const struct v4l2_subdev_video_ops tegra_csi_video_ops = {
>  	.s_stream = tegra_csi_s_stream,
> -	.g_frame_interval = tegra_csi_g_frame_interval,
> -	.s_frame_interval = tegra_csi_g_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
> @@ -440,6 +439,8 @@ static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
>  	.enum_frame_interval	= csi_enum_frameintervals,
>  	.get_fmt		= csi_get_format,
>  	.set_fmt		= csi_set_format,
> +	.get_frame_interval	= tegra_csi_get_frame_interval,
> +	.set_frame_interval	= tegra_csi_get_frame_interval,
>  };
>  
>  static const struct v4l2_subdev_ops tegra_csi_ops = {
> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
> index d278836fd9cb..acf5be24a5ca 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -425,7 +425,7 @@ __v4l2_find_nearest_size(const void *array, size_t array_size,
>  
>  /**
>   * v4l2_g_parm_cap - helper routine for vidioc_g_parm to fill this in by
> - *      calling the g_frame_interval op of the given subdev. It only works
> + *      calling the get_frame_interval op of the given subdev. It only works
>   *      for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
>   *      function name.
>   *
> @@ -438,7 +438,7 @@ int v4l2_g_parm_cap(struct video_device *vdev,
>  
>  /**
>   * v4l2_s_parm_cap - helper routine for vidioc_s_parm to fill this in by
> - *      calling the s_frame_interval op of the given subdev. It only works
> + *      calling the set_frame_interval op of the given subdev. It only works
>   *      for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
>   *      function name.
>   *
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 8b08f6640dee..b2dbaa739afa 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -452,12 +452,6 @@ enum v4l2_subdev_pre_streamon_flags {
>   *
>   * @g_pixelaspect: callback to return the pixelaspect ratio.
>   *
> - * @g_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
> - *		      ioctl handler code.
> - *
> - * @s_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
> - *		      ioctl handler code.
> - *
>   * @s_dv_timings: Set custom dv timings in the sub device. This is used
>   *	when sub device is capable of setting detailed timing information
>   *	in the hardware to generate/detect the video signal.
> @@ -496,10 +490,6 @@ struct v4l2_subdev_video_ops {
>  	int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
>  	int (*s_stream)(struct v4l2_subdev *sd, int enable);
>  	int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect);
> -	int (*g_frame_interval)(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *interval);
> -	int (*s_frame_interval)(struct v4l2_subdev *sd,
> -				struct v4l2_subdev_frame_interval *interval);
>  	int (*s_dv_timings)(struct v4l2_subdev *sd,
>  			struct v4l2_dv_timings *timings);
>  	int (*g_dv_timings)(struct v4l2_subdev *sd,
> @@ -787,6 +777,12 @@ struct v4l2_subdev_state {
>   *
>   * @set_selection: callback for VIDIOC_SUBDEV_S_SELECTION() ioctl handler code.
>   *
> + * @get_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
> + *			ioctl handler code.
> + *
> + * @set_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
> + *			ioctl handler code.
> + *
>   * @get_edid: callback for VIDIOC_SUBDEV_G_EDID() ioctl handler code.
>   *
>   * @set_edid: callback for VIDIOC_SUBDEV_S_EDID() ioctl handler code.
> @@ -856,6 +852,12 @@ struct v4l2_subdev_pad_ops {
>  	int (*set_selection)(struct v4l2_subdev *sd,
>  			     struct v4l2_subdev_state *state,
>  			     struct v4l2_subdev_selection *sel);
> +	int (*get_frame_interval)(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *state,
> +				  struct v4l2_subdev_frame_interval *interval);
> +	int (*set_frame_interval)(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *state,
> +				  struct v4l2_subdev_frame_interval *interval);
>  	int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
>  	int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
>  	int (*dv_timings_cap)(struct v4l2_subdev *sd,
> 
> base-commit: bec3db03911bd85da29c1c8ee556162153002c9a
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> 

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state
  2023-12-05 14:08 ` [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state Laurent Pinchart
@ 2023-12-06  1:00   ` kernel test robot
  2023-12-06  3:06   ` kernel test robot
  1 sibling, 0 replies; 12+ messages in thread
From: kernel test robot @ 2023-12-06  1:00 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: oe-kbuild-all

Hi Laurent,

kernel test robot noticed the following build errors:

[auto build test ERROR on bec3db03911bd85da29c1c8ee556162153002c9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Laurent-Pinchart/media-v4l2-subdev-Add-which-field-to-struct-v4l2_subdev_frame_interval/20231205-220946
base:   bec3db03911bd85da29c1c8ee556162153002c9a
patch link:    https://lore.kernel.org/r/20231205140810.22368-3-laurent.pinchart%40ideasonboard.com
patch subject: [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state
config: x86_64-randconfig-002-20231206 (https://download.01.org/0day-ci/archive/20231206/202312060829.GmtNe4FB-lkp@intel.com/config)
compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231206/202312060829.GmtNe4FB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312060829.GmtNe4FB-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from include/media/v4l2-device.h:13:0,
                    from drivers/media/v4l2-core/v4l2-subdev.c:24:
   drivers/media/v4l2-core/v4l2-subdev.c: In function 'v4l2_subdev_get_frame_interval':
   include/media/v4l2-subdev.h:1577:9: error: implicit declaration of function '__v4l2_subdev_state_get_interval___VA_OPT__'; did you mean '__v4l2_subdev_state_get_interval_'? [-Werror=implicit-function-declaration]
            __v4l2_subdev_state_get_interval_ ## __VA_OPT__(stream) \
            ^
   include/media/v4l2-subdev.h:1577:9: note: in definition of macro 'v4l2_subdev_state_get_interval'
            __v4l2_subdev_state_get_interval_ ## __VA_OPT__(stream) \
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> include/media/v4l2-subdev.h:1577:57: error: 'stream' undeclared (first use in this function); did you mean 'strim'?
            __v4l2_subdev_state_get_interval_ ## __VA_OPT__(stream) \
                                                            ^
   drivers/media/v4l2-core/v4l2-subdev.c:1762:13: note: in expansion of macro 'v4l2_subdev_state_get_interval'
     interval = v4l2_subdev_state_get_interval(state, fi->pad, fi->stream);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/media/v4l2-subdev.h:1577:57: note: each undeclared identifier is reported only once for each function it appears in
            __v4l2_subdev_state_get_interval_ ## __VA_OPT__(stream) \
                                                            ^
   drivers/media/v4l2-core/v4l2-subdev.c:1762:13: note: in expansion of macro 'v4l2_subdev_state_get_interval'
     interval = v4l2_subdev_state_get_interval(state, fi->pad, fi->stream);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> include/media/v4l2-subdev.h:1578:21: error: expected ')' before '__VA_OPT__'
            (state, pad __VA_OPT__(,) __VA_ARGS__)
                        ^
   drivers/media/v4l2-core/v4l2-subdev.c:1762:13: note: in expansion of macro 'v4l2_subdev_state_get_interval'
     interval = v4l2_subdev_state_get_interval(state, fi->pad, fi->stream);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +1577 include/media/v4l2-subdev.h

  1483	
  1484	/**
  1485	 * v4l2_subdev_get_fmt() - Fill format based on state
  1486	 * @sd: subdevice
  1487	 * @state: subdevice state
  1488	 * @format: pointer to &struct v4l2_subdev_format
  1489	 *
  1490	 * Fill @format->format field based on the information in the @format struct.
  1491	 *
  1492	 * This function can be used by the subdev drivers which support active state to
  1493	 * implement v4l2_subdev_pad_ops.get_fmt if the subdev driver does not need to
  1494	 * do anything special in their get_fmt op.
  1495	 *
  1496	 * Returns 0 on success, error value otherwise.
  1497	 */
  1498	int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
  1499				struct v4l2_subdev_format *format);
  1500	
  1501	/**
  1502	 * v4l2_subdev_get_frame_interval() - Fill frame interval based on state
  1503	 * @sd: subdevice
  1504	 * @state: subdevice state
  1505	 * @fi: pointer to &struct v4l2_subdev_frame_interval
  1506	 *
  1507	 * Fill @fi->interval field based on the information in the @fi struct.
  1508	 *
  1509	 * This function can be used by the subdev drivers which support active state to
  1510	 * implement v4l2_subdev_pad_ops.get_frame_interval if the subdev driver does
  1511	 * not need to do anything special in their get_frame_interval op.
  1512	 *
  1513	 * Returns 0 on success, error value otherwise.
  1514	 */
  1515	int v4l2_subdev_get_frame_interval(struct v4l2_subdev *sd,
  1516					   struct v4l2_subdev_state *state,
  1517					   struct v4l2_subdev_frame_interval *fi);
  1518	
  1519	/**
  1520	 * v4l2_subdev_set_routing() - Set given routing to subdev state
  1521	 * @sd: The subdevice
  1522	 * @state: The subdevice state
  1523	 * @routing: Routing that will be copied to subdev state
  1524	 *
  1525	 * This will release old routing table (if any) from the state, allocate
  1526	 * enough space for the given routing, and copy the routing.
  1527	 *
  1528	 * This can be used from the subdev driver's set_routing op, after validating
  1529	 * the routing.
  1530	 */
  1531	int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
  1532				    struct v4l2_subdev_state *state,
  1533				    const struct v4l2_subdev_krouting *routing);
  1534	
  1535	struct v4l2_subdev_route *
  1536	__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing,
  1537					struct v4l2_subdev_route *route);
  1538	
  1539	/**
  1540	 * for_each_active_route - iterate on all active routes of a routing table
  1541	 * @routing: The routing table
  1542	 * @route: The route iterator
  1543	 */
  1544	#define for_each_active_route(routing, route) \
  1545		for ((route) = NULL;                  \
  1546		     ((route) = __v4l2_subdev_next_active_route((routing), (route)));)
  1547	
  1548	/**
  1549	 * v4l2_subdev_set_routing_with_fmt() - Set given routing and format to subdev
  1550	 *					state
  1551	 * @sd: The subdevice
  1552	 * @state: The subdevice state
  1553	 * @routing: Routing that will be copied to subdev state
  1554	 * @fmt: Format used to initialize all the streams
  1555	 *
  1556	 * This is the same as v4l2_subdev_set_routing, but additionally initializes
  1557	 * all the streams using the given format.
  1558	 */
  1559	int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
  1560					     struct v4l2_subdev_state *state,
  1561					     const struct v4l2_subdev_krouting *routing,
  1562					     const struct v4l2_mbus_framefmt *fmt);
  1563	
  1564	/**
  1565	 * v4l2_subdev_state_get_interval() - Get pointer to a stream frame interval
  1566	 * @state: subdevice state
  1567	 * @pad: pad id
  1568	 * @...: stream id (optional argument)
  1569	 *
  1570	 * This returns a pointer to the frame interval for the given pad + stream in
  1571	 * the subdev state.
  1572	 *
  1573	 * For stream-unaware drivers the frame interval for the corresponding pad is
  1574	 * returned. If the pad does not exist, NULL is returned.
  1575	 */
  1576	#define v4l2_subdev_state_get_interval(state, pad, ...)         \
> 1577	        __v4l2_subdev_state_get_interval_ ## __VA_OPT__(stream) \
> 1578	        (state, pad __VA_OPT__(,) __VA_ARGS__)
  1579	#define __v4l2_subdev_state_get_interval_(state, pad)	\
  1580	        __v4l2_subdev_state_get_interval(state, pad, 0)
  1581	#define __v4l2_subdev_state_get_interval_stream(state, pad, stream)	\
  1582	        __v4l2_subdev_state_get_interval(state, pad, stream)
  1583	struct v4l2_fract *
  1584	__v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
  1585					 unsigned int pad, u32 stream);
  1586	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state
  2023-12-05 14:08 ` [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state Laurent Pinchart
  2023-12-06  1:00   ` kernel test robot
@ 2023-12-06  3:06   ` kernel test robot
  1 sibling, 0 replies; 12+ messages in thread
From: kernel test robot @ 2023-12-06  3:06 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: llvm, oe-kbuild-all

Hi Laurent,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bec3db03911bd85da29c1c8ee556162153002c9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Laurent-Pinchart/media-v4l2-subdev-Add-which-field-to-struct-v4l2_subdev_frame_interval/20231205-220946
base:   bec3db03911bd85da29c1c8ee556162153002c9a
patch link:    https://lore.kernel.org/r/20231205140810.22368-3-laurent.pinchart%40ideasonboard.com
patch subject: [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state
config: arm-aspeed_g4_defconfig (https://download.01.org/0day-ci/archive/20231206/202312061141.SrudvARf-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231206/202312061141.SrudvARf-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312061141.SrudvARf-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/media/v4l2-core/v4l2-subdev.c:21:
   In file included from include/linux/videodev2.h:61:
   include/uapi/linux/videodev2.h:1809:2: warning: field  within 'struct v4l2_ext_control' is less aligned than 'union v4l2_ext_control::(anonymous at include/uapi/linux/videodev2.h:1809:2)' and is usually due to 'struct v4l2_ext_control' being packed, which can lead to unaligned accesses [-Wunaligned-access]
    1809 |         union {
         |         ^
>> drivers/media/v4l2-core/v4l2-subdev.c:1655:1: warning: no previous prototype for function '__v4l2_subdev_state_get_interval' [-Wmissing-prototypes]
    1655 | __v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
         | ^
   drivers/media/v4l2-core/v4l2-subdev.c:1654:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
    1654 | struct v4l2_fract *
         | ^
         | static 
   2 warnings generated.


vim +/__v4l2_subdev_state_get_interval +1655 drivers/media/v4l2-core/v4l2-subdev.c

  1653	
  1654	struct v4l2_fract *
> 1655	__v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
  1656					 unsigned int pad, u32 stream)
  1657	{
  1658		struct v4l2_subdev_stream_configs *stream_configs;
  1659		unsigned int i;
  1660	
  1661		if (WARN_ON(!state))
  1662			return NULL;
  1663	
  1664		lockdep_assert_held(state->lock);
  1665	
  1666		if (state->pads) {
  1667			if (stream)
  1668				return NULL;
  1669	
  1670			if (pad >= state->sd->entity.num_pads)
  1671				return NULL;
  1672	
  1673			return &state->pads[pad].interval;
  1674		}
  1675	
  1676		lockdep_assert_held(state->lock);
  1677	
  1678		stream_configs = &state->stream_configs;
  1679	
  1680		for (i = 0; i < stream_configs->num_configs; ++i) {
  1681			if (stream_configs->configs[i].pad == pad &&
  1682			    stream_configs->configs[i].stream == stream)
  1683				return &stream_configs->configs[i].interval;
  1684		}
  1685	
  1686		return NULL;
  1687	}
  1688	EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_interval);
  1689	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations
  2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
                   ` (6 preceding siblings ...)
  2023-12-05 14:11 ` [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
@ 2023-12-06  3:52 ` kernel test robot
  7 siblings, 0 replies; 12+ messages in thread
From: kernel test robot @ 2023-12-06  3:52 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: oe-kbuild-all

Hi Laurent,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bec3db03911bd85da29c1c8ee556162153002c9a]

url:    https://github.com/intel-lab-lkp/linux/commits/Laurent-Pinchart/media-v4l2-subdev-Add-which-field-to-struct-v4l2_subdev_frame_interval/20231205-220946
base:   bec3db03911bd85da29c1c8ee556162153002c9a
patch link:    https://lore.kernel.org/r/20231205140810.22368-1-laurent.pinchart%40ideasonboard.com
patch subject: [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations
config: arm-randconfig-r052-20231206 (https://download.01.org/0day-ci/archive/20231206/202312061101.PLrz5NnJ-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231206/202312061101.PLrz5NnJ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312061101.PLrz5NnJ-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/media/v4l2-device.h:13,
                    from drivers/media/v4l2-core/v4l2-common.c:47:
   drivers/media/v4l2-core/v4l2-common.c: In function 'v4l2_g_parm_cap':
   include/media/v4l2-subdev.h:1805:25: error: implicit declaration of function 'v4l2_subdev_get_unlocked_active_state' [-Werror=implicit-function-declaration]
    1805 |                 state = v4l2_subdev_get_unlocked_active_state(sd);      \
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/v4l2-core/v4l2-common.c:200:15: note: in expansion of macro 'v4l2_subdev_call_state_active'
     200 |         ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> include/media/v4l2-subdev.h:1805:23: warning: assignment to 'struct v4l2_subdev_state *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
    1805 |                 state = v4l2_subdev_get_unlocked_active_state(sd);      \
         |                       ^
   drivers/media/v4l2-core/v4l2-common.c:200:15: note: in expansion of macro 'v4l2_subdev_call_state_active'
     200 |         ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/media/v4l2-subdev.h:1807:25: error: implicit declaration of function 'v4l2_subdev_lock_state'; did you mean 'v4l2_subdev_notify'? [-Werror=implicit-function-declaration]
    1807 |                         v4l2_subdev_lock_state(state);                  \
         |                         ^~~~~~~~~~~~~~~~~~~~~~
   drivers/media/v4l2-core/v4l2-common.c:200:15: note: in expansion of macro 'v4l2_subdev_call_state_active'
     200 |         ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/media/v4l2-subdev.h:1810:25: error: implicit declaration of function 'v4l2_subdev_unlock_state' [-Werror=implicit-function-declaration]
    1810 |                         v4l2_subdev_unlock_state(state);                \
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/v4l2-core/v4l2-common.c:200:15: note: in expansion of macro 'v4l2_subdev_call_state_active'
     200 |         ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/v4l2-core/v4l2-common.c: In function 'v4l2_s_parm_cap':
>> include/media/v4l2-subdev.h:1805:23: warning: assignment to 'struct v4l2_subdev_state *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
    1805 |                 state = v4l2_subdev_get_unlocked_active_state(sd);      \
         |                       ^
   drivers/media/v4l2-core/v4l2-common.c:227:15: note: in expansion of macro 'v4l2_subdev_call_state_active'
     227 |         ret = v4l2_subdev_call_state_active(sd, pad, set_frame_interval, &ival);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +1805 include/media/v4l2-subdev.h

a8fa55078a7784 Janusz Krzysztofik    2019-05-20  1753  
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1754  /**
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1755   * v4l2_subdev_call - call an operation of a v4l2_subdev.
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1756   *
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1757   * @sd: pointer to the &struct v4l2_subdev
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1758   * @o: name of the element at &struct v4l2_subdev_ops that contains @f.
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1759   *     Each element there groups a set of callbacks functions.
aab7b7d19d038c Wolfram Sang          2019-11-10  1760   * @f: callback function to be called.
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1761   *     The callback functions are defined in groups, according to
02679876b74d26 Mauro Carvalho Chehab 2017-12-19  1762   *     each element at &struct v4l2_subdev_ops.
60d70d75c12db7 Jonathan Neuschäfer   2020-02-27  1763   * @args: arguments for @f.
21c29de1d09048 Mauro Carvalho Chehab 2016-07-20  1764   *
21c29de1d09048 Mauro Carvalho Chehab 2016-07-20  1765   * Example: err = v4l2_subdev_call(sd, video, s_std, norm);
2a1fcdf0823052 Hans Verkuil          2008-11-29  1766   */
2a1fcdf0823052 Hans Verkuil          2008-11-29  1767  #define v4l2_subdev_call(sd, o, f, args...)				\
da48c948c263c9 Arnd Bergmann         2017-07-19  1768  	({								\
3d769df5fc32dc Hans Verkuil          2019-02-08  1769  		struct v4l2_subdev *__sd = (sd);			\
da48c948c263c9 Arnd Bergmann         2017-07-19  1770  		int __result;						\
3d769df5fc32dc Hans Verkuil          2019-02-08  1771  		if (!__sd)						\
da48c948c263c9 Arnd Bergmann         2017-07-19  1772  			__result = -ENODEV;				\
3d769df5fc32dc Hans Verkuil          2019-02-08  1773  		else if (!(__sd->ops->o && __sd->ops->o->f))		\
da48c948c263c9 Arnd Bergmann         2017-07-19  1774  			__result = -ENOIOCTLCMD;			\
a8fa55078a7784 Janusz Krzysztofik    2019-05-20  1775  		else if (v4l2_subdev_call_wrappers.o &&			\
a8fa55078a7784 Janusz Krzysztofik    2019-05-20  1776  			 v4l2_subdev_call_wrappers.o->f)		\
a8fa55078a7784 Janusz Krzysztofik    2019-05-20  1777  			__result = v4l2_subdev_call_wrappers.o->f(	\
a8fa55078a7784 Janusz Krzysztofik    2019-05-20  1778  							__sd, ##args);	\
da48c948c263c9 Arnd Bergmann         2017-07-19  1779  		else							\
3d769df5fc32dc Hans Verkuil          2019-02-08  1780  			__result = __sd->ops->o->f(__sd, ##args);	\
da48c948c263c9 Arnd Bergmann         2017-07-19  1781  		__result;						\
da48c948c263c9 Arnd Bergmann         2017-07-19  1782  	})
2a1fcdf0823052 Hans Verkuil          2008-11-29  1783  
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1784  /**
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1785   * v4l2_subdev_call_state_active - call an operation of a v4l2_subdev which
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1786   *				   takes state as a parameter, passing the
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1787   *				   subdev its active state.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1788   *
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1789   * @sd: pointer to the &struct v4l2_subdev
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1790   * @o: name of the element at &struct v4l2_subdev_ops that contains @f.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1791   *     Each element there groups a set of callbacks functions.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1792   * @f: callback function to be called.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1793   *     The callback functions are defined in groups, according to
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1794   *     each element at &struct v4l2_subdev_ops.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1795   * @args: arguments for @f.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1796   *
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1797   * This is similar to v4l2_subdev_call(), except that this version can only be
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1798   * used for ops that take a subdev state as a parameter. The macro will get the
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1799   * active state, lock it before calling the op and unlock it after the call.
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1800   */
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1801  #define v4l2_subdev_call_state_active(sd, o, f, args...)		\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1802  	({								\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1803  		int __result;						\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1804  		struct v4l2_subdev_state *state;			\
ed647ea668fb27 Tomi Valkeinen        2022-04-12 @1805  		state = v4l2_subdev_get_unlocked_active_state(sd);	\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1806  		if (state)						\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1807  			v4l2_subdev_lock_state(state);			\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1808  		__result = v4l2_subdev_call(sd, o, f, state, ##args);	\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1809  		if (state)						\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1810  			v4l2_subdev_unlock_state(state);		\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1811  		__result;						\
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1812  	})
ed647ea668fb27 Tomi Valkeinen        2022-04-12  1813  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval
  2023-12-05 14:08 ` [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval Laurent Pinchart
@ 2023-12-06  8:58   ` Hans Verkuil
  0 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2023-12-06  8:58 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media
  Cc: Akinobu Mita, Andrzej Hajda, Daniel Scally, Hans de Goede,
	Jacopo Mondi, Jonathan Hunter, Kieran Bingham, Lars-Peter Clausen,
	Leon Luo, Luca Ceresoli, Mauro Carvalho Chehab,
	Niklas Söderlund, Paul Elder, Pavel Machek, Philipp Zabel,
	Ricardo Ribalda, Rui Miguel Silva, Sakari Ailus,
	Sowjanya Komatineni, Steve Longerbeam, Sylwester Nawrocki,
	Thierry Reding, Tomi Valkeinen, linux-tegra

On 05/12/2023 15:08, Laurent Pinchart wrote:
> Due to a historical mishap, the v4l2_subdev_frame_interval structure
> is the only part of the V4L2 subdev userspace API that doesn't contain a
> 'which' field. This prevents trying frame intervals using the subdev
> 'TRY' state mechanism.
> 
> Adding a 'which' field is simple as the structure has 8 reserved fields.
> This would however break userspace as the field is currently set to 0,
> corresponding to V4L2_SUBDEV_FORMAT_TRY, while the corresponding ioctls
> currently operate on the 'ACTIVE' state. We thus need to add a new
> subdev client cap, V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL, to indicate
> that userspace is aware of this new field.
> 
> All drivers that implement the subdev .get_frame_interval() and
> .set_frame_interval() operations are updated to return -EINVAL when
> operating on the TRY state, preserving the current behaviour.
> 
> While at it, fix a bad copy&paste in the documentation of the struct
> v4l2_subdev_frame_interval_enum 'which' field.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> # for imx-media
> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
>  .../media/v4l/vidioc-subdev-g-client-cap.rst  |  5 ++++
>  .../v4l/vidioc-subdev-g-frame-interval.rst    | 17 ++++++++-----
>  drivers/media/i2c/adv7180.c                   |  3 +++
>  drivers/media/i2c/et8ek8/et8ek8_driver.c      |  6 +++++
>  drivers/media/i2c/imx214.c                    |  3 +++
>  drivers/media/i2c/imx274.c                    |  6 +++++
>  drivers/media/i2c/max9286.c                   |  6 +++++
>  drivers/media/i2c/mt9m111.c                   |  6 +++++
>  drivers/media/i2c/mt9m114.c                   |  6 +++++
>  drivers/media/i2c/mt9v011.c                   |  6 +++++
>  drivers/media/i2c/mt9v111.c                   |  6 +++++
>  drivers/media/i2c/ov2680.c                    |  3 +++
>  drivers/media/i2c/ov5640.c                    |  6 +++++
>  drivers/media/i2c/ov5648.c                    |  3 +++
>  drivers/media/i2c/ov5693.c                    |  3 +++
>  drivers/media/i2c/ov6650.c                    |  6 +++++
>  drivers/media/i2c/ov7251.c                    |  6 +++++
>  drivers/media/i2c/ov7670.c                    |  4 +++
>  drivers/media/i2c/ov772x.c                    |  6 +++++
>  drivers/media/i2c/ov8865.c                    |  3 +++
>  drivers/media/i2c/ov9650.c                    |  6 +++++
>  drivers/media/i2c/s5c73m3/s5c73m3-core.c      |  6 +++++
>  drivers/media/i2c/s5k5baf.c                   |  6 +++++
>  drivers/media/i2c/tvp514x.c                   |  4 +++
>  drivers/media/v4l2-core/v4l2-subdev.c         | 25 ++++++++++++-------
>  .../media/atomisp/i2c/atomisp-gc0310.c        |  3 +++
>  .../media/atomisp/i2c/atomisp-gc2235.c        |  3 +++
>  .../media/atomisp/i2c/atomisp-mt9m114.c       |  3 +++
>  .../media/atomisp/i2c/atomisp-ov2722.c        |  3 +++
>  drivers/staging/media/imx/imx-ic-prp.c        |  6 +++++
>  drivers/staging/media/imx/imx-ic-prpencvf.c   |  6 +++++
>  drivers/staging/media/imx/imx-media-csi.c     |  6 +++++
>  drivers/staging/media/imx/imx-media-vdic.c    |  6 +++++
>  drivers/staging/media/tegra-video/csi.c       |  3 +++
>  include/uapi/linux/v4l2-subdev.h              | 13 ++++++++--
>  35 files changed, 192 insertions(+), 17 deletions(-)
> 

<snip>

> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index f0fbb4a7c150..cc2717f734e7 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -116,13 +116,15 @@ struct v4l2_subdev_frame_size_enum {
>   * @pad: pad number, as reported by the media API
>   * @interval: frame interval in seconds
>   * @stream: stream number, defined in subdev routing
> + * @which: interval type (from enum v4l2_subdev_format_whence)
>   * @reserved: drivers and applications must zero this array
>   */
>  struct v4l2_subdev_frame_interval {
>  	__u32 pad;
>  	struct v4l2_fract interval;
>  	__u32 stream;
> -	__u32 reserved[8];
> +	__u32 which;
> +	__u32 reserved[7];
>  };
>  
>  /**
> @@ -133,7 +135,7 @@ struct v4l2_subdev_frame_interval {
>   * @width: frame width in pixels
>   * @height: frame height in pixels
>   * @interval: frame interval in seconds
> - * @which: format type (from enum v4l2_subdev_format_whence)
> + * @which: interval type (from enum v4l2_subdev_format_whence)
>   * @stream: stream number, defined in subdev routing
>   * @reserved: drivers and applications must zero this array
>   */
> @@ -241,6 +243,13 @@ struct v4l2_subdev_routing {
>   */
>  #define V4L2_SUBDEV_CLIENT_CAP_STREAMS		(1ULL << 0)
>  
> +/*
> + * The client is aware of the struct v4l2_subdev_frame_interval which field. If
> + * this is not set (which is the default), the which field is forced to
> + * V4L2_SUBDEV_FORMAT_ACTIVE by the kernel.
> + */
> +#define V4L2_SUBDEV_CLIENT_CAP_WHICH_INTERVAL	(1U << 1)

1U -> 1ULL

I also think that the define should be renamed to _CAP_INTERVAL_WHICH.
I keep reading "WHICH_INTERVAL" as "Which interval?" :-)

Also, you generally first put the structure before the field name,
so INTERVAL_WHICH feels much more logical to me.

Or possibly: INTERVAL_USES_WHICH, which is even more descriptive.

Regards,

	Hans

> +
>  /**
>   * struct v4l2_subdev_client_capability - Capabilities of the client accessing
>   *					  the subdev


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-12-06  8:58 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-05 14:08 [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
2023-12-05 14:08 ` [PATCH v3 2/7] media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval Laurent Pinchart
2023-12-06  8:58   ` Hans Verkuil
2023-12-05 14:08 ` [PATCH v3 3/7] media: v4l2-subdev: Store frame interval in subdev state Laurent Pinchart
2023-12-06  1:00   ` kernel test robot
2023-12-06  3:06   ` kernel test robot
2023-12-05 14:08 ` [PATCH v3 4/7] media: docs: uAPI: Clarify error documentation for invalid 'which' value Laurent Pinchart
2023-12-05 14:08 ` [PATCH v3 5/7] media: docs: uAPI: Expand " Laurent Pinchart
2023-12-05 14:08 ` [PATCH v3 6/7] media: docs: uAPI: Fix documentation of 'which' field for routing ioctls Laurent Pinchart
2023-12-05 14:08 ` [PATCH v3 7/7] media: i2c: thp7312: Store frame interval in subdev state Laurent Pinchart
2023-12-05 14:11 ` [PATCH v3 1/7] media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations Laurent Pinchart
2023-12-06  3:52 ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.