diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index f4be2a1..efc20bf 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -37,8 +37,11 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-of.h>
+#if 0
 #include <media/videobuf-core.h>
 #include <media/videobuf2-core.h>
+#endif
+#include <media/v4l2-mediabus.h>
 
 /* Default to VGA resolution */
 #define DEFAULT_WIDTH	640
@@ -453,6 +456,98 @@ static int soc_camera_expbuf(struct file *file, void *priv,
 		return vb2_expbuf(&icd->vb2_vidq, p);
 }
 
+static int soc_camera_init_user_formats_pad(struct soc_camera_device *icd, int src_pad_idx)
+{
+	struct v4l2_subdev *sd= soc_camera_to_subdev(icd);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct v4l2_subdev_mbus_code_enum code;
+	int fmts= 0, raw_fmts, i, ret;
+
+	code.pad= src_pad_idx;
+	code.index= 0;
+
+	// subdev_has_op -> enum_mbus_code vs enum_mbus_fmt
+	if (v4l2_subdev_has_op(sd, pad, enum_mbus_code)) {
+		while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code))
+			code.index++;
+	} else {
+		u32 pixcode;
+
+		while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, code.index, &pixcode))
+		{
+			code.code= pixcode;
+			code.index++;
+		}
+	}
+	raw_fmts= code.index;
+
+	if (!ici->ops->get_formats) {
+		/*
+		 * Fallback mode - the host will have to serve all
+		 * sensor-provided formats one-to-one to the user
+		 */
+		fmts = raw_fmts;
+	}
+	else {
+		/*
+		 * First pass - only count formats this host-sensor
+		 * configuration can provide
+		 */
+		for (i = 0; i < raw_fmts; i++) {
+			int ret = ici->ops->get_formats(icd, i, NULL);
+			if (ret < 0)
+				return ret;
+			fmts += ret;
+		}
+	}
+
+	if (!fmts)
+		return -ENXIO;
+
+	icd->user_formats =
+		vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+	if (!icd->user_formats)
+		return -ENOMEM;
+
+	dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
+
+	/* Second pass - actually fill data formats */
+	fmts = 0;
+	for (i = 0; i < raw_fmts; i++) {
+		if (!ici->ops->get_formats) {
+			code.index= i;
+			// subdev_has_op -> enum_mbus_code vs enum_mbus_fmt
+			if (v4l2_subdev_has_op(sd, pad, enum_mbus_code)) {
+				v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code);
+			} else {
+				u32 pixcode;
+
+				v4l2_subdev_call(sd, video, enum_mbus_fmt, code.index, &pixcode);
+				code.code= pixcode;
+			}
+			icd->user_formats[fmts].host_fmt =
+				soc_mbus_get_fmtdesc(code.code);
+			if (icd->user_formats[fmts].host_fmt)
+				icd->user_formats[fmts++].code = code.code;
+		} else {
+			ret = ici->ops->get_formats(icd, i,
+						    &icd->user_formats[fmts]);
+			if (ret < 0)
+				goto egfmt;
+			fmts += ret;
+		}
+	}
+
+	icd->num_user_formats = fmts;
+	icd->current_fmt = &icd->user_formats[0];
+
+	return 0;
+
+egfmt:
+	vfree(icd->user_formats);
+	return ret;
+}
+
 /* Always entered with .host_lock held */
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
@@ -1289,6 +1384,7 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd)
 {
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct v4l2_mbus_framefmt mf;
+	int src_pad_idx= -1;
 	int ret;
 
 	sd->grp_id = soc_camera_grp_id(icd);
@@ -1307,7 +1403,30 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd)
 	}
 
 	/* At this point client .probe() should have run already */
-	ret = soc_camera_init_user_formats(icd);
+	// subdev_has_op -> enum_mbus_code vs enum_mbus_fmt
+	if (!v4l2_subdev_has_op(sd, pad, enum_mbus_code))
+		ret = soc_camera_init_user_formats(icd);
+	else {
+		ret = media_entity_init(&icd->vdev->entity, 1,
+					&icd->pad, 0);
+		if (!ret) {
+			for (src_pad_idx= 0; src_pad_idx < sd->entity.num_pads; src_pad_idx++)
+				if (sd->entity.pads[src_pad_idx].flags == MEDIA_PAD_FL_SOURCE)
+					break;
+
+			if (src_pad_idx < sd->entity.num_pads) {
+				ret = media_entity_create_link(
+					&icd->vdev->entity, 0,
+					&sd->entity, src_pad_idx,
+					MEDIA_LNK_FL_IMMUTABLE |
+					MEDIA_LNK_FL_ENABLED);
+			}
+		}
+
+		if (!ret)
+			ret = soc_camera_init_user_formats_pad(icd,
+							src_pad_idx);
+	}
 	if (ret < 0)
 		goto eusrfmt;
 
