diff --git a/utils/v4l2-ctl/Makefile.am b/utils/v4l2-ctl/Makefile.am
index 83fa49a3..b3ccfc8b 100644
--- a/utils/v4l2-ctl/Makefile.am
+++ b/utils/v4l2-ctl/Makefile.am
@@ -6,9 +6,16 @@ v4l2_ctl_SOURCES = v4l2-ctl.cpp v4l2-ctl.h v4l2-ctl-common.cpp v4l2-ctl-tuner.cp
 	v4l2-ctl-io.cpp v4l2-ctl-stds.cpp v4l2-ctl-vidcap.cpp v4l2-ctl-vidout.cpp \
 	v4l2-ctl-overlay.cpp v4l2-ctl-vbi.cpp v4l2-ctl-selection.cpp v4l2-ctl-misc.cpp \
 	v4l2-ctl-streaming.cpp v4l2-ctl-sdr.cpp v4l2-ctl-edid.cpp v4l2-ctl-modes.cpp \
-	v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp
+	v4l2-ctl-subdev.cpp v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp
 v4l2_ctl_CPPFLAGS = -I$(top_srcdir)/utils/common

+media-bus-format-names.h: ../../include/linux/media-bus-format.h
+	sed -e '/#define MEDIA_BUS_FMT/ ! d; s/.*FMT_//; /FIXED/ d; s/\t.*//; s/.*/{ \"&\", MEDIA_BUS_FMT_& },/;' \
+	< $< > $@
+
+BUILT_SOURCES = media-bus-format-names.h
+CLEANFILES = $(BUILT_SOURCES)
+
 if WITH_V4L2_CTL_LIBV4L
 v4l2_ctl_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la -lrt -lpthread
 else
diff --git a/utils/v4l2-ctl/v4l2-ctl-common.cpp b/utils/v4l2-ctl/v4l2-ctl-common.cpp
index 46e621f7..2f521f5d 100644
--- a/utils/v4l2-ctl/v4l2-ctl-common.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-common.cpp
@@ -91,6 +91,8 @@ void common_usage(void)
 #ifndef NO_LIBV4L2
 	       "  -w, --wrapper      use the libv4l2 wrapper library.\n"
 #endif
+	       "  --which-is-try     set the 'which' argument to V4L2_SUBDEV_FORMAT_TRY instead of\n"
+	       "                     V4L2_SUBDEV_FORMAT_ACTIVE (the default)\n"
 	       "  --list-devices     list all v4l devices\n"
 	       "  --log-status       log the board status in the kernel log [VIDIOC_LOG_STATUS]\n"
 	       "  --get-priority     query the current access priority [VIDIOC_G_PRIORITY]\n"
diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
index e02dc756..9dced5b1 100644
--- a/utils/v4l2-ctl/v4l2-ctl.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl.cpp
@@ -83,6 +83,7 @@ static struct option long_options[] = {
 	{"help-vbi", no_argument, 0, OptHelpVbi},
 	{"help-sdr", no_argument, 0, OptHelpSdr},
 	{"help-meta", no_argument, 0, OptHelpMeta},
+	{"help-subdev", no_argument, 0, OptHelpSubDev},
 	{"help-selection", no_argument, 0, OptHelpSelection},
 	{"help-misc", no_argument, 0, OptHelpMisc},
 	{"help-streaming", no_argument, 0, OptHelpStreaming},
@@ -91,6 +92,7 @@ static struct option long_options[] = {
 #ifndef NO_LIBV4L2
 	{"wrapper", no_argument, 0, OptUseWrapper},
 #endif
+	{"which-is-try", no_argument, 0, OptWhichIsTry},
 	{"concise", no_argument, 0, OptConcise},
 	{"get-output", no_argument, 0, OptGetOutput},
 	{"set-output", required_argument, 0, OptSetOutput},
@@ -115,6 +117,7 @@ static struct option long_options[] = {
 	{"list-formats-sdr-out", no_argument, 0, OptListSdrOutFormats},
 	{"list-formats-out", no_argument, 0, OptListOutFormats},
 	{"list-formats-meta", no_argument, 0, OptListMetaFormats},
+	{"list-subdev-mbus-codes", optional_argument, 0, OptListSubDevMBusCodes},
 	{"list-fields-out", no_argument, 0, OptListOutFields},
 	{"clear-clips", no_argument, 0, OptClearClips},
 	{"clear-bitmap", no_argument, 0, OptClearBitmap},
@@ -1212,6 +1215,7 @@ int main(int argc, char **argv)
 	const char *wait_event_id = NULL;
 	__u32 poll_for_event = 0;	/* poll for this event */
 	const char *poll_event_id = NULL;
+	__u32 which = V4L2_SUBDEV_FORMAT_ACTIVE;
 	unsigned secs = 0;
 	char short_options[26 * 2 * 3 + 1];
 	int idx = 0;
@@ -1274,6 +1278,9 @@ int main(int argc, char **argv)
 		case OptHelpMeta:
 			meta_usage();
 			return 0;
+		case OptHelpSubDev:
+			subdev_usage();
+			return 0;
 		case OptHelpSelection:
 			selection_usage();
 			return 0;
@@ -1317,6 +1324,9 @@ int main(int argc, char **argv)
 			if (poll_for_event == 0)
 				return 1;
 			break;
+		case OptWhichIsTry:
+			which = V4L2_SUBDEV_FORMAT_TRY;
+			break;
 		case OptSleep:
 			secs = strtoul(optarg, 0L, 0);
 			break;
@@ -1341,6 +1351,7 @@ int main(int argc, char **argv)
 			vbi_cmd(ch, optarg);
 			sdr_cmd(ch, optarg);
 			meta_cmd(ch, optarg);
+			subdev_cmd(ch, optarg);
 			selection_cmd(ch, optarg);
 			misc_cmd(ch, optarg);
 			streaming_cmd(ch, optarg);
@@ -1480,6 +1491,7 @@ int main(int argc, char **argv)
 	vbi_set(fd);
 	sdr_set(fd);
 	meta_set(fd);
+	subdev_set(fd, which);
 	selection_set(fd);
 	streaming_set(fd, out_fd);
 	misc_set(fd);
@@ -1497,6 +1509,7 @@ int main(int argc, char **argv)
 	vbi_get(fd);
 	sdr_get(fd);
 	meta_get(fd);
+	subdev_get(fd, which);
 	selection_get(fd);
 	misc_get(fd);
 	edid_get(fd);
@@ -1512,6 +1525,7 @@ int main(int argc, char **argv)
 	vbi_list(fd);
 	sdr_list(fd);
 	meta_list(fd);
+	subdev_list(fd, which);
 	streaming_list(fd, out_fd);

 	if (options[OptWaitForEvent]) {
diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h
index 3b56d8a6..2ac29268 100644
--- a/utils/v4l2-ctl/v4l2-ctl.h
+++ b/utils/v4l2-ctl/v4l2-ctl.h
@@ -10,6 +10,7 @@
 #include <string>

 #include <linux/videodev2.h>
+#include <linux/v4l2-subdev.h>

 #ifndef NO_LIBV4L2
 #include <libv4l2.h>
@@ -58,6 +59,7 @@ enum Option {
 	OptGetVideoFormat = 'V',
 	OptSetVideoFormat = 'v',
 	OptUseWrapper = 'w',
+	OptWhichIsTry = 'W',

 	OptGetSlicedVbiOutFormat = 128,
 	OptGetOverlayFormat,
@@ -97,6 +99,7 @@ enum Option {
 	OptListSdrOutFormats,
 	OptListOutFormats,
 	OptListMetaFormats,
+	OptListSubDevMBusCodes,
 	OptListOutFields,
 	OptClearClips,
 	OptClearBitmap,
@@ -211,6 +214,7 @@ enum Option {
 	OptHelpVbi,
 	OptHelpSdr,
 	OptHelpMeta,
+	OptHelpSubDev,
 	OptHelpSelection,
 	OptHelpMisc,
 	OptHelpStreaming,
@@ -345,6 +349,13 @@ void meta_set(int fd);
 void meta_get(int fd);
 void meta_list(int fd);

+// v4l2-ctl-subdev.cpp
+void subdev_usage(void);
+void subdev_cmd(int ch, char *optarg);
+void subdev_set(int fd, __u32 which);
+void subdev_get(int fd, __u32 which);
+void subdev_list(int fd, __u32 which);
+
 // v4l2-ctl-selection.cpp
 void selection_usage(void);
 void selection_cmd(int ch, char *optarg);
