diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ee579916f..d20ca25d3 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -84,6 +84,7 @@ source "drivers/media/platform/sunxi/Kconfig"
 source "drivers/media/platform/ti/Kconfig"
 source "drivers/media/platform/verisilicon/Kconfig"
 source "drivers/media/platform/via/Kconfig"
+source "drivers/media/platform/toshiba/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
 
 endif # MEDIA_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 5453bb868..0406f2488 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -27,6 +27,7 @@ obj-y += sunxi/
 obj-y += ti/
 obj-y += verisilicon/
 obj-y += via/
+obj-y += toshiba/
 obj-y += xilinx/
 
 # Please place here only ancillary drivers that aren't SoC-specific
diff --git a/drivers/media/platform/toshiba/Kconfig b/drivers/media/platform/toshiba/Kconfig
new file mode 100644
index 000000000..f02983f4f
--- /dev/null
+++ b/drivers/media/platform/toshiba/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "Toshiba media platform drivers"
+
+source "drivers/media/platform/toshiba/visconti/Kconfig"
+
diff --git a/drivers/media/platform/toshiba/Makefile b/drivers/media/platform/toshiba/Makefile
new file mode 100644
index 000000000..2bce85ef3
--- /dev/null
+++ b/drivers/media/platform/toshiba/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y += visconti/
diff --git a/drivers/media/platform/toshiba/visconti/Kconfig b/drivers/media/platform/toshiba/visconti/Kconfig
new file mode 100644
index 000000000..acab70e9c
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_VISCONTI_VIIF
+	tristate "Visconti Camera Interface driver"
+	depends on V4L_PLATFORM_DRIVERS
+	depends on VIDEO_DEV && OF
+	depends on ARCH_VISCONTI || COMPILE_TEST
+	select MEDIA_CONTROLLER
+	select V4L2_ASYNC
+	select V4L2_FWNODE
+	select VIDEOBUF2_DMA_CONTIG
+	select VIDEO_V4L2_SUBDEV_API
+	help
+	  This is V4L2 driver for Toshiba Visconti Camera Interface hardware
+
+	  This driver yields 3 video device nodes
+	  and 1 media device node for a hardware instance.
+	  To compile this driver as a module, choose M here: the
+	  module will be called visconti-viif.
diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
new file mode 100644
index 000000000..5f2f9199c
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Visconti video input device driver
+#
+
+visconti-viif-objs = viif.o viif_capture.o viif_isp.o viif_csi2rx.o viif_common.o
+
+obj-$(CONFIG_VIDEO_VISCONTI_VIIF) += visconti-viif.o
diff --git a/drivers/media/platform/toshiba/visconti/viif.c b/drivers/media/platform/toshiba/visconti/viif.c
new file mode 100644
index 000000000..345dc457a
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif.c
@@ -0,0 +1,716 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-fwnode.h>
+
+#include "viif.h"
+#include "viif_capture.h"
+#include "viif_csi2rx.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_regs.h"
+
+/*=============================================*/
+/* Register Access */
+/*=============================================*/
+static inline void viif_hwaif_write(struct viif_device *viif_dev, unsigned int regid, u32 val)
+{
+	writel(val, viif_dev->hwaif_reg + regid);
+}
+
+static inline void viif_mpu_write(struct viif_device *viif_dev, unsigned int regid, u32 val)
+{
+	writel(val, viif_dev->mpu_reg + regid);
+}
+
+/*=============================================*/
+/* Low Layer Interrupt handler */
+/*=============================================*/
+/**
+ * viif_main_status_err_set_irq_mask() - Set mask condition for STATUS error of MAIN unit
+ *
+ * @mask: STATUS error mask condition
+ */
+static void viif_main_status_err_set_irq_mask(struct viif_device *viif_dev, u32 mask)
+{
+	viif_capture_write(viif_dev, REG_INT_M_MASK, mask);
+}
+
+/**
+ * viif_main_vsync_set_irq_mask() - Set mask condition for Vsync of MAIN unit
+ *
+ * @mask: Vsync mask condition
+ */
+static void viif_main_vsync_set_irq_mask(struct viif_device *viif_dev, u32 mask)
+{
+	viif_capture_write(viif_dev, REG_INT_M_SYNC_MASK, mask);
+}
+
+/**
+ * viif_sub_status_err_set_irq_mask() -
+ *  Set mask condition for STATUS error of SUB unit or VOIF loopback
+ *
+ * @mask: STATUS error mask condition
+ */
+static void viif_sub_status_err_set_irq_mask(struct viif_device *viif_dev, u32 mask)
+{
+	viif_capture_write(viif_dev, REG_INT_S_MASK, mask);
+}
+
+/**
+ * viif_sub_vsync_set_irq_mask() - Set mask condition for Vsync of SUB unit or VOIF loopback
+ *
+ * @mask: Vsync mask condition
+ */
+static void viif_sub_vsync_set_irq_mask(struct viif_device *viif_dev, const u32 mask)
+{
+	viif_capture_write(viif_dev, REG_INT_S_SYNC_MASK, mask);
+}
+
+/**
+ * viif_read_err_irq_registers() - STATUS error interruption handler
+ *
+ * @event_main: information of STATUS error interruption of MAIN unit
+ * @event_sub: information of STATUS error interruption of SUB unit(CH0 and CH1)
+ */
+
+static void viif_read_err_irq_registers(struct viif_device *viif_dev, u32 *event_main,
+					u32 *event_sub)
+{
+	u32 val, mask;
+
+	*event_main = 0;
+	*event_sub = 0;
+
+	val = viif_capture_read(viif_dev, REG_INT_M_STATUS);
+	mask = viif_capture_read(viif_dev, REG_INT_M_MASK);
+	val &= ~mask;
+	if (val) {
+		viif_capture_write(viif_dev, REG_INT_M_STATUS, val);
+		*event_main = val;
+	}
+
+	val = viif_capture_read(viif_dev, REG_INT_S_STATUS);
+	mask = viif_capture_read(viif_dev, REG_INT_S_MASK);
+	val &= ~mask;
+	if (val) {
+		viif_capture_write(viif_dev, REG_INT_S_STATUS, val);
+		*event_sub = val;
+	}
+}
+
+/**
+ * viif_read_vsynq_irq_registers() - Vsync interruption handler
+ *
+ * @event_main: information of Vsync interruption of MAIN unit
+ * @event_sub: information of Vsync interruption of SUB unit
+ */
+static void viif_read_vsynq_irq_registers(struct viif_device *viif_dev, u32 *event_main,
+					  u32 *event_sub)
+{
+	u32 val, mask;
+
+	*event_main = 0;
+	*event_sub = 0;
+
+	val = viif_capture_read(viif_dev, REG_INT_M_SYNC);
+	mask = viif_capture_read(viif_dev, REG_INT_M_SYNC_MASK);
+	val &= ~mask;
+	if (val) {
+		viif_capture_write(viif_dev, REG_INT_M_SYNC, val);
+		*event_main = val;
+	}
+
+	val = viif_capture_read(viif_dev, REG_INT_S_SYNC);
+	mask = viif_capture_read(viif_dev, REG_INT_S_SYNC_MASK);
+	val &= ~mask;
+	if (val) {
+		viif_capture_write(viif_dev, REG_INT_S_SYNC, val);
+		*event_sub = val;
+	}
+}
+
+static u32 viif_get_l2_transfer_status(struct viif_device *viif_dev)
+{
+	u32 l2_status;
+
+	l2_status = viif_capture_read(viif_dev, REG_L2_CRGBF_ISP_INT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_ISP_INT, l2_status);
+	return l2_status & MASK_L2_STATUS_ERR_ALL;
+}
+
+/*=============================================*/
+/* Low Layer hardware setup */
+/*=============================================*/
+static void viif_mpu_disable(struct viif_device *viif_dev)
+{
+	viif_mpu_write(viif_dev, REG_MPU_MP_EN, 0);
+	viif_mpu_write(viif_dev, REG_MPU_MF_EN, 1);
+}
+
+static void viif_hwaif_enable(struct viif_device *viif_dev)
+{
+	/* pass through; disable all entries */
+	viif_hwaif_write(viif_dev, REG_HWAIF_REGION_ENTRY_EN, 0);
+
+	/* no limit for outstanding requests */
+	viif_hwaif_write(viif_dev, REG_HWAIF_OSTD_RLEN, 0);
+	viif_hwaif_write(viif_dev, REG_HWAIF_OSTD_WREQ, 0);
+
+	/* no data-pack/outstanding */
+	viif_hwaif_write(viif_dev, REG_HWAIF_HWAIF_CONF, 0);
+
+	/* enable bus access */
+	viif_hwaif_write(viif_dev, REG_HWAIF_HWAIF_EN, 1);
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+void visconti_viif_hw_on(struct viif_device *viif_dev)
+{
+	/* Disable MPU */
+	viif_mpu_disable(viif_dev);
+	/* Enable HWAIF */
+	viif_hwaif_enable(viif_dev);
+}
+
+void visconti_viif_hw_off(struct viif_device *viif_dev)
+{
+	/* Uninitialize HWD driver */
+}
+
+static inline struct viif_device *v4l2_to_viif(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct viif_device, v4l2_dev);
+}
+
+static struct viif_subdev *to_viif_subdev(struct v4l2_async_subdev *asd)
+{
+	return container_of(asd, struct viif_subdev, asd);
+}
+
+/* This function runs in work queue context */
+/* Reading ISP registers takes 30us. */
+/* Please note that this function should be finished */
+/* before a userland capture application is trigered by vb2_buffer_done() */
+static void visconti_viif_wthread_l1info(struct work_struct *work)
+{
+	/* called function is implemented by the next patch */
+/*
+ *	struct viif_device *viif_dev = container_of(work, struct viif_device, work);
+ *
+ *	visconti_viif_save_l1_info(viif_dev);
+ */
+}
+
+static void viif_vsync_irq_handler_w_isp(struct viif_device *viif_dev)
+{
+	u32 event_main, event_sub, status_err, l2_transfer_status;
+	u64 ts;
+
+	ts = ktime_get_ns();
+	viif_read_vsynq_irq_registers(viif_dev, &event_main, &event_sub);
+
+	/* Delayed Vsync of MAIN unit */
+	if (event_main & MASK_INT_M_SYNC_LINES_DELAY_INT2) {
+		/* unmask timeout error of gamma table */
+		viif_main_status_err_set_irq_mask(viif_dev, MASK_INT_M_DELAY_INT_ERROR);
+		viif_dev->masked_gamma_path = 0;
+
+		/* Get abort status of L2ISP */
+		spin_lock(&viif_dev->regbuf_lock);
+		hwd_viif_isp_guard_start(viif_dev);
+		l2_transfer_status = viif_get_l2_transfer_status(viif_dev);
+		hwd_viif_isp_guard_end(viif_dev);
+		spin_unlock(&viif_dev->regbuf_lock);
+
+		status_err = viif_dev->status_err;
+		viif_dev->status_err = 0;
+
+		visconti_viif_capture_switch_buffer(&viif_dev->cap_dev0, status_err,
+						    l2_transfer_status, ts);
+		visconti_viif_capture_switch_buffer(&viif_dev->cap_dev1, status_err,
+						    l2_transfer_status, ts);
+		queue_work(viif_dev->wq, &viif_dev->work);
+	}
+
+	/* Delayed Vsync of SUB unit */
+	if (event_sub & MASK_INT_S_SYNC_LINES_DELAY_INT1)
+		visconti_viif_capture_switch_buffer(&viif_dev->cap_dev2, 0, 0, ts);
+}
+
+static void viif_status_err_irq_handler(struct viif_device *viif_dev)
+{
+	u32 event_main, event_sub, val, mask;
+
+	viif_read_err_irq_registers(viif_dev, &event_main, &event_sub);
+
+	if (event_main) {
+		/* mask for gamma table time out error which will be unmasked in the next Vsync */
+		val = FIELD_GET(MASK_INT_M_L2ISP_GAMMA_TABLE_TIMEOUT, event_main);
+		if (val) {
+			viif_dev->masked_gamma_path |= val;
+			mask = MASK_INT_M_DELAY_INT_ERROR |
+			       FIELD_PREP(MASK_INT_M_L2ISP_GAMMA_TABLE_TIMEOUT,
+					  viif_dev->masked_gamma_path);
+			viif_main_status_err_set_irq_mask(viif_dev, mask);
+		}
+
+		viif_dev->status_err = event_main;
+	}
+	viif_dev->reported_err_main |= event_main;
+	viif_dev->reported_err_sub |= event_sub;
+	dev_err(viif_dev->dev, "MAIN/SUB error 0x%x 0x%x.\n", event_main, event_sub);
+}
+
+static void viif_csi2rx_err_irq_handler(struct viif_device *viif_dev)
+{
+	u32 event;
+
+	event = visconti_viif_csi2rx_err_irq_handler(viif_dev);
+	viif_dev->reported_err_csi2rx |= event;
+	dev_err(viif_dev->dev, "CSI2RX error 0x%x.\n", event);
+}
+
+static irqreturn_t visconti_viif_irq(int irq, void *dev_id)
+{
+	struct viif_device *viif_dev = dev_id;
+	int irq_type = irq - viif_dev->irq[0];
+
+	switch (irq_type) {
+	case 0:
+		viif_vsync_irq_handler_w_isp(viif_dev);
+		break;
+	case 1:
+		viif_status_err_irq_handler(viif_dev);
+		break;
+	case 2:
+		viif_csi2rx_err_irq_handler(viif_dev);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* ----- Async Notifier Operations----- */
+static int visconti_viif_notify_bound(struct v4l2_async_notifier *notifier,
+				      struct v4l2_subdev *v4l2_sd, struct v4l2_async_subdev *asd)
+{
+	struct viif_subdev *viif_sd = to_viif_subdev(asd);
+
+	viif_sd->v4l2_sd = v4l2_sd;
+
+	return 0;
+}
+
+static void visconti_viif_create_links(struct viif_device *viif_dev)
+{
+	unsigned int source_pad;
+	int ret;
+
+	/* camera subdev pad0 -> isp suddev pad0 */
+	ret = media_entity_get_fwnode_pad(&viif_dev->sd->v4l2_sd->entity,
+					  viif_dev->sd->v4l2_sd->fwnode, MEDIA_PAD_FL_SOURCE);
+	if (ret < 0) {
+		dev_err(viif_dev->dev, "failed to find source pad\n");
+		return;
+	}
+	source_pad = ret;
+
+	ret = media_create_pad_link(&viif_dev->sd->v4l2_sd->entity, source_pad,
+				    &viif_dev->csi2rx_subdev.sd.entity, VIIF_CSI2RX_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (camera:src -> csi2rx:sink)\n");
+
+	ret = media_create_pad_link(&viif_dev->csi2rx_subdev.sd.entity, VIIF_CSI2RX_PAD_SRC,
+				    &viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (csi2rx:src -> isp:sink)\n");
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_PATH0,
+				    &viif_dev->cap_dev0.vdev.entity, VIIF_CAPTURE_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:src -> capture0:sink)\n");
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_PATH1,
+				    &viif_dev->cap_dev1.vdev.entity, VIIF_CAPTURE_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:src -> capture1:sink)\n");
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_PATH2,
+				    &viif_dev->cap_dev2.vdev.entity, VIIF_CAPTURE_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:src -> capture2:sink)\n");
+}
+
+static void visconti_viif_notify_unbind(struct v4l2_async_notifier *notifier,
+					struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+{
+	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
+	struct viif_subdev *viif_sd = to_viif_subdev(asd);
+
+	v4l2_dev->ctrl_handler = NULL;
+	viif_sd->v4l2_sd = NULL;
+}
+
+static int visconti_viif_notify_complete(struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
+	struct viif_device *viif_dev = v4l2_to_viif(v4l2_dev);
+	int ret;
+
+	ret = v4l2_device_register_subdev_nodes(v4l2_dev);
+	if (ret < 0) {
+		dev_err(v4l2_dev->dev, "Failed to register subdev nodes\n");
+		return ret;
+	}
+
+	/* Make sure at least one sensor is primary and use it to initialize */
+	if (!viif_dev->sd)
+		viif_dev->sd = &viif_dev->subdevs[0];
+
+	ret = visconti_viif_capture_register_ctrl_handlers(viif_dev);
+	if (ret)
+		return ret;
+
+	visconti_viif_create_links(viif_dev);
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations viif_notify_ops = {
+	.bound = visconti_viif_notify_bound,
+	.unbind = visconti_viif_notify_unbind,
+	.complete = visconti_viif_notify_complete,
+};
+
+/* ----- Probe and Remove ----- */
+static int visconti_viif_init_async_subdevs(struct viif_device *viif_dev, unsigned int n_sd)
+{
+	/* Reserve memory for 'n_sd' viif_subdev descriptors. */
+	viif_dev->subdevs =
+		devm_kcalloc(viif_dev->dev, n_sd, sizeof(*viif_dev->subdevs), GFP_KERNEL);
+	if (!viif_dev->subdevs)
+		return -ENOMEM;
+
+	/* Reserve memory for 'n_sd' pointers to async_subdevices.
+	 * viif_dev->asds members will point to &viif_dev.asd
+	 */
+	viif_dev->asds = devm_kcalloc(viif_dev->dev, n_sd, sizeof(*viif_dev->asds), GFP_KERNEL);
+	if (!viif_dev->asds)
+		return -ENOMEM;
+
+	viif_dev->sd = NULL;
+
+	return 0;
+}
+
+static int visconti_viif_parse_dt(struct viif_device *viif_dev)
+{
+	struct device_node *of = viif_dev->dev->of_node;
+	struct v4l2_fwnode_endpoint fw_ep;
+	struct viif_subdev *viif_sd;
+	struct device_node *ep;
+	unsigned int i;
+	int num_ep;
+	int ret;
+
+	memset(&fw_ep, 0, sizeof(struct v4l2_fwnode_endpoint));
+
+	num_ep = of_graph_get_endpoint_count(of);
+	if (!num_ep)
+		return -ENODEV;
+
+	ret = visconti_viif_init_async_subdevs(viif_dev, num_ep);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num_ep; i++) {
+		ep = of_graph_get_endpoint_by_regs(of, 0, i);
+		if (!ep) {
+			dev_err(viif_dev->dev, "No subdevice connected on endpoint %u.\n", i);
+			ret = -ENODEV;
+			goto error_put_node;
+		}
+
+		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep);
+		if (ret) {
+			dev_err(viif_dev->dev, "Unable to parse endpoint #%u.\n", i);
+			goto error_put_node;
+		}
+
+		if (fw_ep.bus_type != V4L2_MBUS_CSI2_DPHY ||
+		    fw_ep.bus.mipi_csi2.num_data_lanes == 0) {
+			dev_err(viif_dev->dev, "missing CSI-2 properties in endpoint\n");
+			ret = -EINVAL;
+			goto error_put_node;
+		}
+
+		/* Setup the ceu subdevice and the async subdevice. */
+		viif_sd = &viif_dev->subdevs[i];
+		INIT_LIST_HEAD(&viif_sd->asd.list);
+
+		viif_sd->num_lane = fw_ep.bus.mipi_csi2.num_data_lanes;
+		viif_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+		viif_sd->asd.match.fwnode =
+			fwnode_graph_get_remote_port_parent(of_fwnode_handle(ep));
+
+		viif_dev->asds[i] = &viif_sd->asd;
+		of_node_put(ep);
+	}
+
+	return num_ep;
+
+error_put_node:
+	of_node_put(ep);
+	return ret;
+}
+
+static const struct of_device_id visconti_viif_of_table[] = {
+	{
+		.compatible = "toshiba,visconti-viif",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, visconti_viif_of_table);
+
+#define NUM_IRQS   3
+#define IRQ_ID_STR "viif"
+
+static int visconti_viif_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device *dev = &pdev->dev;
+	struct viif_device *viif_dev;
+	dma_addr_t tables_dma;
+	int ret, i, num_sd;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
+	if (ret)
+		return ret;
+
+	viif_dev = devm_kzalloc(dev, sizeof(*viif_dev), GFP_KERNEL);
+	if (!viif_dev)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, viif_dev);
+	viif_dev->dev = dev;
+
+	spin_lock_init(&viif_dev->regbuf_lock);
+	mutex_init(&viif_dev->pow_lock);
+	mutex_init(&viif_dev->stream_lock);
+
+	viif_dev->capture_reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(viif_dev->capture_reg))
+		return PTR_ERR(viif_dev->capture_reg);
+
+	viif_dev->csi2host_reg = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(viif_dev->csi2host_reg))
+		return PTR_ERR(viif_dev->csi2host_reg);
+
+	viif_dev->hwaif_reg = devm_platform_ioremap_resource(pdev, 2);
+	if (IS_ERR(viif_dev->hwaif_reg))
+		return PTR_ERR(viif_dev->hwaif_reg);
+
+	viif_dev->mpu_reg = devm_platform_ioremap_resource(pdev, 3);
+	if (IS_ERR(viif_dev->mpu_reg))
+		return PTR_ERR(viif_dev->mpu_reg);
+
+	viif_dev->run_flag_main = false;
+
+	for (i = 0; i < NUM_IRQS; i++) {
+		ret = platform_get_irq(pdev, i);
+		if (ret < 0) {
+			dev_err(dev, "failed to acquire irq resource\n");
+			return ret;
+		}
+		viif_dev->irq[i] = ret;
+		ret = devm_request_irq(dev, viif_dev->irq[i], visconti_viif_irq, 0, IRQ_ID_STR,
+				       viif_dev);
+		if (ret) {
+			dev_err(dev, "irq request failed\n");
+			return ret;
+		}
+	}
+
+	viif_dev->tables =
+		dma_alloc_wc(dev, sizeof(struct viif_table_area), &tables_dma, GFP_KERNEL);
+	if (!viif_dev->tables) {
+		dev_err(dev, "dma_alloc_wc failed\n");
+		return -ENOMEM;
+	}
+	viif_dev->tables_dma = (struct viif_table_area *)tables_dma;
+
+	/* power control */
+	pm_runtime_enable(dev);
+
+	/* build media_dev */
+	viif_dev->media_dev.hw_revision = 0;
+	strscpy(viif_dev->media_dev.model, VIIF_DRIVER_NAME, sizeof(viif_dev->media_dev.model));
+	viif_dev->media_dev.dev = dev;
+	/* TODO: platform:visconti-viif-0,1,2,3 for each VIIF driver instance */
+	snprintf(viif_dev->media_dev.bus_info, sizeof(viif_dev->media_dev.bus_info), "%s-0",
+		 VIIF_BUS_INFO_BASE);
+	media_device_init(&viif_dev->media_dev);
+
+	/* build v4l2_dev */
+	viif_dev->v4l2_dev.mdev = &viif_dev->media_dev;
+	ret = v4l2_device_register(dev, &viif_dev->v4l2_dev);
+	if (ret)
+		goto error_dma_free;
+
+	ret = media_device_register(&viif_dev->media_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register media device: %d\n", ret);
+		goto error_v4l2_unregister;
+	}
+
+	ret = visconti_viif_csi2rx_register(viif_dev);
+	if (ret) {
+		dev_err(dev, "failed to register csi2rx sub node: %d\n", ret);
+		goto error_media_unregister;
+	}
+
+	ret = visconti_viif_isp_register(viif_dev);
+	if (ret) {
+		dev_err(dev, "failed to register isp sub node: %d\n", ret);
+		goto error_media_unregister;
+	}
+	ret = visconti_viif_capture_register(viif_dev);
+	if (ret) {
+		dev_err(dev, "failed to register capture node: %d\n", ret);
+		goto error_media_unregister;
+	}
+
+	/* check device type */
+	of_id = of_match_device(visconti_viif_of_table, dev);
+
+	num_sd = visconti_viif_parse_dt(viif_dev);
+	if (ret < 0) {
+		ret = num_sd;
+		goto error_media_unregister;
+	}
+
+	viif_dev->notifier.v4l2_dev = &viif_dev->v4l2_dev;
+	v4l2_async_nf_init(&viif_dev->notifier);
+	for (i = 0; i < num_sd; i++)
+		__v4l2_async_nf_add_subdev(&viif_dev->notifier, viif_dev->asds[i]);
+	viif_dev->notifier.ops = &viif_notify_ops;
+	ret = v4l2_async_nf_register(&viif_dev->v4l2_dev, &viif_dev->notifier);
+	if (ret)
+		goto error_media_unregister;
+
+	viif_dev->wq = create_workqueue("visconti-viif");
+	if (!viif_dev->wq)
+		return -ENOMEM;
+	INIT_WORK(&viif_dev->work, visconti_viif_wthread_l1info);
+
+	return 0;
+
+error_media_unregister:
+	media_device_unregister(&viif_dev->media_dev);
+error_v4l2_unregister:
+	v4l2_device_unregister(&viif_dev->v4l2_dev);
+error_dma_free:
+	pm_runtime_disable(dev);
+	dma_free_wc(&pdev->dev, sizeof(struct viif_table_area), viif_dev->tables,
+		    (dma_addr_t)viif_dev->tables_dma);
+	return ret;
+}
+
+static int visconti_viif_remove(struct platform_device *pdev)
+{
+	struct viif_device *viif_dev = platform_get_drvdata(pdev);
+
+	destroy_workqueue(viif_dev->wq);
+	visconti_viif_isp_unregister(viif_dev);
+	visconti_viif_capture_unregister(viif_dev);
+	v4l2_async_nf_unregister(&viif_dev->notifier);
+	media_device_unregister(&viif_dev->media_dev);
+	v4l2_device_unregister(&viif_dev->v4l2_dev);
+	pm_runtime_disable(&pdev->dev);
+	dma_free_wc(&pdev->dev, sizeof(struct viif_table_area), viif_dev->tables,
+		    (dma_addr_t)viif_dev->tables_dma);
+
+	return 0;
+}
+
+static int visconti_viif_runtime_suspend(struct device *dev)
+{
+	/* This callback is kicked when the last device-file is closed */
+	struct viif_device *viif_dev = dev_get_drvdata(dev);
+
+	mutex_lock(&viif_dev->pow_lock);
+	visconti_viif_hw_off(viif_dev);
+	mutex_unlock(&viif_dev->pow_lock);
+
+	return 0;
+}
+
+static int visconti_viif_runtime_resume(struct device *dev)
+{
+	/* This callback is kicked when the first device-file is opened */
+	struct viif_device *viif_dev = dev_get_drvdata(dev);
+
+	viif_dev->rawpack_mode = (u32)VIIF_RAWPACK_DISABLE;
+
+	mutex_lock(&viif_dev->pow_lock);
+
+	/* Initialize HWD driver */
+	visconti_viif_hw_on(viif_dev);
+
+	/* VSYNC mask setting of MAIN unit */
+	viif_main_vsync_set_irq_mask(viif_dev, MASK_INT_M_SYNC_MASK_SET);
+
+	/* STATUS error mask setting of MAIN unit */
+	viif_main_status_err_set_irq_mask(viif_dev, MASK_INT_M_DELAY_INT_ERROR);
+
+	/* VSYNC mask settings of SUB unit */
+	viif_sub_vsync_set_irq_mask(viif_dev, MASK_INT_S_SYNC_MASK_SET);
+
+	/* STATUS error mask setting(unmask) of SUB unit */
+	viif_sub_status_err_set_irq_mask(viif_dev,
+					 MASK_INT_S_RESERVED_SET | MASK_INT_S_DELAY_INT_ERROR);
+
+	mutex_unlock(&viif_dev->pow_lock);
+
+	return 0;
+}
+
+static const struct dev_pm_ops visconti_viif_pm_ops = {
+	SET_RUNTIME_PM_OPS(visconti_viif_runtime_suspend, visconti_viif_runtime_resume, NULL)
+};
+
+static struct platform_driver visconti_viif_driver = {
+	.probe = visconti_viif_probe,
+	.remove = visconti_viif_remove,
+	.driver = {
+			.name = "visconti_viif",
+			.of_match_table = visconti_viif_of_table,
+			.pm = &visconti_viif_pm_ops,
+		},
+};
+
+module_platform_driver(visconti_viif_driver);
+
+MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
+MODULE_DESCRIPTION("Toshiba Visconti Video Input driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/toshiba/visconti/viif.h b/drivers/media/platform/toshiba/visconti/viif.h
new file mode 100644
index 000000000..df6c0a8de
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif.h
@@ -0,0 +1,375 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_H
+#define VIIF_H
+
+#include <linux/visconti_viif.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define VIIF_DRIVER_NAME   "visconti-viif"
+#define VIIF_BUS_INFO_BASE "platform:" VIIF_DRIVER_NAME
+
+#define VIIF_ISP_REGBUF_0 0
+#define VIIF_L2ISP_POST_0 0
+#define VIIF_L2ISP_POST_1 1
+#define VIIF_MAX_POST_NUM 2U
+
+#define VIIF_CAPTURE_PAD_SINK  0
+#define VIIF_ISP_PAD_SINK      0
+#define VIIF_ISP_PAD_SRC_PATH0 1
+#define VIIF_ISP_PAD_SRC_PATH1 2
+#define VIIF_ISP_PAD_SRC_PATH2 3
+#define VIIF_ISP_PAD_NUM       4
+
+#define VIIF_CSI2RX_PAD_SINK 0
+#define VIIF_CSI2RX_PAD_SRC  1
+#define VIIF_CSI2RX_PAD_NUM  2
+
+#define CAPTURE_PATH_MAIN_POST0 0
+#define CAPTURE_PATH_MAIN_POST1 1
+#define CAPTURE_PATH_SUB	2
+
+#define VIIF_DPC_TABLE_BYTES	   8192
+#define VIIF_LSC_TABLE_BYTES	   1536
+#define VIIF_UNDIST_TABLE_BYTES	   8192
+#define VIIF_L2_GAMMA_TABLE_BYTES  512
+#define VIIF_L2_GAMMA_TABLE_CH_NUM 6
+
+#define VIIF_HW_AVAILABLE_IRQS 4
+
+#define VIIF_SYS_CLK 500000UL
+
+enum viif_output_color_mode {
+	VIIF_COLOR_Y_G = 0,
+	VIIF_COLOR_U_B = 1U,
+	VIIF_COLOR_V_R = 2U,
+	VIIF_COLOR_YUV_RGB = 4U
+};
+
+/**
+ * struct viif_img_area - image area definition
+ * @x: x position. Range: [0..8062]
+ * @y: y position. Range: [0..3966]
+ * @w: image width. Range: [128..8190]
+ * @h: image height. Range: [128..4094]
+ */
+struct viif_img_area {
+	u32 x;
+	u32 y;
+	u32 w;
+	u32 h;
+};
+
+/**
+ * struct viif_out_process - configuration of output process of MAIN unit and L2ISP
+ * @half_scale: true to enable half scaling
+ * @select_color: viif_output_color_mode "select output color"
+ * @alpha: alpha value used in case of ARGB8888 output. Range: [0..255]
+ */
+struct viif_out_process {
+	bool half_scale;
+	enum viif_output_color_mode select_color;
+	u8 alpha;
+};
+
+/**
+ * struct viif_fmt - description of supported output image format
+ * @fourcc: V4L2 fourcc format ID
+ * @bpp: bits per pixel for each plane
+ * @num_planes: number of planes in a image
+ * @colorspace: colorspace ID
+ * @pitch_align: alignment constraint of pitch
+ */
+struct viif_fmt {
+	u32 fourcc;
+	u8 bpp[3];
+	u8 num_planes;
+	u32 colorspace;
+	u32 pitch_align;
+};
+
+/**
+ * struct viif_subdev - information of attached subdevice (image sensor)
+ * @v4l2_sd: v4l2 subdev for the sensor
+ * @asd: async subdev for the sensor
+ * @num_lane: num of CSI2 DPHY lanes, specified in Device Tree
+ */
+struct viif_subdev {
+	struct v4l2_subdev *v4l2_sd;
+	struct v4l2_async_subdev asd;
+	unsigned int num_lane;
+};
+
+/*
+ * struct viif_table_area - table for ISP features.
+ *
+ * The memory block for this structure must be allocated with dma_alloc_wc()
+ * so that the allocated block will be phisically continuous.
+ */
+struct viif_table_area {
+	/* L1ISP DPC */
+	u32 dpc_table_h[VIIF_DPC_TABLE_BYTES / sizeof(u32)];
+	u32 dpc_table_m[VIIF_DPC_TABLE_BYTES / sizeof(u32)];
+	u32 dpc_table_l[VIIF_DPC_TABLE_BYTES / sizeof(u32)];
+	/* L1ISP LSC */
+	u16 lsc_table_gr[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	u16 lsc_table_r[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	u16 lsc_table_b[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	u16 lsc_table_gb[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	/* L2ISP UNDIST */
+	u32 undist_write_g[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	u32 undist_read_b[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	u32 undist_read_g[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	u32 undist_read_r[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	/* L2ISP GAMMA */
+	u16 l2_gamma_table[VIIF_MAX_POST_NUM][VIIF_L2_GAMMA_TABLE_CH_NUM]
+			  [VIIF_L2_GAMMA_TABLE_BYTES / sizeof(u16)];
+};
+
+/**
+ * struct cap_dev - device node for capture device
+ * @pathid: 0 for MAIN POST0, 1 for MAIN POST1, 2 for SUB
+ * @vdev: video node
+ * @capture_pad: media pad
+ * @ctrl_handler: v4l2 control handler
+ * @vlock: serialize ioctl to vb2_queue and video_device
+ * @vb2_vq: queue of buffers
+ * @buf_queue: list of available buffers
+ * @active: VDMAC will start writing to this bufffer at the next VSYNC
+ * @dma_active: VDMAC will complete writing to this buffer at the next VSYNC
+ * @buf_cnt: number of queued buffers
+ * @sequence: total count of processed frames
+ * @buf_lock: serialize queue access (including ISR's)
+ * @v4l2_pix: current picture format (set by S_FMT)
+ * @out_format: output format for VDMAC
+ * @img_area: crop of output picture
+ * @out_process: output configuration
+ * @fmts: format supported by this capture device
+ * @fmt_size: sizeof fmts
+ * @viif_dev: reference to viif device
+ */
+struct cap_dev {
+	u32 pathid;
+	struct video_device vdev;
+	struct media_pad capture_pad;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct mutex vlock; /*serialize ioctl to vb2_queue and video_device*/
+
+	/* vb2 queue, capture buffer list and active buffer pointer */
+	struct vb2_queue vb2_vq;
+	struct list_head buf_queue;
+	struct vb2_v4l2_buffer *active;
+	struct vb2_v4l2_buffer *dma_active;
+	int buf_cnt;
+	unsigned int sequence;
+	spinlock_t buf_lock; /* serialize queue access (including ISR's) */
+
+	/* current configuration of frame and pixel format */
+	struct v4l2_pix_format_mplane v4l2_pix;
+	unsigned int out_format;
+	struct viif_img_area img_area;
+	struct viif_out_process out_process;
+
+	/* format supported by this cap device */
+	const struct viif_fmt *fmts;
+	int fmt_size;
+
+	struct viif_device *viif_dev;
+};
+
+/**
+ * struct isp_subdev - device node for ISP suddevice
+ * @sd: v4l2 subdevice
+ * @pads: media pad
+ * @pad_cfg: configuration of media pad
+ * @mutex: serialize V4L2 query
+ * @viif_dev: reference to viif device
+ * @ctrl_handler: v4l2 control handler
+ * @ctrl_rawpack_mode: control
+ * @ctrl_input_mode: control
+ * @ctrl_last_capture_status: control
+ */
+struct isp_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[VIIF_ISP_PAD_NUM];
+	struct v4l2_subdev_pad_config pad_cfg[VIIF_ISP_PAD_NUM];
+	struct mutex ops_lock; /* serialize V4L2 query */
+	struct viif_device *viif_dev;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl *ctrl_rawpack_mode;
+	struct v4l2_ctrl *ctrl_input_mode;
+	struct v4l2_ctrl *ctrl_last_capture_status;
+};
+
+/**
+ * struct csi2rx_subdev - device node for CSI2RX suddevice
+ * @sd: v4l2 subdevice
+ * @pads: media pad
+ * @pad_cfg: configuration of media pad
+ * @mutex: serialize V4L2 query
+ * @viif_dev: reference to viif device
+ */
+struct csi2rx_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[VIIF_CSI2RX_PAD_NUM];
+	struct v4l2_subdev_pad_config pad_cfg[VIIF_CSI2RX_PAD_NUM];
+	struct mutex ops_lock; /* serialize V4L2 query */
+	struct viif_device *viif_dev;
+};
+
+/**
+ * struct viif_l2_roi_path_info - crop information of main paths
+ * @roi_num:
+ *
+ * - 1: crops of MAIN POST0 and POST1 share the same ROI
+ * - 2: crops of MAIN POST0 and POST1 have independent ROIs
+ *
+ * @post_crop_x: left of crop rect for a POST
+ * @post_crop_y: top of crop rect for a POST
+ * @post_crop_w: width of crop rect for a POST
+ * @post_crop_h: height of crop rect for a POST
+ */
+struct viif_l2_roi_path_info {
+	u32 roi_num;
+	bool post_enable_flag[VIIF_MAX_POST_NUM];
+	u32 post_crop_x[VIIF_MAX_POST_NUM];
+	u32 post_crop_y[VIIF_MAX_POST_NUM];
+	u32 post_crop_w[VIIF_MAX_POST_NUM];
+	u32 post_crop_h[VIIF_MAX_POST_NUM];
+};
+
+/**
+ * struct viif_img_clk - relation between realtime duration and number of lines
+ * @pixel_clock: picture transfer clock frequency
+ * @htotal_size: width of picture including blanking period
+ *
+ * These values are used to convert realtime duration (such as HW specific setup time)
+ * into number of lines in a picture.
+ * See sysclk_to_numlines() called at the reconfiguration of L1ISP HDRC feature.
+ */
+struct viif_img_clk {
+	unsigned int pixel_clock;
+	unsigned int htotal_size;
+};
+
+/**
+ * struct viif_device - driver information of Visconti VIIF
+ * @dev: device
+ * @v4l2_dev: v4l2 device
+ * @media_dev: media device
+ * @pipe: media pipeline
+ * @masked_gamma_path: flag to ignore L2_GAMMA error just after capture error
+ * @subdevs: sensor subdevice specified in device tree
+ * @asds: async subdevices for subdevs
+ * @notifier: async subdev notification helper
+ * @sd: points current image sensor subdevice
+ * @cap_dev0: capture device for MAIN PATH 0
+ * @cap_dev1: capture device for MAIN PATH 1
+ * @cap_dev2: capture device for MAIN PATH 2
+ * @isp_subdev: ISP subdevice
+ * @csi2rx_subdev: CSI2RX subdevice
+ * @stream_lock: serialize stream ON/OFF sequence
+ * @regbuf_lock: Serialize VIIF Register Buffer Access
+ * @pow_lock: serialize power control
+ * @l2_roi_path_info: crop information of main paths
+ * @img_clk: relation between realtime duration and number of lines
+ * @run_flag_main: flag to check if the stream is ON
+ * @capture_reg: HW capture registers
+ * @csi2host_reg: HW CSI2RX registers
+ * @hwaif_reg: HW bus interface registers
+ * @mpu_reg: HW memory protection unit registers
+ * @irq: IRQ number
+ * @tables: table for ISP features (virtual address)
+ * @tables_dma: table for ISP features (IOVA)
+ * @rawpack_mode: rawpack mode
+ * @wq: workqueue queue
+ * @work: workqueue task to update V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS
+ * @status_err: error of Main path in a frame
+ * @reported_err_main: accumerated error flags for MAIN path
+ * @reported_err_sub: accumerated error flags for SUB path
+ * @reported_err_csi2rx: accumerated error flags for CSI2RX
+ */
+struct viif_device {
+	struct device *dev;
+	struct v4l2_device v4l2_dev;
+	struct media_device media_dev;
+	struct media_pipeline pipe;
+	u32 masked_gamma_path;
+
+	struct viif_subdev *subdevs;
+	struct v4l2_async_subdev **asds;
+	struct v4l2_async_notifier notifier;
+
+	struct viif_subdev *sd;
+
+	struct cap_dev cap_dev0;
+	struct cap_dev cap_dev1;
+	struct cap_dev cap_dev2;
+	struct isp_subdev isp_subdev;
+	struct csi2rx_subdev csi2rx_subdev;
+
+	/* stream_lock - Serialize stream ON/OFF sequence */
+	struct mutex stream_lock;
+
+	/* regbuf_lock - Serialize VIIF Register Buffer Access */
+	spinlock_t regbuf_lock;
+
+	/* pow_lock - serialize power control*/
+	struct mutex pow_lock;
+
+	struct viif_l2_roi_path_info l2_roi_path_info;
+	struct viif_img_clk img_clk;
+	bool run_flag_main;
+
+	void __iomem *capture_reg;
+	void __iomem *csi2host_reg;
+	void __iomem *hwaif_reg;
+	void __iomem *mpu_reg;
+	unsigned int irq[VIIF_HW_AVAILABLE_IRQS];
+
+	/* Un-cache table area */
+	struct viif_table_area *tables;
+	struct viif_table_area *tables_dma;
+
+	/* Rawpack mode */
+	u32 rawpack_mode;
+
+	/* work queue to save L1 status of the latest frame */
+	struct workqueue_struct *wq;
+	struct work_struct work;
+
+	/* Error flag checked at delayed vsync handler  */
+	u32 status_err;
+
+	/* Error flag checked at compound control GET_REPORTED_ERRORS  */
+	u32 reported_err_main;
+	u32 reported_err_sub;
+	u32 reported_err_csi2rx;
+};
+
+static inline void viif_capture_write(struct viif_device *viif_dev, unsigned int regid, u32 val)
+{
+	writel(val, viif_dev->capture_reg + regid);
+}
+
+static inline u32 viif_capture_read(struct viif_device *viif_dev, unsigned int regid)
+{
+	return readl(viif_dev->capture_reg + regid);
+}
+
+#endif /* VIIF_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_capture.c b/drivers/media/platform/toshiba/visconti/viif_capture.c
new file mode 100644
index 000000000..aa3d1bbd1
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_capture.c
@@ -0,0 +1,1481 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_regs.h"
+
+/* single plane for RGB/Grayscale types, 3 planes for YUV types */
+#define VIIF_MAX_PLANE_NUM 3
+
+/* maximum horizontal/vertical position/dimension of CROP with ISP */
+#define VIIF_CROP_MAX_X_ISP 8062U
+#define VIIF_CROP_MAX_Y_ISP 3966U
+#define VIIF_CROP_MAX_W_ISP 8190U
+#define VIIF_CROP_MAX_H_ISP 4094U
+
+/* minimum horizontal/vertical dimension of CROP */
+#define VIIF_CROP_MIN_W 128U
+#define VIIF_CROP_MIN_H 128U
+
+/* maximum output size with ISP */
+#define VIIF_MAX_OUTPUT_IMG_WIDTH_ISP  5760U
+#define VIIF_MAX_OUTPUT_IMG_HEIGHT_ISP 3240U
+#define VIIF_MAX_PITCH_ISP	       32704U
+
+/* maximum output size for SUB path */
+#define VIIF_MAX_OUTPUT_IMG_WIDTH_SUB  4096U
+#define VIIF_MAX_OUTPUT_IMG_HEIGHT_SUB 2160U
+#define VIIF_MAX_PITCH		       65536U
+
+/* minimum output size */
+#define VIIF_MIN_OUTPUT_IMG_WIDTH  128U
+#define VIIF_MIN_OUTPUT_IMG_HEIGHT 128U
+
+/* DMA settings for SUB path */
+#define VDMAC_SRAM_BASE_ADDR_W03 0x440U
+#define SRAM_SIZE_W_PORT	 0x200
+
+enum viif_color_format {
+	VIIF_YCBCR422_8_PACKED = 0,
+	VIIF_RGB888_PACKED = 1U,
+	VIIF_ARGB8888_PACKED = 3U,
+	VIIF_YCBCR422_8_PLANAR = 8U,
+	VIIF_RGB888_YCBCR444_8_PLANAR = 9U,
+	VIIF_ONE_COLOR_8 = 11U,
+	VIIF_YCBCR422_16_PLANAR = 12U,
+	VIIF_RGB161616_YCBCR444_16_PLANAR = 13U,
+	VIIF_ONE_COLOR_16 = 15U
+};
+
+/**
+ * struct viif_csc_param - color conversion information
+ * @r_cr_in_offset: input offset of R/Cr
+ * @g_y_in_offset: input offset of G/Y
+ * @b_cb_in_offset: input offset of B/Cb
+ * @coef: coefficient of matrix.
+ * @r_cr_out_offset: output offset of R/Cr
+ * @g_y_out_offset: output offset of G/Y
+ * @b_cb_out_offset: output offset of B/Cb
+ *
+ * Range of parameters is:
+ *
+ * - {r_cr,g_y,b_cb}_{in,out}_offset
+ *
+ *   - Range: [0x0..0x1FFFF]
+ *
+ * - coef
+ *
+ *   - Range: [0x0..0xFFFF]
+ *   - [0] : c00(YG_YG), [1] : c01(UB_YG), [2] : c02(VR_YG),
+ *   - [3] : c10(YG_UB), [4] : c11(UB_UB), [5] : c12(VR_UB),
+ *   - [6] : c20(YG_VR), [7] : c21(UB_VR), [8] : c22(VR_VR)
+ */
+struct viif_csc_param {
+	u32 r_cr_in_offset;
+	u32 g_y_in_offset;
+	u32 b_cb_in_offset;
+	u32 coef[9];
+	u32 r_cr_out_offset;
+	u32 g_y_out_offset;
+	u32 b_cb_out_offset;
+};
+
+/**
+ * struct viif_pixelmap - pixelmap information
+ * @pmap_dma: start address of pixel data(DMA address). 4byte alignment.
+ * @pitch: pitch size of pixel map [unit: byte]
+ *
+ * Condition of pitch in case of L2ISP output is as below.
+ *
+ * * max: 32704
+ * * min: max (active width of image * k / r, 128)
+ * * alignment: 64
+ *
+ * Condition of pitch in the other cases is as below.
+ *
+ * * max: 65536
+ * * min: active width of image * k / r
+ * * alignment: 4
+ *
+ * k is the size of 1 pixel and the value is as below.
+ *
+ * * VIIF_YCBCR422_8_PACKED: 2
+ * * VIIF_RGB888_PACKED: 3
+ * * VIIF_ARGB8888_PACKED: 4
+ * * VIIF_YCBCR422_8_PLANAR: 1
+ * * VIIF_RGB888_YCBCR444_8_PLANAR: 1
+ * * VIIF_ONE_COLOR_8: 1
+ * * VIIF_YCBCR422_16_PLANAR: 2
+ * * VIIF_RGB161616_YCBCR444_16_PLANAR: 2
+ * * VIIF_ONE_COLOR_16: 2
+ *
+ * r is the correction factor for Cb or Cr of YCbCr422 planar and the value is as below.
+ *
+ * * YCbCr422 Cb-planar: 2
+ * * YCbCr422 Cr-planar: 2
+ * * others: 1
+ */
+struct viif_pixelmap {
+	dma_addr_t pmap_dma;
+	u32 pitch;
+};
+
+/**
+ * struct viif_img - image information
+ * @width: active width of image [unit: pixel]
+ * * Range: [128..5760](output from L2ISP)
+ * * Range: [128..4096](output from SUB unit)
+ * * The value should be even.
+ *
+ * @height: active height of image[line]
+ * * Range: [128..3240](output from L2ISP)
+ * * Range: [128..2160](output from SUB unit)
+ * * The value should be even.
+ *
+ * @format: viif_color_format "color format"
+ * * Below color formats are supported for input and output of MAIN unit
+ * * VIIF_YCBCR422_8_PACKED
+ * * VIIF_RGB888_PACKED
+ * * VIIF_ARGB8888_PACKED
+ * * VIIF_YCBCR422_8_PLANAR
+ * * VIIF_RGB888_YCBCR444_8_PLANAR
+ * * VIIF_ONE_COLOR_8
+ * * VIIF_YCBCR422_16_PLANAR
+ * * VIIF_RGB161616_YCBCR444_16_PLANAR
+ * * VIIF_ONE_COLOR_16
+ * * Below color formats are supported for output of SUB unit
+ * * VIIF_ONE_COLOR_8
+ * * VIIF_ONE_COLOR_16
+ *
+ * @pixelmap: pixelmap information
+ * * [0]: Y/G-planar, packed/Y/RAW
+ * * [1]: Cb/B-planar
+ * * [2]: Cr/R-planar
+ */
+struct viif_img {
+	u32 width;
+	u32 height;
+	enum viif_color_format format;
+	struct viif_pixelmap pixelmap[VIIF_MAX_PLANE_NUM];
+};
+
+/*=============================================*/
+/* Low Layer Implementation */
+/*=============================================*/
+/**
+ * viif_l2_set_output_csc() - Set output CSC parameters of L2ISP
+ *
+ * @post_id: POST ID. Range: [0..1]
+ * @param: Pointer to output csc parameters of L2ISP
+ */
+static int viif_l2_set_output_csc(struct viif_device *viif_dev, u32 post_id,
+				  const struct viif_csc_param *param)
+{
+	/* disable csc matrix when param is NULL */
+	if (!param) {
+		viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB(post_id), 0);
+		return 0;
+	}
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG_OFFSETI(post_id),
+			   param->g_y_in_offset);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG1(post_id),
+			   FIELD_CSC_MTB_LOWER(param->coef[0]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG2(post_id),
+			   FIELD_CSC_MTB_UPPER(param->coef[1]) |
+				   FIELD_CSC_MTB_LOWER(param->coef[2]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG_OFFSETO(post_id),
+			   param->g_y_out_offset);
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB_OFFSETI(post_id),
+			   param->b_cb_in_offset);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB1(post_id),
+			   FIELD_CSC_MTB_LOWER(param->coef[3]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB2(post_id),
+			   FIELD_CSC_MTB_UPPER(param->coef[4]) |
+				   FIELD_CSC_MTB_LOWER(param->coef[5]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB_OFFSETO(post_id),
+			   param->b_cb_out_offset);
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR_OFFSETI(post_id),
+			   param->r_cr_in_offset);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR1(post_id),
+			   FIELD_CSC_MTB_LOWER(param->coef[6]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR2(post_id),
+			   FIELD_CSC_MTB_UPPER(param->coef[7]) |
+				   FIELD_CSC_MTB_LOWER(param->coef[8]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR_OFFSETO(post_id),
+			   param->r_cr_out_offset);
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB(post_id), 1);
+
+	return 0;
+}
+
+struct viif_out_format_spec {
+	int num_planes;
+	int bytes_per_px;
+	int pitch_align;
+	int skips_px[3];
+};
+
+struct viif_out_format_spec out_format_spec[] = {
+	[VIIF_YCBCR422_8_PACKED] = {
+		.num_planes = 1,
+		.bytes_per_px = 2,
+		.pitch_align = 256,
+		.skips_px = {1},
+	},
+	[VIIF_RGB888_PACKED] = {
+		.num_planes = 1,
+		.bytes_per_px = 3,
+		.pitch_align = 384,
+		.skips_px = {1},
+	},
+	[VIIF_ARGB8888_PACKED] = {
+		.num_planes = 1,
+		.bytes_per_px = 4,
+		.pitch_align = 512,
+		.skips_px = {1},
+	},
+	[VIIF_ONE_COLOR_8] = {
+		.num_planes = 1,
+		.bytes_per_px = 1,
+		.pitch_align = 128,
+		.skips_px = {1},
+	},
+	[VIIF_ONE_COLOR_16] = {
+		.num_planes = 1,
+		.bytes_per_px = 2,
+		.pitch_align = 128,
+		.skips_px = {1},
+	},
+	[VIIF_YCBCR422_8_PLANAR] = {
+		.num_planes = 3,
+		.bytes_per_px = 1,
+		.pitch_align = 128,
+		.skips_px = {1, 2, 2},
+	},
+	[VIIF_RGB888_YCBCR444_8_PLANAR] = {
+		.num_planes = 3,
+		.bytes_per_px = 1,
+		.pitch_align = 128,
+		.skips_px = {1, 1, 1},
+	},
+	[VIIF_YCBCR422_16_PLANAR] = {
+		.num_planes = 3,
+		.bytes_per_px = 2,
+		.pitch_align = 128,
+		.skips_px = {1, 2, 2},
+	},
+	[VIIF_RGB161616_YCBCR444_16_PLANAR] = {
+		.num_planes = 3,
+		.bytes_per_px = 2,
+		.pitch_align = 128,
+		.skips_px = {1, 1, 1}
+	}
+};
+
+/**
+ * viif_l2_set_img_transmission() - Set image transfer condition of L2ISP
+ *
+ * @post_id: POST ID. Range: [0..1]
+ * @enable: set True to enable image transfer of MAIN unit.
+ * @src: Pointer to crop area information
+ * @out_process: Pointer to output process information
+ * @img: Pointer to output image information
+ *
+ * see also: #viif_l2_set_roi_path
+ */
+static int viif_l2_set_img_transmission(struct viif_device *viif_dev, u32 post_id, bool enable,
+					const struct viif_img_area *src,
+					const struct viif_out_process *out_process,
+					const struct viif_img *img)
+{
+	dma_addr_t img_start_addr[VIIF_MAX_PLANE_NUM];
+	u32 pitch[VIIF_MAX_PLANE_NUM];
+	struct viif_out_format_spec *spec;
+	unsigned int i;
+
+	/* pitch alignment for planar or one color format */
+	if (post_id >= VIIF_MAX_POST_NUM || (enable && (!src || !out_process)) ||
+	    (!enable && (src || out_process))) {
+		return -EINVAL;
+	}
+
+	/* DISABLE: no DMA transmission setup, set minimum crop rectangle */
+	if (!enable) {
+		viif_dev->l2_roi_path_info.post_enable_flag[post_id] = false;
+		viif_dev->l2_roi_path_info.post_crop_x[post_id] = 0U;
+		viif_dev->l2_roi_path_info.post_crop_y[post_id] = 0U;
+		viif_dev->l2_roi_path_info.post_crop_w[post_id] = VIIF_CROP_MIN_W;
+		viif_dev->l2_roi_path_info.post_crop_h[post_id] = VIIF_CROP_MIN_H;
+		visconti_viif_l2_set_roi_path(viif_dev);
+
+		return 0;
+	}
+
+	if (out_process->select_color != VIIF_COLOR_Y_G &&
+	    out_process->select_color != VIIF_COLOR_U_B &&
+	    out_process->select_color != VIIF_COLOR_V_R &&
+	    out_process->select_color != VIIF_COLOR_YUV_RGB) {
+		return -EINVAL;
+	}
+
+	if (img->format != VIIF_ARGB8888_PACKED && out_process->alpha)
+		return -EINVAL;
+
+	if ((img->width % 2U) || (img->height % 2U) || img->width < VIIF_MIN_OUTPUT_IMG_WIDTH ||
+	    img->height < VIIF_MIN_OUTPUT_IMG_HEIGHT ||
+	    img->width > VIIF_MAX_OUTPUT_IMG_WIDTH_ISP ||
+	    img->height > VIIF_MAX_OUTPUT_IMG_HEIGHT_ISP) {
+		return -EINVAL;
+	}
+
+	if (src->x > VIIF_CROP_MAX_X_ISP || src->y > VIIF_CROP_MAX_Y_ISP ||
+	    src->w < VIIF_CROP_MIN_W || src->w > VIIF_CROP_MAX_W_ISP || src->h < VIIF_CROP_MIN_H ||
+	    src->h > VIIF_CROP_MAX_H_ISP) {
+		return -EINVAL;
+	}
+
+	if (out_process->half_scale) {
+		if ((src->w != (img->width * 2U)) || (src->h != (img->height * 2U)))
+			return -EINVAL;
+	} else {
+		if (src->w != img->width || src->h != img->height)
+			return -EINVAL;
+	}
+
+	if (out_process->select_color == VIIF_COLOR_Y_G ||
+	    out_process->select_color == VIIF_COLOR_U_B ||
+	    out_process->select_color == VIIF_COLOR_V_R) {
+		if (img->format != VIIF_ONE_COLOR_8 && img->format != VIIF_ONE_COLOR_16)
+			return -EINVAL;
+	}
+
+	spec = &out_format_spec[img->format];
+	if (!spec->num_planes)
+		return -EINVAL;
+
+	for (i = 0; i < spec->num_planes; i++) {
+		img_start_addr[i] = (u32)img->pixelmap[i].pmap_dma;
+		pitch[i] = img->pixelmap[i].pitch;
+	}
+
+	for (i = 0; i < spec->num_planes; i++) {
+		u32 pitch_req = max(((img->width * spec->bytes_per_px) / spec->skips_px[i]), 128U);
+
+		if (pitch[i] < pitch_req || pitch[i] > VIIF_MAX_PITCH_ISP ||
+		    (pitch[i] % spec->pitch_align) || (img_start_addr[i] % 4U)) {
+			return -EINVAL;
+		}
+	}
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_OUT_STADR_G(post_id), (u32)img_start_addr[0]);
+	viif_capture_write(viif_dev, REG_L2_POST_X_OUT_PITCH_G(post_id), pitch[0]);
+	if (spec->num_planes == 3) {
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_STADR_B(post_id),
+				   (u32)img_start_addr[1]);
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_STADR_R(post_id),
+				   (u32)img_start_addr[2]);
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_PITCH_B(post_id), pitch[1]);
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_PITCH_R(post_id), pitch[2]);
+	}
+
+	/* Set CROP */
+	viif_capture_write(viif_dev, REG_L2_POST_X_CAP_OFFSET(post_id), (src->y << 16U) | src->x);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CAP_SIZE(post_id), (src->h << 16U) | src->w);
+
+	/* Set output process */
+	viif_capture_write(viif_dev, REG_L2_POST_X_HALF_SCALE_EN(post_id),
+			   out_process->half_scale ? 1 : 0);
+	viif_capture_write(viif_dev, REG_L2_POST_X_C_SELECT(post_id), out_process->select_color);
+	viif_capture_write(viif_dev, REG_L2_POST_X_OPORTALP(post_id), (u32)out_process->alpha);
+	viif_capture_write(viif_dev, REG_L2_POST_X_OPORTFMT(post_id), img->format);
+
+	/* Update ROI area and input to each POST */
+	viif_dev->l2_roi_path_info.post_enable_flag[post_id] = true;
+	viif_dev->l2_roi_path_info.post_crop_x[post_id] = src->x;
+	viif_dev->l2_roi_path_info.post_crop_y[post_id] = src->y;
+	viif_dev->l2_roi_path_info.post_crop_w[post_id] = src->w;
+	viif_dev->l2_roi_path_info.post_crop_h[post_id] = src->h;
+	visconti_viif_l2_set_roi_path(viif_dev);
+
+	return 0;
+}
+
+/**
+ * viif_sub_set_img_transmission() - Set image transfer condition of SUB unit
+ *
+ * @img: Pointer to output image information
+ */
+static int viif_sub_set_img_transmission(struct viif_device *viif_dev, const struct viif_img *img)
+{
+	dma_addr_t img_start_addr, img_end_addr;
+	u32 data_width, pitch, height;
+	u32 bytes_px, port_control;
+
+	/* disable VDMAC when img is NULL */
+	if (!img) {
+		viif_capture_write(viif_dev, REG_IPORTS_IMGEN, 0);
+		port_control = ~((u32)1U << 3U) & viif_capture_read(viif_dev, REG_VDM_W_ENABLE);
+		viif_capture_write(viif_dev, REG_VDM_W_ENABLE, port_control);
+		return 0;
+	}
+
+	if ((img->width % 2U) || (img->height % 2U))
+		return -EINVAL;
+
+	if (img->width < VIIF_MIN_OUTPUT_IMG_WIDTH || img->height < VIIF_MIN_OUTPUT_IMG_HEIGHT ||
+	    img->width > VIIF_MAX_OUTPUT_IMG_WIDTH_SUB ||
+	    img->height > VIIF_MAX_OUTPUT_IMG_HEIGHT_SUB) {
+		return -EINVAL;
+	}
+
+	img_start_addr = (u32)img->pixelmap[0].pmap_dma;
+	pitch = img->pixelmap[0].pitch;
+	height = img->height;
+
+	switch (img->format) {
+	case VIIF_ONE_COLOR_8:
+		data_width = 0U;
+		img_end_addr = img_start_addr + img->width - 1U;
+		bytes_px = 1;
+		break;
+	case VIIF_ONE_COLOR_16:
+		data_width = 1U;
+		img_end_addr = img_start_addr + (img->width * 2U) - 1U;
+		bytes_px = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (img_start_addr % 4U)
+		return -EINVAL;
+
+	if ((pitch < (img->width * bytes_px)) || pitch > VIIF_MAX_PITCH || (pitch % 4U))
+		return -EINVAL;
+
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_SRAM_BASE(IDX_WPORT_SUB_IMG),
+			   VDMAC_SRAM_BASE_ADDR_W03);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_SRAM_SIZE(IDX_WPORT_SUB_IMG),
+			   SRAM_SIZE_W_PORT);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_STADR(IDX_WPORT_SUB_IMG),
+			   (u32)img_start_addr);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_ENDADR(IDX_WPORT_SUB_IMG),
+			   (u32)img_end_addr);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_HEIGHT(IDX_WPORT_SUB_IMG), height);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_PITCH(IDX_WPORT_SUB_IMG), pitch);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_CFG0(IDX_WPORT_SUB_IMG), data_width << 8U);
+	port_control = BIT(3) | viif_capture_read(viif_dev, REG_VDM_W_ENABLE);
+	viif_capture_write(viif_dev, REG_VDM_W_ENABLE, port_control);
+	viif_capture_write(viif_dev, REG_IPORTS_IMGEN, 1);
+
+	return 0;
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+struct viif_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head queue;
+};
+
+static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
+{
+	return container_of(vbuf, struct viif_buffer, vb);
+}
+
+static inline struct cap_dev *video_drvdata_to_capdev(struct file *file)
+{
+	return (struct cap_dev *)video_drvdata(file);
+}
+
+static inline struct cap_dev *vb2queue_to_capdev(struct vb2_queue *vq)
+{
+	return (struct cap_dev *)vb2_get_drv_priv(vq);
+}
+
+/* ----- ISRs and VB2 Operations ----- */
+static void viif_regbuf_access_start(struct viif_device *viif_dev)
+{
+	spin_lock(&viif_dev->regbuf_lock);
+	hwd_viif_isp_guard_start(viif_dev);
+}
+
+static void viif_regbuf_access_end(struct viif_device *viif_dev)
+{
+	hwd_viif_isp_guard_end(viif_dev);
+	spin_unlock(&viif_dev->regbuf_lock);
+}
+
+static int viif_set_img(struct cap_dev *cap_dev, struct vb2_buffer *vb)
+{
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct viif_img next_out_img;
+	int i, ret = 0;
+
+	next_out_img.width = pix->width;
+	next_out_img.height = pix->height;
+	next_out_img.format = cap_dev->out_format;
+
+	for (i = 0; i < pix->num_planes; i++) {
+		next_out_img.pixelmap[i].pitch = pix->plane_fmt[i].bytesperline;
+		next_out_img.pixelmap[i].pmap_dma = vb2_dma_contig_plane_dma_addr(vb, i);
+	}
+
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		viif_regbuf_access_start(viif_dev);
+		ret = viif_l2_set_img_transmission(viif_dev, VIIF_L2ISP_POST_0, true,
+						   &cap_dev->img_area, &cap_dev->out_process,
+						   &next_out_img);
+		viif_regbuf_access_end(viif_dev);
+		if (ret)
+			dev_err(viif_dev->dev, "set img error. %d\n", ret);
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		viif_regbuf_access_start(viif_dev);
+		ret = viif_l2_set_img_transmission(viif_dev, VIIF_L2ISP_POST_1, true,
+						   &cap_dev->img_area, &cap_dev->out_process,
+						   &next_out_img);
+		viif_regbuf_access_end(viif_dev);
+		if (ret)
+			dev_err(viif_dev->dev, "set img error. %d\n", ret);
+	} else if (cap_dev->pathid == CAPTURE_PATH_SUB) {
+		viif_regbuf_access_start(viif_dev);
+		ret = viif_sub_set_img_transmission(viif_dev, &next_out_img);
+		viif_regbuf_access_end(viif_dev);
+		if (ret)
+			dev_err(viif_dev->dev, "set img error. %d\n", ret);
+	}
+
+	return ret;
+}
+
+/*
+ * viif_capture_switch_buffer() is called from interrupt service routine
+ * triggered by VSync with some fixed delay.
+ * The function may switch DMA target buffer by calling viif_set_img().
+ * The VIIF DMA HW captures the destination address at next VSync
+ * and completes transfer at one more after.
+ * Therefore, filled buffer is available at the one after next ISR.
+ *
+ * To avoid DMA HW getting stucked, we always need to set valid destination address.
+ * If a prepared buffer is not available, we reuse the buffer currently being transferred to.
+ *
+ * The cap_dev structure has two pointers and a queue to handle video buffers;
+ + Description of each item at the entry of this function:
+ * * buf_queue:  holds prepared buffers, set by vb2_queue()
+ * * active:     pointing at address captured (and to be filled) by DMA HW
+ * * dma_active: pointing at buffer filled by DMA HW
+ *
+ * Rules to update items:
+ * * when buf_queue is not empty, "active" buffer goes "dma_active"
+ * * when buf_queue is empty:
+ *   * "active" buffer stays the same (DMA HW fills the same buffer for coming two frames)
+ *   * "dma_active" gets NULL (filled buffer will be reused; should not go "DONE" at next ISR)
+ *
+ * Simulation:
+ * | buf_queue   | active  | dma_active | note |
+ * | X           | NULL    | NULL       |      |
+ * <QBUF BUF0>
+ * | X           | BUF0    | NULL       | BUF0 stays |
+ * | X           | BUF0    | NULL       | BUF0 stays |
+ * <QBUF BUF1>
+ * <QBUF BUF2>
+ * | BUF2 BUF1   | BUF0    | NULL       |      |
+ * | BUF2        | BUF1    | BUF0       | BUF0 goes DONE |
+ * | X           | BUF2    | BUF1       | BUF1 goes DONE, BUF2 stays |
+ * | X           | BUF2    | NULL       | BUF2 stays |
+ */
+void visconti_viif_capture_switch_buffer(struct cap_dev *cap_dev, u32 status_err,
+					 u32 l2_transfer_status, u64 timestamp)
+{
+	spin_lock(&cap_dev->buf_lock);
+
+	if (cap_dev->dma_active) {
+		/* DMA has completed and another framebuffer instance is set */
+		struct vb2_v4l2_buffer *vbuf = cap_dev->dma_active;
+		enum vb2_buffer_state state;
+
+		cap_dev->buf_cnt--;
+		vbuf->vb2_buf.timestamp = timestamp;
+		vbuf->sequence = cap_dev->sequence++;
+		vbuf->field = V4L2_FIELD_NONE;
+		if (status_err || l2_transfer_status)
+			state = VB2_BUF_STATE_ERROR;
+		else
+			state = VB2_BUF_STATE_DONE;
+
+		vb2_buffer_done(&vbuf->vb2_buf, state);
+	}
+
+	/* QUEUE pop to register an instance as next DMA target; if empty, reuse current instance */
+	if (!list_empty(&cap_dev->buf_queue)) {
+		struct viif_buffer *buf =
+			list_entry(cap_dev->buf_queue.next, struct viif_buffer, queue);
+		list_del_init(&buf->queue);
+		viif_set_img(cap_dev, &buf->vb.vb2_buf);
+		cap_dev->dma_active = cap_dev->active;
+		cap_dev->active = &buf->vb;
+	} else {
+		cap_dev->dma_active = NULL;
+	}
+
+	spin_unlock(&cap_dev->buf_lock);
+}
+
+/* --- Capture buffer control --- */
+static int viif_vb2_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes,
+			  unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vq);
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	unsigned int i;
+
+	/* num_planes is set: just check plane sizes. */
+	if (*num_planes) {
+		for (i = 0; i < pix->num_planes; i++)
+			if (sizes[i] < pix->plane_fmt[i].sizeimage)
+				return -EINVAL;
+
+		return 0;
+	}
+
+	/* num_planes not set: called from REQBUFS, just set plane sizes. */
+	*num_planes = pix->num_planes;
+	for (i = 0; i < pix->num_planes; i++)
+		sizes[i] = pix->plane_fmt[i].sizeimage;
+
+	cap_dev->buf_cnt = 0;
+
+	return 0;
+}
+
+static void viif_vb2_queue(struct vb2_buffer *vb)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct viif_buffer *buf = vb2_to_viif(vbuf);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&cap_dev->buf_lock, irqflags);
+
+	if (!cap_dev->active) {
+		cap_dev->active = vbuf;
+		viif_set_img(cap_dev, vb);
+	} else {
+		list_add_tail(&buf->queue, &cap_dev->buf_queue);
+	}
+	cap_dev->buf_cnt++;
+
+	spin_unlock_irqrestore(&cap_dev->buf_lock, irqflags);
+}
+
+static int viif_vb2_prepare(struct vb2_buffer *vb)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vb->vb2_queue);
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	unsigned int i;
+
+	for (i = 0; i < pix->num_planes; i++) {
+		if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) {
+			dev_err(viif_dev->dev, "Plane size too small (%lu < %u)\n",
+				vb2_plane_size(vb, i), pix->plane_fmt[i].sizeimage);
+			return -EINVAL;
+		}
+
+		vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage);
+	}
+	return 0;
+}
+
+static void viif_return_all_buffers(struct cap_dev *cap_dev, enum vb2_buffer_state state)
+{
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct viif_buffer *buf;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&cap_dev->buf_lock, irqflags);
+
+	/* buffer control */
+	if (cap_dev->active) {
+		vb2_buffer_done(&cap_dev->active->vb2_buf, state);
+		cap_dev->buf_cnt--;
+		cap_dev->active = NULL;
+	}
+	if (cap_dev->dma_active) {
+		vb2_buffer_done(&cap_dev->dma_active->vb2_buf, state);
+		cap_dev->buf_cnt--;
+		cap_dev->dma_active = NULL;
+	}
+
+	/* Release all queued buffers. */
+	list_for_each_entry(buf, &cap_dev->buf_queue, queue) {
+		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+		cap_dev->buf_cnt--;
+	}
+	INIT_LIST_HEAD(&cap_dev->buf_queue);
+	if (cap_dev->buf_cnt)
+		dev_err(viif_dev->dev, "Buffer count error %d\n", cap_dev->buf_cnt);
+
+	spin_unlock_irqrestore(&cap_dev->buf_lock, irqflags);
+}
+
+static int viif_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vq);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	int ret = 0;
+
+	mutex_lock(&viif_dev->stream_lock);
+
+	/* note that pipe is shared among paths; see pipe.streaming_count member variable */
+	ret = video_device_pipeline_start(&cap_dev->vdev, &viif_dev->pipe);
+	if (ret) {
+		dev_err(viif_dev->dev, "start pipeline failed %d\n", ret);
+		goto release_lock;
+	}
+
+	/* buffer control */
+	cap_dev->sequence = 0;
+
+	/* Currently, only path0 (MAIN POST0) initializes ISP and Camera */
+	/* Possibly, initialization can be done when pipe.streaming_count==0 */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		/* CSI2RX start */
+		ret = v4l2_subdev_call(&viif_dev->isp_subdev.sd, video, s_stream, true);
+		if (ret) {
+			dev_err(viif_dev->dev, "Start isp subdevice stream failed. %d\n", ret);
+			viif_return_all_buffers(cap_dev, VB2_BUF_STATE_QUEUED);
+			video_device_pipeline_stop(&cap_dev->vdev);
+			goto release_lock;
+		}
+	}
+
+release_lock:
+	mutex_unlock(&viif_dev->stream_lock);
+	return ret;
+}
+
+static void viif_stop_streaming(struct vb2_queue *vq)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vq);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	int ret;
+
+	mutex_lock(&viif_dev->stream_lock);
+
+	/* Currently, only path0 (MAIN POST0) stops ISP and Camera */
+	/* Possibly, teardown can be done when pipe.streaming_count==0 */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		ret = v4l2_subdev_call(&viif_dev->isp_subdev.sd, video, s_stream, false);
+		if (ret)
+			dev_err(viif_dev->dev, "Stop isp subdevice stream failed %d\n", ret);
+	}
+
+	viif_return_all_buffers(cap_dev, VB2_BUF_STATE_ERROR);
+	video_device_pipeline_stop(&cap_dev->vdev);
+	mutex_unlock(&viif_dev->stream_lock);
+}
+
+static const struct vb2_ops viif_vb2_ops = {
+	.queue_setup = viif_vb2_setup,
+	.buf_queue = viif_vb2_queue,
+	.buf_prepare = viif_vb2_prepare,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = viif_start_streaming,
+	.stop_streaming = viif_stop_streaming,
+};
+
+/* --- VIIF hardware settings --- */
+/* L2ISP output csc setting for YUV to RGB(ITU-R BT.709) */
+static const struct viif_csc_param viif_csc_yuv2rgb = {
+	.r_cr_in_offset = 0x18000,
+	.g_y_in_offset = 0x1f000,
+	.b_cb_in_offset = 0x18000,
+	.coef = {
+			[0] = 0x1000,
+			[1] = 0xfd12,
+			[2] = 0xf8ad,
+			[3] = 0x1000,
+			[4] = 0x1d07,
+			[5] = 0x0000,
+			[6] = 0x1000,
+			[7] = 0x0000,
+			[8] = 0x18a2,
+		},
+	.r_cr_out_offset = 0x1000,
+	.g_y_out_offset = 0x1000,
+	.b_cb_out_offset = 0x1000,
+};
+
+/* L2ISP output csc setting for RGB to YUV(ITU-R BT.709) */
+static const struct viif_csc_param viif_csc_rgb2yuv = {
+	.r_cr_in_offset = 0x1f000,
+	.g_y_in_offset = 0x1f000,
+	.b_cb_in_offset = 0x1f000,
+	.coef = {
+			[0] = 0x0b71,
+			[1] = 0x0128,
+			[2] = 0x0367,
+			[3] = 0xf9b1,
+			[4] = 0x082f,
+			[5] = 0xfe20,
+			[6] = 0xf891,
+			[7] = 0xff40,
+			[8] = 0x082f,
+		},
+	.r_cr_out_offset = 0x8000,
+	.g_y_out_offset = 0x1000,
+	.b_cb_out_offset = 0x8000,
+};
+
+static int viif_l2_set_format(struct cap_dev *cap_dev)
+{
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	const struct viif_csc_param *csc_param = NULL;
+	struct v4l2_subdev_selection sel = {
+		.target = V4L2_SEL_TGT_CROP,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	bool inp_is_rgb = false;
+	bool out_is_rgb = false;
+	u32 postid;
+	int ret;
+
+	/* check path id */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		sel.pad = VIIF_ISP_PAD_SRC_PATH0;
+		fmt.pad = VIIF_ISP_PAD_SRC_PATH0;
+		postid = VIIF_L2ISP_POST_0;
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		sel.pad = VIIF_ISP_PAD_SRC_PATH1;
+		fmt.pad = VIIF_ISP_PAD_SRC_PATH1;
+		postid = VIIF_L2ISP_POST_1;
+	} else {
+		return -EINVAL;
+	}
+
+	cap_dev->out_process.half_scale = false;
+	cap_dev->out_process.select_color = VIIF_COLOR_YUV_RGB;
+	cap_dev->out_process.alpha = 0;
+
+	ret = v4l2_subdev_call(&viif_dev->isp_subdev.sd, pad, get_selection, NULL, &sel);
+	if (ret) {
+		cap_dev->img_area.x = 0;
+		cap_dev->img_area.y = 0;
+		cap_dev->img_area.w = pix->width;
+		cap_dev->img_area.h = pix->height;
+	} else {
+		cap_dev->img_area.x = sel.r.left;
+		cap_dev->img_area.y = sel.r.top;
+		cap_dev->img_area.w = sel.r.width;
+		cap_dev->img_area.h = sel.r.height;
+	}
+
+	ret = v4l2_subdev_call(&viif_dev->isp_subdev.sd, pad, get_fmt, NULL, &fmt);
+	if (!ret)
+		inp_is_rgb = (fmt.format.code == MEDIA_BUS_FMT_RGB888_1X24);
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_RGB24:
+		cap_dev->out_format = VIIF_RGB888_PACKED;
+		out_is_rgb = true;
+		break;
+	case V4L2_PIX_FMT_ABGR32:
+		cap_dev->out_format = VIIF_ARGB8888_PACKED;
+		cap_dev->out_process.alpha = 0xff;
+		out_is_rgb = true;
+		break;
+	case V4L2_PIX_FMT_YUV422M:
+		cap_dev->out_format = VIIF_YCBCR422_8_PLANAR;
+		break;
+	case V4L2_PIX_FMT_YUV444M:
+		cap_dev->out_format = VIIF_RGB888_YCBCR444_8_PLANAR;
+		break;
+	case V4L2_PIX_FMT_Y16:
+		cap_dev->out_format = VIIF_ONE_COLOR_16;
+		cap_dev->out_process.select_color = VIIF_COLOR_Y_G;
+		break;
+	}
+
+	if (!inp_is_rgb && out_is_rgb)
+		csc_param = &viif_csc_yuv2rgb; /* YUV -> RGB */
+	else if (inp_is_rgb && !out_is_rgb)
+		csc_param = &viif_csc_rgb2yuv; /* RGB -> YUV */
+
+	return viif_l2_set_output_csc(viif_dev, postid, csc_param);
+}
+
+/* --- IOCTL Operations --- */
+static const struct viif_fmt viif_capture_fmt_list_mainpath[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.bpp = { 24, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 384,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.bpp = { 32, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 512,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422M,
+		.bpp = { 8, 4, 4 },
+		.num_planes = 3,
+		.colorspace = V4L2_COLORSPACE_REC709,
+		.pitch_align = 128,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV444M,
+		.bpp = { 8, 8, 8 },
+		.num_planes = 3,
+		.colorspace = V4L2_COLORSPACE_REC709,
+		.pitch_align = 128,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_Y16,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_REC709,
+		.pitch_align = 128,
+	},
+};
+
+static const struct viif_fmt viif_capture_fmt_list_subpath[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_SRGGB8,
+		.bpp = { 8, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SRGGB10,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SRGGB12,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SRGGB14,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+};
+
+static const struct viif_fmt *get_viif_fmt_from_fourcc(struct cap_dev *cap_dev, unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < cap_dev->fmt_size; i++) {
+		const struct viif_fmt *fmt = &cap_dev->fmts[i];
+
+		if (fmt->fourcc == fourcc)
+			return fmt;
+	}
+	return NULL;
+}
+
+static u32 get_pixelformat_from_fourcc(struct cap_dev *cap_dev, unsigned int fourcc)
+{
+	const struct viif_fmt *fmt = get_viif_fmt_from_fourcc(cap_dev, fourcc);
+
+	return fmt ? fmt->fourcc : cap_dev->fmts[0].fourcc;
+}
+
+static u32 get_pixelformat_from_mbus_code(struct cap_dev *cap_dev, unsigned int mbus_code)
+{
+	const struct viif_fmt *fmt;
+	unsigned int fourcc;
+
+	switch (mbus_code) {
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+		fourcc = V4L2_PIX_FMT_SRGGB8;
+		break;
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+		fourcc = V4L2_PIX_FMT_SRGGB10;
+		break;
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+		fourcc = V4L2_PIX_FMT_SRGGB12;
+		break;
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+		fourcc = V4L2_PIX_FMT_SRGGB14;
+		break;
+	default:
+		return cap_dev->fmts[0].fourcc;
+	}
+
+	fmt = get_viif_fmt_from_fourcc(cap_dev, fourcc);
+	return fmt ? fmt->fourcc : cap_dev->fmts[0].fourcc;
+}
+
+static void viif_calc_plane_sizes(struct cap_dev *cap_dev, struct v4l2_pix_format_mplane *pix)
+{
+	const struct viif_fmt *viif_fmt = get_viif_fmt_from_fourcc(cap_dev, pix->pixelformat);
+	unsigned int i;
+
+	for (i = 0; i < viif_fmt->num_planes; i++) {
+		struct v4l2_plane_pix_format *plane_i = &pix->plane_fmt[i];
+		unsigned int bpl;
+
+		memset(plane_i, 0, sizeof(*plane_i));
+		bpl = roundup(pix->width * viif_fmt->bpp[i] / 8, viif_fmt->pitch_align);
+
+		plane_i->bytesperline = bpl;
+		plane_i->sizeimage = pix->height * bpl;
+	}
+	pix->num_planes = viif_fmt->num_planes;
+}
+
+static int viif_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	struct viif_device *viif_dev = video_drvdata_to_capdev(file)->viif_dev;
+
+	strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
+	snprintf(cap->card, sizeof(cap->card), "%s-%s", VIIF_DRIVER_NAME, dev_name(viif_dev->dev));
+	/* TODO: platform:visconti-viif-0,1,2,3 for each VIIF driver instance */
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "%s-0", VIIF_BUS_INFO_BASE);
+
+	return 0;
+}
+
+static int viif_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	if (f->index >= cap_dev->fmt_size)
+		return -EINVAL;
+
+	f->pixelformat = cap_dev->fmts[f->index].fourcc;
+	return 0;
+}
+
+static void viif_try_fmt(struct cap_dev *cap_dev, struct v4l2_pix_format_mplane *pix)
+{
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_subdev_format format = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	int ret;
+
+	/* check path id */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0)
+		format.pad = VIIF_ISP_PAD_SRC_PATH0;
+	else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1)
+		format.pad = VIIF_ISP_PAD_SRC_PATH1;
+	else
+		format.pad = VIIF_ISP_PAD_SRC_PATH2;
+
+	pix->field = V4L2_FIELD_NONE;
+	pix->colorspace = V4L2_COLORSPACE_DEFAULT;
+	pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	pix->quantization = V4L2_QUANTIZATION_DEFAULT;
+
+	ret = v4l2_subdev_call(&viif_dev->isp_subdev.sd, pad, get_fmt, NULL, &format);
+	if (ret) {
+		/* minimal default format */
+		pix->width = VIIF_MIN_OUTPUT_IMG_WIDTH;
+		pix->height = VIIF_MIN_OUTPUT_IMG_HEIGHT;
+		pix->pixelformat = (cap_dev->pathid == CAPTURE_PATH_SUB) ?
+			V4L2_PIX_FMT_SRGGB8 : V4L2_PIX_FMT_RGB24;
+		viif_calc_plane_sizes(cap_dev, pix);
+		return;
+	}
+
+	pix->width = format.format.width;
+	pix->height = format.format.height;
+
+	/* check output format */
+	pix->pixelformat = (cap_dev->pathid == CAPTURE_PATH_SUB) ?
+		get_pixelformat_from_mbus_code(cap_dev, format.format.code) :
+		get_pixelformat_from_fourcc(cap_dev, pix->pixelformat);
+
+	/* update derived parameters, such as bpp */
+	viif_calc_plane_sizes(cap_dev, pix);
+}
+
+static int viif_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	viif_try_fmt(cap_dev, &f->fmt.pix_mp);
+	return 0;
+}
+
+static int viif_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	int ret = 0;
+
+	if (vb2_is_busy(&cap_dev->vb2_vq))
+		return -EBUSY;
+
+	if (f->type != cap_dev->vb2_vq.type)
+		return -EINVAL;
+
+	viif_try_fmt(cap_dev, &f->fmt.pix_mp);
+	cap_dev->v4l2_pix = f->fmt.pix_mp;
+
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		ret = visconti_viif_isp_main_set_unit(viif_dev);
+		if (ret)
+			return ret;
+
+		ret = viif_l2_set_format(cap_dev);
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		ret = viif_l2_set_format(cap_dev);
+	} else {
+		cap_dev->out_format = (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_SRGGB8) ?
+						    VIIF_ONE_COLOR_8 :
+						    VIIF_ONE_COLOR_16;
+		ret = visconti_viif_isp_sub_set_unit(viif_dev);
+	}
+
+	return ret;
+}
+
+static int viif_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	f->fmt.pix_mp = cap_dev->v4l2_pix;
+
+	return 0;
+}
+
+static int viif_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	if (fsize->index)
+		return -EINVAL;
+
+	if (!get_viif_fmt_from_fourcc(cap_dev, fsize->pixel_format))
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+	fsize->stepwise.min_width = VIIF_MIN_OUTPUT_IMG_WIDTH;
+	fsize->stepwise.max_width = (cap_dev->pathid == CAPTURE_PATH_SUB) ?
+						  VIIF_MAX_OUTPUT_IMG_WIDTH_SUB :
+						  VIIF_MAX_OUTPUT_IMG_WIDTH_ISP;
+	fsize->stepwise.min_height = VIIF_MIN_OUTPUT_IMG_HEIGHT;
+	fsize->stepwise.max_height = (cap_dev->pathid == CAPTURE_PATH_SUB) ?
+						   VIIF_MAX_OUTPUT_IMG_HEIGHT_SUB :
+						   VIIF_MAX_OUTPUT_IMG_HEIGHT_ISP;
+	fsize->stepwise.step_width = 1;
+	fsize->stepwise.step_height = 1;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops viif_ioctl_ops = {
+	.vidioc_querycap = viif_querycap,
+
+	.vidioc_enum_fmt_vid_cap = viif_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap_mplane = viif_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap_mplane = viif_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane = viif_g_fmt_vid_cap,
+
+	.vidioc_enum_framesizes = viif_enum_framesizes,
+
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+
+	.vidioc_log_status = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* --- File Operations --- */
+static const struct v4l2_pix_format_mplane pixm_default[3] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+		.width = 1920,
+		.height = 1080,
+		.field = V4L2_FIELD_NONE,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+		.width = 1920,
+		.height = 1080,
+		.field = V4L2_FIELD_NONE,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_SRGGB8,
+		.width = 1920,
+		.height = 1080,
+		.field = V4L2_FIELD_NONE,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	}
+};
+
+static int viif_capture_open(struct file *file)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_pix_format_mplane pixm;
+	int ret;
+
+	ret = v4l2_fh_open(file);
+	if (ret)
+		return ret;
+
+	ret = pm_runtime_resume_and_get(viif_dev->dev);
+	if (ret) {
+		v4l2_fh_release(file);
+		return ret;
+	}
+
+	/* Initialize image format */
+	pixm = pixm_default[cap_dev->pathid];
+	viif_try_fmt(cap_dev, &pixm);
+	cap_dev->v4l2_pix = pixm;
+
+	return 0;
+}
+
+static int viif_capture_release(struct file *file)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+
+	vb2_fop_release(file);
+	pm_runtime_put(viif_dev->dev);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations viif_fops = {
+	.owner = THIS_MODULE,
+	.open = viif_capture_open,
+	.release = viif_capture_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vb2_fop_mmap,
+	.poll = vb2_fop_poll,
+};
+
+/* ----- media control callbacks ----- */
+static int viif_capture_link_validate(struct media_link *link)
+{
+	/* link validation at start-stream */
+	return 0;
+}
+
+static const struct media_entity_operations viif_media_ops = {
+	.link_validate = viif_capture_link_validate,
+};
+
+/* ----- attach ctrl callbacck handler ----- */
+int visconti_viif_capture_register_ctrl_handlers(struct viif_device *viif_dev)
+{
+	int ret;
+
+	/* MAIN POST0: merge controls of ISP and sensor */
+	ret = v4l2_ctrl_add_handler(&viif_dev->cap_dev0.ctrl_handler,
+				    viif_dev->sd->v4l2_sd->ctrl_handler, NULL, true);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to add sensor ctrl_handler");
+		return ret;
+	}
+	ret = v4l2_ctrl_add_handler(&viif_dev->cap_dev0.ctrl_handler,
+				    &viif_dev->isp_subdev.ctrl_handler, NULL, true);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to add isp subdev ctrl_handler");
+		return ret;
+	}
+
+	/* MAIN POST1: merge controls of ISP and sensor */
+	ret = v4l2_ctrl_add_handler(&viif_dev->cap_dev1.ctrl_handler,
+				    viif_dev->sd->v4l2_sd->ctrl_handler, NULL, true);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to add sensor ctrl_handler");
+		return ret;
+	}
+	ret = v4l2_ctrl_add_handler(&viif_dev->cap_dev1.ctrl_handler,
+				    &viif_dev->isp_subdev.ctrl_handler, NULL, true);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to add isp subdev ctrl_handler");
+		return ret;
+	}
+
+	/* SUB: no control is exported */
+
+	return 0;
+}
+
+/* ----- register/remove capture device node ----- */
+static int visconti_viif_capture_register_node(struct cap_dev *cap_dev)
+{
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_device *v4l2_dev = &viif_dev->v4l2_dev;
+	struct video_device *vdev = &cap_dev->vdev;
+	struct vb2_queue *q = &cap_dev->vb2_vq;
+	static const char *const node_name[] = {
+		"viif_capture_post0",
+		"viif_capture_post1",
+		"viif_capture_sub",
+	};
+	int ret;
+
+	INIT_LIST_HEAD(&cap_dev->buf_queue);
+
+	mutex_init(&cap_dev->vlock);
+	spin_lock_init(&cap_dev->buf_lock);
+
+	/* Initialize vb2 queue. */
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+	q->min_buffers_needed = 3;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->ops = &viif_vb2_ops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->drv_priv = cap_dev;
+	q->buf_struct_size = sizeof(struct viif_buffer);
+	q->lock = &cap_dev->vlock;
+	q->dev = viif_dev->v4l2_dev.dev;
+
+	ret = vb2_queue_init(q);
+	if (ret)
+		return ret;
+
+	/* Register the video device. */
+	strscpy(vdev->name, node_name[cap_dev->pathid], sizeof(vdev->name));
+	vdev->v4l2_dev = v4l2_dev;
+	vdev->lock = &cap_dev->vlock;
+	vdev->queue = &cap_dev->vb2_vq;
+	vdev->ctrl_handler = NULL;
+	vdev->fops = &viif_fops;
+	vdev->ioctl_ops = &viif_ioctl_ops;
+	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
+	vdev->device_caps |= V4L2_CAP_IO_MC;
+	vdev->entity.ops = &viif_media_ops;
+	vdev->release = video_device_release_empty;
+	video_set_drvdata(vdev, cap_dev);
+	vdev->vfl_dir = VFL_DIR_RX;
+	cap_dev->capture_pad.flags = MEDIA_PAD_FL_SINK;
+
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+	if (ret < 0) {
+		dev_err(v4l2_dev->dev, "video_register_device failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = media_entity_pads_init(&vdev->entity, 1, &cap_dev->capture_pad);
+	if (ret) {
+		video_unregister_device(vdev);
+		return ret;
+	}
+
+	ret = v4l2_ctrl_handler_init(&cap_dev->ctrl_handler, 30);
+	if (ret)
+		return -ENOMEM;
+
+	cap_dev->vdev.ctrl_handler = &cap_dev->ctrl_handler;
+
+	return 0;
+}
+
+int visconti_viif_capture_register(struct viif_device *viif_dev)
+{
+	int ret;
+
+	/* register MAIN POST0 (primary RGB)*/
+	viif_dev->cap_dev0.pathid = CAPTURE_PATH_MAIN_POST0;
+	viif_dev->cap_dev0.viif_dev = viif_dev;
+	viif_dev->cap_dev0.fmts = viif_capture_fmt_list_mainpath;
+	viif_dev->cap_dev0.fmt_size = ARRAY_SIZE(viif_capture_fmt_list_mainpath);
+	ret = visconti_viif_capture_register_node(&viif_dev->cap_dev0);
+	if (ret)
+		return ret;
+
+	/* register MAIN POST1 (additional RGB)*/
+	viif_dev->cap_dev1.pathid = CAPTURE_PATH_MAIN_POST1;
+	viif_dev->cap_dev1.viif_dev = viif_dev;
+	viif_dev->cap_dev1.fmts = viif_capture_fmt_list_mainpath;
+	viif_dev->cap_dev1.fmt_size = ARRAY_SIZE(viif_capture_fmt_list_mainpath);
+	ret = visconti_viif_capture_register_node(&viif_dev->cap_dev1);
+	if (ret)
+		return ret;
+
+	/* register SUB (RAW) */
+	viif_dev->cap_dev2.pathid = CAPTURE_PATH_SUB;
+	viif_dev->cap_dev2.viif_dev = viif_dev;
+	viif_dev->cap_dev2.fmts = viif_capture_fmt_list_subpath;
+	viif_dev->cap_dev2.fmt_size = ARRAY_SIZE(viif_capture_fmt_list_subpath);
+	ret = visconti_viif_capture_register_node(&viif_dev->cap_dev2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void visconti_viif_capture_unregister_node(struct cap_dev *cap_dev)
+{
+	media_entity_cleanup(&cap_dev->vdev.entity);
+	v4l2_ctrl_handler_free(&cap_dev->ctrl_handler);
+	vb2_video_unregister_device(&cap_dev->vdev);
+	mutex_destroy(&cap_dev->vlock);
+}
+
+void visconti_viif_capture_unregister(struct viif_device *viif_dev)
+{
+	visconti_viif_capture_unregister_node(&viif_dev->cap_dev0);
+	visconti_viif_capture_unregister_node(&viif_dev->cap_dev1);
+	visconti_viif_capture_unregister_node(&viif_dev->cap_dev2);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_capture.h b/drivers/media/platform/toshiba/visconti/viif_capture.h
new file mode 100644
index 000000000..dded862be
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_capture.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_CAPTURE_H
+#define VIIF_CAPTURE_H
+
+struct viif_device;
+struct cap_dev;
+struct viif_l2_roi_config;
+
+int visconti_viif_capture_register_ctrl_handlers(struct viif_device *viif_dev);
+void visconti_viif_capture_switch_buffer(struct cap_dev *cap_dev, u32 status_err,
+					 u32 l2_transfer_status, u64 timestamp);
+
+int visconti_viif_capture_register(struct viif_device *viif_dev);
+void visconti_viif_capture_unregister(struct viif_device *viif_dev);
+
+#endif /* VIIF_CAPTURE_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_common.c b/drivers/media/platform/toshiba/visconti/viif_common.c
new file mode 100644
index 000000000..0dde5e2a6
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_common.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_regs.h"
+
+/*=============================================*/
+/* Low level guards for registers */
+/*=============================================*/
+
+#define VIIF_L1_CRGBF_R_START_ADDR_LIMIT 0x0200U
+#define VIIF_L1_CRGBF_R_END_ADDR_LIMIT	 0x10BFU
+#define VIIF_L2_CRGBF_R_START_ADDR_LIMIT 0x1CU
+#define VIIF_L2_CRGBF_R_END_ADDR_LIMIT	 0x1FU
+
+/**
+ * hwd_viif_main_mask_vlatch() - Control Vlatch mask of MAIN unit
+ *
+ * @enable: true to enable Vlatch mask of MAIN unit, false to disable
+ */
+static void hwd_viif_main_mask_vlatch(struct viif_device *viif_dev, bool enable)
+{
+	u32 val = enable ? MASK_IPORTM_VLATCH : 0;
+
+	viif_capture_write(viif_dev, REG_IPORTM0_LD, val);
+	viif_capture_write(viif_dev, REG_IPORTM1_LD, val);
+}
+
+/**
+ * hwd_viif_isp_set_regbuf_auto_transmission() - Set register buffer auto transmission
+ */
+void hwd_viif_isp_set_regbuf_auto_transmission(struct viif_device *viif_dev)
+{
+	/* Set parameters for auto read transmission of register buffer */
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_RBADDR, VIIF_L1_CRGBF_R_START_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_READDR, VIIF_L1_CRGBF_R_END_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_RBADDR, VIIF_L2_CRGBF_R_START_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_READDR, VIIF_L2_CRGBF_R_END_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, VAL_L2_CRGBF_TRN_AUTO_READ_BANK0);
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, VAL_L1_CRGBF_TRN_AUTO_READ_BANK0);
+}
+
+/**
+ * hwd_viif_isp_disable_regbuf_auto_transmission() - Disable register buffer auto transmission
+ */
+void hwd_viif_isp_disable_regbuf_auto_transmission(struct viif_device *viif_dev)
+{
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, 0);
+}
+
+/**
+ * hwd_viif_isp_guard_start() - stop register auto update
+ *
+ *
+ * This function call stops update of some hardware registers
+ * while the manual setup of VIIF, L1ISP registers is in progress.
+ *
+ * * regbuf control: load/store HW register (settings, status) values to backup SRAM.
+ * * vlatch control: copy timer-counter register value to status register.
+ */
+void hwd_viif_isp_guard_start(struct viif_device *viif_dev)
+{
+	hwd_viif_isp_disable_regbuf_auto_transmission(viif_dev);
+	ndelay(500);
+	hwd_viif_main_mask_vlatch(viif_dev, true);
+}
+
+/**
+ * hwd_viif_isp_guard_end() - restart register auto update
+ *
+ * see also hwd_viif_isp_guard_start().
+ */
+void hwd_viif_isp_guard_end(struct viif_device *viif_dev)
+{
+	hwd_viif_main_mask_vlatch(viif_dev, false);
+	hwd_viif_isp_set_regbuf_auto_transmission(viif_dev);
+}
+
+/*=============================================*/
+/* supported Visual formats */
+/*=============================================*/
+static const struct viif_mbus_format mbus_formats[] = {
+	{ .code = MEDIA_BUS_FMT_RGB888_1X24,
+	  .bpp = 24,
+	  .rgb_out = true,
+	  .mipi_dt = MIPI_CSI2_DT_RGB888 },
+	{ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+	  .bpp = 16,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_YUV422_8B },
+	{ .code = MEDIA_BUS_FMT_UYVY10_1X20,
+	  .bpp = 20,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_YUV422_10B },
+	{ .code = MEDIA_BUS_FMT_RGB565_1X16,
+	  .bpp = 16,
+	  .rgb_out = true,
+	  .mipi_dt = MIPI_CSI2_DT_RGB565 },
+	{ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+	  .bpp = 8,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+	  .bpp = 8,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+	  .bpp = 8,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+	  .bpp = 8,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+	  .bpp = 10,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+	  .bpp = 10,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+	  .bpp = 10,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+	  .bpp = 10,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+	  .bpp = 12,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+	  .bpp = 12,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+	  .bpp = 12,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+	  .bpp = 12,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
+	  .bpp = 14,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+	{ .code = MEDIA_BUS_FMT_SGRBG14_1X14,
+	  .bpp = 14,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+	{ .code = MEDIA_BUS_FMT_SGBRG14_1X14,
+	  .bpp = 14,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+	{ .code = MEDIA_BUS_FMT_SBGGR14_1X14,
+	  .bpp = 14,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+};
+
+const struct viif_mbus_format *viif_mbus_format_from_code(unsigned int mbus_code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mbus_formats); i++)
+		if (mbus_formats[i].code == mbus_code)
+			return &mbus_formats[i];
+
+	return NULL;
+}
+
+const struct viif_mbus_format *viif_mbus_format_nth(unsigned int n)
+{
+	return (n < ARRAY_SIZE(mbus_formats)) ? &mbus_formats[n] : NULL;
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_common.h b/drivers/media/platform/toshiba/visconti/viif_common.h
new file mode 100644
index 000000000..e9dbac6fa
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_common.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_COMMON_H
+#define VIIF_COMMON_H
+
+#include "viif.h"
+
+/**
+ * struct viif_mbus_format - description of supported input format
+ *
+ * @code: V4L2 media bus format (coming from image sensor)
+ * @bpp: bits per pixel
+ * @mipi_dt: MIPI Datatype corresponding to code
+ * @rgb_out:
+ * * True: L1ISP output is RGB format
+ * * False: L1ISP output is YUV format
+ */
+struct viif_mbus_format {
+	unsigned int code;
+	unsigned int bpp;
+	unsigned int mipi_dt;
+	bool rgb_out;
+};
+
+void hwd_viif_isp_set_regbuf_auto_transmission(struct viif_device *viif_dev);
+void hwd_viif_isp_disable_regbuf_auto_transmission(struct viif_device *viif_dev);
+void hwd_viif_isp_guard_start(struct viif_device *viif_dev);
+void hwd_viif_isp_guard_end(struct viif_device *viif_dev);
+
+const struct viif_mbus_format *viif_mbus_format_from_code(unsigned int mbus_code);
+const struct viif_mbus_format *viif_mbus_format_nth(unsigned int n);
+
+#endif /* VIIF_COMMON_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_csi2rx.c b/drivers/media/platform/toshiba/visconti/viif_csi2rx.c
new file mode 100644
index 000000000..0a92597bc
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_csi2rx.c
@@ -0,0 +1,687 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_csi2rx.h"
+#include "viif_csi2rx_regs.h"
+#include "viif_regs.h"
+
+/**
+ * enum viif_csi2rx_dphy_lane - D-PHY Lane assignment
+ *
+ * specifies which line(L0-L3) is assigned to D0-D3
+ */
+enum viif_csi2rx_dphy_lane {
+	VIIF_CSI2RX_DPHY_L0L1L2L3 = 0U,
+	VIIF_CSI2RX_DPHY_L0L3L1L2 = 1U,
+	VIIF_CSI2RX_DPHY_L0L2L3L1 = 2U,
+	VIIF_CSI2RX_DPHY_L0L1L3L2 = 4U,
+	VIIF_CSI2RX_DPHY_L0L3L2L1 = 5U,
+	VIIF_CSI2RX_DPHY_L0L2L1L3 = 6U
+};
+
+/**
+ * struct viif_csi2rx_line_err_target
+ *
+ * Virtual Channel and Data Type pair for CSI2RX line error monitor
+ *
+ * When 0 is set to dt, line error detection is disabled.
+ *
+ * * VC can be 0 .. 3
+ * * DT can be 0 or 0x10 .. 0x3F
+ */
+#define VIIF_CSI2RX_ERROR_MONITORS_NUM 8
+struct viif_csi2rx_line_err_target {
+	u32 vc[VIIF_CSI2RX_ERROR_MONITORS_NUM];
+	u32 dt[VIIF_CSI2RX_ERROR_MONITORS_NUM];
+};
+
+#define VIIF_CSI2RX_MAX_VC	3U
+#define VIIF_DPHY_MIN_DATA_RATE 80U
+#define VIIF_DPHY_MAX_DATA_RATE 1500U
+#define VIIF_DPHY_CFG_CLK_25M	32U
+
+#define VIIF_CSI2RX_DEF_WIDTH  1920
+#define VIIF_CSI2RX_DEF_HEIGHT 1080
+#define VIIF_CSI2RX_DEF_FMT    MEDIA_BUS_FMT_SRGGB10_1X10
+#define VIIF_ISP_MIN_WIDTH     640
+#define VIIF_ISP_MAX_WIDTH     3840
+#define VIIF_ISP_MIN_HEIGHT    480
+#define VIIF_ISP_MAX_HEIGHT    2160
+
+/*=============================================*/
+/* Register Access */
+/*=============================================*/
+static inline void viif_csi2rx_write(struct viif_device *viif_dev, u32 regid, u32 val)
+{
+	writel(val, viif_dev->csi2host_reg + regid);
+}
+
+static inline u32 viif_csi2rx_read(struct viif_device *viif_dev, u32 regid)
+{
+	return readl(viif_dev->csi2host_reg + regid);
+}
+
+/*=============================================*/
+/* DPHY control commands via test register */
+/*=============================================*/
+static inline void tick_testclk(struct viif_device *viif_dev)
+{
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_1);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_0);
+}
+
+static inline void set_dphy_addr(struct viif_device *viif_dev, u32 test_mode)
+{
+	/* select testcode Ex space with top 4bits of test_mode */
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL1,
+			  BIT_TESTCTRL1_ADDR | DIG_TESTCODE_EXT);
+	tick_testclk(viif_dev);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL1, FIELD_GET(0xF00, test_mode));
+	tick_testclk(viif_dev);
+
+	/* set bottom 8bit of test_mode */
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL1,
+			  BIT_TESTCTRL1_ADDR | FIELD_GET(0xFF, test_mode));
+	tick_testclk(viif_dev);
+}
+
+static void write_dphy_param(struct viif_device *viif_dev, u32 test_mode, u8 test_in)
+{
+	set_dphy_addr(viif_dev, test_mode);
+
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL1, (u32)test_in);
+	tick_testclk(viif_dev);
+}
+
+static u8 read_dphy_param(u32 test_mode, struct viif_device *viif_dev)
+{
+	u32 read_data;
+
+	set_dphy_addr(viif_dev, test_mode);
+
+	read_data = viif_csi2rx_read(viif_dev, REG_CSI2RX_PHY_TESTCTRL1);
+	return (u8)(FIELD_GET(MASK_TESTCTRL1_DIN, read_data));
+}
+
+/*=============================================*/
+/* DPHY configuration */
+/*=============================================*/
+/**
+ * struct viif_dphy_hs_info - dphy hs information
+ *
+ * @rate: Data rate [Mbps]
+ * @hsfreqrange: IP operating frequency(hsfreqrange)
+ * @osc_freq_target: DDL target oscillation frequency(osc_freq_target)
+ */
+struct viif_dphy_hs_info {
+	u32 rate;
+	u32 hsfreqrange;
+	u32 osc_freq_target;
+};
+
+static const struct viif_dphy_hs_info dphy_hs_info[] = {
+	{ 80, 0x0, 0x1cc },   { 85, 0x10, 0x1cc },   { 95, 0x20, 0x1cc },   { 105, 0x30, 0x1cc },
+	{ 115, 0x1, 0x1cc },  { 125, 0x11, 0x1cc },  { 135, 0x21, 0x1cc },  { 145, 0x31, 0x1cc },
+	{ 155, 0x2, 0x1cc },  { 165, 0x12, 0x1cc },  { 175, 0x22, 0x1cc },  { 185, 0x32, 0x1cc },
+	{ 198, 0x3, 0x1cc },  { 213, 0x13, 0x1cc },  { 228, 0x23, 0x1cc },  { 243, 0x33, 0x1cc },
+	{ 263, 0x4, 0x1cc },  { 288, 0x14, 0x1cc },  { 313, 0x25, 0x1cc },  { 338, 0x35, 0x1cc },
+	{ 375, 0x5, 0x1cc },  { 425, 0x16, 0x1cc },  { 475, 0x26, 0x1cc },  { 525, 0x37, 0x1cc },
+	{ 575, 0x7, 0x1cc },  { 625, 0x18, 0x1cc },  { 675, 0x28, 0x1cc },  { 725, 0x39, 0x1cc },
+	{ 775, 0x9, 0x1cc },  { 825, 0x19, 0x1cc },  { 875, 0x29, 0x1cc },  { 925, 0x3a, 0x1cc },
+	{ 975, 0xa, 0x1cc },  { 1025, 0x1a, 0x1cc }, { 1075, 0x2a, 0x1cc }, { 1125, 0x3b, 0x1cc },
+	{ 1175, 0xb, 0x1cc }, { 1225, 0x1b, 0x1cc }, { 1275, 0x2b, 0x1cc }, { 1325, 0x3c, 0x1cc },
+	{ 1375, 0xc, 0x1cc }, { 1425, 0x1c, 0x1cc }, { 1475, 0x2c, 0x1cc }
+};
+
+/**
+ * get_dphy_hs_transfer_info() - Get DPHY HS info from table
+ *
+ * @dphy_rate: DPHY clock in MHz
+ * @hsfreqrange: HS Frequency Range
+ * @osc_freq_target: OSC Frequency Target
+ */
+static void get_dphy_hs_transfer_info(u32 dphy_rate, u32 *hsfreqrange, u32 *osc_freq_target)
+{
+	unsigned int i;
+
+	for (i = 1; i < ARRAY_SIZE(dphy_hs_info); i++) {
+		if (dphy_rate < dphy_hs_info[i].rate) {
+			*hsfreqrange = dphy_hs_info[i - 1].hsfreqrange;
+			*osc_freq_target = dphy_hs_info[i - 1].osc_freq_target;
+			return;
+		}
+	}
+
+	/* not found; return the largest entry */
+	*hsfreqrange = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].hsfreqrange;
+	*osc_freq_target = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].osc_freq_target;
+}
+
+/**
+ * viif_csi2rx_set_dphy_rate() - Set D-PHY rate
+ *
+ * @dphy_rate: D-PHY rate of 1 Lane [Unit: Mbps]. Range: [80..1500]
+ */
+static void viif_csi2rx_set_dphy_rate(struct viif_device *viif_dev, u32 dphy_rate)
+{
+	u32 hsfreqrange, osc_freq_target;
+
+	get_dphy_hs_transfer_info(dphy_rate, &hsfreqrange, &osc_freq_target);
+
+	write_dphy_param(viif_dev, DIG_SYS_1, (u8)hsfreqrange);
+	write_dphy_param(viif_dev, DIG_SYS_0, SYS_0_HSFREQRANGE_OVR);
+	write_dphy_param(viif_dev, DIG_RX_STARTUP_OVR_5, STARTUP_OVR_5_BYPASS);
+	write_dphy_param(viif_dev, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL);
+	write_dphy_param(viif_dev, DIG_CB_2, CB_2_LPRX_BIAS | CB_2_RESERVED);
+	write_dphy_param(viif_dev, DIG_SYS_7, SYS_7_DESKEW_POL | SYS_7_RESERVED);
+	write_dphy_param(viif_dev, DIG_CLKLANE_LANE_6, CLKLANE_RXHS_PULL_LONG);
+	write_dphy_param(viif_dev, DIG_RX_STARTUP_OVR_2, FIELD_GET(0xFF, osc_freq_target));
+	write_dphy_param(viif_dev, DIG_RX_STARTUP_OVR_3, FIELD_GET(0xF00, osc_freq_target));
+	write_dphy_param(viif_dev, DIG_RX_STARTUP_OVR_4,
+			 STARTUP_OVR_4_CNTVAL | STARTUP_OVR_4_DDL_EN);
+
+	viif_capture_write(viif_dev, REG_DPHY_FREQRANGE, VIIF_DPHY_CFG_CLK_25M);
+}
+
+/**
+ * check_dphy_calibration_status() - Check D-PHY calibration status
+ *
+ * @test_mode: test code related to calibration information
+ * @mask_err: mask for error bit (0 for absence)
+ * @mask_done: mask for done bit
+ * Return: -EAGAIN: calibration is not done
+ * Return: -EIO: calibration was failed
+ * Return: 0: calibration was succeeded
+ */
+static int check_dphy_calibration_status(struct viif_device *viif_dev, u32 test_mode, u32 mask_err,
+					 u32 mask_done)
+{
+	u32 read_data = (u32)read_dphy_param(test_mode, viif_dev);
+
+	if (!(read_data & mask_done))
+		return -EAGAIN;
+
+	/* done with error */
+	if (read_data & mask_err)
+		return -EIO;
+
+	return 0;
+}
+
+/*=============================================*/
+/* Low Layer Implementation */
+/*=============================================*/
+/**
+ * viif_csi2rx_initialize() - Initialize CSI-2 RX driver
+ *
+ * @num_lane: Range: [1..4]
+ * @lane_assign: lane connection. For more refer @ref viif_dphy_lane_assignment
+ * @dphy_rate: D-PHY rate of 1 Lane [Unit: Mbps]. Range: [80..1500]
+ * @rext_calibration: set True to enable rext calibration, False to disable.
+ * @err_target: Pointer to configuration for Line error detection.
+ * Return: 0 Operation completes successfully
+ * Return: -EINVAL Parameter error
+ */
+static int viif_csi2rx_initialize(struct viif_device *viif_dev, u32 num_lane,
+				  enum viif_csi2rx_dphy_lane lane_assign, u32 dphy_rate,
+				  bool rext_calibration,
+				  const struct viif_csi2rx_line_err_target *err_target)
+{
+	u32 i, val;
+
+	if (num_lane == 0U || num_lane > 4U || lane_assign > VIIF_CSI2RX_DPHY_L0L2L1L3)
+		return -EINVAL;
+
+	if (dphy_rate < VIIF_DPHY_MIN_DATA_RATE || dphy_rate > VIIF_DPHY_MAX_DATA_RATE ||
+	    !err_target) {
+		return -EINVAL;
+	}
+
+	for (i = 0; i < VIIF_CSI2RX_ERROR_MONITORS_NUM; i++) {
+		if (err_target->vc[i] > VIIF_CSI2RX_MAX_VC ||
+		    err_target->dt[i] > MIPI_CSI2_DT_USER_DEFINED(7) ||
+		    (err_target->dt[i] < MIPI_CSI2_DT_NULL && err_target->dt[i])) {
+			return -EINVAL;
+		}
+	}
+
+	/* 1st phase of initialization */
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_RESETN, 1);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_RSTZ, 0);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL0, 1);
+	ndelay(15U);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL0, 0);
+
+	/* Configure D-PHY frequency range */
+	viif_csi2rx_set_dphy_rate(viif_dev, dphy_rate);
+
+	/* 2nd phase of initialization */
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_NLANES, (num_lane - 1U));
+	ndelay(5U);
+
+	/* configuration not to use rext */
+	if (!rext_calibration) {
+		write_dphy_param(viif_dev, DIG_SYS_3, SYS_3_NO_REXT);
+		ndelay(5U);
+	}
+
+	/* Release D-PHY from Reset */
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_SHUTDOWNZ, 1);
+	ndelay(5U);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_RSTZ, 1);
+
+	/* configuration of line error target */
+	val = (err_target->vc[3] << 30U) | (err_target->dt[3] << 24U) | (err_target->vc[2] << 22U) |
+	      (err_target->dt[2] << 16U) | (err_target->vc[1] << 14U) | (err_target->dt[1] << 8U) |
+	      (err_target->vc[0] << 6U) | (err_target->dt[0]);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_DATA_IDS_1, val);
+	val = (err_target->vc[7] << 30U) | (err_target->dt[7] << 24U) | (err_target->vc[6] << 22U) |
+	      (err_target->dt[6] << 16U) | (err_target->vc[5] << 14U) | (err_target->dt[5] << 8U) |
+	      (err_target->vc[4] << 6U) | (err_target->dt[4]);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_DATA_IDS_2, val);
+
+	/* configuration of mask */
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_INT_MSK_PHY_FATAL, MASK_PHY_FATAL_ALL);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_INT_MSK_PKT_FATAL, MASK_PKT_FATAL_ALL);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_INT_MSK_FRAME_FATAL, MASK_FRAME_FATAL_ALL);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_INT_MSK_PHY, MASK_PHY_ERROR_ALL);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_INT_MSK_PKT, MASK_PKT_ERROR_ALL);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_INT_MSK_LINE, MASK_LINE_ERROR_ALL);
+
+	/* configuration of lane assignment */
+	viif_capture_write(viif_dev, REG_DPHY_LANE, lane_assign);
+
+	return 0;
+}
+
+/**
+ * viif_csi2rx_uninitialize() - Uninitialize CSI-2 RX driver
+ */
+static int viif_csi2rx_uninitialize(struct viif_device *viif_dev)
+{
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_RSTZ, 0);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_PHY_TESTCTRL0, 1);
+	viif_csi2rx_write(viif_dev, REG_CSI2RX_RESETN, 0);
+
+	return 0;
+}
+
+/*=============================================*/
+/* handling vendor specific control requests */
+/*=============================================*/
+/**
+ * visconti_viif_csi2rx_get_calibration_status() - Get CSI-2 RX calibration status
+ *
+ * @status: Pointer to D-PHY calibration status information
+ * Return: 0 Operation completes successfully
+ */
+int visconti_viif_csi2rx_get_calibration_status(struct viif_device *viif_dev,
+						struct viif_csi2rx_dphy_calibration_status *status)
+{
+	/* termination calibration with REXT */
+	status->term_cal_with_rext = check_dphy_calibration_status(
+		viif_dev, DIG_TERM_CAL_1, MASK_TERM_CAL_ERR, MASK_TERM_CAL_DONE);
+
+	/* offset calibration */
+	status->clock_lane_offset_cal = check_dphy_calibration_status(
+		viif_dev, DIG_CLKLANE_OFFSET_CAL_0, MASK_CLK_CAL_ERR, MASK_CLK_CAL_DONE);
+	status->data_lane0_offset_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE0_OFFSET_CAL_0, MASK_CAL_ERR, MASK_CAL_DONE);
+	status->data_lane1_offset_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE1_OFFSET_CAL_0, MASK_CAL_ERR, MASK_CAL_DONE);
+	status->data_lane2_offset_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE2_OFFSET_CAL_0, MASK_CAL_ERR, MASK_CAL_DONE);
+	status->data_lane3_offset_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE3_OFFSET_CAL_0, MASK_CAL_ERR, MASK_CAL_DONE);
+
+	/* Digital Delay Line calibration */
+	status->data_lane0_ddl_tuning_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE0_DDL_0, MASK_DDL_ERR, MASK_DDL_DONE);
+	status->data_lane1_ddl_tuning_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE1_DDL_0, MASK_DDL_ERR, MASK_DDL_DONE);
+	status->data_lane2_ddl_tuning_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE2_DDL_0, MASK_DDL_ERR, MASK_DDL_DONE);
+	status->data_lane3_ddl_tuning_cal = check_dphy_calibration_status(
+		viif_dev, DIG_LANE3_DDL_0, MASK_DDL_ERR, MASK_DDL_DONE);
+
+	return 0;
+}
+
+/**
+ * visconti_viif_csi2rx_get_err_status() - Get CSI-2 RX error status
+ *
+ * @csi_err: error information
+ * Return: 0 Operation completes successfully
+ */
+int visconti_viif_csi2rx_get_err_status(struct viif_device *viif_dev,
+					struct viif_csi2rx_err_status *csi_err)
+{
+	csi_err->err_phy_fatal = viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_PHY_FATAL);
+	csi_err->err_pkt_fatal = viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_PKT_FATAL);
+	csi_err->err_frame_fatal = viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_FRAME_FATAL);
+	csi_err->err_phy = viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_PHY);
+	csi_err->err_pkt = viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_PKT);
+	csi_err->err_line = viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_LINE);
+
+	return 0;
+}
+
+/**
+ * visconti_viif_csi2rx_err_irq_handler() - CSI-2 RX error interruption handler
+ *
+ * Return: event information of CSI-2 RX error interruption
+ */
+u32 visconti_viif_csi2rx_err_irq_handler(struct viif_device *viif_dev)
+{
+	return viif_csi2rx_read(viif_dev, REG_CSI2RX_INT_ST_MAIN);
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+static inline struct csi2rx_subdev *to_csi2rx_subdev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct csi2rx_subdev, sd);
+}
+
+static int64_t get_pixelclock(struct v4l2_subdev *sd)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	if (!ctrl)
+		return -EINVAL;
+
+	return v4l2_ctrl_g_ctrl_int64(ctrl);
+}
+
+static unsigned int viif_get_mbus_bpp(unsigned int mbus_code)
+{
+	const struct viif_mbus_format *fmt;
+
+	fmt = viif_mbus_format_from_code(mbus_code);
+
+	return fmt ? fmt->bpp : 24; /* default bpp */
+}
+
+/* ----- handling CSI2RX hardware ----- */
+static const struct viif_csi2rx_line_err_target err_target_vc0_alldt = {
+	/* select VC=0 */
+	/* select all supported DataTypes */
+	.dt = {
+		MIPI_CSI2_DT_RGB565,
+		MIPI_CSI2_DT_YUV422_8B,
+		MIPI_CSI2_DT_YUV422_10B,
+		MIPI_CSI2_DT_RGB888,
+		MIPI_CSI2_DT_RAW8,
+		MIPI_CSI2_DT_RAW10,
+		MIPI_CSI2_DT_RAW12,
+		MIPI_CSI2_DT_RAW14,
+	}
+};
+
+static int viif_csi2rx_start(struct viif_device *viif_dev)
+{
+	struct viif_subdev *viif_sd = viif_dev->sd;
+	struct v4l2_mbus_config cfg = { 0 };
+	struct v4l2_subdev_format fmt = {
+		.pad = 0,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	int num_lane, dphy_rate;
+	s64 pixelclock;
+	int ret;
+
+	ret = v4l2_subdev_call(viif_sd->v4l2_sd, pad, get_mbus_config, 0, &cfg);
+	if (ret) {
+		dev_dbg(viif_dev->dev, "subdev: g_mbus_config error. %d\n", ret);
+		num_lane = viif_sd->num_lane;
+	} else {
+		if (cfg.type != V4L2_MBUS_CSI2_DPHY)
+			return -EINVAL;
+		num_lane = cfg.bus.mipi_csi2.num_data_lanes;
+	}
+
+	ret = v4l2_subdev_call(viif_sd->v4l2_sd, pad, get_fmt, 0, &fmt);
+	if (ret)
+		return -EINVAL;
+
+	pixelclock = get_pixelclock(viif_sd->v4l2_sd);
+	if (pixelclock < 0)
+		return -EINVAL;
+
+	dphy_rate = pixelclock * viif_get_mbus_bpp(fmt.format.code) / num_lane / 1000000;
+
+	ret = viif_csi2rx_initialize(viif_dev, num_lane, VIIF_CSI2RX_DPHY_L0L1L2L3, dphy_rate, true,
+				     &err_target_vc0_alldt);
+	return ret;
+}
+
+static int viif_csi2rx_stop(struct viif_device *viif_dev)
+{
+	viif_csi2rx_uninitialize(viif_dev);
+
+	return 0;
+}
+
+/* ----- V4L2 subdevice APIs (csi2rx subdevice) ----- */
+static struct v4l2_mbus_framefmt *
+visconti_viif_csi2rx_get_pad_fmt(struct csi2rx_subdev *csi2rx, struct v4l2_subdev_state *sd_state,
+				 unsigned int pad, u32 which)
+{
+	struct v4l2_subdev_state state = {
+		.pads = csi2rx->pad_cfg,
+	};
+
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(&csi2rx->sd, sd_state, pad);
+	else
+		return v4l2_subdev_get_try_format(&csi2rx->sd, &state, pad);
+}
+
+static int visconti_viif_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
+					       struct v4l2_subdev_state *sd_state,
+					       struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct csi2rx_subdev *csi2rx = to_csi2rx_subdev(sd);
+	const struct viif_mbus_format *fmt;
+
+	if (code->pad == VIIF_CSI2RX_PAD_SRC) {
+		const struct v4l2_mbus_framefmt *sink_fmt;
+
+		/* should be equal to current settings of sink pad */
+		if (code->index)
+			return -EINVAL;
+
+		mutex_lock(&csi2rx->ops_lock);
+
+		sink_fmt = visconti_viif_csi2rx_get_pad_fmt(csi2rx, sd_state, VIIF_CSI2RX_PAD_SINK,
+							    code->which);
+		code->code = sink_fmt->code;
+
+		mutex_unlock(&csi2rx->ops_lock);
+
+		return 0;
+	}
+
+	/* find specified format */
+	fmt = viif_mbus_format_nth(code->index);
+	if (!fmt)
+		return -EINVAL;
+
+	code->code = fmt->code;
+	return 0;
+}
+
+static int visconti_viif_csi2rx_init_config(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, VIIF_CSI2RX_PAD_SINK);
+	src_fmt = v4l2_subdev_get_try_format(sd, sd_state, VIIF_CSI2RX_PAD_SRC);
+
+	sink_fmt->width = VIIF_CSI2RX_DEF_WIDTH;
+	sink_fmt->height = VIIF_CSI2RX_DEF_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = VIIF_CSI2RX_DEF_FMT;
+
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static int visconti_viif_csi2rx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
+					struct v4l2_subdev_format *fmt)
+{
+	struct csi2rx_subdev *csi2rx = to_csi2rx_subdev(sd);
+
+	mutex_lock(&csi2rx->ops_lock);
+	fmt->format = *visconti_viif_csi2rx_get_pad_fmt(csi2rx, sd_state, fmt->pad, fmt->which);
+	mutex_unlock(&csi2rx->ops_lock);
+
+	return 0;
+}
+
+static int visconti_viif_csi2rx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
+					struct v4l2_subdev_format *fmt)
+{
+	struct csi2rx_subdev *csi2rx = to_csi2rx_subdev(sd);
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	if (fmt->pad == VIIF_CSI2RX_PAD_SRC)
+		return visconti_viif_csi2rx_get_fmt(sd, sd_state, fmt);
+
+	mutex_lock(&csi2rx->ops_lock);
+
+	sink_fmt = visconti_viif_csi2rx_get_pad_fmt(csi2rx, sd_state, VIIF_CSI2RX_PAD_SINK,
+						    fmt->which);
+
+	sink_fmt->code = viif_mbus_format_from_code(fmt->format.code) ? fmt->format.code :
+									      VIIF_CSI2RX_DEF_FMT;
+	sink_fmt->width = clamp_t(u32, fmt->format.width, VIIF_ISP_MIN_WIDTH, VIIF_ISP_MAX_WIDTH);
+	sink_fmt->height =
+		clamp_t(u32, fmt->format.height, VIIF_ISP_MIN_HEIGHT, VIIF_ISP_MAX_HEIGHT);
+
+	fmt->format = *sink_fmt;
+
+	/* sourcep pad should have the same format */
+	src_fmt =
+		visconti_viif_csi2rx_get_pad_fmt(csi2rx, sd_state, VIIF_CSI2RX_PAD_SRC, fmt->which);
+	*src_fmt = *sink_fmt;
+
+	mutex_unlock(&csi2rx->ops_lock);
+
+	return 0;
+}
+
+static int visconti_viif_csi2rx_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct csi2rx_subdev *csi2rx = to_csi2rx_subdev(sd);
+	struct viif_device *viif_dev = csi2rx->viif_dev;
+	int ret;
+
+	/* disabling: turn off sensor -> turn off CSI2RX */
+	if (!enable) {
+		v4l2_subdev_call(viif_dev->sd->v4l2_sd, video, s_stream, false);
+		return viif_csi2rx_stop(viif_dev);
+	}
+
+	/* enabling: turn on CSI2RX -> turn on sensor -> (error handling) */
+	ret = viif_csi2rx_start(viif_dev);
+	if (ret)
+		return ret;
+
+	ret = v4l2_subdev_call(viif_dev->sd->v4l2_sd, video, s_stream, true);
+	if (ret) {
+		viif_csi2rx_stop(viif_dev);
+		return ret;
+	}
+	return 0;
+}
+
+/* ----- register/remove csi2rx subdevice node ----- */
+static const struct media_entity_operations visconti_viif_csi2rx_media_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_video_ops visconti_viif_csi2rx_video_ops = {
+	.s_stream = visconti_viif_csi2rx_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops visconti_viif_csi2rx_pad_ops = {
+	.enum_mbus_code = visconti_viif_csi2rx_enum_mbus_code,
+	.init_cfg = visconti_viif_csi2rx_init_config,
+	.get_fmt = visconti_viif_csi2rx_get_fmt,
+	.set_fmt = visconti_viif_csi2rx_set_fmt,
+};
+
+static const struct v4l2_subdev_ops visconti_viif_csi2rx_ops = {
+	.video = &visconti_viif_csi2rx_video_ops,
+	.pad = &visconti_viif_csi2rx_pad_ops,
+};
+
+int visconti_viif_csi2rx_register(struct viif_device *viif_dev)
+{
+	struct v4l2_subdev_state state = {
+		.pads = viif_dev->csi2rx_subdev.pad_cfg,
+	};
+	struct media_pad *pads = viif_dev->csi2rx_subdev.pads;
+	struct v4l2_subdev *sd = &viif_dev->csi2rx_subdev.sd;
+	int ret;
+
+	viif_dev->csi2rx_subdev.viif_dev = viif_dev;
+
+	v4l2_subdev_init(sd, &visconti_viif_csi2rx_ops);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->entity.ops = &visconti_viif_csi2rx_media_ops;
+	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	sd->owner = THIS_MODULE;
+	strscpy(sd->name, "visconti-viif:csi2rx", sizeof(sd->name));
+
+	pads[VIIF_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[VIIF_CSI2RX_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+
+	mutex_init(&viif_dev->csi2rx_subdev.ops_lock);
+
+	ret = media_entity_pads_init(&sd->entity, VIIF_CSI2RX_PAD_NUM, pads);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed on media_entity_pads_init\n");
+		return ret;
+	}
+
+	ret = v4l2_device_register_subdev(&viif_dev->v4l2_dev, sd);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to register CSI2RX subdev\n");
+		goto err_cleanup_media_entity;
+	}
+
+	visconti_viif_csi2rx_init_config(sd, &state);
+
+	return 0;
+
+err_cleanup_media_entity:
+	media_entity_cleanup(&sd->entity);
+	mutex_destroy(&viif_dev->csi2rx_subdev.ops_lock);
+	viif_dev->csi2rx_subdev.viif_dev = NULL;
+	return ret;
+}
+
+void visconti_viif_csi2rx_unregister(struct viif_device *viif_dev)
+{
+	v4l2_device_unregister_subdev(&viif_dev->csi2rx_subdev.sd);
+	media_entity_cleanup(&viif_dev->csi2rx_subdev.sd.entity);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_csi2rx.h b/drivers/media/platform/toshiba/visconti/viif_csi2rx.h
new file mode 100644
index 000000000..07dd70d72
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_csi2rx.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_CSI2RX_H
+#define VIIF_CSI2RX_H
+
+struct viif_device;
+struct viif_csi2rx_dphy_calibration_status;
+
+int visconti_viif_csi2rx_get_calibration_status(
+	struct viif_device *viif_dev,
+	struct viif_csi2rx_dphy_calibration_status *calibration_status);
+int visconti_viif_csi2rx_get_err_status(struct viif_device *viif_dev,
+					struct viif_csi2rx_err_status *csi_err);
+u32 visconti_viif_csi2rx_err_irq_handler(struct viif_device *viif_dev);
+
+int visconti_viif_csi2rx_register(struct viif_device *viif_dev);
+void visconti_viif_csi2rx_unregister(struct viif_device *viif_dev);
+
+#endif /* VIIF_CSI2RX_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_csi2rx_regs.h b/drivers/media/platform/toshiba/visconti/viif_csi2rx_regs.h
new file mode 100644
index 000000000..d3865d4f7
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_csi2rx_regs.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture register definitions
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_CSI2RX_REGS_H
+#define VIIF_CSI2RX_REGS_H
+
+/*=============================================*/
+/* CSI2HOST registers */
+/*=============================================*/
+#define REG_CSI2RX_NLANES	 0x4
+#define REG_CSI2RX_PHY_SHUTDOWNZ 0x40
+#define REG_CSI2RX_PHY_RSTZ	 0x44
+
+/* access to dphy external registers */
+#define REG_CSI2RX_PHY_TESTCTRL0 0x50
+#define BIT_TESTCTRL0_CLK_0	 0
+#define BIT_TESTCTRL0_CLK_1	 BIT(1)
+
+#define REG_CSI2RX_PHY_TESTCTRL1 0x54
+#define BIT_TESTCTRL1_ADDR	 BIT(16)
+#define MASK_TESTCTRL1_DIN	 0xFF
+#define MASK_TESTCTRL1_DOUT	 0xFF00
+
+#define REG_CSI2RX_INT_ST_PHY_FATAL  0xE0
+#define REG_CSI2RX_INT_MSK_PHY_FATAL 0xE4
+#define MASK_PHY_FATAL_ALL	     0x0000000F
+
+#define REG_CSI2RX_INT_ST_PKT_FATAL  0xF0
+#define REG_CSI2RX_INT_MSK_PKT_FATAL 0xF4
+#define MASK_PKT_FATAL_ALL	     0x0001000F
+
+#define REG_CSI2RX_INT_ST_FRAME_FATAL  0x100
+#define REG_CSI2RX_INT_MSK_FRAME_FATAL 0x104
+#define MASK_FRAME_FATAL_ALL	       0x000F0F0F
+
+#define REG_CSI2RX_INT_ST_PHY  0x110
+#define REG_CSI2RX_INT_MSK_PHY 0x114
+#define MASK_PHY_ERROR_ALL     0x000F000F
+
+#define REG_CSI2RX_INT_ST_PKT  0x120
+#define REG_CSI2RX_INT_MSK_PKT 0x124
+#define MASK_PKT_ERROR_ALL     0x000F000F
+
+#define REG_CSI2RX_INT_ST_LINE	0x130
+#define REG_CSI2RX_INT_MSK_LINE 0x134
+#define MASK_LINE_ERROR_ALL	0x00FF00FF
+
+/*=============================================*/
+/* DPHY register space */
+/*=============================================*/
+enum dphy_testcode {
+	DIG_TESTCODE_EXT = 0,
+	DIG_SYS_0 = 0x001,
+	DIG_SYS_1 = 0x002,
+	DIG_SYS_3 = 0x004,
+	DIG_SYS_7 = 0x008,
+	DIG_RX_STARTUP_OVR_2 = 0x0E2,
+	DIG_RX_STARTUP_OVR_3 = 0x0E3,
+	DIG_RX_STARTUP_OVR_4 = 0x0E4,
+	DIG_RX_STARTUP_OVR_5 = 0x0E5,
+	DIG_CB_2 = 0x1AC,
+	DIG_TERM_CAL_0 = 0x220,
+	DIG_TERM_CAL_1 = 0x221,
+	DIG_TERM_CAL_2 = 0x222,
+	DIG_CLKLANE_LANE_6 = 0x307,
+	DIG_CLKLANE_OFFSET_CAL_0 = 0x39D,
+	DIG_LANE0_OFFSET_CAL_0 = 0x59F,
+	DIG_LANE0_DDL_0 = 0x5E0,
+	DIG_LANE1_OFFSET_CAL_0 = 0x79F,
+	DIG_LANE1_DDL_0 = 0x7E0,
+	DIG_LANE2_OFFSET_CAL_0 = 0x99F,
+	DIG_LANE2_DDL_0 = 0x9E0,
+	DIG_LANE3_OFFSET_CAL_0 = 0xB9F,
+	DIG_LANE3_DDL_0 = 0xBE0,
+};
+
+#define SYS_0_HSFREQRANGE_OVR  BIT(5)
+#define SYS_3_NO_REXT	       BIT(4)
+#define SYS_7_RESERVED	       FIELD_PREP(0x1F, 0x0C)
+#define SYS_7_DESKEW_POL       BIT(5)
+#define STARTUP_OVR_4_CNTVAL   FIELD_PREP(0x70, 0x01)
+#define STARTUP_OVR_4_DDL_EN   BIT(0)
+#define STARTUP_OVR_5_BYPASS   BIT(0)
+#define CB_2_LPRX_BIAS	       BIT(6)
+#define CB_2_RESERVED	       FIELD_PREP(0x3F, 0x0B)
+#define CLKLANE_RXHS_PULL_LONG BIT(7)
+
+/* bit mask for calibration result registers */
+#define MASK_TERM_CAL_ERR  0
+#define MASK_TERM_CAL_DONE BIT(7)
+#define MASK_CLK_CAL_ERR   BIT(4)
+#define MASK_CLK_CAL_DONE  BIT(0)
+#define MASK_CAL_ERR	   BIT(2)
+#define MASK_CAL_DONE	   BIT(1)
+#define MASK_DDL_ERR	   BIT(1)
+#define MASK_DDL_DONE	   BIT(2)
+
+#endif /* VIIF_CSI2RX_REGS_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.c b/drivers/media/platform/toshiba/visconti/viif_isp.c
new file mode 100644
index 000000000..94e62e95c
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.c
@@ -0,0 +1,1269 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_regs.h"
+
+/* disable CSI2 capture at viif_mux_start() */
+#define VIIF_CSI2_NOT_CAPTURE -1
+
+/* minimum crop width and height */
+#define VIIF_CROP_MIN_W 128U
+#define VIIF_CROP_MIN_H 128U
+
+/* up to 2 ROIs are available to be passed to POSTs */
+/* set ROI_NONE for a POST currently not running */
+#define VIIF_L2_ROI_MAX_NUM 2U
+#define VIIF_L2_ROI_NONE    3U
+
+/* validation at main_set_unit() and sub_set_unit() */
+/* picture size: [unit: pixel] */
+#define VIIF_MIN_HTOTAL_PIXEL 143U
+#define VIIF_MAX_HTOTAL_PIXEL 65535U
+
+/* pixel clock: [unit: kHz] */
+#define VIIF_MIN_PIXEL_CLOCK 3375U
+#define VIIF_MAX_PIXEL_CLOCK 600000U
+
+/* horizontal back porch size: [unit: system clock ticks] */
+#define VIIF_HBP_SYSCLK 10U
+
+/* num of pictures accepted by the ISP */
+#define VIIF_L1_INPUT_NUM_MIN 1U
+#define VIIF_L1_INPUT_NUM_MAX 3U
+
+/* active picture size: [unit: pixel] */
+#define VIIF_MIN_HACTIVE_PIXEL_W_L1ISP	640U
+#define VIIF_MAX_HACTIVE_PIXEL_W_L1ISP	3840U
+#define VIIF_MIN_HACTIVE_PIXEL_WO_L1ISP 128U
+#define VIIF_MAX_HACTIVE_PIXEL_WO_L1ISP 4096U
+
+/* picture vertical size: [unit: line] */
+#define VIIF_MIN_VTOTAL_LINE	       144U
+#define VIIF_MAX_VTOTAL_LINE	       16383U
+#define VIIF_MIN_VBP_LINE	       5U
+#define VIIF_MAX_VBP_LINE	       4095U
+#define VIIF_MIN_VACTIVE_LINE_WO_L1ISP 128U
+#define VIIF_MAX_VACTIVE_LINE_WO_L1ISP 2160U
+#define VIIF_MIN_VACTIVE_LINE_W_L1ISP  480U
+#define VIIF_MAX_VACTIVE_LINE_W_L1ISP  2160U
+
+/* internal operation latencies: [unit: system clock ticks]*/
+#define VIIF_TABLE_LOAD_TIME	24000UL
+#define VIIF_REGBUF_ACCESS_TIME 15360UL
+
+/* offset of Vsync delay: [unit: line] */
+#define VIIF_L1_DELAY_W_HDRC  31U
+#define VIIF_L1_DELAY_WO_HDRC 11U
+
+/* timeout definitions for viif_stop_mux() */
+/*
+ * wait time for force abort to complete (max 1line time = 1228.8 us)
+ * when width = 4096, RAW24, 80Mbps
+ */
+#define VIIF_WAIT_ABORT_COMPLETE_TIME 1229U
+
+/*
+ * complete time of register buffer transfer.
+ * actual time is about 30us in case of L1ISP
+ */
+#define VIIF_WAIT_ISP_REGBF_TRNS_COMPLETE_TIME 39U
+
+/* default parameters for V4L2 subdevice node */
+#define VISCONTI_VIIF_ISP_DEFAULT_WIDTH	  1920
+#define VISCONTI_VIIF_ISP_DEFAULT_HEIGHT  1080
+#define VISCONTI_VIIF_MAX_COMPOSED_WIDTH  8190
+#define VISCONTI_VIIF_MAX_COMPOSED_HEIGHT 4094
+
+/**
+ * struct viif_input_img - input image information
+ * @pixel_clock: pixel clock [unit: kHz]. Range: [3375..600000]
+ * @htotal_size: horizontal total size [unit: pixel]. Range: [143..65535]
+ * @hactive_size: horizontal active size [unit: pixel]
+ * * Range (w/o L1ISP): [128..4096] (multiple of 2)
+ * * Range (with L1ISP): [640..3840] (multiple of 8)
+ * * Range (SUB path): 0
+ * @vtotal_size: vertical total size [unit: line].
+ * * Range: [144..16383]
+ * @vbp_size: vertical back porch size.
+ * * Range: [5..4095]
+ * @vactive_size: vertical active size [unit: line].
+ * * Range (w/o L1ISP) [128..2160] (multiple of 2)
+ * * Range (with L1ISP) [480..2160] (multiple of 2)
+ * @input_num: the number of input images. Range: [1..3]
+ * * Range (w/o L1ISP): 1
+ * * Range (with L1ISP): [1..3]
+ * * Range (SUB path): 1
+ * @hobc_width: the number of horizontal optical black pixels.
+ * * Range (w/o L1ISP): 0
+ * * Range (with L1ISP):  [0,16,32,64 or 128]
+ *   * should be 0 when hobc_margin = 0
+ * * Range (SUB path): 0
+ * @hobc_margin: the number of horizontal optical black margin.
+ * * Range (w/o L1ISP): 0
+ * * Range (with L1ISP): [0..30] (even number)
+ +   * should be 0 when hobc_width = 0
+ * * Range (SUB path): 0
+ *
+ * Constraints between parameters:
+ *
+ * * (htotal_size > (hactive_size + hobc_width + hobc_margin))
+ * * (vtotal_size > (vbp_size + vactive_size * input_num))
+ * * w/o L1ISP:
+ *   * vbp_size >= (39360[cycle] / 500000[kHz]) * (pixel_clock / htotal_size) + 16 + ISST time
+ * * with L1ISP:
+ *   * vbp_size >= (54720[cycle] / 500000[kHz]) * (pixel_clock / htotal_size) + 38 + ISST time
+ *
+ * Note: L1ISP is used when RAW data is input to MAIN unit
+ */
+struct viif_input_img {
+	u32 pixel_clock;
+	u32 htotal_size;
+	u32 hactive_size;
+	u32 vtotal_size;
+	u32 vbp_size;
+	u32 vactive_size;
+	u32 input_num;
+	u32 hobc_width;
+	u32 hobc_margin;
+};
+
+/*=============================================*/
+/* Low Layer Implementation */
+/*=============================================*/
+/* Convert the unit of time-period (from sysclk, to num lines in the image) */
+static u32 sysclk_to_numlines(u32 time_in_sysclk, const struct viif_input_img *img)
+{
+	u64 v1 = (u64)time_in_sysclk * img->pixel_clock;
+	u64 v2 = (u64)img->htotal_size * VIIF_SYS_CLK;
+
+	return div64_u64(v1, v2);
+}
+
+static u32 lineperiod_in_sysclk(u32 hsize, u32 pixel_clock)
+{
+	return div64_u64((u64)hsize * VIIF_SYS_CLK, pixel_clock);
+}
+
+/**
+ * viif_l2_set_roi_num_2() - Set ROI path condition when ROI num is 2
+ */
+static void viif_l2_set_roi_num_2(struct viif_device *viif_dev)
+{
+	struct viif_l2_roi_path_info *info = &viif_dev->l2_roi_path_info;
+	u32 i;
+
+	for (i = 0; i < VIIF_L2_ROI_MAX_NUM; i++) {
+		/* ROI-n is the same as CROP area of POST-n */
+		if (info->post_enable_flag[i]) {
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_H(i),
+					   info->post_crop_x[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_V(i),
+					   info->post_crop_y[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_HSIZE(i),
+					   info->post_crop_w[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_VSIZE(i),
+					   info->post_crop_h[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_TO_POST(i), i);
+		} else {
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_H(i), 0);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_V(i), 0);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_HSIZE(i), VIIF_CROP_MIN_W);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_VSIZE(i), VIIF_CROP_MIN_H);
+			viif_capture_write(viif_dev, REG_L2_ROI_TO_POST(i), VIIF_L2_ROI_NONE);
+		}
+	}
+}
+
+/**
+ * viif_l2_set_roi_num_1() - Set ROI path condition when ROI num is 1
+ */
+static void viif_l2_set_roi_num_1(struct viif_device *viif_dev)
+{
+	struct viif_l2_roi_path_info *info = &viif_dev->l2_roi_path_info;
+	u32 val, x_min, x_max, y_min, y_max;
+	u32 i, x, y, w, h;
+
+	/* ROI0 is input to POST0 and POST1 */
+	if (info->post_enable_flag[0]) {
+		/* POST0 is enabled */
+		x_min = info->post_crop_x[0];
+		x_max = info->post_crop_x[0] + info->post_crop_w[0];
+		y_min = info->post_crop_y[0];
+		y_max = info->post_crop_y[0] + info->post_crop_h[0];
+		if (info->post_enable_flag[1]) {
+			/* POST1 is enabled */
+			x_min = min(x_min, info->post_crop_x[1]);
+			val = info->post_crop_x[1] + info->post_crop_w[1];
+			x_max = max(x_max, val);
+			y_min = min(y_min, info->post_crop_y[1]);
+			val = info->post_crop_y[1] + info->post_crop_h[1];
+			y_max = max(y_max, val);
+		}
+		x = x_min;
+		y = y_min;
+		w = x_max - x_min;
+		h = y_max - y_min;
+	} else if (info->post_enable_flag[1]) {
+		/* POST0 is disabled and POST1 is enabled */
+		x = info->post_crop_x[1];
+		w = info->post_crop_w[1];
+		y = info->post_crop_y[1];
+		h = info->post_crop_h[1];
+	} else {
+		/* All POSTs are disabled */
+		x = 0;
+		y = 0;
+		w = VIIF_CROP_MIN_W;
+		h = VIIF_CROP_MIN_H;
+	}
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_H(0), x);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_V(0), y);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_HSIZE(0), w);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_VSIZE(0), h);
+
+	for (i = 0; i < VIIF_MAX_POST_NUM; i++)
+		viif_capture_write(viif_dev, REG_L2_ROI_TO_POST(i),
+				   info->post_enable_flag[i] ? 0 : VIIF_L2_ROI_NONE);
+}
+
+/**
+ * visconti_viif_l2_set_roi_path() - Set ROI path condition
+ */
+void visconti_viif_l2_set_roi_path(struct viif_device *viif_dev)
+{
+	if (viif_dev->l2_roi_path_info.roi_num == 1U)
+		viif_l2_set_roi_num_1(viif_dev);
+	else
+		viif_l2_set_roi_num_2(viif_dev);
+}
+
+/**
+ * viif_l2_set_roi() - Set ROI parameters of L2ISP
+ */
+void visconti_viif_l2_set_roi(struct viif_device *viif_dev, const struct viif_l2_roi_config *param)
+{
+	u32 val;
+	int i;
+
+	/* Set the number of ROI and update resource info with roi_num */
+	viif_capture_write(viif_dev, REG_L2_ROI_NUM, param->roi_num);
+	viif_dev->l2_roi_path_info.roi_num = param->roi_num;
+
+	/* Update ROI area and input to each POST */
+	visconti_viif_l2_set_roi_path(viif_dev);
+
+	/* Set the remaining parameters */
+	for (i = 0; i < 2; i++) {
+		viif_capture_write(viif_dev, REG_L2_ROI_X_SCALE(i), param->roi_scale[i]);
+		viif_capture_write(viif_dev, REG_L2_ROI_X_SCALE_INV(i), param->roi_scale_inv[i]);
+		val = (param->corrected_wo_scale_hsize[i] << 13U) | param->corrected_hsize[i];
+		viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_HSIZE(i), val);
+		val = (param->corrected_wo_scale_vsize[i] << 12U) | param->corrected_vsize[i];
+		viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_VSIZE(i), val);
+	}
+}
+
+/**
+ * hwd_viif_main_set_unit() - Set static configuration of MAIN unit(CH0 or CH1)
+ *
+ * @data_type: DT of image; either of
+ *     YUV422_8B, YUV422_10B, RGB565, RGB888, RAW8, RAW10, RAW12, RAW14
+ * @in_img: Pointer to input image information
+ * @rawpack: RAW pack mode. For more refer @ref hwd_viif_raw_pack_mode
+ * @yuv_interp: true to use interpolation for YUV422 to YUV444 conversion.
+ * Return: 0 Operation completes successfully
+ * Return: -EINVAL Parameter error
+ */
+static int viif_main_set_unit(struct viif_device *viif_dev, u32 data_type,
+			      const struct viif_input_img *in_img, u32 rawpack, bool yuv_interp)
+{
+	u32 total_hact_size = 0U, total_vact_size = 0U;
+	u32 sw_delay0, sw_delay1, hw_delay;
+	u32 val, color, sysclk_num;
+	u32 i;
+
+	if (!in_img)
+		return -EINVAL;
+	if (rawpack != VIIF_RAWPACK_DISABLE && rawpack != VIIF_RAWPACK_MSBFIRST &&
+	    rawpack != VIIF_RAWPACK_LSBFIRST) {
+		return -EINVAL;
+	}
+	if (data_type != MIPI_CSI2_DT_RAW8 && data_type != MIPI_CSI2_DT_RAW10 &&
+	    data_type != MIPI_CSI2_DT_RAW12 && rawpack != VIIF_RAWPACK_DISABLE) {
+		return -EINVAL;
+	}
+
+	if (in_img->pixel_clock < VIIF_MIN_PIXEL_CLOCK ||
+	    in_img->pixel_clock > VIIF_MAX_PIXEL_CLOCK ||
+	    in_img->htotal_size < VIIF_MIN_HTOTAL_PIXEL ||
+	    in_img->htotal_size > VIIF_MAX_HTOTAL_PIXEL ||
+	    in_img->vtotal_size < VIIF_MIN_VTOTAL_LINE ||
+	    in_img->vtotal_size > VIIF_MAX_VTOTAL_LINE || in_img->vbp_size < VIIF_MIN_VBP_LINE ||
+	    in_img->vbp_size > VIIF_MAX_VBP_LINE || (in_img->hactive_size % 2U) ||
+	    (in_img->vactive_size % 2U)) {
+		return -EINVAL;
+	}
+
+	if (in_img->input_num < VIIF_L1_INPUT_NUM_MIN ||
+	    in_img->input_num > VIIF_L1_INPUT_NUM_MAX) {
+		return -EINVAL;
+	}
+
+	if (in_img->hobc_width != 0U && in_img->hobc_width != 16U && in_img->hobc_width != 32U &&
+	    in_img->hobc_width != 64U && in_img->hobc_width != 128U) {
+		return -EINVAL;
+	}
+
+	if (in_img->hobc_margin > 30U || (in_img->hobc_margin % 2U))
+		return -EINVAL;
+
+	if (!in_img->hobc_width && in_img->hobc_margin)
+		return -EINVAL;
+
+	if (in_img->hobc_width && !in_img->hobc_margin)
+		return -EINVAL;
+
+	if (data_type == MIPI_CSI2_DT_RAW8 || data_type == MIPI_CSI2_DT_RAW10 ||
+	    data_type == MIPI_CSI2_DT_RAW12 || data_type == MIPI_CSI2_DT_RAW14) {
+		/* parameter check in case of L1ISP(in case of RAW) */
+		if (in_img->hactive_size < VIIF_MIN_HACTIVE_PIXEL_W_L1ISP ||
+		    in_img->hactive_size > VIIF_MAX_HACTIVE_PIXEL_W_L1ISP ||
+		    in_img->vactive_size < VIIF_MIN_VACTIVE_LINE_W_L1ISP ||
+		    in_img->vactive_size > VIIF_MAX_VACTIVE_LINE_W_L1ISP ||
+		    (in_img->hactive_size % 8U)) {
+			return -EINVAL;
+		}
+
+		/* check vbp range in case of L1ISP on */
+		/* the constant value "7" is configuration margin */
+		val = sysclk_to_numlines(VIIF_TABLE_LOAD_TIME + VIIF_REGBUF_ACCESS_TIME * 2U,
+					 in_img) +
+		      VIIF_L1_DELAY_W_HDRC + 7U;
+		if (in_img->vbp_size < val)
+			return -EINVAL;
+
+		/* calculate total of horizontal active size and vertical active size */
+		if (rawpack != VIIF_RAWPACK_DISABLE) {
+			val = (in_img->hactive_size + in_img->hobc_width + in_img->hobc_margin) *
+			      2U;
+		} else {
+			val = in_img->hactive_size + in_img->hobc_width + in_img->hobc_margin;
+		}
+
+		total_hact_size = val;
+		total_vact_size = in_img->vactive_size * in_img->input_num;
+	} else {
+		/* OTHER input than RAW(L1ISP is off) */
+		if (in_img->hactive_size < VIIF_MIN_HACTIVE_PIXEL_WO_L1ISP ||
+		    in_img->hactive_size > VIIF_MAX_HACTIVE_PIXEL_WO_L1ISP ||
+		    in_img->vactive_size < VIIF_MIN_VACTIVE_LINE_WO_L1ISP ||
+		    in_img->vactive_size > VIIF_MAX_VACTIVE_LINE_WO_L1ISP ||
+		    in_img->input_num != 1 || in_img->hobc_width) {
+			return -EINVAL;
+		}
+
+		/* check vbp range in case of L1ISP off */
+		/* the constant value "16" is configuration margin */
+		val = sysclk_to_numlines(VIIF_TABLE_LOAD_TIME + VIIF_REGBUF_ACCESS_TIME, in_img) +
+		      16U;
+		if (in_img->vbp_size < val)
+			return -EINVAL;
+
+		total_hact_size = in_img->hactive_size;
+		total_vact_size = in_img->vactive_size;
+	}
+
+	if (in_img->htotal_size <= total_hact_size ||
+	    (in_img->vtotal_size <= (in_img->vbp_size + total_vact_size))) {
+		return -EINVAL;
+	}
+
+	/* Set DT and color type of image data */
+	viif_capture_write(viif_dev, REG_IPORTM_MAIN_DT, (data_type << 8U) | data_type);
+	viif_capture_write(viif_dev, REG_IPORTM_OTHER, 0x00);
+
+	/* Set back porch*/
+	viif_capture_write(viif_dev, REG_BACK_PORCH_M, (in_img->vbp_size << 16U) | VIIF_HBP_SYSCLK);
+
+	/* single pulse of vsync is input to DPGM */
+	viif_capture_write(viif_dev, REG_DPGM_VSYNC_SOURCE, VAL_DPGM_VSYNC_PULSE);
+
+	/* set preprocess type before L2ISP based on color_type. */
+	if (data_type == MIPI_CSI2_DT_YUV422_8B || data_type == MIPI_CSI2_DT_YUV422_10B) {
+		color = VAL_PREPROCCESS_FMT_YUV422;
+	} else if (data_type == MIPI_CSI2_DT_RGB565 || data_type == MIPI_CSI2_DT_RGB888) {
+		color = VAL_PREPROCCESS_FMT_RGB;
+	} else {
+		/* RGB or YUV444 from L1ISP */
+		color = VAL_PREPROCCESS_FMT_YUV444;
+	}
+	viif_capture_write(viif_dev, REG_PREPROCCESS_FMTM, color);
+
+	/* set Total size and valid size information of image data */
+	sysclk_num = lineperiod_in_sysclk(in_img->htotal_size, in_img->pixel_clock);
+	sysclk_num &= GENMASK(15, 0);
+	viif_capture_write(viif_dev, REG_TOTALSIZE_M, (in_img->vtotal_size << 16U) | sysclk_num);
+	viif_capture_write(viif_dev, REG_VALSIZE_M, (total_vact_size << 16U) | total_hact_size);
+
+	/* set image size information to L2ISP */
+	viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_VSIZE, in_img->vactive_size);
+	viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_HSIZE, in_img->hactive_size);
+
+	/* RAW input case */
+	if (data_type >= MIPI_CSI2_DT_RAW8) {
+		/* interpolaton mode = by LINE */
+		viif_capture_write(viif_dev, REG_L1_IBUF_INPUT_ORDER, in_img->input_num);
+		viif_capture_write(viif_dev, REG_L1_SYSM_HEIGHT, in_img->vactive_size);
+		viif_capture_write(viif_dev, REG_L1_SYSM_WIDTH, in_img->hactive_size);
+		val = (in_img->hobc_margin << 8U) | in_img->hobc_width;
+		viif_capture_write(viif_dev, REG_L1_HOBC_MARGIN, val);
+	}
+
+	/* Set rawpack */
+	viif_capture_write(viif_dev, REG_IPORTM_MAIN_RAW, rawpack);
+
+	/* Set yuv_conv; only for VAL_PREPROCCESS_FMT_YUV422 */
+	viif_capture_write(viif_dev, REG_PREPROCCESS_C24M, yuv_interp ? 1 : 0);
+
+	/* Set vsync delay */
+	hw_delay = in_img->vbp_size - sysclk_to_numlines(VIIF_TABLE_LOAD_TIME, in_img) + 4U;
+	hw_delay = min(hw_delay, 255U);
+
+	sw_delay0 = hw_delay - sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, in_img) + 2U;
+
+	if (data_type == MIPI_CSI2_DT_RAW8 || data_type == MIPI_CSI2_DT_RAW10 ||
+	    data_type == MIPI_CSI2_DT_RAW12 || data_type == MIPI_CSI2_DT_RAW14) {
+		sw_delay1 = sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, in_img) +
+			    VIIF_L1_DELAY_WO_HDRC + 1U;
+	} else {
+		sw_delay1 = 10U;
+	}
+	viif_capture_write(viif_dev, REG_INT_M0_LINE, sw_delay0 << 16U);
+	viif_capture_write(viif_dev, REG_INT_M1_LINE, (sw_delay1 << 16U) | hw_delay);
+
+	/* M2_LINE is the same condition as M1_LINE */
+	viif_capture_write(viif_dev, REG_INT_M2_LINE, (sw_delay1 << 16U) | hw_delay);
+
+	/* hold pixel_clock, htotal_size for future use */
+	viif_dev->img_clk.pixel_clock = in_img->pixel_clock;
+	viif_dev->img_clk.htotal_size = in_img->htotal_size;
+
+	/* initialize crop information of POSTs */
+	viif_dev->l2_roi_path_info.roi_num = 0;
+	for (i = 0; i < VIIF_MAX_POST_NUM; i++) {
+		viif_dev->l2_roi_path_info.post_enable_flag[i] = false;
+		viif_dev->l2_roi_path_info.post_crop_x[i] = 0;
+		viif_dev->l2_roi_path_info.post_crop_y[i] = 0;
+		viif_dev->l2_roi_path_info.post_crop_w[i] = 0;
+		viif_dev->l2_roi_path_info.post_crop_h[i] = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * viif_sub_set_unit() - Set static configuration of SUB unit
+ *
+ * @dt_image: DT of image. Range: [0x1E, 0x1F, 0x22, 0x24, 0x2A-0x2D]
+ * @in_img: Pointer to input image information
+ * Return: 0 Operation completes successfully
+ * Return: -EINVAL Parameter error
+ */
+static int viif_sub_set_unit(struct viif_device *viif_dev, u32 dt_image,
+			     const struct viif_input_img *in_img)
+{
+	u32 sysclk_num, temp_delay;
+
+	if (dt_image < MIPI_CSI2_DT_RAW8 || dt_image > MIPI_CSI2_DT_RAW14)
+		return -EINVAL;
+
+	if (!in_img)
+		return -EINVAL;
+
+	if (in_img->hactive_size || in_img->input_num != 1 || in_img->hobc_width ||
+	    in_img->hobc_margin) {
+		return -EINVAL;
+	}
+
+	if (in_img->pixel_clock < VIIF_MIN_PIXEL_CLOCK ||
+	    in_img->pixel_clock > VIIF_MAX_PIXEL_CLOCK ||
+	    in_img->htotal_size < VIIF_MIN_HTOTAL_PIXEL ||
+	    in_img->htotal_size > VIIF_MAX_HTOTAL_PIXEL ||
+	    in_img->vtotal_size < VIIF_MIN_VTOTAL_LINE ||
+	    in_img->vtotal_size > VIIF_MAX_VTOTAL_LINE || in_img->vbp_size < VIIF_MIN_VBP_LINE ||
+	    in_img->vbp_size > VIIF_MAX_VBP_LINE ||
+	    in_img->vactive_size < VIIF_MIN_VACTIVE_LINE_WO_L1ISP ||
+	    in_img->vactive_size > VIIF_MAX_VACTIVE_LINE_WO_L1ISP || (in_img->vactive_size % 2U)) {
+		return -EINVAL;
+	}
+
+	if (in_img->vtotal_size <= (in_img->vbp_size + in_img->vactive_size))
+		return -EINVAL;
+
+	/* Set DT of image data and DT of long packet data*/
+	viif_capture_write(viif_dev, REG_IPORTS_MAIN_DT, dt_image);
+	viif_capture_write(viif_dev, REG_IPORTS_OTHER, 0x00);
+
+	/* Set line size and delay value of delayed Vsync */
+	sysclk_num = lineperiod_in_sysclk(in_img->htotal_size, in_img->pixel_clock);
+	viif_capture_write(viif_dev, REG_INT_SA0_LINE, sysclk_num & GENMASK(15, 0));
+	temp_delay = in_img->vbp_size - 4U;
+	if (temp_delay > 255U) {
+		/* Replace the value with HW max spec */
+		temp_delay = 255U;
+	}
+	viif_capture_write(viif_dev, REG_INT_SA1_LINE, temp_delay);
+
+	return 0;
+}
+
+/**
+ * viif_mux_start() - Setup CSI-2 input path
+ *
+ * @vc_main: VCID (0, 1, 2, 3) to capture with Main unit; VIIF_CSI2_NOT_CAPTURE to disable.
+ * @vc_sub:  VCID (0, 1, 2, 3) to capture with Sub unit; VIIF_CSI2_NOT_CAPTURE to disable.
+ */
+static void viif_mux_start(struct viif_device *viif_dev, s32 vc_main, s32 vc_sub)
+{
+	bool en_vc0 = false, en_vc1 = false;
+
+	viif_capture_write(viif_dev, REG_IPORTM, VAL_IPORTM_INPUT_CSI2);
+
+	if (vc_main != VIIF_CSI2_NOT_CAPTURE) {
+		viif_capture_write(viif_dev, REG_VCID0SELECT, (u32)vc_main);
+		en_vc0 = true;
+	}
+	if (vc_sub != VIIF_CSI2_NOT_CAPTURE) {
+		viif_capture_write(viif_dev, REG_VCID1SELECT, (u32)vc_sub);
+		en_vc1 = true;
+	}
+
+	/* Control VC port enable */
+	viif_capture_write(viif_dev, REG_VCPORTEN,
+			   (en_vc0 ? MASK_VCPORTEN_EN_VC0 : 0) |
+				   (en_vc1 ? MASK_VCPORTEN_EN_VC1 : 0));
+
+	if (en_vc0) {
+		/* Update flag information for run status of MAIN unit */
+		viif_dev->run_flag_main = true;
+	}
+}
+
+/**
+ * viif_mux_stop() - Teardown CSI-2 input path
+ *
+ * Return: 0 Operation completes successfully
+ * Return: -ETIMEDOUT Driver timeout error
+ */
+static int viif_mux_stop(struct viif_device *viif_dev)
+{
+	u64 timeout_ns, cur_ns;
+
+	/* Disable auto transmission of register buffer */
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, 0);
+
+	/* Wait for completion of register buffer transmission */
+	udelay(VIIF_WAIT_ISP_REGBF_TRNS_COMPLETE_TIME);
+
+	/* Stop all VCs, long packet input and emb data input of MAIN unit */
+	viif_capture_write(viif_dev, REG_VCPORTEN, 0);
+	viif_capture_write(viif_dev, REG_IPORTM_OTHEREN, 0);
+	viif_capture_write(viif_dev, REG_IPORTM_EMBEN, 0);
+
+	/* Stop image data input, long packet input and emb data input of SUB unit */
+	viif_capture_write(viif_dev, REG_IPORTS_OTHEREN, 0);
+	viif_capture_write(viif_dev, REG_IPORTS_EMBEN, 0);
+	viif_capture_write(viif_dev, REG_IPORTS_IMGEN, 0);
+
+	/* Stop VDMAC for all table ports, input ports and write ports */
+	viif_capture_write(viif_dev, REG_VDM_T_ENABLE, 0);
+	viif_capture_write(viif_dev, REG_VDM_R_ENABLE, 0);
+	viif_capture_write(viif_dev, REG_VDM_W_ENABLE, 0);
+
+	/* Stop all groups(g00, g01 and g02) of VDMAC */
+	viif_capture_write(viif_dev, REG_VDM_ABORTSET, 0x7);
+
+	timeout_ns = ktime_get_ns() + VIIF_WAIT_ABORT_COMPLETE_TIME * 1000;
+
+	do {
+		u32 status_r, status_w, status_t, l2_status;
+
+		/* Get VDMAC transfer status  */
+		status_r = viif_capture_read(viif_dev, REG_VDM_R_RUN);
+		status_w = viif_capture_read(viif_dev, REG_VDM_W_RUN);
+		status_t = viif_capture_read(viif_dev, REG_VDM_T_RUN);
+		l2_status = viif_capture_read(viif_dev, REG_L2_BUS_L2_STATUS);
+
+		if (!status_r && !status_w && !status_t && !l2_status) {
+			viif_dev->run_flag_main = false;
+			return 0;
+		}
+
+		cur_ns = ktime_get_ns();
+	} while (timeout_ns > cur_ns);
+
+	return -ETIMEDOUT;
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+/* ----- supported MBUS formats ----- */
+static bool viif_get_mbus_rgb_out(unsigned int mbus_code)
+{
+	const struct viif_mbus_format *fmt;
+
+	fmt = viif_mbus_format_from_code(mbus_code);
+
+	return fmt ? fmt->rgb_out : false; /* YUV as default */
+}
+
+static bool viif_is_valid_mbus_code(unsigned int mbus_code)
+{
+	return viif_mbus_format_from_code(mbus_code) ? true : false;
+}
+
+/* ----- handling main processing path ----- */
+static int viif_get_dv_timings(struct viif_device *viif_dev, struct v4l2_dv_timings *timings)
+{
+	struct viif_subdev *viif_sd = viif_dev->sd;
+	struct v4l2_subdev_pad_config pad_cfg;
+	struct v4l2_subdev_state pad_state = {
+		.pads = &pad_cfg,
+	};
+	struct v4l2_subdev_format format = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = 0,
+	};
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	/* some video I/F support dv_timings query */
+	ret = v4l2_subdev_call(viif_sd->v4l2_sd, video, g_dv_timings, timings);
+	if (!ret)
+		return 0;
+
+	/* others: call some discrete APIs */
+	ret = v4l2_subdev_call(viif_sd->v4l2_sd, pad, get_fmt, &pad_state, &format);
+	if (ret)
+		return ret;
+
+	timings->bt.width = format.format.width;
+	timings->bt.height = format.format.height;
+
+	ctrl = v4l2_ctrl_find(viif_sd->v4l2_sd->ctrl_handler, V4L2_CID_HBLANK);
+	if (!ctrl) {
+		dev_err(viif_dev->dev, "subdev: V4L2_CID_VBLANK error.\n");
+		return -EINVAL;
+	}
+	timings->bt.hsync = v4l2_ctrl_g_ctrl(ctrl);
+
+	ctrl = v4l2_ctrl_find(viif_sd->v4l2_sd->ctrl_handler, V4L2_CID_VBLANK);
+	if (!ctrl) {
+		dev_err(viif_dev->dev, "subdev: V4L2_CID_VBLANK error.\n");
+		return -EINVAL;
+	}
+	timings->bt.vsync = v4l2_ctrl_g_ctrl(ctrl);
+
+	ctrl = v4l2_ctrl_find(viif_sd->v4l2_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	if (!ctrl) {
+		dev_err(viif_dev->dev, "subdev: V4L2_CID_PIXEL_RATE error.\n");
+		return -EINVAL;
+	}
+	timings->bt.pixelclock = v4l2_ctrl_g_ctrl_int64(ctrl);
+
+	return 0;
+}
+
+static unsigned int dt_image_from_mbus_code(unsigned int mbus_code)
+{
+	const struct viif_mbus_format *fmt;
+
+	fmt = viif_mbus_format_from_code(mbus_code);
+
+	return fmt ? fmt->mipi_dt : MIPI_CSI2_DT_RGB888;
+}
+
+int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev)
+{
+	unsigned int data_type, rawpack;
+	struct viif_subdev *viif_sd = viif_dev->sd;
+	struct viif_input_img in_img_main;
+	struct v4l2_dv_timings timings;
+	struct v4l2_subdev_format fmt = {
+		.pad = 0,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	bool yuv_interp = false;
+	int mag_hactive = 1;
+	int ret = 0;
+
+	/* check controls */
+	viif_dev->isp_subdev.ctrl_rawpack_mode->ops->s_ctrl(viif_dev->isp_subdev.ctrl_rawpack_mode);
+	viif_dev->isp_subdev.ctrl_input_mode->ops->s_ctrl(viif_dev->isp_subdev.ctrl_input_mode);
+
+	ret = viif_get_dv_timings(viif_dev, &timings);
+	if (ret) {
+		dev_err(viif_dev->dev, "could not get timing information of subdev");
+		return -EINVAL;
+	}
+
+	ret = v4l2_subdev_call(viif_sd->v4l2_sd, pad, get_fmt, NULL, &fmt);
+	if (ret) {
+		dev_err(viif_dev->dev, "could not get pad information of subdev");
+		return -EINVAL;
+	}
+
+	data_type = dt_image_from_mbus_code(fmt.format.code);
+
+	if (data_type == MIPI_CSI2_DT_RAW8 || data_type == MIPI_CSI2_DT_RAW10 ||
+	    data_type == MIPI_CSI2_DT_RAW12) {
+		rawpack = viif_dev->rawpack_mode;
+		if (rawpack != VIIF_RAWPACK_DISABLE)
+			mag_hactive = 2;
+	} else {
+		rawpack = VIIF_RAWPACK_DISABLE;
+	}
+
+	yuv_interp = (data_type == MIPI_CSI2_DT_YUV422_8B || data_type == MIPI_CSI2_DT_YUV422_10B);
+
+	in_img_main.hactive_size = timings.bt.width;
+	in_img_main.vactive_size = timings.bt.height;
+	in_img_main.htotal_size = timings.bt.width * mag_hactive + timings.bt.hsync;
+	in_img_main.vtotal_size = timings.bt.height + timings.bt.vsync;
+	in_img_main.pixel_clock = timings.bt.pixelclock / 1000;
+	in_img_main.vbp_size = timings.bt.vsync - 5;
+
+	in_img_main.input_num = 1;
+	in_img_main.hobc_width = 0;
+	in_img_main.hobc_margin = 0;
+
+	/* configuration of MAIN unit */
+	ret = viif_main_set_unit(viif_dev, data_type, &in_img_main, rawpack, yuv_interp);
+	if (ret) {
+		dev_err(viif_dev->dev, "main_set_unit error. %d\n", ret);
+		return ret;
+	}
+
+	/* Enable regbuf */
+	hwd_viif_isp_set_regbuf_auto_transmission(viif_dev);
+
+	/* L2 UNDIST Enable through mode as default  */
+	/* this function is implemented in the next patch */
+	/*
+	 * ret = visconti_viif_l2_undist_through(viif_dev);
+	 * if (ret)
+	 *	dev_err(viif_dev->dev, "l2_set_undist error. %d\n", ret);
+	 */
+	return ret;
+}
+
+int visconti_viif_isp_sub_set_unit(struct viif_device *viif_dev)
+{
+	struct viif_input_img in_img_sub;
+	struct v4l2_dv_timings timings;
+	struct v4l2_subdev_format fmt = {
+		.pad = 0,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	unsigned int dt_image;
+	int ret;
+
+	ret = viif_get_dv_timings(viif_dev, &timings);
+	if (ret)
+		return -EINVAL;
+
+	ret = v4l2_subdev_call(viif_dev->sd->v4l2_sd, pad, get_fmt, NULL, &fmt);
+	if (ret) {
+		dev_err(viif_dev->dev, "could not get pad information of subdev");
+		return -EINVAL;
+	}
+
+	dt_image = dt_image_from_mbus_code(fmt.format.code);
+
+	in_img_sub.hactive_size = 0;
+	in_img_sub.vactive_size = timings.bt.height;
+	in_img_sub.htotal_size = timings.bt.width + timings.bt.hsync;
+	in_img_sub.vtotal_size = timings.bt.height + timings.bt.vsync;
+	in_img_sub.pixel_clock = timings.bt.pixelclock / 1000;
+	in_img_sub.vbp_size = timings.bt.vsync - 5;
+	in_img_sub.input_num = 1;
+	in_img_sub.hobc_width = 0;
+	in_img_sub.hobc_margin = 0;
+
+	ret = viif_sub_set_unit(viif_dev, dt_image, &in_img_sub);
+	if (ret)
+		dev_err(viif_dev->dev, "sub_set_unit error. %d\n", ret);
+
+	return ret;
+};
+
+/* ----- subdevice video operations ----- */
+static int visconti_viif_isp_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	int ret;
+
+	/* disabling: stop sensor, CSI2RX -> stop MUX, ISP */
+	if (!enable) {
+		v4l2_subdev_call(&viif_dev->csi2rx_subdev.sd, video, s_stream, false);
+		viif_mux_stop(viif_dev);
+		// stop ISP
+		return 0;
+	}
+
+	pr_info("try re-evaluate controls");
+	__v4l2_ctrl_handler_setup(&viif_dev->isp_subdev.ctrl_handler);
+
+	/* enabling: start ISP, MUX -> start CSI2RX, sensor */
+	// start ISP
+	viif_dev->masked_gamma_path = 0;
+	viif_mux_start(viif_dev, 0, 0);
+	ret = v4l2_subdev_call(&viif_dev->csi2rx_subdev.sd, video, s_stream, true);
+	if (ret)
+		viif_mux_stop(viif_dev);
+	return ret;
+}
+
+/* ----- subdevice pad operations ----- */
+static int visconti_viif_isp_enum_mbus_code(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *sd_state,
+					    struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (!code->pad) {
+		/* sink */
+		const struct viif_mbus_format *fmt;
+
+		fmt = viif_mbus_format_nth(code->index);
+		if (fmt) {
+			code->code = fmt->code;
+			return 0;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	/* source */
+	if (code->index > 0)
+		return -EINVAL;
+	code->code = MEDIA_BUS_FMT_YUV8_1X24;
+	return 0;
+}
+
+static struct v4l2_mbus_framefmt *visconti_viif_isp_get_pad_fmt(struct v4l2_subdev *sd,
+								struct v4l2_subdev_state *sd_state,
+								unsigned int pad, u32 which)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_subdev_state state = {
+		.pads = viif_dev->isp_subdev.pad_cfg,
+	};
+
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(&viif_dev->isp_subdev.sd, sd_state, pad);
+	else
+		return v4l2_subdev_get_try_format(&viif_dev->isp_subdev.sd, &state, pad);
+}
+
+static struct v4l2_rect *visconti_viif_isp_get_pad_crop(struct v4l2_subdev *sd,
+							struct v4l2_subdev_state *sd_state,
+							unsigned int pad, u32 which)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_subdev_state state = {
+		.pads = viif_dev->isp_subdev.pad_cfg,
+	};
+
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(&viif_dev->isp_subdev.sd, sd_state, pad);
+	else
+		return v4l2_subdev_get_try_crop(&viif_dev->isp_subdev.sd, &state, pad);
+}
+
+static struct v4l2_rect *visconti_viif_isp_get_pad_compose(struct v4l2_subdev *sd,
+							   struct v4l2_subdev_state *sd_state,
+							   unsigned int pad, u32 which)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_subdev_state state = {
+		.pads = viif_dev->isp_subdev.pad_cfg,
+	};
+
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_compose(&viif_dev->isp_subdev.sd, sd_state, pad);
+	else
+		return v4l2_subdev_get_try_compose(&viif_dev->isp_subdev.sd, &state, pad);
+}
+
+static int visconti_viif_isp_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_format *fmt)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+
+	mutex_lock(&viif_dev->isp_subdev.ops_lock);
+	fmt->format = *visconti_viif_isp_get_pad_fmt(sd, sd_state, fmt->pad, fmt->which);
+	mutex_unlock(&viif_dev->isp_subdev.ops_lock);
+
+	return 0;
+}
+
+static void visconti_viif_isp_set_sink_fmt(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state,
+					   struct v4l2_mbus_framefmt *format, u32 which)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src0_fmt, *src1_fmt, *src2_fmt;
+
+	sink_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SINK, which);
+	src0_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SRC_PATH0, which);
+	src1_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SRC_PATH1, which);
+	src2_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SRC_PATH2, which);
+
+	/* update mbus code only if it's available */
+	if (viif_is_valid_mbus_code(format->code))
+		sink_fmt->code = format->code;
+
+	/* sink::mbus_code is derived from src::mbus_code */
+	if (viif_get_mbus_rgb_out(sink_fmt->code)) {
+		src0_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+		src1_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+	} else {
+		src0_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+		src1_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+	}
+
+	/* SRC2 (RAW output) follows SINK format */
+	src2_fmt->code = format->code;
+	src2_fmt->width = format->width;
+	src2_fmt->height = format->height;
+
+	/* size check */
+	sink_fmt->width = format->width;
+	sink_fmt->height = format->height;
+
+	*format = *sink_fmt;
+}
+
+static void visconti_viif_isp_set_src_fmt(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_mbus_framefmt *format, unsigned int pad,
+					  u32 which)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+	struct v4l2_rect *src_crop;
+
+	sink_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SINK,
+						 V4L2_SUBDEV_FORMAT_ACTIVE);
+	src_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, pad, which);
+	src_crop = visconti_viif_isp_get_pad_crop(sd, sd_state, pad, which);
+
+	/* sink::mbus_code is derived from src::mbus_code */
+	if (viif_get_mbus_rgb_out(sink_fmt->code))
+		src_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+	else
+		src_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+
+	/*size check*/
+	src_fmt->width = format->width;
+	src_fmt->height = format->height;
+
+	/*update crop*/
+	src_crop->width = format->width;
+	src_crop->height = format->height;
+
+	*format = *src_fmt;
+}
+
+static void visconti_viif_isp_set_src_fmt_rawpath(struct v4l2_subdev *sd,
+						  struct v4l2_subdev_state *sd_state,
+						  struct v4l2_mbus_framefmt *format,
+						  unsigned int pad, u32 which)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	sink_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SINK,
+						 V4L2_SUBDEV_FORMAT_ACTIVE);
+	src_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, pad, which);
+
+	/* RAWPATH SRC pad has just the same configuration as SINK pad */
+	src_fmt->code = sink_fmt->code;
+	src_fmt->width = sink_fmt->width;
+	src_fmt->height = sink_fmt->height;
+
+	*format = *src_fmt;
+}
+
+static int visconti_viif_isp_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_format *fmt)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+
+	mutex_lock(&viif_dev->isp_subdev.ops_lock);
+
+	if (fmt->pad == VIIF_ISP_PAD_SINK)
+		visconti_viif_isp_set_sink_fmt(sd, sd_state, &fmt->format, fmt->which);
+	else if (fmt->pad == VIIF_ISP_PAD_SRC_PATH2)
+		visconti_viif_isp_set_src_fmt_rawpath(sd, sd_state, &fmt->format, fmt->pad,
+						      fmt->which);
+	else
+		visconti_viif_isp_set_src_fmt(sd, sd_state, &fmt->format, fmt->pad, fmt->which);
+
+	mutex_unlock(&viif_dev->isp_subdev.ops_lock);
+
+	return 0;
+}
+
+static int visconti_viif_isp_init_config(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+	struct v4l2_rect *src_crop, *sink_compose;
+
+	sink_fmt =
+		v4l2_subdev_get_try_format(&viif_dev->isp_subdev.sd, sd_state, VIIF_ISP_PAD_SINK);
+	sink_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	sink_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+
+	sink_compose =
+		v4l2_subdev_get_try_compose(&viif_dev->isp_subdev.sd, sd_state, VIIF_ISP_PAD_SINK);
+	sink_compose->top = 0;
+	sink_compose->left = 0;
+	sink_compose->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	sink_compose->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+
+	src_fmt = v4l2_subdev_get_try_format(&viif_dev->isp_subdev.sd, sd_state,
+					     VIIF_ISP_PAD_SRC_PATH0);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+
+	src_crop = v4l2_subdev_get_try_crop(&viif_dev->isp_subdev.sd, sd_state,
+					    VIIF_ISP_PAD_SRC_PATH0);
+	src_crop->top = 0;
+	src_crop->left = 0;
+	src_crop->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_crop->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+
+	src_fmt = v4l2_subdev_get_try_format(&viif_dev->isp_subdev.sd, sd_state,
+					     VIIF_ISP_PAD_SRC_PATH1);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+
+	src_crop = v4l2_subdev_get_try_crop(&viif_dev->isp_subdev.sd, sd_state,
+					    VIIF_ISP_PAD_SRC_PATH1);
+	src_crop->top = 0;
+	src_crop->left = 0;
+	src_crop->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_crop->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+
+	src_fmt = v4l2_subdev_get_try_format(&viif_dev->isp_subdev.sd, sd_state,
+					     VIIF_ISP_PAD_SRC_PATH2);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+
+	return 0;
+}
+
+static int visconti_viif_isp_get_selection(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state,
+					   struct v4l2_subdev_selection *sel)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_mbus_framefmt *sink_fmt;
+	int ret = -EINVAL;
+
+	mutex_lock(&viif_dev->isp_subdev.ops_lock);
+	if (sel->pad == VIIF_ISP_PAD_SINK) {
+		/* SINK PAD */
+		switch (sel->target) {
+		case V4L2_SEL_TGT_CROP:
+			sink_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, VIIF_ISP_PAD_SINK,
+								 sel->which);
+			sel->r.top = 0;
+			sel->r.left = 0;
+			sel->r.width = sink_fmt->width;
+			sel->r.height = sink_fmt->height;
+			ret = 0;
+			break;
+		case V4L2_SEL_TGT_COMPOSE:
+			sel->r = *visconti_viif_isp_get_pad_compose(sd, sd_state, VIIF_ISP_PAD_SINK,
+								    sel->which);
+			ret = 0;
+			break;
+		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+			/* fixed value */
+			sel->r.top = 0;
+			sel->r.left = 0;
+			sel->r.width = VISCONTI_VIIF_MAX_COMPOSED_WIDTH;
+			sel->r.height = VISCONTI_VIIF_MAX_COMPOSED_HEIGHT;
+			ret = 0;
+			break;
+		}
+	} else if ((sel->pad == VIIF_ISP_PAD_SRC_PATH0) || (sel->pad == VIIF_ISP_PAD_SRC_PATH1)) {
+		/* SRC PAD */
+		switch (sel->target) {
+		case V4L2_SEL_TGT_CROP:
+			sel->r =
+				*visconti_viif_isp_get_pad_crop(sd, sd_state, sel->pad, sel->which);
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&viif_dev->isp_subdev.ops_lock);
+
+	return ret;
+}
+
+static int visconti_viif_isp_set_selection(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state,
+					   struct v4l2_subdev_selection *sel)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_mbus_framefmt *src_fmt;
+	struct v4l2_rect *rect, *rect_compose;
+	int ret = -EINVAL;
+
+	mutex_lock(&viif_dev->isp_subdev.ops_lock);
+	/* only source::selection::crop is writable */
+	if (sel->pad == VIIF_ISP_PAD_SRC_PATH0 || sel->pad == VIIF_ISP_PAD_SRC_PATH1) {
+		switch (sel->target) {
+		case V4L2_SEL_TGT_CROP: {
+			/* check if new SRC::CROP is inside SINK::COMPOSE */
+			rect_compose = visconti_viif_isp_get_pad_compose(
+				sd, sd_state, VIIF_ISP_PAD_SINK, sel->which);
+			if (sel->r.top < rect_compose->top || sel->r.left < rect_compose->left ||
+			    (sel->r.top + sel->r.height) >
+				    (rect_compose->top + rect_compose->height) ||
+			    (sel->r.left + sel->r.width) >
+				    (rect_compose->left + rect_compose->width)) {
+				break;
+			}
+
+			rect = visconti_viif_isp_get_pad_crop(sd, sd_state, sel->pad, sel->which);
+			*rect = sel->r;
+
+			/* update SRC::FMT along with SRC::CROP */
+			src_fmt = visconti_viif_isp_get_pad_fmt(sd, sd_state, sel->pad, sel->which);
+			src_fmt->width = sel->r.width;
+			src_fmt->height = sel->r.height;
+			ret = 0;
+			break;
+		}
+		}
+	}
+	mutex_unlock(&viif_dev->isp_subdev.ops_lock);
+
+	return ret;
+}
+
+void visconti_viif_isp_set_compose_rect(struct viif_device *viif_dev,
+					struct viif_l2_roi_config *roi)
+{
+	struct v4l2_rect *rect;
+
+	rect = visconti_viif_isp_get_pad_compose(&viif_dev->isp_subdev.sd, NULL, VIIF_ISP_PAD_SINK,
+						 V4L2_SUBDEV_FORMAT_ACTIVE);
+	rect->top = 0;
+	rect->left = 0;
+	rect->width = roi->corrected_hsize[0];
+	rect->height = roi->corrected_vsize[0];
+}
+
+static const struct media_entity_operations visconti_viif_isp_media_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_pad_ops visconti_viif_isp_pad_ops = {
+	.enum_mbus_code = visconti_viif_isp_enum_mbus_code,
+	.get_selection = visconti_viif_isp_get_selection,
+	.set_selection = visconti_viif_isp_set_selection,
+	.init_cfg = visconti_viif_isp_init_config,
+	.get_fmt = visconti_viif_isp_get_fmt,
+	.set_fmt = visconti_viif_isp_set_fmt,
+	.link_validate = v4l2_subdev_link_validate_default,
+};
+
+static const struct v4l2_subdev_video_ops visconti_viif_isp_video_ops = {
+	.s_stream = visconti_viif_isp_s_stream,
+};
+
+static const struct v4l2_subdev_ops visconti_viif_isp_ops = {
+	.video = &visconti_viif_isp_video_ops,
+	.pad = &visconti_viif_isp_pad_ops,
+};
+
+/* ----- register/remove isp subdevice node ----- */
+int visconti_viif_isp_register(struct viif_device *viif_dev)
+{
+	struct v4l2_subdev_state state = {
+		.pads = viif_dev->isp_subdev.pad_cfg,
+	};
+	struct media_pad *pads = viif_dev->isp_subdev.pads;
+	struct v4l2_subdev *sd = &viif_dev->isp_subdev.sd;
+	int ret;
+
+	viif_dev->isp_subdev.viif_dev = viif_dev;
+
+	v4l2_subdev_init(sd, &visconti_viif_isp_ops);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->entity.ops = &visconti_viif_isp_media_ops;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+	sd->owner = THIS_MODULE;
+	strscpy(sd->name, "visconti-viif:isp", sizeof(sd->name));
+
+	pads[0].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[1].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[2].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[3].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+
+	mutex_init(&viif_dev->isp_subdev.ops_lock);
+
+	/* this function is implemented in the next patch */
+/*
+ *	visconti_viif_isp_init_controls(viif_dev);
+ */
+
+	ret = media_entity_pads_init(&sd->entity, 4, pads);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed on media_entity_pads_init\n");
+		return ret;
+	}
+
+	ret = v4l2_device_register_subdev(&viif_dev->v4l2_dev, sd);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to resize ISP subdev\n");
+		goto err_cleanup_media_entity;
+	}
+
+	visconti_viif_isp_init_config(sd, &state);
+
+	return 0;
+
+err_cleanup_media_entity:
+	media_entity_cleanup(&sd->entity);
+	return ret;
+}
+
+void visconti_viif_isp_unregister(struct viif_device *viif_dev)
+{
+	v4l2_device_unregister_subdev(&viif_dev->isp_subdev.sd);
+	media_entity_cleanup(&viif_dev->isp_subdev.sd.entity);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.h b/drivers/media/platform/toshiba/visconti/viif_isp.h
new file mode 100644
index 000000000..42e9e3009
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_ISP_H
+#define VIIF_ISP_H
+
+struct viif_device;
+struct viif_l2_roi_config;
+
+void visconti_viif_l2_set_roi_path(struct viif_device *viif_dev);
+void visconti_viif_l2_set_roi(struct viif_device *viif_dev, const struct viif_l2_roi_config *param);
+int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev);
+int visconti_viif_isp_sub_set_unit(struct viif_device *viif_dev);
+void visconti_viif_isp_set_compose_rect(struct viif_device *viif_dev,
+					struct viif_l2_roi_config *roi);
+
+int visconti_viif_isp_register(struct viif_device *viif_dev);
+void visconti_viif_isp_unregister(struct viif_device *viif_dev);
+
+#endif /* VIIF_ISP_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_regs.h b/drivers/media/platform/toshiba/visconti/viif_regs.h
new file mode 100644
index 000000000..14c142a66
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_regs.h
@@ -0,0 +1,714 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture register definitions
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_REGS_H
+#define VIIF_REGS_H
+
+/*=============================================*/
+/* Capture registers */
+/*=============================================*/
+#define REG_IPORTM0_LD	   0
+#define REG_IPORTM1_LD	   0x4
+#define MASK_IPORTM_VLATCH 0x3
+
+#define REG_CSI2RX_RESETN      0x8
+#define REG_CSI2RX_INT_ST_MAIN 0xC
+#define REG_CSI2RX_DATA_IDS_1  0x10
+#define REG_CSI2RX_DATA_IDS_2  0x14
+#define REG_VCID0SELECT	       0x30
+#define REG_VCID1SELECT	       0x34
+#define REG_VCPORTEN	       0x3C
+#define MASK_VCPORTEN_EN_VC0   BIT(0)
+#define MASK_VCPORTEN_EN_VC1   BIT(4)
+#define REG_IPORTM	       0x54
+#define VAL_IPORTM_INPUT_CSI2  0
+
+#define REG_IPORTM_MAIN_DT		 0x58
+#define REG_IPORTM_MAIN_RAW		 0x5C
+#define REG_IPORTM_OTHER		 0x60
+#define REG_IPORTM_OTHEREN		 0x64
+#define REG_IPORTM_EMBEN		 0x68
+#define REG_IPORTS_MAIN_DT		 0x78
+#define REG_IPORTS_OTHER		 0x80
+#define REG_IPORTS_OTHEREN		 0x84
+#define REG_IPORTS_EMBEN		 0x88
+#define REG_IPORTS_IMGEN		 0x8C
+#define REG_TOTALSIZE_M			 0xC0
+#define REG_VALSIZE_M			 0xC4
+#define REG_BACK_PORCH_M		 0xC8
+#define REG_INT_M_SYNC			 0x130
+#define REG_INT_M_SYNC_MASK		 0x134
+#define MASK_INT_M_SYNC_VSYNC_INT	 BIT(0)
+#define MASK_INT_M_SYNC_LINES_DELAY_INT1 BIT(1)
+#define MASK_INT_M_SYNC_LINES_DELAY_INT2 BIT(2)
+#define MASK_INT_M_SYNC_SW_DELAY_INT0	 BIT(16)
+#define MASK_INT_M_SYNC_SW_DELAY_INT1	 BIT(17)
+#define MASK_INT_M_SYNC_SW_DELAY_INT2	 BIT(18)
+/* we only care for LINES_DELAY_INT2, SW_DELAY_INT2 */
+#define MASK_INT_M_SYNC_MASK_SET                                        \
+	(MASK_INT_M_SYNC_VSYNC_INT | MASK_INT_M_SYNC_LINES_DELAY_INT1 | \
+	 MASK_INT_M_SYNC_SW_DELAY_INT0 | MASK_INT_M_SYNC_SW_DELAY_INT1)
+
+#define REG_INT_S_SYNC			 0x138
+#define REG_INT_S_SYNC_MASK		 0x13C
+#define MASK_INT_S_SYNC_VSYNC_INT	 BIT(0)
+#define MASK_INT_S_SYNC_LINES_DELAY_INT1 BIT(1)
+#define MASK_INT_S_SYNC_SW_DELAY_INT0	 BIT(16)
+#define MASK_INT_S_SYNC_SW_DELAY_INT1	 BIT(17)
+/* we only care for LINES_DELAY_INT1 */
+#define MASK_INT_S_SYNC_MASK_SET \
+	(MASK_INT_S_SYNC_VSYNC_INT | MASK_INT_S_SYNC_SW_DELAY_INT0 | MASK_INT_S_SYNC_SW_DELAY_INT1)
+
+#define REG_INT_M0_LINE			     0x140
+#define REG_INT_M1_LINE			     0x144
+#define REG_INT_M2_LINE			     0x148
+#define REG_INT_SA0_LINE		     0x160
+#define REG_INT_SA1_LINE		     0x164
+#define REG_INT_M_STATUS		     0x180
+#define REG_INT_M_MASK			     0x184
+#define MASK_INT_M_L2ISP_SIZE_ERROR	     BIT(0)
+#define MASK_INT_M_CRGBF_INTCRGERR_WRSTART   BIT(1)
+#define MASK_INT_M_CRGBF_INTCRGERR_RDSTART   BIT(2)
+#define MASK_INT_M_EMBED_ERROR		     BIT(3)
+#define MASK_INT_M_USERDATA_ERROR	     BIT(4)
+#define MASK_INT_M_L2ISP_GAMMA_TABLE_TIMEOUT (BIT(8) | BIT(9) | BIT(10))
+#define MASK_INT_M_L2ISP_GRID_TABLE_TIMEOUT  BIT(11)
+#define MASK_INT_M_L1ISP_SIZE_ERROR0	     BIT(16)
+#define MASK_INT_M_L1ISP_SIZE_ERROR1	     BIT(17)
+#define MASK_INT_M_L1ISP_SIZE_ERROR2	     BIT(18)
+#define MASK_INT_M_L1ISP_SIZE_ERROR3	     BIT(19)
+#define MASK_INT_M_L1ISP_SIZE_ERROR4	     BIT(20)
+#define MASK_INT_M_L1ISP_INT_ERR_CRGWRSTART  BIT(21)
+#define MASK_INT_M_L1ISP_INT_ERR_CRGRDSTART  BIT(22)
+#define MASK_INT_M_DELAY_INT_ERROR	     BIT(24)
+
+#define REG_INT_S_STATUS	   0x188
+#define REG_INT_S_MASK		   0x18C
+#define MASK_INT_S_SIZE_ERROR	   BIT(0)
+#define MASK_INT_S_EMBED_ERROR	   BIT(1)
+#define MASK_INT_S_USERDATA_ERROR  BIT(2)
+#define MASK_INT_S_DELAY_INT_ERROR BIT(24)
+#define MASK_INT_S_RESERVED_SET	   (BIT(16) | BIT(28))
+
+#define REG_PREPROCCESS_FMTM	   0x210
+#define VAL_PREPROCCESS_FMT_RGB	   (0x0 << 4)
+#define VAL_PREPROCCESS_FMT_YUV444 (0x1 << 4)
+#define VAL_PREPROCCESS_FMT_YUV422 (0x3 << 4)
+
+#define REG_PREPROCCESS_C24M		   0x214
+#define REG_L2ISP_INPUT_CSC_MTB		   0x220
+#define REG_L2ISP_INPUT_CSC_MTB_YG_OFFSETI 0x230
+#define REG_L2ISP_INPUT_CSC_MTB_YG1	   0x234
+#define REG_L2ISP_INPUT_CSC_MTB_YG2	   0x238
+#define REG_L2ISP_INPUT_CSC_MTB_YG_OFFSETO 0x23C
+#define REG_L2ISP_INPUT_CSC_MTB_CB_OFFSETI 0x240
+#define REG_L2ISP_INPUT_CSC_MTB_CB1	   0x244
+#define REG_L2ISP_INPUT_CSC_MTB_CB2	   0x248
+#define REG_L2ISP_INPUT_CSC_MTB_CB_OFFSETO 0x24C
+#define REG_L2ISP_INPUT_CSC_MTB_CR_OFFSETI 0x250
+#define REG_L2ISP_INPUT_CSC_MTB_CR1	   0x254
+#define REG_L2ISP_INPUT_CSC_MTB_CR2	   0x258
+#define REG_L2ISP_INPUT_CSC_MTB_CR_OFFSETO 0x25C
+#define REG_DPHY_FREQRANGE		   0x700
+#define REG_DPHY_LANE			   0x710
+#define REG_DPGM_VSYNC_SOURCE		   0x804
+#define VAL_DPGM_VSYNC_PULSE		   1
+
+#define REG_VDM_R_ENABLE		 0x1030
+#define REG_VDM_W_ENABLE		 0x1034
+#define REG_VDM_T_ENABLE		 0x1038
+#define MASK_VDM_T_ENABLE_L1_DPC_H	 BIT(0)
+#define MASK_VDM_T_ENABLE_L1_DPC_M	 BIT(1)
+#define MASK_VDM_T_ENABLE_L1_DPC_L	 BIT(2)
+#define MASK_VDM_T_ENABLE_L1_DPC	 0x07
+#define MASK_VDM_T_ENABLE_L1_LSSC_GR	 BIT(4)
+#define MASK_VDM_T_ENABLE_L1_LSSC_R	 BIT(5)
+#define MASK_VDM_T_ENABLE_L1_LSSC_B	 BIT(6)
+#define MASK_VDM_T_ENABLE_L1_LSSC_GB	 BIT(7)
+#define MASK_VDM_T_ENABLE_L1_LSSC	 0x00F0
+#define MASK_VDM_T_ENABLE_L2_UNDIST_RD_B BIT(8)
+#define MASK_VDM_T_ENABLE_L2_UNDIST_RD_G BIT(9)
+#define MASK_VDM_T_ENABLE_L2_UNDIST_RD_R BIT(10)
+#define MASK_VDM_T_ENABLE_L2_UNDIST_WR_G BIT(11)
+#define MASK_VDM_T_ENABLE_L2_UNDIST	 0x0F00
+/* val: 12-23; postid: 0-1, ch: 0-5 */
+#define MASK_VDM_T_ENABLE_L2_GAMMA(postid, ch) BIT(12 + ((postid) * 6) + (ch))
+#define MASK_VDM_T_ENABLE_L2_GAMMA_ALL(postid) (0x3FU << (12 + ((postid) * 6)))
+
+#define REG_VDM_ABORTSET 0x103C
+
+/* x: 0-3 */
+#define REG_VDM_TGROUP_X_BASE(x)		 (0x1040 + 16 * (x))
+#define REG_VDM_TGROUP_X_CFG(x)		 (REG_VDM_TGROUP_X_BASE(x) + 0)
+#define REG_VDM_TGROUP_X_SRAM_BASE(x)	 (REG_VDM_TGROUP_X_BASE(x) + 4)
+#define REG_VDM_TGROUP_X_SRAM_SIZE(x)	 (REG_VDM_TGROUP_X_BASE(x) + 8)
+#define IDX_TGROUP_L1_ISP		 0
+#define IDX_TGROUP_L2_UNDIST		 1
+#define IDX_TGROUP_L2_GAMMA_LUT(post_id) (2 + (post_id))
+#define VAL_TGROUP_CFG_64BIT_RD		 0x0310U
+#define VAL_TGROUP_CFG_32BIT_RD		 0x0210U
+
+/* x: 0-23*/
+#define REG_VDM_TPORT_X_BASE(x)	(0x1100 + 8 * (x))
+#define REG_VDM_TPORT_X_SIZE(x)	(REG_VDM_TPORT_X_BASE(x) + 4)
+#define REG_VDM_TPORT_X_STADR(x) (REG_VDM_TPORT_X_BASE(x) + 0)
+/* idx: 0-2; x: 0-2 */
+#define IDX_TPORT_L1_DPC(x)	 (x)
+#define IDX_TPORT_L1_DPC_H	 0
+#define IDX_TPORT_L1_DPC_M	 1
+#define IDX_TPORT_L1_DPC_L	 2
+#define IDX_TPORT_L1_LSSC_GR	 4
+#define IDX_TPORT_L1_LSSC_R	 5
+#define IDX_TPORT_L1_LSSC_B	 6
+#define IDX_TPORT_L1_LSSC_GB	 7
+#define IDX_TPORT_L2_UNDIST_RD_B 8
+#define IDX_TPORT_L2_UNDIST_RD_G 9
+#define IDX_TPORT_L2_UNDIST_RD_R 10
+#define IDX_TPORT_L2_UNDIST_WR_G 11
+/* idx: 12-23; post_id: 0-1, col: 0-5 */
+#define IDX_TPORT_L2_GAMMA_LUT(post_id, col) (12 + (col) + (post_id) * 6)
+
+/* x: 0-5 */
+#define REG_VDM_WPORT_X_BASE(x)	      (0x1300 + 64 * (x))
+#define REG_VDM_WPORT_X_W_CFG0(x)      (REG_VDM_WPORT_X_BASE(x) + 16)
+#define REG_VDM_WPORT_X_W_ENDADR(x)    (REG_VDM_WPORT_X_BASE(x) + 4)
+#define REG_VDM_WPORT_X_W_HEIGHT(x)    (REG_VDM_WPORT_X_BASE(x) + 8)
+#define REG_VDM_WPORT_X_W_PITCH(x)     (REG_VDM_WPORT_X_BASE(x) + 12)
+#define REG_VDM_WPORT_X_W_SRAM_BASE(x) (REG_VDM_WPORT_X_BASE(x) + 24)
+#define REG_VDM_WPORT_X_W_SRAM_SIZE(x) (REG_VDM_WPORT_X_BASE(x) + 28)
+#define REG_VDM_WPORT_X_W_STADR(x)     (REG_VDM_WPORT_X_BASE(x) + 0)
+#define IDX_WPORT_MAIN_LNG	      0
+#define IDX_WPORT_MAIN_EMB	      1
+#define IDX_WPORT_SUB_IMG	      3
+#define IDX_WPORT_SUB_LNG	      4
+#define IDX_WPORT_SUB_EMB	      5
+
+#define REG_VDM_R_RUN		0x1E18
+#define REG_VDM_W_RUN		0x1E1C
+#define REG_VDM_T_RUN		0x1E20
+#define REG_L1_SYSM_WIDTH	0x2000
+#define REG_L1_SYSM_HEIGHT	0x2004
+#define REG_L1_SYSM_START_COLOR 0x2008
+#define REG_L1_SYSM_INPUT_MODE	0x200C
+#define REG_L1_SYSM_YCOEF_R	0x2014
+#define REG_L1_SYSM_YCOEF_G	0x2018
+#define REG_L1_SYSM_YCOEF_B	0x201C
+#define REG_L1_SYSM_AG_H	0x2040
+#define REG_L1_SYSM_AG_M	0x2044
+#define REG_L1_SYSM_AG_L	0x2048
+#define REG_L1_SYSM_AG_PARAM_A	0x204C
+#define REG_L1_SYSM_AG_PARAM_B	0x2050
+#define REG_L1_SYSM_AG_PARAM_C	0x2054
+#define REG_L1_SYSM_AG_PARAM_D	0x2058
+#define PACK_L1_SYSM_AG_PARAM(grad, ofst) \
+	(FIELD_PREP(0x00FF0000, (grad)) | FIELD_PREP(0x00FFFF, (ofst)))
+
+#define REG_L1_SYSM_AG_SEL_HOBC 0x205C
+#define REG_L1_SYSM_AG_SEL_ABPC 0x2060
+#define REG_L1_SYSM_AG_SEL_RCNR 0x2064
+#define PACK_L1_SYSM_AG_SEL_HML(high, mid, low) \
+	(FIELD_PREP(0x00C0, (high)) | FIELD_PREP(0x0030, (mid)) | FIELD_PREP(0x0C, (low)))
+
+#define REG_L1_SYSM_AG_SEL_LSSC		   0x2068
+#define REG_L1_SYSM_AG_SEL_MPRO		   0x206C
+#define REG_L1_SYSM_AG_SEL_VPRO		   0x2070
+#define PACK_L1_SYSM_AG_SEL_SP(ssel, psel) (FIELD_PREP(0x00C0, (ssel)) | (FIELD_PREP(0x03, (psel))))
+
+#define REG_L1_SYSM_AG_CONT_HOBC01_EN 0x2074
+#define REG_L1_SYSM_AG_CONT_HOBC2_EN  0x2078
+#define REG_L1_SYSM_AG_CONT_ABPC01_EN 0x207C
+#define REG_L1_SYSM_AG_CONT_ABPC2_EN  0x2080
+#define REG_L1_SYSM_AG_CONT_RCNR01_EN 0x2084
+#define REG_L1_SYSM_AG_CONT_RCNR2_EN  0x2088
+#define MASK_L1_SYSM_AG_CONT_M_EN     BIT(24)
+#define MASK_L1_SYSM_AG_CONT_H_EN     BIT(8)
+#define MASK_L1_SYSM_AG_CONT_M_VAL    0x00FF0000
+#define MASK_L1_SYSM_AG_CONT_H_VAL    0x00FF
+#define MASK_L1_SYSM_AG_CONT_L_EN     BIT(8)
+#define MASK_L1_SYSM_AG_CONT_L_VAL    0x00FF
+
+#define REG_L1_SYSM_AG_CONT_LSSC_EN 0x208C
+#define REG_L1_SYSM_AG_CONT_MPRO_EN 0x2090
+#define REG_L1_SYSM_AG_CONT_VPRO_EN 0x2094
+#define MASK_L1_SYSM_AG_CONT_EN	    BIT(8)
+#define MASK_L1_SYSM_AG_CONT_VAL    0x00FF
+
+#define LEN_L1_HDRE_SRCPOINT	 16
+#define REG_L1_HDRE_SRCPOINT(x) (0x20C4 + 4 * (x))
+
+#define LEN_L1_HDRE_SRCBASE	17
+#define REG_L1_HDRE_SRCBASE(x) (0x2104 + 4 * (x))
+
+#define LEN_L1_HDRE_RATIO     17
+#define REG_L1_HDRE_RATIO(x) (0x2148 + 4 * (x))
+
+#define LEN_L1_HDRE_DSTBASE	17
+#define REG_L1_HDRE_DSTBASE(x) (0x218C + 4 * (x))
+
+#define REG_L1_HDRE_DSTMAXVAL	 0x21D0
+#define REG_L1_AEXP_ON		 0x2200
+#define REG_L1_AEXP_RESULT_AVE	 0x2204
+#define REG_L1_AEXP_START_X	 0x2210
+#define REG_L1_AEXP_START_Y	 0x2214
+#define REG_L1_AEXP_BLOCK_WIDTH	 0x2218
+#define REG_L1_AEXP_BLOCK_HEIGHT 0x221C
+#define REG_L1_AEXP_WEIGHT_0	 0x2220
+#define REG_L1_AEXP_WEIGHT_1	 0x2224
+#define REG_L1_AEXP_WEIGHT_2	 0x2228
+#define REG_L1_AEXP_WEIGHT_3	 0x222C
+#define REG_L1_AEXP_WEIGHT_4	 0x2230
+#define REG_L1_AEXP_WEIGHT_5	 0x2234
+#define REG_L1_AEXP_WEIGHT_6	 0x2238
+#define REG_L1_AEXP_WEIGHT_7	 0x223C
+#define REG_L1_AEXP_SATUR_RATIO	 0x2240
+#define REG_L1_AEXP_BLACK_RATIO	 0x2244
+#define REG_L1_AEXP_SATUR_LEVEL	 0x2248
+/* 8 x 8 elements */
+#define REG_L1_AEXP_AVE(y, x)	       (0x2250 + 32 * (y) + 4 * (x))
+#define REG_L1_AEXP_SATUR_BLACK_PIXNUM 0x2350
+#define REG_L1_AEXP_AVE4LINESY0	       0x2354
+#define REG_L1_AEXP_AVE4LINESY1	       0x2358
+#define REG_L1_AEXP_AVE4LINESY2	       0x235C
+#define REG_L1_AEXP_AVE4LINESY3	       0x2360
+#define REG_L1_AEXP_AVE4LINES0	       0x2364
+#define REG_L1_AEXP_AVE4LINES1	       0x2368
+#define REG_L1_AEXP_AVE4LINES2	       0x236C
+#define REG_L1_AEXP_AVE4LINES3	       0x2370
+#define REG_L1_IBUF_DEPTH	       0x2380
+#define REG_L1_IBUF_INPUT_ORDER	       0x2384
+#define REG_L1_SLIC_SRCBLACKLEVEL_GR   0x2390
+#define REG_L1_SLIC_SRCBLACKLEVEL_R    0x2394
+#define REG_L1_SLIC_SRCBLACKLEVEL_B    0x2398
+#define REG_L1_SLIC_SRCBLACKLEVEL_GB   0x239C
+#define REG_L1_ABPC012_STA_EN	       0x240C
+#define REG_L1_ABPC012_DYN_EN	       0x2410
+#define MASK_L1_ABPC_ENABLE_H	       BIT(24)
+#define MASK_L1_ABPC_ENABLE_M	       BIT(16)
+#define MASK_L1_ABPC_ENABLE_L	       BIT(8)
+
+#define REG_L1_ABPC012_DYN_MODE	       0x2414
+#define MASK_L1_ABPC_DYN_MODE_2PIXEL_H BIT(24)
+#define MASK_L1_ABPC_DYN_MODE_2PIXEL_M BIT(16)
+#define MASK_L1_ABPC_DYN_MODE_2PIXEL_L BIT(8)
+
+#define REG_L1_ABPC0_RATIO_LIMIT      0x2424
+#define REG_L1_ABPC0_DARK_LIMIT	      0x242C
+#define REG_L1_ABPC0_SN_COEF_W_AG_MIN 0x2430
+#define REG_L1_ABPC0_SN_COEF_W_AG_MID 0x2434
+#define REG_L1_ABPC0_SN_COEF_W_AG_MAX 0x2438
+#define REG_L1_ABPC0_SN_COEF_W_TH_MIN 0x243C
+#define REG_L1_ABPC0_SN_COEF_W_TH_MAX 0x2440
+#define REG_L1_ABPC0_SN_COEF_B_AG_MIN 0x2444
+#define REG_L1_ABPC0_SN_COEF_B_AG_MID 0x2448
+#define REG_L1_ABPC0_SN_COEF_B_AG_MAX 0x244C
+#define REG_L1_ABPC0_SN_COEF_B_TH_MIN 0x2450
+#define REG_L1_ABPC0_SN_COEF_B_TH_MAX 0x2454
+#define REG_L1_ABPC1_RATIO_LIMIT      0x2460
+#define REG_L1_ABPC1_DARK_LIMIT	      0x2468
+#define REG_L1_ABPC1_SN_COEF_W_AG_MIN 0x246C
+#define REG_L1_ABPC1_SN_COEF_W_AG_MID 0x2470
+#define REG_L1_ABPC1_SN_COEF_W_AG_MAX 0x2474
+#define REG_L1_ABPC1_SN_COEF_W_TH_MIN 0x2478
+#define REG_L1_ABPC1_SN_COEF_W_TH_MAX 0x247C
+#define REG_L1_ABPC1_SN_COEF_B_AG_MIN 0x2480
+#define REG_L1_ABPC1_SN_COEF_B_AG_MID 0x2484
+#define REG_L1_ABPC1_SN_COEF_B_AG_MAX 0x2488
+#define REG_L1_ABPC1_SN_COEF_B_TH_MIN 0x248C
+#define REG_L1_ABPC1_SN_COEF_B_TH_MAX 0x2490
+#define REG_L1_ABPC2_RATIO_LIMIT      0x249C
+#define REG_L1_ABPC2_DARK_LIMIT	      0x24A4
+#define REG_L1_ABPC2_SN_COEF_W_AG_MIN 0x24A8
+#define REG_L1_ABPC2_SN_COEF_W_AG_MID 0x24AC
+#define REG_L1_ABPC2_SN_COEF_W_AG_MAX 0x24B0
+#define REG_L1_ABPC2_SN_COEF_W_TH_MIN 0x24B4
+#define REG_L1_ABPC2_SN_COEF_W_TH_MAX 0x24B8
+#define REG_L1_ABPC2_SN_COEF_B_AG_MIN 0x24BC
+#define REG_L1_ABPC2_SN_COEF_B_AG_MID 0x24C0
+#define REG_L1_ABPC2_SN_COEF_B_AG_MAX 0x24C4
+#define REG_L1_ABPC2_SN_COEF_B_TH_MIN 0x24C8
+#define REG_L1_ABPC2_SN_COEF_B_TH_MAX 0x24CC
+#define REG_L1_PWHB_H_GR	      0x2584
+#define REG_L1_PWHB_HR		      0x2588
+#define REG_L1_PWHB_HB		      0x258C
+#define REG_L1_PWHB_H_GB	      0x2590
+#define REG_L1_PWHB_M_GR	      0x2594
+#define REG_L1_PWHB_MR		      0x2598
+#define REG_L1_PWHB_MB		      0x259C
+#define REG_L1_PWHB_M_GB	      0x25A0
+#define REG_L1_PWHB_L_GR	      0x25A4
+#define REG_L1_PWHB_LR		      0x25A8
+#define REG_L1_PWHB_LB		      0x25AC
+#define REG_L1_PWHB_L_GB	      0x25B0
+#define REG_L1_PWHB_DSTMAXVAL	      0x25B4
+
+/* 0 for high, 1 for middle, 2 for low sensitivity image */
+#define REG_L1_RCNR_X_SW(x)		  (0x2608 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_DARK_AG0(x)	  (0x260C + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_DARK_AG1(x)	  (0x2610 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_DARK_AG2(x)	  (0x2614 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_RATIO_AG0(x)	  (0x2618 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_RATIO_AG1(x)	  (0x261C + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_RATIO_AG2(x)	  (0x2620 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_CLIP_GAIN_R(x)	  (0x2624 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_CLIP_GAIN_G(x)	  (0x2628 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_CLIP_GAIN_B(x)	  (0x262C + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_DARK_AG0(x)	  (0x2630 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_DARK_AG1(x)	  (0x2634 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_DARK_AG2(x)	  (0x2638 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_RATIO_AG0(x)	  (0x263C + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_RATIO_AG1(x)	  (0x2640 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_RATIO_AG2(x)	  (0x2644 + 0x94 * (x))
+#define REG_L1_RCNR_X_INF_ZERO_CLIP(x)	  (0x2648 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_D2BLEND_AG0(x) (0x2650 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_D2BLEND_AG1(x) (0x2654 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_D2BLEND_AG2(x) (0x2658 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_BLACK(x)	  (0x265C + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_MINDIV(x)	  (0x2660 + 0x94 * (x))
+#define REG_L1_RCNR_X_HRY_TYPE(x)	  (0x2664 + 0x94 * (x))
+#define REG_L1_RCNR_X_ANF_BLEND_AG0(x)	  (0x2668 + 0x94 * (x))
+#define REG_L1_RCNR_X_ANF_BLEND_AG1(x)	  (0x266C + 0x94 * (x))
+#define REG_L1_RCNR_X_ANF_BLEND_AG2(x)	  (0x2670 + 0x94 * (x))
+#define REG_L1_RCNR_X_LPF_THRESHOLD(x)	  (0x2678 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_HLBLEND_AG0(x) (0x267C + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_HLBLEND_AG1(x) (0x2680 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_HLBLEND_AG2(x) (0x2684 + 0x94 * (x))
+#define REG_L1_RCNR_X_GNR_SW(x)		  (0x2688 + 0x94 * (x))
+#define REG_L1_RCNR_X_GNR_RATIO(x)	  (0x268C + 0x94 * (x))
+#define REG_L1_RCNR_X_GNR_WIDE_EN(x)	  (0x2690 + 0x94 * (x))
+
+#define REG_L1_HDRS_HDRRATIO_M	     0x2884
+#define REG_L1_HDRS_HDRRATIO_L	     0x2888
+#define REG_L1_HDRS_HDRRATIO_E	     0x288C
+#define REG_L1_HDRS_BLENDEND_H	     0x2898
+#define REG_L1_HDRS_BLENDEND_M	     0x289C
+#define REG_L1_HDRS_BLENDEND_E	     0x28A0
+#define REG_L1_HDRS_BLENDBEG_H	     0x28A4
+#define REG_L1_HDRS_BLENDBEG_M	     0x28A8
+#define REG_L1_HDRS_BLENDBEG_E	     0x28AC
+#define REG_L1_HDRS_DG_H	     0x28C8
+#define REG_L1_HDRS_DG_M	     0x28CC
+#define REG_L1_HDRS_DG_L	     0x28D0
+#define REG_L1_HDRS_DG_E	     0x28D4
+#define REG_L1_HDRS_LEDMODE_ON	     0x28D8
+#define REG_L1_HDRS_HDRMODE	     0x28DC
+#define REG_L1_HDRS_DSTMAXVAL	     0x28EC
+#define REG_L1_BLVC_SRCBLACKLEVEL_GR 0x2900
+#define REG_L1_BLVC_SRCBLACKLEVEL_R  0x2904
+#define REG_L1_BLVC_SRCBLACKLEVEL_B  0x2908
+#define REG_L1_BLVC_SRCBLACKLEVELGB  0x290C
+#define REG_L1_BLVC_MULTVAL_GR	     0x2910
+#define REG_L1_BLVC_MULTVAL_R	     0x2914
+#define REG_L1_BLVC_MULTVAL_B	     0x2918
+#define REG_L1_BLVC_MULTVAL_GB	     0x291C
+#define REG_L1_BLVC_DSTMAXVAL	     0x2920
+#define REG_L1_LSSC_EN		     0x2980
+#define REG_L1_LSSC_PWHB_R_GAIN	     0x2990
+#define REG_L1_LSSC_PWHB_GR_GAIN     0x2994
+#define REG_L1_LSSC_PWHB_GB_GAIN     0x2998
+#define REG_L1_LSSC_PWHB_B_GAIN	     0x299C
+#define REG_L1_LSSC_PARA_EN	     0x29A0
+#define REG_L1_LSSC_PARA_H_CENTER    0x29A4
+#define REG_L1_LSSC_PARA_V_CENTER    0x29A8
+#define REG_L1_LSSC_PARA_H_GAIN	     0x29AC
+#define REG_L1_LSSC_PARA_V_GAIN	     0x29B0
+#define REG_L1_LSSC_PARA_MGSEL2	     0x29B4
+#define REG_L1_LSSC_PARA_MGSEL4	     0x29B8
+
+/*0: R/2D, 1: R/4D, 2: GR/2D, 3: GR/4D, 4: GB/2D, 5: GB/4D, 6: B/2D, 7: B/4D*/
+#define REG_L1_LSSC_PARA_COEF_X_H_L(x)	 (0x29BC + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_H_R(x)	 (0x29C0 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_V_U(x)	 (0x29C4 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_V_D(x)	 (0x29C8 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_LU(x) (0x29CC + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_RU(x) (0x29D0 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_LD(x) (0x29D4 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_RD(x) (0x29D8 + 0x20 * (x))
+
+#define REG_L1_LSSC_GRID_EN	   0x2ABC
+#define REG_L1_LSSC_GRID_H_CENTER  0x2AC0
+#define REG_L1_LSSC_GRID_V_CENTER  0x2AC4
+#define REG_L1_LSSC_GRID_H_SIZE	   0x2AC8
+#define REG_L1_LSSC_GRID_V_SIZE	   0x2ACC
+#define REG_L1_LSSC_GRID_MGSEL	   0x2AD0
+#define REG_L1_MPRO_SW		   0x2B00
+#define REG_L1_MPRO_CONF	   0x2B04
+#define REG_L1_MPRO_DST_MINVAL	   0x2B0C
+#define REG_L1_MPRO_DST_MAXVAL	   0x2B10
+#define REG_L1_MPRO_LM0_RMG_MIN	   0x2B20
+#define REG_L1_MPRO_LM0_RMB_MIN	   0x2B24
+#define REG_L1_MPRO_LM0_GMR_MIN	   0x2B28
+#define REG_L1_MPRO_LM0_GMB_MIN	   0x2B2C
+#define REG_L1_MPRO_LM0_BMR_MIN	   0x2B30
+#define REG_L1_MPRO_LM0_BMG_MIN	   0x2B34
+#define REG_L1_MPRO_LM0_RMG_MAX	   0x2B38
+#define REG_L1_MPRO_LM0_RMB_MAX	   0x2B3C
+#define REG_L1_MPRO_LM0_GMR_MAX	   0x2B40
+#define REG_L1_MPRO_LM0_GMB_MAX	   0x2B44
+#define REG_L1_MPRO_LM0_BMR_MAX	   0x2B48
+#define REG_L1_MPRO_LM0_BMG_MAX	   0x2B4C
+#define REG_L1_MPRO_LCS_MODE	   0x2BF0
+#define REG_L1_VPRO_PGC_SW	   0x2D80
+#define REG_L1_VPRO_YUVC_SW	   0x2D88
+#define REG_L1_VPRO_YNR_SW	   0x2D8C
+#define REG_L1_VPRO_ETE_SW	   0x2D90
+#define REG_L1_VPRO_CSUP_UVSUP_SW  0x2D94
+#define REG_L1_VPRO_CSUP_CORING_SW 0x2D98
+#define REG_L1_VPRO_BRIGHT_SW	   0x2D9C
+#define REG_L1_VPRO_LCNT_SW	   0x2DA0
+#define REG_L1_VPRO_NLCNT_SW	   0x2DA4
+#define REG_L1_VPRO_EDGE_SUP_SW	   0x2DAC
+#define REG_L1_VPRO_CNR_SW	   0x2DB0
+#define REG_L1_VPRO_BLKADJ	   0x2DB8
+/* (GAM00P is fixed 0) GAM01P-GAM44P: x:0-43 */
+#define REG_L1_VPRO_GAMxP(x)		 (0x2DBC + 4 * (x))
+#define REG_L1_VPRO_CB_MAT		 0x2E6C
+#define REG_L1_VPRO_CR_MAT		 0x2E70
+#define REG_L1_VPRO_BRIGHT		 0x2E74
+#define REG_L1_VPRO_LCONT_LEV		 0x2E78
+#define REG_L1_VPRO_BLK_KNEE		 0x2E7C
+#define REG_L1_VPRO_WHT_KNEE		 0x2E80
+#define REG_L1_VPRO_BLK_CONT0		 0x2E84
+#define REG_L1_VPRO_BLK_CONT1		 0x2E88
+#define REG_L1_VPRO_BLK_CONT2		 0x2E8C
+#define REG_L1_VPRO_WHT_CONT0		 0x2E90
+#define REG_L1_VPRO_WHT_CONT1		 0x2E94
+#define REG_L1_VPRO_WHT_CONT2		 0x2E98
+#define REG_L1_VPRO_YNR_GAIN_MIN	 0x2EB4
+#define REG_L1_VPRO_YNR_GAIN_MAX	 0x2EB8
+#define REG_L1_VPRO_YNR_LIM_MIN		 0x2EBC
+#define REG_L1_VPRO_YNR_LIM_MAX		 0x2EC0
+#define REG_L1_VPRO_ETE_GAIN_MIN	 0x2EC4
+#define REG_L1_VPRO_ETE_GAIN_MAX	 0x2EC8
+#define REG_L1_VPRO_ETE_LIM_MIN		 0x2ECC
+#define REG_L1_VPRO_ETE_LIM_MAX		 0x2ED0
+#define REG_L1_VPRO_ETE_CORING_MIN	 0x2ED4
+#define REG_L1_VPRO_ETE_CORING_MAX	 0x2ED8
+#define REG_L1_VPRO_CB_GAIN		 0x2EDC
+#define REG_L1_VPRO_CR_GAIN		 0x2EE0
+#define REG_L1_VPRO_CBR_MGAIN_MIN	 0x2EE4
+#define REG_L1_VPRO_CB_P_GAIN_MAX	 0x2EE8
+#define REG_L1_VPRO_CB_M_GAIN_MAX	 0x2EEC
+#define REG_L1_VPRO_CR_P_GAIN_MAX	 0x2EF0
+#define REG_L1_VPRO_CR_M_GAIN_MAX	 0x2EF4
+#define REG_L1_VPRO_CSUP_CORING_LV_MIN	 0x2EF8
+#define REG_L1_VPRO_CSUP_CORING_LV_MAX	 0x2EFC
+#define REG_L1_VPRO_CSUP_CORING_GAIN_MIN 0x2F00
+#define REG_L1_VPRO_CSUP_CORING_GAIN_MAX 0x2F04
+#define REG_L1_VPRO_CSUP_BK_SLV		 0x2F08
+#define REG_L1_VPRO_CSUP_BK_MP		 0x2F0C
+#define REG_L1_VPRO_CSUP_BLACK		 0x2F10
+#define REG_L1_VPRO_CSUP_WH_SLV		 0x2F14
+#define REG_L1_VPRO_CSUP_WH_MP		 0x2F18
+#define REG_L1_VPRO_CSUP_WHITE		 0x2F1C
+#define REG_L1_VPRO_EDGE_SUP_GAIN	 0x2F20
+#define REG_L1_VPRO_EDGE_SUP_LIM	 0x2F24
+#define REG_L1_AWHB_SW			 0x2F80
+#define MASK_L1_AWHB_SW_EN		 BIT(7)
+#define MASK_L1_AWHB_SW_LOCK		 BIT(5)
+
+#define REG_L1_AWHB_WBMRG	     0x2F88
+#define REG_L1_AWHB_WBMGG	     0x2F8C
+#define REG_L1_AWHB_WBMBG	     0x2F90
+#define REG_L1_AWHB_GATE_CONF0	     0x2F94
+#define MASK_L1_AWHB_GATE_YGATE_SEL  BIT(7)
+#define MASK_L1_AWHB_GATE_YGATE_DATA 0x0060
+#define MASK_L1_AWHB_GATE_CGRANGE    0x0003
+
+#define REG_L1_AWHB_GATE_CONF1	   0x2F98
+#define MASK_L1_AWHB_GATE_YGATESW  BIT(5)
+#define MASK_L1_AWHB_GATE_HEXSW	   BIT(4)
+#define MASK_L1_AWHB_GATE_AREAMODE 0x0003
+
+#define REG_L1_AWHB_AREA_HSIZE	    0x2F9C
+#define REG_L1_AWHB_AREA_VSIZE	    0x2FA0
+#define REG_L1_AWHB_AREA_HOFS	    0x2FA4
+#define REG_L1_AWHB_AREA_VOFS	    0x2FA8
+#define REG_L1_AWHB_AREA_MASKH	    0x2FAC
+#define REG_L1_AWHB_AREA_MASKL	    0x2FB0
+#define REG_L1_AWHB_SQ_CONF	    0x2FB4
+#define MASK_L1_AWHB_SQ_CONF_SQ3POL BIT(2)
+#define MASK_L1_AWHB_SQ_CONF_SQ3SW  BIT(3)
+#define MASK_L1_AWHB_SQ_CONF_SQ2POL BIT(4)
+#define MASK_L1_AWHB_SQ_CONF_SQ2SW  BIT(5)
+#define MASK_L1_AWHB_SQ_CONF_SQ1POL BIT(6)
+#define MASK_L1_AWHB_SQ_CONF_SQ1SW  BIT(7)
+
+#define REG_L1_AWHB_YGATEH	   0x2FB8
+#define REG_L1_AWHB_YGATEL	   0x2FBC
+#define REG_L1_AWHB_BYCUT0P	   0x2FC8
+#define REG_L1_AWHB_BYCUT0N	   0x2FCC
+#define REG_L1_AWHB_RYCUT0P	   0x2FD0
+#define REG_L1_AWHB_RYCUT0N	   0x2FD4
+#define REG_L1_AWHB_RBCUT0H	   0x2FD8
+#define REG_L1_AWHB_RBCUT0L	   0x2FDC
+#define REG_L1_AWHB_BYCUT1H	   0x2FF8
+#define REG_L1_AWHB_BYCUT1L	   0x2FFC
+#define REG_L1_AWHB_RYCUT1H	   0x3000
+#define REG_L1_AWHB_RYCUT1L	   0x3004
+#define REG_L1_AWHB_BYCUT2H	   0x3008
+#define REG_L1_AWHB_BYCUT2L	   0x300C
+#define REG_L1_AWHB_RYCUT2H	   0x3010
+#define REG_L1_AWHB_RYCUT2L	   0x3014
+#define REG_L1_AWHB_BYCUT3H	   0x3018
+#define REG_L1_AWHB_BYCUT3L	   0x301C
+#define REG_L1_AWHB_RYCUT3H	   0x3020
+#define REG_L1_AWHB_RYCUT3L	   0x3024
+#define REG_L1_AWHB_AWBSFTU	   0x3028
+#define REG_L1_AWHB_AWBSFTV	   0x302C
+#define REG_L1_AWHB_AWBSPD	   0x3030
+#define MASK_L1_AWHB_AWBSPD_HUECOR BIT(4)
+#define MASK_L1_AWHB_AWBSPD_SPD	   0x0F
+
+#define REG_L1_AWHB_AWBULV	0x3034
+#define REG_L1_AWHB_AWBVLV	0x3038
+#define REG_L1_AWHB_AWBWAIT	0x303C
+#define REG_L1_AWHB_AWBONDOT	0x3040
+#define REG_L1_AWHB_AWBFZTIM	0x3044
+#define REG_L1_AWHB_WBGRMAX	0x3048
+#define REG_L1_AWHB_WBGRMIN	0x304C
+#define REG_L1_AWHB_WBGBMAX	0x3050
+#define REG_L1_AWHB_WBGBMIN	0x3054
+#define REG_L1_AWHB_AVE_USIG	0x308C
+#define REG_L1_AWHB_AVE_VSIG	0x3090
+#define REG_L1_AWHB_NUM_UVON	0x3094
+#define REG_L1_AWHB_AWBGAINR	0x3098
+#define REG_L1_AWHB_AWBGAING	0x309C
+#define REG_L1_AWHB_AWBGAINB	0x30A0
+#define REG_L1_AWHB_R_CTR_STOP	0x30B0
+#define REG_L1_HOBC_MARGIN	0x30C4
+#define REG_L1_HDRC_EN		0x3200
+#define REG_L1_HDRC_THR_SFT_AMT 0x3204
+#define REG_L1_HDRC_RATIO	0x320C
+#define REG_L1_HDRC_PT_RATIO	0x321C
+#define REG_L1_HDRC_PT_BLEND	0x3220
+#define REG_L1_HDRC_PT_BLEND2	0x3224
+#define REG_L1_HDRC_PT_SAT	0x3228
+#define REG_L1_HDRC_TN_TYPE	0x322C
+#define REG_L1_HDRC_TNP_MAX	0x3230
+#define REG_L1_HDRC_TNP_MAG	0x3234
+
+#define LEN_L1_HDRC_TNP_FIL	5
+#define REG_L1_HDRC_TNP_FIL(x) (0x3248 + 4 * (x))
+
+#define LEN_L1_HDRC_UTN_TBL	20
+#define REG_L1_HDRC_UTN_TBL(x) (0x325C + 4 * (x))
+
+#define REG_L1_HDRC_FLR_VAL		   0x32AC
+#define REG_L1_HDRC_FLR_ADP		   0x32B0
+#define REG_L1_HDRC_YBR_OFF		   0x32EC
+#define REG_L1_HDRC_ORGY_BLEND		   0x32F0
+#define REG_L1_HDRC_MAR_TOP		   0x3300
+#define REG_L1_HDRC_MAR_LEFT		   0x3304
+#define REG_L1_CRGBF_ACC_CONF		   0x3700
+#define VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS  0
+#define VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0 1
+
+#define REG_L1_CRGBF_TRN_A_CONF		 0x370C
+#define VAL_L1_CRGBF_TRN_AUTO_READ_BANK0 BIT(16)
+
+#define REG_L1_CRGBF_INT_STAT	     0x3718
+#define REG_L1_CRGBF_INT_MASK	     0x371C
+#define REG_L1_CRGBF_INT_MASKED_STAT 0x3720
+#define REG_L1_CRGBF_TRN_RBADDR	     0x372C
+#define REG_L1_CRGBF_TRN_READDR	     0x3730
+#define REG_L1_CRGBF_ISP_INT_MASK    0x3738
+#define REG_L2_SENSOR_CROP_OFS_H     0x5000
+#define REG_L2_SENSOR_CROP_OFS_V     0x5004
+#define REG_L2_SENSOR_CROP_HSIZE     0x5008
+#define REG_L2_SENSOR_CROP_VSIZE     0x500C
+#define REG_L2_BUS_L2_STATUS	     0x5018
+#define REG_L2_ROI_NUM		     0x5040
+/* x: 0-1 */
+#define REG_L2_ROI_TO_POST(x)	       (0x5044 + 4 * (x))
+#define REG_L2_ROI_X_BASE(x)	       (0x5050 + 32 * (x))
+#define REG_L2_ROI_X_SCALE(x)	       (REG_L2_ROI_X_BASE(x) + 0)
+#define REG_L2_ROI_X_SCALE_INV(x)       (REG_L2_ROI_X_BASE(x) + 4)
+#define REG_L2_ROI_X_CORRECTED_HSIZE(x) (REG_L2_ROI_X_BASE(x) + 8)
+#define REG_L2_ROI_X_CORRECTED_VSIZE(x) (REG_L2_ROI_X_BASE(x) + 12)
+#define REG_L2_ROI_X_OUT_OFS_H(x)       (REG_L2_ROI_X_BASE(x) + 16)
+#define REG_L2_ROI_X_OUT_HSIZE(x)       (REG_L2_ROI_X_BASE(x) + 24)
+#define REG_L2_ROI_X_OUT_OFS_V(x)       (REG_L2_ROI_X_BASE(x) + 20)
+#define REG_L2_ROI_X_OUT_VSIZE(x)       (REG_L2_ROI_X_BASE(x) + 28)
+#define REG_L2_VALID_R_NORM2_POLY      0x50B0
+#define REG_L2_VALID_R_NORM2_GRID      0x50B4
+#define REG_L2_MODE		       0x5100
+#define REG_L2_NORM_SCALE	       0x5104
+#define REG_L2_ROI_WRITE_AREA_DELTA(x) (0x510C + 4 * (x))
+#define REG_L2_GRID_NODE_NUM_H	       0x5118
+#define REG_L2_GRID_NODE_NUM_V	       0x511C
+#define REG_L2_GRID_PATCH_HSIZE_INV    0x5120
+#define REG_L2_GRID_PATCH_VSIZE_INV    0x5124
+/* x: 0-10 */
+#define REG_L2_POLY10_WRITE_G_COEF(x) (0x5128 + 4 * (x))
+#define REG_L2_POLY10_READ_B_COEF(x)  (0x5154 + 4 * (x))
+#define REG_L2_POLY10_READ_G_COEF(x)  (0x5180 + 4 * (x))
+#define REG_L2_POLY10_READ_R_COEF(x)  (0x51AC + 4 * (x))
+/* x: 0-1 */
+#define REG_L2_POST_X_BASE(x)		   (0x5200 + 256 * (x))
+#define REG_L2_POST_X_CAP_OFFSET(x)	   (REG_L2_POST_X_BASE(x) + 0)
+#define REG_L2_POST_X_CAP_SIZE(x)	   (REG_L2_POST_X_BASE(x) + 4)
+#define REG_L2_POST_X_CSC_MTB_CB1(x)	   (REG_L2_POST_X_BASE(x) + 148)
+#define REG_L2_POST_X_CSC_MTB_CB2(x)	   (REG_L2_POST_X_BASE(x) + 152)
+#define REG_L2_POST_X_CSC_MTB_CB_OFFSETI(x) (REG_L2_POST_X_BASE(x) + 144)
+#define REG_L2_POST_X_CSC_MTB_CB_OFFSETO(x) (REG_L2_POST_X_BASE(x) + 156)
+#define REG_L2_POST_X_CSC_MTB_CR1(x)	   (REG_L2_POST_X_BASE(x) + 164)
+#define REG_L2_POST_X_CSC_MTB_CR2(x)	   (REG_L2_POST_X_BASE(x) + 168)
+#define REG_L2_POST_X_CSC_MTB_CR_OFFSETI(x) (REG_L2_POST_X_BASE(x) + 160)
+#define REG_L2_POST_X_CSC_MTB_CR_OFFSETO(x) (REG_L2_POST_X_BASE(x) + 172)
+#define REG_L2_POST_X_CSC_MTB(x)		   (REG_L2_POST_X_BASE(x) + 112)
+#define REG_L2_POST_X_CSC_MTB_YG1(x)	   (REG_L2_POST_X_BASE(x) + 132)
+#define REG_L2_POST_X_CSC_MTB_YG2(x)	   (REG_L2_POST_X_BASE(x) + 136)
+#define REG_L2_POST_X_CSC_MTB_YG_OFFSETI(x) (REG_L2_POST_X_BASE(x) + 128)
+#define REG_L2_POST_X_CSC_MTB_YG_OFFSETO(x) (REG_L2_POST_X_BASE(x) + 140)
+#define FIELD_CSC_MTB_UPPER(x)		   (FIELD_PREP(0xFFFF0000, (x)))
+#define FIELD_CSC_MTB_LOWER(x)		   (FIELD_PREP(0x0000FFFF, (x)))
+
+#define REG_L2_POST_X_C_SELECT(x)	 (REG_L2_POST_X_BASE(x) + 96)
+#define REG_L2_POST_X_GAMMA_M(x)		 (REG_L2_POST_X_BASE(x) + 80)
+#define REG_L2_POST_X_HALF_SCALE_EN(x)	 (REG_L2_POST_X_BASE(x) + 8)
+#define REG_L2_POST_X_OPORTALP(x)	 (REG_L2_POST_X_BASE(x) + 176)
+#define REG_L2_POST_X_OPORTFMT(x)	 (REG_L2_POST_X_BASE(x) + 180)
+#define REG_L2_POST_X_OUT_PITCH_B(x)	 (REG_L2_POST_X_BASE(x) + 196)
+#define REG_L2_POST_X_OUT_PITCH_G(x)	 (REG_L2_POST_X_BASE(x) + 200)
+#define REG_L2_POST_X_OUT_PITCH_R(x)	 (REG_L2_POST_X_BASE(x) + 204)
+#define REG_L2_POST_X_OUT_STADR_B(x)	 (REG_L2_POST_X_BASE(x) + 184)
+#define REG_L2_POST_X_OUT_STADR_G(x)	 (REG_L2_POST_X_BASE(x) + 188)
+#define REG_L2_POST_X_OUT_STADR_R(x)	 (REG_L2_POST_X_BASE(x) + 192)
+#define REG_L2_CRGBF_TRN_A_CONF		 0x570C
+#define VAL_L2_CRGBF_TRN_AUTO_READ_BANK0 BIT(16)
+
+#define REG_L2_CRGBF_INT_STAT		  0x5718
+#define REG_L2_CRGBF_INT_MASK		  0x571C
+#define REG_L2_CRGBF_INT_MASKED_STAT	  0x5720
+#define REG_L2_CRGBF_TRN_RBADDR		  0x572C
+#define REG_L2_CRGBF_TRN_READDR		  0x5730
+#define REG_L2_CRGBF_ISP_INT		  0x5734
+#define REG_L2_CRGBF_ISP_INT_MASK	  0x5738
+#define MASK_L2_CRGBF_ISP_INT_DONE	  BIT(0)
+#define MASK_L2_CRGBF_ISP_INT_ABORT_POST0 BIT(1)
+#define MASK_L2_CRGBF_ISP_INT_ABORT_POST1 BIT(2)
+#define MASK_L2_CRGBF_ISP_INT_ABORT_OTHER BIT(4)
+#define MASK_L2_STATUS_ERR_ALL                                                   \
+	(MASK_L2_CRGBF_ISP_INT_ABORT_POST0 | MASK_L2_CRGBF_ISP_INT_ABORT_POST1 | \
+	 MASK_L2_CRGBF_ISP_INT_ABORT_OTHER)
+
+/*=============================================*/
+/* HWA bus interface registers */
+/*=============================================*/
+#define REG_HWAIF_HWAIF_EN	  0
+#define REG_HWAIF_HWAIF_CONF	  0x10
+#define REG_HWAIF_OSTD_RLEN	  0x14
+#define REG_HWAIF_OSTD_WREQ	  0x18
+#define REG_HWAIF_REGION_ENTRY_EN 0xF0
+
+/*=============================================*/
+/* Memory Protection Unit registers */
+/*=============================================*/
+#define REG_MPU_MP_EN 0
+#define REG_MPU_MF_EN 0x3A4
+
+#endif /* VIIF_REGS_H */
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 5e80daa4f..4b2d77e18 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -203,6 +203,12 @@ enum v4l2_colorfx {
  */
 #define V4L2_CID_USER_ASPEED_BASE		(V4L2_CID_USER_BASE + 0x11a0)
 
+/*
+ * The base for Toshiba Visconti VIIF driver controls
+ * We reserve 32 controls for this driver
+ */
+#define V4L2_CID_USER_VISCONTI_BASE		(V4L2_CID_USER_BASE + 0x11b0)
+
 /* MPEG-class control IDs */
 /* The MPEG controls are applicable to all codec controls
  * and the 'MPEG' part of the define is historical */
diff --git a/include/uapi/linux/visconti_viif.h b/include/uapi/linux/visconti_viif.h
new file mode 100644
index 000000000..8e301b1f3
--- /dev/null
+++ b/include/uapi/linux/visconti_viif.h
@@ -0,0 +1,1800 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2022 TOSHIBA CORPORATION
+ * (C) Copyright 2022 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __UAPI_VISCONTI_VIIF_H_
+#define __UAPI_VISCONTI_VIIF_H_
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+/* Visconti specific compound controls */
+#define V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE	       (V4L2_CID_USER_VISCONTI_BASE + 1)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE	       (V4L2_CID_USER_VISCONTI_BASE + 2)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF	       (V4L2_CID_USER_VISCONTI_BASE + 3)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE	       (V4L2_CID_USER_VISCONTI_BASE + 4)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG		       (V4L2_CID_USER_VISCONTI_BASE + 5)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE		       (V4L2_CID_USER_VISCONTI_BASE + 6)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION       (V4L2_CID_USER_VISCONTI_BASE + 7)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC		       (V4L2_CID_USER_VISCONTI_BASE + 8)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE (V4L2_CID_USER_VISCONTI_BASE + 9)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION \
+	(V4L2_CID_USER_VISCONTI_BASE + 10)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS			 (V4L2_CID_USER_VISCONTI_BASE + 11)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION (V4L2_CID_USER_VISCONTI_BASE + 12)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC			 (V4L2_CID_USER_VISCONTI_BASE + 13)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS		 (V4L2_CID_USER_VISCONTI_BASE + 14)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB			 (V4L2_CID_USER_VISCONTI_BASE + 15)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_LOCK_AWB_GAIN		 (V4L2_CID_USER_VISCONTI_BASE + 16)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC			 (V4L2_CID_USER_VISCONTI_BASE + 17)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM		 (V4L2_CID_USER_VISCONTI_BASE + 18)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_GAMMA			 (V4L2_CID_USER_VISCONTI_BASE + 19)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT (V4L2_CID_USER_VISCONTI_BASE + 20)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION	 (V4L2_CID_USER_VISCONTI_BASE + 21)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST		 (V4L2_CID_USER_VISCONTI_BASE + 22)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI			 (V4L2_CID_USER_VISCONTI_BASE + 23)
+#define V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA			 (V4L2_CID_USER_VISCONTI_BASE + 24)
+#define V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_CALIBRATION_STATUS	 (V4L2_CID_USER_VISCONTI_BASE + 25)
+#define V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_ERR_STATUS		 (V4L2_CID_USER_VISCONTI_BASE + 26)
+#define V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS		 (V4L2_CID_USER_VISCONTI_BASE + 27)
+#define V4L2_CID_VISCONTI_VIIF_GET_REPORTED_ERRORS		 (V4L2_CID_USER_VISCONTI_BASE + 28)
+
+/* Enable/Disable flag */
+#define VIIF_DISABLE (0U)
+#define VIIF_ENABLE  (1U)
+
+/**
+ * enum viif_rawpack_mode - RAW pack mode for :ref:`V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE`
+ *
+ * @VIIF_RAWPACK_DISABLE: RAW pack disable
+ * @VIIF_RAWPACK_MSBFIRST: RAW pack enable (MSB First)
+ * @VIIF_RAWPACK_LSBFIRST: RAW pack enable (LSB First)
+ */
+enum viif_rawpack_mode {
+	VIIF_RAWPACK_DISABLE = 0,
+	VIIF_RAWPACK_MSBFIRST = 2,
+	VIIF_RAWPACK_LSBFIRST = 3,
+};
+
+/**
+ * enum viif_l1_input - L1ISP preprocessing mode,
+ * referred by :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE`
+ *
+ * @VIIF_L1_INPUT_HDR: bypass(HDR input)
+ * @VIIF_L1_INPUT_PWL: HDRE(PWL input)
+ * @VIIF_L1_INPUT_HDR_IMG_CORRECT: SLIC-ABPC-PWHB-RCNR-HDRS
+ * @VIIF_L1_INPUT_PWL_IMG_CORRECT: HDRE-SLIC-ABPC-PWHB-RCNR-HDRS
+ */
+enum viif_l1_input {
+	VIIF_L1_INPUT_HDR = 0,
+	VIIF_L1_INPUT_PWL = 1,
+	VIIF_L1_INPUT_HDR_IMG_CORRECT = 3,
+	VIIF_L1_INPUT_PWL_IMG_CORRECT = 4,
+};
+
+/**
+ * enum viif_l1_raw - L1ISP RAW color filter mode,
+ * referred by :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE`
+ *
+ * @VIIF_L1_RAW_GR_R_B_GB: Gr-R-B-Gb
+ * @VIIF_L1_RAW_R_GR_GB_B: R-Gr-Gb-B
+ * @VIIF_L1_RAW_B_GB_GR_R: B-Gb-Gr-R
+ * @VIIF_L1_RAW_GB_B_R_GR: Gb-B-R-Gr
+ */
+enum viif_l1_raw {
+	VIIF_L1_RAW_GR_R_B_GB = 0,
+	VIIF_L1_RAW_R_GR_GB_B = 1,
+	VIIF_L1_RAW_B_GB_GR_R = 2,
+	VIIF_L1_RAW_GB_B_R_GR = 3,
+};
+
+/**
+ * struct viif_l1_input_mode_config - L1ISP INPUT MODE parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE`
+ *
+ * @mode: &enum viif_l1_input value.
+ * @depth: Color depth (even only). Range for each L1ISP pre-processing mode is:
+ *
+ *  - VIIF_L1_INPUT_HDR, VIIF_L1_INPUT_HDR_IMG_CORRECT: Range: [8..24].
+ *  - VIIF_L1_INPUT_PWL, VIIF_L1_INPUT_PWL_IMG_CORRECT: Range: [8..14].
+ * @raw_color_filter: &enum viif_l1_raw value.
+ */
+struct viif_l1_input_mode_config {
+	__u32 mode;
+	__u32 depth;
+	__u32 raw_color_filter;
+};
+
+/**
+ * struct viif_l1_rgb_to_y_coef_config - L1ISP coefficient for calculating
+ * Y from RGB parameters for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF`
+ * @coef_r: R co-efficient. Range: [256..65024], Accuracy: 1/65536.
+ * @coef_g: G co-efficient. Range: [256..65024], Accuracy: 1/65536.
+ * @coef_b: B co-efficient. Range: [256..65024], Accuracy: 1/65536.
+ */
+struct viif_l1_rgb_to_y_coef_config {
+	__u16 coef_r;
+	__u16 coef_g;
+	__u16 coef_b;
+};
+
+/**
+ * enum viif_l1_img_sensitivity_mode - L1ISP image sensitivity
+ *
+ * @VIIF_L1_IMG_SENSITIVITY_HIGH: high sensitivity
+ * @VIIF_L1_IMG_SENSITIVITY_MIDDLE_LED: middle sensitivity or led
+ * @VIIF_L1_IMG_SENSITIVITY_LOW: low sensitivity
+ */
+enum viif_l1_img_sensitivity_mode {
+	VIIF_L1_IMG_SENSITIVITY_HIGH = 0,
+	VIIF_L1_IMG_SENSITIVITY_MIDDLE_LED = 1,
+	VIIF_L1_IMG_SENSITIVITY_LOW = 2,
+};
+
+/**
+ * struct viif_l1_ag_mode_config - L1ISP AG mode parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE`
+ * @sysm_ag_grad: Analog gain slope. Range: [0..255], Index corresponds to psel id.
+ * @sysm_ag_ofst: Analog gain offset. Range: [0..65535], Index corresponds to psel id.
+ * @sysm_ag_cont_hobc_en_high: set 1 to enable  control analog gain
+ *                             for high sensitivity image of OBCC
+ * @sysm_ag_psel_hobc_high: Analog gain id for high sensitivity image of OBCC. Range: [0..3]
+ * @sysm_ag_cont_hobc_en_middle_led: set 1 to enable control analog gain
+ *                                   for middle sensitivity or LED image of OBCC
+ * @sysm_ag_psel_hobc_middle_led: Analog gain id for middle sensitivity
+ *                                or LED image of OBCC. Range: [0..3]
+ * @sysm_ag_cont_hobc_en_low: set 1 to enable control analog gain
+ *                            for low sensitivity image of OBCC
+ * @sysm_ag_psel_hobc_low: Analog gain id for low sensitivity image of OBCC. Range:[0..3]
+ * @sysm_ag_cont_abpc_en_high: set 1 to enable control analog gain
+ *                             for high sensitivity image of ABPC
+ * @sysm_ag_psel_abpc_high: Analog gain id for high sensitivity image of ABPC. Range: [0..3]
+ * @sysm_ag_cont_abpc_en_middle_led: set 1 to enable control analog gain
+ *                                   for middle sensitivity or LED image of ABPC
+ * @sysm_ag_psel_abpc_middle_led: Analog gain id for middle sensitivity
+ *                                or LED image of ABPC. Range: [0..3]
+ * @sysm_ag_cont_abpc_en_low: set 1 to enable control analog gain
+ *                            for low sensitivity image of ABPC
+ * @sysm_ag_psel_abpc_low: Analog gain id for low sensitivity image of ABPC. Range: [0..3]
+ * @sysm_ag_cont_rcnr_en_high: set 1 to enable control analog gain
+ *                             for high sensitivity image of RCNR
+ * @sysm_ag_psel_rcnr_high: Analog gain id for high sensitivity image of RCNR. Range: [0..3]
+ * @sysm_ag_cont_rcnr_en_middle_led: set 1 to enable control analog gain
+ *                                   for middle sensitivity or LED image of RCNR
+ * @sysm_ag_psel_rcnr_middle_led: Analog gain id for middle sensitivity
+ *                                or LED image of RCNR. Range: [0..3]
+ * @sysm_ag_cont_rcnr_en_low: set 1 to enable control analog gain
+ *                            for low sensitivity image of RCNR
+ * @sysm_ag_psel_rcnr_low: Analog gain id for low sensitivity image of RCNR. Range: [0..3]
+ * @sysm_ag_cont_lssc_en: set 1 to enable control analog gain for LSC
+ * @sysm_ag_ssel_lssc: &enum viif_l1_img_sensitivity_mode value. Sensitive image used for LSC.
+ * @sysm_ag_psel_lssc: Analog gain id for LSC. Range: [0..3]
+ * @sysm_ag_cont_mpro_en: set 1 to enable control analog gain for color matrix
+ * @sysm_ag_ssel_mpro: &enum viif_l1_img_sensitivity_mode value.
+ *                     Sensitive image used for color matrix.
+ * @sysm_ag_psel_mpro: Analog gain id for color matrix. Range: [0..3]
+ * @sysm_ag_cont_vpro_en: set 1 to enable control analog gain for image adjustment
+ * @sysm_ag_ssel_vpro: &enum viif_l1_img_sensitivity_mode value.
+ *                     Sensitive image used for image adjustment.
+ * @sysm_ag_psel_vpro: Analog gain id for image adjustment. Range: [0..3]
+ * @sysm_ag_cont_hobc_test_high: Manual analog gain for high sensitivity image
+ *                               of OBCC. Range: [0..255]
+ * @sysm_ag_cont_hobc_test_middle_led: Manual analog gain for middle sensitivity
+ *                                     or led image of OBCC. Range: [0..255]
+ * @sysm_ag_cont_hobc_test_low: Manual analog gain for low sensitivity image
+ *                              of OBCC. Range: [0..255]
+ * @sysm_ag_cont_abpc_test_high: Manual analog gain for high sensitivity image
+ *                               of ABPC. Range: [0..255]
+ * @sysm_ag_cont_abpc_test_middle_led: Manual analog gain for middle sensitivity
+ *                                     or led image of ABPC. Range: [0..255]
+ * @sysm_ag_cont_abpc_test_low: Manual analog gain for low sensitivity image
+ *                              of ABPC. Range: [0..255]
+ * @sysm_ag_cont_rcnr_test_high: Manual analog gain for high sensitivity image
+ *                               of RCNR. Range:  [0..255]
+ * @sysm_ag_cont_rcnr_test_middle_led: Manual analog gain for middle sensitivity
+ *                                     or led image of RCNR. Range: [0..255]
+ * @sysm_ag_cont_rcnr_test_low: Manual analog gain for low sensitivity image
+ *                              of RCNR. Range:  [0..255]
+ * @sysm_ag_cont_lssc_test: Manual analog gain for LSSC. Range: [0..255]
+ * @sysm_ag_cont_mpro_test: Manual analog gain for color matrix. Range: [0..255]
+ * @sysm_ag_cont_vpro_test: Manual analog gain for image adjustment. Range: [0..255]
+ *
+ * Configuration of analog gain generation for each L1ISP module.
+ *
+ * If sysm_ag_cont_xxxx_en = 1, analog_gain for each module is generated from
+ * sysm_ag_grad, sysm_ag_ofst and the value specified at
+ * :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG`.
+ * If sysm_ag_cont_xxxx_en = 0,
+ * the value of sysm_ag_cont_xxxx_test is used for analog_gain for each module.
+ *
+ * Up to 4 sets of parameters (sysm_ag_grad[4] and sysm_ag_ofst[4]) can be used
+ * to generate analog gain.
+ * The parameter sysm_ag_psel_xxxx specifies the set to be used for module xxxx.
+ * For example, if sysm_ag_psel_hobc_high is set to 2,
+ * values in sysm_ag_grad[2] and sysm_ag_ofst[2] are used
+ * to generate analog gain for high sensitivity images in OBCC processing.
+ *
+ * Analog gain generation for each L1ISP module is disabled when
+ * "sysm_ag_cont_xxxx_en=0" and "sysm_ag_cont_xxxx_test=0".
+ * Be sure to disable the analog gain generation
+ * if VIIF_L1_INPUT_HDR or VIIF_L1_INPUT_PWL is set to
+ * :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE`.
+ *
+ */
+struct viif_l1_ag_mode_config {
+	__u8 sysm_ag_grad[4];
+	__u16 sysm_ag_ofst[4];
+	__u32 sysm_ag_cont_hobc_en_high;
+	__u32 sysm_ag_psel_hobc_high;
+	__u32 sysm_ag_cont_hobc_en_middle_led;
+	__u32 sysm_ag_psel_hobc_middle_led;
+	__u32 sysm_ag_cont_hobc_en_low;
+	__u32 sysm_ag_psel_hobc_low;
+	__u32 sysm_ag_cont_abpc_en_high;
+	__u32 sysm_ag_psel_abpc_high;
+	__u32 sysm_ag_cont_abpc_en_middle_led;
+	__u32 sysm_ag_psel_abpc_middle_led;
+	__u32 sysm_ag_cont_abpc_en_low;
+	__u32 sysm_ag_psel_abpc_low;
+	__u32 sysm_ag_cont_rcnr_en_high;
+	__u32 sysm_ag_psel_rcnr_high;
+	__u32 sysm_ag_cont_rcnr_en_middle_led;
+	__u32 sysm_ag_psel_rcnr_middle_led;
+	__u32 sysm_ag_cont_rcnr_en_low;
+	__u32 sysm_ag_psel_rcnr_low;
+	__u32 sysm_ag_cont_lssc_en;
+	__u32 sysm_ag_ssel_lssc;
+	__u32 sysm_ag_psel_lssc;
+	__u32 sysm_ag_cont_mpro_en;
+	__u32 sysm_ag_ssel_mpro;
+	__u32 sysm_ag_psel_mpro;
+	__u32 sysm_ag_cont_vpro_en;
+	__u32 sysm_ag_ssel_vpro;
+	__u32 sysm_ag_psel_vpro;
+	__u8 sysm_ag_cont_hobc_test_high;
+	__u8 sysm_ag_cont_hobc_test_middle_led;
+	__u8 sysm_ag_cont_hobc_test_low;
+	__u8 sysm_ag_cont_abpc_test_high;
+	__u8 sysm_ag_cont_abpc_test_middle_led;
+	__u8 sysm_ag_cont_abpc_test_low;
+	__u8 sysm_ag_cont_rcnr_test_high;
+	__u8 sysm_ag_cont_rcnr_test_middle_led;
+	__u8 sysm_ag_cont_rcnr_test_low;
+	__u8 sysm_ag_cont_lssc_test;
+	__u8 sysm_ag_cont_mpro_test;
+	__u8 sysm_ag_cont_vpro_test;
+};
+
+/**
+ * struct viif_l1_ag_config - L1ISP AG parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG`
+ * @gain_h: Analog gain for high sensitive image. Range: [0..65535].
+ * @gain_m: Analog gain for middle sensitive image or LED image. Range: [0..65535].
+ * @gain_l: Analog gain for low sensitive image. Range:  [0..65535].
+ */
+struct viif_l1_ag_config {
+	__u16 gain_h;
+	__u16 gain_m;
+	__u16 gain_l;
+};
+
+/**
+ * struct viif_l1_hdre_config - L1ISP HDRE parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE`
+ * @hdre_src_point: Knee point N value of PWL compressed signal. Range: [0..0x3FFF].
+ * @hdre_dst_base: Offset value of HDR signal in Knee area M. Range: [0..0xFFFFFF].
+ * @hdre_ratio: Slope of output pixel value in Knee area M.
+ *              Range: [0..0x3FFFFF], Accuracy: 1/64.
+ * @hdre_dst_max_val: Maximum value of output pixel. Range: [0..0xFFFFFF].
+ */
+struct viif_l1_hdre_config {
+	__u32 hdre_src_point[16];
+	__u32 hdre_dst_base[17];
+	__u32 hdre_ratio[17];
+	__u32 hdre_dst_max_val;
+};
+
+/**
+ * struct viif_l1_img_extraction_config -  L1ISP image extraction parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION`
+ * @input_black_gr: Black level of input pixel (Gr). Range: [0..0xFFFFFF].
+ * @input_black_r: Black level of input pixel (R). Range: [0..0xFFFFFF].
+ * @input_black_b: Black level of input pixel (B). Range: [0..0xFFFFFF].
+ * @input_black_gb: Black level of input pixel (Gb). Range: [0..0xFFFFFF].
+ */
+struct viif_l1_img_extraction_config {
+	__u32 input_black_gr;
+	__u32 input_black_r;
+	__u32 input_black_b;
+	__u32 input_black_gb;
+};
+
+/**
+ * enum viif_l1_dpc_mode - L1ISP defect pixel correction mode
+ * @VIIF_L1_DPC_1PIXEL: 1 pixel correction mode
+ * @VIIF_L1_DPC_2PIXEL: 2 pixel correction mode
+ */
+enum viif_l1_dpc_mode {
+	VIIF_L1_DPC_1PIXEL = 0,
+	VIIF_L1_DPC_2PIXEL = 1,
+};
+
+/**
+ * struct viif_l1_dpc - L1ISP defect pixel correction parameters
+ * for &struct viif_l1_dpc_config
+ * @abpc_sta_en: 1:enable/0:disable setting of Static DPC
+ * @abpc_dyn_en: 1:enable/0:disable setting of Dynamic DPC
+ * @abpc_dyn_mode: &enume viif_l1_dpc_mode value. Sets dynamic DPC mode.
+ * @abpc_ratio_limit: Variation adjustment of dynamic DPC. Range: [0..1023].
+ * @abpc_dark_limit: White defect judgment limit of dark area. Range: [0..1023].
+ * @abpc_sn_coef_w_ag_min: Luminance difference adjustment of white DPC
+ *                         (undere lower threshold).
+ * @abpc_sn_coef_w_ag_mid: Luminance difference adjustment of white DPC
+ *                         (between lower and upper threshold).
+ * @abpc_sn_coef_w_ag_max: Luminance difference adjustment of white DPC
+ *                         (over upper threshold).
+ * @abpc_sn_coef_b_ag_min: Luminance difference adjustment of black DPC
+ *                         (undere lower threshold).
+ * @abpc_sn_coef_b_ag_mid: Luminance difference adjustment of black DPC
+ *                         (between lower and upper threshold).
+ * @abpc_sn_coef_b_ag_max: Luminance difference adjustment of black DPC
+ *                         (over upper threshold).
+ * @abpc_sn_coef_w_th_min: Luminance difference adjustment of white DPC
+ *                         analog gain lower threshold.
+ * @abpc_sn_coef_w_th_max: Luminance difference adjustment of white DPC
+ *                         analog gain upper threshold.
+ * @abpc_sn_coef_b_th_min: Luminance difference adjustment of black DPC
+ *                         analog gain lower threshold.
+ * @abpc_sn_coef_b_th_max: Luminance difference adjustment of black DPC
+ *                         analog gain upper threshold.
+ *
+ * Range of abpc_sn_coef_{w,b}_ag_{min,mid,max} is:
+ *
+ * - Range: [1..31]
+ *
+ * Range and constraints of sn_coef_{w,b}_th_{min,max} are:
+ *
+ * - Range: [0..255]
+ * - Constraint: abpc_sn_coef_w_th_min < abpc_sn_coef_w_th_max
+ * - Constraint: abpc_sn_coef_b_th_min < abpc_sn_coef_b_th_max
+ */
+struct viif_l1_dpc {
+	__u32 abpc_sta_en;
+	__u32 abpc_dyn_en;
+	__u32 abpc_dyn_mode;
+	__u32 abpc_ratio_limit;
+	__u32 abpc_dark_limit;
+	__u32 abpc_sn_coef_w_ag_min;
+	__u32 abpc_sn_coef_w_ag_mid;
+	__u32 abpc_sn_coef_w_ag_max;
+	__u32 abpc_sn_coef_b_ag_min;
+	__u32 abpc_sn_coef_b_ag_mid;
+	__u32 abpc_sn_coef_b_ag_max;
+	__u8 abpc_sn_coef_w_th_min;
+	__u8 abpc_sn_coef_w_th_max;
+	__u8 abpc_sn_coef_b_th_min;
+	__u8 abpc_sn_coef_b_th_max;
+};
+
+/**
+ * struct viif_l1_dpc_config - L1ISP defect pixel correction parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC`
+ * @param_h: DPC parameter for high sensitive image. Refer to &struct viif_l1_dpc
+ * @param_m: DPC parameter for middle sensitive image. Refer to &struct viif_l1_dpc
+ * @param_l: DPC parameter for low sensitive image. Refer to &struct viif_l1_dpc
+ * @table_h: DPC table for high sensitive image.
+ *           The table is referred only when param_h.abpc_sta_en =1
+ * @table_m: DPC table for middle sensitive image or LED image.
+ *           The table is referred only when param_m.abpc_sta_en =1
+ * @table_l: DPC table for low sensitive image.
+ *           The table is referred only when param_l.abpc_sta_en =1
+ *
+ * The size of each table is 8192 Bytes (u32 * 2048)
+ * Application should make sure that the table data is based on HW specification
+ * since this driver does not check the DPC table.
+ */
+struct viif_l1_dpc_config {
+	struct viif_l1_dpc param_h;
+	struct viif_l1_dpc param_m;
+	struct viif_l1_dpc param_l;
+	__u32 table_h[2048];
+	__u32 table_m[2048];
+	__u32 table_l[2048];
+};
+
+/**
+ * struct viif_l1_preset_wb - L1ISP  preset white balance parameters
+ * for &struct viif_l1_preset_white_balance_config
+ * @gain_gr: Gr gain. Range: [0..524287], Accuracy 1/16384
+ * @gain_r: R gain. Range: [0..524287], Accuracy 1/16384
+ * @gain_b: B gain. Range: [0..524287], Accuracy 1/16384
+ * @gain_gb: Gb gain. Range: [0..524287], Accuracy 1/16384
+ */
+struct viif_l1_preset_wb {
+	__u32 gain_gr;
+	__u32 gain_r;
+	__u32 gain_b;
+	__u32 gain_gb;
+};
+
+/**
+ * struct viif_l1_preset_white_balance_config - L1ISP  preset white balance
+ * parameters for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE`
+ * @dstmaxval: Maximum value of output pixel. Range: [0..4095]
+ * @param_h: Preset white balance parameter for high sensitive image.
+ *           Refer to &struct viif_l1_preset_wb
+ * @param_m: Preset white balance parameters for middle sensitive image or LED image.
+ *           Refer to &struct viif_l1_preset_wb
+ * @param_l: Preset white balance parameters for low sensitive image.
+ *           Refer to &struct viif_l1_preset_wb
+ */
+struct viif_l1_preset_white_balance_config {
+	__u32 dstmaxval;
+	struct viif_l1_preset_wb param_h;
+	struct viif_l1_preset_wb param_m;
+	struct viif_l1_preset_wb param_l;
+};
+
+/**
+ * enum viif_l1_rcnr_type - L1ISP high resolution luminance filter type
+ *
+ * @VIIF_L1_RCNR_LOW_RESOLUTION: low resolution
+ * @VIIF_L1_RCNR_MIDDLE_RESOLUTION: middle resolution
+ * @VIIF_L1_RCNR_HIGH_RESOLUTION: high resolution
+ * @VIIF_L1_RCNR_ULTRA_HIGH_RESOLUTION: ultra high resolution
+ */
+enum viif_l1_rcnr_type {
+	VIIF_L1_RCNR_LOW_RESOLUTION = 0,
+	VIIF_L1_RCNR_MIDDLE_RESOLUTION = 1,
+	VIIF_L1_RCNR_HIGH_RESOLUTION = 2,
+	VIIF_L1_RCNR_ULTRA_HIGH_RESOLUTION = 3,
+};
+
+/**
+ * enum viif_l1_msf_blend_ratio - L1ISP MSF blend ratio
+ *
+ * @VIIF_L1_MSF_BLEND_RATIO_0_DIV_64: 0/64
+ * @VIIF_L1_MSF_BLEND_RATIO_1_DIV_64: 1/64
+ * @VIIF_L1_MSF_BLEND_RATIO_2_DIV_64: 2/64
+ */
+enum viif_l1_msf_blend_ratio {
+	VIIF_L1_MSF_BLEND_RATIO_0_DIV_64 = 0,
+	VIIF_L1_MSF_BLEND_RATIO_1_DIV_64 = 1,
+	VIIF_L1_MSF_BLEND_RATIO_2_DIV_64 = 2,
+};
+
+/**
+ * struct viif_l1_raw_color_noise_reduction - L1ISP RCNR parameters
+ * for &struct viif_l1_raw_color_noise_reduction_config
+ * @rcnr_sw: set 1 to enable RAW color noise reduction, 0 to disable.
+ * @rcnr_cnf_dark_ag0: Maximum value of LSF dark noise adjustment. Range: [0..63].
+ * @rcnr_cnf_dark_ag1: Middle value of LSF dark noise adjustment. Range: [0..63].
+ * @rcnr_cnf_dark_ag2: Minimum value of LSF dark noise adjustment. Range: [0..63].
+ * @rcnr_cnf_ratio_ag0: Maximum value of LSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_cnf_ratio_ag1: Middle value of LSF luminance interlocking noise adjustment:
+ *                      Range: [0..31].
+ * @rcnr_cnf_ratio_ag2: Minimum value of LSF luminance interlocking noise adjustment:
+ *                      Range: [0..31].
+ * @rcnr_cnf_clip_gain_r: LSF color correction limit adjustment gain R. Range: [0..3].
+ * @rcnr_cnf_clip_gain_g: LSF color correction limit adjustment gain G. Range: [0..3].
+ * @rcnr_cnf_clip_gain_b: LSF color correction limit adjustment gain B. Range: [0..3].
+ * @rcnr_a1l_dark_ag0: Maximum value of MSF dark noise adjustment. Range: [0..63].
+ * @rcnr_a1l_dark_ag1: Middle value of MSF dark noise adjustment. Range: [0..63].
+ * @rcnr_a1l_dark_ag2: Minimum value of MSF dark noise adjustment. Range: [0..63].
+ * @rcnr_a1l_ratio_ag0: Maximum value of MSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_a1l_ratio_ag1: Middle value of MSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_a1l_ratio_ag2: Minimum value of MSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_inf_zero_clip: Input stage zero clip setting. Range: [0..256].
+ * @rcnr_merge_d2blend_ag0: Maximum value of filter results and input blend ratio. Range: [0..16].
+ * @rcnr_merge_d2blend_ag1: Middle value of filter results and input blend ratio. Range: [0..16].
+ * @rcnr_merge_d2blend_ag2: Minimum value of filter results and input blend ratio. Range: [0..16].
+ * @rcnr_merge_black: Black level minimum value. Range: [0..64].
+ * @rcnr_merge_mindiv: 0 div guard value of inverse arithmetic unit. Range: [4..16].
+ * @rcnr_hry_type: &enum viif_l1_rcnr_type value. Filter type for HSF filter process.
+ * @rcnr_anf_blend_ag0: &enum viif_l1_msf_blend_ratio value.
+ *                      Maximum value of MSF result blend ratio in write back data to line memory.
+ * @rcnr_anf_blend_ag1: &enum viif_l1_msf_blend_ratio value.
+ *                      Middle value of MSF result blend ratio in write back data to line memory.
+ * @rcnr_anf_blend_ag2: &enum viif_l1_msf_blend_ratio value.
+ *                      Minimum value of MSF result blend ratio in write back data to line memory.
+ * @rcnr_lpf_threshold: Multiplier value for calculating dark noise / luminance
+ *                      interlock noise of MSF. Range: [0..31], Accuracy: 1/8.
+ * @rcnr_merge_hlblend_ag0: Maximum value of luminance signal generation blend. Range: [0..2].
+ * @rcnr_merge_hlblend_ag1: Middle value of luminance signal generation blend. Range: [0..2].
+ * @rcnr_merge_hlblend_ag2: Minimum value of luminance signal generation blend. Range: [0..2].
+ * @rcnr_gnr_sw: set 1 to enable Gr/Gb sensitivity ratio correction function switching,
+ *                0 to disable.
+ * @rcnr_gnr_ratio: Upper limit of Gr/Gb sensitivity ratio correction factor. Range: [0..15].
+ * @rcnr_gnr_wide_en: set 1 to double correction upper limit ratio of rcnr_gnr_ratio,
+ *                    0 to just use the specified ratio.
+ */
+struct viif_l1_raw_color_noise_reduction {
+	__u32 rcnr_sw;
+	__u32 rcnr_cnf_dark_ag0;
+	__u32 rcnr_cnf_dark_ag1;
+	__u32 rcnr_cnf_dark_ag2;
+	__u32 rcnr_cnf_ratio_ag0;
+	__u32 rcnr_cnf_ratio_ag1;
+	__u32 rcnr_cnf_ratio_ag2;
+	__u32 rcnr_cnf_clip_gain_r;
+	__u32 rcnr_cnf_clip_gain_g;
+	__u32 rcnr_cnf_clip_gain_b;
+	__u32 rcnr_a1l_dark_ag0;
+	__u32 rcnr_a1l_dark_ag1;
+	__u32 rcnr_a1l_dark_ag2;
+	__u32 rcnr_a1l_ratio_ag0;
+	__u32 rcnr_a1l_ratio_ag1;
+	__u32 rcnr_a1l_ratio_ag2;
+	__u32 rcnr_inf_zero_clip;
+	__u32 rcnr_merge_d2blend_ag0;
+	__u32 rcnr_merge_d2blend_ag1;
+	__u32 rcnr_merge_d2blend_ag2;
+	__u32 rcnr_merge_black;
+	__u32 rcnr_merge_mindiv;
+	__u32 rcnr_hry_type;
+	__u32 rcnr_anf_blend_ag0;
+	__u32 rcnr_anf_blend_ag1;
+	__u32 rcnr_anf_blend_ag2;
+	__u32 rcnr_lpf_threshold;
+	__u32 rcnr_merge_hlblend_ag0;
+	__u32 rcnr_merge_hlblend_ag1;
+	__u32 rcnr_merge_hlblend_ag2;
+	__u32 rcnr_gnr_sw;
+	__u32 rcnr_gnr_ratio;
+	__u32 rcnr_gnr_wide_en;
+};
+
+/**
+ * struct viif_l1_raw_color_noise_reduction_config - L1ISP RCNR parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION`
+ * @param_h: RAW color noise reduction parameter for high sensitive image.
+ *           Refer to &struct viif_l1_raw_color_noise_reduction
+ * @param_m: RAW color noise reduction parameter for middle sensitive image or LED image.
+ *           Refer to &struct viif_l1_raw_color_noise_reduction
+ * @param_l: RAW color noise reduction parameter for low sensitive image.
+ *           Refer to &struct viif_l1_raw_color_noise_reduction
+ */
+struct viif_l1_raw_color_noise_reduction_config {
+	struct viif_l1_raw_color_noise_reduction param_h;
+	struct viif_l1_raw_color_noise_reduction param_m;
+	struct viif_l1_raw_color_noise_reduction param_l;
+};
+
+/**
+ * enum viif_l1_hdrs_middle_img_mode - L1ISP HDR setting
+ *
+ * @VIIF_L1_HDRS_NOT_USE_MIDDLE_SENS_IMAGE: not use middle image
+ * @VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE: use middle image
+ */
+enum viif_l1_hdrs_middle_img_mode {
+	VIIF_L1_HDRS_NOT_USE_MIDDLE_SENS_IMAGE = 0,
+	VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE = 1,
+};
+
+/**
+ * struct viif_l1_hdrs_config - L1ISP HDRS parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS`
+ * @hdrs_hdr_mode: &enum viif_l1_hdrs_middle_img_mode value.
+ *                 Switch for use of middle sensitivity image in HDRS.
+ * @hdrs_hdr_ratio_m: Magnification ratio of middle sensitivity image for high
+ *                    sensitivity image.
+ * @hdrs_hdr_ratio_l: Magnification ratio of low sensitivity image for high
+ *                    sensitivity image.
+ * @hdrs_hdr_ratio_e: Magnification ratio of LED image for high sensitivity image.
+ * @hdrs_dg_h: High sensitivity image digital gain.
+ * @hdrs_dg_m: Middle sensitivity image digital gain.
+ * @hdrs_dg_l: Low sensitivity image digital gain.
+ * @hdrs_dg_e: LED image digital gain.
+ * @hdrs_blendend_h: Maximum luminance used for blend high sensitivity image.
+ * @hdrs_blendend_m: Maximum luminance used for blend middle sensitivity image.
+ * @hdrs_blendend_e: Maximum luminance used for blend LED image.
+ * @hdrs_blendbeg_h: Minimum luminance used for blend high sensitivity image.
+ * @hdrs_blendbeg_m: Minimum luminance used for blend middle sensitivity image.
+ * @hdrs_blendbeg_e: Minimum luminance used for blend LED image.
+ * @hdrs_led_mode_on: set 1 to enable LED mode, 0 to disable
+ * @hdrs_dst_max_val: Maximum value of output pixel. Range: [0..0xFFFFFF].
+ *
+ * Range and Accuracy of parameters are:
+ *
+ * - hdrs_hdr_ratio_{m,l,e}
+ *
+ *   - Range: [0x400..0x400000]
+ *   - Accuracy: 1/1024
+ *
+ * - hdrs_dg_{h,m,l,e}
+ *
+ *   - Range: [0..0x3FFFFF]
+ *   - Accuracy: 1/1024
+ *
+ * - hdrs_blend{end,beg}_{h,m,e}
+ *
+ *   - Range [0..4095]
+ *
+ * Parameter error will be returned when:
+ * (hdrs_hdr_mode == VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE) && (hdrs_led_mode_on == 1)
+ */
+struct viif_l1_hdrs_config {
+	__u32 hdrs_hdr_mode;
+	__u32 hdrs_hdr_ratio_m;
+	__u32 hdrs_hdr_ratio_l;
+	__u32 hdrs_hdr_ratio_e;
+	__u32 hdrs_dg_h;
+	__u32 hdrs_dg_m;
+	__u32 hdrs_dg_l;
+	__u32 hdrs_dg_e;
+	__u32 hdrs_blendend_h;
+	__u32 hdrs_blendend_m;
+	__u32 hdrs_blendend_e;
+	__u32 hdrs_blendbeg_h;
+	__u32 hdrs_blendbeg_m;
+	__u32 hdrs_blendbeg_e;
+	__u32 hdrs_led_mode_on;
+	__u32 hdrs_dst_max_val;
+};
+
+/**
+ * struct viif_l1_black_level_correction_config -  L1ISP image level conversion
+ * parameters for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION`
+ * @srcblacklevel_gr: Black level of Gr input pixel. Range: [0..0xFFFFFF].
+ * @srcblacklevel_r: Black level of R input pixel. Range: [0..0xFFFFFF].
+ * @srcblacklevel_b: Black level of B input pixel. Range: [0..0xFFFFFF].
+ * @srcblacklevel_gb: Black level of Gb input pixel. Range: [0..0xFFFFFF].
+ * @mulval_gr: Gr gain. Range: [0..0xFFFFF], Accuracy: 1/256.
+ * @mulval_r: R gain. Range: [0..0xFFFFF], Accuracy: 1/256.
+ * @mulval_b: B gain. Range: [0..0xFFFFF], Accuracy: 1/256.
+ * @mulval_gb: Gb gain. Range: [0..0xFFFFF], Accuracy: 1/256.
+ * @dstmaxval: Maximum value of output pixel. Range: [0..0xFFFFFF].
+ */
+struct viif_l1_black_level_correction_config {
+	__u32 srcblacklevel_gr;
+	__u32 srcblacklevel_r;
+	__u32 srcblacklevel_b;
+	__u32 srcblacklevel_gb;
+	__u32 mulval_gr;
+	__u32 mulval_r;
+	__u32 mulval_b;
+	__u32 mulval_gb;
+	__u32 dstmaxval;
+};
+
+/**
+ * enum viif_l1_para_coef_gain - L1ISP parabola shading correction coefficient ratio
+ *
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_EIGHTH: 1/8
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_FOURTH: 1/4
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_SECOND: 1/2
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_FIRST: 1/1
+ */
+enum viif_l1_para_coef_gain {
+	VIIF_L1_PARA_COEF_GAIN_ONE_EIGHTH = 0, /* 1/8 */
+	VIIF_L1_PARA_COEF_GAIN_ONE_FOURTH = 1, /* 1/4 */
+	VIIF_L1_PARA_COEF_GAIN_ONE_SECOND = 2, /* 1/2 */
+	VIIF_L1_PARA_COEF_GAIN_ONE_FIRST = 3, /* 1/1 */
+};
+
+/**
+ * enum viif_l1_grid_coef_gain - L1ISP grid shading correction coefficient ratio
+ *
+ * @VIIF_L1_GRID_COEF_GAIN_X1: x1
+ * @VIIF_L1_GRID_COEF_GAIN_X2: x2
+ */
+enum viif_l1_grid_coef_gain {
+	VIIF_L1_GRID_COEF_GAIN_X1 = 0,
+	VIIF_L1_GRID_COEF_GAIN_X2 = 1,
+};
+
+/**
+ * struct viif_l1_lsc_parabola_ag_param - L2ISP parabola shading parameters
+ * for &struct viif_l1_lsc_parabola_param
+ * @lssc_paracoef_h_l_max: Parabola coefficient left maximum gain value
+ * @lssc_paracoef_h_l_min: Parabola coefficient left minimum gain value
+ * @lssc_paracoef_h_r_max: Parabola coefficient right maximum gain value
+ * @lssc_paracoef_h_r_min: Parabola coefficient right minimum gain value
+ * @lssc_paracoef_v_u_max: Parabola coefficient upper maximum gain value
+ * @lssc_paracoef_v_u_min: Parabola coefficient upper minimum gain value
+ * @lssc_paracoef_v_d_max: Parabola coefficient lower maximum gain value
+ * @lssc_paracoef_v_d_min: Parabola coefficient lower minimum gain value
+ * @lssc_paracoef_hv_lu_max: Parabola coefficient upper left gain maximum value
+ * @lssc_paracoef_hv_lu_min: Parabola coefficient upper left gain minimum value
+ * @lssc_paracoef_hv_ru_max: Parabola coefficient upper right gain maximum value
+ * @lssc_paracoef_hv_ru_min: Parabola coefficient upper right minimum gain value
+ * @lssc_paracoef_hv_ld_max: Parabola coefficient lower left gain maximum value
+ * @lssc_paracoef_hv_ld_min: Parabola coefficient lower left gain minimum value
+ * @lssc_paracoef_hv_rd_max: Parabola coefficient lower right gain maximum value
+ * @lssc_paracoef_hv_rd_min: Parabola coefficient lower right minimum gain value
+ *
+ * The Range, Accuracy and Constraint of each coefficient are:
+ *
+ * - Range: [-4096..4095]
+ * - Accuracy: accuracy: 1/256
+ * - Constraint: lssc_paracoef_xx_xx_min <= lssc_paracoef_xx_xx_max
+ */
+struct viif_l1_lsc_parabola_ag_param {
+	__s16 lssc_paracoef_h_l_max;
+	__s16 lssc_paracoef_h_l_min;
+	__s16 lssc_paracoef_h_r_max;
+	__s16 lssc_paracoef_h_r_min;
+	__s16 lssc_paracoef_v_u_max;
+	__s16 lssc_paracoef_v_u_min;
+	__s16 lssc_paracoef_v_d_max;
+	__s16 lssc_paracoef_v_d_min;
+	__s16 lssc_paracoef_hv_lu_max;
+	__s16 lssc_paracoef_hv_lu_min;
+	__s16 lssc_paracoef_hv_ru_max;
+	__s16 lssc_paracoef_hv_ru_min;
+	__s16 lssc_paracoef_hv_ld_max;
+	__s16 lssc_paracoef_hv_ld_min;
+	__s16 lssc_paracoef_hv_rd_max;
+	__s16 lssc_paracoef_hv_rd_min;
+};
+
+/**
+ * struct viif_l1_lsc_parabola_param - L2ISP parabola shading parameters
+ * for &struct viif_l1_lsc
+ * @lssc_para_h_center: Horizontal coordinate of central optical axis.
+ *                      Range: [0..(Input image width - 1)].
+ * @lssc_para_v_center: Vertical coordinate of central optical axis.
+ *                      Range: [0..(Input image height - 1)].
+ * @lssc_para_h_gain: Horizontal distance gain with the optical axis.
+ *                    Range: [0..4095], Accuracy: 1/256.
+ * @lssc_para_v_gain: Vertical distance gain with the optical axis.
+ *                    Range: [0..4095], Accuracy: 1/256.
+ * @lssc_para_mgsel2: &enum viif_l1_para_coef_gain value.
+ *                    Parabola 2D correction coefficient gain magnification ratio.
+ * @lssc_para_mgsel4: &enum viif_l1_para_coef_gain value.
+ *                    Parabola 4D correction coefficient gain magnification ratio.
+ * @r_2d: 2D parabola coefficient for R.
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @r_4d: 4D parabola coefficient for R.
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gr_2d: 2D parabola coefficient for Gr
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gr_4d: 4D parabola coefficient for Gr
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gb_2d: 2D parabola coefficient for Gb
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gb_4d: 4D parabola coefficient for Gb
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @b_2d: 2D parabola coefficient for B
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @b_4d: 4D parabola coefficient for B
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ */
+struct viif_l1_lsc_parabola_param {
+	__u32 lssc_para_h_center;
+	__u32 lssc_para_v_center;
+	__u32 lssc_para_h_gain;
+	__u32 lssc_para_v_gain;
+	__u32 lssc_para_mgsel2;
+	__u32 lssc_para_mgsel4;
+	struct viif_l1_lsc_parabola_ag_param r_2d;
+	struct viif_l1_lsc_parabola_ag_param r_4d;
+	struct viif_l1_lsc_parabola_ag_param gr_2d;
+	struct viif_l1_lsc_parabola_ag_param gr_4d;
+	struct viif_l1_lsc_parabola_ag_param gb_2d;
+	struct viif_l1_lsc_parabola_ag_param gb_4d;
+	struct viif_l1_lsc_parabola_ag_param b_2d;
+	struct viif_l1_lsc_parabola_ag_param b_4d;
+};
+
+/**
+ * struct viif_l1_lsc_grid_param - L2ISP grid shading parameters
+ * for &struct viif_l1_lsc
+ * @lssc_grid_h_size:  Grid horizontal direction pixel count.
+ *                     Range: [32, 64, 128, 256, 512]
+ * @lssc_grid_v_size:  Grid vertical direction pixel count.
+ *                     Range: [32, 64, 128, 256, 512]
+ * @lssc_grid_h_center: Horizontal coordinates of grid (1, 1)
+ * @lssc_grid_v_center: Vertical coordinates of grid (1, 1)
+ * @lssc_grid_mgsel: &enum viif_l1_grid_coef_gain value.
+ *                   Grid correction coefficient gain value magnification ratio.
+ *
+ * Range and constraint of parameters are:
+ *
+ * - lssc_grid_h_center:
+ *
+ *    - Range: [1..lssc_grid_h_size]
+ *    - Constraint: "Input image width <= lssc_grid_h_center + lssc_grid_h_size * 31"
+ *
+ * - lssc_grid_v_center:
+ *
+ *    - Range: [1..lssc_grid_v_size]
+ *    - Constraint: "Input image height <= lssc_grid_v_center + lssc_grid_v_size * 23"
+ */
+struct viif_l1_lsc_grid_param {
+	__u32 lssc_grid_h_size;
+	__u32 lssc_grid_v_size;
+	__u32 lssc_grid_h_center;
+	__u32 lssc_grid_v_center;
+	__u32 lssc_grid_mgsel;
+};
+
+/**
+ * struct viif_l1_lsc - L2ISP LSC parameters for &struct viif_l1_lsc_config
+ * @lssc_parabola_param: see &struct viif_l1_lsc_parabola_param
+ * @lssc_grid_param: see &struct viif_l1_lsc_grid_param
+ * @lssc_pwhb_r_gain_max: PWB R correction processing coefficient maximum value
+ * @lssc_pwhb_r_gain_min: PWB R correction processing coefficient minimum value
+ * @lssc_pwhb_gr_gain_max: PWB Gr correction processing coefficient maximum value
+ * @lssc_pwhb_gr_gain_min: PWB Gr correction processing coefficient minimum value
+ * @lssc_pwhb_gb_gain_max: PWB Gb correction processing coefficient maximum value
+ * @lssc_pwhb_gb_gain_min: PWB Gb correction processing coefficient minimum value
+ * @lssc_pwhb_b_gain_max: PWB B correction processing coefficient maximum value
+ * @lssc_pwhb_b_gain_min: PWB B correction processing coefficient minimum value
+ *
+ * The range, accuracy and restriction of lssc_pwhb_{r,gr,gb,b}_gain_{max,min} are:
+ *
+ * - Range: [0..2047]
+ * - Accuracy: 1/256
+ * - Restriction: xxxx_gain_min <= xxxx_gain_max
+ */
+struct viif_l1_lsc {
+	struct viif_l1_lsc_parabola_param lssc_parabola_param;
+	struct viif_l1_lsc_grid_param lssc_grid_param;
+	__u32 lssc_pwhb_r_gain_max;
+	__u32 lssc_pwhb_r_gain_min;
+	__u32 lssc_pwhb_gr_gain_max;
+	__u32 lssc_pwhb_gr_gain_min;
+	__u32 lssc_pwhb_gb_gain_max;
+	__u32 lssc_pwhb_gb_gain_min;
+	__u32 lssc_pwhb_b_gain_max;
+	__u32 lssc_pwhb_b_gain_min;
+};
+
+/* MASKs for viif_l1_lsc_config::enable */
+#define VIIF_L1_LSC_PARABOLA_EN_MASK BIT(0)
+#define VIIF_L1_LSC_GRID_EN_MASK     BIT(1)
+
+/**
+ * struct viif_l1_lsc_config - L2ISP LSC parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC`
+ * @enable: set 0 to disable LSC operation,
+ *          1 to enable parabola shading,
+ *          2 to enable grid shading,
+ *          3 to enable both parabola and grid shadings.
+ * @param: see &struct viif_l1_lsc
+ * @table_gr: Grid table for LSC of Gr component.
+ *            This table is referred only when grid shading is used
+ * @table_r:  Grid table for LSC of R component.
+ *            This table is referred only when grid shading is used
+ * @table_b:  Grid table for LSC of B component.
+ *            This table is referred only when grid shading is used
+ * @table_gb: Grid table for LSC of Gb component.
+ *            This table is referred only when grid shading is used
+ *
+ * The size of each table is 1536 Bytes (u16 * 768).
+ * Application should make sure that the table data is based on HW specification
+ * since this driver does not check the grid table.
+ */
+struct viif_l1_lsc_config {
+	__u32 enable;
+	struct viif_l1_lsc param;
+	__u16 table_gr[768];
+	__u16 table_r[768];
+	__u16 table_b[768];
+	__u16 table_gb[768];
+};
+
+/**
+ * enum viif_l1_demosaic_mode - L1ISP demosaic modeenum viif_l1_demosaic_mode
+ *
+ * @VIIF_L1_DEMOSAIC_ACPI: Toshiba ACPI algorithm
+ * @VIIF_L1_DEMOSAIC_DMG: DMG algorithm
+ */
+enum viif_l1_demosaic_mode {
+	VIIF_L1_DEMOSAIC_ACPI = 0,
+	VIIF_L1_DEMOSAIC_DMG = 1,
+};
+
+/**
+ * struct viif_l1_color_matrix_correction - L1ISP color matrix correction
+ * parameters for &struct viif_l1_main_process_config
+ * @coef_rmg_min: (R-G) Minimum coefficient
+ * @coef_rmg_max: (R-G) Maximum coefficient
+ * @coef_rmb_min: (R-B) Minimum coefficient
+ * @coef_rmb_max: (R-B) Maximum coefficient
+ * @coef_gmr_min: (G-R) Minimum coefficient
+ * @coef_gmr_max: (G-R) Maximum coefficient
+ * @coef_gmb_min: (G-B) Minimum coefficient
+ * @coef_gmb_max: (G-B) Maximum coefficient
+ * @coef_bmr_min: (B-R) Minimum coefficient
+ * @coef_bmr_max: (B-R) Maximum coefficient
+ * @coef_bmg_min: (B-G) Minimum coefficient
+ * @coef_bmg_max: (B-G) Maximum coefficient
+ * @dst_minval: Minimum value of output pixel. Range: [0..0xFFFF].
+ *
+ * The range, accuracy and restriction of each coefficient are:
+ *
+ * - Range: [-32768..32767]
+ * - Accuracy: 1/4096
+ * - Restriction: coef_xxx_min <= coef_xxx_max
+ */
+struct viif_l1_color_matrix_correction {
+	__s16 coef_rmg_min;
+	__s16 coef_rmg_max;
+	__s16 coef_rmb_min;
+	__s16 coef_rmb_max;
+	__s16 coef_gmr_min;
+	__s16 coef_gmr_max;
+	__s16 coef_gmb_min;
+	__s16 coef_gmb_max;
+	__s16 coef_bmr_min;
+	__s16 coef_bmr_max;
+	__s16 coef_bmg_min;
+	__s16 coef_bmg_max;
+	__u16 dst_minval;
+};
+
+/**
+ * struct viif_l1_main_process_config - L1ISP Main process operating parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS`
+ * @demosaic_mode: &enum viif_l1_demosaic_mode value. Sets demosaic mode.
+ * @damp_lsbsel: Clipping range of output pixel value to AWB adjustment function. Range: [0..15].
+ * @colormat_enable: set 1 to enable color matrix correction, 0 to disable.
+ * @dst_maxval: Maximum value of output pixel. Range: [0..0xFFFFFF].
+ *              Applicable to output of each process (digital amplifier,
+ *              demosaicing and color matrix correction) in L1ISP Main process.
+ * @colormat_param: see &struct viif_l1_color_matrix_correction
+ */
+struct viif_l1_main_process_config {
+	__u32 demosaic_mode;
+	__u32 damp_lsbsel;
+	__u32 colormat_enable;
+	__u32 dst_maxval;
+	struct viif_l1_color_matrix_correction colormat_param;
+};
+
+/**
+ * enum viif_l1_awb_mag - L1ISP signal magnification before AWB adjustment
+ *
+ * @VIIF_L1_AWB_ONE_SECOND: x 1/2
+ * @VIIF_L1_AWB_X1: 1 times
+ * @VIIF_L1_AWB_X2: 2 times
+ * @VIIF_L1_AWB_X4: 4 times
+ */
+enum viif_l1_awb_mag {
+	VIIF_L1_AWB_ONE_SECOND = 0,
+	VIIF_L1_AWB_X1 = 1,
+	VIIF_L1_AWB_X2 = 2,
+	VIIF_L1_AWB_X4 = 3,
+};
+
+/**
+ * enum viif_l1_awb_area_mode - L1ISP AWB detection target area
+ *
+ * @VIIF_L1_AWB_AREA_MODE0: only center area
+ * @VIIF_L1_AWB_AREA_MODE1: center area when uv is in square gate
+ * @VIIF_L1_AWB_AREA_MODE2: all area except center area
+ * @VIIF_L1_AWB_AREA_MODE3: all area
+ */
+enum viif_l1_awb_area_mode {
+	VIIF_L1_AWB_AREA_MODE0 = 0,
+	VIIF_L1_AWB_AREA_MODE1 = 1,
+	VIIF_L1_AWB_AREA_MODE2 = 2,
+	VIIF_L1_AWB_AREA_MODE3 = 3,
+};
+
+/**
+ * enum viif_l1_awb_restart_cond - L1ISP AWB adjustment restart conditions
+ *
+ * @VIIF_L1_AWB_RESTART_NO: no restart
+ * @VIIF_L1_AWB_RESTART_128FRAME: restart after 128 frame
+ * @VIIF_L1_AWB_RESTART_64FRAME: restart after 64 frame
+ * @VIIF_L1_AWB_RESTART_32FRAME: restart after 32 frame
+ * @VIIF_L1_AWB_RESTART_16FRAME: restart after 16 frame
+ * @VIIF_L1_AWB_RESTART_8FRAME: restart after 8 frame
+ * @VIIF_L1_AWB_RESTART_4FRAME: restart after 4 frame
+ * @VIIF_L1_AWB_RESTART_2FRAME: restart after 2 frame
+ */
+enum viif_l1_awb_restart_cond {
+	VIIF_L1_AWB_RESTART_NO = 0,
+	VIIF_L1_AWB_RESTART_128FRAME = 1,
+	VIIF_L1_AWB_RESTART_64FRAME = 2,
+	VIIF_L1_AWB_RESTART_32FRAME = 3,
+	VIIF_L1_AWB_RESTART_16FRAME = 4,
+	VIIF_L1_AWB_RESTART_8FRAME = 5,
+	VIIF_L1_AWB_RESTART_4FRAME = 6,
+	VIIF_L1_AWB_RESTART_2FRAME = 7,
+};
+
+/**
+ * struct viif_l1_awb - L1ISP AWB adjustment parameters
+ * for &struct viif_l1_awb_config
+ * @awhb_ygate_sel: 1:Enable/0:Disable to fix Y value at YUV conversion
+ * @awhb_ygate_data: Y value when Y value is fixed. Range: [64, 128, 256, 512].
+ * @awhb_cgrange: &enum viif_l1_awb_mag value.
+ *                Signal output magnification ratio before AWB adjustment.
+ * @awhb_ygatesw: 1:Enable/0:Disable settings of luminance gate
+ * @awhb_hexsw: 1:Enable/0:Disable settings of hexa-gate
+ * @awhb_areamode: &enum viif_l1_awb_area_mode value.
+ *                 Final selection of accumulation area for detection target area.
+ * @awhb_area_hsize: Horizontal size per block in central area.
+ *                   Range: [1..(Input image width -8)/8].
+ * @awhb_area_vsize: Vertical size per block in central area.
+ *                   Range: [1..(Input image height -4)/8].
+ * @awhb_area_hofs: Horizontal offset of block [0] in central area.
+ *                  Range: [0..(Input image width -9)].
+ * @awhb_area_vofs: Vertical offset of block [0] in central area.
+ *                  Range: [0..(Input image height -5)].
+ * @awhb_area_maskh: Setting 1:Enable/0:Disable of accumulated selection.
+ *                   Each bit corresponds to the following:
+ *                   [31:0] = {
+ *                   (7, 3),(6, 3),(5, 3),(4, 3),(3, 3),(2, 3),(1, 3),(0, 3),
+ *                   (7, 2),(6, 2),(5, 2),(4, 2),(3, 2),(2, 2),(1, 2),(0, 2),
+ *                   (7, 1),(6, 1),(5, 1),(4, 1),(3, 1),(2, 1),(1, 1),(0, 1),
+ *                   (7, 0),(6, 0),(5, 0),(4, 0),(3, 0),(2, 0),(1, 0),(0, 0)}
+ * @awhb_area_maskl: Setting 1:Enable/0:Disable of accumulated selection.
+ *                   Each bit corresponds to the following:
+ *                   [31:0] = {
+ *                   (7, 7),(6, 7),(5, 7),(4, 7),(3, 7),(2, 7),(1, 7),(0, 7),
+ *                   (7, 6),(6, 6),(5, 6),(4, 6),(3, 6),(2, 6),(1, 6),(0, 6),
+ *                   (7, 5),(6, 5),(5, 5),(4, 5),(3, 5),(2, 5),(1, 5),(0, 5),
+ *                   (7, 4),(6, 4),(5, 4),(4, 4),(3, 4),(2, 4),(1, 4),(0, 4)}
+ * @awhb_sq_sw: 1:Enable/0:Disable each square gate
+ * @awhb_sq_pol: 1:Enable/0:Disable to add accumulated gate for each square gate
+ * @awhb_bycut0p: U upper end value. Range: [0..127].
+ * @awhb_bycut0n: U lower end value. Range: [0..127].
+ * @awhb_rycut0p: V upper end value. Range: [0..127].
+ * @awhb_rycut0n: V lower end value. Range: [0..127].
+ * @awhb_rbcut0h: V-axis intercept upper end. Range: [-127..127].
+ * @awhb_rbcut0l: V-axis intercept lower end. Range: [-127..127].
+ * @awhb_bycut_h: U direction center value of each square gate. Range:  [-127..127].
+ * @awhb_bycut_l: U direction width of each square gate. Range: [0..127].
+ * @awhb_rycut_h: V direction center value of each square gate. Range: [-127..127].
+ * @awhb_rycut_l: V direction width of each square gate. Range: [0..127].
+ * @awhb_awbsftu: U gain offset. Range: [-127..127].
+ * @awhb_awbsftv: V gain offset. Range: [-127..127].
+ * @awhb_awbhuecor: 1:Enable/0:Disable setting of color correlation retention function
+ * @awhb_awbspd: UV convergence speed multiplier. Range: [0..15] (0 means "stop").
+ * @awhb_awbulv: U convergence point level. Range: [0..31].
+ * @awhb_awbvlv: V convergence point level. Range: [0..31].
+ * @awhb_awbondot: Accumulation operation stop pixel count threshold. Range: [0..1023].
+ * @awhb_awbfztim: &enum viif_l1_awb_restart_cond value. Condition to restart AWB process.
+ * @awhb_wbgrmax: B gain adjustment range (Width from center to upper limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_wbgbmax: R gain adjustment range (Width from center to upper limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_wbgrmin: B gain adjustment range (Width from center to lower limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_wbgbmin: R gain adjustment range (Width from center to lower limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_ygateh: Luminance gate maximum value. Range: [0..255].
+ * @awhb_ygatel: Luminance gate minimum value. Range: [0..255].
+ * @awhb_awbwait: Number of restart frames after UV convergence freeze. Range: [0..255].
+ */
+struct viif_l1_awb {
+	__u32 awhb_ygate_sel;
+	__u32 awhb_ygate_data;
+	__u32 awhb_cgrange;
+	__u32 awhb_ygatesw;
+	__u32 awhb_hexsw;
+	__u32 awhb_areamode;
+	__u32 awhb_area_hsize;
+	__u32 awhb_area_vsize;
+	__u32 awhb_area_hofs;
+	__u32 awhb_area_vofs;
+	__u32 awhb_area_maskh;
+	__u32 awhb_area_maskl;
+	__u32 awhb_sq_sw[3];
+	__u32 awhb_sq_pol[3];
+	__u32 awhb_bycut0p;
+	__u32 awhb_bycut0n;
+	__u32 awhb_rycut0p;
+	__u32 awhb_rycut0n;
+	__s32 awhb_rbcut0h;
+	__s32 awhb_rbcut0l;
+	__s32 awhb_bycut_h[3];
+	__u32 awhb_bycut_l[3];
+	__s32 awhb_rycut_h[3];
+	__u32 awhb_rycut_l[3];
+	__s32 awhb_awbsftu;
+	__s32 awhb_awbsftv;
+	__u32 awhb_awbhuecor;
+	__u32 awhb_awbspd;
+	__u32 awhb_awbulv;
+	__u32 awhb_awbvlv;
+	__u32 awhb_awbondot;
+	__u32 awhb_awbfztim;
+	__u8 awhb_wbgrmax;
+	__u8 awhb_wbgbmax;
+	__u8 awhb_wbgrmin;
+	__u8 awhb_wbgbmin;
+	__u8 awhb_ygateh;
+	__u8 awhb_ygatel;
+	__u8 awhb_awbwait;
+};
+
+/**
+ * struct viif_l1_awb_config - L1ISP AWB parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB`
+ * @enable: set 1 to enable AWB , 0 to disable
+ * @awhb_wbmrg: White balance adjustment R gain. Range: [64..1023], Accuracy: 1/256.
+ * @awhb_wbmgg: White balance adjustment G gain. Range: [64..1023], Accuracy: 1/256.
+ * @awhb_wbmbg: White balance adjustment B gain. Range: [64..1023], Accuracy: 1/256.
+ * @param: a &struct viif_l1_awb instance
+ */
+struct viif_l1_awb_config {
+	__u32 enable;
+	__u32 awhb_wbmrg;
+	__u32 awhb_wbmgg;
+	__u32 awhb_wbmbg;
+	struct viif_l1_awb param;
+};
+
+/**
+ * enum viif_l1_hdrc_tone_type - L1ISP HDRC tone type
+ *
+ * @VIIF_L1_HDRC_TONE_USER: User Tone
+ * @VIIF_L1_HDRC_TONE_PRESET: Preset Tone
+ */
+enum viif_l1_hdrc_tone_type {
+	VIIF_L1_HDRC_TONE_USER = 0,
+	VIIF_L1_HDRC_TONE_PRESET = 1,
+};
+
+/**
+ * struct viif_l1_hdrc - L1ISP HDRC parameters for &struct viif_l1_hdrc_config
+ * @hdrc_ratio: Data width of input image. Range: [10..24] bits.
+ * @hdrc_pt_ratio: Preset Tone curve slope. Range: [0..13].
+ * @hdrc_pt_blend: Preset Tone0 curve blend ratio. Range: [0..256], Accuracy: 1/256.
+ * @hdrc_pt_blend2: Preset Tone2 curve blend ratio. Range: [0..256], Accuracy: 1/256.
+ * @hdrc_tn_type: &enum viif_l1_hdrc_tone_type value. L1ISP HDRC tone type.
+ * @hdrc_utn_tbl: HDRC value of User Tone curve. Range: [0..0xFFFF].
+ * @hdrc_flr_val: Constant flare value. Range: [0..0xFFFFFF].
+ * @hdrc_flr_adp: set 1 to enable dynamic flare measurement, 0 to disable.
+ * @hdrc_ybr_off: set 1 to turn OFF bilateral luminance filter, 0 to turn ON.
+ * @hdrc_orgy_blend: Blend settings of luminance correction data after HDRC
+ *                   and data before luminance correction. Range: [0..16]
+ *                   (0:Luminance correction 100%, 8:Luminance correction 50%,
+ *                   16:Luminance correction 0%).
+ * @hdrc_pt_sat: Preset Tone saturation value. Range: [0..0xFFFF].
+ *
+ * Restrictions for parameters
+ *
+ * - hdrc_pt_blend + hdrc_pt_blend2 <= 256
+ * - input_image_height % 64 != {18, 20, 22, 24, 26}
+ *
+ *   - only when dynamic flare control is enabled
+ *   - note that the driver will not return error if this condition is not satisfied.
+ *
+ * - hdrc_utn_tbl[N] <= hdrc_utn_tbl[N+1]
+ *
+ *   - note that the driver will not return error if this condition is not satisfied.
+ */
+struct viif_l1_hdrc {
+	__u32 hdrc_ratio;
+	__u32 hdrc_pt_ratio;
+	__u32 hdrc_pt_blend;
+	__u32 hdrc_pt_blend2;
+	__u32 hdrc_tn_type;
+	__u16 hdrc_utn_tbl[20];
+	__u32 hdrc_flr_val;
+	__u32 hdrc_flr_adp;
+	__u32 hdrc_ybr_off;
+	__u32 hdrc_orgy_blend;
+	__u16 hdrc_pt_sat;
+};
+
+/**
+ * struct viif_l1_hdrc_config - L1ISP HDRC parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC`
+ * @enable: set 1 to enable HDR compression, 0 to disable
+ * @hdrc_thr_sft_amt: Amount of right shift in through mode (HDRC disabled). Range: [0..8].
+ *                    Should be 0 if HDRC is enabled
+ * @param: HDR compression parameter; see &struct viif_l1_hdrc
+ */
+struct viif_l1_hdrc_config {
+	__u32 enable;
+	__u32 hdrc_thr_sft_amt;
+	struct viif_l1_hdrc param;
+};
+
+/**
+ * struct viif_l1_hdrc_ltm_config - L1ISP HDRC LTM parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM`
+ * @tnp_max: Tone blend rate maximum value of LTM function.
+ *           Range: [0..4194303], Accuracy: 1/64. Set 0 to turn off LTM function.
+ * @tnp_mag: Intensity adjustment of LTM function. Range: [0..16383], Accuracy: 1/64.
+ * @tnp_fil: Smoothing filter coefficient. Range: [0..255].
+ *
+ * Restriction: (tmp_fil[1] + tnp_fil[2] + tnp_fil[3] + tnp_fil[4]) * 2 + tnp_fil[0] = 1024
+ */
+struct viif_l1_hdrc_ltm_config {
+	__u32 tnp_max;
+	__u32 tnp_mag;
+	__u8 tnp_fil[5];
+};
+
+/**
+ * struct viif_l1_gamma - L1ISP gamma correction parameters
+ * for &struct viif_l1_gamma_config
+ * @gam_p: Luminance value after gamma correction. Range: [0..8191].
+ * @blkadj: Black level adjustment value after gamma correction. Range: [0..65535].
+ */
+struct viif_l1_gamma {
+	__u16 gam_p[44];
+	__u16 blkadj;
+};
+
+/**
+ * struct viif_l1_gamma_config - L1ISP gamma correction parameters
+ * @enable: set 1 to enable gamma correction at L1ISP, 0 to disable.
+ * @param: see &struct viif_l1_gamma.
+ */
+struct viif_l1_gamma_config {
+	__u32 enable;
+	struct viif_l1_gamma param;
+};
+
+/**
+ * struct viif_l1_nonlinear_contrast -  L1ISP non-linear contrast parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @blk_knee: Black side peak luminance value. Range: [0..0xFFFF].
+ * @wht_knee: White side peak luminance value. Range: [0..0xFFFF].
+ * @blk_cont: Black side slope
+ * @wht_cont: White side slope
+ *
+ * Range, Accuracy and Index for {blk,wht}_cont is:
+ *
+ * - Range: [0..255]
+ * - Accuracy: 1/256
+ *
+ * - Index
+ *
+ *   - 0: the value at AG minimum
+ *   - 1: the value at AG less than 128
+ *   - 2: the value at AG equal to or more than 128
+ */
+struct viif_l1_nonlinear_contrast {
+	__u16 blk_knee;
+	__u16 wht_knee;
+	__u8 blk_cont[3];
+	__u8 wht_cont[3];
+};
+
+/**
+ * struct viif_l1_lum_noise_reduction -  L1ISP luminance noise reduction
+ * parameters for &struct viif_l1_img_quality_adjustment_config
+ * @gain_min: Minimum value of extracted noise gain. Range: [0..0xFFFF], Accuracy: 1/256
+ * @gain_max: Maximum value of extracted noise gain. Range: [0..0xFFFF], Accuracy: 1/256
+ * @lim_min: Minimum value of extracted noise limit. Range: [0..0xFFFF]
+ * @lim_max: Maximum value of extracted noise limit. Range: [0..0xFFFF]
+ *
+ * Constraint: "gain_min <= gain_max" and "lim_min <= lim_max"
+ *
+ */
+struct viif_l1_lum_noise_reduction {
+	__u16 gain_min;
+	__u16 gain_max;
+	__u16 lim_min;
+	__u16 lim_max;
+};
+
+/**
+ * struct viif_l1_edge_enhancement -  L1ISP edge enhancement parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @gain_min: Extracted edge gain minimum value. Range: [0..0xFFFF], Accuracy: 1/256
+ * @gain_max: Extracted edge gain maximum value. Range: [0..0xFFFF], Accuracy: 1/256
+ * @lim_min: Extracted edge limit minimum value. Range: [0..0xFFFF]
+ * @lim_max: Extracted edge limit maximum value. Range: [0..0xFFFF]
+ * @coring_min: Extracted edge coring threshold minimum value. Range: [0..0xFFFF]
+ * @coring_max: Extracted edge coring threshold maximum value. Range: [0..0xFFFF]
+ *
+ * Constraint: "gain_min <= gain_max" and "lim_min <= lim_max" and "coring_min <= coring_max"
+ */
+struct viif_l1_edge_enhancement {
+	__u16 gain_min;
+	__u16 gain_max;
+	__u16 lim_min;
+	__u16 lim_max;
+	__u16 coring_min;
+	__u16 coring_max;
+};
+
+/**
+ * struct viif_l1_uv_suppression -  L1ISP UV suppression parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @bk_mp: Black side slope. Range: [0..0x3FFF], Accuracy: 1/16384
+ * @black: Minimum black side gain. Range: [0..0x3FFF], Accuracy: 1/16384
+ * @wh_mp: White side slope. Range: [0..0x3FFF], Accuracy: 1/16384
+ * @white: Minimum white side gain. Range: [0..0x3FFF], Accuracy: 1/16384
+ * @bk_slv: Black side intercept. Range: [0..0xFFFF]
+ * @wh_slv: White side intercept. Range: [0..0xFFFF]
+ *
+ * Constraint: bk_slb < wh_slv
+ */
+struct viif_l1_uv_suppression {
+	__u32 bk_mp;
+	__u32 black;
+	__u32 wh_mp;
+	__u32 white;
+	__u16 bk_slv;
+	__u16 wh_slv;
+};
+
+/**
+ * struct viif_l1_coring_suppression -  L1ISP coring suppression parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @lv_min: Minimum coring threshold. Range: [0..0xFFFF]
+ * @lv_max: Maximum coring threshold. Range: [0..0xFFFF]
+ * @gain_min: Minimum gain. Range: [0..0xFFFF], Accuracy: 1/65536
+ * @gain_max: Maximum gain. Range: [0..0xFFFF], Accuracy: 1/65536
+ *
+ * Constraint: "lv_min <= lv_max" and "gain_min <= gain_max"
+ */
+struct viif_l1_coring_suppression {
+	__u16 lv_min;
+	__u16 lv_max;
+	__u16 gain_min;
+	__u16 gain_max;
+};
+
+/**
+ * struct viif_l1_edge_suppression -  L1ISP edge suppression parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @gain: Gain of edge color suppression. Range: [0..0xFFFF], Accuracy: 1/256
+ * @lim: Limiter threshold of edge color suppression. Range: [0..15]
+ */
+struct viif_l1_edge_suppression {
+	__u16 gain;
+	__u32 lim;
+};
+
+/**
+ * struct viif_l1_color_level -  L1ISP color level parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @cb_gain: U component gain
+ * @cr_gain: V component gain
+ * @cbr_mgain_min: UV component gain
+ * @cbp_gain_max: Positive U component gain
+ * @cbm_gain_max: Negative V component gain
+ * @crp_gain_max: Positive U component gain
+ * @crm_gain_max: Negative V component gain
+ *
+ * Range and Accuracy of parameters are:
+ *
+ * - Range: [0..0xFFF]
+ * - Accuracy: 1/2048
+ */
+struct viif_l1_color_level {
+	__u32 cb_gain;
+	__u32 cr_gain;
+	__u32 cbr_mgain_min;
+	__u32 cbp_gain_max;
+	__u32 cbm_gain_max;
+	__u32 crp_gain_max;
+	__u32 crm_gain_max;
+};
+
+/* MASKs for viif_l1_img_quality_adjustment_config::enable */
+#define VIIF_L1_IQA_NONLINEAR_CONTRAST_EN_MASK	  BIT(0)
+#define VIIF_L1_IQA_LUM_NOISE_REDUCTION_EN_MASK	  BIT(1)
+#define VIIF_L1_IQA_EDGE_ENHANCEMENT_EN_MASK	  BIT(2)
+#define VIIF_L1_IQA_UV_SUPPRESSION_EN_MASK	  BIT(3)
+#define VIIF_L1_IQA_CORING_SUPPRESSION_EN_MASK	  BIT(4)
+#define VIIF_L1_IQA_EDGE_SUPPRESSION_EN_MASK	  BIT(5)
+#define VIIF_L1_IQA_COLOR_LEVEL_EN_MASK		  BIT(6)
+#define VIIF_L1_IQA_COLOR_NOISE_REDUCTION_EN_MASK BIT(7)
+
+/**
+ * struct viif_l1_img_quality_adjustment_config -  L1ISP image quality
+ * adjustment parameters for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT`
+ * @enable: | bit vector; set 1 to enable each function, 0 to disable.
+ *          | bit0: nonlinear_contrast
+ *          | bit1: lum_noise_reduction
+ *          | bit2: edge_enhancement
+ *          | bit3: uv_suppression
+ *          | bit4: coring_suppression
+ *          | bit5: edge_suppression
+ *          | bit6: color_level
+ *          | bit7: color_noise_reduction
+ * @coef_cb: Cb coefficient used in RGB to YUV conversion.
+ *           Range: [0..0xFFFF], Accuracy: 1/65536
+ * @coef_cr: Cr coefficient used in RGB to YUV conversion.
+ *           Range: [0..0xFFFF], Accuracy: 1/65536
+ * @brightness: Brightness adjustment value. Range: [-32768..32767] (0 to turn off)
+ * @linear_contrast: Linear contrast adjustment value.
+ *                   Range: [0..0xFF], Accuracy: 1/128 (128 to turn off)
+ * @nonlinear_contrast: see &struct viif_l1_nonlinear_contrast; controlled by bit0 of enable.
+ * @lum_noise_reduction: see &struct viif_l1_lum_noise_reduction; controlled by bit1 of enable.
+ * @edge_enhancement: see &struct viif_l1_edge_enhancement; controlled by bit2 of enable.
+ * @uv_suppression: see &struct viif_l1_uv_suppression: controlled by bit3 of enable.
+ * @coring_suppression: see &struct viif_l1_coring_suppression; controlled by bit4 of enable.
+ * @edge_suppression: see &struct viif_l1_edge_suppression; controlled by bit5 of enable.
+ * @color_level: see &struct viif_l1_color_level; controlled by bit6 of enable.
+ */
+struct viif_l1_img_quality_adjustment_config {
+	__u32 enable;
+	__u16 coef_cb;
+	__u16 coef_cr;
+	__s16 brightness;
+	__u8 linear_contrast;
+	struct viif_l1_nonlinear_contrast nonlinear_contrast;
+	struct viif_l1_lum_noise_reduction lum_noise_reduction;
+	struct viif_l1_edge_enhancement edge_enhancement;
+	struct viif_l1_uv_suppression uv_suppression;
+	struct viif_l1_coring_suppression coring_suppression;
+	struct viif_l1_edge_suppression edge_suppression;
+	struct viif_l1_color_level color_level;
+};
+
+/**
+ * struct viif_l1_avg_lum_generation_config - L1ISP average luminance generation configuration
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION`
+ * @enable: set 1 to enable aggregation of AVG LUM, 0 to disable
+ * @aexp_start_x: horizontal position of block 0. Range: [0.."width of input image - 1"]
+ * @aexp_start_y: vertical position of block 0. Range: [0.."height of input image - 1"]
+ * @aexp_block_width: width of one block.
+ *                    Range: [64.."width of input image"] (Should be multiple of 64)
+ * @aexp_block_height: height of one block.
+ *                     Range: [64.."height of input image"] (Should be multiple of 64)
+ * @aexp_weight: weight of each block. Range: [0..3].
+ *               Nested indices are: [y position][x position].
+ * @aexp_satur_ratio: threshold to judge whether saturated block or not. Range: [0..256]
+ * @aexp_black_ratio: threshold to judge whether black block or not. Range: [0..256]
+ * @aexp_satur_level: threshold to judge whether saturated pixel or not. Range: [0x0..0xffffff]
+ * @aexp_ave4linesy: vertical position of the initial line
+ *                   for 4-lines average luminance.
+ *                   Range: [0.."height of input image - 4"]
+ */
+struct viif_l1_avg_lum_generation_config {
+	__u32 enable;
+	__u32 aexp_start_x;
+	__u32 aexp_start_y;
+	__u32 aexp_block_width;
+	__u32 aexp_block_height;
+	__u32 aexp_weight[8][8];
+	__u32 aexp_satur_ratio;
+	__u32 aexp_black_ratio;
+	__u32 aexp_satur_level;
+	__u32 aexp_ave4linesy[4];
+};
+
+/**
+ * enum viif_l2_undist_mode - L2ISP undistortion mode
+ * @VIIF_L2_UNDIST_POLY: polynomial mode
+ * @VIIF_L2_UNDIST_GRID: grid table mode
+ * @VIIF_L2_UNDIST_POLY_TO_GRID: polynomial, then grid table mode
+ * @VIIF_L2_UNDIST_GRID_TO_POLY: grid table, then polynomial mode
+ */
+enum viif_l2_undist_mode {
+	VIIF_L2_UNDIST_POLY = 0,
+	VIIF_L2_UNDIST_GRID = 1,
+	VIIF_L2_UNDIST_POLY_TO_GRID = 2,
+	VIIF_L2_UNDIST_GRID_TO_POLY = 3,
+};
+
+/**
+ * struct viif_l2_undist - L2ISP UNDIST parameters
+ * for &struct viif_l2_undist_config
+ * @through_mode: 1:enable or 0:disable through mode of undistortion
+ * @roi_mode: &enum viif_l2_undist_mode value. Sets L2ISP undistortion mode.
+ * @sensor_crop_ofs_h: Horizontal start position of sensor crop area.
+ * @sensor_crop_ofs_v: Vertical start position of sensor crop area.
+ * @norm_scale: Normalization coefficient for distance from center
+ * @valid_r_norm2_poly: Setting target area for polynomial correction
+ * @valid_r_norm2_grid: Setting target area for grid table correction
+ * @roi_write_area_delta: Error adjustment value of forward function and
+ *                        inverse function for pixel position calculation
+ * @poly_write_g_coef: 10th-order polynomial coefficient for G write pixel position calculation
+ * @poly_read_b_coef: 10th-order polynomial coefficient for B read pixel position calculation
+ * @poly_read_g_coef: 10th-order polynomial coefficient for G read pixel position calculation
+ * @poly_read_r_coef: 10th-order polynomial coefficient for R read pixel position calculation
+ * @grid_node_num_h: Number of horizontal grids
+ * @grid_node_num_v: Number of vertical grids
+ * @grid_patch_hsize_inv: Inverse pixel size between horizontal grids
+ * @grid_patch_vsize_inv: Inverse pixel size between vertical grids
+ *
+ * Range and Accuracy of parameters are:
+ *
+ * - sensor_crop_ofs_{h,v}
+ *
+ *   - Range: [-4296..4296]
+ *   - Accuracy: 1/2
+ *
+ * - norm_scale
+ *
+ *   - Range: [0..1677721]
+ *   - Accuracy: 1/33554432
+ *
+ * - valid_r_norm2_{poly,grid}
+ *
+ *   - Range: [0..0x3FFFFFF]
+ *   - Accuracy: 1/33554432
+ *
+ * - roi_write_area_delta
+ *
+ *   - Range: [0..0x7FF]
+ *   - Accuracy: 1/1024
+ *
+ * - poly_write_g_coef, poly_read_{b,g,r}_coef
+ *
+ *   - Range: [-2147352576..2147352576]
+ *   - Accuracy: 1/131072
+ *
+ * - grid_node_num_{v.h}
+ *
+ *   - Range: [16..64]
+ *
+ * - grid_patch_{hsize,vsize}_inv
+ *
+ *   - Range: [0..0x7FFFFF]
+ *   - Accuracy: 1/8388608
+ */
+struct viif_l2_undist {
+	__u32 through_mode;
+	__u32 roi_mode[2];
+	__s32 sensor_crop_ofs_h;
+	__s32 sensor_crop_ofs_v;
+	__u32 norm_scale;
+	__u32 valid_r_norm2_poly;
+	__u32 valid_r_norm2_grid;
+	__u32 roi_write_area_delta[2];
+	__s32 poly_write_g_coef[11];
+	__s32 poly_read_b_coef[11];
+	__s32 poly_read_g_coef[11];
+	__s32 poly_read_r_coef[11];
+	__u32 grid_node_num_h;
+	__u32 grid_node_num_v;
+	__u32 grid_patch_hsize_inv;
+	__u32 grid_patch_vsize_inv;
+};
+
+/**
+ * struct viif_l2_undist_config - L2ISP UNDIST parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST`
+ * @param: &struct viif_l2_undist
+ * @write_g: write-G grid table.
+ * @read_b: read-B grid table.
+ * @read_g: read-G grid table.
+ * @read_r: read-R grid table.
+ * @size: Table size in bytes. Range: [1024..8192] or 0.
+ *        The value should be "grid_node_num_h * grid_node_num_v * 4".
+ *        See also &struct viif_l2_undist.
+ *
+ * The tables are referred when param.roi_mode[] is
+ * either of VIIF_L2_UNDIST_GRID, VIIF_L2_UNDIST_POLY_TO_GRID, VIIF_L2_UNDIST_GRID_TO_POLY
+ * Application should make sure that the table data is based on HW specification
+ * since this driver does not check the contents of specified grid table.
+ */
+struct viif_l2_undist_config {
+	struct viif_l2_undist param;
+	__u8 write_g[8192];
+	__u8 read_b[8192];
+	__u8 read_g[8192];
+	__u8 read_r[8192];
+	__u32 size;
+};
+
+/**
+ * struct viif_l2_roi_config - L2ISP ROI parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI`
+ * @roi_num:
+ *     1 when only capture path0 is activated,
+ *     2 when both capture path 0 and path 1 are activated.
+ * @roi_scale: Scale value for each ROI. Range: [32768..131072], Accuracy: 1/65536
+ * @roi_scale_inv: Inverse scale value for each ROI. Range: [32768..131072], Accuracy: 1/65536
+ * @corrected_wo_scale_hsize: Corrected image width for each ROI. Range: [128..8190]
+ * @corrected_wo_scale_vsize: Corrected image height for each ROI. Range: [128..4094]
+ * @corrected_hsize: Corrected and scaled image width for each ROI. Range: [128..8190]
+ * @corrected_vsize: Corrected and scaled image height for each ROI. Range: [128..4094]
+ */
+struct viif_l2_roi_config {
+	__u32 roi_num;
+	__u32 roi_scale[2];
+	__u32 roi_scale_inv[2];
+	__u32 corrected_wo_scale_hsize[2];
+	__u32 corrected_wo_scale_vsize[2];
+	__u32 corrected_hsize[2];
+	__u32 corrected_vsize[2];
+};
+
+/** enum viif_gamma_mode - Gamma correction mode
+ *
+ * @VIIF_GAMMA_COMPRESSED: compressed table mode
+ * @VIIF_GAMMA_LINEAR: linear table mode
+ */
+enum viif_gamma_mode {
+	VIIF_GAMMA_COMPRESSED = 0,
+	VIIF_GAMMA_LINEAR = 1,
+};
+
+/**
+ * struct viif_l2_gamma_config - L2ISP gamma correction parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA`
+ * @pathid: 0 for Capture Path 0, 1 for Capture Path 1.
+ * @table_en: 6bit vector to enable gamma table; all 0 to disable gamma correction
+ * @vsplit: Line switching position of first table and second table. Range: [0..4094].
+ *          Should set 0 in case 0 is set to @enable
+ * @mode: &enum viif_gamma_mode value.
+ *        Should set VIIF_GAMMA_COMPRESSED when 0 is set to @enable
+ * @table: gamma table for L2ISP gamma; 6 channels, each has __u16 typed 512 bytes.
+ *         [0]: G/Y(1st table), [1]: G/Y(2nd table), [2]: B/U(1st table)
+ *         [3]: B/U(2nd table), [4]: R/V(1st table), [5]: R/V(2nd table)
+ */
+struct viif_l2_gamma_config {
+	__u32 pathid;
+	__u32 table_en;
+	__u32 vsplit;
+	__u32 mode;
+	__u16 table[6][256];
+};
+
+/**
+ * struct viif_csi2rx_dphy_calibration_status - CSI2-RX D-PHY Calibration
+ * information for :ref:`V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_CALIBRATION_STATUS`
+ * @term_cal_with_rext: Result of termination calibration with rext
+ * @clock_lane_offset_cal: Result of offset calibration of clock lane
+ * @data_lane0_offset_cal: Result of offset calibration of data lane0
+ * @data_lane1_offset_cal: Result of offset calibration of data lane1
+ * @data_lane2_offset_cal: Result of offset calibration of data lane2
+ * @data_lane3_offset_cal: Result of offset calibration of data lane3
+ * @data_lane0_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane0
+ * @data_lane1_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane1
+ * @data_lane2_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane2
+ * @data_lane3_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane3
+ *
+ * Possible returned values for each member are:
+ *
+ * - -EAGAIN: calibration is not done
+ * - -EIO: calibration was failed
+ * - 0; calibration is succeeded
+ */
+struct viif_csi2rx_dphy_calibration_status {
+	__s32 term_cal_with_rext;
+	__s32 clock_lane_offset_cal;
+	__s32 data_lane0_offset_cal;
+	__s32 data_lane1_offset_cal;
+	__s32 data_lane2_offset_cal;
+	__s32 data_lane3_offset_cal;
+	__s32 data_lane0_ddl_tuning_cal;
+	__s32 data_lane1_ddl_tuning_cal;
+	__s32 data_lane2_ddl_tuning_cal;
+	__s32 data_lane3_ddl_tuning_cal;
+};
+
+/**
+ * struct viif_csi2rx_err_status - CSI2RX Error status parameters
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_ERR_STATUS`
+ * @err_phy_fatal: D-PHY FATAL error.
+ *
+ *  - bit[3]: Start of transmission error on DATA Lane3.
+ *  - bit[2]: Start of transmission error on DATA Lane2.
+ *  - bit[1]: Start of transmission error on DATA Lane1.
+ *  - bit[0]: Start of transmission error on DATA Lane0.
+ * @err_pkt_fatal: Packet FATAL error.
+ *
+ *  - bit[16]: Header ECC contains 2 errors, unrecoverable.
+ *  - bit[3]: Checksum error detected on virtual channel 3.
+ *  - bit[2]: Checksum error detected on virtual channel 2.
+ *  - bit[1]: Checksum error detected on virtual channel 1.
+ *  - bit[0]: Checksum error detected on virtual channel 0.
+ * @err_frame_fatal: Frame FATAL error.
+ *
+ *  - bit[19]: Last received Frame, in virtual channel 3, has at least one CRC error.
+ *  - bit[18]: Last received Frame, in virtual channel 2, has at least one CRC error.
+ *  - bit[17]: Last received Frame, in virtual channel 1, has at least one CRC error.
+ *  - bit[16]: Last received Frame, in virtual channel 0, has at least one CRC error.
+ *  - bit[11]: Incorrect Frame Sequence detected in virtual channel 3.
+ *  - bit[10]: Incorrect Frame Sequence detected in virtual channel 2.
+ *  - bit[9]: Incorrect Frame Sequence detected in virtual channel 1.
+ *  - bit[8]: Incorrect Frame Sequence detected in virtual channel 0.
+ *  - bit[3]: Error matching Frame Start with Frame End for virtual channel 3.
+ *  - bit[2]: Error matching Frame Start with Frame End for virtual channel 2.
+ *  - bit[1]: Error matching Frame Start with Frame End for virtual channel 1.
+ *  - bit[0]: Error matching Frame Start with Frame End for virtual channel 0.
+ * @err_phy: D-PHY error.
+ *
+ *  - bit[19]: Escape Entry Error on Data Lane 3.
+ *  - bit[18]: Escape Entry Error on Data Lane 2.
+ *  - bit[17]: Escape Entry Error on Data Lane 1.
+ *  - bit[16]: Escape Entry Error on Data Lane 0.
+ *  - bit[3]: Start of Transmission Error on Data Lane 3 (synchronization can still be achieved).
+ *  - bit[2]: Start of Transmission Error on Data Lane 2 (synchronization can still be achieved).
+ *  - bit[1]: Start of Transmission Error on Data Lane 1 (synchronization can still be achieved).
+ *  - bit[0]: Start of Transmission Error on Data Lane 0 (synchronization can still be achieved).
+ * @err_pkt: Packet error.
+ *
+ *  - bit[19]: Header Error detected and corrected on virtual channel 3.
+ *  - bit[18]: Header Error detected and corrected on virtual channel 2.
+ *  - bit[17]: Header Error detected and corrected on virtual channel 1.
+ *  - bit[16]: Header Error detected and corrected on virtual channel 0.
+ *  - bit[3]: Unrecognized or unimplemented data type detected in virtual channel 3.
+ *  - bit[2]: Unrecognized or unimplemented data type detected in virtual channel 2.
+ *  - bit[1]: Unrecognized or unimplemented data type detected in virtual channel 1.
+ *  - bit[0]: Unrecognized or unimplemented data type detected in virtual channel 0.
+ * @err_line: Line error.
+ *
+ *  - bit[23]: Error in the sequence of lines for vc7 and dt7.
+ *  - bit[22]: Error in the sequence of lines for vc6 and dt6.
+ *  - bit[21]: Error in the sequence of lines for vc5 and dt5.
+ *  - bit[20]: Error in the sequence of lines for vc4 and dt4.
+ *  - bit[19]: Error in the sequence of lines for vc3 and dt3.
+ *  - bit[18]: Error in the sequence of lines for vc2 and dt2.
+ *  - bit[17]: Error in the sequence of lines for vc1 and dt1.
+ *  - bit[16]: Error in the sequence of lines for vc0 and dt0.
+ *  - bit[7]: Error matching Line Start with Line End for vc7 and dt7.
+ *  - bit[6]: Error matching Line Start with Line End for vc6 and dt6.
+ *  - bit[5]: Error matching Line Start with Line End for vc5 and dt5.
+ *  - bit[4]: Error matching Line Start with Line End for vc4 and dt4.
+ *  - bit[3]: Error matching Line Start with Line End for vc3 and dt3.
+ *  - bit[2]: Error matching Line Start with Line End for vc2 and dt2.
+ *  - bit[1]: Error matching Line Start with Line End for vc1 and dt1.
+ *  - bit[0]: Error matching Line Start with Line End for vc0 and dt0.
+ */
+struct viif_csi2rx_err_status {
+	__u32 err_phy_fatal;
+	__u32 err_pkt_fatal;
+	__u32 err_frame_fatal;
+	__u32 err_phy;
+	__u32 err_pkt;
+	__u32 err_line;
+};
+
+/**
+ * struct viif_l1_info - L1ISP AWB information
+ * for &struct viif_isp_capture_status
+ * @avg_lum_weight: weighted average luminance value at average luminance generation
+ * @avg_lum_block: average luminance of each block.
+ *                 Nested indices are: [y position][x position].
+ * @avg_lum_four_line_lum: 4-lines average luminance.
+ *                         avg_lum_four_line_lum[n] corresponds to aexp_ave4linesy[n]
+ * @avg_satur_pixnum: the number of saturated pixel at average luminance generation
+ * @avg_black_pixnum: the number of black pixel at average luminance generation
+ * @awb_ave_u: U average value of AWB adjustment
+ * @awb_ave_v: V average value of AWB adjustment
+ * @awb_accumulated_pixel: Accumulated pixel count of AWB adjustment
+ * @awb_gain_r: R gain used in the next frame of AWB adjustment
+ * @awb_gain_g: G gain used in the next frame of AWB adjustment
+ * @awb_gain_b: B gain used in the next frame of AWB adjustment
+ * @awb_status_u: boolean value of U convergence state of AWB adjustment
+ *                (0: not-converged, 1: converged)
+ * @awb_status_v: boolean value of V convergence state of AWB adjustment
+ *                (0: not-converged, 1: converged)
+ */
+struct viif_l1_info {
+	__u32 avg_lum_weight;
+	__u32 avg_lum_block[8][8];
+	__u32 avg_lum_four_line_lum[4];
+	__u32 avg_satur_pixnum;
+	__u32 avg_black_pixnum;
+	__u32 awb_ave_u;
+	__u32 awb_ave_v;
+	__u32 awb_accumulated_pixel;
+	__u32 awb_gain_r;
+	__u32 awb_gain_g;
+	__u32 awb_gain_b;
+	__u8 awb_status_u;
+	__u8 awb_status_v;
+};
+
+/**
+ * struct viif_isp_capture_status - L1ISP capture information
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS`
+ * @l1_info: L1ISP AWB information. Refer to &struct viif_l1_info
+ */
+struct viif_isp_capture_status {
+	struct viif_l1_info l1_info;
+};
+
+/**
+ * struct viif_reported_errors - Errors since last call
+ * for :ref:`V4L2_CID_VISCONTI_VIIF_GET_REPORTED_ERRORS`
+ * @main: error flag value for capture device 0 and 1
+ * @sub: error flag value for capture device 2
+ * @csi2rx: error flag value for CSI2 receiver
+ */
+struct viif_reported_errors {
+	__u32 main;
+	__u32 sub;
+	__u32 csi2rx;
+};
+
+#endif /* __UAPI_VISCONTI_VIIF_H_ */
