Merge "msm: camera: isp: Add VFE HW driver support" into msm-4.9
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt
new file mode 100644
index 0000000..1c18228
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt
@@ -0,0 +1,109 @@
+* Qualcomm Technologies, Inc. MSM Camera VFE
+
+Camera VFE device provides the definitions for enabling
+the VFE hardware. It also provides the functions for the client
+to control the VFE hardware.
+
+=======================
+Required Node Structure
+=======================
+The VFE device is described in one level of the device node.
+
+======================================
+First Level Node - CAM VFE device
+======================================
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should specify the compatibility string for matching the
+    driver. e.g. "qcom,vfe170", "qcom,vfe-lite170".
+
+- cell-index
+  Usage: required
+  Value type: <u32>
+  Definition: Should specify the hardware index id.
+
+- reg-names
+  Usage: required
+  Value type: <string>
+  Definition: Should specify the name of the register block.
+
+- reg
+  Usage: required
+  Value type: <u32>
+  Definition: Register values.
+
+- interrupt-names
+  Usage: Required
+  Value type: <string>
+  Definition: Name of the interrupt.
+
+- interrupts
+  Usage: Required
+  Value type: <u32>
+  Definition: Interrupt associated with VFE HW.
+
+- regulator-names
+  Usage: required
+  Value type: <string>
+  Definition: Name of the regulator resources for VFE HW.
+
+- xxxx-supply
+  Usage: required
+  Value type: <phandle>
+  Definition: Regulator reference corresponding to the names listed in
+    "regulator-names".
+
+- clock-names
+  Usage: required
+  Value type: <string>
+  Definition: List of clock names required for VFE HW.
+
+- clocks
+  Usage: required
+  Value type: <phandle>
+  Definition: List of clocks used for VFE HW.
+
+- clock-rates
+  Usage: required
+  Value type: <u32>
+  Definition: List of clocks rates.
+
+- src-clock-name
+  Usage: required
+  Value type: <string>
+  Definition: Source clock name.
+
+Example:
+	qcom,vfe0@acaf000 {
+		cell-index = <0>;
+		compatible = "qcom,vfe170";
+		reg-names = "ife";
+		reg = <0xacaf000 0x4000>;
+		interrupts = <0 465 0>;
+		interrupt-names = "ife";
+		vdd-names = "camss-vdd", "ife0-vdd";
+		camss-vdd-supply = <&titan_top_gdsc>;
+		ife0-vdd-supply = <&ife_0_gdsc>;
+		clock-names = "soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"ife_csid_clk",
+			"ife_csid_clk_src",
+			"camnoc_axi_clk",
+			"ife_axi_clk",
+		clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_0_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_0_CSID_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_AXI_CLK>,
+		clock-rates = <0 0 80000000 0 320000000 0 384000000 0 0 0>;
+		src-clock-name = "ife_clk_src";
+		status = "ok";
+	};
diff --git a/drivers/media/platform/msm/camera/cam_isp/Makefile b/drivers/media/platform/msm/camera/cam_isp/Makefile
index b6e2d09..77ad6fc 100644
--- a/drivers/media/platform/msm/camera/cam_isp/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/Makefile
@@ -4,4 +4,5 @@
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
 