@@ -1318,11 +1437,28 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd)
 		goto evidstart;
 
 	/* Try to improve our guess of a reasonable window format */
-	if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
-		icd->user_width		= mf.width;
-		icd->user_height	= mf.height;
-		icd->colorspace		= mf.colorspace;
-		icd->field		= mf.field;
+	// subdev_has_op -> get_fmt vs g_mbus_fmt
+	if (v4l2_subdev_has_op(sd, pad, enum_mbus_code)
+		&& v4l2_subdev_has_op(sd, pad, get_fmt)
+		&& src_pad_idx != -1) {
+		struct v4l2_subdev_format sd_format;
+
+		sd_format.pad= src_pad_idx;
+		sd_format.which= V4L2_SUBDEV_FORMAT_ACTIVE;
+
+		if (!v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_format)) {
+			icd->user_width		= sd_format.format.width;
+			icd->user_height	= sd_format.format.height;
+			icd->colorspace		= sd_format.format.colorspace;
+			icd->field		= sd_format.format.field;
+		}
+	} else {
+		if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
+			icd->user_width		= mf.width;
+			icd->user_height	= mf.height;
+			icd->colorspace		= mf.colorspace;
+			icd->field		= mf.field;
+		}
 	}
 	soc_camera_remove_device(icd);
 
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index 8e74fb7..8a1ca05 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -224,9 +224,27 @@ static int client_s_fmt(struct soc_camera_device *icd,
 	bool host_1to1;
 	int ret;
 
-	ret = v4l2_device_call_until_err(sd->v4l2_dev,
-					 soc_camera_grp_id(icd), video,
-					 s_mbus_fmt, mf);
+	// subdev_has_op -> set_fmt vs s_mbus_fmt
+	if (v4l2_subdev_has_op(sd, pad, set_fmt)) {
+		struct v4l2_subdev_format sd_format;
+		struct media_pad *remote_pad;
+
+		remote_pad= media_entity_remote_pad(
+			&icd->vdev->entity.pads[0]);
+		sd_format.pad = remote_pad->index;
+		sd_format.which= V4L2_SUBDEV_FORMAT_ACTIVE;
+		sd_format.format= *mf;
+
+		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+			soc_camera_grp_id(icd), pad, set_fmt, NULL,
+			&sd_format);
+
+		mf->width = sd_format.format.width;
+		mf->height = sd_format.format.height;
+	} else {
+		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+			 soc_camera_grp_id(icd), video, s_mbus_fmt, mf);
+	}
 	if (ret < 0)
 		return ret;
 
@@ -264,9 +282,26 @@ static int client_s_fmt(struct soc_camera_device *icd,
 		tmp_h = min(2 * tmp_h, max_height);
 		mf->width = tmp_w;
 		mf->height = tmp_h;
-		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+		// subdev_has_op -> set_fmt vs s_mbus_fmt
+		if (v4l2_subdev_has_op(sd, pad, set_fmt)) {
+			struct v4l2_subdev_format sd_format;
+			struct media_pad *remote_pad;
+
+			remote_pad= media_entity_remote_pad(
+				&icd->vdev->entity.pads[0]);
+			sd_format.pad = remote_pad->index;
+			sd_format.which= V4L2_SUBDEV_FORMAT_ACTIVE;
+			sd_format.format= *mf;
+
+			ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd),
+					pad, set_fmt, NULL,
+					&sd_format);
+		} else {
+			ret = v4l2_device_call_until_err(sd->v4l2_dev,
 					soc_camera_grp_id(icd), video,
 					s_mbus_fmt, mf);
+		}
 		dev_geo(dev, "Camera scaled to %ux%u\n",
 			mf->width, mf->height);
 		if (ret < 0) {
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 2f6261f..f0c5238 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -42,6 +42,7 @@ struct soc_camera_device {
 	unsigned char devnum;		/* Device number per host */
 	struct soc_camera_sense *sense;	/* See comment in struct definition */
 	struct video_device *vdev;
+	struct media_pad pad;
 	struct v4l2_ctrl_handler ctrl_handler;
 	const struct soc_camera_format_xlate *current_fmt;
 	struct soc_camera_format_xlate *user_formats;
