diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..186749d31abf 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -121,53 +121,17 @@ static int subdev_close(struct file *file)
 }
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
-			struct v4l2_subdev_format *format)
+void *v4l2_subdev_call_va_arg(int n, ...)
 {
-	if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
-
-	if (format->pad >= sd->entity.num_pads)
-		return -EINVAL;
-
-	return 0;
-}
-
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
-{
-	if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
-
-	if (crop->pad >= sd->entity.num_pads)
-		return -EINVAL;
-
-	return 0;
-}
-
-static int check_selection(struct v4l2_subdev *sd,
-			   struct v4l2_subdev_selection *sel)
-{
-	if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
-
-	if (sel->pad >= sd->entity.num_pads)
-		return -EINVAL;
-
-	return 0;
-}
-
-static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
-{
-	if (edid->pad >= sd->entity.num_pads)
-		return -EINVAL;
-
-	if (edid->blocks && edid->edid == NULL)
-		return -EINVAL;
-
-	return 0;
+	va_list ap;
+	int i;
+	void *p;
+
+	va_start(ap, n);
+	for (i = 9; i < n; i++)
+		p = va_arg(ap, void *);
+	va_end(ap);
+	return p;
 }
 #endif
 
@@ -292,10 +256,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_G_FMT: {
 		struct v4l2_subdev_format *format = arg;
 
-		rval = check_format(sd, format);
-		if (rval)
-			return rval;
-
 		memset(format->reserved, 0, sizeof(format->reserved));
 		memset(format->format.reserved, 0, sizeof(format->format.reserved));
 		return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
@@ -304,10 +264,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_S_FMT: {
 		struct v4l2_subdev_format *format = arg;
 
-		rval = check_format(sd, format);
-		if (rval)
-			return rval;
-
 		memset(format->reserved, 0, sizeof(format->reserved));
 		memset(format->format.reserved, 0, sizeof(format->format.reserved));
 		return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
@@ -317,10 +273,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		struct v4l2_subdev_crop *crop = arg;
 		struct v4l2_subdev_selection sel;
 
-		rval = check_crop(sd, crop);
-		if (rval)
-			return rval;
-
 		memset(crop->reserved, 0, sizeof(crop->reserved));
 		memset(&sel, 0, sizeof(sel));
 		sel.which = crop->which;
@@ -340,10 +292,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		struct v4l2_subdev_selection sel;
 
 		memset(crop->reserved, 0, sizeof(crop->reserved));
-		rval = check_crop(sd, crop);
-		if (rval)
-			return rval;
-
 		memset(&sel, 0, sizeof(sel));
 		sel.which = crop->which;
 		sel.pad = crop->pad;
@@ -361,13 +309,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
 		struct v4l2_subdev_mbus_code_enum *code = arg;
 
-		if (code->which != V4L2_SUBDEV_FORMAT_TRY &&
-		    code->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-			return -EINVAL;
-
-		if (code->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		memset(code->reserved, 0, sizeof(code->reserved));
 		return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
 					code);
@@ -376,13 +317,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
 		struct v4l2_subdev_frame_size_enum *fse = arg;
 
-		if (fse->which != V4L2_SUBDEV_FORMAT_TRY &&
-		    fse->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-			return -EINVAL;
-
-		if (fse->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		memset(fse->reserved, 0, sizeof(fse->reserved));
 		return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
 					fse);
@@ -391,9 +325,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
 		struct v4l2_subdev_frame_interval *fi = arg;
 
-		if (fi->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		memset(fi->reserved, 0, sizeof(fi->reserved));
 		return v4l2_subdev_call(sd, video, g_frame_interval, arg);
 	}
@@ -401,9 +332,6 @@ 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 (fi->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		memset(fi->reserved, 0, sizeof(fi->reserved));
 		return v4l2_subdev_call(sd, video, s_frame_interval, arg);
 	}
@@ -411,13 +339,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
 		struct v4l2_subdev_frame_interval_enum *fie = arg;
 
-		if (fie->which != V4L2_SUBDEV_FORMAT_TRY &&
-		    fie->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-			return -EINVAL;
-
-		if (fie->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		memset(fie->reserved, 0, sizeof(fie->reserved));
 		return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
 					fie);
@@ -426,10 +347,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_G_SELECTION: {
 		struct v4l2_subdev_selection *sel = arg;
 
-		rval = check_selection(sd, sel);
-		if (rval)
-			return rval;
-
 		memset(sel->reserved, 0, sizeof(sel->reserved));
 		return v4l2_subdev_call(
 			sd, pad, get_selection, subdev_fh->pad, sel);
@@ -438,10 +355,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_SUBDEV_S_SELECTION: {
 		struct v4l2_subdev_selection *sel = arg;
 
-		rval = check_selection(sd, sel);
-		if (rval)
-			return rval;
-
 		memset(sel->reserved, 0, sizeof(sel->reserved));
 		return v4l2_subdev_call(
 			sd, pad, set_selection, subdev_fh->pad, sel);
@@ -450,38 +363,24 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_G_EDID: {
 		struct v4l2_subdev_edid *edid = arg;
 
-		rval = check_edid(sd, edid);
-		if (rval)
-			return rval;
-
 		return v4l2_subdev_call(sd, pad, get_edid, edid);
 	}
 
 	case VIDIOC_S_EDID: {
 		struct v4l2_subdev_edid *edid = arg;
 
-		rval = check_edid(sd, edid);
-		if (rval)
-			return rval;
-
 		return v4l2_subdev_call(sd, pad, set_edid, edid);
 	}
 
 	case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {
 		struct v4l2_dv_timings_cap *cap = arg;
 
-		if (cap->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
 	}
 
 	case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {
 		struct v4l2_enum_dv_timings *dvt = arg;
 
-		if (dvt->pad >= sd->entity.num_pads)
-			return -EINVAL;
-
 		return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt);
 	}
 
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index a7fa5b80915a..a0ad8c6f588b 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -1091,6 +1091,82 @@ void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg);
 void v4l2_subdev_init(struct v4l2_subdev *sd,
 		      const struct v4l2_subdev_ops *ops);
 
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+void *v4l2_subdev_call_va_arg(int n, ...);
+
+#define v4l2_subdev_call_chk_args(sd, o, f, args...)			\
+({									\
+	__u32 __which = V4L2_SUBDEV_FORMAT_ACTIVE;			\
+	__u32 __pad = 0;						\
+	if ((void *)&sd->ops->o == &sd->ops->pad) {			\
+		if ((void *)&sd->ops->o->f == &sd->ops->pad->get_fmt ||	\
+		    (void *)&sd->ops->o->f == &sd->ops->pad->set_fmt) {	\
+			struct v4l2_subdev_format *__fmt;		\
+			__fmt = v4l2_subdev_call_va_arg(2, ##args);	\
+			__which = __fmt->which;				\
+			__pad = __fmt->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->enum_mbus_code) {	\
+			struct v4l2_subdev_mbus_code_enum *__code;	\
+			__code = v4l2_subdev_call_va_arg(2, ##args);	\
+			__which = __code->which;			\
+			__pad = __code->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->enum_frame_size) {	\
+			struct v4l2_subdev_frame_size_enum *__fse;	\
+			__fse = v4l2_subdev_call_va_arg(2, ##args);	\
+			__which = __fse->which;				\
+			__pad = __fse->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->enum_frame_interval) {\
+			struct v4l2_subdev_frame_interval_enum *__fie;	\
+			__fie = v4l2_subdev_call_va_arg(2, ##args);	\
+			__which = __fie->which;				\
+			__pad = __fie->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->get_selection ||	\
+			   (void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->set_selection) {	\
+			struct v4l2_subdev_selection *__sel;		\
+			__sel = v4l2_subdev_call_va_arg(2, ##args);	\
+			__which = __sel->which;				\
+			__pad = __sel->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->get_edid ||		\
+			   (void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->set_edid) {		\
+			struct v4l2_subdev_edid *__edid;		\
+			__edid = v4l2_subdev_call_va_arg(1, ##args);	\
+			__pad = __edid->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->dv_timings_cap) {	\
+			struct v4l2_dv_timings_cap *__cap;		\
+			__cap = v4l2_subdev_call_va_arg(1, ##args);	\
+			__pad = __cap->pad;				\
+		} else if ((void *)&sd->ops->o->f ==			\
+				   &sd->ops->pad->enum_dv_timings) {	\
+			struct v4l2_enum_dv_timings *__dvt;		\
+			__dvt = v4l2_subdev_call_va_arg(1, ##args);	\
+			__pad = __dvt->pad;				\
+		}							\
+	} else if ((void *)&sd->ops->o == &sd->ops->video) {		\
+		if ((void *)&sd->ops->o->f ==				\
+			    &sd->ops->video->g_frame_interval ||	\
+		    (void *)&sd->ops->o->f ==				\
+			    &sd->ops->video->s_frame_interval) {	\
+			struct v4l2_subdev_frame_interval *__fi;	\
+			__fi = v4l2_subdev_call_va_arg(1, ##args);	\
+			__pad = __fi->pad;				\
+		}							\
+	}								\
+	(__which == V4L2_SUBDEV_FORMAT_ACTIVE ||			\
+	 __which == V4L2_SUBDEV_FORMAT_TRY) &&				\
+	__pad < (sd->entity.num_pads ? : 1) ? 0 : -EINVAL;		\
+})
+#else
+#define v4l2_subdev_call_chk_args(sd, o, f, args...) 0
+#endif
+
 /**
  * v4l2_subdev_call - call an operation of a v4l2_subdev.
  *
@@ -1112,6 +1188,9 @@ void v4l2_subdev_init(struct v4l2_subdev *sd,
 			__result = -ENODEV;				\
 		else if (!(__sd->ops->o && __sd->ops->o->f))		\
 			__result = -ENOIOCTLCMD;			\
+		else if (v4l2_subdev_call_chk_args(sd, o, f, ##args))	\
+			__result = v4l2_subdev_call_chk_args(sd, o, f,	\
+							     ##args);	\
 		else							\
 			__result = __sd->ops->o->f(__sd, ##args);	\
 		__result;						\