+obj-$(CONFIG_SPECTRA_CAMERA) += isp_hw_mgr/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_dev.o cam_isp_context.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
new file mode 100644
index 0000000..68a1a7d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile
new file mode 100644
index 0000000..076c2cf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/Makefile
@@ -0,0 +1,11 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_tasklet_util.o
+obj-$(CONFIG_SPECTRA_CAMERA) += irq_controller/
\ No newline at end of file
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c
new file mode 100644
index 0000000..ecc71b3
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c
@@ -0,0 +1,322 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/ratelimit.h>
+#include "cam_tasklet_util.h"
+#include "cam_irq_controller.h"
+
+#undef  CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define CAM_TASKLETQ_SIZE              256
+
+static void cam_tasklet_action(unsigned long data);
+
+/**
+ * struct cam_tasklet_queue_cmd:
+ * @Brief:                  Structure associated with each slot in the
+ *                          tasklet queue
+ *
+ * @list:                   list_head member for each entry in queue
+ * @payload:                Payload structure for the event. This will be
+ *                          passed to the handler function
+ * @bottom_half_handler:    Function pointer for event handler in bottom
+ *                          half context
+ *
+ */
+struct cam_tasklet_queue_cmd {
+	struct list_head                   list;
+	void                              *payload;
+	CAM_IRQ_HANDLER_BOTTOM_HALF        bottom_half_handler;
+};
+
+/**
+ * struct cam_tasklet_info:
+ * @Brief:                  Tasklet private structure
+ *
+ * @list:                   list_head member for each tasklet
+ * @index:                  Instance id for the tasklet
+ * @tasklet_lock:           Spin lock
+ * @tasklet_active:         Atomic variable to control tasklet state
+ * @tasklet:                Tasklet structure used to schedule bottom half
+ * @free_cmd_list:          List of free tasklet queue cmd for use
+ * @used_cmd_list:          List of used tasklet queue cmd
+ * @cmd_queue:              Array of tasklet cmd for storage
+ * @ctx_priv:               Private data passed to the handling function
+ *
+ */
+struct cam_tasklet_info {
+	struct list_head                   list;
+	uint32_t                           index;
+	spinlock_t                         tasklet_lock;
+	atomic_t                           tasklet_active;
+	struct tasklet_struct              tasklet;
+
+	struct list_head                   free_cmd_list;
+	struct list_head                   used_cmd_list;
+	struct cam_tasklet_queue_cmd       cmd_queue[CAM_TASKLETQ_SIZE];
+
+	void                              *ctx_priv;
+};
+
+/**
+ * cam_tasklet_get_cmd()
+ *
+ * @brief:              Get free cmd from tasklet
+ *
+ * @tasklet:            Tasklet Info structure to get cmd from
+ * @tasklet_cmd:        Return tasklet_cmd pointer if successful
+ *
+ * @return:             0: Success
+ *                      Negative: Failure
+ */
+static int cam_tasklet_get_cmd(
+	struct cam_tasklet_info        *tasklet,
+	struct cam_tasklet_queue_cmd  **tasklet_cmd)
+{
+	int           rc = 0;
+	unsigned long flags;
+
+	*tasklet_cmd = NULL;
+
+	if (!atomic_read(&tasklet->tasklet_active)) {
+		pr_err_ratelimited("Tasklet is not active!\n");
+		rc = -EPIPE;
+		return rc;
+	}
+
+	spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+	if (list_empty(&tasklet->free_cmd_list)) {
+		pr_err_ratelimited("No more free tasklet cmd!\n");
+		rc = -ENODEV;
+		goto spin_unlock;
+	} else {
+		*tasklet_cmd = list_first_entry(&tasklet->free_cmd_list,
+			struct cam_tasklet_queue_cmd, list);
+		list_del_init(&(*tasklet_cmd)->list);
+	}
+
+spin_unlock:
+	spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+	return rc;
+}
+
+/**
+ * cam_tasklet_put_cmd()
+ *
+ * @brief:              Put back cmd to free list
+ *
+ * @tasklet:            Tasklet Info structure to put cmd into
+ * @tasklet_cmd:        tasklet_cmd pointer that needs to be put back
+ *
+ * @return:             Void
+ */
+static void cam_tasklet_put_cmd(
+	struct cam_tasklet_info        *tasklet,
+	struct cam_tasklet_queue_cmd  **tasklet_cmd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+	list_add_tail(&(*tasklet_cmd)->list,
+		&tasklet->free_cmd_list);
+	spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+}
+
+/**
+ * cam_tasklet_dequeue_cmd()
+ *
+ * @brief:              Initialize the tasklet info structure
+ *
+ * @hw_mgr_ctx:         Private Ctx data that will be passed to the handler
+ *                      function
+ * @idx:                Index of tasklet used as identity
+ * @tasklet_action:     Tasklet callback function that will be called
+ *                      when tasklet runs on CPU
+ *
+ * @return:             0: Success
+ *                      Negative: Failure
+ */
+static int cam_tasklet_dequeue_cmd(
+	struct cam_tasklet_info        *tasklet,
+	struct cam_tasklet_queue_cmd  **tasklet_cmd)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	*tasklet_cmd = NULL;
+
+	if (!atomic_read(&tasklet->tasklet_active)) {
+		pr_err("Tasklet is not active!\n");
+		rc = -EPIPE;
+		return rc;
+	}
+
+	CDBG("Dequeue before lock.\n");
+	spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+	if (list_empty(&tasklet->used_cmd_list)) {
+		CDBG("End of list reached. Exit\n");
+		rc = -ENODEV;
+		goto spin_unlock;
+	} else {
+		*tasklet_cmd = list_first_entry(&tasklet->used_cmd_list,
+			struct cam_tasklet_queue_cmd, list);
+		list_del_init(&(*tasklet_cmd)->list);
+		CDBG("Dequeue Successful\n");
+	}
+
+spin_unlock:
+	spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+	return rc;
+}
+
+int cam_tasklet_enqueue_cmd(
+	void                              *bottom_half,
+	void                              *handler_priv,
+	void                              *evt_payload_priv,
+	CAM_IRQ_HANDLER_BOTTOM_HALF        bottom_half_handler)
+{
+	struct cam_tasklet_info       *tasklet = bottom_half;
+	struct cam_tasklet_queue_cmd  *tasklet_cmd = NULL;
+	unsigned long                  flags;
+	int                            rc;
+
+	if (!bottom_half) {
+		pr_err("NULL bottom half\n");
+		return -EINVAL;
+	}
+
+	rc = cam_tasklet_get_cmd(tasklet, &tasklet_cmd);
+
+	if (tasklet_cmd) {
+		CDBG("%s: Enqueue tasklet cmd\n", __func__);
+		tasklet_cmd->bottom_half_handler = bottom_half_handler;
+		tasklet_cmd->payload = evt_payload_priv;
+		spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+		list_add_tail(&tasklet_cmd->list,
+			&tasklet->used_cmd_list);
+		spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+		tasklet_schedule(&tasklet->tasklet);
+	} else {
+		pr_err("%s: tasklet cmd is NULL!\n", __func__);
+	}
+
+	return rc;
+}
+
+int cam_tasklet_init(
+	void                    **tasklet_info,
+	void                     *hw_mgr_ctx,
+	uint32_t                  idx)
+{
+	int i;
+	struct cam_tasklet_info  *tasklet = NULL;
+
+	tasklet = kzalloc(sizeof(struct cam_tasklet_info), GFP_KERNEL);
+	if (!tasklet) {
+		CDBG("Error! Unable to allocate memory for tasklet");
+		*tasklet_info = NULL;
+		return -ENOMEM;
+	}
+
+	tasklet->ctx_priv = hw_mgr_ctx;
+	tasklet->index = idx;
+	spin_lock_init(&tasklet->tasklet_lock);
+	memset(tasklet->cmd_queue, 0, sizeof(tasklet->cmd_queue));
+	INIT_LIST_HEAD(&tasklet->free_cmd_list);
+	INIT_LIST_HEAD(&tasklet->used_cmd_list);
+	for (i = 0; i < CAM_TASKLETQ_SIZE; i++) {
+		INIT_LIST_HEAD(&tasklet->cmd_queue[i].list);
+		list_add_tail(&tasklet->cmd_queue[i].list,
+			&tasklet->free_cmd_list);
+	}
+	tasklet_init(&tasklet->tasklet, cam_tasklet_action,
+		(unsigned long)tasklet);
+	cam_tasklet_stop(tasklet);
+
+	*tasklet_info = tasklet;
+
+	return 0;
+}
+
+void cam_tasklet_deinit(void    **tasklet_info)
+{
+	struct cam_tasklet_info *tasklet = *tasklet_info;
+
+	atomic_set(&tasklet->tasklet_active, 0);
+	tasklet_kill(&tasklet->tasklet);
+	kfree(tasklet);
+	*tasklet_info = NULL;
+}
+
+int cam_tasklet_start(void  *tasklet_info)
+{
+	struct cam_tasklet_info       *tasklet = tasklet_info;
+	struct cam_tasklet_queue_cmd  *tasklet_cmd;
+	struct cam_tasklet_queue_cmd  *tasklet_cmd_temp;
+
+	if (atomic_read(&tasklet->tasklet_active)) {
+		pr_err("Tasklet already active. idx = %d\n", tasklet->index);
+		return -EBUSY;
+	}
+	atomic_set(&tasklet->tasklet_active, 1);
+
+	/* flush the command queue first */
+	list_for_each_entry_safe(tasklet_cmd, tasklet_cmd_temp,
+		&tasklet->used_cmd_list, list) {
+		list_del_init(&tasklet_cmd->list);
+		list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list);
+	}
+
+	tasklet_enable(&tasklet->tasklet);
+
+	return 0;
+}
+
+void cam_tasklet_stop(void  *tasklet_info)
+{
+	struct cam_tasklet_info  *tasklet = tasklet_info;
+
+	atomic_set(&tasklet->tasklet_active, 0);
+	tasklet_disable(&tasklet->tasklet);
+}
+
+/*
+ * cam_tasklet_action()
+ *
+ * @brief:              Process function that will be called  when tasklet runs
+ *                      on CPU
+ *
+ * @data:               Tasklet Info structure that is passed in tasklet_init
+ *
+ * @return:             Void
+ */
+static void cam_tasklet_action(unsigned long data)
+{
+	struct cam_tasklet_info          *tasklet_info = NULL;
+	struct cam_tasklet_queue_cmd     *tasklet_cmd = NULL;
+
+	tasklet_info = (struct cam_tasklet_info *)data;
+
+	while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) {
+		tasklet_cmd->bottom_half_handler(tasklet_info->ctx_priv,
+			tasklet_cmd->payload);
+		cam_tasklet_put_cmd(tasklet_info, &tasklet_cmd);
+	}
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h
new file mode 100644
index 0000000..0e4bf12
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_TASKLET_UTIL_H_
+#define _CAM_TASKLET_UTIL_H_
+
+#include "cam_irq_controller.h"
+
+/*
+ * cam_tasklet_init()
+ *
+ * @brief:              Initialize the tasklet info structure
+ *
+ * @tasklet:            Tasklet to initialize
+ * @hw_mgr_ctx:         Private Ctx data that will be passed to the handler
+ *                      function
+ * @idx:                Index of tasklet used as identity
+ *
+ * @return:             0: Success
+ *                      Negative: Failure
+ */
+int cam_tasklet_init(
+	void                   **tasklet,
+	void                    *hw_mgr_ctx,
+	uint32_t                 idx);
+
+/*
+ * cam_tasklet_deinit()
+ *
+ * @brief:              Deinitialize the tasklet info structure
+ *
+ * @tasklet:            Tasklet to deinitialize
+ *
+ * @return:             Void
+ */
+void cam_tasklet_deinit(void   **tasklet);
+
+/*
+ * cam_tasklet_start()
+ *
+ * @brief:              Enable the tasklet to be scheduled and run.
+ *                      Caller should make sure this function is called
+ *                      before trying to enqueue.
+ *
+ * @tasklet:            Tasklet to start
+ *
+ * @return:             0: Success
+ *                      Negative: Failure
+ */
+int cam_tasklet_start(void    *tasklet);
+
+/*
+ * cam_tasklet_stop()
+ *
+ * @brief:              Disable the tasklet so it can no longer be scheduled.
+ *                      Need to enable again to run.
+ *
+ * @tasklet:            Tasklet to stop
+ *
+ * @return:             Void
+ */
+void cam_tasklet_stop(void    *tasklet);
+
+/*
+ * cam_tasklet_enqueue_cmd()
+ *
+ * @brief:               Enqueue the tasklet_cmd to used list
+ *
+ * @bottom_half:         Tasklet info to enqueue onto
+ * @handler_priv:        Private Handler data that will be passed to the
+ *                       handler function
+ * @evt_payload_priv:    Event payload that will be passed to the handler
+ *                       function
+ * @bottom_half_handler: Callback function that will be called by tasklet
+ *                       for handling event
+ *
+ * @return:              0: Success
+ *                       Negative: Failure
+ */
+int cam_tasklet_enqueue_cmd(
+	void                              *bottom_half,
+	void                              *handler_priv,
+	void                              *evt_payload_priv,
+	CAM_IRQ_HANDLER_BOTTOM_HALF        bottom_half_handler);
+
+#endif /* _CAM_TASKLET_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile
new file mode 100644
index 0000000..1fc0dd2
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_irq_controller.o
\ No newline at end of file
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
new file mode 100644
index 0000000..366ac8a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -0,0 +1,513 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include "cam_io_util.h"
+#include "cam_irq_controller.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+/**
+ * struct cam_irq_evt_handler:
+ * @Brief:                  Event handler information
+ *
+ * @priority:               Priority level of this event
+ * @evt_bit_mask_arr:       evt_bit_mask that has the bits set for IRQs to
+ *                          subscribe for
+ * @handler_priv:           Private data that will be passed to the Top/Bottom
+ *                          Half handler function
+ * @top_half_handler:       Top half Handler callback function
+ * @bottom_half_handler:    Bottom half Handler callback function
+ * @bottom_half:            Pointer to bottom_half implementation on which to
+ *                          enqueue the event for further handling
+ * @bottom_half_enqueue_func:
+ *                          Function used to enqueue the bottom_half event
+ * @list_node:              list_head struct used for overall handler List
+ * @th_list_node:           list_head struct used for top half handler List
+ */
+struct cam_irq_evt_handler {
+	enum cam_irq_priority_level        priority;
+	uint32_t                          *evt_bit_mask_arr;
+	void                              *handler_priv;
+	CAM_IRQ_HANDLER_TOP_HALF           top_half_handler;
+	CAM_IRQ_HANDLER_BOTTOM_HALF        bottom_half_handler;
+	void                              *bottom_half;
+	CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC   bottom_half_enqueue_func;
+	struct list_head                   list_node;
+	struct list_head                   th_list_node;
+	int                                index;
+};
+
+/**
+ * struct cam_irq_register_obj:
+ * @Brief:                  Structure containing information related to
+ *                          a particular register Set
+ *
+ * @index:                  Index of set in Array
+ * @mask_reg_offset:        Offset of IRQ MASK register
+ * @clear_reg_offset:       Offset of IRQ CLEAR register
+ * @status_reg_offset:      Offset of IRQ STATUS register
+ * @top_half_enable_mask:   Array of enabled bit_mask sorted by priority
+ */
+struct cam_irq_register_obj {
+	uint32_t                     index;
+	uint32_t                     mask_reg_offset;
+	uint32_t                     clear_reg_offset;
+	uint32_t                     status_reg_offset;
+	uint32_t                     top_half_enable_mask[CAM_IRQ_PRIORITY_MAX];
+};
+
+/**
+ * struct cam_irq_controller:
+ *
+ * @brief:                  IRQ Controller structure.
+ *
+ * @name:                   Name of IRQ Controller block
+ * @mem_base:               Mapped base address of register space to which
+ *                          register offsets are added to access registers
+ * @num_registers:          Number of sets(mask/clear/status) of IRQ registers
+ * @irq_register_arr:       Array of Register object associated with this
+ *                          Controller
+ * @irq_status_arr:         Array of IRQ Status values
+ * @global_clear_offset:    Offset of Global IRQ Clear register. This register
+ *                          contains the BIT that needs to be set for the CLEAR
+ *                          to take effect
+ * @global_clear_bitmask:   Bitmask needed to be used in Global Clear register
+ *                          for Clear IRQ cmd to take effect
+ * @evt_handler_list_head:  List of all event handlers
+ * @th_list_head:           List of handlers sorted by priority
+ * @hdl_idx:                Unique identity of handler assigned on Subscribe.
+ *                          Used to Unsubscribe.
+ * @rw_lock:                Read-Write Lock for use by controller
+ */
+struct cam_irq_controller {
+	const char                     *name;
+	void __iomem                   *mem_base;
+	uint32_t                        num_registers;
+	struct cam_irq_register_obj    *irq_register_arr;
+	uint32_t                       *irq_status_arr;
+	uint32_t                        global_clear_offset;
+	uint32_t                        global_clear_bitmask;
+	struct list_head                evt_handler_list_head;
+	struct list_head                th_list_head[CAM_IRQ_PRIORITY_MAX];
+	uint32_t                        hdl_idx;
+	rwlock_t                        rw_lock;
+};
+
+int cam_irq_controller_deinit(void **irq_controller)
+{
+	struct cam_irq_controller *controller = *irq_controller;
+	struct cam_irq_evt_handler *evt_handler = NULL;
+
+	while (!list_empty(&controller->evt_handler_list_head)) {
+		evt_handler = list_first_entry(
+			&controller->evt_handler_list_head,
+			struct cam_irq_evt_handler, list_node);
+		list_del_init(&evt_handler->list_node);
+		kfree(evt_handler);
+	}
+
+	kfree(controller->irq_register_arr);
+	kfree(controller->irq_status_arr);
+	kfree(controller);
+	*irq_controller = NULL;
+	return 0;
+}
+
+int cam_irq_controller_init(const char       *name,
+	void __iomem                         *mem_base,
+	struct cam_irq_controller_reg_info   *register_info,
+	void                                **irq_controller)
+{
+	struct cam_irq_controller *controller = NULL;
+	int i, rc = 0;
+
+	*irq_controller = NULL;
+
+	if (!register_info->num_registers || !register_info->irq_reg_set ||
+		!name || !mem_base) {
+		pr_err("Invalid parameters\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	controller = kzalloc(sizeof(struct cam_irq_controller), GFP_KERNEL);
+	if (!controller) {
+		CDBG("Failed to allocate IRQ Controller\n");
+		return -ENOMEM;
+	}
+
+	controller->irq_register_arr = kzalloc(register_info->num_registers *
+		sizeof(struct cam_irq_register_obj), GFP_KERNEL);
+	if (!controller->irq_register_arr) {
+		CDBG("Failed to allocate IRQ register Arr\n");
+		rc = -ENOMEM;
+		goto reg_alloc_error;
+	}
+
+	controller->irq_status_arr = kzalloc(register_info->num_registers *
+		sizeof(uint32_t), GFP_KERNEL);
+	if (!controller->irq_status_arr) {
+		CDBG("Failed to allocate IRQ status Arr\n");
+		rc = -ENOMEM;
+		goto status_alloc_error;
+	}
+	controller->name = name;
+
+	CDBG("num_registers: %d\n", register_info->num_registers);
+	for (i = 0; i < register_info->num_registers; i++) {
+		controller->irq_register_arr[i].index = i;
+		controller->irq_register_arr[i].mask_reg_offset =
+			register_info->irq_reg_set[i].mask_reg_offset;
+		controller->irq_register_arr[i].clear_reg_offset =
+			register_info->irq_reg_set[i].clear_reg_offset;
+		controller->irq_register_arr[i].status_reg_offset =
+			register_info->irq_reg_set[i].status_reg_offset;
+		CDBG("i %d mask_reg_offset: 0x%x\n", i,
+			controller->irq_register_arr[i].mask_reg_offset);
+		CDBG("i %d clear_reg_offset: 0x%x\n", i,
+			controller->irq_register_arr[i].clear_reg_offset);
+		CDBG("i %d status_reg_offset: 0x%x\n", i,
+			controller->irq_register_arr[i].status_reg_offset);
+	}
+	controller->num_registers        = register_info->num_registers;
+	controller->global_clear_bitmask = register_info->global_clear_bitmask;
+	controller->global_clear_offset  = register_info->global_clear_offset;
+	controller->mem_base             = mem_base;
+
+	CDBG("global_clear_bitmask: 0x%x\n",
+		controller->global_clear_bitmask);
+	CDBG("global_clear_offset: 0x%x\n",
+		controller->global_clear_offset);
+	CDBG("mem_base: 0x%llx\n", (uint64_t)controller->mem_base);
+
+	INIT_LIST_HEAD(&controller->evt_handler_list_head);
+	for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++)
+		INIT_LIST_HEAD(&controller->th_list_head[i]);
+
+	rwlock_init(&controller->rw_lock);
+
+	controller->hdl_idx = 1;
+	*irq_controller = controller;
+
+	return rc;
+
+status_alloc_error:
+	kfree(controller->irq_register_arr);
+reg_alloc_error:
+	kfree(controller);
+
+	return rc;
+}
+
+int cam_irq_controller_subscribe_irq(void *irq_controller,
+	enum cam_irq_priority_level        priority,
+	uint32_t                          *evt_bit_mask_arr,
+	void                              *handler_priv,
+	CAM_IRQ_HANDLER_TOP_HALF           top_half_handler,
+	CAM_IRQ_HANDLER_BOTTOM_HALF        bottom_half_handler,
+	void                              *bottom_half,
+	CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC   bottom_half_enqueue_func)
+{
+	struct cam_irq_controller  *controller  = irq_controller;
+	struct cam_irq_evt_handler *evt_handler = NULL;
+	int                         i;
+	int                         rc = 0;
+	uint32_t                    irq_mask;
+	unsigned long               flags;
+
+	if (!controller || !handler_priv || !evt_bit_mask_arr) {
+		pr_err("Invalid params: ctlr=%pK handler_priv=%pK bit_mask_arr = %pK\n",
+			controller, handler_priv, evt_bit_mask_arr);
+		return -EINVAL;
+	}
+
+	if (!top_half_handler) {
+		pr_err("Missing top half handler\n");
+		return -EINVAL;
+	}
+
+	if (bottom_half_handler &&
+		(!bottom_half || !bottom_half_enqueue_func)) {
+		pr_err("Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK\n",
+			bottom_half_handler,
+			bottom_half,
+			bottom_half_enqueue_func);
+		return -EINVAL;
+	}
+
+	if (priority >= CAM_IRQ_PRIORITY_MAX) {
+		pr_err("Invalid priority=%u, max=%u\n", priority,
+			CAM_IRQ_PRIORITY_MAX);
+		return -EINVAL;
+	}
+
+	if (sizeof(evt_bit_mask_arr) !=
+		sizeof(uint32_t) * controller->num_registers) {
+		pr_err("Invalid evt_mask size = %lu expected = %lu\n",
+			sizeof(evt_bit_mask_arr),
+			sizeof(uint32_t) * controller->num_registers);
+		return -EINVAL;
+	}
+
+	evt_handler = kzalloc(sizeof(struct cam_irq_evt_handler), GFP_KERNEL);
+	if (!evt_handler) {
+		CDBG("Error allocating hlist_node\n");
+		return -ENOMEM;
+	}
+
+	evt_handler->evt_bit_mask_arr = kzalloc(sizeof(uint32_t) *
+		controller->num_registers, GFP_KERNEL);
+	if (!evt_handler->evt_bit_mask_arr) {
+		CDBG("Error allocating hlist_node\n");
+		rc = -ENOMEM;
+		goto free_evt_handler;
+	}
+
+	INIT_LIST_HEAD(&evt_handler->list_node);
+	INIT_LIST_HEAD(&evt_handler->th_list_node);
+
+	for (i = 0; i < controller->num_registers; i++)
+		evt_handler->evt_bit_mask_arr[i] = evt_bit_mask_arr[i];
+
+	evt_handler->priority                 = priority;
+	evt_handler->handler_priv             = handler_priv;
+	evt_handler->top_half_handler         = top_half_handler;
+	evt_handler->bottom_half_handler      = bottom_half_handler;
+	evt_handler->bottom_half              = bottom_half;
+	evt_handler->bottom_half_enqueue_func = bottom_half_enqueue_func;
+	evt_handler->index                    = controller->hdl_idx++;
+	if (controller->hdl_idx > 0x3FFFFFFF)
+		controller->hdl_idx = 1;
+
+	write_lock_irqsave(&controller->rw_lock, flags);
+	for (i = 0; i < controller->num_registers; i++) {
+		controller->irq_register_arr[i].top_half_enable_mask[priority]
+			|= evt_bit_mask_arr[i];
+
+		irq_mask = cam_io_r_mb(controller->mem_base +
+			controller->irq_register_arr[i].mask_reg_offset);
+		irq_mask |= evt_bit_mask_arr[i];
+
+		cam_io_w_mb(irq_mask, controller->mem_base +
+			controller->irq_register_arr[i].mask_reg_offset);
+	}
+	write_unlock_irqrestore(&controller->rw_lock, flags);
+
+	list_add_tail(&evt_handler->list_node,
+		&controller->evt_handler_list_head);
+	list_add_tail(&evt_handler->th_list_node,
+		&controller->th_list_head[priority]);
+
+	return evt_handler->index;
+
+free_evt_handler:
+	kfree(evt_handler);
+	evt_handler = NULL;
+
+	return rc;
+}
+
+int cam_irq_controller_unsubscribe_irq(void *irq_controller,
+	uint32_t handle)
+{
+	struct cam_irq_controller  *controller  = irq_controller;
+	struct cam_irq_evt_handler *evt_handler = NULL;
+	struct cam_irq_evt_handler *evt_handler_temp;
+	uint32_t                    i;
+	uint32_t                    found = 0;
+	uint32_t                    irq_mask;
+	unsigned long               flags;
+	int                         rc = -EINVAL;
+
+	list_for_each_entry_safe(evt_handler, evt_handler_temp,
+		&controller->evt_handler_list_head, list_node) {
+		if (evt_handler->index == handle) {
+			CDBG("unsubscribe item %d\n", handle);
+			list_del_init(&evt_handler->list_node);
+			list_del_init(&evt_handler->th_list_node);
+			found = 1;
+			rc = 0;
+			break;
+		}
+	}
+
+	if (found) {
+		write_lock_irqsave(&controller->rw_lock, flags);
+		for (i = 0; i < controller->num_registers; i++) {
+			controller->irq_register_arr[i].
+				top_half_enable_mask[evt_handler->priority] &=
+				~(evt_handler->evt_bit_mask_arr[i]);
+
+			irq_mask = cam_io_r_mb(controller->mem_base +
+				controller->irq_register_arr[i].
+				mask_reg_offset);
+			irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]);
+
+			cam_io_w_mb(irq_mask, controller->mem_base +
+				controller->irq_register_arr[i].
+				mask_reg_offset);
+
+			/* Clear the IRQ bits of this handler */
+			cam_io_w_mb(evt_handler->evt_bit_mask_arr[i],
+				controller->mem_base +
+				controller->irq_register_arr[i].
+				clear_reg_offset);
+			if (controller->global_clear_offset)
+				cam_io_w_mb(
+					controller->global_clear_bitmask,
+					controller->mem_base +
+					controller->global_clear_offset);
+		}
+		write_unlock_irqrestore(&controller->rw_lock, flags);
+
+		kfree(evt_handler->evt_bit_mask_arr);
+		kfree(evt_handler);
+	}
+
+	return rc;
+}
+
+/**
+ * cam_irq_controller_match_bit_mask()
+ *
+ * @Brief:                This function checks if any of the enabled IRQ bits
+ *                        for a certain handler is Set in the Status values
+ *                        of the controller.
+ *
+ * @controller:           IRQ Controller structure
+ * @evt_handler:          Event handler structure
+ *
+ * @Return:               True: If any interested IRQ Bit is Set
+ *                        False: Otherwise
+ */
+static bool cam_irq_controller_match_bit_mask(
+	struct cam_irq_controller   *controller,
+	struct cam_irq_evt_handler  *evt_handler)
+{
+	int i;
+
+	for (i = 0; i < controller->num_registers; i++) {
+		if (evt_handler->evt_bit_mask_arr[i] &
+			controller->irq_status_arr[i])
+			return true;
+	}
+
+	return false;
+}
+
+static void cam_irq_controller_th_processing(
+	struct cam_irq_controller      *controller,
+	struct list_head               *th_list_head)
+{
+	struct cam_irq_evt_handler     *evt_handler = NULL;
+	struct cam_irq_th_payload       th_payload;
+	bool                            is_irq_match;
+	int                             rc = -EINVAL;
+
+	CDBG("Enter\n");
+
+	if (list_empty(th_list_head))
+		return;
+
+	list_for_each_entry(evt_handler, th_list_head, th_list_node) {
+		is_irq_match = cam_irq_controller_match_bit_mask(controller,
+			evt_handler);
+
+		if (!is_irq_match)
+			continue;
+
+		CDBG("match found\n");
+
+		cam_irq_th_payload_init(&th_payload);
+		th_payload.handler_priv   = evt_handler->handler_priv;
+		th_payload.num_registers  = controller->num_registers;
+		th_payload.evt_status_arr = controller->irq_status_arr;
+
+		/*
+		 * irq_status_arr[0] is dummy argument passed. the entire
+		 * status array is passed in th_payload.
+		 */
+		if (evt_handler->top_half_handler)
+			rc = evt_handler->top_half_handler(
+				controller->irq_status_arr[0],
+				(void *)&th_payload);
+
+
+		if (!rc && evt_handler->bottom_half_handler) {
+			CDBG("Enqueuing bottom half\n");
+			if (evt_handler->bottom_half_enqueue_func) {
+				evt_handler->bottom_half_enqueue_func(
+					evt_handler->bottom_half,
+					evt_handler->handler_priv,
+					th_payload.evt_payload_priv,
+					evt_handler->bottom_half_handler);
+			}
+		}
+	}
+
+	CDBG("Exit\n");
+}
+
+irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
+{
+	struct cam_irq_controller      *controller  = priv;
+	int i, j;
+	bool need_th_processing[CAM_IRQ_PRIORITY_MAX] = {false};
+
+	if (!controller)
+		return IRQ_NONE;
+
+	read_lock(&controller->rw_lock);
+	for (i = 0; i < controller->num_registers; i++) {
+		controller->irq_status_arr[i] = cam_io_r_mb(
+			controller->mem_base +
+			controller->irq_register_arr[i].status_reg_offset);
+		cam_io_w_mb(controller->irq_status_arr[i],
+			controller->mem_base +
+			controller->irq_register_arr[i].clear_reg_offset);
+		CDBG("Read irq status%d = 0x%x\n", i,
+			controller->irq_status_arr[i]);
+		for (j = 0; j < CAM_IRQ_PRIORITY_MAX; j++) {
+			if (controller->irq_register_arr[i].
+				top_half_enable_mask[j] &
+				controller->irq_status_arr[i])
+				need_th_processing[j] = true;
+				CDBG("i %d j %d need_th_processing = %d\n",
+					i, j, need_th_processing[j]);
+		}
+	}
+	read_unlock(&controller->rw_lock);
+
+	CDBG("Status Registers read Successful\n");
+
+	if (controller->global_clear_offset)
+		cam_io_w_mb(controller->global_clear_bitmask,
+			controller->mem_base + controller->global_clear_offset);
+
+	CDBG("Status Clear done\n");
+
+	for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) {
+		if (need_th_processing[i]) {
+			CDBG("%s: Invoke TH processing\n", __func__);
+			cam_irq_controller_th_processing(controller,
+				&controller->th_list_head[i]);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
new file mode 100644
index 0000000..2f88a8b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
@@ -0,0 +1,218 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_IRQ_CONTROLLER_H_
+#define _CAM_IRQ_CONTROLLER_H_
+
+#include <linux/interrupt.h>
+
+#define CAM_IRQ_BITS_PER_REGISTER      32
+
+/*
+ * enum cam_irq_priority_level:
+ * @Brief:                  Priority levels for IRQ events.
+ *                          Priority_0 events will be serviced before
+ *                          Priority_1 if they these bits are set in the same
+ *                          Status Read. And so on upto Priority_4.
+ *
+ *                          Default Priority is Priority_4.
+ */
+enum cam_irq_priority_level {
+	CAM_IRQ_PRIORITY_0,
+	CAM_IRQ_PRIORITY_1,
+	CAM_IRQ_PRIORITY_2,
+	CAM_IRQ_PRIORITY_3,
+	CAM_IRQ_PRIORITY_4,
+	CAM_IRQ_PRIORITY_MAX,
+};
+
+/*
+ * struct cam_irq_register_set:
+ * @Brief:                  Structure containing offsets of IRQ related
+ *                          registers belonging to a Set
+ *
+ * @mask_reg_offset:        Offset of IRQ MASK register
+ * @clear_reg_offset:       Offset of IRQ CLEAR register
+ * @status_reg_offset:      Offset of IRQ STATUS register
+ */
+struct cam_irq_register_set {
+	uint32_t                       mask_reg_offset;
+	uint32_t                       clear_reg_offset;
+	uint32_t                       status_reg_offset;
+};
+
+/*
+ * struct cam_irq_controller_reg_info:
+ * @Brief:                  Structure describing the IRQ registers
+ *
+ * @num_registers:          Number of sets(mask/clear/status) of IRQ registers
+ * @irq_reg_set:            Array of Register Set Offsets.
+ *                          Length of array = num_registers
+ * @global_clear_offset:    Offset of Global IRQ Clear register. This register
+ *                          contains the BIT that needs to be set for the CLEAR
+ *                          to take effect
+ * @global_clear_bitmask:   Bitmask needed to be used in Global Clear register
+ *                          for Clear IRQ cmd to take effect
+ */
+struct cam_irq_controller_reg_info {
+	uint32_t                      num_registers;
+	struct cam_irq_register_set  *irq_reg_set;
+	uint32_t                      global_clear_offset;
+	uint32_t                      global_clear_bitmask;
+};
+
+/*
+ * struct cam_irq_th_payload:
+ * @Brief:                  Event payload structure. This structure will be
+ *                          passed to the Top Half handler functions.
+ *
+ * @handler_priv:           Private Data of handling object set when
+ *                          subscribing to IRQ event.
+ * @num_registers:          Length of evt_bit_mask Array below
+ * @evt_status_arr:         Array of Status bitmask read from registers.
+ *                          Length of array = num_registers
+ * @evt_payload_priv:       Private payload pointer which can be set by Top
+ *                          Half handler for use in Bottom Half.
+ */
+struct cam_irq_th_payload {
+	void       *handler_priv;
+	uint32_t    num_registers;
+	uint32_t   *evt_status_arr;
+	void       *evt_payload_priv;
+};
+
+/*
+ * cam_irq_th_payload_init()
+ *
+ * @brief:              Initialize the top half payload structure
+ *
+ * @th_payload:         Top Half payload structure to Initialize
+ *
+ * @return:             Void
+ */
+static inline void cam_irq_th_payload_init(
+	struct cam_irq_th_payload *th_payload) {
+	th_payload->handler_priv = NULL;
+	th_payload->evt_payload_priv = NULL;
+	th_payload->evt_status_arr = NULL;
+}
+
+typedef int (*CAM_IRQ_HANDLER_TOP_HALF)(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload);
+
+typedef int (*CAM_IRQ_HANDLER_BOTTOM_HALF)(void *handler_priv,
+	void *evt_payload_priv);
+
+typedef int (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half,
+	void *handler_priv, void *evt_payload_priv,
+	CAM_IRQ_HANDLER_BOTTOM_HALF);
+
+/*
+ * cam_irq_controller_init()
+ *
+ * @brief:              Create and Initialize IRQ Controller.
+ *
+ * @name:               Name of IRQ Controller block
+ * @mem_base:           Mapped base address of register space to which
+ *                      register offsets are added to access registers
+ * @register_info:      Register Info structure associated with this Controller
+ * @irq_controller:     Pointer to IRQ Controller that will be filled if
+ *                      initialization is successful
+ *
+ * @return:             0: Success
+ *                      Negative: Failure
+ */
+int cam_irq_controller_init(const char       *name,
+	void __iomem                         *mem_base,
+	struct cam_irq_controller_reg_info   *register_info,
+	void                                **irq_controller);
+
+/*
+ * cam_irq_controller_subscribe_irq()
+ *
+ * @brief:               Subscribe to certain IRQ events.
+ *
+ * @irq_controller:      Pointer to IRQ Controller that controls this event IRQ
+ * @priority:            Priority level of these events used if multiple events
+ *                       are SET in the Status Register
+ * @evt_bit_mask_arr:    evt_bit_mask that has the bits set for IRQs to
+ *                       subscribe for
+ * @handler_priv:        Private data that will be passed to the Top/Bottom Half
+ *                       handler function
+ * @top_half_handler:    Top half Handler callback function
+ * @bottom_half_handler: Bottom half Handler callback function
+ * @bottom_half:         Pointer to bottom_half implementation on which to
+ *                       enqueue the event for further handling
+ * @bottom_half_enqueue_func:
+ *                       Function used to enqueue the bottom_half event
+ *
+ * @return:              Positive: Success. Value represents handle which is
+ *                                 to be used to unsubscribe
+ *                       Negative: Failure
+ */
+int cam_irq_controller_subscribe_irq(void *irq_controller,
+	enum cam_irq_priority_level        priority,
+	uint32_t                          *evt_bit_mask_arr,
+	void                              *handler_priv,
+	CAM_IRQ_HANDLER_TOP_HALF           top_half_handler,
+	CAM_IRQ_HANDLER_BOTTOM_HALF        bottom_half_handler,
+	void                              *bottom_half,
+	CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC   bottom_half_enqueue_func);
+
+/*
+ * cam_irq_controller_unsubscribe_irq()
+ *
+ * @brief:               Unsubscribe to IRQ events previously subscribed to.
+ *
+ * @irq_controller:      Pointer to IRQ Controller that controls this event IRQ
+ * @handle:              Handle returned on successful subscribe used to
+ *                       identify the handler object
+ *
+ * @return:              0: Success
+ *                       Negative: Failure
+ */
+int cam_irq_controller_unsubscribe_irq(void *irq_controller,
+	uint32_t handle);
+
+/*
+ * cam_irq_controller_deinit()
+ *
+ * @brief:              Deinitialize IRQ Controller.
+ *
+ * @irq_controller:     Pointer to IRQ Controller that needs to be
+ *                      deinitialized
+ *
+ * @return:             0: Success
+ *                      Negative: Failure
+ */
+int cam_irq_controller_deinit(void **irq_controller);
+
+/*
+ * cam_irq_controller_handle_irq()
+ *
+ * @brief:              Function that should be registered with the IRQ line.
+ *                      This is the first function to be called when the IRQ
+ *                      is fired. It will read the Status register and Clear
+ *                      the IRQ bits. It will then call the top_half handlers
+ *                      and enqueue the result to bottom_half.
+ *
+ * @irq_num:            Number of IRQ line that was set that lead to this
+ *                      function being called
+ * @priv:               Private data registered with request_irq is passed back
+ *                      here. This private data should be the irq_controller
+ *                      structure.
+ *
+ * @return:             IRQ_HANDLED/IRQ_NONE
+ */
+irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv);
+
+#endif /*_CAM_IRQ_CONTROLLER_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/Makefile
index 4e6a06e6..4bf4a0e 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/
+obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
new file mode 100644
index 0000000..ea34406
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -0,0 +1,162 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_ISP_HW_H_
+#define _CAM_ISP_HW_H_
+
+#include <linux/completion.h>
+#include "cam_hw.h"
+#include "cam_soc_util.h"
+#include "cam_irq_controller.h"
+
+/*
+ * struct cam_isp_timestamp:
+ *
+ * @mono_time:          Monotonic boot time
+ * @vt_time:            AV Timer time
+ * @ticks:              Qtimer ticks
+ */
+struct cam_isp_timestamp {
+	struct timeval          mono_time;
+	struct timeval          vt_time;
+	uint64_t                ticks;
+};
+
+/*
+ * cam_isp_hw_get_timestamp()
+ *
+ * @Brief:              Get timestamp values
+ *
+ * @time_stamp:         Structure that holds different time values
+ *
+ * @Return:             Void
+ */
+void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp);
+
+enum cam_isp_hw_type {
+	CAM_ISP_HW_TYPE_CSID        = 0,
+	CAM_ISP_HW_TYPE_ISPIF       = 1,
+	CAM_ISP_HW_TYPE_VFE         = 2,
+	CAM_ISP_HW_TYPE_IFE_CSID    = 3,
+	CAM_ISP_HW_TYPE_MAX         = 4,
+};
+
+enum cam_isp_hw_split_id {
+	CAM_ISP_HW_SPLIT_LEFT       = 0,
+	CAM_ISP_HW_SPLIT_RIGHT,
+	CAM_ISP_HW_SPLIT_MAX,
+};
+
+enum cam_isp_hw_sync_mode {
+	CAM_ISP_HW_SYNC_NONE,
+	CAM_ISP_HW_SYNC_MASTER,
+	CAM_ISP_HW_SYNC_SLAVE,
+	CAM_ISP_HW_SYNC_MAX,
+};
+
+enum cam_isp_resource_state {
+	CAM_ISP_RESOURCE_STATE_UNAVAILABLE   = 0,
+	CAM_ISP_RESOURCE_STATE_AVAILABLE     = 1,
+	CAM_ISP_RESOURCE_STATE_RESERVED      = 2,
+	CAM_ISP_RESOURCE_STATE_INIT_HW       = 3,
+	CAM_ISP_RESOURCE_STATE_STREAMING     = 4,
+};
+
+enum cam_isp_resource_type {
+	CAM_ISP_RESOURCE_UNINT,
+	CAM_ISP_RESOURCE_SRC,
+	CAM_ISP_RESOURCE_CID,
+	CAM_ISP_RESOURCE_PIX_PATH,
+	CAM_ISP_RESOURCE_VFE_IN,
+	CAM_ISP_RESOURCE_VFE_OUT,
+	CAM_ISP_RESOURCE_MAX,
+};
+
+/*
+ * struct cam_isp_resource_node:
+ *
+ * @Brief:                        Structure representing HW resource object
+ *
+ * @res_type:                     Resource Type
+ * @res_id:                       Unique resource ID within res_type objects
+ *                                for a particular HW
+ * @res_state:                    State of the resource
+ * @hw_intf:                      HW Interface of HW to which this resource
+ *                                belongs
+ * @res_priv:                     Private data of the resource
+ * @list:                         list_head node for this resource
+ * @cdm_ops:                      CDM operation functions
+ * @tasklet_info:                 Tasklet structure that will be used to
+ *                                schedule IRQ events related to this resource
+ * @irq_handle:                   handle returned on subscribing for IRQ event
+ * @start:                        function pointer to start the HW resource
+ * @stop:                         function pointer to stop the HW resource
+ * @process_cmd:                  function pointer for processing commands
+ *                                specific to the resource
+ * @top_half_handler:             Top Half handler function
+ * @bottom_half_handler:          Bottom Half handler function
+ */
+struct cam_isp_resource_node {
+	enum cam_isp_resource_type     res_type;
+	uint32_t                       res_id;
+	enum cam_isp_resource_state    res_state;
+	struct cam_hw_intf            *hw_intf;
+	void                          *res_priv;
+	struct list_head               list;
+	void                          *cdm_ops;
+	void                          *tasklet_info;
+	int                            irq_handle;
+
+	int (*start)(struct cam_isp_resource_node *rsrc_node);
+	int (*stop)(struct cam_isp_resource_node *rsrc_node);
+	int (*process_cmd)(struct cam_isp_resource_node *rsrc_node,
+		uint32_t cmd_type, void *cmd_args, uint32_t arg_size);
+	CAM_IRQ_HANDLER_TOP_HALF       top_half_handler;
+	CAM_IRQ_HANDLER_BOTTOM_HALF    bottom_half_handler;
+};
+
+/*
+ * struct cam_isp_hw_get_cdm_args:
+ *
+ * @Brief:           Contain the command buffer information
+ *                   to store the CDM commands.
+ *
+ * @res:             Resource node
+ * @cmd_buf_addr:    Command buffer to store the change base command
+ * @size:            Size of the buffer in bytes
+ * @used_bytes:      Consumed bytes in the command buffer
+ *
+ */
+struct cam_isp_hw_get_cdm_args {
+	struct cam_isp_resource_node   *res;
+	uint32_t                       *cmd_buf_addr;
+	uint32_t                        size;
+	uint32_t                        used_bytes;
+};
+
+/*
+ * struct cam_isp_hw_get_buf_update:
+ *
+ * @Brief:         Get cdm commands for buffer updates.
+ *
+ * @ cdm:          Command buffer information
+ * @ image_buf:    Contain the image buffer information
+ * @ num_buf:      Number of buffers in the image_buf array
+ *
+ */
+struct cam_isp_hw_get_buf_update {
+	struct cam_isp_hw_get_cdm_args  cdm;
+	uint64_t                       *image_buf;
+	uint32_t                        num_buf;
+};
+
+#endif /* _CAM_ISP_HW_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
new file mode 100644
index 0000000..15db6a6
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -0,0 +1,255 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_HW_INTF_H_
+#define _CAM_VFE_HW_INTF_H_
+
+#include "cam_isp_hw.h"
+
+#define CAM_VFE_HW_NUM_MAX                       4
+
+#define VFE_CORE_BASE_IDX             0
+/*
+ * VBIF and BUS do not exist on same HW.
+ * Hence both can be 1 below.
+ */
+#define VFE_VBIF_BASE_IDX             1
+#define VFE_BUS_BASE_IDX              1
+
+enum cam_isp_hw_vfe_in_mux {
+	CAM_ISP_HW_VFE_IN_CAMIF     = 0,
+	CAM_ISP_HW_VFE_IN_TESTGEN   = 1,
+	CAM_ISP_HW_VFE_IN_BUS_RD    = 2,
+	CAM_ISP_HW_VFE_IN_RDI0      = 3,
+	CAM_ISP_HW_VFE_IN_RDI1      = 4,
+	CAM_ISP_HW_VFE_IN_RDI2      = 5,
+	CAM_ISP_HW_VFE_IN_RDI3      = 6,
+	CAM_ISP_HW_VFE_IN_MAX,
+};
+
+enum cam_isp_hw_vfe_core {
+	CAM_ISP_HW_VFE_CORE_0,
+	CAM_ISP_HW_VFE_CORE_1,
+	CAM_ISP_HW_VFE_CORE_2,
+	CAM_ISP_HW_VFE_CORE_3,
+	CAM_ISP_HW_VFE_CORE_MAX,
+};
+
+enum cam_vfe_hw_cmd_type {
+	CAM_VFE_HW_CMD_GET_CHANGE_BASE,
+	CAM_VFE_HW_CMD_GET_BUF_UPDATE,
+	CAM_VFE_HW_CMD_GET_REG_UPDATE,
+	CAM_VFE_HW_CMD_MAX,
+};
+
+enum cam_vfe_hw_irq_status {
+	CAM_VFE_IRQ_STATUS_ERR_COMP             = -3,
+	CAM_VFE_IRQ_STATUS_COMP_OWRT            = -2,
+	CAM_VFE_IRQ_STATUS_ERR                  = -1,
+	CAM_VFE_IRQ_STATUS_SUCCESS              = 0,
+	CAM_VFE_IRQ_STATUS_MAX,
+};
+
+enum cam_vfe_hw_irq_regs {
+	CAM_IFE_IRQ_CAMIF_REG_STATUS0           = 0,
+	CAM_IFE_IRQ_CAMIF_REG_STATUS1           = 1,
+	CAM_IFE_IRQ_VIOLATION_STATUS            = 2,
+	CAM_IFE_IRQ_REGISTERS_MAX,
+};
+
+enum cam_vfe_bus_irq_regs {
+	CAM_IFE_IRQ_BUS_REG_STATUS0             = 0,
+	CAM_IFE_IRQ_BUS_REG_STATUS1             = 1,
+	CAM_IFE_IRQ_BUS_REG_STATUS2             = 2,
+	CAM_IFE_IRQ_BUS_REG_COMP_ERR            = 3,
+	CAM_IFE_IRQ_BUS_REG_COMP_OWRT           = 4,
+	CAM_IFE_IRQ_BUS_DUAL_COMP_ERR           = 5,
+	CAM_IFE_IRQ_BUS_DUAL_COMP_OWRT          = 6,
+	CAM_IFE_BUS_IRQ_REGISTERS_MAX,
+};
+
+/*
+ * struct cam_vfe_hw_get_hw_cap:
+ *
+ * @max_width:               Max width supported by HW
+ * @max_height:              Max height supported by HW
+ * @max_pixel_num:           Max Pixel channels available
+ * @max_rdi_num:             Max Raw channels available
+ */
+struct cam_vfe_hw_get_hw_cap {
+	uint32_t                max_width;
+	uint32_t                max_height;
+	uint32_t                max_pixel_num;
+	uint32_t                max_rdi_num;
+};
+
+/*
+ * struct cam_vfe_hw_vfe_out_acquire_args:
+ *
+ * @rsrc_node:               Pointer to Resource Node object, filled if acquire
+ *                           is successful
+ * @out_port_info:           Output Port details to acquire
+ * @unique_id:               Unique Identity of Context to associate with this
+ *                           resource. Used for composite grouping of multiple
+ *                           resources in the same context
+ * @is_dual:                 Dual VFE or not
+ * @split_id:                In case of Dual VFE, this is Left or Right.
+ *                           (Default is Left if Single VFE)
+ * @is_master:               In case of Dual VFE, this is Master or Slave.
+ *                           (Default is Master in case of Single VFE)
+ * @dual_slave_core:         If Master and Slave exists, HW Index of Slave
+ * @cdm_ops:                 CDM operations
+ */
+struct cam_vfe_hw_vfe_out_acquire_args {
+	struct cam_isp_resource_node      *rsrc_node;
+	struct cam_isp_out_port_info      *out_port_info;
+	uint32_t                           unique_id;
+	uint32_t                           is_dual;
+	enum cam_isp_hw_split_id           split_id;
+	uint32_t                           is_master;
+	uint32_t                           dual_slave_core;
+	struct cam_cdm_utils_ops          *cdm_ops;
+};
+
+/*
+ * struct cam_vfe_hw_vfe_in_acquire_args:
+ *
+ * @rsrc_node:               Pointer to Resource Node object, filled if acquire
+ *                           is successful
+ * @res_id:                  Resource ID of resource to acquire if specific,
+ *                           else CAM_ISP_HW_VFE_IN_MAX
+ * @cdm_ops:                 CDM operations
+ * @sync_mode:               In case of Dual VFE, this is Master or Slave.
+ *                           (Default is Master in case of Single VFE)
+ * @in_port:                 Input port details to acquire
+ */
+struct cam_vfe_hw_vfe_in_acquire_args {
+	struct cam_isp_resource_node         *rsrc_node;
+	uint32_t                              res_id;
+	void                                 *cdm_ops;
+	enum cam_isp_hw_sync_mode             sync_mode;
+	struct cam_isp_in_port_info          *in_port;
+};
+
+/*
+ * struct cam_vfe_acquire_args:
+ *
+ * @rsrc_type:               Type of Resource (OUT/IN) to acquire
+ * @tasklet:                 Tasklet to associate with this resource. This is
+ *                           used to schedule bottom of IRQ events associated
+ *                           with this resource.
+ * @vfe_out:                 Acquire args for VFE_OUT
+ * @vfe_in:                  Acquire args for VFE_IN
+ */
+struct cam_vfe_acquire_args {
+	enum cam_isp_resource_type           rsrc_type;
+	void                                *tasklet;
+	union {
+		struct cam_vfe_hw_vfe_out_acquire_args  vfe_out;
+		struct cam_vfe_hw_vfe_in_acquire_args   vfe_in;
+	};
+};
+
+/*
+ * struct cam_vfe_top_irq_evt_payload:
+ *
+ * @Brief:                   This structure is used to save payload for IRQ
+ *                           related to VFE_TOP resources
+ *
+ * @list:                    list_head node for the payload
+ * @core_index:              Index of VFE HW that generated this IRQ event
+ * @core_info:               Private data of handler in bottom half context
+ * @evt_id:                  IRQ event
+ * @irq_reg_val:             IRQ and Error register values, read when IRQ was
+ *                           handled
+ * @error_type:              Identify different errors
+ * @ts:                      Timestamp
+ */
+struct cam_vfe_top_irq_evt_payload {
+	struct list_head           list;
+	uint32_t                   core_index;
+	void                      *core_info;
+	uint32_t                   evt_id;
+	uint32_t                   irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX];
+	uint32_t                   error_type;
+	struct cam_isp_timestamp   ts;
+};
+
+/*
+ * struct cam_vfe_bus_irq_evt_payload:
+ *
+ * @Brief:                   This structure is used to save payload for IRQ
+ *                           related to VFE_BUS resources
+ *
+ * @list:                    list_head node for the payload
+ * @core_index:              Index of VFE HW that generated this IRQ event
+ * @core_info:               Private data of handler in bottom half context
+ * @evt_id:                  IRQ event
+ * @irq_reg_val:             IRQ and Error register values, read when IRQ was
+ *                           handled
+ * @error_type:              Identify different errors
+ * @ts:                      Timestamp
+ */
+struct cam_vfe_bus_irq_evt_payload {
+	struct list_head             list;
+	uint32_t                     core_index;
+	void                        *core_info;
+	uint32_t                     evt_id;
+	uint32_t                     irq_reg_val[CAM_IFE_BUS_IRQ_REGISTERS_MAX];
+	uint32_t                     error_type;
+	struct cam_vfe_bus_ver2_priv *bus_priv;
+	struct cam_isp_timestamp     ts;
+};
+
+/*
+ * struct cam_vfe_irq_handler_priv:
+ *
+ * @Brief:                   This structure is used as private data to
+ *                           register with IRQ controller. It has information
+ *                           needed by top half and bottom half.
+ *
+ * @core_index:              Index of VFE HW that generated this IRQ event
+ * @core_info:               Private data of handler in bottom half context
+ * @mem_base:                Mapped base address of the register space
+ * @reset_complete:          Completion structure to be signaled if Reset IRQ
+ *                           is Set
+ */
+struct cam_vfe_irq_handler_priv {
+	uint32_t                     core_index;
+	void                        *core_info;
+	void __iomem                *mem_base;
+	struct completion           *reset_complete;
+};
+
+/*
+ * cam_vfe_hw_init()
+ *
+ * @Brief:                  Initialize VFE HW device
+ *
+ * @vfe_hw:                 vfe_hw interface to fill in and return on
+ *                          successful initialization
+ * @hw_idx:                 Index of VFE HW
+ */
+int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx);
+
+/*
+ * cam_vfe_put_evt_payload()
+ *
+ * @Brief:                  Put the evt payload back to free list
+ *
+ * @core_info:              VFE HW core_info
+ * @evt_payload:            Event payload data
+ */
+int cam_vfe_put_evt_payload(void             *core_info,
+	struct cam_vfe_top_irq_evt_payload  **evt_payload);
+
+#endif /* _CAM_VFE_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile
new file mode 100644
index 0000000..5a67efa
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile
@@ -0,0 +1,15 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
+
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_soc.o cam_vfe_dev.o cam_vfe_core.o
+obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe170/
\ No newline at end of file
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
new file mode 100644
index 0000000..488a00b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -0,0 +1,619 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/ratelimit.h>
+#include "cam_tasklet_util.h"
+#include "cam_isp_hw_mgr_intf.h"
+#include "cam_vfe_soc.h"
+#include "cam_vfe_core.h"
+#include "cam_vfe_bus.h"
+#include "cam_vfe_top.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static const char drv_name[] = "vfe";
+
+static uint32_t irq_reg_offset[CAM_IFE_IRQ_REGISTERS_MAX] = {
+	0x0000006C,
+	0x00000070,
+	0x0000007C,
+};
+
+static uint32_t top_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
+	0x7803FDFF,
+	0x0FFF7EB3,
+};
+
+static uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
+	0x80000000,
+	0x00000000,
+};
+
+static uint32_t bus_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {
+	0x00000200,
+	0x00000000,
+};
+
+static int cam_vfe_get_evt_payload(struct cam_vfe_hw_core_info *core_info,
+	struct cam_vfe_top_irq_evt_payload    **evt_payload)
+{
+	spin_lock(&core_info->spin_lock);
+	if (list_empty(&core_info->free_payload_list)) {
+		*evt_payload = NULL;
+		spin_unlock(&core_info->spin_lock);
+		pr_err_ratelimited("No free payload, core info 0x%x\n",
+			core_info->cpas_handle);
+		return -ENODEV;
+	}
+
+	*evt_payload = list_first_entry(&core_info->free_payload_list,
+		struct cam_vfe_top_irq_evt_payload, list);
+	list_del_init(&(*evt_payload)->list);
+	spin_unlock(&core_info->spin_lock);
+
+	return 0;
+}
+
+int cam_vfe_put_evt_payload(void             *core_info,
+	struct cam_vfe_top_irq_evt_payload  **evt_payload)
+{
+	struct cam_vfe_hw_core_info        *vfe_core_info = core_info;
+	unsigned long                       flags;
+
+	if (!core_info) {
+		pr_err("Invalid param core_info NULL");
+		return -EINVAL;
+	}
+	if (*evt_payload == NULL) {
+		pr_err("No payload to put\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&vfe_core_info->spin_lock, flags);
+	list_add_tail(&(*evt_payload)->list, &vfe_core_info->free_payload_list);
+	spin_unlock_irqrestore(&vfe_core_info->spin_lock, flags);
+
+	*evt_payload = NULL;
+	return 0;
+}
+
+int cam_vfe_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size)
+{
+	struct cam_hw_info                *vfe_dev = hw_priv;
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	int rc = 0;
+
+	CDBG("Enter\n");
+	if (!hw_priv) {
+		pr_err("%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_vfe_hw_core_info *)vfe_dev->core_info;
+
+	if (core_info->vfe_top->hw_ops.get_hw_caps)
+		core_info->vfe_top->hw_ops.get_hw_caps(
+			core_info->vfe_top->top_priv,
+			get_hw_cap_args, arg_size);
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+int cam_vfe_reset_irq_top_half(uint32_t    evt_id,
+	struct cam_irq_th_payload         *th_payload)
+{
+	int32_t                            rc = -EINVAL;
+	struct cam_vfe_irq_handler_priv   *handler_priv;
+
+	handler_priv = th_payload->handler_priv;
+
+	CDBG("Enter\n");
+	CDBG("IRQ status_0 = 0x%x\n", th_payload->evt_status_arr[0]);
+
+	if (th_payload->evt_status_arr[0] & (1<<31)) {
+		CDBG("Calling Complete for RESET CMD\n");
+		complete(handler_priv->reset_complete);
+
+		/*
+		 * Clear All IRQs to avoid spurious IRQs immediately
+		 * after Reset Done.
+		 */
+		cam_io_w(0xFFFFFFFF, handler_priv->mem_base + 0x64);
+		cam_io_w(0xFFFFFFFF, handler_priv->mem_base + 0x68);
+		cam_io_w(0x1, handler_priv->mem_base + 0x58);
+
+		rc = 0;
+	}
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info                *vfe_hw = hw_priv;
+	struct cam_hw_soc_info            *soc_info = NULL;
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	int rc = 0;
+
+	CDBG("Enter\n");
+	if (!hw_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&vfe_hw->hw_mutex);
+	vfe_hw->open_count++;
+	if (vfe_hw->open_count > 1) {
+		mutex_unlock(&vfe_hw->hw_mutex);
+		CDBG("VFE has already been initialized cnt %d\n",
+			vfe_hw->open_count);
+		return 0;
+	}
+	mutex_unlock(&vfe_hw->hw_mutex);
+
+	soc_info = &vfe_hw->soc_info;
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+
+	/* Turn ON Regulators, Clocks and other SOC resources */
+	rc = cam_vfe_enable_soc_resources(soc_info);
+	if (rc) {
+		pr_err("Enable SOC failed\n");
+		rc = -EFAULT;
+		goto decrement_open_cnt;
+	}
+
+	CDBG("Enable soc done\n");
+
+	/* Do HW Reset */
+	rc = cam_vfe_reset(hw_priv, NULL, 0);
+	if (rc) {
+		pr_err("Reset Failed\n");
+		goto disable_soc;
+	}
+
+	return 0;
+
+disable_soc:
+	cam_vfe_disable_soc_resources(soc_info);
+decrement_open_cnt:
+	mutex_lock(&vfe_hw->hw_mutex);
+	vfe_hw->open_count--;
+	mutex_unlock(&vfe_hw->hw_mutex);
+	return rc;
+}
+
+int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info                *vfe_hw = hw_priv;
+	struct cam_hw_soc_info            *soc_info = NULL;
+	int rc = 0;
+
+	CDBG("Enter\n");
+	if (!hw_priv) {
+		pr_err("%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vfe_hw->hw_mutex);
+	if (!vfe_hw->open_count) {
+		mutex_unlock(&vfe_hw->hw_mutex);
+		pr_err("Error! Unbalanced deinit\n");
+		return -EFAULT;
+	}
+	vfe_hw->open_count--;
+	if (vfe_hw->open_count) {
+		mutex_unlock(&vfe_hw->hw_mutex);
+		CDBG("open_cnt non-zero =%d\n", vfe_hw->open_count);
+		return 0;
+	}
+	mutex_unlock(&vfe_hw->hw_mutex);
+
+	soc_info = &vfe_hw->soc_info;
+
+	/* Turn OFF Regulators, Clocks and other SOC resources */
+	CDBG("Disable SOC resource\n");
+	rc = cam_vfe_disable_soc_resources(soc_info);
+	if (rc)
+		pr_err("Disable SOC failed\n");
+
+	vfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+int cam_vfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size)
+{
+	struct cam_hw_info                *vfe_hw  = hw_priv;
+	struct cam_hw_soc_info            *soc_info = NULL;
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	int rc;
+
+	CDBG("Enter\n");
+
+	if (!hw_priv) {
+		pr_err("Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	soc_info = &vfe_hw->soc_info;
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+
+	core_info->irq_payload.core_index = soc_info->index;
+	core_info->irq_payload.mem_base =
+		vfe_hw->soc_info.reg_map[VFE_CORE_BASE_IDX].mem_base;
+	core_info->irq_payload.core_info = core_info;
+	core_info->irq_payload.reset_complete = &vfe_hw->hw_complete;
+
+	core_info->irq_handle = cam_irq_controller_subscribe_irq(
+		core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_0,
+		top_reset_irq_reg_mask, &core_info->irq_payload,
+		cam_vfe_reset_irq_top_half, NULL, NULL, NULL);
+	if (core_info->irq_handle < 0) {
+		pr_err("subscribe irq controller failed\n");
+		return -EFAULT;
+	}
+
+	reinit_completion(&vfe_hw->hw_complete);
+
+	CDBG("calling RESET\n");
+	core_info->vfe_top->hw_ops.reset(core_info->vfe_top->top_priv, NULL, 0);
+	CDBG("waiting for vfe reset complete\n");
+	/* Wait for Completion or Timeout of 500ms */
+	rc = wait_for_completion_timeout(&vfe_hw->hw_complete, 500);
+	if (!rc)
+		pr_err("Error! Reset Timeout\n");
+
+	CDBG("reset complete done (%d)\n", rc);
+
+	rc = cam_irq_controller_unsubscribe_irq(
+		core_info->vfe_irq_controller, core_info->irq_handle);
+	if (rc)
+		pr_err("Error! Unsubscribe failed\n");
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp)
+{
+	struct timespec ts;
+
+	get_monotonic_boottime(&ts);
+	time_stamp->mono_time.tv_sec    = ts.tv_sec;
+	time_stamp->mono_time.tv_usec   = ts.tv_nsec/1000;
+}
+
+
+int cam_vfe_irq_top_half(uint32_t    evt_id,
+	struct cam_irq_th_payload   *th_payload)
+{
+	int32_t                              rc;
+	int                                  i;
+	struct cam_vfe_irq_handler_priv     *handler_priv;
+	struct cam_vfe_top_irq_evt_payload  *evt_payload;
+
+	handler_priv = th_payload->handler_priv;
+
+	CDBG("IRQ status_0 = %x\n", th_payload->evt_status_arr[0]);
+	CDBG("IRQ status_1 = %x\n", th_payload->evt_status_arr[1]);
+
+	rc  = cam_vfe_get_evt_payload(handler_priv->core_info, &evt_payload);
+	if (rc) {
+		pr_err_ratelimited("No tasklet_cmd is free in queue\n");
+		return rc;
+	}
+
+	cam_isp_hw_get_timestamp(&evt_payload->ts);
+
+	evt_payload->core_index = handler_priv->core_index;
+	evt_payload->core_info  = handler_priv->core_info;
+	evt_payload->evt_id  = evt_id;
+
+	for (i = 0; i < th_payload->num_registers; i++)
+		evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i];
+
+	for (; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) {
+		evt_payload->irq_reg_val[i] = cam_io_r(handler_priv->mem_base +
+			irq_reg_offset[i]);
+	}
+	CDBG("Violation status = %x\n", evt_payload->irq_reg_val[2]);
+
+	/*
+	 *  need to handle overflow condition here, otherwise irq storm
+	 *  will block everything.
+	 */
+	if (evt_payload->irq_reg_val[1]) {
+		pr_err("Mask all the interrupts\n");
+		cam_io_w(0, handler_priv->mem_base + 0x60);
+		cam_io_w(0, handler_priv->mem_base + 0x5C);
+
+		evt_payload->error_type = CAM_ISP_HW_ERROR_OVERFLOW;
+	}
+
+	th_payload->evt_payload_priv = evt_payload;
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+int cam_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size)
+{
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	struct cam_hw_info                *vfe_hw  = hw_priv;
+	struct cam_vfe_acquire_args       *acquire;
+	int rc = -ENODEV;
+
+
+	if (!hw_priv || !reserve_args || (arg_size !=
+		sizeof(struct cam_vfe_acquire_args))) {
+		pr_err("Invalid input arguments\n");
+		return -EINVAL;
+	}
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+	acquire = (struct cam_vfe_acquire_args   *)reserve_args;
+
+	mutex_lock(&vfe_hw->hw_mutex);
+	if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_IN)
+		rc = core_info->vfe_top->hw_ops.reserve(
+			core_info->vfe_top->top_priv,
+			acquire,
+			sizeof(acquire));
+	else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_OUT)
+		rc = core_info->vfe_bus->acquire_resource(
+			core_info->vfe_bus->bus_priv, acquire);
+	else
+		pr_err("Invalid res type:%d\n", acquire->rsrc_type);
+
+	mutex_unlock(&vfe_hw->hw_mutex);
+
+	return rc;
+}
+
+
+int cam_vfe_release(void *hw_priv, void *release_args, uint32_t arg_size)
+{
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	struct cam_hw_info                *vfe_hw  = hw_priv;
+	struct cam_isp_resource_node      *isp_res;
+	int rc = -ENODEV;
+
+	if (!hw_priv || !release_args ||
+		(arg_size != sizeof(struct cam_isp_resource_node))) {
+		pr_err("Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+	isp_res = (struct cam_isp_resource_node      *) release_args;
+
+	mutex_lock(&vfe_hw->hw_mutex);
+	if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN)
+		rc = core_info->vfe_top->hw_ops.release(
+			core_info->vfe_top->top_priv, isp_res,
+			sizeof(struct cam_isp_resource_node));
+	else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT)
+		rc = core_info->vfe_bus->release_resource(
+			core_info->vfe_bus->bus_priv, isp_res);
+	else
+		pr_err("Invalid res type:%d\n", isp_res->res_type);
+
+	mutex_unlock(&vfe_hw->hw_mutex);
+
+	return rc;
+}
+
+
+int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size)
+{
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	struct cam_hw_info                *vfe_hw  = hw_priv;
+	struct cam_isp_resource_node      *isp_res;
+	int rc = -ENODEV;
+
+	if (!hw_priv || !start_args ||
+		(arg_size != sizeof(struct cam_isp_resource_node))) {
+		pr_err("Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+	isp_res = (struct cam_isp_resource_node  *)start_args;
+
+	mutex_lock(&vfe_hw->hw_mutex);
+	if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) {
+		isp_res->irq_handle = cam_irq_controller_subscribe_irq(
+			core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_2,
+			top_irq_reg_mask, &core_info->irq_payload,
+			cam_vfe_irq_top_half, NULL,
+			isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
+		if (isp_res->irq_handle > 0)
+			rc = core_info->vfe_top->hw_ops.start(
+				core_info->vfe_top->top_priv, isp_res,
+				sizeof(struct cam_isp_resource_node));
+		else
+			pr_err("Error! subscribe irq controller failed\n");
+	} else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) {
+		isp_res->irq_handle = cam_irq_controller_subscribe_irq(
+			core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_1,
+			bus_irq_reg_mask, &core_info->irq_payload,
+			core_info->vfe_bus->top_half_handler,
+			NULL,
+			isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
+		if (isp_res->irq_handle > 0)
+			rc = core_info->vfe_bus->start_resource(isp_res);
+		else
+			pr_err("Error! subscribe irq controller failed\n");
+	} else {
+		pr_err("Invalid res type:%d\n", isp_res->res_type);
+	}
+
+	mutex_unlock(&vfe_hw->hw_mutex);
+
+	return rc;
+}
+
+int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size)
+{
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	struct cam_hw_info                *vfe_hw  = hw_priv;
+	struct cam_isp_resource_node      *isp_res;
+	int rc = -EINVAL;
+
+	if (!hw_priv || !stop_args ||
+		(arg_size != sizeof(struct cam_isp_resource_node))) {
+		pr_err("Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+	isp_res = (struct cam_isp_resource_node  *)stop_args;
+
+	mutex_lock(&vfe_hw->hw_mutex);
+	if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) {
+		cam_irq_controller_unsubscribe_irq(
+			core_info->vfe_irq_controller, isp_res->irq_handle);
+		rc = core_info->vfe_top->hw_ops.stop(
+			core_info->vfe_top->top_priv, isp_res,
+			sizeof(struct cam_isp_resource_node));
+	} else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) {
+		cam_irq_controller_unsubscribe_irq(
+			core_info->vfe_irq_controller, isp_res->irq_handle);
+		rc = core_info->vfe_bus->stop_resource(isp_res);
+	} else {
+		pr_err("Invalid res type:%d\n", isp_res->res_type);
+	}
+
+	mutex_unlock(&vfe_hw->hw_mutex);
+
+	return rc;
+}
+
+int cam_vfe_read(void *hw_priv, void *read_args, uint32_t arg_size)
+{
+	return -EPERM;
+}
+
+int cam_vfe_write(void *hw_priv, void *write_args, uint32_t arg_size)
+{
+	return -EPERM;
+}
+
+int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info                *vfe_hw = hw_priv;
+	struct cam_hw_soc_info            *soc_info = NULL;
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	struct cam_vfe_hw_info            *hw_info = NULL;
+	int rc = 0;
+
+	if (!hw_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	soc_info = &vfe_hw->soc_info;
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+	hw_info = core_info->vfe_hw_info;
+
+	switch (cmd_type) {
+	case CAM_VFE_HW_CMD_GET_CHANGE_BASE:
+	case CAM_VFE_HW_CMD_GET_REG_UPDATE:
+		rc = core_info->vfe_top->hw_ops.process_cmd(
+			core_info->vfe_top->top_priv, cmd_type, cmd_args,
+			arg_size);
+
+		break;
+	case CAM_VFE_HW_CMD_GET_BUF_UPDATE:
+		rc = core_info->vfe_bus->process_cmd(
+			core_info->vfe_bus->bus_priv, cmd_type, cmd_args,
+			arg_size);
+		break;
+
+	default:
+		pr_err("Invalid cmd type:%d\n", cmd_type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+irqreturn_t cam_vfe_irq(int irq_num, void *data)
+{
+	struct cam_hw_info            *vfe_hw;
+	struct cam_vfe_hw_core_info   *core_info;
+
+	if (!data)
+		return IRQ_NONE;
+
+	vfe_hw = (struct cam_hw_info *)data;
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+
+	return cam_irq_controller_handle_irq(irq_num,
+		core_info->vfe_irq_controller);
+}
+
+int cam_vfe_core_init(struct cam_vfe_hw_core_info  *core_info,
+	struct cam_hw_soc_info                     *soc_info,
+	struct cam_hw_intf                         *hw_intf,
+	struct cam_vfe_hw_info                     *vfe_hw_info)
+{
+	int rc = -EINVAL;
+	int i;
+
+	CDBG("Enter");
+
+	rc = cam_irq_controller_init(drv_name,
+		CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX),
+		vfe_hw_info->irq_reg_info, &core_info->vfe_irq_controller);
+	if (rc) {
+		pr_err("Error! cam_irq_controller_init failed\n");
+		return rc;
+	}
+
+	rc = cam_vfe_top_init(vfe_hw_info->top_version,
+		soc_info, hw_intf, vfe_hw_info->top_hw_info,
+		&core_info->vfe_top);
+	if (rc) {
+		pr_err("Error! cam_vfe_top_init failed\n");
+		return rc;
+	}
+
+	rc = cam_vfe_bus_init(vfe_hw_info->bus_version,
+		soc_info->reg_map[0].mem_base, hw_intf,
+		vfe_hw_info->bus_hw_info, NULL, &core_info->vfe_bus);
+	if (rc) {
+		pr_err("Error! cam_vfe_bus_init failed\n");
+		return rc;
+	}
+
+	INIT_LIST_HEAD(&core_info->free_payload_list);
+	for (i = 0; i < CAM_VFE_EVT_MAX; i++) {
+		INIT_LIST_HEAD(&core_info->evt_payload[i].list);
+		list_add_tail(&core_info->evt_payload[i].list,
+			&core_info->free_payload_list);
+	}
+
+	spin_lock_init(&core_info->spin_lock);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
new file mode 100644
index 0000000..92e322b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_CORE_H_
+#define _CAM_VFE_CORE_H_
+
+#include <linux/spinlock.h>
+#include "cam_hw_intf.h"
+#include "cam_vfe_top.h"
+#include "cam_vfe_bus.h"
+#include "cam_vfe_hw_intf.h"
+
+struct cam_vfe_hw_info {
+	struct cam_irq_controller_reg_info *irq_reg_info;
+
+	uint32_t                          bus_version;
+	void                             *bus_hw_info;
+
+	uint32_t                          top_version;
+	void                             *top_hw_info;
+	uint32_t                          camif_version;
+	void                             *camif_reg;
+
+	uint32_t                          testgen_version;
+	void                             *testgen_reg;
+
+	uint32_t                          num_qos_settings;
+	struct cam_isp_reg_val_pair      *qos_settings;
+
+	uint32_t                          num_ds_settings;
+	struct cam_isp_reg_val_pair      *ds_settings;
+
+	uint32_t                          num_vbif_settings;
+	struct cam_isp_reg_val_pair      *vbif_settings;
+};
+
+#define CAM_VFE_EVT_MAX                    128
+
+struct cam_vfe_hw_core_info {
+	struct cam_vfe_hw_info             *vfe_hw_info;
+	void                               *vfe_irq_controller;
+	struct cam_vfe_top                 *vfe_top;
+	struct cam_vfe_bus                 *vfe_bus;
+
+	struct cam_vfe_top_irq_evt_payload  evt_payload[CAM_VFE_EVT_MAX];
+	struct list_head                    free_payload_list;
+	struct cam_vfe_irq_handler_priv     irq_payload;
+	uint32_t                            cpas_handle;
+	int                                 irq_handle;
+	spinlock_t                          spin_lock;
+};
+
+int cam_vfe_get_hw_caps(void *device_priv,
+	void *get_hw_cap_args, uint32_t arg_size);
+int cam_vfe_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_vfe_deinit_hw(void *hw_priv,
+	void *deinit_hw_args, uint32_t arg_size);
+int cam_vfe_reset(void *device_priv,
+	void *reset_core_args, uint32_t arg_size);
+int cam_vfe_reserve(void *device_priv,
+	void *reserve_args, uint32_t arg_size);
+int cam_vfe_release(void *device_priv,
+	void *reserve_args, uint32_t arg_size);
+int cam_vfe_start(void *device_priv,
+	void *start_args, uint32_t arg_size);
+int cam_vfe_stop(void *device_priv,
+	void *stop_args, uint32_t arg_size);
+int cam_vfe_read(void *device_priv,
+	void *read_args, uint32_t arg_size);
+int cam_vfe_write(void *device_priv,
+	void *write_args, uint32_t arg_size);
+int cam_vfe_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+
+irqreturn_t cam_vfe_irq(int irq_num, void *data);
+
+int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info,
+	struct cam_hw_soc_info             *soc_info,
+	struct cam_hw_intf                 *hw_intf,
+	struct cam_vfe_hw_info             *vfe_hw_info);
+
+#endif /* _CAM_VFE_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c
new file mode 100644
index 0000000..40279ae
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include "cam_vfe_dev.h"
+#include "cam_vfe_core.h"
+#include "cam_vfe_soc.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static struct cam_hw_intf *cam_vfe_hw_list[CAM_VFE_HW_NUM_MAX] = {0, 0, 0, 0};
+
+int cam_vfe_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info                *vfe_hw = NULL;
+	struct cam_hw_intf                *vfe_hw_intf = NULL;
+	const struct of_device_id         *match_dev = NULL;
+	struct cam_vfe_hw_core_info       *core_info = NULL;
+	struct cam_vfe_hw_info            *hw_info = NULL;
+	int                                rc = 0;
+
+	vfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!vfe_hw_intf) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &vfe_hw_intf->hw_idx);
+
+	vfe_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!vfe_hw) {
+		rc = -ENOMEM;
+		goto free_vfe_hw_intf;
+	}
+	vfe_hw->soc_info.pdev = pdev;
+	vfe_hw_intf->hw_priv = vfe_hw;
+	vfe_hw_intf->hw_ops.get_hw_caps = cam_vfe_get_hw_caps;
+	vfe_hw_intf->hw_ops.init = cam_vfe_init_hw;
+	vfe_hw_intf->hw_ops.deinit = cam_vfe_deinit_hw;
+	vfe_hw_intf->hw_ops.reset = cam_vfe_reset;
+	vfe_hw_intf->hw_ops.reserve = cam_vfe_reserve;
+	vfe_hw_intf->hw_ops.release = cam_vfe_release;
+	vfe_hw_intf->hw_ops.start = cam_vfe_start;
+	vfe_hw_intf->hw_ops.stop = cam_vfe_stop;
+	vfe_hw_intf->hw_ops.read = cam_vfe_read;
+	vfe_hw_intf->hw_ops.write = cam_vfe_write;
+	vfe_hw_intf->hw_ops.process_cmd = cam_vfe_process_cmd;
+	vfe_hw_intf->hw_type = CAM_ISP_HW_TYPE_VFE;
+
+	CDBG("type %d index %d\n", vfe_hw_intf->hw_type, vfe_hw_intf->hw_idx);
+
+	platform_set_drvdata(pdev, vfe_hw_intf);
+
+	vfe_hw->core_info = kzalloc(sizeof(struct cam_vfe_hw_core_info),
+		GFP_KERNEL);
+	if (!vfe_hw->core_info) {
+		CDBG("Failed to alloc for core\n");
+		rc = -ENOMEM;
+		goto free_vfe_hw;
+	}
+	core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_err("Of_match Failed\n");
+		rc = -EINVAL;
+		goto free_core_info;
+	}
+	hw_info = (struct cam_vfe_hw_info *)match_dev->data;
+	core_info->vfe_hw_info = hw_info;
+
+	rc = cam_vfe_init_soc_resources(&vfe_hw->soc_info, cam_vfe_irq,
+		vfe_hw);
+	if (rc < 0) {
+		pr_err("Failed to init soc\n");
+		goto free_core_info;
+	}
+
+	rc = cam_vfe_core_init(core_info, &vfe_hw->soc_info,
+		vfe_hw_intf, hw_info);
+	if (rc < 0) {
+		pr_err("Failed to init core\n");
+		goto deinit_soc;
+	}
+
+	vfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&vfe_hw->hw_mutex);
+	spin_lock_init(&vfe_hw->hw_lock);
+	init_completion(&vfe_hw->hw_complete);
+
+	if (vfe_hw_intf->hw_idx < CAM_VFE_HW_NUM_MAX)
+		cam_vfe_hw_list[vfe_hw_intf->hw_idx] = vfe_hw_intf;
+
+	cam_vfe_init_hw(vfe_hw, NULL, 0);
+	cam_vfe_deinit_hw(vfe_hw, NULL, 0);
+
+	CDBG("VFE%d probe successful\n", vfe_hw_intf->hw_idx);
+
+	return rc;
+
+deinit_soc:
+free_core_info:
+	kfree(vfe_hw->core_info);
+free_vfe_hw:
+	kfree(vfe_hw);
+free_vfe_hw_intf:
+	kfree(vfe_hw_intf);
+end:
+	return rc;
+}
+
+int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx)
+{
+	int rc = 0;
+
+	if (cam_vfe_hw_list[hw_idx]) {
+		*vfe_hw = cam_vfe_hw_list[hw_idx];
+		rc = 0;
+	} else {
+		*vfe_hw = NULL;
+		rc = -ENODEV;
+	}
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h
new file mode 100644
index 0000000..ca54d81
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_DEV_H_
+#define _CAM_VFE_DEV_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * cam_vfe_probe()
+ *
+ * @brief:                   Driver probe function called on Boot
+ *
+ * @pdev:                    Platform Device pointer
+ *
+ * @Return:                  0: Success
+ *                           Non-zero: Failure
+ */
+int cam_vfe_probe(struct platform_device *pdev);
+
+#endif /* _CAM_VFE_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
new file mode 100644
index 0000000..3670ca9
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
@@ -0,0 +1,165 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include "cam_cpas_api.h"
+#include "cam_vfe_soc.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_vfe_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc) {
+		pr_err("Error! get DT properties failed\n");
+		return rc;
+	}
+
+	return rc;
+}
+
+static int cam_vfe_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t vfe_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, vfe_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t vfe_irq_handler, void *irq_data)
+{
+	int                               rc = 0;
+	struct cam_vfe_soc_private       *soc_private;
+	struct cam_cpas_register_params   cpas_register_param;
+
+	soc_private = kzalloc(sizeof(struct cam_vfe_soc_private),
+		GFP_KERNEL);
+	if (!soc_private) {
+		CDBG("Error! soc_private Alloc Failed\n");
+		return -ENOMEM;
+	}
+	soc_info->soc_private = soc_private;
+
+	rc = cam_vfe_get_dt_properties(soc_info);
+	if (rc < 0) {
+		pr_err("Error! Get DT properties failed\n");
+		goto free_soc_private;
+	}
+
+	rc = cam_vfe_request_platform_resource(soc_info, vfe_irq_handler,
+		irq_data);
+	if (rc < 0) {
+		pr_err("Error! Request platform resources failed\n");
+		goto free_soc_private;
+	}
+
+	memset(&cpas_register_param, 0, sizeof(cpas_register_param));
+	strlcpy(cpas_register_param.identifier, "ife",
+		CAM_HW_IDENTIFIER_LENGTH);
+	cpas_register_param.cell_index = soc_info->index;
+	cpas_register_param.dev = &soc_info->pdev->dev;
+	rc = cam_cpas_register_client(&cpas_register_param);
+	if (rc) {
+		pr_err("CPAS registration failed\n");
+		goto release_soc;
+	} else {
+		soc_private->cpas_handle = cpas_register_param.client_handle;
+	}
+
+	return rc;
+
+release_soc:
+	cam_soc_util_release_platform_resource(soc_info);
+free_soc_private:
+	kfree(soc_private);
+
+	return rc;
+}
+
+int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int                               rc = 0;
+	struct cam_vfe_soc_private       *soc_private;
+	struct cam_ahb_vote               ahb_vote;
+	struct cam_axi_vote               axi_vote;
+
+	if (!soc_info) {
+		pr_err("Error! Invalid params\n");
+		rc = -EINVAL;
+		goto end;
+	}
+	soc_private = soc_info->soc_private;
+
+	ahb_vote.type       = CAM_VOTE_ABSOLUTE;
+	ahb_vote.vote.level = CAM_SVS_VOTE;
+
+	axi_vote.compressed_bw   = 640000000;
+	axi_vote.uncompressed_bw = 640000000;
+
+	rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote);
+	if (rc) {
+		pr_err("Error! CPAS start failed.\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, true);
+	if (rc) {
+		pr_err("Error! enable platform failed\n");
+		goto stop_cpas;
+	}
+
+	return rc;
+
+stop_cpas:
+	cam_cpas_stop(soc_private->cpas_handle);
+end:
+	return rc;
+}
+
+
+int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+	struct cam_vfe_soc_private       *soc_private;
+
+	if (!soc_info) {
+		pr_err("Error! Invalid params\n");
+		rc = -EINVAL;
+		return rc;
+	}
+	soc_private = soc_info->soc_private;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	if (rc) {
+		pr_err("%s: disable platform failed\n", __func__);
+		return rc;
+	}
+
+	rc = cam_cpas_stop(soc_private->cpas_handle);
+	if (rc) {
+		pr_err("Error! CPAS stop failed.\n");
+		return rc;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
new file mode 100644
index 0000000..27fb192
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_SOC_H_
+#define _CAM_VFE_SOC_H_
+
+#include "cam_soc_util.h"
+#include "cam_isp_hw.h"
+
+/*
+ * struct cam_vfe_soc_private:
+ *
+ * @Brief:                   Private SOC data specific to VFE HW Driver
+ *
+ * @cpas_handle:             Handle returned on registering with CPAS driver.
+ *                           This handle is used for all further interface
+ *                           with CPAS.
+ */
+struct cam_vfe_soc_private {
+	uint32_t cpas_handle;
+};
+
+/*
+ * cam_vfe_init_soc_resources()
+ *
+ * @Brief:                   Initialize SOC resources including private data
+ *
+ * @soc_info:                Device soc information
+ * @handler:                 Irq handler function pointer
+ * @irq_data:                Irq handler function Callback data
+ *
+ * @Return:                  0: Success
+ *                           Non-zero: Failure
+ */
+int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t vfe_irq_handler, void *irq_data);
+
+/*
+ * cam_vfe_enable_soc_resources()
+ *
+ * @brief:                   Enable regulator, irq resources, start CPAS
+ *
+ * @soc_info:                Device soc information
+ *
+ * @Return:                  0: Success
+ *                           Non-zero: Failure
+ */
+int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+/*
+ * cam_vfe_disable_soc_resources()
+ *
+ * @brief:                   Disable regulator, irq resources, stop CPAS
+ *
+ * @soc_info:                Device soc information
+ *
+ * @Return:                  0: Success
+ *                           Non-zero: Failure
+ */
+int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* _CAM_VFE_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile
new file mode 100644
index 0000000..77e4eb3
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe170.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c
new file mode 100644
index 0000000..2245ab1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include "cam_vfe170.h"
+#include "cam_vfe_hw_intf.h"
+#include "cam_vfe_core.h"
+#include "cam_vfe_dev.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static const struct of_device_id cam_vfe170_dt_match[] = {
+	{
+		.compatible = "qcom,vfe170",
+		.data = &cam_vfe170_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match);
+
+static struct platform_driver cam_vfe170_driver = {
+	.probe = cam_vfe_probe,
+	.driver = {
+		.name = "cam_vfe170",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_vfe170_dt_match,
+	},
+};
+
+static int __init cam_vfe170_init_module(void)
+{
+	return platform_driver_register(&cam_vfe170_driver);
+}
+
+static void __exit cam_vfe170_exit_module(void)
+{
+	platform_driver_unregister(&cam_vfe170_driver);
+}
+
+module_init(cam_vfe170_init_module);
+module_exit(cam_vfe170_exit_module);
+MODULE_DESCRIPTION("CAM VFE170 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h
new file mode 100644
index 0000000..b550071
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h
@@ -0,0 +1,781 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE170_H_
+#define _CAM_VFE170_H_
+
+#include "cam_vfe_camif_ver2.h"
+#include "cam_vfe_bus_ver2.h"
+#include "cam_irq_controller.h"
+#include "cam_vfe_top_ver2.h"
+#include "cam_vfe_core.h"
+
+static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = {
+	{
+		.mask_reg_offset   = 0x0000005C,
+		.clear_reg_offset  = 0x00000064,
+		.status_reg_offset = 0x0000006C,
+	},
+	{
+		.mask_reg_offset   = 0x00000060,
+		.clear_reg_offset  = 0x00000068,
+		.status_reg_offset = 0x00000070,
+	},
+};
+
+static struct cam_irq_controller_reg_info vfe170_top_irq_reg_info = {
+	.num_registers = 2,
+	.irq_reg_set = vfe170_top_irq_reg_set,
+	.global_clear_offset  = 0x00000058,
+	.global_clear_bitmask = 0x00000001,
+};
+
+static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = {
+	.camif_cmd                = 0x00000478,
+	.camif_config             = 0x0000047C,
+	.line_skip_pattern        = 0x00000488,
+	.pixel_skip_pattern       = 0x0000048C,
+	.skip_period              = 0x00000490,
+	.irq_subsample_pattern    = 0x0000049C,
+	.epoch_irq                = 0x000004A0,
+	.raw_crop_width_cfg       = 0x00000CE4,
+	.raw_crop_height_cfg      = 0x00000CE8,
+};
+
+static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = {
+	.raw_crop_first_pixel_shift      = 16,
+	.raw_crop_first_pixel_mask       = 0xFFFF,
+	.raw_crop_last_pixel_shift       = 0x0,
+	.raw_crop_last_pixel_mask        = 0x3FFF,
+	.raw_crop_first_line_shift       = 16,
+	.raw_crop_first_line_mask        = 0xFFFF,
+	.raw_crop_last_line_shift        = 0,
+	.raw_crop_last_line_mask         = 0x3FFF,
+	.input_mux_sel_shift             = 5,
+	.input_mux_sel_mask              = 0x3,
+	.extern_reg_update_shift         = 4,
+	.extern_reg_update_mask          = 1,
+	.pixel_pattern_shift             = 0,
+	.pixel_pattern_mask              = 0x7,
+	.epoch_line_cfg                  = 0x140000,
+	.sof_irq_mask                    = 0x00000001,
+	.epoch0_irq_mask                 = 0x00000004,
+	.reg_update_irq_mask             = 0x00000010,
+};
+
+struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_170_reg = {
+	.reset    = 0x0000001C,
+	.cgc_ovd  = 0x0000002C,
+	.enable   = 0x00000040,
+};
+
+struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_170_reg = {
+	.reset    = 0x00000020,
+	.cgc_ovd  = 0x00000030,
+	.enable   = 0x00000044,
+};
+
+struct cam_vfe_top_ver2_reg_offset_module_ctrl color_170_reg = {
+	.reset    = 0x00000024,
+	.cgc_ovd  = 0x00000034,
+	.enable   = 0x00000048,
+};
+
+struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_reg = {
+	.reset    = 0x00000028,
+	.cgc_ovd  = 0x00000038,
+	.enable   = 0x0000004C,
+};
+
+static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = {
+	.hw_version               = 0x00000000,
+	.hw_capability            = 0x00000004,
+	.lens_feature             = 0x00000008,
+	.stats_feature            = 0x0000000C,
+	.color_feature            = 0x00000010,
+	.zoom_feature             = 0x00000014,
+	.global_reset_cmd         = 0x00000018,
+	.module_ctrl              = {
+		&lens_170_reg,
+		&stats_170_reg,
+		&color_170_reg,
+		&zoom_170_reg,
+	},
+	.bus_cgc_ovd              = 0x0000003C,
+	.core_cfg                 = 0x00000050,
+	.three_D_cfg              = 0x00000054,
+	.violation_status         = 0x0000007C,
+	.reg_update_cmd           = 0x000004AC,
+};
+
+static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = {
+	.common_reg = &vfe170_top_common_reg,
+	.camif_hw_info = {
+		.common_reg = &vfe170_top_common_reg,
+		.camif_reg =  &vfe170_camif_reg,
+		.reg_data  =  &vfe_170_camif_reg_data,
+		},
+	.mux_type = {
+		CAM_VFE_CAMIF_VER_2_0,
+		CAM_VFE_RDI_VER_1_0,
+		CAM_VFE_RDI_VER_1_0,
+		CAM_VFE_RDI_VER_1_0,
+	},
+};
+
+static struct cam_irq_register_set vfe170_bus_irq_reg[3] = {
+		{
+			.mask_reg_offset   = 0x00002044,
+			.clear_reg_offset  = 0x00002050,
+			.status_reg_offset = 0x0000205C,
+		},
+		{
+			.mask_reg_offset   = 0x00002048,
+			.clear_reg_offset  = 0x00002054,
+			.status_reg_offset = 0x00002060,
+		},
+		{
+			.mask_reg_offset   = 0x0000204C,
+			.clear_reg_offset  = 0x00002058,
+			.status_reg_offset = 0x00002064,
+		},
+};
+
+static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = {
+	.tile_cfg         = 0x0000252C,
+	.h_init           = 0x00002530,
+	.v_init           = 0x00002534,
+	.meta_addr        = 0x00002538,
+	.meta_offset      = 0x0000253C,
+	.meta_stride      = 0x00002540,
+	.mode_cfg         = 0x00002544,
+};
+
+static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = {
+	.tile_cfg         = 0x0000262C,
+	.h_init           = 0x00002630,
+	.v_init           = 0x00002634,
+	.meta_addr        = 0x00002638,
+	.meta_offset      = 0x0000263C,
+	.meta_stride      = 0x00002640,
+	.mode_cfg         = 0x00002644,
+};
+
+static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = {
+	.common_reg = {
+		.hw_version                   = 0x00002000,
+		.hw_capability                = 0x00002004,
+		.sw_reset                     = 0x00002008,
+		.cgc_ovd                      = 0x0000200C,
+		.pwr_iso_cfg                  = 0x000020CC,
+		.dual_master_comp_cfg         = 0x00002028,
+		.irq_reg_info = {
+			.num_registers        = 3,
+			.irq_reg_set          = vfe170_bus_irq_reg,
+			.global_clear_offset  = 0x00002068,
+			.global_clear_bitmask = 0x00000001,
+		},
+		.comp_error_status            = 0x0000206C,
+		.comp_ovrwr_status            = 0x00002070,
+		.dual_comp_error_status       = 0x00002074,
+		.dual_comp_error_status       = 0x00002078,
+	},
+	.bus_client_reg = {
+		/* BUS Client 0 */
+		{
+			.status0                  = 0x00002200,
+			.status1                  = 0x00002204,
+			.cfg                      = 0x00002208,
+			.header_addr              = 0x0000220C,
+			.header_cfg               = 0x00002210,
+			.image_addr               = 0x00002214,
+			.image_addr_offset        = 0x00002218,
+			.buffer_width_cfg         = 0x0000221C,
+			.buffer_height_cfg        = 0x00002220,
+			.packer_cfg               = 0x00002224,
+			.stride                   = 0x00002228,
+			.irq_subsample_period     = 0x00002248,
+			.irq_subsample_pattern    = 0x0000224C,
+			.framedrop_period         = 0x00002250,
+			.framedrop_pattern        = 0x00002254,
+			.frame_inc                = 0x00002258,
+			.burst_limit              = 0x0000225C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 1 */
+		{
+			.status0                  = 0x00002300,
+			.status1                  = 0x00002304,
+			.cfg                      = 0x00002308,
+			.header_addr              = 0x0000230C,
+			.header_cfg               = 0x00002310,
+			.image_addr               = 0x00002314,
+			.image_addr_offset        = 0x00002318,
+			.buffer_width_cfg         = 0x0000231C,
+			.buffer_height_cfg        = 0x00002320,
+			.packer_cfg               = 0x00002324,
+			.stride                   = 0x00002328,
+			.irq_subsample_period     = 0x00002348,
+			.irq_subsample_pattern    = 0x0000234C,
+			.framedrop_period         = 0x00002350,
+			.framedrop_pattern        = 0x00002354,
+			.frame_inc                = 0x00002358,
+			.burst_limit              = 0x0000235C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 2 */
+		{
+			.status0                  = 0x00002400,
+			.status1                  = 0x00002404,
+			.cfg                      = 0x00002408,
+			.header_addr              = 0x0000240C,
+			.header_cfg               = 0x00002410,
+			.image_addr               = 0x00002414,
+			.image_addr_offset        = 0x00002418,
+			.buffer_width_cfg         = 0x0000241C,
+			.buffer_height_cfg        = 0x00002420,
+			.packer_cfg               = 0x00002424,
+			.stride                   = 0x00002428,
+			.irq_subsample_period     = 0x00002448,
+			.irq_subsample_pattern    = 0x0000244C,
+			.framedrop_period         = 0x00002450,
+			.framedrop_pattern        = 0x00002454,
+			.frame_inc                = 0x00002458,
+			.burst_limit              = 0x0000245C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 3 */
+		{
+			.status0                  = 0x00002500,
+			.status1                  = 0x00002504,
+			.cfg                      = 0x00002508,
+			.header_addr              = 0x0000250C,
+			.header_cfg               = 0x00002510,
+			.image_addr               = 0x00002514,
+			.image_addr_offset        = 0x00002518,
+			.buffer_width_cfg         = 0x0000251C,
+			.buffer_height_cfg        = 0x00002520,
+			.packer_cfg               = 0x00002524,
+			.stride                   = 0x00002528,
+			.irq_subsample_period     = 0x00002548,
+			.irq_subsample_pattern    = 0x0000254C,
+			.framedrop_period         = 0x00002550,
+			.framedrop_pattern        = 0x00002554,
+			.frame_inc                = 0x00002558,
+			.burst_limit              = 0x0000255C,
+			.ubwc_regs                = &ubwc_regs_client_3,
+		},
+		/* BUS Client 4 */
+		{
+			.status0                  = 0x00002600,
+			.status1                  = 0x00002604,
+			.cfg                      = 0x00002608,
+			.header_addr              = 0x0000260C,
+			.header_cfg               = 0x00002610,
+			.image_addr               = 0x00002614,
+			.image_addr_offset        = 0x00002618,
+			.buffer_width_cfg         = 0x0000261C,
+			.buffer_height_cfg        = 0x00002620,
+			.packer_cfg               = 0x00002624,
+			.stride                   = 0x00002628,
+			.irq_subsample_period     = 0x00002648,
+			.irq_subsample_pattern    = 0x0000264C,
+			.framedrop_period         = 0x00002650,
+			.framedrop_pattern        = 0x00002654,
+			.frame_inc                = 0x00002658,
+			.burst_limit              = 0x0000265C,
+			.ubwc_regs                = &ubwc_regs_client_4,
+		},
+		/* BUS Client 5 */
+		{
+			.status0                  = 0x00002700,
+			.status1                  = 0x00002704,
+			.cfg                      = 0x00002708,
+			.header_addr              = 0x0000270C,
+			.header_cfg               = 0x00002710,
+			.image_addr               = 0x00002714,
+			.image_addr_offset        = 0x00002718,
+			.buffer_width_cfg         = 0x0000271C,
+			.buffer_height_cfg        = 0x00002720,
+			.packer_cfg               = 0x00002724,
+			.stride                   = 0x00002728,
+			.irq_subsample_period     = 0x00002748,
+			.irq_subsample_pattern    = 0x0000274C,
+			.framedrop_period         = 0x00002750,
+			.framedrop_pattern        = 0x00002754,
+			.frame_inc                = 0x00002758,
+			.burst_limit              = 0x0000275C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 6 */
+		{
+			.status0                  = 0x00002800,
+			.status1                  = 0x00002804,
+			.cfg                      = 0x00002808,
+			.header_addr              = 0x0000280C,
+			.header_cfg               = 0x00002810,
+			.image_addr               = 0x00002814,
+			.image_addr_offset        = 0x00002818,
+			.buffer_width_cfg         = 0x0000281C,
+			.buffer_height_cfg        = 0x00002820,
+			.packer_cfg               = 0x00002824,
+			.stride                   = 0x00002828,
+			.irq_subsample_period     = 0x00002848,
+			.irq_subsample_pattern    = 0x0000284C,
+			.framedrop_period         = 0x00002850,
+			.framedrop_pattern        = 0x00002854,
+			.frame_inc                = 0x00002858,
+			.burst_limit              = 0x0000285C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 7 */
+		{
+			.status0                  = 0x00002900,
+			.status1                  = 0x00002904,
+			.cfg                      = 0x00002908,
+			.header_addr              = 0x0000290C,
+			.header_cfg               = 0x00002910,
+			.image_addr               = 0x00002914,
+			.image_addr_offset        = 0x00002918,
+			.buffer_width_cfg         = 0x0000291C,
+			.buffer_height_cfg        = 0x00002920,
+			.packer_cfg               = 0x00002924,
+			.stride                   = 0x00002928,
+			.irq_subsample_period     = 0x00002948,
+			.irq_subsample_pattern    = 0x0000294C,
+			.framedrop_period         = 0x00002950,
+			.framedrop_pattern        = 0x00002954,
+			.frame_inc                = 0x00002958,
+			.burst_limit              = 0x0000295C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 8 */
+		{
+			.status0                  = 0x00002A00,
+			.status1                  = 0x00002A04,
+			.cfg                      = 0x00002A08,
+			.header_addr              = 0x00002A0C,
+			.header_cfg               = 0x00002A10,
+			.image_addr               = 0x00002A14,
+			.image_addr_offset        = 0x00002A18,
+			.buffer_width_cfg         = 0x00002A1C,
+			.buffer_height_cfg        = 0x00002A20,
+			.packer_cfg               = 0x00002A24,
+			.stride                   = 0x00002A28,
+			.irq_subsample_period     = 0x00002A48,
+			.irq_subsample_pattern    = 0x00002A4C,
+			.framedrop_period         = 0x00002A50,
+			.framedrop_pattern        = 0x00002A54,
+			.frame_inc                = 0x00002A58,
+			.burst_limit              = 0x00002A5C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 9 */
+		{
+			.status0                  = 0x00002B00,
+			.status1                  = 0x00002B04,
+			.cfg                      = 0x00002B08,
+			.header_addr              = 0x00002B0C,
+			.header_cfg               = 0x00002B10,
+			.image_addr               = 0x00002B14,
+			.image_addr_offset        = 0x00002B18,
+			.buffer_width_cfg         = 0x00002B1C,
+			.buffer_height_cfg        = 0x00002B20,
+			.packer_cfg               = 0x00002B24,
+			.stride                   = 0x00002B28,
+			.irq_subsample_period     = 0x00002B48,
+			.irq_subsample_pattern    = 0x00002B4C,
+			.framedrop_period         = 0x00002B50,
+			.framedrop_pattern        = 0x00002B54,
+			.frame_inc                = 0x00002B58,
+			.burst_limit              = 0x00002B5C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 10 */
+		{
+			.status0                  = 0x00002C00,
+			.status1                  = 0x00002C04,
+			.cfg                      = 0x00002C08,
+			.header_addr              = 0x00002C0C,
+			.header_cfg               = 0x00002C10,
+			.image_addr               = 0x00002C14,
+			.image_addr_offset        = 0x00002C18,
+			.buffer_width_cfg         = 0x00002C1C,
+			.buffer_height_cfg        = 0x00002C20,
+			.packer_cfg               = 0x00002C24,
+			.stride                   = 0x00002C28,
+			.irq_subsample_period     = 0x00002C48,
+			.irq_subsample_pattern    = 0x00002C4C,
+			.framedrop_period         = 0x00002C50,
+			.framedrop_pattern        = 0x00002C54,
+			.frame_inc                = 0x00002C58,
+			.burst_limit              = 0x00002C5C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 11 */
+		{
+			.status0                  = 0x00002D00,
+			.status1                  = 0x00002D04,
+			.cfg                      = 0x00002D08,
+			.header_addr              = 0x00002D0C,
+			.header_cfg               = 0x00002D10,
+			.image_addr               = 0x00002D14,
+			.image_addr_offset        = 0x00002D18,
+			.buffer_width_cfg         = 0x00002D1C,
+			.buffer_height_cfg        = 0x00002D20,
+			.packer_cfg               = 0x00002D24,
+			.stride                   = 0x00002D28,
+			.irq_subsample_period     = 0x00002D48,
+			.irq_subsample_pattern    = 0x00002D4C,
+			.framedrop_period         = 0x00002D50,
+			.framedrop_pattern        = 0x00002D54,
+			.frame_inc                = 0x00002D58,
+			.burst_limit              = 0x00002D5C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 12 */
+		{
+			.status0                  = 0x00002E00,
+			.status1                  = 0x00002E04,
+			.cfg                      = 0x00002E08,
+			.header_addr              = 0x00002E0C,
+			.header_cfg               = 0x00002E10,
+			.image_addr               = 0x00002E14,
+			.image_addr_offset        = 0x00002E18,
+			.buffer_width_cfg         = 0x00002E1C,
+			.buffer_height_cfg        = 0x00002E20,
+			.packer_cfg               = 0x00002E24,
+			.stride                   = 0x00002E28,
+			.irq_subsample_period     = 0x00002E48,
+			.irq_subsample_pattern    = 0x00002E4C,
+			.framedrop_period         = 0x00002E50,
+			.framedrop_pattern        = 0x00002E54,
+			.frame_inc                = 0x00002E58,
+			.burst_limit              = 0x00002E5C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 13 */
+		{
+			.status0                  = 0x00002F00,
+			.status1                  = 0x00002F04,
+			.cfg                      = 0x00002F08,
+			.header_addr              = 0x00002F0C,
+			.header_cfg               = 0x00002F10,
+			.image_addr               = 0x00002F14,
+			.image_addr_offset        = 0x00002F18,
+			.buffer_width_cfg         = 0x00002F1C,
+			.buffer_height_cfg        = 0x00002F20,
+			.packer_cfg               = 0x00002F24,
+			.stride                   = 0x00002F28,
+			.irq_subsample_period     = 0x00002F48,
+			.irq_subsample_pattern    = 0x00002F4C,
+			.framedrop_period         = 0x00002F50,
+			.framedrop_pattern        = 0x00002F54,
+			.frame_inc                = 0x00002F58,
+			.burst_limit              = 0x00002F5C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 14 */
+		{
+			.status0                  = 0x00003000,
+			.status1                  = 0x00003004,
+			.cfg                      = 0x00003008,
+			.header_addr              = 0x0000300C,
+			.header_cfg               = 0x00003010,
+			.image_addr               = 0x00003014,
+			.image_addr_offset        = 0x00003018,
+			.buffer_width_cfg         = 0x0000301C,
+			.buffer_height_cfg        = 0x00003020,
+			.packer_cfg               = 0x00003024,
+			.stride                   = 0x00003028,
+			.irq_subsample_period     = 0x00003048,
+			.irq_subsample_pattern    = 0x0000304C,
+			.framedrop_period         = 0x00003050,
+			.framedrop_pattern        = 0x00003054,
+			.frame_inc                = 0x00003058,
+			.burst_limit              = 0x0000305C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 15 */
+		{
+			.status0                  = 0x00003100,
+			.status1                  = 0x00003104,
+			.cfg                      = 0x00003108,
+			.header_addr              = 0x0000310C,
+			.header_cfg               = 0x00003110,
+			.image_addr               = 0x00003114,
+			.image_addr_offset        = 0x00003118,
+			.buffer_width_cfg         = 0x0000311C,
+			.buffer_height_cfg        = 0x00003120,
+			.packer_cfg               = 0x00003124,
+			.stride                   = 0x00003128,
+			.irq_subsample_period     = 0x00003148,
+			.irq_subsample_pattern    = 0x0000314C,
+			.framedrop_period         = 0x00003150,
+			.framedrop_pattern        = 0x00003154,
+			.frame_inc                = 0x00003158,
+			.burst_limit              = 0x0000315C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 16 */
+		{
+			.status0                  = 0x00003200,
+			.status1                  = 0x00003204,
+			.cfg                      = 0x00003208,
+			.header_addr              = 0x0000320C,
+			.header_cfg               = 0x00003210,
+			.image_addr               = 0x00003214,
+			.image_addr_offset        = 0x00003218,
+			.buffer_width_cfg         = 0x0000321C,
+			.buffer_height_cfg        = 0x00003220,
+			.packer_cfg               = 0x00003224,
+			.stride                   = 0x00003228,
+			.irq_subsample_period     = 0x00003248,
+			.irq_subsample_pattern    = 0x0000324C,
+			.framedrop_period         = 0x00003250,
+			.framedrop_pattern        = 0x00003254,
+			.frame_inc                = 0x00003258,
+			.burst_limit              = 0x0000325C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 17 */
+		{
+			.status0                  = 0x00003300,
+			.status1                  = 0x00003304,
+			.cfg                      = 0x00003308,
+			.header_addr              = 0x0000330C,
+			.header_cfg               = 0x00003310,
+			.image_addr               = 0x00003314,
+			.image_addr_offset        = 0x00003318,
+			.buffer_width_cfg         = 0x0000331C,
+			.buffer_height_cfg        = 0x00003320,
+			.packer_cfg               = 0x00003324,
+			.stride                   = 0x00003328,
+			.irq_subsample_period     = 0x00003348,
+			.irq_subsample_pattern    = 0x0000334C,
+			.framedrop_period         = 0x00003350,
+			.framedrop_pattern        = 0x00003354,
+			.frame_inc                = 0x00003358,
+			.burst_limit              = 0x0000335C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 18 */
+		{
+			.status0                  = 0x00003400,
+			.status1                  = 0x00003404,
+			.cfg                      = 0x00003408,
+			.header_addr              = 0x0000340C,
+			.header_cfg               = 0x00003410,
+			.image_addr               = 0x00003414,
+			.image_addr_offset        = 0x00003418,
+			.buffer_width_cfg         = 0x0000341C,
+			.buffer_height_cfg        = 0x00003420,
+			.packer_cfg               = 0x00003424,
+			.stride                   = 0x00003428,
+			.irq_subsample_period     = 0x00003448,
+			.irq_subsample_pattern    = 0x0000344C,
+			.framedrop_period         = 0x00003450,
+			.framedrop_pattern        = 0x00003454,
+			.frame_inc                = 0x00003458,
+			.burst_limit              = 0x0000345C,
+			.ubwc_regs                = NULL,
+		},
+		/* BUS Client 19 */
+		{
+			.status0                  = 0x00003500,
+			.status1                  = 0x00003504,
+			.cfg                      = 0x00003508,
+			.header_addr              = 0x0000350C,
+			.header_cfg               = 0x00003510,
+			.image_addr               = 0x00003514,
+			.image_addr_offset        = 0x00003518,
+			.buffer_width_cfg         = 0x0000351C,
+			.buffer_height_cfg        = 0x00003520,
+			.packer_cfg               = 0x00003524,
+			.stride                   = 0x00003528,
+			.irq_subsample_period     = 0x00003548,
+			.irq_subsample_pattern    = 0x0000354C,
+			.framedrop_period         = 0x00003550,
+			.framedrop_pattern        = 0x00003554,
+			.frame_inc                = 0x00003558,
+			.burst_limit              = 0x0000355C,
+			.ubwc_regs                = NULL,
+		},
+	},
+	.comp_grp_reg = {
+		/* CAM_VFE_BUS_VER2_COMP_GRP_0 */
+		{
+			.comp_mask                    = 0x00002010,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_1 */
+		{
+			.comp_mask                    = 0x00002014,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_2 */
+		{
+			.comp_mask                    = 0x00002018,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_3 */
+		{
+			.comp_mask                    = 0x0000201C,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_4 */
+		{
+			.comp_mask                    = 0x00002020,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_5 */
+		{
+			.comp_mask                    = 0x00002024,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */
+		{
+			.comp_mask                    = 0x0000202C,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */
+		{
+			.comp_mask                    = 0x00002030,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */
+		{
+			.comp_mask                    = 0x00002034,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */
+		{
+			.comp_mask                    = 0x00002038,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */
+		{
+			.comp_mask                    = 0x0000203C,
+		},
+		/* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */
+		{
+			.comp_mask                    = 0x00002040,
+		},
+	},
+	.vfe_out_hw_info = {
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_FULL,
+			.max_width     = 4096,
+			.max_height    = 4096,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_DS4,
+			.max_width     = 1920,
+			.max_height    = 1080,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_DS16,
+			.max_width     = 1920,
+			.max_height    = 1080,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_FD,
+			.max_width     = 1920,
+			.max_height    = 1080,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_PDAF,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_RDI0,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_RDI1,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  = CAM_VFE_BUS_VER2_VFE_OUT_RDI2,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST,
+			.max_width     = 1920,
+			.max_height    = 1080,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+		{
+			.vfe_out_type  =
+				CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST,
+			.max_width     = -1,
+			.max_height    = -1,
+		},
+	},
+};
+
+struct cam_vfe_hw_info cam_vfe170_hw_info = {
+	.irq_reg_info                  = &vfe170_top_irq_reg_info,
+
+	.bus_version                   = CAM_VFE_BUS_VER_2_0,
+	.bus_hw_info                   = &vfe170_bus_hw_info,
+
+	.top_version                   = CAM_VFE_TOP_VER_2_0,
+	.top_hw_info                   = &vfe170_top_hw_info,
+
+	.camif_version                 = CAM_VFE_CAMIF_VER_2_0,
+	.camif_reg                     = &vfe170_camif_reg,
+
+};
+
+#endif /* _CAM_VFE170_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile
new file mode 100644
index 0000000..cea1137
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile
@@ -0,0 +1,10 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c
new file mode 100644
index 0000000..50952f8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include "cam_vfe_bus.h"
+#include "cam_vfe_bus_ver1.h"
+#include "cam_vfe_bus_ver2.h"
+
+int cam_vfe_bus_init(uint32_t          bus_version,
+	void __iomem                  *mem_base,
+	struct cam_hw_intf            *hw_intf,
+	void                          *bus_hw_info,
+	void                          *vfe_irq_controller,
+	struct cam_vfe_bus            **vfe_bus)
+{
+	int rc = -ENODEV;
+
+	switch (bus_version) {
+	case CAM_VFE_BUS_VER_2_0:
+		rc = cam_vfe_bus_ver2_init(mem_base, hw_intf, bus_hw_info,
+			vfe_irq_controller, vfe_bus);
+		break;
+	default:
+		pr_err("Unsupported Bus Version %x\n", bus_version);
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h
new file mode 100644
index 0000000..3572451
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_BUS_VER1_H_
+#define _CAM_VFE_BUS_VER1_H_
+
+enum cam_vfe_bus_ver1_pingpong_id {
+	CAM_VFE_BUS_VER1_PING,
+	CAM_VFE_BUS_VER1_PONG,
+	CAM_VFE_BUS_VER1_PINGPONG_MAX,
+};
+
+enum cam_vfe_bus_ver1_wm_type {
+	CAM_VFE_BUS_WM_TYPE_IMAGE,
+	CAM_VFE_BUS_WM_TYPE_STATS,
+	CAM_VFE_BUS_WM_TYPE_MAX,
+};
+
+enum cam_vfe_bus_ver1_comp_grp_type {
+	CAM_VFE_BUS_VER1_COMP_GRP_IMG0,
+	CAM_VFE_BUS_VER1_COMP_GRP_IMG1,
+	CAM_VFE_BUS_VER1_COMP_GRP_IMG2,
+	CAM_VFE_BUS_VER1_COMP_GRP_IMG3,
+	CAM_VFE_BUS_VER1_COMP_GRP_STATS0,
+	CAM_VFE_BUS_VER1_COMP_GRP_STATS1,
+	CAM_VFE_BUS_VER1_COMP_GRP_MAX,
+};
+
+struct cam_vfe_bus_ver1_common_reg {
+	uint32_t cmd_offset;
+	uint32_t cfg_offset;
+	uint32_t io_fmt_offset;
+	uint32_t argb_cfg_offset;
+	uint32_t xbar_cfg0_offset;
+	uint32_t xbar_cfg1_offset;
+	uint32_t xbar_cfg2_offset;
+	uint32_t xbar_cfg3_offset;
+	uint32_t ping_pong_status_reg;
+};
+
+struct cam_vfe_bus_ver1_wm_reg {
+	uint32_t wm_cfg_offset;
+	uint32_t ping_addr_offset;
+	uint32_t ping_max_addr_offset;
+	uint32_t pong_addr_offset;
+	uint32_t pong_max_addr_offset;
+	uint32_t addr_cfg_offset;
+	uint32_t ub_cfg_offset;
+	uint32_t image_size_offset;
+	uint32_t buffer_cfg_offset;
+	uint32_t framedrop_pattern_offset;
+	uint32_t irq_subsample_pattern_offset;
+	uint32_t ping_pong_status_bit; /* 0 - 31 */
+	uint32_t composite_bit; /* 0 -31 */
+};
+
+struct cam_vfe_bus_ver1_wm_resource_data {
+	uint32_t             index;
+	uint32_t             wm_type;
+	uint32_t             res_type;
+
+	uint32_t             offset;
+	uint32_t             width;
+	uint32_t             height;
+	uint32_t             stride;
+	uint32_t             scanline;
+
+	uint32_t             burst_len;
+
+	uint32_t             framedrop_period;
+	uint32_t             framedrop_pattern;
+
+	uint32_t             buf_valid[CAM_VFE_BUS_VER1_PINGPONG_MAX];
+	uint32_t             ub_size;
+	uint32_t             ub_offset;
+
+	struct cam_vfe_bus_ver1_wm_reg  hw_regs;
+};
+
+struct cam_vfe_bus_ver1_comp_grp_reg {
+	enum cam_vfe_bus_ver1_comp_grp_type comp_grp_type;
+	uint32_t             comp_grp_offset;
+};
+
+struct cam_vfe_bus_ver1_comp_grp {
+	struct cam_vfe_bus_ver1_comp_grp_reg reg_info;
+	struct list_head     wm_list;
+	uint32_t             cur_bit_mask;
+};
+
+/*
+ * cam_vfe_bus_ver1_init()
+ *
+ * @Brief:                   Initialize Bus layer
+ *
+ * @mem_base:                Mapped base address of register space
+ * @hw_intf:                 HW Interface of HW to which this resource belongs
+ * @bus_hw_info:             BUS HW info that contains details of BUS registers
+ * @vfe_irq_controller:      VFE IRQ Controller to use for subscribing to Top
+ *                           level IRQs
+ * @vfe_bus:                 Pointer to vfe_bus structure which will be filled
+ *                           and returned on successful initialize
+ */
+int cam_vfe_bus_ver1_init(
+	void __iomem                         *mem_base,
+	struct cam_hw_intf                   *hw_intf,
+	void                                 *bus_hw_info,
+	void                                 *vfe_irq_controller,
+	struct cam_vfe_bus                  **vfe_bus);
+
+#endif /* _CAM_VFE_BUS_VER1_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
new file mode 100644
index 0000000..48b0363
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -0,0 +1,1718 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/ratelimit.h>
+#include <linux/slab.h>
+#include "cam_io_util.h"
+#include "cam_cdm_util.h"
+#include "cam_hw_intf.h"
+#include "cam_vfe_hw_intf.h"
+#include "cam_irq_controller.h"
+#include "cam_vfe_bus.h"
+#include "cam_vfe_bus_ver2.h"
+#include "cam_vfe_core.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static uint32_t irq_reg_offset[CAM_IFE_BUS_IRQ_REGISTERS_MAX] = {
+	0x0000205C,
+	0x00002060,
+	0x00002064,
+	0x0000206C,
+	0x00002070,
+	0x00002074,
+	0x00002078,
+};
+
+enum cam_vfe_bus_packer_format {
+	PACKER_FMT_PLAIN_128                   = 0x0,
+	PACKER_FMT_PLAIN_8                     = 0x1,
+	PACKER_FMT_PLAIN_16_10BPP              = 0x2,
+	PACKER_FMT_PLAIN_16_12BPP              = 0x3,
+	PACKER_FMT_PLAIN_16_14BPP              = 0x4,
+	PACKER_FMT_PLAIN_16_16BPP              = 0x5,
+	PACKER_FMT_ARGB_10                     = 0x6,
+	PACKER_FMT_ARGB_12                     = 0x7,
+	PACKER_FMT_ARGB_14                     = 0x8,
+	PACKER_FMT_PLAIN_32_20BPP              = 0x9,
+	PACKER_FMT_PLAIN_64                    = 0xA,
+	PACKER_FMT_TP_10                       = 0xB,
+	PACKER_FMT_PLAIN_32_32BPP              = 0xC,
+	PACKER_FMT_PLAIN_8_ODD_EVEN            = 0xD,
+	PACKER_FMT_PLAIN_8_LSB_MSB_10          = 0xE,
+	PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF,
+	PACKER_FMT_MAX                         = 0xF,
+};
+
+struct cam_vfe_bus_ver2_common_data {
+	void __iomem                               *mem_base;
+	struct cam_hw_intf                         *hw_intf;
+	void                                       *bus_irq_controller;
+	void                                       *vfe_irq_controller;
+	struct cam_vfe_bus_ver2_reg_offset_common  *common_reg;
+};
+
+struct cam_vfe_bus_ver2_wm_resource_data {
+	uint32_t             index;
+	struct cam_vfe_bus_ver2_common_data            *common_data;
+	struct cam_vfe_bus_ver2_reg_offset_bus_client  *hw_regs;
+
+	uint32_t             irq_enabled;
+
+	uint32_t             offset;
+	uint32_t             width;
+	uint32_t             height;
+	uint32_t             stride;
+	uint32_t             format;
+	enum cam_vfe_bus_packer_format pack_fmt;
+
+	uint32_t             burst_len;
+	uint32_t             frame_based;
+
+	uint32_t             irq_subsample_period;
+	uint32_t             irq_subsample_pattern;
+	uint32_t             framedrop_period;
+	uint32_t             framedrop_pattern;
+};
+
+struct cam_vfe_bus_ver2_comp_grp_data {
+	enum cam_vfe_bus_ver2_comp_grp_type          comp_grp_type;
+	struct cam_vfe_bus_ver2_common_data         *common_data;
+	struct cam_vfe_bus_ver2_reg_offset_comp_grp *hw_regs;
+
+	uint32_t                         irq_enabled;
+	uint32_t                         comp_grp_local_idx;
+	uint32_t                         unique_id;
+
+	uint32_t                         is_master;
+	uint32_t                         dual_slave_core;
+	uint32_t                         intra_client_mask;
+	uint32_t                         composite_mask;
+};
+
+struct cam_vfe_bus_ver2_vfe_out_data {
+	uint32_t                              out_type;
+	struct cam_vfe_bus_ver2_common_data  *common_data;
+
+	uint32_t                         num_wm;
+	struct cam_isp_resource_node    *wm_res[PLANE_MAX];
+
+	struct cam_isp_resource_node    *comp_grp;
+	enum cam_isp_hw_sync_mode        dual_comp_sync_mode;
+	uint32_t                         dual_hw_alternate_vfe_id;
+	struct list_head                 vfe_out_list;
+
+	uint32_t                         format;
+	uint32_t                         max_width;
+	uint32_t                         max_height;
+	struct cam_cdm_utils_ops        *cdm_util_ops;
+};
+
+
+struct cam_vfe_bus_ver2_priv {
+	struct cam_vfe_bus_ver2_common_data common_data;
+
+	struct cam_isp_resource_node  bus_client[CAM_VFE_BUS_VER2_MAX_CLIENTS];
+	struct cam_isp_resource_node  comp_grp[CAM_VFE_BUS_VER2_COMP_GRP_MAX];
+	struct cam_isp_resource_node  vfe_out[CAM_VFE_BUS_VER2_VFE_OUT_MAX];
+
+	struct list_head                    free_comp_grp;
+	struct list_head                    free_dual_comp_grp;
+	struct list_head                    used_comp_grp;
+
+	struct cam_vfe_bus_irq_evt_payload  evt_payload[128];
+	struct list_head                    free_payload_list;
+};
+
+static int cam_vfe_bus_put_evt_payload(void     *core_info,
+	struct cam_vfe_bus_irq_evt_payload     **evt_payload);
+
+static int cam_vfe_bus_ver2_get_intra_client_mask(
+	enum cam_vfe_bus_ver2_vfe_core_id  dual_slave_core,
+	enum cam_vfe_bus_ver2_vfe_core_id  current_core,
+	uint32_t                          *intra_client_mask)
+{
+	int rc = 0;
+
+	*intra_client_mask = 0;
+
+	if (dual_slave_core == current_core) {
+		pr_err("Invalid params. Same core as Master and Slave\n");
+		return -EINVAL;
+	}
+
+	switch (current_core) {
+	case CAM_VFE_BUS_VER2_VFE_CORE_0:
+		switch (dual_slave_core) {
+		case CAM_VFE_BUS_VER2_VFE_CORE_1:
+			*intra_client_mask = 0x1;
+			break;
+		case CAM_VFE_BUS_VER2_VFE_CORE_2:
+			*intra_client_mask = 0x2;
+			break;
+		default:
+			pr_err("Invalid value for slave core %u\n",
+				dual_slave_core);
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_CORE_1:
+		switch (dual_slave_core) {
+		case CAM_VFE_BUS_VER2_VFE_CORE_0:
+			*intra_client_mask = 0x1;
+			break;
+		case CAM_VFE_BUS_VER2_VFE_CORE_2:
+			*intra_client_mask = 0x2;
+			break;
+		default:
+			pr_err("Invalid value for slave core %u\n",
+				dual_slave_core);
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_CORE_2:
+		switch (dual_slave_core) {
+		case CAM_VFE_BUS_VER2_VFE_CORE_0:
+			*intra_client_mask = 0x1;
+			break;
+		case CAM_VFE_BUS_VER2_VFE_CORE_1:
+			*intra_client_mask = 0x2;
+			break;
+		default:
+			pr_err("Invalid value for slave core %u\n",
+				dual_slave_core);
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	default:
+		pr_err("Invalid value for master core %u\n", current_core);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static enum cam_vfe_bus_ver2_vfe_out_type
+	cam_vfe_bus_get_out_res_id(uint32_t res_type)
+{
+	switch (res_type) {
+	case CAM_ISP_IFE_OUT_RES_FULL:
+		return CAM_VFE_BUS_VER2_VFE_OUT_FULL;
+	case CAM_ISP_IFE_OUT_RES_DS4:
+		return CAM_VFE_BUS_VER2_VFE_OUT_DS4;
+	case CAM_ISP_IFE_OUT_RES_DS16:
+		return CAM_VFE_BUS_VER2_VFE_OUT_DS16;
+	case CAM_ISP_IFE_OUT_RES_FD:
+		return CAM_VFE_BUS_VER2_VFE_OUT_FD;
+	case CAM_ISP_IFE_OUT_RES_RAW_DUMP:
+		return CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP;
+	case CAM_ISP_IFE_OUT_RES_PDAF:
+		return CAM_VFE_BUS_VER2_VFE_OUT_PDAF;
+	case CAM_ISP_IFE_OUT_RES_RDI_0:
+		return CAM_VFE_BUS_VER2_VFE_OUT_RDI0;
+	case CAM_ISP_IFE_OUT_RES_RDI_1:
+		return CAM_VFE_BUS_VER2_VFE_OUT_RDI1;
+	case CAM_ISP_IFE_OUT_RES_RDI_2:
+		return CAM_VFE_BUS_VER2_VFE_OUT_RDI2;
+	case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE;
+	case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST;
+	case CAM_ISP_IFE_OUT_RES_STATS_TL_BG:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG;
+	case CAM_ISP_IFE_OUT_RES_STATS_BF:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF;
+	case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG;
+	case CAM_ISP_IFE_OUT_RES_STATS_BHIST:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST;
+	case CAM_ISP_IFE_OUT_RES_STATS_RS:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS;
+	case CAM_ISP_IFE_OUT_RES_STATS_CS:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS;
+	case CAM_ISP_IFE_OUT_RES_STATS_IHIST:
+		return CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST;
+	default:
+		return CAM_VFE_BUS_VER2_VFE_OUT_MAX;
+	}
+}
+
+static int cam_vfe_bus_get_num_wm(
+	enum cam_vfe_bus_ver2_vfe_out_type    res_type,
+	uint32_t                              format)
+{
+	switch (res_type) {
+	case CAM_VFE_BUS_VER2_VFE_OUT_RDI0:
+	case CAM_VFE_BUS_VER2_VFE_OUT_RDI1:
+	case CAM_VFE_BUS_VER2_VFE_OUT_RDI2:
+		switch (format) {
+		case CAM_FORMAT_MIPI_RAW_8:
+		case CAM_FORMAT_MIPI_RAW_10:
+		case CAM_FORMAT_MIPI_RAW_12:
+		case CAM_FORMAT_MIPI_RAW_14:
+		case CAM_FORMAT_MIPI_RAW_16:
+		case CAM_FORMAT_MIPI_RAW_20:
+		case CAM_FORMAT_PLAIN128:
+			return 1;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_FULL:
+		switch (format) {
+		case CAM_FORMAT_NV21:
+		case CAM_FORMAT_NV12:
+		case CAM_FORMAT_MIPI_RAW_8:
+		case CAM_FORMAT_PLAIN8:
+		case CAM_FORMAT_TP10:
+		case CAM_FORMAT_UBWC_NV12:
+		case CAM_FORMAT_UBWC_NV12_4R:
+		case CAM_FORMAT_UBWC_TP10:
+		case CAM_FORMAT_UBWC_P010:
+			return 2;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_FD:
+		switch (format) {
+		case CAM_FORMAT_NV21:
+		case CAM_FORMAT_NV12:
+		case CAM_FORMAT_PLAIN8:
+		case CAM_FORMAT_TP10:
+		case CAM_FORMAT_PLAIN16_10:
+			return 2;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_DS4:
+	case CAM_VFE_BUS_VER2_VFE_OUT_DS16:
+		switch (format) {
+		case CAM_FORMAT_PD8:
+		case CAM_FORMAT_PD10:
+			return 1;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP:
+		switch (format) {
+		case CAM_FORMAT_ARGB_14:
+		case CAM_FORMAT_PLAIN8:
+		case CAM_FORMAT_PLAIN16_10:
+		case CAM_FORMAT_PLAIN16_12:
+		case CAM_FORMAT_PLAIN16_14:
+			return 1;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_PDAF:
+		switch (format) {
+		case CAM_FORMAT_PLAIN8:
+		case CAM_FORMAT_PLAIN16_10:
+		case CAM_FORMAT_PLAIN16_12:
+		case CAM_FORMAT_PLAIN16_14:
+			return 1;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS:
+		switch (format) {
+		case CAM_FORMAT_PLAIN64:
+			return 1;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS:
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST:
+		switch (format) {
+		case CAM_FORMAT_PLAIN16_16:
+			return 1;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	pr_err("Unsupported format %u for resource_type %u", format, res_type);
+
+	return -EINVAL;
+}
+
+static int cam_vfe_bus_get_wm_idx(
+	enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id,
+	enum cam_vfe_bus_plane_type plane)
+{
+	int wm_idx = -1;
+
+	switch (vfe_out_res_id) {
+	case CAM_VFE_BUS_VER2_VFE_OUT_FULL:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 3;
+			break;
+		case PLANE_C:
+			wm_idx = 4;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_DS4:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 5;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_DS16:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 6;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_FD:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 7;
+			break;
+		case PLANE_C:
+			wm_idx = 8;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 9;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_PDAF:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 10;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_RDI0:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 0;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_RDI1:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 1;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_RDI2:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 2;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 11;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 12;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 13;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 14;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 15;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 16;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 17;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 18;
+			break;
+		default:
+			break;
+		}
+		break;
+	case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST:
+		switch (plane) {
+		case PLANE_Y:
+			wm_idx = 19;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return wm_idx;
+}
+
+static enum cam_vfe_bus_packer_format
+	cam_vfe_bus_get_packer_fmt(uint32_t out_fmt)
+{
+	switch (out_fmt) {
+	case CAM_FORMAT_NV21:
+	case CAM_FORMAT_NV12:
+		return PACKER_FMT_PLAIN_8;
+	default:
+		return PACKER_FMT_MAX;
+	}
+}
+
+static int cam_vfe_bus_acquire_wm(
+	struct cam_vfe_bus_ver2_priv          *ver2_bus_priv,
+	struct cam_isp_out_port_info          *out_port_info,
+	enum cam_vfe_bus_ver2_vfe_out_type     vfe_out_res_id,
+	enum cam_vfe_bus_plane_type            plane,
+	enum cam_isp_hw_split_id               split_id,
+	uint32_t                               subscribe_irq,
+	struct cam_isp_resource_node         **wm_res,
+	uint32_t                              *client_done_mask)
+{
+	uint32_t wm_idx = 0;
+	struct cam_isp_resource_node              *wm_res_local = NULL;
+	struct cam_vfe_bus_ver2_wm_resource_data  *rsrc_data = NULL;
+
+	*wm_res = NULL;
+	*client_done_mask = 0;
+
+	/* No need to allocate for BUS VER2. VFE OUT to WM is fixed. */
+	wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, plane);
+	if (wm_idx < 0 || wm_idx >= CAM_VFE_BUS_VER2_MAX_CLIENTS) {
+		pr_err("Unsupported VFE out %d plane %d\n",
+			vfe_out_res_id, plane);
+		return -EINVAL;
+	}
+
+	wm_res_local = &ver2_bus_priv->bus_client[wm_idx];
+	wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+
+	rsrc_data = wm_res_local->res_priv;
+	rsrc_data->irq_enabled = subscribe_irq;
+	rsrc_data->format = out_port_info->format;
+	rsrc_data->pack_fmt = cam_vfe_bus_get_packer_fmt(rsrc_data->format);
+
+	rsrc_data->width = out_port_info->width;
+	rsrc_data->height = out_port_info->height;
+	if (plane == PLANE_C) {
+		switch (rsrc_data->format) {
+		case CAM_FORMAT_NV21:
+		case CAM_FORMAT_NV12:
+			rsrc_data->height /= 2;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (vfe_out_res_id >= CAM_ISP_IFE_OUT_RES_RDI_0 &&
+		vfe_out_res_id <= CAM_ISP_IFE_OUT_RES_RDI_3)
+		rsrc_data->frame_based = 1;
+
+	*client_done_mask = (1 << wm_idx);
+	*wm_res = wm_res_local;
+
+	return 0;
+}
+
+static int cam_vfe_bus_release_wm(void   *bus_priv,
+	struct cam_isp_resource_node     *wm_res)
+{
+	struct cam_vfe_bus_ver2_wm_resource_data   *rsrc_data =
+		wm_res->res_priv;
+
+	rsrc_data->irq_enabled = 0;
+	rsrc_data->offset = 0;
+	rsrc_data->width = 0;
+	rsrc_data->height = 0;
+	rsrc_data->stride = 0;
+	rsrc_data->format = 0;
+	rsrc_data->pack_fmt = 0;
+	rsrc_data->burst_len = 0;
+	rsrc_data->frame_based = 0;
+	rsrc_data->irq_subsample_period = 0;
+	rsrc_data->irq_subsample_pattern = 0;
+	rsrc_data->framedrop_period = 0;
+	rsrc_data->framedrop_pattern = 0;
+
+	wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+
+	return 0;
+}
+
+static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res)
+{
+	int rc = 0;
+	struct cam_vfe_bus_ver2_wm_resource_data   *rsrc_data =
+		wm_res->res_priv;
+	struct cam_vfe_bus_ver2_common_data        *common_data =
+		rsrc_data->common_data;
+
+	CDBG("WM res %d width = %d, height = %d\n", rsrc_data->index,
+		rsrc_data->width, rsrc_data->height);
+	CDBG("WM res %d pk_fmt = %d\n", rsrc_data->index,
+		rsrc_data->pack_fmt & PACKER_FMT_MAX);
+	CDBG("WM res %d stride = %d, burst len = %d\n",
+		rsrc_data->index, rsrc_data->width, 0xf);
+
+	cam_io_w_mb(0,
+		common_data->mem_base + rsrc_data->hw_regs->header_addr);
+	cam_io_w_mb(0,
+		common_data->mem_base + rsrc_data->hw_regs->header_cfg);
+	cam_io_w_mb(0,
+		common_data->mem_base + rsrc_data->hw_regs->frame_inc);
+	cam_io_w_mb(rsrc_data->width,
+		common_data->mem_base + rsrc_data->hw_regs->buffer_width_cfg);
+	cam_io_w(rsrc_data->height,
+		common_data->mem_base + rsrc_data->hw_regs->buffer_height_cfg);
+	cam_io_w(0xe,
+		common_data->mem_base + rsrc_data->hw_regs->packer_cfg);
+	cam_io_w(rsrc_data->width,
+		common_data->mem_base + rsrc_data->hw_regs->stride);
+	cam_io_w(0xf,
+		common_data->mem_base + rsrc_data->hw_regs->burst_limit);
+
+	cam_io_w(0xFFFFFFFF, common_data->mem_base +
+		rsrc_data->hw_regs->irq_subsample_pattern);
+	cam_io_w(0x0, common_data->mem_base +
+		rsrc_data->hw_regs->irq_subsample_period);
+
+	cam_io_w(0xFFFFFFFF,
+	 common_data->mem_base + rsrc_data->hw_regs->framedrop_pattern);
+	cam_io_w(0x0,
+	 common_data->mem_base + rsrc_data->hw_regs->framedrop_period);
+
+	/* UBWC registers */
+	switch (rsrc_data->format) {
+	case CAM_FORMAT_UBWC_NV12:
+		/* Program UBWC registers */
+		break;
+	default:
+		break;
+	}
+
+	/* Subscribe IRQ */
+	if (rsrc_data->irq_enabled) {
+		/*
+		 * Currently all WM IRQ are subscribed in one place. Need to
+		 * make it dynamic later.
+		 */
+	}
+
+	/* Enable WM */
+	cam_io_w_mb(0x1,
+		common_data->mem_base + rsrc_data->hw_regs->cfg);
+	CDBG("enable WM red %d offset 0x%x val 0x%x\n", rsrc_data->index,
+		(uint32_t) rsrc_data->hw_regs->cfg, 0x1);
+
+	wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
+	return rc;
+}
+
+static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res)
+{
+	int rc = 0;
+	struct cam_vfe_bus_ver2_wm_resource_data   *rsrc_data =
+		wm_res->res_priv;
+	struct cam_vfe_bus_ver2_common_data        *common_data =
+		rsrc_data->common_data;
+
+	/* Disble WM */
+	cam_io_w_mb(0x0,
+		common_data->mem_base + rsrc_data->hw_regs->cfg);
+
+	CDBG("irq_enabled %d", rsrc_data->irq_enabled);
+	/* Unsubscribe IRQ */
+	if (rsrc_data->irq_enabled) {
+		/*
+		 * Currently all WM IRQ are unsubscribed in one place. Need to
+		 * make it dynamic.
+		 */
+	}
+
+	/* Halt & Reset WM */
+	cam_io_w_mb(BIT(rsrc_data->index),
+		common_data->mem_base + common_data->common_reg->sw_reset);
+
+	wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+
+	return rc;
+}
+
+static int cam_vfe_bus_handle_wm_done_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	return -EPERM;
+}
+
+static int cam_vfe_bus_handle_wm_done_bottom_half(void *wm_node,
+	void *evt_payload_priv)
+{
+	int rc = CAM_VFE_IRQ_STATUS_ERR;
+	struct cam_isp_resource_node          *wm_res = wm_node;
+	struct cam_vfe_bus_irq_evt_payload    *evt_payload = evt_payload_priv;
+	struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = wm_res->res_priv;
+	uint32_t  *cam_ife_irq_regs = evt_payload->irq_reg_val;
+	uint32_t   status_reg;
+
+	status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0];
+
+	if (status_reg & BIT(rsrc_data->index))
+		rc = CAM_VFE_IRQ_STATUS_SUCCESS;
+
+	if (rc == CAM_VFE_IRQ_STATUS_SUCCESS)
+		cam_vfe_bus_put_evt_payload(evt_payload->core_info,
+			&evt_payload);
+
+	return rc;
+}
+
+static int cam_vfe_bus_init_wm_resource(uint32_t index,
+	struct cam_vfe_bus_ver2_priv    *ver2_bus_priv,
+	struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
+	struct cam_isp_resource_node    *wm_res)
+{
+	int rc = 0;
+	struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data;
+
+	rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_wm_resource_data),
+		GFP_KERNEL);
+	if (!rsrc_data) {
+		CDBG("Failed to alloc for wm res priv\n");
+		rc = -ENOMEM;
+		return rc;
+	}
+	wm_res->res_priv = rsrc_data;
+
+	rsrc_data->index = index;
+	rsrc_data->hw_regs = &ver2_hw_info->bus_client_reg[index];
+	rsrc_data->common_data = &ver2_bus_priv->common_data;
+
+	wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+	INIT_LIST_HEAD(&wm_res->list);
+
+	wm_res->start = cam_vfe_bus_start_wm;
+	wm_res->stop = cam_vfe_bus_stop_wm;
+	wm_res->top_half_handler = cam_vfe_bus_handle_wm_done_top_half;
+	wm_res->bottom_half_handler = cam_vfe_bus_handle_wm_done_bottom_half;
+	wm_res->hw_intf = ver2_bus_priv->common_data.hw_intf;
+
+	return rc;
+}
+
+static void cam_vfe_bus_add_wm_to_comp_grp(
+	struct cam_isp_resource_node    *comp_grp,
+	uint32_t                         composite_mask)
+{
+	struct cam_vfe_bus_ver2_comp_grp_data  *rsrc_data = comp_grp->res_priv;
+
+	rsrc_data->composite_mask |= composite_mask;
+}
+
+static void cam_vfe_bus_match_comp_grp(
+	struct cam_vfe_bus_ver2_priv  *ver2_bus_priv,
+	struct cam_isp_resource_node **comp_grp,
+	uint32_t                       comp_grp_local_idx,
+	uint32_t                       unique_id)
+{
+	struct cam_vfe_bus_ver2_comp_grp_data  *rsrc_data = NULL;
+	struct cam_isp_resource_node           *comp_grp_local = NULL;
+
+	list_for_each_entry(comp_grp_local,
+		&ver2_bus_priv->used_comp_grp, list) {
+		rsrc_data = comp_grp_local->res_priv;
+		if (rsrc_data->comp_grp_local_idx == comp_grp_local_idx &&
+			rsrc_data->unique_id == unique_id) {
+			/* Match found */
+			*comp_grp = comp_grp_local;
+			return;
+		}
+	}
+
+	*comp_grp = NULL;
+}
+
+static int cam_vfe_bus_acquire_comp_grp(
+	struct cam_vfe_bus_ver2_priv        *ver2_bus_priv,
+	struct cam_isp_out_port_info        *out_port_info,
+	uint32_t                             unique_id,
+	uint32_t                             is_dual,
+	uint32_t                             is_master,
+	enum cam_vfe_bus_ver2_vfe_core_id    dual_slave_core,
+	struct cam_isp_resource_node       **comp_grp)
+{
+	int rc = 0;
+	struct cam_isp_resource_node           *comp_grp_local = NULL;
+	struct cam_vfe_bus_ver2_comp_grp_data  *rsrc_data = NULL;
+
+	/* Check if matching comp_grp already acquired */
+	cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local,
+		out_port_info->comp_grp_id, unique_id);
+
+	if (!comp_grp_local) {
+		/* First find a free group */
+		if (is_dual) {
+			if (list_empty(&ver2_bus_priv->free_dual_comp_grp)) {
+				pr_err("No Free Composite Group\n");
+				return -ENODEV;
+			}
+			comp_grp_local = list_first_entry(
+				&ver2_bus_priv->free_dual_comp_grp,
+				struct cam_isp_resource_node, list);
+			rsrc_data = comp_grp_local->res_priv;
+			rc = cam_vfe_bus_ver2_get_intra_client_mask(
+				dual_slave_core,
+				comp_grp_local->hw_intf->hw_idx,
+				&rsrc_data->intra_client_mask);
+		} else {
+			if (list_empty(&ver2_bus_priv->free_comp_grp)) {
+				pr_err("No Free Composite Group\n");
+				return -ENODEV;
+			}
+			comp_grp_local = list_first_entry(
+				&ver2_bus_priv->free_comp_grp,
+				struct cam_isp_resource_node, list);
+			rsrc_data = comp_grp_local->res_priv;
+		}
+
+		list_del(&comp_grp_local->list);
+		comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+
+		rsrc_data->is_master = is_master;
+		rsrc_data->composite_mask = 0;
+		rsrc_data->unique_id = unique_id;
+		rsrc_data->comp_grp_local_idx = out_port_info->comp_grp_id;
+
+		list_add_tail(&comp_grp_local->list,
+			&ver2_bus_priv->used_comp_grp);
+
+	} else {
+		rsrc_data = comp_grp_local->res_priv;
+		/* Do not support runtime change in composite mask */
+		if (comp_grp_local->res_state ==
+			CAM_ISP_RESOURCE_STATE_STREAMING) {
+			pr_err("Invalid State %d Comp Grp %u\n",
+				comp_grp_local->res_state,
+				rsrc_data->comp_grp_type);
+			return -EBUSY;
+		}
+	}
+
+	*comp_grp = comp_grp_local;
+
+	return rc;
+}
+
+static int cam_vfe_bus_release_comp_grp(
+	struct cam_vfe_bus_ver2_priv         *ver2_bus_priv,
+	struct cam_isp_resource_node         *in_comp_grp)
+{
+	struct cam_isp_resource_node           *comp_grp = NULL;
+	struct cam_vfe_bus_ver2_comp_grp_data  *in_rsrc_data = NULL;
+	int match_found = 0;
+
+	if (!in_comp_grp) {
+		pr_err("Invalid Params Comp Grp %pK\n", in_rsrc_data);
+		return -EINVAL;
+	}
+
+	if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+		/* Already Released. Do Nothing */
+		return 0;
+	}
+
+	in_rsrc_data = in_comp_grp->res_priv;
+
+	list_for_each_entry(comp_grp, &ver2_bus_priv->used_comp_grp, list) {
+		if (comp_grp == in_comp_grp) {
+			match_found = 1;
+			break;
+		}
+	}
+
+	if (!match_found) {
+		pr_err("Could not find matching Comp Grp type %u\n",
+			in_rsrc_data->comp_grp_type);
+		return -ENODEV;
+	}
+
+
+	list_del(&comp_grp->list);
+	if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
+		in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
+		list_add_tail(&comp_grp->list,
+			&ver2_bus_priv->free_dual_comp_grp);
+	else if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0
+		&& in_rsrc_data->comp_grp_type <=
+		CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
+		list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp);
+
+	list_add_tail(&comp_grp->list,
+		&ver2_bus_priv->free_comp_grp);
+	in_rsrc_data->unique_id = 0;
+	in_rsrc_data->comp_grp_local_idx = 0;
+	in_rsrc_data->composite_mask = 0;
+	in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
+
+	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+
+	return -ENODEV;
+}
+
+static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp)
+{
+	int rc = 0;
+	struct cam_vfe_bus_ver2_comp_grp_data      *rsrc_data =
+		comp_grp->res_priv;
+	struct cam_vfe_bus_ver2_common_data        *common_data =
+		rsrc_data->common_data;
+
+	/*
+	 * Individual Comp_Grp Subscribe IRQ can be done here once
+	 * dynamic IRQ enable support is added.
+	 */
+	cam_io_w_mb(0x00001F70, common_data->mem_base + 0x2044);
+	cam_io_w_mb(0x000FFFE7, common_data->mem_base + 0x2048);
+	cam_io_w_mb(0x000000FF, common_data->mem_base + 0x204c);
+
+	cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base +
+		rsrc_data->hw_regs->comp_mask);
+
+	CDBG("composite_mask is 0x%x\n", rsrc_data->composite_mask);
+	CDBG("composite_mask addr 0x%x\n",  rsrc_data->hw_regs->comp_mask);
+
+	if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
+		rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 &&
+		rsrc_data->is_master) {
+		int dual_comp_grp = (rsrc_data->comp_grp_type -
+			CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0);
+		int intra_client_en = cam_io_r_mb(common_data->mem_base +
+			common_data->common_reg->dual_master_comp_cfg);
+
+		/* 2 Bits per comp_grp. Hence left shift by comp_grp * 2 */
+		intra_client_en |=
+			(rsrc_data->intra_client_mask << dual_comp_grp * 2);
+
+		cam_io_w_mb(intra_client_en, common_data->mem_base +
+			common_data->common_reg->dual_master_comp_cfg);
+	}
+
+	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+	return rc;
+}
+
+static int cam_vfe_bus_stop_comp_grp(struct cam_isp_resource_node *comp_grp)
+{
+	int rc = 0;
+	struct cam_vfe_bus_ver2_comp_grp_data      *rsrc_data =
+		comp_grp->res_priv;
+	struct cam_vfe_bus_ver2_common_data        *common_data =
+		rsrc_data->common_data;
+
+	/* Unsubscribe IRQ */
+
+	cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base +
+		rsrc_data->hw_regs->comp_mask);
+	if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
+		rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 &&
+		rsrc_data->is_master) {
+		int dual_comp_grp = (rsrc_data->comp_grp_type -
+			CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0);
+		int intra_client_en = cam_io_r_mb(common_data->mem_base +
+			common_data->common_reg->dual_master_comp_cfg);
+
+		/* 2 Bits per comp_grp. Hence left shift by comp_grp * 2 */
+		intra_client_en &=
+			~(rsrc_data->intra_client_mask << dual_comp_grp * 2);
+
+		cam_io_w_mb(intra_client_en, common_data->mem_base +
+			common_data->common_reg->dual_master_comp_cfg);
+	}
+
+	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+
+	return rc;
+}
+
+static int cam_vfe_bus_handle_comp_done_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	return -EPERM;
+}
+
+static int cam_vfe_bus_handle_comp_done_bottom_half(
+	void                *handler_priv,
+	void                *evt_payload_priv)
+{
+	int rc = CAM_VFE_IRQ_STATUS_ERR;
+	struct cam_isp_resource_node          *comp_grp = handler_priv;
+	struct cam_vfe_bus_irq_evt_payload    *evt_payload = evt_payload_priv;
+	struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = comp_grp->res_priv;
+	uint32_t  *cam_ife_irq_regs = evt_payload->irq_reg_val;
+	uint32_t   status_reg;
+	uint32_t   comp_err_reg;
+	uint32_t   dual_comp_grp;
+
+	CDBG("comp grp type %d\n", rsrc_data->comp_grp_type);
+	switch (rsrc_data->comp_grp_type) {
+	case CAM_VFE_BUS_VER2_COMP_GRP_0:
+	case CAM_VFE_BUS_VER2_COMP_GRP_1:
+	case CAM_VFE_BUS_VER2_COMP_GRP_2:
+	case CAM_VFE_BUS_VER2_COMP_GRP_3:
+	case CAM_VFE_BUS_VER2_COMP_GRP_4:
+	case CAM_VFE_BUS_VER2_COMP_GRP_5:
+		dual_comp_grp = (rsrc_data->comp_grp_type -
+			CAM_VFE_BUS_VER2_COMP_GRP_0);
+
+		/* Check for Regular composite error */
+		status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0];
+
+		comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_COMP_ERR];
+		if ((status_reg & BIT(11)) &&
+			(comp_err_reg & rsrc_data->composite_mask)) {
+			/* Check for Regular composite error */
+			rc = CAM_VFE_IRQ_STATUS_ERR_COMP;
+			break;
+		}
+
+		comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_COMP_OWRT];
+		/* Check for Regular composite Overwrite */
+		if ((status_reg & BIT(12)) &&
+			(comp_err_reg & rsrc_data->composite_mask)) {
+			rc = CAM_VFE_IRQ_STATUS_COMP_OWRT;
+			break;
+		}
+
+		/* Regular Composite SUCCESS*/
+		if (status_reg & BIT(dual_comp_grp + 5))
+			rc = CAM_VFE_IRQ_STATUS_SUCCESS;
+
+		CDBG("status reg = 0x%x, bit index = %d\n",
+			status_reg, (dual_comp_grp + 5));
+		break;
+
+	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0:
+	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1:
+	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2:
+	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3:
+	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4:
+	case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5:
+		dual_comp_grp = (rsrc_data->comp_grp_type -
+			CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0);
+
+		/* Check for DUAL composite error */
+		status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2];
+
+		comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_DUAL_COMP_ERR];
+		if ((status_reg & BIT(6)) &&
+			(comp_err_reg & rsrc_data->composite_mask)) {
+			/* Check for DUAL composite error */
+			rc = CAM_VFE_IRQ_STATUS_ERR_COMP;
+			break;
+		}
+
+		/* Check for Dual composite Overwrite */
+		comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_DUAL_COMP_OWRT];
+		if ((status_reg & BIT(7)) &&
+			(comp_err_reg & rsrc_data->composite_mask)) {
+			rc = CAM_VFE_IRQ_STATUS_COMP_OWRT;
+			break;
+		}
+
+		/* DUAL Composite SUCCESS*/
+		if (status_reg & BIT(dual_comp_grp))
+			rc = CAM_VFE_IRQ_STATUS_SUCCESS;
+
+		break;
+
+	default:
+		rc = CAM_VFE_IRQ_STATUS_ERR;
+		break;
+	}
+
+	if (rc == CAM_VFE_IRQ_STATUS_SUCCESS)
+		cam_vfe_bus_put_evt_payload(evt_payload->core_info,
+			&evt_payload);
+
+	return rc;
+}
+
+static int cam_vfe_bus_init_comp_grp(uint32_t index,
+	struct cam_vfe_bus_ver2_priv    *ver2_bus_priv,
+	struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
+	struct cam_isp_resource_node    *comp_grp)
+{
+	struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data =
+		comp_grp->res_priv;
+
+	rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_comp_grp_data),
+		GFP_KERNEL);
+	if (!rsrc_data) {
+		CDBG("Failed to alloc for comp_grp_priv\n");
+		return -ENOMEM;
+	}
+	comp_grp->res_priv = rsrc_data;
+
+	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+	INIT_LIST_HEAD(&comp_grp->list);
+
+	rsrc_data->comp_grp_type   = index;
+	rsrc_data->common_data     = &ver2_bus_priv->common_data;
+	rsrc_data->hw_regs         = &ver2_hw_info->comp_grp_reg[index];
+	rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
+
+
+	if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
+		rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
+		list_add_tail(&comp_grp->list,
+			&ver2_bus_priv->free_dual_comp_grp);
+	else if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0
+		&& rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)
+		list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp);
+
+	comp_grp->start = cam_vfe_bus_start_comp_grp;
+	comp_grp->stop = cam_vfe_bus_stop_comp_grp;
+	comp_grp->top_half_handler = cam_vfe_bus_handle_comp_done_top_half;
+	comp_grp->bottom_half_handler =
+		cam_vfe_bus_handle_comp_done_bottom_half;
+	comp_grp->hw_intf = ver2_bus_priv->common_data.hw_intf;
+
+	return 0;
+}
+
+static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args)
+{
+	int                                     rc = -ENODEV;
+	int                                     i;
+	enum cam_vfe_bus_ver2_vfe_out_type      vfe_out_res_id;
+	uint32_t                                format;
+	uint32_t                                num_wm;
+	uint32_t                                subscribe_irq;
+	uint32_t                                client_done_mask;
+	struct cam_vfe_bus_ver2_priv           *ver2_bus_priv = bus_priv;
+	struct cam_vfe_acquire_args            *acq_args = acquire_args;
+	struct cam_vfe_hw_vfe_out_acquire_args *out_acquire_args;
+	struct cam_isp_resource_node           *rsrc_node = NULL;
+	struct cam_vfe_bus_ver2_vfe_out_data   *rsrc_data = NULL;
+
+	if (!bus_priv || !acquire_args) {
+		pr_err("Invalid Param");
+		return -EINVAL;
+	}
+
+	out_acquire_args = &acq_args->vfe_out;
+	format = out_acquire_args->out_port_info->format;
+
+	CDBG("Acquiring resource type 0x%x\n",
+		out_acquire_args->out_port_info->res_type);
+
+	vfe_out_res_id = cam_vfe_bus_get_out_res_id(
+		out_acquire_args->out_port_info->res_type);
+	if (vfe_out_res_id == CAM_VFE_BUS_VER2_VFE_OUT_MAX)
+		return -ENODEV;
+
+	num_wm = cam_vfe_bus_get_num_wm(vfe_out_res_id, format);
+	if (num_wm < 1)
+		return -EINVAL;
+
+	rsrc_node = &ver2_bus_priv->vfe_out[vfe_out_res_id];
+	if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+		pr_err("Resource not available: Res_id %d state:%d\n",
+			vfe_out_res_id, rsrc_node->res_state);
+		return -EBUSY;
+	}
+
+	rsrc_data = rsrc_node->res_priv;
+	rsrc_data->num_wm = num_wm;
+	rsrc_node->res_id = out_acquire_args->out_port_info->res_type;
+	rsrc_node->tasklet_info = acq_args->tasklet;
+	rsrc_node->cdm_ops = out_acquire_args->cdm_ops;
+	rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops;
+
+	/* Reserve Composite Group */
+	if (num_wm > 1 || (out_acquire_args->out_port_info->comp_grp_id >
+		CAM_ISP_RES_COMP_GROUP_NONE &&
+		out_acquire_args->out_port_info->comp_grp_id <
+		CAM_ISP_RES_COMP_GROUP_ID_MAX)) {
+		rc = cam_vfe_bus_acquire_comp_grp(ver2_bus_priv,
+			out_acquire_args->out_port_info,
+			out_acquire_args->unique_id,
+			out_acquire_args->is_dual,
+			out_acquire_args->is_master,
+			out_acquire_args->dual_slave_core,
+			&rsrc_data->comp_grp);
+		if (rc < 0)
+			return rc;
+
+		subscribe_irq = 0;
+	} else
+		subscribe_irq = 1;
+
+	/* Reserve WM */
+	for (i = 0; i < num_wm; i++) {
+		rc = cam_vfe_bus_acquire_wm(ver2_bus_priv,
+			out_acquire_args->out_port_info,
+			vfe_out_res_id,
+			i,
+			out_acquire_args->split_id,
+			subscribe_irq,
+			&rsrc_data->wm_res[i],
+			&client_done_mask);
+		if (rc < 0)
+			goto release_wm;
+
+		if (rsrc_data->comp_grp)
+			cam_vfe_bus_add_wm_to_comp_grp(rsrc_data->comp_grp,
+				client_done_mask);
+	}
+
+	rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+	out_acquire_args->rsrc_node = rsrc_node;
+
+	CDBG("Acquire successful\n");
+	return rc;
+
+release_wm:
+	for (i--; i >= 0; i--)
+		cam_vfe_bus_release_wm(ver2_bus_priv, rsrc_data->wm_res[i]);
+
+	cam_vfe_bus_release_comp_grp(ver2_bus_priv,
+		rsrc_data->comp_grp);
+
+	return rc;
+}
+
+static int cam_vfe_bus_release_vfe_out(void *bus_priv,
+	struct cam_isp_resource_node        *vfe_out)
+{
+	if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
+		pr_err("Error! Invalid resource state:%d\n",
+			vfe_out->res_state);
+	}
+
+	if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED)
+		vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+
+	return 0;
+}
+
+static int cam_vfe_bus_start_vfe_out(struct cam_isp_resource_node *vfe_out)
+{
+	int rc = 0, i;
+	struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+
+	CDBG("Start resource index %d\n", rsrc_data->out_type);
+
+	if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
+		pr_err("Error! Invalid resource state:%d\n",
+			vfe_out->res_state);
+		return -EACCES;
+	}
+
+	for (i = 0; i < rsrc_data->num_wm; i++)
+		rc = cam_vfe_bus_start_wm(rsrc_data->wm_res[i]);
+
+	if (rsrc_data->comp_grp)
+		rc = cam_vfe_bus_start_comp_grp(rsrc_data->comp_grp);
+
+	/* VFE_MODULE_BUS_CGC_OVERRIDE */
+	cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x0000003C);
+	/* VFE_MODULE_COLOR_CGC_OVERRIDE */
+	cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x00000034);
+	/* VFE_MODULE_ZOOM_CGC_OVERRIDE */
+	cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x38);
+	/* VFE_MODULE_LENS_CGC_OVERRIDE */
+	cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x0000002C);
+	/* VFE_MODULE_STATS_CGC_OVERRIDE */
+	cam_io_w_mb(0xFFFFFFFF, rsrc_data->common_data->mem_base + 0x00000030);
+
+	/* BUS_WR_INPUT_IF_ADDR_SYNC_CFG */
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000207C);
+	/*  BUS_WR_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002080);
+	/* BUS_WR_INPUT_IF_ADDR_SYNC_NO_SYNC */
+	cam_io_w_mb(0xFFFFF, rsrc_data->common_data->mem_base + 0x00002084);
+	/* no clock gating at bus input */
+	cam_io_w_mb(0xFFFFF, rsrc_data->common_data->mem_base + 0x0000200C);
+	/*  BUS_WR_PWR_ISO_CFG */
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x000020CC);
+	/*  BUS_WR_TEST_BUS_CTRL */
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000211C);
+	/*  BUS_WR_INPUT_IF_ADDR_SYNC_0 */
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002088);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000208c);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002090);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002094);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x00002098);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x0000209c);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x000020a0);
+	cam_io_w_mb(0x0, rsrc_data->common_data->mem_base + 0x000020a4);
+
+	return rc;
+}
+
+static int cam_vfe_bus_stop_vfe_out(struct cam_isp_resource_node *vfe_out)
+{
+	int rc = 0, i;
+	struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+
+	if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE ||
+		vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
+		return rc;
+	}
+
+	if (rsrc_data->comp_grp)
+		rc = cam_vfe_bus_stop_comp_grp(rsrc_data->comp_grp);
+
+	for (i = 0; i < rsrc_data->num_wm; i++)
+		rc = cam_vfe_bus_stop_wm(rsrc_data->wm_res[i]);
+
+	vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
+	vfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+	return rc;
+}
+
+static int cam_vfe_bus_handle_vfe_out_done_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	return -EPERM;
+}
+
+static int cam_vfe_bus_handle_vfe_out_done_bottom_half(
+	void                *handler_priv,
+	void                *evt_payload_priv)
+{
+	int rc = -EINVAL;
+	struct cam_isp_resource_node         *vfe_out = handler_priv;
+	struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+
+	/*
+	 * If this resource has Composite Group then we only handle
+	 * Composite done. We acquire Composite if number of WM > 1.
+	 * So Else case is only one individual buf_done = WM[0].
+	 */
+	if (rsrc_data->comp_grp) {
+		rc = rsrc_data->comp_grp->bottom_half_handler(
+			rsrc_data->comp_grp, evt_payload_priv);
+	} else {
+		rc = rsrc_data->wm_res[0]->bottom_half_handler(
+			rsrc_data->comp_grp, evt_payload_priv);
+	}
+
+	return rc;
+}
+
+static int cam_vfe_bus_init_vfe_out_resource(uint32_t index,
+	struct cam_vfe_bus_ver2_priv    *ver2_bus_priv,
+	struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
+	struct cam_isp_resource_node    *vfe_out)
+{
+	struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL;
+	int rc = 0;
+
+	rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_vfe_out_data),
+		GFP_KERNEL);
+	if (!rsrc_data) {
+		CDBG("Error! Failed to alloc for vfe out priv\n");
+		rc = -ENOMEM;
+		return rc;
+	}
+	vfe_out->res_priv = rsrc_data;
+
+	vfe_out->res_type = CAM_ISP_RESOURCE_VFE_OUT;
+	vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+	INIT_LIST_HEAD(&vfe_out->list);
+
+	rsrc_data->out_type    = index;
+	rsrc_data->common_data = &ver2_bus_priv->common_data;
+	rsrc_data->max_width   =
+		ver2_hw_info->vfe_out_hw_info[index].max_width;
+	rsrc_data->max_height  =
+		ver2_hw_info->vfe_out_hw_info[index].max_height;
+
+	vfe_out->start = cam_vfe_bus_start_vfe_out;
+	vfe_out->stop = cam_vfe_bus_stop_vfe_out;
+	vfe_out->top_half_handler = cam_vfe_bus_handle_vfe_out_done_top_half;
+	vfe_out->bottom_half_handler =
+		cam_vfe_bus_handle_vfe_out_done_bottom_half;
+	vfe_out->hw_intf = ver2_bus_priv->common_data.hw_intf;
+
+	return 0;
+}
+
+static int cam_vfe_bus_get_evt_payload(
+	struct cam_vfe_bus_ver2_priv         *bus_priv,
+	struct cam_vfe_bus_irq_evt_payload  **evt_payload)
+{
+	if (list_empty(&bus_priv->free_payload_list)) {
+		pr_err("No free payload\n");
+		return -ENODEV;
+	}
+
+	*evt_payload = list_first_entry(&bus_priv->free_payload_list,
+		struct cam_vfe_bus_irq_evt_payload, list);
+	list_del_init(&(*evt_payload)->list);
+	return 0;
+}
+
+static int cam_vfe_bus_put_evt_payload(void     *core_info,
+	struct cam_vfe_bus_irq_evt_payload     **evt_payload)
+{
+	struct cam_vfe_bus_ver2_priv         *bus_priv = NULL;
+
+	if (!core_info) {
+		pr_err("Invalid param core_info NULL");
+		return -EINVAL;
+	}
+	if (*evt_payload == NULL) {
+		pr_err("No payload to put\n");
+		return -EINVAL;
+	}
+	bus_priv = (*evt_payload)->bus_priv;
+	list_add_tail(&(*evt_payload)->list, &bus_priv->free_payload_list);
+	*evt_payload = NULL;
+	return 0;
+}
+
+static int cam_vfe_bus_ver2_handle_irq(uint32_t    evt_id,
+	struct cam_irq_th_payload                 *th_payload)
+{
+	int32_t                                rc;
+	int                                    i;
+	struct cam_vfe_irq_handler_priv       *handler_priv;
+	struct cam_vfe_hw_core_info           *core_info;
+	struct cam_vfe_bus_irq_evt_payload    *evt_payload;
+	struct cam_vfe_bus                    *bus_info;
+	struct cam_vfe_bus_ver2_priv          *bus_priv;
+	struct cam_irq_controller_reg_info    *reg_info;
+
+	handler_priv = th_payload->handler_priv;
+	core_info    = handler_priv->core_info;
+	bus_info     = core_info->vfe_bus;
+	bus_priv     = bus_info->bus_priv;
+	reg_info     = &bus_priv->common_data.common_reg->irq_reg_info;
+
+	/*
+	 *  add reset ack handling here once supported.
+	 *  Just clear all the bus irq status registers and ignore the reset.
+	 */
+
+	CDBG("Enter\n");
+	rc  = cam_vfe_bus_get_evt_payload(bus_priv, &evt_payload);
+	if (rc) {
+		pr_err("No tasklet_cmd is free in queue\n");
+		return rc;
+	}
+
+	cam_isp_hw_get_timestamp(&evt_payload->ts);
+
+	evt_payload->core_index = handler_priv->core_index;
+	evt_payload->core_info  = handler_priv->core_info;
+	evt_payload->bus_priv   = bus_priv;
+	CDBG("core_idx %d, core_info %llx\n", handler_priv->core_index,
+			(uint64_t)handler_priv->core_info);
+
+	for (i = 0; i < CAM_IFE_BUS_IRQ_REGISTERS_MAX; i++) {
+		evt_payload->irq_reg_val[i] = cam_io_r(handler_priv->mem_base +
+			irq_reg_offset[i]);
+		CDBG("irq_status%d = 0x%x\n", i, evt_payload->irq_reg_val[i]);
+	}
+	for (i = 0; i <= CAM_IFE_IRQ_BUS_REG_STATUS2; i++) {
+		cam_io_w(evt_payload->irq_reg_val[i], handler_priv->mem_base +
+			reg_info->irq_reg_set[i].clear_reg_offset);
+		CDBG("Clear irq_status%d = 0x%x offset 0x%x\n", i,
+			evt_payload->irq_reg_val[i],
+			reg_info->irq_reg_set[i].clear_reg_offset);
+	}
+	cam_io_w(reg_info->global_clear_bitmask, handler_priv->mem_base +
+		reg_info->global_clear_offset);
+	CDBG("Global clear bitmask = 0x%x offset 0x%x\n",
+			reg_info->global_clear_bitmask,
+			reg_info->global_clear_offset);
+
+	th_payload->evt_payload_priv = evt_payload;
+
+	return rc;
+}
+
+static int cam_vfe_bus_update_buf(void *priv, void *cmd_args,
+	uint32_t arg_size)
+{
+	struct cam_vfe_bus_ver2_priv             *bus_priv;
+	struct cam_isp_hw_get_buf_update         *update_buf;
+	struct cam_vfe_bus_ver2_vfe_out_data     *vfe_out_data = NULL;
+	struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL;
+	uint32_t  reg_val_pair[6];
+	uint32_t i, size = 0;
+
+	/*
+	 * Need the entire buf io config so we can get the stride info
+	 * for the wm.
+	 */
+
+	bus_priv = (struct cam_vfe_bus_ver2_priv  *) priv;
+	update_buf =  (struct cam_isp_hw_get_buf_update *) cmd_args;
+
+	vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *)
+		update_buf->cdm.res->res_priv;
+
+	if (!vfe_out_data || !vfe_out_data->cdm_util_ops) {
+		pr_err("Failed! Invalid data\n");
+		return -EINVAL;
+	}
+
+	if (update_buf->num_buf < vfe_out_data->num_wm) {
+		pr_err("Failed! Invalid number buffers:%d required:%d\n",
+			update_buf->num_buf, vfe_out_data->num_wm);
+		return -ENOMEM;
+	}
+
+	size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(
+		vfe_out_data->num_wm);
+
+	/* cdm util returns dwords, need to convert to bytes */
+	if ((size * 4) > update_buf->cdm.size) {
+		pr_err("Failed! Buf size:%d insufficient, expected size:%d\n",
+			update_buf->cdm.size, size);
+		return -ENOMEM;
+	}
+
+	for (i = 0 ; i < vfe_out_data->num_wm; i++) {
+		wm_data = vfe_out_data->wm_res[i]->res_priv;
+		reg_val_pair[2 * i] = wm_data->hw_regs->image_addr;
+		reg_val_pair[2 * i + 1] = update_buf->image_buf[i];
+		CDBG("offset 0x%x, value 0x%llx\n",
+			wm_data->hw_regs->image_addr,
+			(uint64_t) update_buf->image_buf[i]);
+	}
+
+	vfe_out_data->cdm_util_ops->cdm_write_regrandom(
+		update_buf->cdm.cmd_buf_addr,
+		vfe_out_data->num_wm, reg_val_pair);
+	/* cdm util returns dwords, need to convert to bytes */
+	update_buf->cdm.used_bytes = size * 4;
+
+	return 0;
+}
+
+static int cam_vfe_bus_process_cmd(void *priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
+{
+	int rc = -EINVAL;
+
+	if (!priv || !cmd_args) {
+		pr_err_ratelimited("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	switch (cmd_type) {
+	case CAM_VFE_HW_CMD_GET_BUF_UPDATE:
+		rc = cam_vfe_bus_update_buf(priv, cmd_args, arg_size);
+		break;
+	default:
+		pr_err_ratelimited("Error! Invalid camif process command:%d\n",
+			cmd_type);
+		break;
+	}
+
+	return rc;
+}
+
+int cam_vfe_bus_ver2_init(
+	void __iomem                         *mem_base,
+	struct cam_hw_intf                   *hw_intf,
+	void                                 *bus_hw_info,
+	void                                 *vfe_irq_controller,
+	struct cam_vfe_bus                  **vfe_bus)
+{
+	int i, rc = 0;
+	struct cam_vfe_bus_ver2_priv    *bus_priv = NULL;
+	struct cam_vfe_bus              *vfe_bus_local;
+	struct cam_vfe_bus_ver2_hw_info *ver2_hw_info = bus_hw_info;
+
+	CDBG("Enter\n");
+
+	vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL);
+	if (!vfe_bus_local) {
+		CDBG("Failed to alloc for vfe_bus\n");
+		rc = -ENOMEM;
+		goto err_alloc_bus;
+	}
+
+	bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver2_priv),
+		GFP_KERNEL);
+	if (!bus_priv) {
+		CDBG("Failed to alloc for vfe_bus_priv\n");
+		rc = -ENOMEM;
+		goto err_alloc_priv;
+	}
+	vfe_bus_local->bus_priv = bus_priv;
+
+	bus_priv->common_data.mem_base           = mem_base;
+	bus_priv->common_data.hw_intf            = hw_intf;
+	bus_priv->common_data.vfe_irq_controller = vfe_irq_controller;
+	bus_priv->common_data.common_reg         = &ver2_hw_info->common_reg;
+
+	INIT_LIST_HEAD(&bus_priv->free_comp_grp);
+	INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp);
+	INIT_LIST_HEAD(&bus_priv->used_comp_grp);
+
+	for (i = 0; i < CAM_VFE_BUS_VER2_MAX_CLIENTS; i++) {
+		rc = cam_vfe_bus_init_wm_resource(i, bus_priv, bus_hw_info,
+			&bus_priv->bus_client[i]);
+		if (rc < 0) {
+			pr_err("Error! Init WM failed\n");
+			goto err_init_wm;
+		}
+	}
+
+	for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) {
+		rc = cam_vfe_bus_init_comp_grp(i, bus_priv, bus_hw_info,
+			&bus_priv->comp_grp[i]);
+		if (rc < 0) {
+			pr_err("Error! Init Comp Grp failed\n");
+			goto err_init_comp_grp;
+		}
+	}
+
+	for (i = 0; i < CAM_VFE_BUS_VER2_VFE_OUT_MAX; i++) {
+		rc = cam_vfe_bus_init_vfe_out_resource(i, bus_priv, bus_hw_info,
+			&bus_priv->vfe_out[i]);
+		if (rc < 0) {
+			pr_err("Error! Init VFE Out failed\n");
+			goto err_init_vfe_out;
+		}
+	}
+
+	INIT_LIST_HEAD(&bus_priv->free_payload_list);
+	for (i = 0; i < 128; i++) {
+		INIT_LIST_HEAD(&bus_priv->evt_payload[i].list);
+		list_add_tail(&bus_priv->evt_payload[i].list,
+			&bus_priv->free_payload_list);
+	}
+
+	vfe_bus_local->acquire_resource = cam_vfe_bus_acquire_vfe_out;
+	vfe_bus_local->release_resource = cam_vfe_bus_release_vfe_out;
+	vfe_bus_local->start_resource   = cam_vfe_bus_start_vfe_out;
+	vfe_bus_local->stop_resource    = cam_vfe_bus_stop_vfe_out;
+	vfe_bus_local->top_half_handler = cam_vfe_bus_ver2_handle_irq;
+	vfe_bus_local->bottom_half_handler = NULL;
+	vfe_bus_local->process_cmd      = cam_vfe_bus_process_cmd;
+
+	*vfe_bus = vfe_bus_local;
+
+	return rc;
+
+err_init_vfe_out:
+err_init_comp_grp:
+err_init_wm:
+	kfree(vfe_bus_local->bus_priv);
+err_alloc_priv:
+	kfree(vfe_bus_local);
+err_alloc_bus:
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h
new file mode 100644
index 0000000..e451174
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h
@@ -0,0 +1,188 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_BUS_VER2_H_
+#define _CAM_VFE_BUS_VER2_H_
+
+#include "cam_irq_controller.h"
+#include "cam_vfe_bus.h"
+
+#define CAM_VFE_BUS_VER2_MAX_CLIENTS 20
+
+enum cam_vfe_bus_ver2_vfe_core_id {
+	CAM_VFE_BUS_VER2_VFE_CORE_0,
+	CAM_VFE_BUS_VER2_VFE_CORE_1,
+	CAM_VFE_BUS_VER2_VFE_CORE_2,
+	CAM_VFE_BUS_VER2_VFE_CORE_MAX,
+};
+
+enum cam_vfe_bus_ver2_comp_grp_type {
+	CAM_VFE_BUS_VER2_COMP_GRP_0,
+	CAM_VFE_BUS_VER2_COMP_GRP_1,
+	CAM_VFE_BUS_VER2_COMP_GRP_2,
+	CAM_VFE_BUS_VER2_COMP_GRP_3,
+	CAM_VFE_BUS_VER2_COMP_GRP_4,
+	CAM_VFE_BUS_VER2_COMP_GRP_5,
+	CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0,
+	CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1,
+	CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2,
+	CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3,
+	CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4,
+	CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5,
+	CAM_VFE_BUS_VER2_COMP_GRP_MAX,
+};
+
+enum cam_vfe_bus_ver2_vfe_out_type {
+	CAM_VFE_BUS_VER2_VFE_OUT_FULL,
+	CAM_VFE_BUS_VER2_VFE_OUT_DS4,
+	CAM_VFE_BUS_VER2_VFE_OUT_DS16,
+	CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP,
+	CAM_VFE_BUS_VER2_VFE_OUT_FD,
+	CAM_VFE_BUS_VER2_VFE_OUT_PDAF,
+	CAM_VFE_BUS_VER2_VFE_OUT_RDI0,
+	CAM_VFE_BUS_VER2_VFE_OUT_RDI1,
+	CAM_VFE_BUS_VER2_VFE_OUT_RDI2,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS,
+	CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST,
+	CAM_VFE_BUS_VER2_VFE_OUT_MAX,
+};
+
+/*
+ * struct cam_vfe_bus_ver2_reg_offset_common:
+ *
+ * @Brief:        Common registers across all BUS Clients
+ */
+struct cam_vfe_bus_ver2_reg_offset_common {
+	uint32_t hw_version;
+	uint32_t hw_capability;
+	uint32_t sw_reset;
+	uint32_t cgc_ovd;
+	uint32_t pwr_iso_cfg;
+	uint32_t dual_master_comp_cfg;
+	struct cam_irq_controller_reg_info irq_reg_info;
+	uint32_t comp_error_status;
+	uint32_t comp_ovrwr_status;
+	uint32_t dual_comp_error_status;
+	uint32_t dual_comp_ovrwr_status;
+	uint32_t addr_sync_cfg;
+	uint32_t addr_syn_frame_hdr;
+	uint32_t addr_syn_no_sync;
+};
+
+/*
+ * struct cam_vfe_bus_ver2_reg_offset_ubwc_client:
+ *
+ * @Brief:        UBWC register offsets for BUS Clients
+ */
+struct cam_vfe_bus_ver2_reg_offset_ubwc_client {
+	uint32_t tile_cfg;
+	uint32_t h_init;
+	uint32_t v_init;
+	uint32_t meta_addr;
+	uint32_t meta_offset;
+	uint32_t meta_stride;
+	uint32_t mode_cfg;
+};
+
+/*
+ * struct cam_vfe_bus_ver2_reg_offset_bus_client:
+ *
+ * @Brief:        Register offsets for BUS Clients
+ */
+struct cam_vfe_bus_ver2_reg_offset_bus_client {
+	uint32_t status0;
+	uint32_t status1;
+	uint32_t cfg;
+	uint32_t header_addr;
+	uint32_t header_cfg;
+	uint32_t image_addr;
+	uint32_t image_addr_offset;
+	uint32_t buffer_width_cfg;
+	uint32_t buffer_height_cfg;
+	uint32_t packer_cfg;
+	uint32_t stride;
+	uint32_t irq_subsample_period;
+	uint32_t irq_subsample_pattern;
+	uint32_t framedrop_period;
+	uint32_t framedrop_pattern;
+	uint32_t frame_inc;
+	uint32_t burst_limit;
+	struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs;
+};
+
+/*
+ * struct cam_vfe_bus_ver2_reg_offset_comp_grp:
+ *
+ * @Brief:        Register offsets for Composite Group registers
+ */
+struct cam_vfe_bus_ver2_reg_offset_comp_grp {
+	uint32_t                            comp_mask;
+};
+
+/*
+ * struct cam_vfe_bus_ver2_vfe_out_hw_info:
+ *
+ * @Brief:        HW capability of VFE Bus Client
+ */
+struct cam_vfe_bus_ver2_vfe_out_hw_info {
+	enum cam_vfe_bus_ver2_vfe_out_type  vfe_out_type;
+	uint32_t                            max_width;
+	uint32_t                            max_height;
+};
+
+/*
+ * struct cam_vfe_bus_ver2_hw_info:
+ *
+ * @Brief:            HW register info for entire Bus
+ *
+ * @common_reg:       Common register details
+ * @bus_client_reg:   Bus client register info
+ * @comp_reg_grp:     Composite group register info
+ * @vfe_out_hw_info:  VFE output capability
+ */
+struct cam_vfe_bus_ver2_hw_info {
+	struct cam_vfe_bus_ver2_reg_offset_common  common_reg;
+	struct cam_vfe_bus_ver2_reg_offset_bus_client
+		bus_client_reg[CAM_VFE_BUS_VER2_MAX_CLIENTS];
+	struct cam_vfe_bus_ver2_reg_offset_comp_grp
+		comp_grp_reg[CAM_VFE_BUS_VER2_COMP_GRP_MAX];
+	struct cam_vfe_bus_ver2_vfe_out_hw_info
+		vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX];
+};
+
+/*
+ * cam_vfe_bus_ver2_init()
+ *
+ * @Brief:                   Initialize Bus layer
+ *
+ * @mem_base:                Mapped base address of register space
+ * @hw_intf:                 HW Interface of HW to which this resource belongs
+ * @bus_hw_info:             BUS HW info that contains details of BUS registers
+ * @vfe_irq_controller:      VFE IRQ Controller to use for subscribing to Top
+ *                           level IRQs
+ * @vfe_bus:                 Pointer to vfe_bus structure which will be filled
+ *                           and returned on successful initialize
+ */
+int cam_vfe_bus_ver2_init(void __iomem   *mem_base,
+	struct cam_hw_intf                   *hw_intf,
+	void                                 *bus_hw_info,
+	void                                 *vfe_irq_controller,
+	struct cam_vfe_bus                  **vfe_bus);
+
+#endif /* _CAM_VFE_BUS_VER2_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h
new file mode 100644
index 0000000..d202c13
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_BUS_H_
+#define _CAM_VFE_BUS_H_
+
+#include <uapi/media/cam_isp.h>
+#include "cam_isp_hw.h"
+
+#define CAM_VFE_BUS_VER_1_0 0x1000
+#define CAM_VFE_BUS_VER_2_0 0x2000
+
+enum cam_vfe_bus_plane_type {
+	PLANE_Y,
+	PLANE_C,
+	PLANE_MAX,
+};
+
+/*
+ * struct cam_vfe_bus:
+ *
+ * @Brief:                   Bus interface structure
+ *
+ * @bus_priv:                Private data of BUS
+ * @acquire_resource:        Function pointer for acquiring BUS output resource
+ * @release_resource:        Function pointer for releasing BUS resource
+ * @start_resource:          Function for starting BUS Output resource
+ * @stop_resource:           Function for stopping BUS Output resource
+ * @process_cmd:             Function to process commands specific to BUS
+ *                           resources
+ * @top_half_handler:        Top Half handler function
+ * @bottom_half_handler:     Bottom Half handler function
+ */
+struct cam_vfe_bus {
+	void               *bus_priv;
+
+	int (*acquire_resource)(void *bus_priv, void *acquire_args);
+	int (*release_resource)(void *bus_priv,
+		struct cam_isp_resource_node *vfe_out);
+	int (*start_resource)(struct cam_isp_resource_node *vfe_out);
+	int (*stop_resource)(struct cam_isp_resource_node *vfe_out);
+	int (*process_cmd)(void *priv, uint32_t cmd_type, void *cmd_args,
+		uint32_t arg_size);
+	CAM_IRQ_HANDLER_TOP_HALF       top_half_handler;
+	CAM_IRQ_HANDLER_BOTTOM_HALF    bottom_half_handler;
+};
+
+/*
+ * cam_vfe_bus_init()
+ *
+ * @Brief:                   Initialize Bus layer
+ *
+ * @bus_version:             Version of BUS to initialize
+ * @mem_base:                Mapped base address of register space
+ * @hw_intf:                 HW Interface of HW to which this resource belongs
+ * @bus_hw_info:             BUS HW info that contains details of BUS registers
+ * @vfe_irq_controller:      VFE IRQ Controller to use for subscribing to Top
+ *                           level IRQs
+ * @vfe_bus:                 Pointer to vfe_bus structure which will be filled
+ *                           and returned on successful initialize
+ */
+int cam_vfe_bus_init(uint32_t          bus_version,
+	void __iomem                  *mem_base,
+	struct cam_hw_intf            *hw_intf,
+	void                          *bus_hw_info,
+	void                          *vfe_irq_controller,
+	struct cam_vfe_bus            **vfe_bus);
+
+#endif /* _CAM_VFE_BUS_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
new file mode 100644
index 0000000..56dc513
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
@@ -0,0 +1,10 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
new file mode 100644
index 0000000..ff56115
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -0,0 +1,257 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include <uapi/media/cam_isp.h>
+#include "cam_io_util.h"
+#include "cam_isp_hw_mgr_intf.h"
+#include "cam_vfe_hw_intf.h"
+#include "cam_vfe_top.h"
+#include "cam_vfe_top_ver2.h"
+#include "cam_vfe_camif_ver2.h"
+
+#undef  CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_vfe_mux_camif_data {
+	void __iomem                                *mem_base;
+	struct cam_hw_intf                          *hw_intf;
+	struct cam_vfe_camif_ver2_reg               *camif_reg;
+	struct cam_vfe_top_ver2_reg_offset_common   *common_reg;
+	struct cam_vfe_camif_reg_data               *reg_data;
+
+	enum cam_isp_hw_sync_mode          sync_mode;
+	uint32_t                           pix_pattern;
+	uint32_t                           first_pixel;
+	uint32_t                           first_line;
+	uint32_t                           last_pixel;
+	uint32_t                           last_line;
+};
+
+static int cam_vfe_camif_validate_pix_pattern(uint32_t pattern)
+{
+	int rc;
+
+	switch (pattern) {
+	case CAM_ISP_PATTERN_BAYER_RGRGRG:
+	case CAM_ISP_PATTERN_BAYER_GRGRGR:
+	case CAM_ISP_PATTERN_BAYER_BGBGBG:
+	case CAM_ISP_PATTERN_BAYER_GBGBGB:
+	case CAM_ISP_PATTERN_YUV_YCBYCR:
+	case CAM_ISP_PATTERN_YUV_YCRYCB:
+	case CAM_ISP_PATTERN_YUV_CBYCRY:
+	case CAM_ISP_PATTERN_YUV_CRYCBY:
+		rc = 0;
+		break;
+	default:
+		pr_err("Error! Invalid pix pattern:%d\n", pattern);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int cam_vfe_camif_ver2_acquire_resource(
+	struct cam_isp_resource_node  *camif_res,
+	void                          *acquire_param)
+{
+	struct cam_vfe_mux_camif_data      *camif_data;
+	struct cam_vfe_acquire_args        *acquire_data;
+
+	int rc = 0;
+
+	camif_data   = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
+	acquire_data = (struct cam_vfe_acquire_args   *)acquire_param;
+
+	rc = cam_vfe_camif_validate_pix_pattern(
+			acquire_data->vfe_in.in_port->test_pattern);
+	if (rc)
+		return rc;
+
+	camif_data->sync_mode   = acquire_data->vfe_in.sync_mode;
+	camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern;
+	camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start;
+	camif_data->last_pixel  = acquire_data->vfe_in.in_port->left_stop;
+	camif_data->first_line  = acquire_data->vfe_in.in_port->line_start;
+	camif_data->last_line   = acquire_data->vfe_in.in_port->line_stop;
+
+	return rc;
+}
+
+static int cam_vfe_camif_resource_start(
+	struct cam_isp_resource_node        *camif_res)
+{
+	struct cam_vfe_mux_camif_data       *rsrc_data;
+	uint32_t                             val = 0;
+
+	if (!camif_res) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	if (camif_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
+		pr_err("Error! Invalid camif res res_state:%d\n",
+			camif_res->res_state);
+		return -EINVAL;
+	}
+
+	rsrc_data = (struct cam_vfe_mux_camif_data  *)camif_res->res_priv;
+
+	/*config vfe core*/
+	val = (rsrc_data->pix_pattern <<
+			rsrc_data->reg_data->pixel_pattern_shift);
+	cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg);
+
+	cam_io_w_mb(0x00400040, rsrc_data->mem_base +
+		rsrc_data->camif_reg->camif_config);
+	cam_io_w_mb(0x1, rsrc_data->mem_base +
+			rsrc_data->camif_reg->line_skip_pattern);
+	cam_io_w_mb(0x1, rsrc_data->mem_base +
+			rsrc_data->camif_reg->pixel_skip_pattern);
+	cam_io_w_mb(0x0, rsrc_data->mem_base +
+			rsrc_data->camif_reg->skip_period);
+	cam_io_w_mb(0x1, rsrc_data->mem_base +
+			rsrc_data->camif_reg->irq_subsample_pattern);
+
+	/* epoch config with 20 line  */
+	cam_io_w_mb(0x00140014,
+		rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq);
+
+	camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+
+	/* Reg Update */
+	cam_io_w_mb(0x1, rsrc_data->mem_base + 0x4AC);
+
+	CDBG("Exit\n");
+	return 0;
+}
+
+
+static int cam_vfe_camif_resource_stop(
+	struct cam_isp_resource_node        *camif_res)
+{
+	struct cam_vfe_mux_camif_data       *camif_priv;
+	struct cam_vfe_camif_ver2_reg       *camif_reg;
+	int rc = 0;
+
+	if (!camif_res) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED ||
+		camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)
+		return 0;
+
+	camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
+	camif_reg = camif_priv->camif_reg;
+
+	if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING)
+		camif_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
+
+	return rc;
+}
+
+int cam_vfe_camif_process_cmd(void *priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
+{
+	return -EPERM;
+}
+
+static int cam_vfe_camif_handle_irq_top_half(uint32_t evt_id,
+	struct cam_irq_th_payload *th_payload)
+{
+	return -EPERM;
+}
+
+static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv,
+	void *evt_payload_priv)
+{
+	int                                   ret = CAM_VFE_IRQ_STATUS_ERR;
+	struct cam_isp_resource_node         *camif_node;
+	struct cam_vfe_mux_camif_data        *camif_priv;
+	struct cam_vfe_top_irq_evt_payload   *payload;
+	uint32_t                              irq_status0;
+
+	if (!handler_priv || !evt_payload_priv)
+		return ret;
+
+	camif_node = handler_priv;
+	camif_priv = camif_node->res_priv;
+	payload = evt_payload_priv;
+	irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0];
+
+	CDBG("event ID:%d\n", payload->evt_id);
+	CDBG("irq_status_0 = %x\n", irq_status0);
+
+	switch (payload->evt_id) {
+	case CAM_ISP_HW_EVENT_SOF:
+		if (irq_status0 & camif_priv->reg_data->sof_irq_mask) {
+			CDBG("Received SOF\n");
+			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
+		}
+		break;
+	case CAM_ISP_HW_EVENT_EPOCH:
+		if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) {
+			CDBG("Received EPOCH\n");
+			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
+		}
+		cam_vfe_put_evt_payload(payload->core_info, &payload);
+		break;
+	case CAM_ISP_HW_EVENT_REG_UPDATE:
+		if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) {
+			CDBG("Received REG_UPDATE_ACK\n");
+			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
+		}
+		break;
+	default:
+		break;
+	}
+
+	CDBG("returing status = %d\n", ret);
+	return ret;
+}
+
+int cam_vfe_camif_ver2_init(
+	struct cam_hw_intf            *hw_intf,
+	struct cam_hw_soc_info        *soc_info,
+	void                          *camif_hw_info,
+	struct cam_isp_resource_node  *camif_node)
+{
+	struct cam_vfe_mux_camif_data     *camif_priv = NULL;
+	struct cam_vfe_camif_ver2_hw_info *camif_info = camif_hw_info;
+
+	camif_priv = kzalloc(sizeof(struct cam_vfe_mux_camif_data),
+			GFP_KERNEL);
+	if (!camif_priv) {
+		CDBG("Error! Failed to alloc for camif_priv\n");
+		return -ENOMEM;
+	}
+
+	camif_node->res_priv = camif_priv;
+
+	camif_priv->mem_base   = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base;
+	camif_priv->camif_reg  = camif_info->camif_reg;
+	camif_priv->common_reg = camif_info->common_reg;
+	camif_priv->reg_data   = camif_info->reg_data;
+	camif_priv->hw_intf    = hw_intf;
+
+	camif_node->start = cam_vfe_camif_resource_start;
+	camif_node->stop  = cam_vfe_camif_resource_stop;
+	camif_node->top_half_handler = cam_vfe_camif_handle_irq_top_half;
+	camif_node->bottom_half_handler = cam_vfe_camif_handle_irq_bottom_half;
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h
new file mode 100644
index 0000000..cc6aab0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_CAMIF_VER2_H_
+#define _CAM_VFE_CAMIF_VER2_H_
+
+#include "cam_isp_hw.h"
+#include "cam_vfe_top.h"
+
+struct cam_vfe_camif_ver2_reg {
+	uint32_t     camif_cmd;
+	uint32_t     camif_config;
+	uint32_t     line_skip_pattern;
+	uint32_t     pixel_skip_pattern;
+	uint32_t     skip_period;
+	uint32_t     irq_subsample_pattern;
+	uint32_t     epoch_irq;
+	uint32_t     raw_crop_width_cfg;
+	uint32_t     raw_crop_height_cfg;
+	uint32_t     reg_update_cmd;
+};
+
+struct cam_vfe_camif_reg_data {
+	uint32_t     raw_crop_first_pixel_shift;
+	uint32_t     raw_crop_first_pixel_mask;
+
+	uint32_t     raw_crop_last_pixel_shift;
+	uint32_t     raw_crop_last_pixel_mask;
+
+	uint32_t     raw_crop_first_line_shift;
+	uint32_t     raw_crop_first_line_mask;
+
+	uint32_t     raw_crop_last_line_shift;
+	uint32_t     raw_crop_last_line_mask;
+
+	uint32_t     input_mux_sel_shift;
+	uint32_t     input_mux_sel_mask;
+	uint32_t     extern_reg_update_shift;
+	uint32_t     extern_reg_update_mask;
+
+	uint32_t     pixel_pattern_shift;
+	uint32_t     pixel_pattern_mask;
+
+	uint32_t     epoch_line_cfg;
+	uint32_t     sof_irq_mask;
+	uint32_t     epoch0_irq_mask;
+	uint32_t     reg_update_irq_mask;
+};
+
+struct cam_vfe_camif_ver2_hw_info {
+	struct cam_vfe_top_ver2_reg_offset_common   *common_reg;
+	struct cam_vfe_camif_ver2_reg               *camif_reg;
+	struct cam_vfe_camif_reg_data               *reg_data;
+};
+
+int cam_vfe_camif_ver2_acquire_resource(
+	struct cam_isp_resource_node  *camif_res,
+	void                          *acquire_param);
+
+int cam_vfe_camif_process_cmd(void *priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size);
+
+int cam_vfe_camif_ver2_init(
+	struct cam_hw_intf            *hw_intf,
+	struct cam_hw_soc_info        *soc_info,
+	void                          *camif_hw_info,
+	struct cam_isp_resource_node  *camif_node);
+
+#endif /* _CAM_VFE_CAMIF_VER2_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c
new file mode 100644
index 0000000..e2bceb8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include "cam_vfe_top.h"
+#include "cam_vfe_top_ver2.h"
+
+int cam_vfe_top_init(uint32_t          top_version,
+	struct cam_hw_soc_info        *soc_info,
+	struct cam_hw_intf            *hw_intf,
+	void                          *top_hw_info,
+	struct cam_vfe_top            **vfe_top)
+{
+	int rc = -EINVAL;
+
+	switch (top_version) {
+	case CAM_VFE_TOP_VER_2_0:
+		rc = cam_vfe_top_ver2_init(soc_info, hw_intf, top_hw_info,
+			vfe_top);
+		break;
+	default:
+		pr_err("Error! Unsupported Version %x\n", top_version);
+		break;
+	}
+
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
new file mode 100644
index 0000000..4fa5e98
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -0,0 +1,419 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include "cam_io_util.h"
+#include "cam_cdm_util.h"
+#include "cam_vfe_hw_intf.h"
+#include "cam_vfe_top.h"
+#include "cam_vfe_top_ver2.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_vfe_top_ver2_common_data {
+	struct cam_hw_soc_info                     *soc_info;
+	struct cam_hw_intf                         *hw_intf;
+	struct cam_vfe_top_ver2_reg_offset_common  *common_reg;
+};
+
+struct cam_vfe_top_ver2_priv {
+	struct cam_vfe_top_ver2_common_data common_data;
+	struct cam_vfe_camif               *camif;
+	struct cam_isp_resource_node        mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX];
+};
+
+static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	uint32_t                          size = 0;
+	uint32_t                          mem_base = 0;
+	struct cam_isp_hw_get_cdm_args   *cdm_args  = cmd_args;
+	struct cam_cdm_utils_ops         *cdm_util_ops = NULL;
+
+	if (arg_size != sizeof(struct cam_isp_hw_get_cdm_args)) {
+		pr_err("Error! Invalid cmd size\n");
+		return -EINVAL;
+	}
+
+	if (!cdm_args || !cdm_args->res || !top_priv ||
+		!top_priv->common_data.soc_info) {
+		pr_err("Error! Invalid args\n");
+		return -EINVAL;
+	}
+
+	cdm_util_ops =
+		(struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops;
+
+	if (!cdm_util_ops) {
+		pr_err("Invalid CDM ops\n");
+		return -EINVAL;
+	}
+
+	size = cdm_util_ops->cdm_required_size_changebase();
+	/* since cdm returns dwords, we need to convert it into bytes */
+	if ((size * 4) > cdm_args->size) {
+		pr_err("buf size:%d is not sufficient, expected: %d\n",
+			cdm_args->size, size);
+		return -EINVAL;
+	}
+
+	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(
+		top_priv->common_data.soc_info, VFE_CORE_BASE_IDX);
+	CDBG("core %d mem_base 0x%x\n", top_priv->common_data.soc_info->index,
+		mem_base);
+
+	cdm_util_ops->cdm_write_changebase(cdm_args->cmd_buf_addr, mem_base);
+	cdm_args->used_bytes = (size * 4);
+
+	return 0;
+}
+
+static int cam_vfe_top_mux_get_reg_update(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	uint32_t                          size = 0;
+	uint32_t                          reg_val_pair[2];
+	struct cam_isp_hw_get_cdm_args   *cdm_args = cmd_args;
+	struct cam_cdm_utils_ops         *cdm_util_ops = NULL;
+
+	if (arg_size != sizeof(struct cam_isp_hw_get_cdm_args)) {
+		pr_err("Error! Invalid cmd size\n");
+		return -EINVAL;
+	}
+
+	if (!cdm_args || !cdm_args->res) {
+		pr_err("Error! Invalid args\n");
+		return -EINVAL;
+	}
+
+	cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops;
+
+	if (!cdm_util_ops) {
+		pr_err("Error! Invalid CDM ops\n");
+		return -EINVAL;
+	}
+
+	size = cdm_util_ops->cdm_required_size_reg_random(1);
+	/* since cdm returns dwords, we need to convert it into bytes */
+	if ((size * 4) > cdm_args->size) {
+		pr_err("Error! buf size:%d is not sufficient, expected: %d\n",
+			cdm_args->size, size);
+		return -EINVAL;
+	}
+
+	reg_val_pair[0] = top_priv->common_data.common_reg->reg_update_cmd;
+
+	if (cdm_args->res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+		reg_val_pair[1] = BIT(0);
+	else
+		reg_val_pair[1] = BIT(cdm_args->res->res_id + 1);
+
+	cdm_util_ops->cdm_write_regrandom(cdm_args->cmd_buf_addr,
+		1, reg_val_pair);
+
+	cdm_args->used_bytes = size * 4;
+
+	return 0;
+}
+
+int cam_vfe_top_get_hw_caps(void *device_priv,
+	void *get_hw_cap_args, uint32_t arg_size)
+{
+	return 0;
+}
+
+int cam_vfe_top_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	return 0;
+}
+
+int cam_vfe_top_reset(void *device_priv,
+	void *reset_core_args, uint32_t arg_size)
+{
+	struct cam_vfe_top_ver2_priv   *top_priv = device_priv;
+	struct cam_hw_soc_info         *soc_info = NULL;
+	struct cam_vfe_top_ver2_reg_offset_common *reg_common = NULL;
+
+	if (!top_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	soc_info = top_priv->common_data.soc_info;
+	reg_common = top_priv->common_data.common_reg;
+
+	/* Mask All the IRQs except RESET */
+	cam_io_w_mb((1 << 31),
+		CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + 0x5C);
+
+	/* Reset HW */
+	cam_io_w_mb(0x00003F9F,
+		CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) +
+		reg_common->global_reset_cmd);
+
+	CDBG("Reset HW exit\n");
+	return 0;
+}
+
+int cam_vfe_top_reserve(void *device_priv,
+	void *reserve_args, uint32_t arg_size)
+{
+	struct cam_vfe_top_ver2_priv            *top_priv;
+	struct cam_vfe_acquire_args             *args;
+	struct cam_vfe_hw_vfe_in_acquire_args   *acquire_args;
+	uint32_t i;
+	int rc = -EINVAL;
+
+	if (!device_priv || !reserve_args) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
+	args = (struct cam_vfe_acquire_args *)reserve_args;
+	acquire_args = &args->vfe_in;
+
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		if (top_priv->mux_rsrc[i].res_id ==  acquire_args->res_id &&
+			top_priv->mux_rsrc[i].res_state ==
+			CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+
+			if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) {
+				rc = cam_vfe_camif_ver2_acquire_resource(
+					&top_priv->mux_rsrc[i],
+					args);
+				if (rc)
+					break;
+			}
+
+			top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops;
+			top_priv->mux_rsrc[i].tasklet_info = args->tasklet;
+			top_priv->mux_rsrc[i].res_state =
+				CAM_ISP_RESOURCE_STATE_RESERVED;
+			acquire_args->rsrc_node =
+				&top_priv->mux_rsrc[i];
+
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+
+}
+
+int cam_vfe_top_release(void *device_priv,
+	void *release_args, uint32_t arg_size)
+{
+	struct cam_vfe_top_ver2_priv            *top_priv;
+	struct cam_isp_resource_node            *mux_res;
+
+	if (!device_priv || !release_args) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
+	mux_res = (struct cam_isp_resource_node *)release_args;
+
+	if (mux_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
+		pr_err("Error! Resource in Invalid res_state :%d\n",
+			mux_res->res_state);
+		return -EINVAL;
+	}
+
+	mux_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+
+	return 0;
+}
+
+int cam_vfe_top_start(void *device_priv,
+	void *start_args, uint32_t arg_size)
+{
+	struct cam_vfe_top_ver2_priv            *top_priv;
+	struct cam_isp_resource_node            *mux_res;
+	int rc = 0;
+
+	if (!device_priv || !start_args) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
+	mux_res = (struct cam_isp_resource_node *)start_args;
+
+	if (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) {
+		rc = mux_res->start(mux_res);
+	} else if (mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0 &&
+		mux_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3) {
+		mux_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+		rc = 0;
+	} else {
+		pr_err("Invalid res id:%d\n", mux_res->res_id);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+int cam_vfe_top_stop(void *device_priv,
+	void *stop_args, uint32_t arg_size)
+{
+	struct cam_vfe_top_ver2_priv            *top_priv;
+	struct cam_isp_resource_node            *mux_res;
+	int rc = 0;
+
+	if (!device_priv || !stop_args) {
+		pr_err("Error! Invalid input arguments\n");
+		return -EINVAL;
+	}
+
+	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
+	mux_res = (struct cam_isp_resource_node *)stop_args;
+
+	if (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) {
+		rc = mux_res->stop(mux_res);
+	} else if (mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0 &&
+		mux_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3) {
+		mux_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
+		rc = 0;
+	} else {
+		pr_err("Invalid res id:%d\n", mux_res->res_id);
+		rc = -EINVAL;
+	}
+
+	return rc;
+
+}
+
+int cam_vfe_top_read(void *device_priv,
+	void *read_args, uint32_t arg_size)
+{
+	return -ENODEV;
+}
+
+int cam_vfe_top_write(void *device_priv,
+	void *write_args, uint32_t arg_size)
+{
+	return -ENODEV;
+}
+
+int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	int rc = 0;
+	struct cam_vfe_top_ver2_priv            *top_priv;
+
+	if (!device_priv || !cmd_args) {
+		pr_err("Error! Invalid arguments\n");
+		return -EINVAL;
+	}
+	top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
+
+	switch (cmd_type) {
+	case CAM_VFE_HW_CMD_GET_CHANGE_BASE:
+		rc = cam_vfe_top_mux_get_base(top_priv, cmd_args, arg_size);
+		break;
+	case CAM_VFE_HW_CMD_GET_REG_UPDATE:
+		rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args,
+			arg_size);
+		break;
+	default:
+		rc = -EINVAL;
+		pr_err("Error! Invalid cmd:%d\n", cmd_type);
+		break;
+	}
+
+	return rc;
+}
+
+int cam_vfe_top_ver2_init(
+	struct cam_hw_soc_info                 *soc_info,
+	struct cam_hw_intf                     *hw_intf,
+	void                                   *top_hw_info,
+	struct cam_vfe_top                    **vfe_top_ptr)
+{
+	int i, j, rc = 0;
+	struct cam_vfe_top_ver2_priv           *top_priv = NULL;
+	struct cam_vfe_top_ver2_hw_info        *ver2_hw_info = top_hw_info;
+	struct cam_vfe_top                     *vfe_top;
+
+	vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL);
+	if (!vfe_top) {
+		CDBG("Error! Failed to alloc for vfe_top\n");
+		rc = -ENOMEM;
+		goto err_alloc_top;
+	}
+
+	top_priv = kzalloc(sizeof(struct cam_vfe_top_ver2_priv),
+		GFP_KERNEL);
+	if (!top_priv) {
+		CDBG("Error! Failed to alloc for vfe_top_priv\n");
+		rc = -ENOMEM;
+		goto err_alloc_priv;
+	}
+	vfe_top->top_priv = top_priv;
+
+	for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN;
+		top_priv->mux_rsrc[i].hw_intf = hw_intf;
+		top_priv->mux_rsrc[i].res_state =
+			CAM_ISP_RESOURCE_STATE_AVAILABLE;
+		if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) {
+			top_priv->mux_rsrc[i].res_id =
+				CAM_ISP_HW_VFE_IN_CAMIF;
+
+			rc = cam_vfe_camif_ver2_init(hw_intf, soc_info,
+				&ver2_hw_info->camif_hw_info,
+				&top_priv->mux_rsrc[i]);
+			if (rc)
+				goto err_mux_init;
+		} else {
+			/* set the RDI resource id */
+			top_priv->mux_rsrc[i].res_id =
+				CAM_ISP_HW_VFE_IN_RDI0 + j;
+			top_priv->mux_rsrc[i].res_priv = NULL;
+			j++;
+		}
+	}
+
+	vfe_top->hw_ops.get_hw_caps = cam_vfe_top_get_hw_caps;
+	vfe_top->hw_ops.init        = cam_vfe_top_init_hw;
+	vfe_top->hw_ops.reset       = cam_vfe_top_reset;
+	vfe_top->hw_ops.reserve     = cam_vfe_top_reserve;
+	vfe_top->hw_ops.release     = cam_vfe_top_release;
+	vfe_top->hw_ops.start       = cam_vfe_top_start;
+	vfe_top->hw_ops.stop        = cam_vfe_top_stop;
+	vfe_top->hw_ops.read        = cam_vfe_top_read;
+	vfe_top->hw_ops.write       = cam_vfe_top_write;
+	vfe_top->hw_ops.process_cmd = cam_vfe_top_process_cmd;
+	*vfe_top_ptr = vfe_top;
+
+	top_priv->common_data.soc_info     = soc_info;
+	top_priv->common_data.hw_intf      = hw_intf;
+	top_priv->common_data.common_reg   = ver2_hw_info->common_reg;
+
+	return rc;
+
+err_mux_init:
+	kfree(vfe_top->top_priv);
+err_alloc_priv:
+	kfree(vfe_top);
+err_alloc_top:
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
new file mode 100644
index 0000000..24301d7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_TOP_VER2_H_
+#define _CAM_VFE_TOP_VER2_H_
+
+#include "cam_vfe_camif_ver2.h"
+
+#define CAM_VFE_TOP_VER2_MUX_MAX 4
+
+enum cam_vfe_top_ver2_module_type {
+	CAM_VFE_TOP_VER2_MODULE_LENS,
+	CAM_VFE_TOP_VER2_MODULE_STATS,
+	CAM_VFE_TOP_VER2_MODULE_COLOR,
+	CAM_VFE_TOP_VER2_MODULE_ZOOM,
+	CAM_VFE_TOP_VER2_MODULE_MAX,
+};
+
+struct cam_vfe_top_ver2_reg_offset_module_ctrl {
+	uint32_t reset;
+	uint32_t cgc_ovd;
+	uint32_t enable;
+};
+
+struct cam_vfe_top_ver2_reg_offset_common {
+	uint32_t hw_version;
+	uint32_t hw_capability;
+	uint32_t lens_feature;
+	uint32_t stats_feature;
+	uint32_t color_feature;
+	uint32_t zoom_feature;
+	uint32_t global_reset_cmd;
+	struct cam_vfe_top_ver2_reg_offset_module_ctrl
+		*module_ctrl[CAM_VFE_TOP_VER2_MODULE_MAX];
+	uint32_t bus_cgc_ovd;
+	uint32_t core_cfg;
+	uint32_t three_D_cfg;
+	uint32_t violation_status;
+	uint32_t reg_update_cmd;
+};
+
+struct cam_vfe_top_ver2_hw_info {
+	struct cam_vfe_top_ver2_reg_offset_common  *common_reg;
+	struct cam_vfe_camif_ver2_hw_info  camif_hw_info;
+	uint32_t mux_type[CAM_VFE_TOP_VER2_MUX_MAX];
+};
+
+int cam_vfe_top_ver2_init(struct cam_hw_soc_info     *soc_info,
+	struct cam_hw_intf                           *hw_intf,
+	void                                         *top_hw_info,
+	struct cam_vfe_top                           **vfe_top);
+
+#endif /* _CAM_VFE_TOP_VER2_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
new file mode 100644
index 0000000..44c046d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_VFE_TOP_H_
+#define _CAM_VFE_TOP_H_
+
+#include "cam_hw_intf.h"
+#include "cam_isp_hw.h"
+
+#define CAM_VFE_TOP_VER_1_0 0x100000
+#define CAM_VFE_TOP_VER_2_0 0x200000
+
+#define CAM_VFE_CAMIF_VER_1_0 0x10
+#define CAM_VFE_CAMIF_VER_2_0 0x20
+
+#define CAM_VFE_RDI_VER_1_0 0x1000
+
+struct cam_vfe_top {
+	void                   *top_priv;
+	struct cam_hw_ops       hw_ops;
+};
+
+struct cam_vfe_camif {
+	void               *camif_priv;
+	int (*start_resource)(void *priv,
+		struct cam_isp_resource_node *camif_res);
+	int (*stop_resource)(void *priv,
+		struct cam_isp_resource_node *camif_res);
+	int (*acquire_resource)(void *priv,
+		struct cam_isp_resource_node *camif_res,
+		void *acquire_param);
+	int (*release_resource)(void *priv,
+		struct cam_isp_resource_node *camif_res);
+	int (*process_cmd)(void *priv, uint32_t cmd_type, void *cmd_args,
+				uint32_t arg_size);
+};
+
+int cam_vfe_top_init(uint32_t          top_version,
+	struct cam_hw_soc_info        *soc_info,
+	struct cam_hw_intf            *hw_intf,
+	void                          *top_hw_info,
+	struct cam_vfe_top            **vfe_top);
+
+#endif /* _CAM_VFE_TOP_H_*/