Merge "msm: camera: core: remove extra stop during release" into dev/msm-4.9-camx
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt b/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt
new file mode 100644
index 0000000..9a37922
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt
@@ -0,0 +1,149 @@
+* Qualcomm Technologies, Inc. MSM Camera LRME
+
+The MSM camera Low Resolution Motion Estimation device provides dependency
+definitions for enabling Camera LRME HW. MSM camera LRME is implemented in
+multiple device nodes. The root LRME device node has properties defined to
+hint the driver about the LRME HW nodes available during the probe sequence.
+Each node has multiple properties defined for interrupts, clocks and
+regulators.
+
+=======================
+Required Node Structure
+=======================
+LRME root interface node takes care of the handling LRME high level
+driver handling and controls underlying LRME hardware present.
+
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,cam-lrme"
+
+- compat-hw-name
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,lrme"
+
+- num-lrme
+  Usage: required
+  Value type: <u32>
+  Definition: Number of supported LRME HW blocks
+
+Example:
+	qcom,cam-lrme {
+		compatible = "qcom,cam-lrme";
+		compat-hw-name = "qcom,lrme";
+		num-lrme = <1>;
+	};
+
+=======================
+Required Node Structure
+=======================
+LRME Node provides interface for Low Resolution Motion Estimation hardware
+driver about the device register map, interrupt map, clocks, regulators.
+
+- cell-index
+  Usage: required
+  Value type: <u32>
+  Definition: Node instance number
+
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,lrme"
+
+- reg-names
+  Usage: optional
+  Value type: <string>
+  Definition: Name of the register resources
+
+- reg
+  Usage: optional
+  Value type: <u32>
+  Definition: Register values
+
+- reg-cam-base
+  Usage: optional
+  Value type: <u32>
+  Definition: Offset of the register space compared to
+              to Camera base register space
+
+- interrupt-names
+  Usage: optional
+  Value type: <string>
+  Definition: Name of the interrupt
+
+- interrupts
+  Usage: optional
+  Value type: <u32>
+  Definition: Interrupt line associated with LRME HW
+
+- regulator-names
+  Usage: required
+  Value type: <string>
+  Definition: Name of the regulator resources for LRME HW
+
+- camss-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 LRME HW
+
+- clocks
+  Usage: required
+  Value type: <phandle>
+  Definition: List of clocks required for LRME HW
+
+- clock-rates
+  Usage: required
+  Value type: <u32>
+  Definition: List of clocks rates
+
+- clock-cntl-level
+  Usage: required
+  Value type: <string>
+  Definition: List of strings corresponds clock-rates levels
+  Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo
+
+- src-clock-name
+  Usage: required
+  Value type: <string>
+  Definition: Source clock name
+
+Examples:
+	cam_lrme: qcom,lrme@ac6b000 {
+		cell-index = <0>;
+		compatible = "qcom,lrme";
+		reg-names = "lrme";
+		reg = <0xac6b000 0xa00>;
+		reg-cam-base = <0x6b000>;
+		interrupt-names = "lrme";
+		interrupts = <0 476 0>;
+		regulator-names = "camss";
+		camss-supply = <&titan_top_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"camnoc_axi_clk",
+			"lrme_clk_src",
+			"lrme_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_LRME_CLK_SRC>,
+			<&clock_camcc CAM_CC_LRME_CLK>;
+		clock-rates = <0 0 0 0 0 0 0>,
+			<0 0 0 0 0 19200000 19200000>,
+			<0 0 0 0 0 19200000 19200000>,
+			<0 0 0 0 0 19200000 19200000>;
+		clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo";
+		src-clock-name = "lrme_core_clk_src";
+	};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 17bcf0955..35a7774 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -434,13 +434,14 @@
 			"csid0", "csid1", "csid2",
 			"ife0", "ife1", "ife2", "ipe0",
 			"ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0",
-			"icp0", "jpeg-dma0", "jpeg-enc0", "fd0";
+			"icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas";
 		client-axi-port-names =
 			"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
 			"cam_hf_1", "cam_hf_2", "cam_hf_2",
 			"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
 			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
-			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1";
+			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
+			"cam_sf_1";
 		client-bus-camnoc-based;
 		qcom,axi-port-list {
 			qcom,axi-port1 {
@@ -529,7 +530,8 @@
 		cdm-client-names = "vfe",
 			"jpegdma",
 			"jpegenc",
-			"fd";
+			"fd",
+			"lrmecdm";
 		status = "ok";
 	};
 
@@ -775,7 +777,7 @@
 		clock-rates =
 			<0 0 0 0 0 0 384000000 0 0 0 404000000 0>,
 			<0 0 0 0 0 0 538000000 0 0 0 600000000 0>;
-		clock-cntl-level = "svs";
+		clock-cntl-level = "svs", "turbo";
 		src-clock-name = "ife_csid_clk_src";
 		status = "ok";
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index d867129..d2ee9eb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -157,6 +157,33 @@
 		compatible = "qcom,msm-cam-smmu";
 		status = "ok";
 
+		msm_cam_smmu_lrme {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1038 0x0>,
+				<&apps_smmu 0x1058 0x0>,
+				<&apps_smmu 0x1039 0x0>,
+				<&apps_smmu 0x1059 0x0>;
+			label = "lrme";
+			lrme_iova_mem_map: iova-mem-map {
+				iova-mem-region-shared {
+					/* Shared region is 100MB long */
+					iova-region-name = "shared";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0x6400000>;
+					iova-region-id = <0x1>;
+					status = "ok";
+				};
+				/* IO region is approximately 3.3 GB */
+				iova-mem-region-io {
+					iova-region-name = "io";
+					iova-region-start = <0xd800000>;
+					iova-region-len = <0xd2800000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+
 		msm_cam_smmu_ife {
 			compatible = "qcom,msm-cam-smmu-cb";
 			iommus = <&apps_smmu 0x808 0x0>,
@@ -329,13 +356,14 @@
 			"csid0", "csid1", "csid2",
 			"ife0", "ife1", "ife2", "ipe0",
 			"ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0",
-			"icp0", "jpeg-dma0", "jpeg-enc0", "fd0";
+			"icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas0";
 		client-axi-port-names =
 			"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_hf_2",
 			"cam_sf_1", "cam_hf_1", "cam_hf_2", "cam_hf_2",
 			"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
 			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
-			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1";
+			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
+			"cam_sf_1";
 		client-bus-camnoc-based;
 		qcom,axi-port-list {
 			qcom,axi-port1 {
@@ -415,4 +443,44 @@
 			};
 		};
 	};
+
+	qcom,cam-lrme {
+		compatible = "qcom,cam-lrme";
+		arch-compat = "lrme";
+		status = "ok";
+	};
+
+	cam_lrme: qcom,lrme@ac6b000 {
+		cell-index = <0>;
+		compatible = "qcom,lrme";
+		reg-names = "lrme";
+		reg = <0xac6b000 0xa00>;
+		reg-cam-base = <0x6b000>;
+		interrupt-names = "lrme";
+		interrupts = <0 476 0>;
+		regulator-names = "camss";
+		camss-supply = <&titan_top_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"camnoc_axi_clk",
+			"lrme_clk_src",
+			"lrme_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_LRME_CLK_SRC>,
+			<&clock_camcc CAM_CC_LRME_CLK>;
+		clock-rates = <0 0 0 0 0 200000000 200000000>,
+			<0 0 0 0 0 269000000 269000000>,
+			<0 0 0 0 0 320000000 320000000>,
+			<0 0 0 0 0 400000000 400000000>;
+
+		clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo";
+		src-clock-name = "lrme_clk_src";
+		status = "ok";
+	};
 };
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index 48fa1c0..9e0aee9 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -10,3 +10,4 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
index d039d75..7447e1d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -134,8 +134,8 @@
 		rc = ctx->state_machine[ctx->state].crm_ops.unlink(
 			ctx, unlink);
 	} else {
-		CAM_ERR(CAM_CORE, "No crm unlink in dev %d, state %d",
-			ctx->dev_hdl, ctx->state);
+		CAM_ERR(CAM_CORE, "No crm unlink in dev %d, name %s, state %d",
+			ctx->dev_hdl, ctx->dev_name, ctx->state);
 		rc = -EPROTO;
 	}
 	mutex_unlock(&ctx->ctx_mutex);
@@ -196,6 +196,30 @@
 	return rc;
 }
 
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *process_evt)
+{
+	int rc;
+
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context is not ready");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.process_evt) {
+		rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx,
+			process_evt);
+	} else {
+		CAM_ERR(CAM_CORE, "No crm process evt in dev %d, state %d",
+			ctx->dev_hdl, ctx->state);
+		rc = -EPROTO;
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
 int cam_context_handle_acquire_dev(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
index 6d1589e..d536663 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -56,6 +56,7 @@
  * @num_in_acked:          Number of in fence acked
  * @num_out_acked:         Number of out fence acked
  * @flushed:               Request is flushed
+ * @error_flag:            Flag an error
  * @ctx:                   The context to which this request belongs
  *
  */
@@ -73,6 +74,7 @@
 	uint32_t                      num_in_acked;
 	uint32_t                      num_out_acked;
 	int                           flushed;
+	bool                          error_flag;
 	struct cam_context           *ctx;
 };
 
@@ -120,6 +122,8 @@
 			struct cam_req_mgr_apply_request *apply);
 	int (*flush_req)(struct cam_context *ctx,
 			struct cam_req_mgr_flush_request *flush);
+	int (*process_evt)(struct cam_context *ctx,
+			struct cam_req_mgr_link_evt_data *evt_data);
 };
 
 
@@ -270,6 +274,18 @@
 		struct cam_req_mgr_flush_request *apply);
 
 /**
+ * cam_context_handle_crm_process_evt()
+ *
+ * @brief:        Handle process event command
+ *
+ * @ctx:          Object pointer for cam_context
+ * @process_evt:  process event command payload
+ *
+ */
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+		struct cam_req_mgr_link_evt_data *process_evt);
+
+/**
  * cam_context_handle_acquire_dev()
  *
  * @brief:        Handle acquire device command
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index 32f6572..0a1c2cf 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -178,6 +178,7 @@
 			req->ctx = NULL;
 			req->flushed = 0;
 			spin_lock(&ctx->lock);
+			list_del_init(&req->list);
 			list_add_tail(&req->list, &ctx->free_req_list);
 			spin_unlock(&ctx->lock);
 		}
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index 1f0213e..3b0adc4 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -309,6 +309,26 @@
 	return cam_context_handle_crm_flush_req(ctx, flush);
 }
 
+static int __cam_node_crm_process_evt(
+	struct cam_req_mgr_link_evt_data *evt_data)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!evt_data) {
+		CAM_ERR(CAM_CORE, "Invalid process event request payload");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl);
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
+			evt_data->dev_hdl);
+		return -EINVAL;
+	}
+
+	return cam_context_handle_crm_process_evt(ctx, evt_data);
+}
+
 int cam_node_deinit(struct cam_node *node)
 {
 	if (node)
@@ -361,6 +381,7 @@
 	node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info;
 	node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
 	node->crm_node_intf.flush_req = __cam_node_crm_flush_req;
+	node->crm_node_intf.process_evt = __cam_node_crm_process_evt;
 
 	mutex_init(&node->list_mutex);
 	INIT_LIST_HEAD(&node->free_ctx_list);
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index e51d350..a8855ae 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -109,7 +109,19 @@
 			new_write_idx << BYTE_WORD_SHIFT);
 	}
 
+	/*
+	 * To make sure command data in a command queue before
+	 * updating write index
+	 */
+	wmb();
+
 	q->qhdr_write_idx = new_write_idx;
+
+	/*
+	 * Before raising interrupt make sure command data is ready for
+	 * firmware to process
+	 */
+	wmb();
 	cam_io_w((uint32_t)INTR_ENABLE,
 		g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
 err:
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 93926a78..340a1e2 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1644,6 +1644,7 @@
 	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
 		clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
 	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+	hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap = NULL;
 	cam_icp_hw_mgr_clk_info_update(hw_mgr, &hw_mgr->ctx_data[ctx_id]);
 	hw_mgr->ctx_data[ctx_id].clk_info.curr_fc = 0;
 	hw_mgr->ctx_data[ctx_id].clk_info.base_clk = 0;
@@ -2068,6 +2069,7 @@
 	ctx_data = config_args->ctxt_to_hw_map;
 	mutex_lock(&ctx_data->ctx_mutex);
 	if (!ctx_data->in_use) {
+		mutex_unlock(&ctx_data->ctx_mutex);
 		CAM_ERR(CAM_ICP, "ctx is not in use");
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index ae6b149..5c95dad 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -216,19 +216,7 @@
 			continue;
 		}
 
-		if (!bubble_state) {
-			CAM_DBG(CAM_ISP,
-				"Sync with success: req %lld res 0x%x fd 0x%x",
-				req->request_id,
-				req_isp->fence_map_out[j].resource_handle,
-				req_isp->fence_map_out[j].sync_id);
-
-			rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
-				CAM_SYNC_STATE_SIGNALED_SUCCESS);
-			if (rc)
-				CAM_DBG(CAM_ISP, "Sync failed with rc = %d",
-					 rc);
-		} else if (!req_isp->bubble_report) {
+		if (req->error_flag || !req_isp->bubble_report) {
 			CAM_DBG(CAM_ISP,
 				"Sync with failure: req %lld res 0x%x fd 0x%x",
 				req->request_id,
@@ -240,6 +228,18 @@
 			if (rc)
 				CAM_ERR(CAM_ISP, "Sync failed with rc = %d",
 					rc);
+		} else if (!bubble_state) {
+			CAM_DBG(CAM_ISP,
+				"Sync with success: req %lld res 0x%x fd 0x%x",
+				req->request_id,
+				req_isp->fence_map_out[j].resource_handle,
+				req_isp->fence_map_out[j].sync_id);
+
+			rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+				CAM_SYNC_STATE_SIGNALED_SUCCESS);
+			if (rc)
+				CAM_DBG(CAM_ISP, "Sync failed with rc = %d",
+					rc);
 		} else {
 			/*
 			 * Ignore the buffer done if bubble detect is on
@@ -304,7 +304,7 @@
 		ctx_isp->sof_timestamp_val);
 	CAM_DBG(CAM_ISP, " sof status:%d", sof_event_status);
 
-	if (cam_req_mgr_notify_frame_message(&req_msg,
+	if (cam_req_mgr_notify_message(&req_msg,
 		V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT))
 		CAM_ERR(CAM_ISP,
 			"Error in notifying the sof time for req id:%lld",
@@ -2091,6 +2091,34 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *link_evt_data)
+{
+	int rc = 0;
+	struct cam_ctx_request *req_current;
+	struct cam_ctx_request *req_prev;
+	bool req_id_found = false;
+
+	list_for_each_entry_safe(req_current, req_prev,
+		&ctx->pending_req_list, list) {
+		if (link_evt_data->req_id == req_current->request_id) {
+			req_current->error_flag = true;
+			req_id_found = true;
+			CAM_DBG(CAM_ISP,
+				"flagging req_id=%lld as error on link_hdl: %d for dev_hdl: %d",
+				link_evt_data->req_id, link_evt_data->link_hdl,
+				link_evt_data->dev_hdl);
+		}
+	}
+
+	if (!req_id_found) {
+		CAM_ERR(CAM_ISP,
+			"req_id=%lld not found in the pending list ",
+			link_evt_data->req_id);
+		rc = -EINVAL;
+	}
+	return rc;
+}
 static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx,
 	struct cam_req_mgr_core_dev_link_setup *unlink)
 {
@@ -2223,6 +2251,7 @@
 			.unlink = __cam_isp_ctx_unlink_in_activated,
 			.apply_req = __cam_isp_ctx_apply_req,
 			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
+			.process_evt = __cam_isp_ctx_process_evt,
 		},
 		.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
 	},
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index d5a5347..8880cb5 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -41,10 +41,12 @@
 	(CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1)
 
 #define CAM_ISP_GENERIC_BLOB_TYPE_MAX               \
-	(CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG + 1)
+	(CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG + 1)
 
 static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = {
 	CAM_ISP_HW_CMD_GET_HFR_UPDATE,
+	CAM_ISP_HW_CMD_CLOCK_UPDATE,
+	CAM_ISP_HW_CMD_BW_UPDATE,
 };
 
 static struct cam_ife_hw_mgr g_ife_hw_mgr;
@@ -866,7 +868,7 @@
 	struct cam_ife_hw_mgr               *ife_hw_mgr;
 	struct cam_ife_hw_mgr_res           *csid_res;
 	struct cam_ife_hw_mgr_res           *cid_res;
-	struct cam_hw_intf                   *hw_intf;
+	struct cam_hw_intf                  *hw_intf;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
@@ -2109,6 +2111,168 @@
 	return rc;
 }
 
+static int cam_isp_blob_clock_update(
+	uint32_t                               blob_type,
+	struct cam_isp_generic_blob_info      *blob_info,
+	struct cam_isp_clock_config           *clock_config,
+	struct cam_hw_prepare_update_args     *prepare)
+{
+	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_vfe_clock_update_args       clock_upd_args;
+	uint64_t                               clk_rate = 0;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+	uint32_t                               j;
+
+	ctx = prepare->ctxt_to_hw_map;
+
+	CAM_DBG(CAM_ISP,
+		"usage=%u left_clk= %lu right_clk=%lu",
+		clock_config->usage_type,
+		clock_config->left_pix_hz,
+		clock_config->right_pix_hz);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			clk_rate = 0;
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+				if (i == CAM_ISP_HW_SPLIT_LEFT)
+					clk_rate =
+						clock_config->left_pix_hz;
+				else
+					clk_rate =
+						clock_config->right_pix_hz;
+			else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
+					&& (hw_mgr_res->res_id <=
+					CAM_ISP_HW_VFE_IN_RDI3))
+				for (j = 0; j < clock_config->num_rdi; j++)
+					clk_rate = max(clock_config->rdi_hz[j],
+						clk_rate);
+			else
+				if (hw_mgr_res->hw_res[i]) {
+					CAM_ERR(CAM_ISP, "Invalid res_id %u",
+						hw_mgr_res->res_id);
+					rc = -EINVAL;
+					return rc;
+				}
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				clock_upd_args.node_res =
+					hw_mgr_res->hw_res[i];
+				CAM_DBG(CAM_ISP,
+				"res_id=%u i= %d clk=%llu\n",
+				hw_mgr_res->res_id, i, clk_rate);
+
+				clock_upd_args.clk_rate = clk_rate;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_CLOCK_UPDATE,
+					&clock_upd_args,
+					sizeof(
+					struct cam_vfe_clock_update_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "Clock Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
+static int cam_isp_blob_bw_update(
+	uint32_t                               blob_type,
+	struct cam_isp_generic_blob_info      *blob_info,
+	struct cam_isp_bw_config              *bw_config,
+	struct cam_hw_prepare_update_args     *prepare)
+{
+	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_vfe_bw_update_args          bw_upd_args;
+	uint64_t                               cam_bw_bps = 0;
+	uint64_t                               ext_bw_bps = 0;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+
+	ctx = prepare->ctxt_to_hw_map;
+
+	CAM_DBG(CAM_ISP,
+		"usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
+		"right cam_bw_bps=%llu ext_bw_bps=%llu",
+		bw_config->usage_type,
+		bw_config->left_pix_vote.cam_bw_bps,
+		bw_config->left_pix_vote.ext_bw_bps,
+		bw_config->right_pix_vote.cam_bw_bps,
+		bw_config->right_pix_vote.ext_bw_bps);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+				if (i == CAM_ISP_HW_SPLIT_LEFT) {
+					cam_bw_bps =
+					bw_config->left_pix_vote.cam_bw_bps;
+					ext_bw_bps =
+					bw_config->left_pix_vote.ext_bw_bps;
+				} else {
+					cam_bw_bps =
+					bw_config->right_pix_vote.cam_bw_bps;
+					ext_bw_bps =
+					bw_config->right_pix_vote.ext_bw_bps;
+				}
+			else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
+						&& (hw_mgr_res->res_id <=
+						CAM_ISP_HW_VFE_IN_RDI3)) {
+				uint32_t idx = hw_mgr_res->res_id -
+						CAM_ISP_HW_VFE_IN_RDI0;
+				if (idx >= bw_config->num_rdi)
+					continue;
+
+				cam_bw_bps =
+					bw_config->rdi_vote[idx].cam_bw_bps;
+				ext_bw_bps =
+					bw_config->rdi_vote[idx].ext_bw_bps;
+			} else
+				if (hw_mgr_res->hw_res[i]) {
+					CAM_ERR(CAM_ISP, "Invalid res_id %u",
+						hw_mgr_res->res_id);
+					rc = -EINVAL;
+					return rc;
+				}
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				bw_upd_args.node_res =
+					hw_mgr_res->hw_res[i];
+
+				bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
+				bw_upd_args.external_bw_bytes = ext_bw_bps;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_BW_UPDATE,
+					&bw_upd_args,
+					sizeof(struct cam_vfe_bw_update_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "BW Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
 static int cam_isp_packet_generic_blob_handler(void *user_data,
 	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
 {
@@ -2146,6 +2310,26 @@
 			CAM_ERR(CAM_ISP, "HFR Update Failed");
 	}
 		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: {
+		struct cam_isp_clock_config    *clock_config =
+			(struct cam_isp_clock_config *)blob_data;
+
+		rc = cam_isp_blob_clock_update(blob_type, blob_info,
+			clock_config, prepare);
+		if (rc)
+			CAM_ERR(CAM_ISP, "Clock Update Failed");
+	}
+		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
+		struct cam_isp_bw_config    *bw_config =
+			(struct cam_isp_bw_config *)blob_data;
+
+		rc = cam_isp_blob_bw_update(blob_type, blob_info,
+			bw_config, prepare);
+		if (rc)
+			CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
+	}
+		break;
 	default:
 		CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
 		break;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index 876a540..3606af9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -97,6 +97,8 @@
 	struct cam_ife_hw_mgr_res                  *hw_mgr_res;
 	struct cam_isp_resource_node               *res;
 	struct cam_isp_hw_dual_isp_update_args      dual_isp_update_args;
+	uint32_t                                    outport_id;
+	uint32_t                                    ports_plane_idx;
 	size_t                                      len = 0;
 	uint32_t                                   *cpu_addr;
 	uint32_t                                    i, j;
@@ -113,6 +115,14 @@
 	dual_config = (struct cam_isp_dual_config *)cpu_addr;
 
 	for (i = 0; i < dual_config->num_ports; i++) {
+
+		if (i >= CAM_ISP_IFE_OUT_RES_MAX) {
+			CAM_ERR(CAM_UTIL,
+				"failed update for i:%d > size_isp_out:%d",
+				i, size_isp_out);
+			return -EINVAL;
+		}
+
 		hw_mgr_res = &res_list_isp_out[i];
 		for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) {
 			if (!hw_mgr_res->hw_res[j])
@@ -122,6 +132,20 @@
 				continue;
 
 			res = hw_mgr_res->hw_res[j];
+
+			if (res->res_id < CAM_ISP_IFE_OUT_RES_BASE ||
+				res->res_id >= CAM_ISP_IFE_OUT_RES_MAX)
+				continue;
+
+			outport_id = res->res_id & 0xFF;
+
+			ports_plane_idx = (j * (dual_config->num_ports *
+				CAM_PACKET_MAX_PLANES)) +
+				(outport_id * CAM_PACKET_MAX_PLANES);
+
+			if (dual_config->stripes[ports_plane_idx].port_id == 0)
+				continue;
+
 			dual_isp_update_args.split_id = j;
 			dual_isp_update_args.res      = res;
 			dual_isp_update_args.dual_cfg = dual_config;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index deef41f..07217f5 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -392,6 +392,7 @@
  *                  for RDI, set  mode to none
  * @master_idx:     For Slave reservation, Give master IFE instance Index.
  *                  Slave will synchronize with master Start and stop operations
+ * @clk_rate        Clock rate
  *
  */
 struct cam_ife_csid_path_cfg {
@@ -409,6 +410,7 @@
 	uint32_t                        height;
 	enum cam_isp_hw_sync_mode       sync_mode;
 	uint32_t                        master_idx;
+	uint64_t                        clk_rate;
 };
 
 /**
@@ -432,6 +434,7 @@
  * @csid_rdin_reset_complete: rdi n completion
  * @csid_debug:               csid debug information to enable the SOT, EOT,
  *                            SOF, EOF, measure etc in the csid hw
+ * @clk_rate                  Clock rate
  *
  */
 struct cam_ife_csid_hw {
@@ -452,6 +455,7 @@
 	struct completion                csid_ipp_complete;
 	struct completion    csid_rdin_complete[CAM_IFE_CSID_RDI_MAX];
 	uint64_t                         csid_debug;
+	uint64_t                         clk_rate;
 };
 
 int cam_ife_csid_hw_probe_init(struct cam_hw_intf  *csid_hw_intf,
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
index c81e6db..b634e38b 100644
--- 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
@@ -90,6 +90,8 @@
 	CAM_ISP_HW_CMD_GET_HFR_UPDATE,
 	CAM_ISP_HW_CMD_GET_SECURE_MODE,
 	CAM_ISP_HW_CMD_STRIPE_UPDATE,
+	CAM_ISP_HW_CMD_CLOCK_UPDATE,
+	CAM_ISP_HW_CMD_BW_UPDATE,
 	CAM_ISP_HW_CMD_MAX,
 };
 
@@ -192,6 +194,8 @@
 		void                                 *data;
 		struct cam_isp_hw_get_wm_update      *wm_update;
 		struct cam_isp_port_hfr_config       *hfr_update;
+		struct cam_isp_clock_config          *clock_update;
+		struct cam_isp_bw_config             *bw_update;
 	};
 };
 
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
index b7ec511..b771ec6 100644
--- 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
@@ -161,6 +161,31 @@
 };
 
 /*
+ * struct cam_vfe_clock_update_args:
+ *
+ * @node_res:                Resource to get the time stamp
+ * @clk_rate:                Clock rate requested
+ */
+struct cam_vfe_clock_update_args {
+	struct cam_isp_resource_node      *node_res;
+	uint64_t                           clk_rate;
+};
+
+/*
+ * struct cam_vfe_bw_update_args:
+ *
+ * @node_res:             Resource to get the time stamp
+ * @camnoc_bw_bytes:      Bandwidth vote request for CAMNOC
+ * @external_bw_bytes:    Bandwidth vote request from CAMNOC
+ *                        out to the rest of the path-to-DDR
+ */
+struct cam_vfe_bw_update_args {
+	struct cam_isp_resource_node      *node_res;
+	uint64_t                           camnoc_bw_bytes;
+	uint64_t                           external_bw_bytes;
+};
+
+/*
  * struct cam_vfe_top_irq_evt_payload:
  *
  * @Brief:                   This structure is used to save payload for IRQ
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
index d1e1605..d534607 100644
--- 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
@@ -264,7 +264,9 @@
 		goto deinint_vfe_res;
 	}
 
-	return 0;
+	vfe_hw->hw_state = CAM_HW_STATE_POWER_UP;
+	return rc;
+
 deinint_vfe_res:
 	if (isp_res && isp_res->deinit)
 		isp_res->deinit(isp_res, NULL, 0);
@@ -650,10 +652,11 @@
 	switch (cmd_type) {
 	case CAM_ISP_HW_CMD_GET_CHANGE_BASE:
 	case CAM_ISP_HW_CMD_GET_REG_UPDATE:
+	case CAM_ISP_HW_CMD_CLOCK_UPDATE:
+	case CAM_ISP_HW_CMD_BW_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_ISP_HW_CMD_GET_BUF_UPDATE:
 	case CAM_ISP_HW_CMD_GET_HFR_UPDATE:
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
index ac8b497..9a2c12c 100644
--- 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
@@ -1,11 +1,13 @@
 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_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/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/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
 
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o cam_vfe_rdi.o
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
index 7baac45..1b8cdf3 100644
--- 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
@@ -17,6 +17,8 @@
 #include "cam_vfe_top.h"
 #include "cam_vfe_top_ver2.h"
 #include "cam_debug_util.h"
+#include "cam_cpas_api.h"
+#include "cam_vfe_soc.h"
 
 #define CAM_VFE_HW_RESET_HW_AND_REG_VAL   0x00003F9F
 #define CAM_VFE_HW_RESET_HW_VAL           0x00003F87
@@ -29,8 +31,11 @@
 
 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];
+	unsigned long                       hw_clk_rate;
+	struct cam_axi_vote                 hw_axi_vote;
+	struct cam_axi_vote             req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX];
+	unsigned long                   req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX];
 };
 
 static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv,
@@ -80,6 +85,174 @@
 	return 0;
 }
 
+static int cam_vfe_top_set_hw_clk_rate(
+	struct cam_vfe_top_ver2_priv *top_priv)
+{
+	struct cam_hw_soc_info        *soc_info = NULL;
+	int                            i, rc = 0;
+	unsigned long                  max_clk_rate = 0;
+
+	soc_info = top_priv->common_data.soc_info;
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		if (top_priv->req_clk_rate[i] > max_clk_rate)
+			max_clk_rate = top_priv->req_clk_rate[i];
+	}
+	if (max_clk_rate == top_priv->hw_clk_rate)
+		return 0;
+
+	CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%lld",
+		soc_info->clk_name[soc_info->src_clk_idx],
+		soc_info->src_clk_idx, max_clk_rate);
+
+	rc = cam_soc_util_set_clk_rate(
+		soc_info->clk[soc_info->src_clk_idx],
+		soc_info->clk_name[soc_info->src_clk_idx],
+		max_clk_rate);
+
+	if (!rc)
+		top_priv->hw_clk_rate = max_clk_rate;
+	else
+		CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc);
+
+	return rc;
+}
+
+static int cam_vfe_top_set_axi_bw_vote(
+	struct cam_vfe_top_ver2_priv *top_priv)
+{
+	struct cam_axi_vote sum = {0, 0};
+	int i, rc = 0;
+	struct cam_hw_soc_info   *soc_info =
+		top_priv->common_data.soc_info;
+	struct cam_vfe_soc_private *soc_private =
+		soc_info->soc_private;
+
+	if (!soc_private) {
+		CAM_ERR(CAM_ISP, "Error soc_private NULL");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		sum.uncompressed_bw +=
+			top_priv->req_axi_vote[i].uncompressed_bw;
+		sum.compressed_bw +=
+			top_priv->req_axi_vote[i].compressed_bw;
+	}
+
+	CAM_DBG(CAM_ISP, "BW Vote: u=%lld c=%lld",
+		sum.uncompressed_bw,
+		sum.compressed_bw);
+
+	if ((top_priv->hw_axi_vote.uncompressed_bw ==
+		sum.uncompressed_bw) &&
+		(top_priv->hw_axi_vote.compressed_bw ==
+		sum.compressed_bw))
+		return 0;
+
+	rc = cam_cpas_update_axi_vote(
+			soc_private->cpas_handle,
+			&sum);
+	if (!rc) {
+		top_priv->hw_axi_vote.uncompressed_bw = sum.uncompressed_bw;
+		top_priv->hw_axi_vote.compressed_bw = sum.compressed_bw;
+	} else
+		CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+
+	return rc;
+}
+
+static int cam_vfe_top_clock_update(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_vfe_clock_update_args     *clk_update = NULL;
+	struct cam_isp_resource_node         *res = NULL;
+	struct cam_hw_info                   *hw_info = NULL;
+	int                                   i, rc = 0;
+
+	clk_update =
+		(struct cam_vfe_clock_update_args *)cmd_args;
+	res = clk_update->node_res;
+
+	if (!res || !res->hw_intf->hw_priv) {
+		CAM_ERR(CAM_ISP, "Invalid input res %pK", res);
+		return -EINVAL;
+	}
+
+	hw_info = res->hw_intf->hw_priv;
+
+	if (res->res_type != CAM_ISP_RESOURCE_VFE_IN ||
+		res->res_id >= CAM_ISP_HW_VFE_IN_MAX) {
+		CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d",
+			res->hw_intf->hw_idx, res->res_type,
+			res->res_id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		if (top_priv->mux_rsrc[i].res_id == res->res_id) {
+			top_priv->req_clk_rate[i] = clk_update->clk_rate;
+			break;
+		}
+	}
+
+	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set clocks yet :%d",
+			res->hw_intf->hw_idx,
+			hw_info->hw_state);
+	} else
+		rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+
+	return rc;
+}
+
+static int cam_vfe_top_bw_update(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_vfe_bw_update_args        *bw_update = NULL;
+	struct cam_isp_resource_node         *res = NULL;
+	struct cam_hw_info                   *hw_info = NULL;
+	int                                   rc = 0;
+	int                                   i;
+
+	bw_update = (struct cam_vfe_bw_update_args *)cmd_args;
+	res = bw_update->node_res;
+
+	if (!res || !res->hw_intf->hw_priv)
+		return -EINVAL;
+
+	hw_info = res->hw_intf->hw_priv;
+
+	if (res->res_type != CAM_ISP_RESOURCE_VFE_IN ||
+		res->res_id >= CAM_ISP_HW_VFE_IN_MAX) {
+		CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d",
+			res->hw_intf->hw_idx, res->res_type,
+			res->res_id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		if (top_priv->mux_rsrc[i].res_id == res->res_id) {
+			top_priv->req_axi_vote[i].uncompressed_bw =
+				bw_update->camnoc_bw_bytes;
+			top_priv->req_axi_vote[i].compressed_bw =
+				bw_update->external_bw_bytes;
+			break;
+		}
+	}
+
+	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+			res->hw_intf->hw_idx,
+			hw_info->hw_state);
+	} else
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+
+	return rc;
+}
+
 static int cam_vfe_top_mux_get_reg_update(
 	struct cam_vfe_top_ver2_priv *top_priv,
 	void *cmd_args, uint32_t arg_size)
@@ -230,9 +403,21 @@
 		return -EINVAL;
 	}
 
-	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
+	top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
 	mux_res = (struct cam_isp_resource_node *)start_args;
 
+	rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
+		return rc;
+	}
+
+	rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
+		return rc;
+	}
+
 	if (mux_res->start) {
 		rc = mux_res->start(mux_res);
 	} else {
@@ -248,7 +433,7 @@
 {
 	struct cam_vfe_top_ver2_priv            *top_priv;
 	struct cam_isp_resource_node            *mux_res;
-	int rc = 0;
+	int i, rc = 0;
 
 	if (!device_priv || !stop_args) {
 		CAM_ERR(CAM_ISP, "Error! Invalid input arguments");
@@ -267,8 +452,16 @@
 		rc = -EINVAL;
 	}
 
-	return rc;
+	if (!rc) {
+		for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+			if (top_priv->mux_rsrc[i].res_id == mux_res->res_id)
+				top_priv->req_clk_rate[i] = 0;
+			top_priv->req_axi_vote[i].compressed_bw = 0;
+			top_priv->req_axi_vote[i].uncompressed_bw = 0;
+		}
+	}
 
+	return rc;
 }
 
 int cam_vfe_top_read(void *device_priv,
@@ -303,6 +496,14 @@
 		rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args,
 			arg_size);
 		break;
+	case CAM_ISP_HW_CMD_CLOCK_UPDATE:
+		rc = cam_vfe_top_clock_update(top_priv, cmd_args,
+			arg_size);
+		break;
+	case CAM_ISP_HW_CMD_BW_UPDATE:
+		rc = cam_vfe_top_bw_update(top_priv, cmd_args,
+			arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
@@ -338,12 +539,19 @@
 		goto free_vfe_top;
 	}
 	vfe_top->top_priv = top_priv;
+	top_priv->hw_clk_rate = 0;
+	top_priv->hw_axi_vote.compressed_bw = 0;
+	top_priv->hw_axi_vote.uncompressed_bw = 0;
 
 	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;
+		top_priv->req_clk_rate[i] = 0;
+		top_priv->req_axi_vote[i].compressed_bw = 0;
+		top_priv->req_axi_vote[i].uncompressed_bw = 0;
+
 		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;
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
index dbb211f..81e3b48 100644
--- 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
@@ -29,21 +29,6 @@
 	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,
diff --git a/drivers/media/platform/msm/camera/cam_lrme/Makefile b/drivers/media/platform/msm/camera/cam_lrme/Makefile
new file mode 100644
index 0000000..fba4529
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw_mgr/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_dev.o cam_lrme_context.o
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
new file mode 100644
index 0000000..0aa5ade
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
@@ -0,0 +1,241 @@
+/* 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 <linux/kernel.h>
+
+#include "cam_debug_util.h"
+#include "cam_lrme_context.h"
+
+static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc = 0;
+	uint64_t ctxt_to_hw_map = (uint64_t)ctx->ctxt_to_hw_map;
+	struct cam_lrme_context *lrme_ctx = ctx->ctx_priv;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = cam_context_acquire_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to acquire");
+		return rc;
+	}
+
+	ctxt_to_hw_map |= (lrme_ctx->index << CAM_LRME_CTX_INDEX_SHIFT);
+	ctx->ctxt_to_hw_map = (void *)ctxt_to_hw_map;
+
+	ctx->state = CAM_CTX_ACQUIRED;
+
+	return rc;
+}
+
+static int __cam_lrme_ctx_release_dev_in_acquired(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = cam_context_release_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to release");
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_AVAILABLE;
+
+	return rc;
+}
+
+static int __cam_lrme_ctx_start_dev_in_acquired(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = cam_context_start_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to start");
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_ACTIVATED;
+
+	return rc;
+}
+
+static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = cam_context_prepare_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to config");
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __cam_lrme_ctx_stop_dev_in_activated(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = cam_context_stop_dev_to_hw(ctx);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to stop dev");
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_ACQUIRED;
+
+	return rc;
+}
+
+static int __cam_lrme_ctx_release_dev_in_activated(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = __cam_lrme_ctx_stop_dev_in_activated(ctx, NULL);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to stop");
+		return rc;
+	}
+
+	rc = cam_context_release_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to release");
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_AVAILABLE;
+
+	return rc;
+}
+
+static int __cam_lrme_ctx_handle_irq_in_activated(void *context,
+	uint32_t evt_id, void *evt_data)
+{
+	int rc;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	rc = cam_context_buf_done_from_hw(context, evt_data, evt_id);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed in buf done, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/* top state machine */
+static struct cam_ctx_ops
+	cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = {
+	/* Uninit */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Available */
+	{
+		.ioctl_ops = {
+			.acquire_dev = __cam_lrme_ctx_acquire_dev_in_available,
+		},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Acquired */
+	{
+		.ioctl_ops = {
+			.release_dev = __cam_lrme_ctx_release_dev_in_acquired,
+			.start_dev = __cam_lrme_ctx_start_dev_in_acquired,
+		},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Ready */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Activate */
+	{
+		.ioctl_ops = {
+			.config_dev = __cam_lrme_ctx_config_dev_in_activated,
+			.release_dev = __cam_lrme_ctx_release_dev_in_activated,
+			.stop_dev = __cam_lrme_ctx_stop_dev_in_activated,
+		},
+		.crm_ops = {},
+		.irq_ops = __cam_lrme_ctx_handle_irq_in_activated,
+	},
+};
+
+int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
+	struct cam_context *base_ctx,
+	struct cam_hw_mgr_intf *hw_intf,
+	uint64_t index)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	if (!base_ctx || !lrme_ctx) {
+		CAM_ERR(CAM_LRME, "Invalid input");
+		return -EINVAL;
+	}
+
+	memset(lrme_ctx, 0, sizeof(*lrme_ctx));
+
+	rc = cam_context_init(base_ctx, "lrme", NULL, hw_intf,
+		lrme_ctx->req_base, CAM_CTX_REQ_MAX);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to init context");
+		return rc;
+	}
+	lrme_ctx->base = base_ctx;
+	lrme_ctx->index = index;
+	base_ctx->ctx_priv = lrme_ctx;
+	base_ctx->state_machine = cam_lrme_ctx_state_machine;
+
+	return rc;
+}
+
+int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_LRME, "Enter");
+
+	if (!lrme_ctx) {
+		CAM_ERR(CAM_LRME, "No ctx to deinit");
+		return -EINVAL;
+	}
+
+	rc = cam_context_deinit(lrme_ctx->base);
+
+	memset(lrme_ctx, 0, sizeof(*lrme_ctx));
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
new file mode 100644
index 0000000..882f7ac
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
@@ -0,0 +1,41 @@
+/* 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_LRME_CONTEXT_H_
+#define _CAM_LRME_CONTEXT_H_
+
+#include "cam_context.h"
+#include "cam_context_utils.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_interface.h"
+#include "cam_sync_api.h"
+
+#define CAM_LRME_CTX_INDEX_SHIFT 32
+
+/**
+ * struct cam_lrme_context
+ *
+ * @base      : Base context pointer for this LRME context
+ * @req_base  : List of base request for this LRME context
+ */
+struct cam_lrme_context {
+	struct cam_context         *base;
+	struct cam_ctx_request      req_base[CAM_CTX_REQ_MAX];
+	uint64_t index;
+};
+
+int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
+	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
+	uint64_t index);
+int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx);
+
+#endif /* _CAM_LRME_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c
new file mode 100644
index 0000000..5be16ef
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c
@@ -0,0 +1,233 @@
+/* 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_subdev.h"
+#include "cam_node.h"
+#include "cam_lrme_context.h"
+#include "cam_lrme_hw_mgr.h"
+#include "cam_lrme_hw_mgr_intf.h"
+
+#define CAM_LRME_DEV_NAME "cam-lrme"
+
+/**
+ * struct cam_lrme_dev
+ *
+ * @sd       : Subdev information
+ * @ctx      : List of base contexts
+ * @lrme_ctx : List of LRME contexts
+ * @lock     : Mutex for LRME subdev
+ * @open_cnt : Open count of LRME subdev
+ */
+struct cam_lrme_dev {
+	struct cam_subdev        sd;
+	struct cam_context       ctx[CAM_CTX_MAX];
+	struct cam_lrme_context  lrme_ctx[CAM_CTX_MAX];
+	struct mutex             lock;
+	uint32_t                 open_cnt;
+};
+
+static struct cam_lrme_dev *g_lrme_dev;
+
+static int cam_lrme_dev_buf_done_cb(void *ctxt_to_hw_map, uint32_t evt_id,
+	void *evt_data)
+{
+	uint64_t index;
+	struct cam_context *ctx;
+	int rc;
+
+	index = CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map);
+	CAM_DBG(CAM_LRME, "ctx index %llu, evt_id %u\n", index, evt_id);
+	ctx = &g_lrme_dev->ctx[index];
+	rc = ctx->irq_cb_intf(ctx, evt_id, evt_data);
+	if (rc)
+		CAM_ERR(CAM_LRME, "irq callback failed");
+
+	return rc;
+}
+
+static int cam_lrme_dev_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_lrme_dev *lrme_dev = g_lrme_dev;
+
+	if (!lrme_dev) {
+		CAM_ERR(CAM_LRME,
+			"LRME Dev not initialized, dev=%pK", lrme_dev);
+		return -ENODEV;
+	}
+
+	mutex_lock(&lrme_dev->lock);
+	lrme_dev->open_cnt++;
+	mutex_unlock(&lrme_dev->lock);
+
+	return 0;
+}
+
+static int cam_lrme_dev_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_lrme_dev *lrme_dev = g_lrme_dev;
+	struct cam_node *node = v4l2_get_subdevdata(sd);
+
+	if (!lrme_dev) {
+		CAM_ERR(CAM_LRME, "Invalid args");
+		return -ENODEV;
+	}
+
+	mutex_lock(&lrme_dev->lock);
+	lrme_dev->open_cnt--;
+	mutex_unlock(&lrme_dev->lock);
+
+	if (!node) {
+		CAM_ERR(CAM_LRME, "Node is NULL");
+		return -EINVAL;
+	}
+
+	if (lrme_dev->open_cnt == 0)
+		cam_node_shutdown(node);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = {
+	.open = cam_lrme_dev_open,
+	.close = cam_lrme_dev_close,
+};
+
+static int cam_lrme_dev_probe(struct platform_device *pdev)
+{
+	int rc;
+	int i;
+	struct cam_hw_mgr_intf hw_mgr_intf;
+	struct cam_node *node;
+
+	g_lrme_dev = kzalloc(sizeof(struct cam_lrme_dev), GFP_KERNEL);
+	if (!g_lrme_dev) {
+		CAM_ERR(CAM_LRME, "No memory");
+		return -ENOMEM;
+	}
+	g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops;
+
+	mutex_init(&g_lrme_dev->lock);
+
+	rc = cam_subdev_probe(&g_lrme_dev->sd, pdev, CAM_LRME_DEV_NAME,
+		CAM_LRME_DEVICE_TYPE);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "LRME cam_subdev_probe failed");
+		goto free_mem;
+	}
+	node = (struct cam_node *)g_lrme_dev->sd.token;
+
+	rc = cam_lrme_hw_mgr_init(&hw_mgr_intf, cam_lrme_dev_buf_done_cb);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Can not initialized LRME HW manager");
+		goto unregister;
+	}
+
+	for (i = 0; i < CAM_CTX_MAX; i++) {
+		rc = cam_lrme_context_init(&g_lrme_dev->lrme_ctx[i],
+				&g_lrme_dev->ctx[i],
+				&node->hw_mgr_intf, i);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "LRME context init failed");
+			goto deinit_ctx;
+		}
+	}
+
+	rc = cam_node_init(node, &hw_mgr_intf, g_lrme_dev->ctx, CAM_CTX_MAX,
+		CAM_LRME_DEV_NAME);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "LRME node init failed");
+		goto deinit_ctx;
+	}
+
+	CAM_DBG(CAM_LRME, "%s probe complete", g_lrme_dev->sd.name);
+
+	return 0;
+
+deinit_ctx:
+	for (--i; i >= 0; i--) {
+		if (cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]))
+			CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i);
+	}
+unregister:
+	if (cam_subdev_remove(&g_lrme_dev->sd))
+		CAM_ERR(CAM_LRME, "Failed in subdev remove");
+free_mem:
+	kfree(g_lrme_dev);
+
+	return rc;
+}
+
+static int cam_lrme_dev_remove(struct platform_device *pdev)
+{
+	int i;
+	int rc = 0;
+
+	for (i = 0; i < CAM_CTX_MAX; i++) {
+		rc = cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]);
+		if (rc)
+			CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i);
+	}
+
+	rc = cam_lrme_hw_mgr_deinit();
+	if (rc)
+		CAM_ERR(CAM_LRME, "Failed in hw mgr deinit, rc=%d", rc);
+
+	rc = cam_subdev_remove(&g_lrme_dev->sd);
+	if (rc)
+		CAM_ERR(CAM_LRME, "Unregister failed");
+
+	mutex_destroy(&g_lrme_dev->lock);
+	kfree(g_lrme_dev);
+	g_lrme_dev = NULL;
+
+	return rc;
+}
+
+static const struct of_device_id cam_lrme_dt_match[] = {
+	{
+		.compatible = "qcom,cam-lrme"
+	},
+	{}
+};
+
+static struct platform_driver cam_lrme_driver = {
+	.probe = cam_lrme_dev_probe,
+	.remove = cam_lrme_dev_remove,
+	.driver = {
+		.name = "cam_lrme",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_lrme_dt_match,
+	},
+};
+
+static int __init cam_lrme_dev_init_module(void)
+{
+	return platform_driver_register(&cam_lrme_driver);
+}
+
+static void __exit cam_lrme_dev_exit_module(void)
+{
+	platform_driver_unregister(&cam_lrme_driver);
+}
+
+module_init(cam_lrme_dev_init_module);
+module_exit(cam_lrme_dev_exit_module);
+MODULE_DESCRIPTION("MSM LRME driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/Makefile b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/Makefile
new file mode 100644
index 0000000..e4c8e0d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
new file mode 100644
index 0000000..448086d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
@@ -0,0 +1,1034 @@
+/* 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 <linux/kernel.h>
+#include <media/cam_cpas.h>
+#include <media/cam_req_mgr.h>
+
+#include "cam_io_util.h"
+#include "cam_soc_util.h"
+#include "cam_mem_mgr_api.h"
+#include "cam_smmu_api.h"
+#include "cam_packet_util.h"
+#include "cam_lrme_context.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_lrme_hw_mgr_intf.h"
+#include "cam_lrme_hw_mgr.h"
+
+static struct cam_lrme_hw_mgr g_lrme_hw_mgr;
+
+static int cam_lrme_mgr_util_reserve_device(struct cam_lrme_hw_mgr *hw_mgr,
+	struct cam_lrme_acquire_args *lrme_acquire_args)
+{
+	int i, index = 0;
+	uint32_t min_ctx = UINT_MAX;
+	struct cam_lrme_device *hw_device = NULL;
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	if (!hw_mgr->device_count) {
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		CAM_ERR(CAM_LRME, "No device is registered");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < hw_mgr->device_count && i < CAM_LRME_HW_MAX; i++) {
+		hw_device = &hw_mgr->hw_device[i];
+		if (!hw_device->num_context) {
+			index = i;
+			break;
+		}
+		if (hw_device->num_context < min_ctx) {
+			min_ctx = hw_device->num_context;
+			index = i;
+		}
+	}
+
+	hw_device = &hw_mgr->hw_device[index];
+	hw_device->num_context++;
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	CAM_DBG(CAM_LRME, "reserve device index %d", index);
+
+	return index;
+}
+
+static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr,
+	uint32_t device_index, struct cam_lrme_device **hw_device)
+{
+	if (!hw_mgr) {
+		CAM_ERR(CAM_LRME, "invalid params hw_mgr %pK", hw_mgr);
+		return -EINVAL;
+	}
+
+	if (device_index >= CAM_LRME_HW_MAX) {
+		CAM_ERR(CAM_LRME, "Wrong device index %d", device_index);
+		return -EINVAL;
+	}
+
+	*hw_device = &hw_mgr->hw_device[device_index];
+
+	return 0;
+}
+
+static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet)
+{
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	int i, rc;
+
+	if (!packet) {
+		CAM_ERR(CAM_LRME, "Invalid args");
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_LRME, "Packet request=%d, op_code=0x%x, size=%d, flags=%d",
+		packet->header.request_id, packet->header.op_code,
+		packet->header.size, packet->header.flags);
+	CAM_DBG(CAM_LRME,
+		"Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)",
+		packet->cmd_buf_offset, packet->num_cmd_buf,
+		packet->io_configs_offset, packet->num_io_configs);
+	CAM_DBG(CAM_LRME,
+		"Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)",
+		packet->patch_offset, packet->num_patches,
+		packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index);
+
+	if (cam_packet_util_validate_packet(packet)) {
+		CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d",
+			packet->kmd_cmd_buf_index,
+			packet->num_cmd_buf, packet->cmd_buf_offset,
+			packet->io_configs_offset, packet->header.size);
+		return -EINVAL;
+	}
+
+	if (!packet->num_io_configs) {
+		CAM_ERR(CAM_LRME, "no io configs");
+		return -EINVAL;
+	}
+
+	cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)&packet->payload +
+		packet->cmd_buf_offset);
+
+	for (i = 0; i < packet->num_cmd_buf; i++) {
+		if (!cmd_desc[i].length)
+			continue;
+
+		CAM_DBG(CAM_LRME,
+			"CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d",
+			i,
+			cmd_desc[i].mem_handle, cmd_desc[i].offset,
+			cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type,
+			cmd_desc[i].meta_data);
+
+		rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Invalid cmd buffer %d", i);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_lrme_hw_io_buffer *input_buf,
+	struct cam_lrme_hw_io_buffer *output_buf, uint32_t io_buf_size)
+{
+	int rc = -EINVAL;
+	uint32_t num_in_buf, num_out_buf, i, j, plane;
+	struct cam_buf_io_cfg *io_cfg;
+	uint64_t io_addr[CAM_PACKET_MAX_PLANES];
+	size_t size;
+
+	num_in_buf = 0;
+	num_out_buf = 0;
+	io_cfg = (struct cam_buf_io_cfg *)((uint8_t *)
+		 &prepare->packet->payload +
+		 prepare->packet->io_configs_offset);
+
+	for (i = 0; i < prepare->packet->num_io_configs; i++) {
+		CAM_DBG(CAM_LRME,
+			"IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]",
+			i, io_cfg[i].mem_handle[0], io_cfg[i].direction,
+			io_cfg[i].resource_type,
+			io_cfg[i].fence, io_cfg[i].format);
+
+		if ((num_in_buf > io_buf_size) ||
+			(num_out_buf > io_buf_size)) {
+			CAM_ERR(CAM_LRME, "Invalid number of buffers %d %d %d",
+				num_in_buf, num_out_buf, io_buf_size);
+			return -EINVAL;
+		}
+
+		memset(io_addr, 0, sizeof(io_addr));
+		for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) {
+			if (!io_cfg[i].mem_handle[plane])
+				break;
+
+			rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[plane],
+				iommu_hdl, &io_addr[plane], &size);
+			if (rc) {
+				CAM_ERR(CAM_LRME, "Cannot get io buf for %d %d",
+					plane, rc);
+				return -ENOMEM;
+			}
+
+			io_addr[plane] += io_cfg[i].offsets[plane];
+
+			if (io_addr[plane] >> 32) {
+				CAM_ERR(CAM_LRME, "Invalid io addr for %d %d",
+					plane, rc);
+				return -ENOMEM;
+			}
+
+			CAM_DBG(CAM_LRME, "IO Address[%d][%d] : %llu",
+				io_cfg[i].direction, plane, io_addr[plane]);
+		}
+
+		switch (io_cfg[i].direction) {
+		case CAM_BUF_INPUT: {
+			prepare->in_map_entries[num_in_buf].resource_handle =
+				io_cfg[i].resource_type;
+			prepare->in_map_entries[num_in_buf].sync_id =
+				io_cfg[i].fence;
+
+			input_buf[num_in_buf].valid = true;
+			for (j = 0; j < plane; j++)
+				input_buf[num_in_buf].io_addr[j] = io_addr[j];
+			input_buf[num_in_buf].num_plane = plane;
+			input_buf[num_in_buf].io_cfg = &io_cfg[i];
+
+			num_in_buf++;
+			break;
+		}
+		case CAM_BUF_OUTPUT: {
+			prepare->out_map_entries[num_out_buf].resource_handle =
+				io_cfg[i].resource_type;
+			prepare->out_map_entries[num_out_buf].sync_id =
+				io_cfg[i].fence;
+
+			output_buf[num_out_buf].valid = true;
+			for (j = 0; j < plane; j++)
+				output_buf[num_out_buf].io_addr[j] = io_addr[j];
+			output_buf[num_out_buf].num_plane = plane;
+			output_buf[num_out_buf].io_cfg = &io_cfg[i];
+
+			num_out_buf++;
+			break;
+		}
+		default:
+			CAM_ERR(CAM_LRME, "Unsupported io direction %d",
+				io_cfg[i].direction);
+			return -EINVAL;
+		}
+	}
+	prepare->num_in_map_entries = num_in_buf;
+	prepare->num_out_map_entries = num_out_buf;
+
+	return 0;
+}
+
+static int cam_lrme_mgr_util_prepare_hw_update_entries(
+	struct cam_lrme_hw_mgr *hw_mgr,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_lrme_hw_cmd_config_args *config_args,
+	struct cam_kmd_buf_info *kmd_buf_info)
+{
+	int i, rc = 0;
+	struct cam_lrme_device *hw_device = NULL;
+	uint32_t *kmd_buf_addr;
+	uint32_t num_entry;
+	uint32_t kmd_buf_max_size;
+	uint32_t kmd_buf_used_bytes = 0;
+	struct cam_hw_update_entry *hw_entry;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+
+	hw_device = config_args->hw_device;
+	if (!hw_device) {
+		CAM_ERR(CAM_LRME, "Invalid hw_device");
+		return -EINVAL;
+	}
+
+	kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr +
+		kmd_buf_info->used_bytes);
+	kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes;
+
+	config_args->cmd_buf_addr = kmd_buf_addr;
+	config_args->size = kmd_buf_max_size;
+	config_args->config_buf_size = 0;
+
+	if (hw_device->hw_intf.hw_ops.process_cmd) {
+		rc = hw_device->hw_intf.hw_ops.process_cmd(
+			hw_device->hw_intf.hw_priv,
+			CAM_LRME_HW_CMD_PREPARE_HW_UPDATE,
+			config_args,
+			sizeof(struct cam_lrme_hw_cmd_config_args));
+		if (rc) {
+			CAM_ERR(CAM_LRME,
+				"Failed in CMD_PREPARE_HW_UPDATE %d", rc);
+			return rc;
+		}
+	} else {
+		CAM_ERR(CAM_LRME, "Can't find handle function");
+		return -EINVAL;
+	}
+
+	kmd_buf_used_bytes += config_args->config_buf_size;
+
+	if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) {
+		CAM_ERR(CAM_LRME, "Invalid kmd used bytes %d (%d)",
+			kmd_buf_used_bytes, kmd_buf_max_size);
+		return -ENOMEM;
+	}
+
+	hw_entry = prepare->hw_update_entries;
+	num_entry = 0;
+
+	if (config_args->config_buf_size) {
+		if ((num_entry + 1) >= prepare->max_hw_update_entries) {
+			CAM_ERR(CAM_LRME, "Insufficient  HW entries :%d %d",
+				num_entry, prepare->max_hw_update_entries);
+			return -EINVAL;
+		}
+
+		hw_entry[num_entry].handle = kmd_buf_info->handle;
+		hw_entry[num_entry].len = config_args->config_buf_size;
+		hw_entry[num_entry].offset = kmd_buf_info->offset;
+
+		kmd_buf_info->used_bytes += config_args->config_buf_size;
+		kmd_buf_info->offset += config_args->config_buf_size;
+		num_entry++;
+	}
+
+	cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)
+		&prepare->packet->payload + prepare->packet->cmd_buf_offset);
+
+	for (i = 0; i < prepare->packet->num_cmd_buf; i++) {
+		if (!cmd_desc[i].length)
+			continue;
+
+		if ((num_entry + 1) >= prepare->max_hw_update_entries) {
+			CAM_ERR(CAM_LRME, "Exceed max num of entry");
+			return -EINVAL;
+		}
+
+		hw_entry[num_entry].handle = cmd_desc[i].mem_handle;
+		hw_entry[num_entry].len = cmd_desc[i].length;
+		hw_entry[num_entry].offset = cmd_desc[i].offset;
+		num_entry++;
+	}
+	prepare->num_hw_update_entries = num_entry;
+
+	CAM_DBG(CAM_LRME, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)",
+		prepare->num_hw_update_entries, prepare->num_in_map_entries,
+		prepare->num_out_map_entries);
+
+	return rc;
+}
+
+static void cam_lrme_mgr_util_put_frame_req(
+	struct list_head *src_list,
+	struct list_head *list,
+	spinlock_t *lock)
+{
+	spin_lock(lock);
+	list_add_tail(list, src_list);
+	spin_unlock(lock);
+}
+
+static int cam_lrme_mgr_util_get_frame_req(
+	struct list_head *src_list,
+	struct cam_lrme_frame_request **frame_req,
+	spinlock_t *lock)
+{
+	int rc = 0;
+	struct cam_lrme_frame_request *req_ptr = NULL;
+
+	spin_lock(lock);
+	if (!list_empty(src_list)) {
+		req_ptr = list_first_entry(src_list,
+			struct cam_lrme_frame_request, frame_list);
+		list_del_init(&req_ptr->frame_list);
+	} else {
+		rc = -ENOENT;
+	}
+	*frame_req = req_ptr;
+	spin_unlock(lock);
+
+	return rc;
+}
+
+
+static int cam_lrme_mgr_util_submit_req(void *priv, void *data)
+{
+	struct cam_lrme_device *hw_device;
+	struct cam_lrme_hw_mgr *hw_mgr;
+	struct cam_lrme_frame_request *frame_req = NULL;
+	struct cam_lrme_hw_submit_args submit_args;
+	struct cam_lrme_mgr_work_data *work_data;
+	int rc;
+	int req_prio = 0;
+
+	if (!priv) {
+		CAM_ERR(CAM_LRME, "worker doesn't have private data");
+		return -EINVAL;
+	}
+
+	hw_mgr = (struct cam_lrme_hw_mgr *)priv;
+	work_data = (struct cam_lrme_mgr_work_data *)data;
+	hw_device = work_data->hw_device;
+
+	rc = cam_lrme_mgr_util_get_frame_req(&hw_device->
+		frame_pending_list_high, &frame_req, &hw_device->high_req_lock);
+
+	if (!frame_req) {
+		rc = cam_lrme_mgr_util_get_frame_req(&hw_device->
+				frame_pending_list_normal, &frame_req,
+				&hw_device->normal_req_lock);
+		if (frame_req)
+			req_prio = 1;
+	}
+
+	if (!frame_req) {
+		CAM_DBG(CAM_LRME, "No pending request");
+		return 0;
+	}
+
+	if (hw_device->hw_intf.hw_ops.process_cmd) {
+		submit_args.hw_update_entries = frame_req->hw_update_entries;
+		submit_args.num_hw_update_entries =
+			frame_req->num_hw_update_entries;
+		submit_args.frame_req = frame_req;
+
+		rc = hw_device->hw_intf.hw_ops.process_cmd(
+			hw_device->hw_intf.hw_priv,
+			CAM_LRME_HW_CMD_SUBMIT,
+			&submit_args, sizeof(struct cam_lrme_hw_submit_args));
+
+		if (rc == -EBUSY)
+			CAM_DBG(CAM_LRME, "device busy");
+		else if (rc)
+			CAM_ERR(CAM_LRME, "submit request failed rc %d", rc);
+		if (rc) {
+			req_prio == 0 ? spin_lock(&hw_device->high_req_lock) :
+				spin_lock(&hw_device->normal_req_lock);
+			list_add(&frame_req->frame_list,
+				(req_prio == 0 ?
+				 &hw_device->frame_pending_list_high :
+				 &hw_device->frame_pending_list_normal));
+			req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) :
+				spin_unlock(&hw_device->normal_req_lock);
+		}
+		if (rc == -EBUSY)
+			rc = 0;
+	} else {
+		req_prio == 0 ? spin_lock(&hw_device->high_req_lock) :
+			spin_lock(&hw_device->normal_req_lock);
+		list_add(&frame_req->frame_list,
+			(req_prio == 0 ?
+			 &hw_device->frame_pending_list_high :
+			 &hw_device->frame_pending_list_normal));
+		req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) :
+			spin_unlock(&hw_device->normal_req_lock);
+		rc = -EINVAL;
+	}
+
+	CAM_DBG(CAM_LRME, "End of submit, rc %d", rc);
+
+	return rc;
+}
+
+static int cam_lrme_mgr_util_schedule_frame_req(
+	struct cam_lrme_hw_mgr *hw_mgr, struct cam_lrme_device *hw_device)
+{
+	int rc = 0;
+	struct crm_workq_task *task;
+	struct cam_lrme_mgr_work_data *work_data;
+
+	task = cam_req_mgr_workq_get_task(hw_device->work);
+	if (!task) {
+		CAM_ERR(CAM_LRME, "Can not get task for worker");
+		return -ENOMEM;
+	}
+
+	work_data = (struct cam_lrme_mgr_work_data *)task->payload;
+	work_data->hw_device = hw_device;
+
+	task->process_cb = cam_lrme_mgr_util_submit_req;
+	CAM_DBG(CAM_LRME, "enqueue submit task");
+	rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0);
+
+	return rc;
+}
+
+static int cam_lrme_mgr_util_release(struct cam_lrme_hw_mgr *hw_mgr,
+	uint32_t device_index)
+{
+	int rc = 0;
+	struct cam_lrme_device *hw_device;
+
+	rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Error in getting device %d", rc);
+		return rc;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	hw_device->num_context--;
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	return rc;
+}
+
+static int cam_lrme_mgr_cb(void *data,
+	struct cam_lrme_hw_cb_args *cb_args)
+{
+	struct cam_lrme_hw_mgr *hw_mgr = &g_lrme_hw_mgr;
+	int rc = 0;
+	bool frame_abort = true;
+	struct cam_lrme_frame_request *frame_req;
+	struct cam_lrme_device *hw_device;
+
+	if (!data || !cb_args) {
+		CAM_ERR(CAM_LRME, "Invalid input args");
+		return -EINVAL;
+	}
+
+	hw_device = (struct cam_lrme_device *)data;
+	frame_req = cb_args->frame_req;
+
+	if (cb_args->cb_type & CAM_LRME_CB_PUT_FRAME) {
+		memset(frame_req, 0x0, sizeof(*frame_req));
+		INIT_LIST_HEAD(&frame_req->frame_list);
+		cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+				&frame_req->frame_list,
+				&hw_mgr->free_req_lock);
+		cb_args->cb_type &= ~CAM_LRME_CB_PUT_FRAME;
+		frame_req = NULL;
+	}
+
+	if (cb_args->cb_type & CAM_LRME_CB_COMP_REG_UPDATE) {
+		cb_args->cb_type &= ~CAM_LRME_CB_COMP_REG_UPDATE;
+		CAM_DBG(CAM_LRME, "Reg update");
+	}
+
+	if (!frame_req)
+		return rc;
+
+	if (cb_args->cb_type & CAM_LRME_CB_BUF_DONE) {
+		cb_args->cb_type &= ~CAM_LRME_CB_BUF_DONE;
+		frame_abort = false;
+	} else if (cb_args->cb_type & CAM_LRME_CB_ERROR) {
+		cb_args->cb_type &= ~CAM_LRME_CB_ERROR;
+		frame_abort = true;
+	} else {
+		CAM_ERR(CAM_LRME, "Wrong cb type %d, req %lld",
+			cb_args->cb_type, frame_req->req_id);
+		return -EINVAL;
+	}
+
+	if (hw_mgr->event_cb) {
+		struct cam_hw_done_event_data buf_data;
+
+		buf_data.request_id = frame_req->req_id;
+		CAM_DBG(CAM_LRME, "frame req %llu, frame_abort %d",
+			frame_req->req_id, frame_abort);
+		rc = hw_mgr->event_cb(frame_req->ctxt_to_hw_map,
+			frame_abort, &buf_data);
+	} else {
+		CAM_ERR(CAM_LRME, "No cb function");
+	}
+	memset(frame_req, 0x0, sizeof(*frame_req));
+	INIT_LIST_HEAD(&frame_req->frame_list);
+	cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+				&frame_req->frame_list,
+				&hw_mgr->free_req_lock);
+
+	rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device);
+
+	return rc;
+}
+
+static int cam_lrme_mgr_get_caps(void *hw_mgr_priv, void *hw_get_caps_args)
+{
+	int rc = 0;
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_query_cap_cmd *args = hw_get_caps_args;
+
+	if (sizeof(struct cam_lrme_query_cap_cmd) != args->size) {
+		CAM_ERR(CAM_LRME,
+			"sizeof(struct cam_query_cap_cmd) = %lu, args->size = %d",
+			sizeof(struct cam_query_cap_cmd), args->size);
+		return -EFAULT;
+	}
+
+	if (copy_to_user((void __user *)args->caps_handle, &(hw_mgr->lrme_caps),
+		sizeof(struct cam_lrme_query_cap_cmd))) {
+		CAM_ERR(CAM_LRME, "copy to user failed");
+		return -EFAULT;
+	}
+
+	return rc;
+}
+
+static int cam_lrme_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args)
+{
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_acquire_args *args =
+		(struct cam_hw_acquire_args *)hw_acquire_args;
+	struct cam_lrme_acquire_args lrme_acquire_args;
+	uint64_t device_index;
+
+	if (!hw_mgr_priv || !args) {
+		CAM_ERR(CAM_LRME,
+		"Invalid input params hw_mgr_priv %pK, acquire_args %pK",
+		hw_mgr_priv, args);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&lrme_acquire_args,
+		(void __user *)args->acquire_info,
+		sizeof(struct cam_lrme_acquire_args))) {
+		CAM_ERR(CAM_LRME, "Failed to copy acquire args from user");
+		return -EFAULT;
+	}
+
+	device_index = cam_lrme_mgr_util_reserve_device(hw_mgr,
+		&lrme_acquire_args);
+	CAM_DBG(CAM_LRME, "Get device id %llu", device_index);
+
+	if (device_index >= hw_mgr->device_count) {
+		CAM_ERR(CAM_LRME, "Get wrong device id %llu", device_index);
+		return -EINVAL;
+	}
+
+	/* device_index is the right 4 bit in ctxt_to_hw_map */
+	args->ctxt_to_hw_map = (void *)device_index;
+
+	return 0;
+}
+
+static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args)
+{
+	int rc = 0;
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_release_args *args =
+		(struct cam_hw_release_args *)hw_release_args;
+	uint64_t device_index;
+
+	if (!hw_mgr_priv || !hw_release_args) {
+		CAM_ERR(CAM_LRME, "Invalid arguments %pK, %pK",
+			hw_mgr_priv, hw_release_args);
+		return -EINVAL;
+	}
+
+	device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+	if (device_index >= hw_mgr->device_count) {
+		CAM_ERR(CAM_LRME, "Invalid device index %llu", device_index);
+		return -EPERM;
+	}
+
+	rc = cam_lrme_mgr_util_release(hw_mgr, device_index);
+	if (rc)
+		CAM_ERR(CAM_LRME, "Failed in release device, rc=%d", rc);
+
+	return rc;
+}
+
+static int cam_lrme_mgr_hw_start(void *hw_mgr_priv, void *hw_start_args)
+{
+	int rc = 0;
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_start_args *args =
+		(struct cam_hw_start_args *)hw_start_args;
+	struct cam_lrme_device *hw_device;
+	uint32_t device_index;
+
+	if (!hw_mgr || !args) {
+		CAM_ERR(CAM_LRME, "Invald input params");
+		return -EINVAL;
+	}
+
+	device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+	if (device_index >= hw_mgr->device_count) {
+		CAM_ERR(CAM_LRME, "Invalid device index %d", device_index);
+		return -EPERM;
+	}
+
+	CAM_DBG(CAM_LRME, "Start device index %d", device_index);
+
+	rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to get hw device");
+		return rc;
+	}
+
+	if (hw_device->hw_intf.hw_ops.start) {
+		rc = hw_device->hw_intf.hw_ops.start(
+			hw_device->hw_intf.hw_priv, NULL, 0);
+	} else {
+		CAM_ERR(CAM_LRME, "Invald start function");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int cam_lrme_mgr_hw_stop(void *hw_mgr_priv, void *stop_args)
+{
+	int rc = 0;
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_stop_args *args =
+		(struct cam_hw_stop_args *)stop_args;
+	struct cam_lrme_device *hw_device;
+	uint32_t device_index;
+
+	if (!hw_mgr_priv || !stop_args) {
+		CAM_ERR(CAM_LRME, "Invalid arguments");
+		return -EINVAL;
+	}
+
+	device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+	if (device_index >= hw_mgr->device_count) {
+		CAM_ERR(CAM_LRME, "Invalid device index %d", device_index);
+		return -EPERM;
+	}
+
+	CAM_DBG(CAM_LRME, "Stop device index %d", device_index);
+
+	rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to get hw device");
+		return rc;
+	}
+
+	if (hw_device->hw_intf.hw_ops.stop) {
+		rc = hw_device->hw_intf.hw_ops.stop(
+			hw_device->hw_intf.hw_priv, NULL, 0);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Failed in HW stop %d", rc);
+			goto end;
+		}
+	}
+
+end:
+	return rc;
+}
+
+static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv,
+	void *hw_prepare_update_args)
+{
+	int rc = 0, i;
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_prepare_update_args *args =
+		(struct cam_hw_prepare_update_args *)hw_prepare_update_args;
+	struct cam_lrme_device *hw_device;
+	struct cam_kmd_buf_info kmd_buf;
+	struct cam_lrme_hw_cmd_config_args config_args;
+	struct cam_lrme_frame_request *frame_req = NULL;
+	uint32_t device_index;
+
+	if (!hw_mgr_priv || !hw_prepare_update_args) {
+		CAM_ERR(CAM_LRME, "Invalid args %pK %pK",
+			hw_mgr_priv, hw_prepare_update_args);
+		return -EINVAL;
+	}
+
+	device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+	if (device_index >= hw_mgr->device_count) {
+		CAM_ERR(CAM_LRME, "Invalid device index %d", device_index);
+		return -EPERM;
+	}
+
+	rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Error in getting device %d", rc);
+		goto error;
+	}
+
+	rc = cam_lrme_mgr_util_packet_validate(args->packet);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Error in packet validation %d", rc);
+		goto error;
+	}
+
+	rc = cam_packet_util_get_kmd_buffer(args->packet, &kmd_buf);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Error in get kmd buf buffer %d", rc);
+		goto error;
+	}
+
+	CAM_DBG(CAM_LRME,
+		"KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d",
+		kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset,
+		kmd_buf.size, kmd_buf.used_bytes);
+
+	rc = cam_packet_util_process_patches(args->packet,
+		hw_mgr->device_iommu.non_secure, hw_mgr->device_iommu.secure);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Patch packet failed, rc=%d", rc);
+		return rc;
+	}
+
+	memset(&config_args, 0, sizeof(config_args));
+	config_args.hw_device = hw_device;
+
+	rc = cam_lrme_mgr_util_prepare_io_buffer(
+		hw_mgr->device_iommu.non_secure, args,
+		config_args.input_buf, config_args.output_buf,
+		CAM_LRME_MAX_IO_BUFFER);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Error in prepare IO Buf %d", rc);
+		goto error;
+	}
+	/* Check port number */
+	if (args->num_in_map_entries == 0 || args->num_out_map_entries == 0) {
+		CAM_ERR(CAM_LRME, "Error in port number in %d, out %d",
+			args->num_in_map_entries, args->num_out_map_entries);
+		goto error;
+	}
+
+	rc = cam_lrme_mgr_util_prepare_hw_update_entries(hw_mgr, args,
+		&config_args, &kmd_buf);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Error in hw update entries %d", rc);
+		goto error;
+	}
+
+	rc = cam_lrme_mgr_util_get_frame_req(&hw_mgr->frame_free_list,
+		&frame_req, &hw_mgr->free_req_lock);
+	if (rc || !frame_req) {
+		CAM_ERR(CAM_LRME, "Can not get free frame request");
+		goto error;
+	}
+
+	frame_req->ctxt_to_hw_map = args->ctxt_to_hw_map;
+	frame_req->req_id = args->packet->header.request_id;
+	frame_req->hw_device = hw_device;
+	frame_req->num_hw_update_entries = args->num_hw_update_entries;
+	for (i = 0; i < args->num_hw_update_entries; i++)
+		frame_req->hw_update_entries[i] = args->hw_update_entries[i];
+
+	args->priv = frame_req;
+
+	CAM_DBG(CAM_LRME, "FramePrepare : Frame[%lld]", frame_req->req_id);
+
+	return 0;
+
+error:
+	return rc;
+}
+
+static int cam_lrme_mgr_hw_config(void *hw_mgr_priv,
+	void *hw_config_args)
+{
+	int rc = 0;
+	struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_config_args *args =
+		(struct cam_hw_config_args *)hw_config_args;
+	struct cam_lrme_frame_request *frame_req;
+	struct cam_lrme_device *hw_device = NULL;
+	enum cam_lrme_hw_mgr_ctx_priority priority;
+
+	if (!hw_mgr_priv || !hw_config_args) {
+		CAM_ERR(CAM_LRME, "Invalid arguments, hw_mgr %pK, config %pK",
+			hw_mgr_priv, hw_config_args);
+		return -EINVAL;
+	}
+
+	if (!args->num_hw_update_entries) {
+		CAM_ERR(CAM_LRME, "No hw update entries");
+		return -EINVAL;
+	}
+
+	frame_req = (struct cam_lrme_frame_request *)args->priv;
+	if (!frame_req) {
+		CAM_ERR(CAM_LRME, "No frame request");
+		return -EINVAL;
+	}
+
+	hw_device = frame_req->hw_device;
+	if (!hw_device)
+		return -EINVAL;
+
+	priority = CAM_LRME_DECODE_PRIORITY(args->ctxt_to_hw_map);
+	if (priority == CAM_LRME_PRIORITY_HIGH) {
+		cam_lrme_mgr_util_put_frame_req(
+			&hw_device->frame_pending_list_high,
+			&frame_req->frame_list, &hw_device->high_req_lock);
+	} else {
+		cam_lrme_mgr_util_put_frame_req(
+			&hw_device->frame_pending_list_normal,
+			&frame_req->frame_list, &hw_device->normal_req_lock);
+	}
+
+	CAM_DBG(CAM_LRME, "schedule req %llu", frame_req->req_id);
+	rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device);
+
+	return rc;
+}
+
+int cam_lrme_mgr_register_device(
+	struct cam_hw_intf *lrme_hw_intf,
+	struct cam_iommu_handle *device_iommu,
+	struct cam_iommu_handle *cdm_iommu)
+{
+	struct cam_lrme_device *hw_device;
+	char buf[128];
+	int i, rc;
+
+	hw_device = &g_lrme_hw_mgr.hw_device[lrme_hw_intf->hw_idx];
+
+	g_lrme_hw_mgr.device_iommu = *device_iommu;
+	g_lrme_hw_mgr.cdm_iommu = *cdm_iommu;
+
+	memcpy(&hw_device->hw_intf, lrme_hw_intf, sizeof(struct cam_hw_intf));
+
+	spin_lock_init(&hw_device->high_req_lock);
+	spin_lock_init(&hw_device->normal_req_lock);
+	INIT_LIST_HEAD(&hw_device->frame_pending_list_high);
+	INIT_LIST_HEAD(&hw_device->frame_pending_list_normal);
+
+	rc = snprintf(buf, sizeof(buf), "cam_lrme_device_submit_worker%d",
+		lrme_hw_intf->hw_idx);
+	CAM_DBG(CAM_LRME, "Create submit workq for %s", buf);
+	rc = cam_req_mgr_workq_create(buf,
+		CAM_LRME_WORKQ_NUM_TASK,
+		&hw_device->work, CRM_WORKQ_USAGE_NON_IRQ);
+	if (rc) {
+		CAM_ERR(CAM_LRME,
+			"Unable to create a worker, rc=%d", rc);
+		return rc;
+	}
+
+	for (i = 0; i < CAM_LRME_WORKQ_NUM_TASK; i++)
+		hw_device->work->task.pool[i].payload =
+			&hw_device->work_data[i];
+
+	if (hw_device->hw_intf.hw_ops.process_cmd) {
+		struct cam_lrme_hw_cmd_set_cb cb_args;
+
+		cb_args.cam_lrme_hw_mgr_cb = cam_lrme_mgr_cb;
+		cb_args.data = hw_device;
+
+		rc = hw_device->hw_intf.hw_ops.process_cmd(
+			hw_device->hw_intf.hw_priv,
+			CAM_LRME_HW_CMD_REGISTER_CB,
+			&cb_args, sizeof(cb_args));
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Register cb failed");
+			goto destroy_workqueue;
+		}
+		CAM_DBG(CAM_LRME, "cb registered");
+	}
+
+	if (hw_device->hw_intf.hw_ops.get_hw_caps) {
+		rc = hw_device->hw_intf.hw_ops.get_hw_caps(
+			hw_device->hw_intf.hw_priv, &hw_device->hw_caps,
+			sizeof(hw_device->hw_caps));
+		if (rc)
+			CAM_ERR(CAM_LRME, "Get caps failed");
+	} else {
+		CAM_ERR(CAM_LRME, "No get_hw_caps function");
+		goto destroy_workqueue;
+	}
+	g_lrme_hw_mgr.lrme_caps.dev_caps[lrme_hw_intf->hw_idx] =
+		hw_device->hw_caps;
+	g_lrme_hw_mgr.device_count++;
+	g_lrme_hw_mgr.lrme_caps.device_iommu = g_lrme_hw_mgr.device_iommu;
+	g_lrme_hw_mgr.lrme_caps.cdm_iommu = g_lrme_hw_mgr.cdm_iommu;
+	g_lrme_hw_mgr.lrme_caps.num_devices = g_lrme_hw_mgr.device_count;
+
+	hw_device->valid = true;
+
+	CAM_DBG(CAM_LRME, "device registration done");
+	return 0;
+
+destroy_workqueue:
+	cam_req_mgr_workq_destroy(&hw_device->work);
+
+	return rc;
+}
+
+int cam_lrme_mgr_deregister_device(int device_index)
+{
+	struct cam_lrme_device *hw_device;
+
+	hw_device = &g_lrme_hw_mgr.hw_device[device_index];
+	cam_req_mgr_workq_destroy(&hw_device->work);
+	memset(hw_device, 0x0, sizeof(struct cam_lrme_device));
+	g_lrme_hw_mgr.device_count--;
+
+	return 0;
+}
+
+int cam_lrme_hw_mgr_deinit(void)
+{
+	mutex_destroy(&g_lrme_hw_mgr.hw_mgr_mutex);
+	memset(&g_lrme_hw_mgr, 0x0, sizeof(g_lrme_hw_mgr));
+
+	return 0;
+}
+
+int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf,
+	cam_hw_event_cb_func cam_lrme_dev_buf_done_cb)
+{
+	int i, rc = 0;
+	struct cam_lrme_frame_request *frame_req;
+
+	if (!hw_mgr_intf)
+		return -EINVAL;
+
+	CAM_DBG(CAM_LRME, "device count %d", g_lrme_hw_mgr.device_count);
+	if (g_lrme_hw_mgr.device_count > CAM_LRME_HW_MAX) {
+		CAM_ERR(CAM_LRME, "Invalid count of devices");
+		return -EINVAL;
+	}
+
+	memset(hw_mgr_intf, 0, sizeof(*hw_mgr_intf));
+
+	mutex_init(&g_lrme_hw_mgr.hw_mgr_mutex);
+	spin_lock_init(&g_lrme_hw_mgr.free_req_lock);
+	INIT_LIST_HEAD(&g_lrme_hw_mgr.frame_free_list);
+
+	/* Init hw mgr frame requests and add to free list */
+	for (i = 0; i < CAM_CTX_REQ_MAX * CAM_CTX_MAX; i++) {
+		frame_req = &g_lrme_hw_mgr.frame_req[i];
+
+		memset(frame_req, 0x0, sizeof(*frame_req));
+		INIT_LIST_HEAD(&frame_req->frame_list);
+
+		list_add_tail(&frame_req->frame_list,
+			&g_lrme_hw_mgr.frame_free_list);
+	}
+
+	hw_mgr_intf->hw_mgr_priv = &g_lrme_hw_mgr;
+	hw_mgr_intf->hw_get_caps = cam_lrme_mgr_get_caps;
+	hw_mgr_intf->hw_acquire = cam_lrme_mgr_hw_acquire;
+	hw_mgr_intf->hw_release = cam_lrme_mgr_hw_release;
+	hw_mgr_intf->hw_start = cam_lrme_mgr_hw_start;
+	hw_mgr_intf->hw_stop = cam_lrme_mgr_hw_stop;
+	hw_mgr_intf->hw_prepare_update = cam_lrme_mgr_hw_prepare_update;
+	hw_mgr_intf->hw_config = cam_lrme_mgr_hw_config;
+	hw_mgr_intf->hw_read = NULL;
+	hw_mgr_intf->hw_write = NULL;
+	hw_mgr_intf->hw_close = NULL;
+
+	g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb;
+
+	CAM_DBG(CAM_LRME, "Hw mgr init done");
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h
new file mode 100644
index 0000000..f7ce4d2
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.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_LRME_HW_MGR_H_
+#define _CAM_LRME_HW_MGR_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <media/cam_lrme.h>
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_cpas_api.h"
+#include "cam_debug_util.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_context.h"
+
+#define CAM_LRME_HW_MAX 1
+#define CAM_LRME_WORKQ_NUM_TASK 10
+
+#define CAM_LRME_DECODE_DEVICE_INDEX(ctxt_to_hw_map) \
+	((uint64_t)ctxt_to_hw_map & 0xF)
+
+#define CAM_LRME_DECODE_PRIORITY(ctxt_to_hw_map) \
+	(((uint64_t)ctxt_to_hw_map & 0xF0) >> 4)
+
+#define CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map) \
+	((uint64_t)ctxt_to_hw_map >> CAM_LRME_CTX_INDEX_SHIFT)
+
+/**
+ * enum cam_lrme_hw_mgr_ctx_priority
+ *
+ * CAM_LRME_PRIORITY_HIGH   : High priority client
+ * CAM_LRME_PRIORITY_NORMAL : Normal priority client
+ */
+enum cam_lrme_hw_mgr_ctx_priority {
+	CAM_LRME_PRIORITY_HIGH,
+	CAM_LRME_PRIORITY_NORMAL,
+};
+
+/**
+ * struct cam_lrme_mgr_work_data : HW Mgr work data
+ *
+ * hw_device : Pointer to the hw device
+ */
+struct cam_lrme_mgr_work_data {
+	struct cam_lrme_device *hw_device;
+};
+
+/**
+ * struct cam_lrme_device     : LRME HW device
+ *
+ * @hw_caps                   : HW device's capabilities
+ * @hw_intf                   : HW device's interface information
+ * @num_context               : Number of contexts using this device
+ * @valid                     : Whether this device is valid
+ * @work                      : HW device's work queue
+ * @work_data                 : HW device's work data
+ * @frame_pending_list_high   : High priority request queue
+ * @frame_pending_list_normal : Normal priority request queue
+ * @high_req_lock             : Spinlock of high priority queue
+ * @normal_req_lock           : Spinlock of normal priority queue
+ */
+struct cam_lrme_device {
+	struct cam_lrme_dev_cap        hw_caps;
+	struct cam_hw_intf             hw_intf;
+	uint32_t                       num_context;
+	bool                           valid;
+	struct cam_req_mgr_core_workq *work;
+	struct cam_lrme_mgr_work_data  work_data[CAM_LRME_WORKQ_NUM_TASK];
+	struct list_head               frame_pending_list_high;
+	struct list_head               frame_pending_list_normal;
+	spinlock_t                     high_req_lock;
+	spinlock_t                     normal_req_lock;
+};
+
+/**
+ * struct cam_lrme_hw_mgr : LRME HW manager
+ *
+ * @device_count    : Number of HW devices
+ * @frame_free_list : List of free frame request
+ * @hw_mgr_mutex    : Mutex to protect HW manager data
+ * @free_req_lock   :Spinlock to protect frame_free_list
+ * @hw_device       : List of HW devices
+ * @device_iommu    : Device iommu
+ * @cdm_iommu       : cdm iommu
+ * @frame_req       : List of frame request to use
+ * @lrme_caps       : LRME capabilities
+ * @event_cb        : IRQ callback function
+ */
+struct cam_lrme_hw_mgr {
+	uint32_t                      device_count;
+	struct list_head              frame_free_list;
+	struct mutex                  hw_mgr_mutex;
+	spinlock_t                    free_req_lock;
+	struct cam_lrme_device        hw_device[CAM_LRME_HW_MAX];
+	struct cam_iommu_handle       device_iommu;
+	struct cam_iommu_handle       cdm_iommu;
+	struct cam_lrme_frame_request frame_req[CAM_CTX_REQ_MAX * CAM_CTX_MAX];
+	struct cam_lrme_query_cap_cmd lrme_caps;
+	cam_hw_event_cb_func          event_cb;
+};
+
+int cam_lrme_mgr_register_device(struct cam_hw_intf *lrme_hw_intf,
+	struct cam_iommu_handle *device_iommu,
+	struct cam_iommu_handle *cdm_iommu);
+int cam_lrme_mgr_deregister_device(int device_index);
+
+#endif /* _CAM_LRME_HW_MGR_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h
new file mode 100644
index 0000000..8bb609c
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h
@@ -0,0 +1,25 @@
+/* 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_LRME_HW_MGR_INTF_H_
+#define _CAM_LRME_HW_MGR_INTF_H_
+
+#include <linux/of.h>
+
+#include "cam_debug_util.h"
+#include "cam_hw_mgr_intf.h"
+
+int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf,
+	cam_hw_event_cb_func cam_lrme_dev_buf_done_cb);
+int cam_lrme_hw_mgr_deinit(void);
+
+#endif /* _CAM_LRME_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile
new file mode 100644
index 0000000..c65d862
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile
@@ -0,0 +1,13 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw
+ccflags-y += -Idrivers/media/platform/msm/camera0
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_dev.o cam_lrme_hw_core.o cam_lrme_hw_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
new file mode 100644
index 0000000..0318739
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -0,0 +1,1022 @@
+/* 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 "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_smmu_api.h"
+
+static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer,
+	uint32_t *index, uint32_t reg_offset, uint32_t reg_value)
+{
+	buffer[(*index)++] = reg_offset;
+	buffer[(*index)++] = reg_value;
+}
+
+static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf,
+	uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd,
+	struct cam_lrme_hw_info *hw_info)
+{
+	uint32_t reg_val;
+
+	/* 1. config buffer size */
+	reg_val = io_buf->io_cfg->planes[0].width;
+	reg_val |= (io_buf->io_cfg->planes[0].height << 16);
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size,
+		reg_val);
+
+	CAM_DBG(CAM_LRME,
+		"width %d", io_buf->io_cfg->planes[0].width);
+	CAM_DBG(CAM_LRME,
+		"height %d", io_buf->io_cfg->planes[0].height);
+
+	/* 2. config image address */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_rd_reg.bus_client_reg[index].addr_image,
+		io_buf->io_addr[0]);
+
+	CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]);
+
+	/* 3. config stride */
+	reg_val = io_buf->io_cfg->planes[0].plane_stride;
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_rd_reg.bus_client_reg[index].rd_stride,
+		reg_val);
+
+	CAM_DBG(CAM_LRME, "plane_stride %d",
+		io_buf->io_cfg->planes[0].plane_stride);
+
+	/* 4. enable client */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1);
+
+	/* 5. unpack_cfg */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, 0x0);
+}
+
+static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf,
+	uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd,
+	struct cam_lrme_hw_info *hw_info)
+{
+	/* config client mode */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_wr_reg.bus_client_reg[index].cfg,
+		0x1);
+
+	/* image address */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_wr_reg.bus_client_reg[index].addr_image,
+		io_buf->io_addr[0]);
+	CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]);
+
+	/* buffer width and height */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_wr_reg.bus_client_reg[index].buffer_width_cfg,
+		io_buf->io_cfg->planes[0].width);
+	CAM_DBG(CAM_LRME, "width %d", io_buf->io_cfg->planes[0].width);
+
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_wr_reg.bus_client_reg[index].buffer_height_cfg,
+		io_buf->io_cfg->planes[0].height);
+	CAM_DBG(CAM_LRME, "height %d", io_buf->io_cfg->planes[0].height);
+
+	/* packer cfg */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_wr_reg.bus_client_reg[index].packer_cfg,
+		(index == 0) ? 0x1 : 0x5);
+
+	/* client stride */
+	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+		hw_info->bus_wr_reg.bus_client_reg[index].wr_stride,
+		io_buf->io_cfg->planes[0].meta_stride);
+	CAM_DBG(CAM_LRME, "plane_stride %d",
+		io_buf->io_cfg->planes[0].plane_stride);
+}
+
+
+static int cam_lrme_hw_util_process_config_hw(struct cam_hw_info *lrme_hw,
+	struct cam_lrme_hw_cmd_config_args *config_args)
+{
+	int i;
+	struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+	struct cam_lrme_cdm_info *hw_cdm_info;
+	uint32_t *cmd_buf_addr = config_args->cmd_buf_addr;
+	uint32_t reg_val_pair[CAM_LRME_MAX_REG_PAIR_NUM];
+	struct cam_lrme_hw_io_buffer *io_buf;
+	struct cam_lrme_hw_info *hw_info =
+		((struct cam_lrme_core *)lrme_hw->core_info)->hw_info;
+	uint32_t num_cmd = 0;
+	uint32_t size;
+	uint32_t mem_base, available_size = config_args->size;
+	uint32_t output_res_mask = 0, input_res_mask = 0;
+
+
+	if (!cmd_buf_addr) {
+		CAM_ERR(CAM_LRME, "Invalid input args");
+		return -EINVAL;
+	}
+
+	hw_cdm_info =
+		((struct cam_lrme_core *)lrme_hw->core_info)->hw_cdm_info;
+
+	for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) {
+		io_buf = &config_args->input_buf[i];
+
+		if (io_buf->valid == false)
+			break;
+
+		if (io_buf->io_cfg->direction != CAM_BUF_INPUT) {
+			CAM_ERR(CAM_LRME, "Incorrect direction %d %d",
+				io_buf->io_cfg->direction, CAM_BUF_INPUT);
+			return -EINVAL;
+		}
+		CAM_DBG(CAM_LRME,
+			"resource_type %d", io_buf->io_cfg->resource_type);
+
+		switch (io_buf->io_cfg->resource_type) {
+		case CAM_LRME_IO_TYPE_TAR:
+			cam_lrme_hw_util_fill_fe_reg(io_buf, 0, reg_val_pair,
+				&num_cmd, hw_info);
+
+			input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_TAR;
+			break;
+		case CAM_LRME_IO_TYPE_REF:
+			cam_lrme_hw_util_fill_fe_reg(io_buf, 1, reg_val_pair,
+				&num_cmd, hw_info);
+
+			input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_REF;
+			break;
+		default:
+			CAM_ERR(CAM_LRME, "wrong resource_type %d",
+				io_buf->io_cfg->resource_type);
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++)
+		if (!((input_res_mask >> i) & 0x1))
+			cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd,
+				hw_info->bus_rd_reg.bus_client_reg[i].core_cfg,
+				0x0);
+
+	for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) {
+		io_buf = &config_args->output_buf[i];
+
+		if (io_buf->valid == false)
+			break;
+
+		if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) {
+			CAM_ERR(CAM_LRME, "Incorrect direction %d %d",
+				io_buf->io_cfg->direction, CAM_BUF_INPUT);
+			return -EINVAL;
+		}
+
+		CAM_DBG(CAM_LRME, "resource_type %d",
+			io_buf->io_cfg->resource_type);
+		switch (io_buf->io_cfg->resource_type) {
+		case CAM_LRME_IO_TYPE_DS2:
+			cam_lrme_hw_util_fill_we_reg(io_buf, 0, reg_val_pair,
+				&num_cmd, hw_info);
+
+			output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_DS2;
+			break;
+		case CAM_LRME_IO_TYPE_RES:
+			cam_lrme_hw_util_fill_we_reg(io_buf, 1, reg_val_pair,
+				&num_cmd, hw_info);
+
+			output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_RES;
+			break;
+
+		default:
+			CAM_ERR(CAM_LRME, "wrong resource_type %d",
+				io_buf->io_cfg->resource_type);
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++)
+		if (!((output_res_mask >> i) & 0x1))
+			cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd,
+				hw_info->bus_wr_reg.bus_client_reg[i].cfg, 0x0);
+
+	if (output_res_mask) {
+		/* write composite mask */
+		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd,
+			hw_info->bus_wr_reg.common_reg.composite_mask_0,
+			output_res_mask);
+	}
+
+	size = hw_cdm_info->cdm_ops->cdm_required_size_changebase();
+	if ((size * 4) > available_size) {
+		CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d",
+			available_size, size);
+		return -EINVAL;
+	}
+
+	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, CAM_LRME_BASE_IDX);
+
+	hw_cdm_info->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base);
+	cmd_buf_addr += size;
+	available_size -= (size * 4);
+
+	size = hw_cdm_info->cdm_ops->cdm_required_size_reg_random(
+		num_cmd / 2);
+
+	if ((size * 4) > available_size) {
+		CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d",
+			available_size, size);
+		return -ENOMEM;
+	}
+
+	hw_cdm_info->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmd / 2,
+		reg_val_pair);
+	cmd_buf_addr += size;
+	available_size -= (size * 4);
+
+	config_args->config_buf_size =
+		config_args->size - available_size;
+
+	return 0;
+}
+
+static int cam_lrme_hw_util_submit_go(struct cam_hw_info *lrme_hw)
+{
+	struct cam_lrme_core *lrme_core;
+	struct cam_hw_soc_info *soc_info;
+	struct cam_lrme_hw_info   *hw_info;
+
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+	hw_info = lrme_core->hw_info;
+	soc_info = &lrme_hw->soc_info;
+
+	cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+		hw_info->bus_rd_reg.common_reg.cmd);
+
+	return 0;
+}
+
+static int cam_lrme_hw_util_reset(struct cam_hw_info *lrme_hw,
+	uint32_t reset_type)
+{
+	struct cam_lrme_core *lrme_core;
+	struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+	struct cam_lrme_hw_info *hw_info;
+	long time_left;
+
+	lrme_core = lrme_hw->core_info;
+	hw_info = lrme_core->hw_info;
+
+	switch (reset_type) {
+	case CAM_LRME_HW_RESET_TYPE_HW_RESET:
+		reinit_completion(&lrme_core->reset_complete);
+		cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+			hw_info->titan_reg.top_rst_cmd);
+		time_left = wait_for_completion_timeout(
+			&lrme_core->reset_complete,
+			msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT));
+		if (time_left <= 0) {
+			CAM_ERR(CAM_LRME,
+				"HW reset wait failed time_left=%ld",
+				time_left);
+			return -ETIMEDOUT;
+		}
+		break;
+	case CAM_LRME_HW_RESET_TYPE_SW_RESET:
+		cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base +
+			hw_info->bus_wr_reg.common_reg.sw_reset);
+		cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base +
+			hw_info->bus_rd_reg.common_reg.sw_reset);
+		reinit_completion(&lrme_core->reset_complete);
+		cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base +
+			hw_info->titan_reg.top_rst_cmd);
+		time_left = wait_for_completion_timeout(
+			&lrme_core->reset_complete,
+			msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT));
+		if (time_left <= 0) {
+			CAM_ERR(CAM_LRME,
+				"SW reset wait failed time_left=%ld",
+				time_left);
+			return -ETIMEDOUT;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw,
+	struct cam_lrme_dev_cap *hw_caps)
+{
+	struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+	struct cam_lrme_hw_info *hw_info =
+		((struct cam_lrme_core *)lrme_hw->core_info)->hw_info;
+	uint32_t reg_value;
+
+	if (!hw_info) {
+		CAM_ERR(CAM_LRME, "Invalid hw info data");
+		return -EINVAL;
+	}
+
+	reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		hw_info->clc_reg.clc_hw_version);
+	hw_caps->clc_hw_version.gen =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+	hw_caps->clc_hw_version.rev =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+	hw_caps->clc_hw_version.step =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+	reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		hw_info->bus_rd_reg.common_reg.hw_version);
+	hw_caps->bus_rd_hw_version.gen =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+	hw_caps->bus_rd_hw_version.rev =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+	hw_caps->bus_rd_hw_version.step =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+	reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		hw_info->bus_wr_reg.common_reg.hw_version);
+	hw_caps->bus_wr_hw_version.gen =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+	hw_caps->bus_wr_hw_version.rev =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+	hw_caps->bus_wr_hw_version.step =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+	reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		hw_info->titan_reg.top_hw_version);
+	hw_caps->top_hw_version.gen =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+	hw_caps->top_hw_version.rev =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+	hw_caps->top_hw_version.step =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+	reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		hw_info->titan_reg.top_titan_version);
+	hw_caps->top_titan_version.gen =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+	hw_caps->top_titan_version.rev =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+	hw_caps->top_titan_version.step =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+	return 0;
+}
+
+static int cam_lrme_hw_util_submit_req(struct cam_lrme_core *lrme_core,
+	struct cam_lrme_frame_request *frame_req)
+{
+	struct cam_lrme_cdm_info *hw_cdm_info =
+		lrme_core->hw_cdm_info;
+	struct cam_cdm_bl_request *cdm_cmd = hw_cdm_info->cdm_cmd;
+	struct cam_hw_update_entry *cmd;
+	int i, rc = 0;
+
+	if (frame_req->num_hw_update_entries > 0) {
+		cdm_cmd->cmd_arrary_count = frame_req->num_hw_update_entries;
+		cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE;
+		cdm_cmd->flag = false;
+		cdm_cmd->userdata = NULL;
+		cdm_cmd->cookie = 0;
+
+		for (i = 0; i <= frame_req->num_hw_update_entries; i++) {
+			cmd = (frame_req->hw_update_entries + i);
+			cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle;
+			cdm_cmd->cmd[i].offset = cmd->offset;
+			cdm_cmd->cmd[i].len = cmd->len;
+		}
+
+		rc = cam_cdm_submit_bls(hw_cdm_info->cdm_handle, cdm_cmd);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Failed to submit cdm commands");
+			return -EINVAL;
+		}
+	} else {
+		CAM_ERR(CAM_LRME, "No hw update entry");
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int cam_lrme_hw_util_process_err(struct cam_hw_info *lrme_hw)
+{
+	struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+	struct cam_lrme_frame_request *req_proc, *req_submit;
+	struct cam_lrme_hw_cb_args cb_args;
+	int rc;
+
+	req_proc = lrme_core->req_proc;
+	req_submit = lrme_core->req_submit;
+	cb_args.cb_type = CAM_LRME_CB_ERROR;
+
+	if ((lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) &&
+		(lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING) &&
+		(lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND)) {
+		CAM_ERR(CAM_LRME, "Get error irq in wrong state %d",
+			lrme_core->state);
+	}
+
+	CAM_ERR_RATE_LIMIT(CAM_LRME, "Start recovery");
+	lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY;
+	rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET);
+	if (rc)
+		CAM_ERR(CAM_LRME, "Failed to reset");
+
+	lrme_core->req_proc = NULL;
+	lrme_core->req_submit = NULL;
+	if (!rc)
+		lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+
+	cb_args.frame_req = req_proc;
+	lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data,
+		&cb_args);
+
+	cb_args.frame_req = req_submit;
+	lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data,
+		&cb_args);
+
+	return rc;
+}
+
+static int cam_lrme_hw_util_process_reg_update(
+	struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args)
+{
+	struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+	int rc = 0;
+
+	cb_args->cb_type |= CAM_LRME_CB_COMP_REG_UPDATE;
+	if (lrme_core->state == CAM_LRME_CORE_STATE_REQ_PENDING) {
+		lrme_core->state = CAM_LRME_CORE_STATE_PROCESSING;
+	} else {
+		CAM_ERR(CAM_LRME, "Reg update in wrong state %d",
+			lrme_core->state);
+		rc = cam_lrme_hw_util_process_err(lrme_hw);
+		if (rc)
+			CAM_ERR(CAM_LRME, "Failed to reset");
+		return -EINVAL;
+	}
+
+	lrme_core->req_proc = lrme_core->req_submit;
+	lrme_core->req_submit = NULL;
+
+	return 0;
+}
+
+static int cam_lrme_hw_util_process_idle(
+	struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args)
+{
+	struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+	int rc = 0;
+
+	cb_args->cb_type |= CAM_LRME_CB_BUF_DONE;
+	switch (lrme_core->state) {
+	case CAM_LRME_CORE_STATE_REQ_PROC_PEND:
+		cam_lrme_hw_util_submit_go(lrme_hw);
+		lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING;
+		break;
+
+	case CAM_LRME_CORE_STATE_PROCESSING:
+		lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+		break;
+
+	default:
+		CAM_ERR(CAM_LRME, "Idle in wrong state %d",
+			lrme_core->state);
+		rc = cam_lrme_hw_util_process_err(lrme_hw);
+		return rc;
+	}
+	cb_args->frame_req = lrme_core->req_proc;
+	lrme_core->req_proc = NULL;
+
+	return 0;
+}
+
+void cam_lrme_set_irq(struct cam_hw_info *lrme_hw,
+	enum cam_lrme_irq_set set)
+{
+	struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+	struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+	struct cam_lrme_hw_info *hw_info = lrme_core->hw_info;
+
+	switch (set) {
+	case CAM_LRME_IRQ_ENABLE:
+		cam_io_w_mb(0xFFFF,
+			soc_info->reg_map[0].mem_base +
+			hw_info->titan_reg.top_irq_mask);
+		cam_io_w_mb(0xFFFF,
+			soc_info->reg_map[0].mem_base +
+			hw_info->bus_wr_reg.common_reg.irq_mask_0);
+		cam_io_w_mb(0xFFFF,
+			soc_info->reg_map[0].mem_base +
+			hw_info->bus_wr_reg.common_reg.irq_mask_1);
+		cam_io_w_mb(0xFFFF,
+			soc_info->reg_map[0].mem_base +
+			hw_info->bus_rd_reg.common_reg.irq_mask);
+		break;
+
+	case CAM_LRME_IRQ_DISABLE:
+		cam_io_w_mb(0x0,
+			soc_info->reg_map[0].mem_base +
+			hw_info->titan_reg.top_irq_mask);
+		cam_io_w_mb(0x0,
+			soc_info->reg_map[0].mem_base +
+			hw_info->bus_wr_reg.common_reg.irq_mask_0);
+		cam_io_w_mb(0x0,
+			soc_info->reg_map[0].mem_base +
+			hw_info->bus_wr_reg.common_reg.irq_mask_1);
+		cam_io_w_mb(0x0,
+			soc_info->reg_map[0].mem_base +
+			hw_info->bus_rd_reg.common_reg.irq_mask);
+		break;
+	}
+}
+
+
+int cam_lrme_hw_process_irq(void *priv, void *data)
+{
+	struct cam_lrme_hw_work_data *work_data;
+	struct cam_hw_info *lrme_hw;
+	struct cam_lrme_core *lrme_core;
+	int rc = 0;
+	uint32_t top_irq_status, fe_irq_status;
+	uint32_t *we_irq_status;
+	struct cam_lrme_hw_cb_args cb_args;
+
+	if (!data || !priv) {
+		CAM_ERR(CAM_LRME, "Invalid data %pK %pK", data, priv);
+		return -EINVAL;
+	}
+
+	memset(&cb_args, 0, sizeof(struct cam_lrme_hw_cb_args));
+	lrme_hw = (struct cam_hw_info *)priv;
+	work_data = (struct cam_lrme_hw_work_data *)data;
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+	top_irq_status = work_data->top_irq_status;
+	fe_irq_status = work_data->fe_irq_status;
+	we_irq_status = work_data->we_irq_status;
+
+	CAM_DBG(CAM_LRME,
+		"top status %x, fe status %x, we status0 %x, we status1 %x",
+		top_irq_status, fe_irq_status, we_irq_status[0],
+		we_irq_status[1]);
+	CAM_DBG(CAM_LRME, "Current state %d", lrme_core->state);
+
+	mutex_lock(&lrme_hw->hw_mutex);
+
+	if (top_irq_status & (1 << 3)) {
+		CAM_DBG(CAM_LRME, "Error");
+		rc = cam_lrme_hw_util_process_err(lrme_hw);
+		if (rc)
+			CAM_ERR(CAM_LRME, "Process error failed");
+		goto end;
+	}
+
+	if (we_irq_status[0] & (1 << 1)) {
+		CAM_DBG(CAM_LRME, "reg update");
+		rc = cam_lrme_hw_util_process_reg_update(lrme_hw, &cb_args);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Process reg_update failed");
+			goto end;
+		}
+	}
+
+	if (top_irq_status & (1 << 4)) {
+		CAM_DBG(CAM_LRME, "IDLE");
+
+		rc = cam_lrme_hw_util_process_idle(lrme_hw, &cb_args);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Process idle failed");
+			goto end;
+		}
+	}
+
+	if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) {
+		lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->
+			hw_mgr_cb.data, &cb_args);
+	} else {
+		CAM_ERR(CAM_LRME, "No hw mgr cb");
+		rc = -EINVAL;
+	}
+
+end:
+	mutex_unlock(&lrme_hw->hw_mutex);
+	return rc;
+}
+
+int cam_lrme_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size)
+{
+	struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+	int rc = 0;
+	struct cam_lrme_core *lrme_core;
+
+	if (!lrme_hw) {
+		CAM_ERR(CAM_LRME,
+			"Invalid input params, lrme_hw %pK",
+			lrme_hw);
+		return -EINVAL;
+	}
+
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+
+	mutex_lock(&lrme_hw->hw_mutex);
+
+	if (lrme_hw->open_count > 0) {
+		CAM_DBG(CAM_LRME, "This device is activated before");
+		goto unlock;
+	}
+
+	rc = cam_lrme_soc_enable_resources(lrme_hw);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to enable soc resources");
+		goto unlock;
+	}
+
+	rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to reset hw");
+		goto disable_soc;
+	}
+
+	if (lrme_core->hw_cdm_info) {
+		struct cam_lrme_cdm_info *hw_cdm_info =
+			lrme_core->hw_cdm_info;
+
+		rc = cam_cdm_stream_on(hw_cdm_info->cdm_handle);
+		if (rc) {
+			CAM_ERR(CAM_LRME, "Failed to stream on cdm");
+			goto disable_soc;
+		}
+	}
+
+	lrme_hw->hw_state = CAM_HW_STATE_POWER_UP;
+	lrme_hw->open_count++;
+	lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+
+	mutex_unlock(&lrme_hw->hw_mutex);
+	return rc;
+
+disable_soc:
+	if (cam_lrme_soc_disable_resources(lrme_hw))
+		CAM_ERR(CAM_LRME, "Error in disable soc resources");
+unlock:
+	mutex_unlock(&lrme_hw->hw_mutex);
+	return rc;
+}
+
+int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size)
+{
+	struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+	int rc = 0;
+	struct cam_lrme_core *lrme_core;
+
+	if (!lrme_hw) {
+		CAM_ERR(CAM_LRME, "Invalid argument");
+		return -EINVAL;
+	}
+
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+
+	mutex_lock(&lrme_hw->hw_mutex);
+
+	if (lrme_hw->open_count == 0) {
+		mutex_unlock(&lrme_hw->hw_mutex);
+		CAM_ERR(CAM_LRME, "Error Unbalanced stop");
+		return -EINVAL;
+	}
+	lrme_hw->open_count--;
+
+	if (lrme_hw->open_count)
+		goto unlock;
+
+	lrme_core->req_proc = NULL;
+	lrme_core->req_submit = NULL;
+
+	if (lrme_core->hw_cdm_info) {
+		struct cam_lrme_cdm_info *hw_cdm_info =
+			lrme_core->hw_cdm_info;
+
+		rc = cam_cdm_stream_off(hw_cdm_info->cdm_handle);
+		if (rc) {
+			CAM_ERR(CAM_LRME,
+				"Failed in CDM StreamOff, handle=0x%x, rc=%d",
+				hw_cdm_info->cdm_handle, rc);
+			goto unlock;
+		}
+	}
+
+	rc = cam_lrme_soc_disable_resources(lrme_hw);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed in Disable SOC, rc=%d", rc);
+		goto unlock;
+	}
+
+	lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+	if (lrme_core->state == CAM_LRME_CORE_STATE_IDLE) {
+		lrme_core->state = CAM_LRME_CORE_STATE_INIT;
+	} else {
+		CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state);
+		return -EINVAL;
+	}
+
+unlock:
+	mutex_unlock(&lrme_hw->hw_mutex);
+	return rc;
+}
+
+int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args,
+	uint32_t arg_size)
+{
+	struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+	struct cam_lrme_core *lrme_core;
+	struct cam_lrme_hw_submit_args *args =
+		(struct cam_lrme_hw_submit_args *)hw_submit_args;
+	int rc = 0;
+	struct cam_lrme_frame_request *frame_req;
+
+
+	if (!hw_priv || !hw_submit_args) {
+		CAM_ERR(CAM_LRME, "Invalid input");
+		return -EINVAL;
+	}
+
+	if (sizeof(struct cam_lrme_hw_submit_args) != arg_size) {
+		CAM_ERR(CAM_LRME,
+			"size of args %lu, arg_size %d",
+			sizeof(struct cam_lrme_hw_submit_args), arg_size);
+		return -EINVAL;
+	}
+
+	frame_req = args->frame_req;
+
+	mutex_lock(&lrme_hw->hw_mutex);
+
+	if (lrme_hw->open_count == 0) {
+		CAM_ERR(CAM_LRME, "HW is not open");
+		mutex_unlock(&lrme_hw->hw_mutex);
+		return -EINVAL;
+	}
+
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+	if (lrme_core->state != CAM_LRME_CORE_STATE_IDLE &&
+		lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) {
+		mutex_unlock(&lrme_hw->hw_mutex);
+		CAM_DBG(CAM_LRME, "device busy, can not submit, state %d",
+			lrme_core->state);
+		return -EBUSY;
+	}
+
+	if (lrme_core->req_submit != NULL) {
+		CAM_ERR(CAM_LRME, "req_submit is not NULL");
+		return -EBUSY;
+	}
+
+	rc = cam_lrme_hw_util_submit_req(lrme_core, frame_req);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Submit req failed");
+		goto error;
+	}
+
+	switch (lrme_core->state) {
+	case CAM_LRME_CORE_STATE_PROCESSING:
+		lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND;
+		break;
+
+	case CAM_LRME_CORE_STATE_IDLE:
+		cam_lrme_hw_util_submit_go(lrme_hw);
+		lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING;
+		break;
+
+	default:
+		CAM_ERR(CAM_LRME, "Wrong hw state");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	lrme_core->req_submit = frame_req;
+	mutex_unlock(&lrme_hw->hw_mutex);
+	CAM_DBG(CAM_LRME, "Release lock, submit done for req %llu",
+		frame_req->req_id);
+
+	return 0;
+
+error:
+	mutex_unlock(&lrme_hw->hw_mutex);
+
+	return rc;
+
+}
+
+int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size)
+{
+	struct cam_hw_info *lrme_hw = hw_priv;
+	struct cam_lrme_core *lrme_core;
+	struct cam_lrme_hw_reset_args *lrme_reset_args = reset_core_args;
+	int rc;
+
+	if (!hw_priv) {
+		CAM_ERR(CAM_LRME, "Invalid input args");
+		return -EINVAL;
+	}
+
+	if (!reset_core_args ||
+		sizeof(struct cam_lrme_hw_reset_args) != arg_size) {
+		CAM_ERR(CAM_LRME, "Invalid reset args");
+		return -EINVAL;
+	}
+
+	lrme_core = lrme_hw->core_info;
+
+	mutex_lock(&lrme_hw->hw_mutex);
+	if (lrme_core->state == CAM_LRME_CORE_STATE_RECOVERY) {
+		mutex_unlock(&lrme_hw->hw_mutex);
+		CAM_ERR(CAM_LRME, "Reset not allowed in %d state",
+			lrme_core->state);
+		return -EINVAL;
+	}
+
+	lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY;
+
+	rc = cam_lrme_hw_util_reset(lrme_hw, lrme_reset_args->reset_type);
+	if (rc) {
+		mutex_unlock(&lrme_hw->hw_mutex);
+		CAM_ERR(CAM_FD, "Failed to reset");
+		return rc;
+	}
+
+	lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+
+	mutex_unlock(&lrme_hw->hw_mutex);
+
+	return 0;
+}
+
+int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args,
+	uint32_t arg_size)
+{
+	struct cam_hw_info *lrme_hw;
+	struct cam_lrme_core *lrme_core;
+	struct cam_lrme_dev_cap *lrme_hw_caps =
+		(struct cam_lrme_dev_cap *)get_hw_cap_args;
+
+	if (!hw_priv || !get_hw_cap_args) {
+		CAM_ERR(CAM_LRME, "Invalid input pointers %pK %pK",
+			hw_priv, get_hw_cap_args);
+		return -EINVAL;
+	}
+
+	lrme_hw = (struct cam_hw_info *)hw_priv;
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+	*lrme_hw_caps = lrme_core->hw_caps;
+
+	return 0;
+}
+
+irqreturn_t cam_lrme_hw_irq(int irq_num, void *data)
+{
+	struct cam_hw_info *lrme_hw;
+	struct cam_lrme_core *lrme_core;
+	struct cam_hw_soc_info *soc_info;
+	struct cam_lrme_hw_info   *hw_info;
+	struct crm_workq_task *task;
+	struct cam_lrme_hw_work_data *work_data;
+	uint32_t top_irq_status, fe_irq_status, we_irq_status0, we_irq_status1;
+	int rc;
+
+	if (!data) {
+		CAM_ERR(CAM_LRME, "Invalid data in IRQ callback");
+		return -EINVAL;
+	}
+
+	lrme_hw = (struct cam_hw_info *)data;
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+	soc_info = &lrme_hw->soc_info;
+	hw_info = lrme_core->hw_info;
+
+	top_irq_status = cam_io_r_mb(
+		soc_info->reg_map[0].mem_base +
+		hw_info->titan_reg.top_irq_status);
+	CAM_DBG(CAM_LRME, "top_irq_status %x", top_irq_status);
+	cam_io_w_mb(top_irq_status,
+		soc_info->reg_map[0].mem_base +
+		hw_info->titan_reg.top_irq_clear);
+	top_irq_status &= CAM_LRME_TOP_IRQ_MASK;
+
+	fe_irq_status = cam_io_r_mb(
+		soc_info->reg_map[0].mem_base +
+		hw_info->bus_rd_reg.common_reg.irq_status);
+	CAM_DBG(CAM_LRME, "fe_irq_status %x", fe_irq_status);
+	cam_io_w_mb(fe_irq_status,
+		soc_info->reg_map[0].mem_base +
+		hw_info->bus_rd_reg.common_reg.irq_clear);
+	fe_irq_status &= CAM_LRME_FE_IRQ_MASK;
+
+	we_irq_status0 = cam_io_r_mb(
+		soc_info->reg_map[0].mem_base +
+		hw_info->bus_wr_reg.common_reg.irq_status_0);
+	CAM_DBG(CAM_LRME, "we_irq_status[0] %x", we_irq_status0);
+	cam_io_w_mb(we_irq_status0,
+		soc_info->reg_map[0].mem_base +
+		hw_info->bus_wr_reg.common_reg.irq_clear_0);
+	we_irq_status0 &= CAM_LRME_WE_IRQ_MASK_0;
+
+	we_irq_status1 = cam_io_r_mb(
+		soc_info->reg_map[0].mem_base +
+		hw_info->bus_wr_reg.common_reg.irq_status_1);
+	CAM_DBG(CAM_LRME, "we_irq_status[1] %x", we_irq_status1);
+	cam_io_w_mb(we_irq_status1,
+		soc_info->reg_map[0].mem_base +
+		hw_info->bus_wr_reg.common_reg.irq_clear_1);
+	we_irq_status1 &= CAM_LRME_WE_IRQ_MASK_1;
+
+	cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+		hw_info->titan_reg.top_irq_cmd);
+	cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+		hw_info->bus_wr_reg.common_reg.irq_cmd);
+	cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+		hw_info->bus_rd_reg.common_reg.irq_cmd);
+
+	if (top_irq_status & 0x1) {
+		complete(&lrme_core->reset_complete);
+		top_irq_status &= (~0x1);
+	}
+
+	if (top_irq_status || fe_irq_status ||
+		we_irq_status0 || we_irq_status1) {
+		task = cam_req_mgr_workq_get_task(lrme_core->work);
+		if (!task) {
+			CAM_ERR(CAM_LRME, "no empty task available");
+			return -ENOMEM;
+		}
+		work_data = (struct cam_lrme_hw_work_data *)task->payload;
+		work_data->top_irq_status = top_irq_status;
+		work_data->fe_irq_status = fe_irq_status;
+		work_data->we_irq_status[0] = we_irq_status0;
+		work_data->we_irq_status[1] = we_irq_status1;
+		task->process_cb = cam_lrme_hw_process_irq;
+		rc = cam_req_mgr_workq_enqueue_task(task, data,
+			CRM_TASK_PRIORITY_0);
+		if (rc)
+			CAM_ERR(CAM_LRME,
+				"Failed in enqueue work task, rc=%d", rc);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+	int rc = 0;
+
+	switch (cmd_type) {
+	case CAM_LRME_HW_CMD_PREPARE_HW_UPDATE: {
+		struct cam_lrme_hw_cmd_config_args *config_args;
+
+		config_args = (struct cam_lrme_hw_cmd_config_args *)cmd_args;
+		rc = cam_lrme_hw_util_process_config_hw(lrme_hw, config_args);
+		break;
+	}
+
+	case CAM_LRME_HW_CMD_REGISTER_CB: {
+		struct cam_lrme_hw_cmd_set_cb *cb_args;
+		struct cam_lrme_device *hw_device;
+		struct cam_lrme_core *lrme_core =
+			(struct cam_lrme_core *)lrme_hw->core_info;
+		cb_args = (struct cam_lrme_hw_cmd_set_cb *)cmd_args;
+		lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb =
+			cb_args->cam_lrme_hw_mgr_cb;
+		lrme_core->hw_mgr_cb.data = cb_args->data;
+		hw_device = cb_args->data;
+		rc = 0;
+		break;
+	}
+
+	case CAM_LRME_HW_CMD_SUBMIT: {
+		struct cam_lrme_hw_submit_args *submit_args;
+
+		submit_args = (struct cam_lrme_hw_submit_args *)cmd_args;
+		rc = cam_lrme_hw_submit_req(hw_priv,
+			submit_args, arg_size);
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h
new file mode 100644
index 0000000..bf2f370
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h
@@ -0,0 +1,457 @@
+/* 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_LRME_HW_CORE_H_
+#define _CAM_LRME_HW_CORE_H_
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_defs.h>
+#include <media/cam_lrme.h>
+
+#include "cam_common_util.h"
+#include "cam_debug_util.h"
+#include "cam_io_util.h"
+#include "cam_cpas_api.h"
+#include "cam_cdm_intf_api.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_req_mgr_workq.h"
+
+#define CAM_LRME_HW_RESET_TIMEOUT 3000
+
+#define CAM_LRME_BUS_RD_MAX_CLIENTS 2
+#define CAM_LRME_BUS_WR_MAX_CLIENTS 2
+
+#define CAM_LRME_HW_WORKQ_NUM_TASK 30
+
+#define CAM_LRME_TOP_IRQ_MASK          0x19
+#define CAM_LRME_WE_IRQ_MASK_0         0x2
+#define CAM_LRME_WE_IRQ_MASK_1         0x0
+#define CAM_LRME_FE_IRQ_MASK           0x0
+
+#define CAM_LRME_MAX_REG_PAIR_NUM 60
+
+/**
+ * enum cam_lrme_irq_set
+ *
+ * @CAM_LRME_IRQ_ENABLE  : Enable irqs
+ * @CAM_LRME_IRQ_DISABLE : Disable irqs
+ */
+enum cam_lrme_irq_set {
+	CAM_LRME_IRQ_ENABLE,
+	CAM_LRME_IRQ_DISABLE,
+};
+
+/**
+ * struct cam_lrme_cdm_info : information used to submit cdm command
+ *
+ * @cdm_handle      : CDM handle for this device
+ * @cdm_ops         : CDM ops
+ * @cdm_cmd         : CDM command pointer
+ */
+struct cam_lrme_cdm_info {
+	uint32_t                   cdm_handle;
+	struct cam_cdm_utils_ops  *cdm_ops;
+	struct cam_cdm_bl_request *cdm_cmd;
+};
+
+/**
+ * struct cam_lrme_hw_work_data : Work data for HW work queue
+ *
+ * @top_irq_status : Top registers irq status
+ * @fe_irq_status  : FE engine irq status
+ * @we_irq_status  : WE engine irq status
+ */
+struct cam_lrme_hw_work_data {
+	uint32_t                          top_irq_status;
+	uint32_t                          fe_irq_status;
+	uint32_t                          we_irq_status[2];
+};
+
+/**
+ *  enum cam_lrme_core_state : LRME core states
+ *
+ * @CAM_LRME_CORE_STATE_UNINIT        : LRME is in uninit state
+ * @CAM_LRME_CORE_STATE_INIT          : LRME is in init state after probe
+ * @ CAM_LRME_CORE_STATE_IDLE         : LRME is in idle state. Hardware is in
+ *                                      this state when no frame is processing
+ *                                      or waiting for this core.
+ * @CAM_LRME_CORE_STATE_REQ_PENDING   : LRME is in pending state. One frame is
+ *                                      waiting for processing
+ * @CAM_LRME_CORE_STATE_PROCESSING    : LRME is in processing state. HW manager
+ *                                      can submit one more frame to HW
+ * @CAM_LRME_CORE_STATE_REQ_PROC_PEND : Indicate two frames are inside HW.
+ * @CAM_LRME_CORE_STATE_RECOVERY      : Indicate core is in the process of reset
+ * @CAM_LRME_CORE_STATE_MAX           : upper limit of states
+ */
+enum cam_lrme_core_state {
+	CAM_LRME_CORE_STATE_UNINIT,
+	CAM_LRME_CORE_STATE_INIT,
+	CAM_LRME_CORE_STATE_IDLE,
+	CAM_LRME_CORE_STATE_REQ_PENDING,
+	CAM_LRME_CORE_STATE_PROCESSING,
+	CAM_LRME_CORE_STATE_REQ_PROC_PEND,
+	CAM_LRME_CORE_STATE_RECOVERY,
+	CAM_LRME_CORE_STATE_MAX,
+};
+
+/**
+ *  struct cam_lrme_core : LRME HW core information
+ *
+ * @hw_info        : Pointer to base HW information structure
+ * @device_iommu   : Device iommu handle
+ * @cdm_iommu      : CDM iommu handle
+ * @hw_caps        : Hardware capabilities
+ * @state          : Hardware state
+ * @reset_complete : Reset completion
+ * @work           : Hardware workqueue to handle irq events
+ * @work_data      : Work data used by hardware workqueue
+ * @hw_mgr_cb      : Hw manager callback
+ * @req_proc       : Pointer to the processing frame request
+ * @req_submit     : Pointer to the frame request waiting for processing
+ * @hw_cdm_info    : CDM information used by this device
+ * @hw_idx         : Hardware index
+ */
+struct cam_lrme_core {
+	struct cam_lrme_hw_info          *hw_info;
+	struct cam_iommu_handle           device_iommu;
+	struct cam_iommu_handle           cdm_iommu;
+	struct cam_lrme_dev_cap           hw_caps;
+	enum cam_lrme_core_state          state;
+	struct completion                 reset_complete;
+	struct cam_req_mgr_core_workq    *work;
+	struct cam_lrme_hw_work_data      work_data[CAM_LRME_HW_WORKQ_NUM_TASK];
+	struct cam_lrme_hw_cmd_set_cb     hw_mgr_cb;
+	struct cam_lrme_frame_request    *req_proc;
+	struct cam_lrme_frame_request    *req_submit;
+	struct cam_lrme_cdm_info         *hw_cdm_info;
+	uint32_t                          hw_idx;
+};
+
+/**
+ * struct cam_lrme_bus_rd_reg_common : Offsets of FE common registers
+ *
+ * @hw_version    : Offset of hw_version register
+ * @hw_capability : Offset of hw_capability register
+ * @sw_reset      : Offset of sw_reset register
+ * @cgc_override  : Offset of cgc_override register
+ * @irq_mask      : Offset of irq_mask register
+ * @irq_clear     : Offset of irq_clear register
+ * @irq_cmd       : Offset of irq_cmd register
+ * @irq_status    : Offset of irq_status register
+ * @cmd           : Offset of cmd register
+ * @irq_set       : Offset of irq_set register
+ * @misr_reset    : Offset of misr_reset register
+ * @security_cfg  : Offset of security_cfg register
+ * @pwr_iso_cfg   : Offset of pwr_iso_cfg register
+ * @pwr_iso_seed  : Offset of pwr_iso_seed register
+ * @test_bus_ctrl : Offset of test_bus_ctrl register
+ * @spare         : Offset of spare register
+ */
+struct cam_lrme_bus_rd_reg_common {
+	uint32_t hw_version;
+	uint32_t hw_capability;
+	uint32_t sw_reset;
+	uint32_t cgc_override;
+	uint32_t irq_mask;
+	uint32_t irq_clear;
+	uint32_t irq_cmd;
+	uint32_t irq_status;
+	uint32_t cmd;
+	uint32_t irq_set;
+	uint32_t misr_reset;
+	uint32_t security_cfg;
+	uint32_t pwr_iso_cfg;
+	uint32_t pwr_iso_seed;
+	uint32_t test_bus_ctrl;
+	uint32_t spare;
+};
+
+/**
+ * struct cam_lrme_bus_wr_reg_common : Offset of WE common registers
+ * @hw_version        : Offset of hw_version register
+ * @hw_capability     : Offset of hw_capability register
+ * @sw_reset          : Offset of sw_reset register
+ * @cgc_override      : Offset of cgc_override register
+ * @misr_reset        : Offset of misr_reset register
+ * @pwr_iso_cfg       : Offset of pwr_iso_cfg register
+ * @test_bus_ctrl     : Offset of test_bus_ctrl register
+ * @composite_mask_0  : Offset of composite_mask_0 register
+ * @irq_mask_0        : Offset of irq_mask_0 register
+ * @irq_mask_1        : Offset of irq_mask_1 register
+ * @irq_clear_0       : Offset of irq_clear_0 register
+ * @irq_clear_1       : Offset of irq_clear_1 register
+ * @irq_status_0      : Offset of irq_status_0 register
+ * @irq_status_1      : Offset of irq_status_1 register
+ * @irq_cmd           : Offset of irq_cmd register
+ * @irq_set_0         : Offset of irq_set_0 register
+ * @irq_set_1         : Offset of irq_set_1 register
+ * @addr_fifo_status  : Offset of addr_fifo_status register
+ * @frame_header_cfg0 : Offset of frame_header_cfg0 register
+ * @frame_header_cfg1 : Offset of frame_header_cfg1 register
+ * @spare             : Offset of spare register
+ */
+struct cam_lrme_bus_wr_reg_common {
+	uint32_t hw_version;
+	uint32_t hw_capability;
+	uint32_t sw_reset;
+	uint32_t cgc_override;
+	uint32_t misr_reset;
+	uint32_t pwr_iso_cfg;
+	uint32_t test_bus_ctrl;
+	uint32_t composite_mask_0;
+	uint32_t irq_mask_0;
+	uint32_t irq_mask_1;
+	uint32_t irq_clear_0;
+	uint32_t irq_clear_1;
+	uint32_t irq_status_0;
+	uint32_t irq_status_1;
+	uint32_t irq_cmd;
+	uint32_t irq_set_0;
+	uint32_t irq_set_1;
+	uint32_t addr_fifo_status;
+	uint32_t frame_header_cfg0;
+	uint32_t frame_header_cfg1;
+	uint32_t spare;
+};
+
+/**
+ * struct cam_lrme_bus_rd_bus_client : Offset of FE registers
+ *
+ * @core_cfg                : Offset of core_cfg register
+ * @ccif_meta_data          : Offset of ccif_meta_data register
+ * @addr_image              : Offset of addr_image register
+ * @rd_buffer_size          : Offset of rd_buffer_size register
+ * @rd_stride               : Offset of rd_stride register
+ * @unpack_cfg_0            : Offset of unpack_cfg_0 register
+ * @latency_buff_allocation : Offset of latency_buff_allocation register
+ * @burst_limit_cfg         : Offset of burst_limit_cfg register
+ * @misr_cfg_0              : Offset of misr_cfg_0 register
+ * @misr_cfg_1              : Offset of misr_cfg_1 register
+ * @misr_rd_val             : Offset of misr_rd_val register
+ * @debug_status_cfg        : Offset of debug_status_cfg register
+ * @debug_status_0          : Offset of debug_status_0 register
+ * @debug_status_1          : Offset of debug_status_1 register
+ */
+struct cam_lrme_bus_rd_bus_client {
+	uint32_t core_cfg;
+	uint32_t ccif_meta_data;
+	uint32_t addr_image;
+	uint32_t rd_buffer_size;
+	uint32_t rd_stride;
+	uint32_t unpack_cfg_0;
+	uint32_t latency_buff_allocation;
+	uint32_t burst_limit_cfg;
+	uint32_t misr_cfg_0;
+	uint32_t misr_cfg_1;
+	uint32_t misr_rd_val;
+	uint32_t debug_status_cfg;
+	uint32_t debug_status_0;
+	uint32_t debug_status_1;
+};
+
+/**
+ * struct cam_lrme_bus_wr_bus_client : Offset of WE registers
+ *
+ * @status_0                  : Offset of status_0 register
+ * @status_1                  : Offset of status_1 register
+ * @cfg                       : Offset of cfg register
+ * @addr_frame_header         : Offset of addr_frame_header register
+ * @frame_header_cfg          : Offset of frame_header_cfg register
+ * @addr_image                : Offset of addr_image register
+ * @addr_image_offset         : Offset of addr_image_offset register
+ * @buffer_width_cfg          : Offset of buffer_width_cfg register
+ * @buffer_height_cfg         : Offset of buffer_height_cfg register
+ * @packer_cfg                : Offset of packer_cfg register
+ * @wr_stride                 : Offset of wr_stride register
+ * @irq_subsample_cfg_period  : Offset of irq_subsample_cfg_period register
+ * @irq_subsample_cfg_pattern : Offset of irq_subsample_cfg_pattern register
+ * @burst_limit_cfg           : Offset of burst_limit_cfg register
+ * @misr_cfg                  : Offset of misr_cfg register
+ * @misr_rd_word_sel          : Offset of misr_rd_word_sel register
+ * @misr_val                  : Offset of misr_val register
+ * @debug_status_cfg          : Offset of debug_status_cfg register
+ * @debug_status_0            : Offset of debug_status_0 register
+ * @debug_status_1            : Offset of debug_status_1 register
+ */
+struct cam_lrme_bus_wr_bus_client {
+	uint32_t status_0;
+	uint32_t status_1;
+	uint32_t cfg;
+	uint32_t addr_frame_header;
+	uint32_t frame_header_cfg;
+	uint32_t addr_image;
+	uint32_t addr_image_offset;
+	uint32_t buffer_width_cfg;
+	uint32_t buffer_height_cfg;
+	uint32_t packer_cfg;
+	uint32_t wr_stride;
+	uint32_t irq_subsample_cfg_period;
+	uint32_t irq_subsample_cfg_pattern;
+	uint32_t burst_limit_cfg;
+	uint32_t misr_cfg;
+	uint32_t misr_rd_word_sel;
+	uint32_t misr_val;
+	uint32_t debug_status_cfg;
+	uint32_t debug_status_0;
+	uint32_t debug_status_1;
+};
+
+/**
+ * struct cam_lrme_bus_rd_hw_info : FE registers information
+ *
+ * @common_reg     : FE common register
+ * @bus_client_reg : List of FE bus registers information
+ */
+struct cam_lrme_bus_rd_hw_info {
+	struct cam_lrme_bus_rd_reg_common common_reg;
+	struct cam_lrme_bus_rd_bus_client
+		bus_client_reg[CAM_LRME_BUS_RD_MAX_CLIENTS];
+};
+
+/**
+ * struct cam_lrme_bus_wr_hw_info : WE engine registers information
+ *
+ * @common_reg     : WE common register
+ * @bus_client_reg : List of WE bus registers information
+ */
+struct cam_lrme_bus_wr_hw_info {
+	struct cam_lrme_bus_wr_reg_common common_reg;
+	struct cam_lrme_bus_wr_bus_client
+		bus_client_reg[CAM_LRME_BUS_WR_MAX_CLIENTS];
+};
+
+/**
+ * struct cam_lrme_clc_reg : Offset of clc registers
+ *
+ * @clc_hw_version                 : Offset of clc_hw_version register
+ * @clc_hw_status                  : Offset of clc_hw_status register
+ * @clc_hw_status_dbg              : Offset of clc_hw_status_dbg register
+ * @clc_module_cfg                 : Offset of clc_module_cfg register
+ * @clc_moduleformat               : Offset of clc_moduleformat register
+ * @clc_rangestep                  : Offset of clc_rangestep register
+ * @clc_offset                     : Offset of clc_offset register
+ * @clc_maxallowedsad              : Offset of clc_maxallowedsad register
+ * @clc_minallowedtarmad           : Offset of clc_minallowedtarmad register
+ * @clc_meaningfulsaddiff          : Offset of clc_meaningfulsaddiff register
+ * @clc_minsaddiffdenom            : Offset of clc_minsaddiffdenom register
+ * @clc_robustnessmeasuredistmap_0 : Offset of measuredistmap_0 register
+ * @clc_robustnessmeasuredistmap_1 : Offset of measuredistmap_1 register
+ * @clc_robustnessmeasuredistmap_2 : Offset of measuredistmap_2 register
+ * @clc_robustnessmeasuredistmap_3 : Offset of measuredistmap_3 register
+ * @clc_robustnessmeasuredistmap_4 : Offset of measuredistmap_4 register
+ * @clc_robustnessmeasuredistmap_5 : Offset of measuredistmap_5 register
+ * @clc_robustnessmeasuredistmap_6 : Offset of measuredistmap_6 register
+ * @clc_robustnessmeasuredistmap_7 : Offset of measuredistmap_7 register
+ * @clc_ds_crop_horizontal         : Offset of clc_ds_crop_horizontal register
+ * @clc_ds_crop_vertical           : Offset of clc_ds_crop_vertical register
+ * @clc_tar_pd_unpacker            : Offset of clc_tar_pd_unpacker register
+ * @clc_ref_pd_unpacker            : Offset of clc_ref_pd_unpacker register
+ * @clc_sw_override                : Offset of clc_sw_override register
+ * @clc_tar_height                 : Offset of clc_tar_height register
+ * @clc_test_bus_ctrl              : Offset of clc_test_bus_ctrl register
+ * @clc_spare                      : Offset of clc_spare register
+ */
+struct cam_lrme_clc_reg {
+	uint32_t clc_hw_version;
+	uint32_t clc_hw_status;
+	uint32_t clc_hw_status_dbg;
+	uint32_t clc_module_cfg;
+	uint32_t clc_moduleformat;
+	uint32_t clc_rangestep;
+	uint32_t clc_offset;
+	uint32_t clc_maxallowedsad;
+	uint32_t clc_minallowedtarmad;
+	uint32_t clc_meaningfulsaddiff;
+	uint32_t clc_minsaddiffdenom;
+	uint32_t clc_robustnessmeasuredistmap_0;
+	uint32_t clc_robustnessmeasuredistmap_1;
+	uint32_t clc_robustnessmeasuredistmap_2;
+	uint32_t clc_robustnessmeasuredistmap_3;
+	uint32_t clc_robustnessmeasuredistmap_4;
+	uint32_t clc_robustnessmeasuredistmap_5;
+	uint32_t clc_robustnessmeasuredistmap_6;
+	uint32_t clc_robustnessmeasuredistmap_7;
+	uint32_t clc_ds_crop_horizontal;
+	uint32_t clc_ds_crop_vertical;
+	uint32_t clc_tar_pd_unpacker;
+	uint32_t clc_ref_pd_unpacker;
+	uint32_t clc_sw_override;
+	uint32_t clc_tar_height;
+	uint32_t clc_ref_height;
+	uint32_t clc_test_bus_ctrl;
+	uint32_t clc_spare;
+};
+
+/**
+ * struct cam_lrme_titan_reg : Offset of LRME top registers
+ *
+ * @top_hw_version           : Offset of top_hw_version register
+ * @top_titan_version        : Offset of top_titan_version register
+ * @top_rst_cmd              : Offset of top_rst_cmd register
+ * @top_core_clk_cfg         : Offset of top_core_clk_cfg register
+ * @top_irq_status           : Offset of top_irq_status register
+ * @top_irq_mask             : Offset of top_irq_mask register
+ * @top_irq_clear            : Offset of top_irq_clear register
+ * @top_irq_set              : Offset of top_irq_set register
+ * @top_irq_cmd              : Offset of top_irq_cmd register
+ * @top_violation_status     : Offset of top_violation_status register
+ * @top_spare                : Offset of top_spare register
+ */
+struct cam_lrme_titan_reg {
+	uint32_t top_hw_version;
+	uint32_t top_titan_version;
+	uint32_t top_rst_cmd;
+	uint32_t top_core_clk_cfg;
+	uint32_t top_irq_status;
+	uint32_t top_irq_mask;
+	uint32_t top_irq_clear;
+	uint32_t top_irq_set;
+	uint32_t top_irq_cmd;
+	uint32_t top_violation_status;
+	uint32_t top_spare;
+};
+
+/**
+ * struct cam_lrme_hw_info : LRME registers information
+ *
+ * @clc_reg    : LRME CLC registers
+ * @bus_rd_reg : LRME FE registers
+ * @bus_wr_reg : LRME WE registers
+ * @titan_reg  : LRME top reisters
+ */
+struct cam_lrme_hw_info {
+	struct cam_lrme_clc_reg clc_reg;
+	struct cam_lrme_bus_rd_hw_info bus_rd_reg;
+	struct cam_lrme_bus_wr_hw_info bus_wr_reg;
+	struct cam_lrme_titan_reg titan_reg;
+};
+
+int cam_lrme_hw_process_irq(void *priv, void *data);
+int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args,
+	uint32_t arg_size);
+int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size);
+int cam_lrme_hw_stop(void *hw_priv, void *stop_args, uint32_t arg_size);
+int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args,
+	uint32_t arg_size);
+irqreturn_t cam_lrme_hw_irq(int irq_num, void *data);
+int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw,
+	struct cam_lrme_dev_cap *hw_caps);
+int cam_lrme_hw_start(void *hw_priv, void *hw_init_args, uint32_t arg_size);
+int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size);
+void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, enum cam_lrme_irq_set set);
+
+#endif /* _CAM_LRME_HW_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
new file mode 100644
index 0000000..2e63752
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
@@ -0,0 +1,320 @@
+/* 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/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_req_mgr.h>
+
+#include "cam_subdev.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_lrme_hw_reg.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_lrme_hw_mgr.h"
+#include "cam_mem_mgr_api.h"
+#include "cam_smmu_api.h"
+
+#define CAM_LRME_HW_WORKQ_NUM_TASK 30
+
+static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core,
+	struct cam_hw_info *lrme_hw)
+{
+	int rc, i;
+	struct cam_cdm_bl_request *cdm_cmd;
+	struct cam_cdm_acquire_data cdm_acquire;
+	struct cam_lrme_cdm_info *hw_cdm_info;
+
+	hw_cdm_info = kzalloc(sizeof(struct cam_lrme_cdm_info),
+		GFP_KERNEL);
+	if (!hw_cdm_info) {
+		CAM_ERR(CAM_LRME, "No memory for hw_cdm_info");
+		return -ENOMEM;
+	}
+
+	cdm_cmd = kzalloc((sizeof(struct cam_cdm_bl_request) +
+		((CAM_LRME_MAX_HW_ENTRIES - 1) *
+		sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
+	if (!cdm_cmd) {
+		CAM_ERR(CAM_LRME, "No memory for cdm_cmd");
+		kfree(hw_cdm_info);
+		return -ENOMEM;
+	}
+
+	memset(&cdm_acquire, 0, sizeof(cdm_acquire));
+	strlcpy(cdm_acquire.identifier, "lrmecdm", sizeof("lrmecdm"));
+	cdm_acquire.cell_index = lrme_hw->soc_info.index;
+	cdm_acquire.handle = 0;
+	cdm_acquire.userdata = hw_cdm_info;
+	cdm_acquire.cam_cdm_callback = NULL;
+	cdm_acquire.id = CAM_CDM_VIRTUAL;
+	cdm_acquire.base_array_cnt = lrme_hw->soc_info.num_reg_map;
+	for (i = 0; i < lrme_hw->soc_info.num_reg_map; i++)
+		cdm_acquire.base_array[i] = &lrme_hw->soc_info.reg_map[i];
+
+	rc = cam_cdm_acquire(&cdm_acquire);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Can't acquire cdm");
+		goto error;
+	}
+
+	hw_cdm_info->cdm_cmd = cdm_cmd;
+	hw_cdm_info->cdm_ops = cdm_acquire.ops;
+	hw_cdm_info->cdm_handle = cdm_acquire.handle;
+
+	lrme_core->hw_cdm_info = hw_cdm_info;
+	CAM_DBG(CAM_LRME, "cdm acquire done");
+
+	return 0;
+error:
+	kfree(cdm_cmd);
+	kfree(hw_cdm_info);
+	return rc;
+}
+
+static int cam_lrme_hw_dev_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info *lrme_hw;
+	struct cam_hw_intf lrme_hw_intf;
+	struct cam_lrme_core *lrme_core;
+	const struct of_device_id *match_dev = NULL;
+	struct cam_lrme_hw_info *hw_info;
+	int rc, i;
+
+	lrme_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!lrme_hw) {
+		CAM_ERR(CAM_LRME, "No memory to create lrme_hw");
+		return -ENOMEM;
+	}
+
+	lrme_core = kzalloc(sizeof(struct cam_lrme_core), GFP_KERNEL);
+	if (!lrme_core) {
+		CAM_ERR(CAM_LRME, "No memory to create lrme_core");
+		kfree(lrme_hw);
+		return -ENOMEM;
+	}
+
+	lrme_hw->core_info = lrme_core;
+	lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+	lrme_hw->soc_info.pdev = pdev;
+	lrme_hw->soc_info.dev = &pdev->dev;
+	lrme_hw->soc_info.dev_name = pdev->name;
+	lrme_hw->open_count = 0;
+	lrme_core->state = CAM_LRME_CORE_STATE_INIT;
+
+	mutex_init(&lrme_hw->hw_mutex);
+	spin_lock_init(&lrme_hw->hw_lock);
+	init_completion(&lrme_hw->hw_complete);
+	init_completion(&lrme_core->reset_complete);
+
+	rc = cam_req_mgr_workq_create("cam_lrme_hw_worker",
+		CAM_LRME_HW_WORKQ_NUM_TASK,
+		&lrme_core->work, CRM_WORKQ_USAGE_IRQ);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc);
+		goto free_memory;
+	}
+
+	for (i = 0; i < CAM_LRME_HW_WORKQ_NUM_TASK; i++)
+		lrme_core->work->task.pool[i].payload =
+			&lrme_core->work_data[i];
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev || !match_dev->data) {
+		CAM_ERR(CAM_LRME, "No Of_match data, %pK", match_dev);
+		rc = -EINVAL;
+		goto destroy_workqueue;
+	}
+	hw_info = (struct cam_lrme_hw_info *)match_dev->data;
+	lrme_core->hw_info = hw_info;
+
+	rc = cam_lrme_soc_init_resources(&lrme_hw->soc_info,
+		cam_lrme_hw_irq, lrme_hw);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to init soc, rc=%d", rc);
+		goto destroy_workqueue;
+	}
+
+	rc = cam_lrme_hw_dev_util_cdm_acquire(lrme_core, lrme_hw);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to acquire cdm");
+		goto deinit_platform_res;
+	}
+
+	rc = cam_smmu_get_handle("lrme", &lrme_core->device_iommu.non_secure);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Get iommu handle failed");
+		goto release_cdm;
+	}
+
+	rc = cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_ATTACH);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "LRME attach iommu handle failed, rc=%d", rc);
+		goto destroy_smmu;
+	}
+
+	rc = cam_lrme_hw_start(lrme_hw, NULL, 0);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc);
+		goto detach_smmu;
+	}
+
+	rc = cam_lrme_hw_util_get_caps(lrme_hw, &lrme_core->hw_caps);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to get hw caps, rc=%d", rc);
+		if (cam_lrme_hw_stop(lrme_hw, NULL, 0))
+			CAM_ERR(CAM_LRME, "Failed in hw deinit");
+		goto detach_smmu;
+	}
+
+	rc = cam_lrme_hw_stop(lrme_hw, NULL, 0);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc);
+		goto detach_smmu;
+	}
+
+	lrme_core->hw_idx = lrme_hw->soc_info.index;
+	lrme_hw_intf.hw_priv = lrme_hw;
+	lrme_hw_intf.hw_idx = lrme_hw->soc_info.index;
+	lrme_hw_intf.hw_ops.get_hw_caps = cam_lrme_hw_get_caps;
+	lrme_hw_intf.hw_ops.init = NULL;
+	lrme_hw_intf.hw_ops.deinit = NULL;
+	lrme_hw_intf.hw_ops.reset = cam_lrme_hw_reset;
+	lrme_hw_intf.hw_ops.reserve = NULL;
+	lrme_hw_intf.hw_ops.release = NULL;
+	lrme_hw_intf.hw_ops.start = cam_lrme_hw_start;
+	lrme_hw_intf.hw_ops.stop = cam_lrme_hw_stop;
+	lrme_hw_intf.hw_ops.read = NULL;
+	lrme_hw_intf.hw_ops.write = NULL;
+	lrme_hw_intf.hw_ops.process_cmd = cam_lrme_hw_process_cmd;
+	lrme_hw_intf.hw_type = CAM_HW_LRME;
+
+	rc = cam_cdm_get_iommu_handle("lrmecdm", &lrme_core->cdm_iommu);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to acquire the CDM iommu handles");
+		goto detach_smmu;
+	}
+
+	rc = cam_lrme_mgr_register_device(&lrme_hw_intf,
+		&lrme_core->device_iommu,
+		&lrme_core->cdm_iommu);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to register device");
+		goto detach_smmu;
+	}
+
+	platform_set_drvdata(pdev, lrme_hw);
+	CAM_DBG(CAM_LRME, "LRME-%d probe successful", lrme_hw_intf.hw_idx);
+
+	return rc;
+
+detach_smmu:
+	cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH);
+destroy_smmu:
+	cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure);
+release_cdm:
+	cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle);
+	kfree(lrme_core->hw_cdm_info->cdm_cmd);
+	kfree(lrme_core->hw_cdm_info);
+deinit_platform_res:
+	if (cam_lrme_soc_deinit_resources(&lrme_hw->soc_info))
+		CAM_ERR(CAM_LRME, "Failed in soc deinit");
+	mutex_destroy(&lrme_hw->hw_mutex);
+destroy_workqueue:
+	cam_req_mgr_workq_destroy(&lrme_core->work);
+free_memory:
+	mutex_destroy(&lrme_hw->hw_mutex);
+	kfree(lrme_hw);
+	kfree(lrme_core);
+
+	return rc;
+}
+
+static int cam_lrme_hw_dev_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct cam_hw_info *lrme_hw;
+	struct cam_lrme_core *lrme_core;
+
+	lrme_hw = platform_get_drvdata(pdev);
+	if (!lrme_hw) {
+		CAM_ERR(CAM_LRME, "Invalid lrme_hw from fd_hw_intf");
+		rc = -ENODEV;
+		goto deinit_platform_res;
+	}
+
+	lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+	if (!lrme_core) {
+		CAM_ERR(CAM_LRME, "Invalid lrme_core from fd_hw");
+		rc = -EINVAL;
+		goto deinit_platform_res;
+	}
+
+	cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH);
+	cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure);
+	cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle);
+	cam_lrme_mgr_deregister_device(lrme_core->hw_idx);
+
+	kfree(lrme_core->hw_cdm_info->cdm_cmd);
+	kfree(lrme_core->hw_cdm_info);
+	kfree(lrme_core);
+
+deinit_platform_res:
+	rc = cam_lrme_soc_deinit_resources(&lrme_hw->soc_info);
+	if (rc)
+		CAM_ERR(CAM_LRME, "Error in LRME soc deinit, rc=%d", rc);
+
+	mutex_destroy(&lrme_hw->hw_mutex);
+	kfree(lrme_hw);
+
+	return rc;
+}
+
+static const struct of_device_id cam_lrme_hw_dt_match[] = {
+	{
+		.compatible = "qcom,lrme",
+		.data = &cam_lrme10_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cam_lrme_hw_dt_match);
+
+static struct platform_driver cam_lrme_hw_driver = {
+	.probe = cam_lrme_hw_dev_probe,
+	.remove = cam_lrme_hw_dev_remove,
+	.driver = {
+		.name = "cam_lrme_hw",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_lrme_hw_dt_match,
+	},
+};
+
+static int __init cam_lrme_hw_init_module(void)
+{
+	return platform_driver_register(&cam_lrme_hw_driver);
+}
+
+static void __exit cam_lrme_hw_exit_module(void)
+{
+	platform_driver_unregister(&cam_lrme_hw_driver);
+}
+
+module_init(cam_lrme_hw_init_module);
+module_exit(cam_lrme_hw_exit_module);
+MODULE_DESCRIPTION("CAM LRME HW driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h
new file mode 100644
index 0000000..d16b174
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h
@@ -0,0 +1,200 @@
+/* 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_LRME_HW_INTF_H_
+#define _CAM_LRME_HW_INTF_H_
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_cpas.h>
+#include <media/cam_req_mgr.h>
+#include <media/cam_lrme.h>
+
+#include "cam_io_util.h"
+#include "cam_soc_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_subdev.h"
+#include "cam_cpas_api.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_debug_util.h"
+
+
+#define CAM_LRME_MAX_IO_BUFFER 2
+#define CAM_LRME_MAX_HW_ENTRIES 5
+
+#define CAM_LRME_BASE_IDX 0
+
+/**
+ *  enum cam_lrme_hw_type : Enum for LRME HW type
+ *
+ * @CAM_HW_LRME : LRME HW type
+ */
+enum cam_lrme_hw_type {
+	CAM_HW_LRME,
+};
+
+/**
+ * enum cam_lrme_cb_type : HW manager call back type
+ *
+ * @CAM_LRME_CB_BUF_DONE        : Indicate buf done has been generated
+ * @CAM_LRME_CB_COMP_REG_UPDATE : Indicate receiving WE comp reg update
+ * @CAM_LRME_CB_PUT_FRAME       : Request HW manager to put back the frame
+ * @CAM_LRME_CB_ERROR           : Indicate error irq has been generated
+ */
+enum cam_lrme_cb_type {
+	CAM_LRME_CB_BUF_DONE = 1,
+	CAM_LRME_CB_COMP_REG_UPDATE = 1 << 1,
+	CAM_LRME_CB_PUT_FRAME = 1 << 2,
+	CAM_LRME_CB_ERROR = 1 << 3,
+};
+
+/**
+ * enum cam_lrme_hw_cmd_type : HW CMD type
+ *
+ * @CAM_LRME_HW_CMD_prepare_hw_update : Prepare HW update
+ * @CAM_LRME_HW_CMD_REGISTER_CB       : register HW manager callback
+ * @CAM_LRME_HW_CMD_SUBMIT            : Submit frame to HW
+ */
+enum cam_lrme_hw_cmd_type {
+	CAM_LRME_HW_CMD_PREPARE_HW_UPDATE,
+	CAM_LRME_HW_CMD_REGISTER_CB,
+	CAM_LRME_HW_CMD_SUBMIT,
+};
+
+/**
+ * enum cam_lrme_hw_reset_type : Type of reset
+ *
+ * @CAM_LRME_HW_RESET_TYPE_HW_RESET : HW reset
+ * @CAM_LRME_HW_RESET_TYPE_SW_RESET : SW reset
+ */
+enum cam_lrme_hw_reset_type {
+	CAM_LRME_HW_RESET_TYPE_HW_RESET,
+	CAM_LRME_HW_RESET_TYPE_SW_RESET,
+};
+
+/**
+ *struct cam_lrme_frame_request : LRME frame request
+ *
+ * @frame_list            : List head
+ * @req_id                : Request ID
+ * @ctxt_to_hw_map        : Information about context id, priority and device id
+ * @hw_device             : Pointer to HW device
+ * @hw_update_entries     : List of hw_update_entries
+ * @num_hw_update_entries : number of hw_update_entries
+ */
+struct cam_lrme_frame_request {
+	struct list_head           frame_list;
+	uint64_t                   req_id;
+	void                      *ctxt_to_hw_map;
+	struct cam_lrme_device    *hw_device;
+	struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES];
+	uint32_t                   num_hw_update_entries;
+};
+
+/**
+ * struct cam_lrme_hw_io_buffer : IO buffer information
+ *
+ * @valid     : Indicate whether this IO config is valid
+ * @io_cfg    : Pointer to IO configuration
+ * @num_buf   : Number of buffers
+ * @num_plane : Number of planes
+ * @io_addr   : List of IO address
+ */
+struct cam_lrme_hw_io_buffer {
+	bool                   valid;
+	struct cam_buf_io_cfg *io_cfg;
+	uint32_t               num_buf;
+	uint32_t               num_plane;
+	uint64_t               io_addr[CAM_PACKET_MAX_PLANES];
+};
+
+/**
+ * struct cam_lrme_hw_cmd_config_args : Args for prepare HW update
+ *
+ * @hw_device       : Pointer to HW device
+ * @input_buf       : List of input buffers
+ * @output_buf      : List of output buffers
+ * @cmd_buf_addr    : Pointer to available KMD buffer
+ * @size            : Available KMD buffer size
+ * @config_buf_size : Size used to prepare update
+ */
+struct cam_lrme_hw_cmd_config_args {
+	struct cam_lrme_device *hw_device;
+	struct cam_lrme_hw_io_buffer input_buf[CAM_LRME_MAX_IO_BUFFER];
+	struct cam_lrme_hw_io_buffer output_buf[CAM_LRME_MAX_IO_BUFFER];
+	uint32_t *cmd_buf_addr;
+	uint32_t size;
+	uint32_t config_buf_size;
+};
+
+/**
+ * struct cam_lrme_hw_flush_args : Args for flush HW
+ *
+ * @ctxt_to_hw_map : Identity of context
+ * @req_to_flush   : Pointer to the frame need to flush in
+ *                   case of single frame flush
+ * @flush_type     : Flush type
+ */
+struct cam_lrme_hw_flush_args {
+	void                          *ctxt_to_hw_map;
+	struct cam_lrme_frame_request *req_to_flush;
+	uint32_t                       flush_type;
+};
+
+/**
+ * struct cam_lrme_hw_reset_args : Args for reset HW
+ *
+ * @reset_type : Enum cam_lrme_hw_reset_type
+ */
+struct cam_lrme_hw_reset_args {
+	uint32_t reset_type;
+};
+
+/**
+ * struct cam_lrme_hw_cb_args : HW manager callback args
+ *
+ * @cb_type   : Callback event type
+ * @frame_req : Pointer to the frame associated with the cb
+ */
+struct cam_lrme_hw_cb_args {
+	uint32_t                       cb_type;
+	struct cam_lrme_frame_request *frame_req;
+};
+
+/**
+ * struct cam_lrme_hw_cmd_set_cb : Args for set callback function
+ *
+ * @cam_lrme_hw_mgr_cb : Callback function pointer
+ * @data               : Data sent along with callback function
+ */
+struct cam_lrme_hw_cmd_set_cb {
+	 int (*cam_lrme_hw_mgr_cb)(void *data,
+		struct cam_lrme_hw_cb_args *args);
+	 void *data;
+};
+
+/**
+ * struct cam_lrme_hw_submit_args : Args for submit request
+ *
+ * @hw_update_entries     : List of hw update entries used to program registers
+ * @num_hw_update_entries : Number of hw update entries
+ * @frame_req             : Pointer to the frame request
+ */
+struct cam_lrme_hw_submit_args {
+	 struct cam_hw_update_entry    *hw_update_entries;
+	 uint32_t            num_hw_update_entries;
+	 struct cam_lrme_frame_request *frame_req;
+};
+
+#endif /* _CAM_LRME_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h
new file mode 100644
index 0000000..39cfde7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h
@@ -0,0 +1,193 @@
+/* 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_LRME_HW_REG_H_
+#define _CAM_LRME_HW_REG_H_
+
+#include "cam_lrme_hw_core.h"
+
+static struct cam_lrme_hw_info cam_lrme10_hw_info = {
+	.clc_reg = {
+		.clc_hw_version                 = 0x00000000,
+		.clc_hw_status                  = 0x00000004,
+		.clc_hw_status_dbg              = 0x00000008,
+		.clc_module_cfg                 = 0x00000060,
+		.clc_moduleformat               = 0x000000A8,
+		.clc_rangestep                  = 0x00000068,
+		.clc_offset                     = 0x0000006C,
+		.clc_maxallowedsad              = 0x00000070,
+		.clc_minallowedtarmad           = 0x00000074,
+		.clc_meaningfulsaddiff          = 0x00000078,
+		.clc_minsaddiffdenom            = 0x0000007C,
+		.clc_robustnessmeasuredistmap_0 = 0x00000080,
+		.clc_robustnessmeasuredistmap_1 = 0x00000084,
+		.clc_robustnessmeasuredistmap_2 = 0x00000088,
+		.clc_robustnessmeasuredistmap_3 = 0x0000008C,
+		.clc_robustnessmeasuredistmap_4 = 0x00000090,
+		.clc_robustnessmeasuredistmap_5 = 0x00000094,
+		.clc_robustnessmeasuredistmap_6 = 0x00000098,
+		.clc_robustnessmeasuredistmap_7 = 0x0000009C,
+		.clc_ds_crop_horizontal         = 0x000000A0,
+		.clc_ds_crop_vertical           = 0x000000A4,
+		.clc_tar_pd_unpacker            = 0x000000AC,
+		.clc_ref_pd_unpacker            = 0x000000B0,
+		.clc_sw_override                = 0x000000B4,
+		.clc_tar_height                 = 0x000000B8,
+		.clc_ref_height                 = 0x000000BC,
+		.clc_test_bus_ctrl              = 0x000001F8,
+		.clc_spare                      = 0x000001FC,
+	},
+	.bus_rd_reg = {
+		.common_reg = {
+			.hw_version     = 0x00000200,
+			.hw_capability  = 0x00000204,
+			.sw_reset       = 0x00000208,
+			.cgc_override   = 0x0000020C,
+			.irq_mask       = 0x00000210,
+			.irq_clear      = 0x00000214,
+			.irq_cmd        = 0x00000218,
+			.irq_status     = 0x0000021C,
+			.cmd            = 0x00000220,
+			.irq_set        = 0x00000224,
+			.misr_reset     = 0x0000022C,
+			.security_cfg   = 0x00000230,
+			.pwr_iso_cfg    = 0x00000234,
+			.pwr_iso_seed   = 0x00000238,
+			.test_bus_ctrl  = 0x00000248,
+			.spare          = 0x0000024C,
+		},
+		.bus_client_reg = {
+			/* bus client 0 */
+			{
+				.core_cfg                = 0x00000250,
+				.ccif_meta_data          = 0x00000254,
+				.addr_image              = 0x00000258,
+				.rd_buffer_size          = 0x0000025C,
+				.rd_stride               = 0x00000260,
+				.unpack_cfg_0            = 0x00000264,
+				.latency_buff_allocation = 0x00000278,
+				.burst_limit_cfg         = 0x00000280,
+				.misr_cfg_0              = 0x00000284,
+				.misr_cfg_1              = 0x00000288,
+				.misr_rd_val             = 0x0000028C,
+				.debug_status_cfg        = 0x00000290,
+				.debug_status_0          = 0x00000294,
+				.debug_status_1          = 0x00000298,
+			},
+			/* bus client 1 */
+			{
+				.core_cfg                = 0x000002F0,
+				.ccif_meta_data          = 0x000002F4,
+				.addr_image              = 0x000002F8,
+				.rd_buffer_size          = 0x000002FC,
+				.rd_stride               = 0x00000300,
+				.unpack_cfg_0            = 0x00000304,
+				.latency_buff_allocation = 0x00000318,
+				.burst_limit_cfg         = 0x00000320,
+				.misr_cfg_0              = 0x00000324,
+				.misr_cfg_1              = 0x00000328,
+				.misr_rd_val             = 0x0000032C,
+				.debug_status_cfg        = 0x00000330,
+				.debug_status_0          = 0x00000334,
+				.debug_status_1          = 0x00000338,
+			},
+		},
+	},
+	.bus_wr_reg = {
+		.common_reg = {
+			.hw_version        = 0x00000500,
+			.hw_capability     = 0x00000504,
+			.sw_reset          = 0x00000508,
+			.cgc_override      = 0x0000050C,
+			.misr_reset        = 0x000005C8,
+			.pwr_iso_cfg       = 0x000005CC,
+			.test_bus_ctrl     = 0x0000061C,
+			.composite_mask_0  = 0x00000510,
+			.irq_mask_0        = 0x00000544,
+			.irq_mask_1        = 0x00000548,
+			.irq_clear_0       = 0x00000550,
+			.irq_clear_1       = 0x00000554,
+			.irq_status_0      = 0x0000055C,
+			.irq_status_1      = 0x00000560,
+			.irq_cmd           = 0x00000568,
+			.irq_set_0         = 0x000005BC,
+			.irq_set_1         = 0x000005C0,
+			.addr_fifo_status  = 0x000005A8,
+			.frame_header_cfg0 = 0x000005AC,
+			.frame_header_cfg1 = 0x000005B0,
+			.spare             = 0x00000620,
+		},
+		.bus_client_reg = {
+			/* bus client 0 */
+			{
+				.status_0                  = 0x00000700,
+				.status_1                  = 0x00000704,
+				.cfg                       = 0x00000708,
+				.addr_frame_header         = 0x0000070C,
+				.frame_header_cfg          = 0x00000710,
+				.addr_image                = 0x00000714,
+				.addr_image_offset         = 0x00000718,
+				.buffer_width_cfg          = 0x0000071C,
+				.buffer_height_cfg         = 0x00000720,
+				.packer_cfg                = 0x00000724,
+				.wr_stride                 = 0x00000728,
+				.irq_subsample_cfg_period  = 0x00000748,
+				.irq_subsample_cfg_pattern = 0x0000074C,
+				.burst_limit_cfg           = 0x0000075C,
+				.misr_cfg                  = 0x00000760,
+				.misr_rd_word_sel          = 0x00000764,
+				.misr_val                  = 0x00000768,
+				.debug_status_cfg          = 0x0000076C,
+				.debug_status_0            = 0x00000770,
+				.debug_status_1            = 0x00000774,
+			},
+			/* bus client 1 */
+			{
+				.status_0                  = 0x00000800,
+				.status_1                  = 0x00000804,
+				.cfg                       = 0x00000808,
+				.addr_frame_header         = 0x0000080C,
+				.frame_header_cfg          = 0x00000810,
+				.addr_image                = 0x00000814,
+				.addr_image_offset         = 0x00000818,
+				.buffer_width_cfg          = 0x0000081C,
+				.buffer_height_cfg         = 0x00000820,
+				.packer_cfg                = 0x00000824,
+				.wr_stride                 = 0x00000828,
+				.irq_subsample_cfg_period  = 0x00000848,
+				.irq_subsample_cfg_pattern = 0x0000084C,
+				.burst_limit_cfg           = 0x0000085C,
+				.misr_cfg                  = 0x00000860,
+				.misr_rd_word_sel          = 0x00000864,
+				.misr_val                  = 0x00000868,
+				.debug_status_cfg          = 0x0000086C,
+				.debug_status_0            = 0x00000870,
+				.debug_status_1            = 0x00000874,
+			},
+		},
+	},
+	.titan_reg = {
+		.top_hw_version        = 0x00000900,
+		.top_titan_version     = 0x00000904,
+		.top_rst_cmd           = 0x00000908,
+		.top_core_clk_cfg      = 0x00000920,
+		.top_irq_status        = 0x0000090C,
+		.top_irq_mask          = 0x00000910,
+		.top_irq_clear         = 0x00000914,
+		.top_irq_set           = 0x00000918,
+		.top_irq_cmd           = 0x0000091C,
+		.top_violation_status  = 0x00000924,
+		.top_spare             = 0x000009FC,
+	},
+};
+
+#endif /* _CAM_LRME_HW_REG_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c
new file mode 100644
index 0000000..75de0dd
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c
@@ -0,0 +1,158 @@
+/* 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+
+
+int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw)
+{
+	struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+	struct cam_lrme_soc_private *soc_private =
+		(struct cam_lrme_soc_private *)soc_info->soc_private;
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote;
+	int rc = 0;
+
+	ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	ahb_vote.vote.level = CAM_SVS_VOTE;
+	axi_vote.compressed_bw = 7200000;
+	axi_vote.uncompressed_bw = 7200000;
+	rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to start cpas, rc %d", rc);
+		return -EFAULT;
+	}
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE,
+		true);
+	if (rc) {
+		CAM_ERR(CAM_LRME,
+			"Failed to enable platform resource, rc %d", rc);
+		goto stop_cpas;
+	}
+
+	cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_ENABLE);
+
+	return rc;
+
+stop_cpas:
+	if (cam_cpas_stop(soc_private->cpas_handle))
+		CAM_ERR(CAM_LRME, "Failed to stop cpas");
+
+	return rc;
+}
+
+int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw)
+{
+	struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+	struct cam_lrme_soc_private *soc_private;
+	int rc = 0;
+
+	soc_private = soc_info->soc_private;
+
+	cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_DISABLE);
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed to disable platform resource");
+		return rc;
+	}
+	rc = cam_cpas_stop(soc_private->cpas_handle);
+	if (rc)
+		CAM_ERR(CAM_LRME, "Failed to stop cpas");
+
+	return rc;
+}
+
+int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t irq_handler, void *private_data)
+{
+	struct cam_lrme_soc_private *soc_private;
+	struct cam_cpas_register_params cpas_register_param;
+	int rc;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed in get_dt_properties, rc=%d", rc);
+		return rc;
+	}
+
+	rc = cam_soc_util_request_platform_resource(soc_info, irq_handler,
+		private_data);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "Failed in request_platform_resource rc=%d",
+			rc);
+		return rc;
+	}
+
+	soc_private = kzalloc(sizeof(struct cam_lrme_soc_private), GFP_KERNEL);
+	if (!soc_private) {
+		rc = -ENOMEM;
+		goto release_res;
+	}
+	soc_info->soc_private = soc_private;
+
+	memset(&cpas_register_param, 0, sizeof(cpas_register_param));
+	strlcpy(cpas_register_param.identifier,
+		"lrmecpas", CAM_HW_IDENTIFIER_LENGTH);
+	cpas_register_param.cell_index = soc_info->index;
+	cpas_register_param.dev = &soc_info->pdev->dev;
+	cpas_register_param.userdata = private_data;
+	cpas_register_param.cam_cpas_client_cb = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_param);
+	if (rc) {
+		CAM_ERR(CAM_LRME, "CPAS registration failed");
+		goto free_soc_private;
+	}
+	soc_private->cpas_handle = cpas_register_param.client_handle;
+	CAM_DBG(CAM_LRME, "CPAS handle=%d", soc_private->cpas_handle);
+
+	return rc;
+
+free_soc_private:
+	kfree(soc_info->soc_private);
+	soc_info->soc_private = NULL;
+release_res:
+	cam_soc_util_release_platform_resource(soc_info);
+
+	return rc;
+}
+
+int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info)
+{
+	struct cam_lrme_soc_private *soc_private =
+		(struct cam_lrme_soc_private *)soc_info->soc_private;
+	int rc;
+
+	rc = cam_cpas_unregister_client(soc_private->cpas_handle);
+	if (rc)
+		CAM_ERR(CAM_LRME, "Unregister cpas failed, handle=%d, rc=%d",
+			soc_private->cpas_handle, rc);
+
+	rc = cam_soc_util_release_platform_resource(soc_info);
+	if (rc)
+		CAM_ERR(CAM_LRME, "release platform failed, rc=%d", rc);
+
+	kfree(soc_info->soc_private);
+	soc_info->soc_private = NULL;
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h
new file mode 100644
index 0000000..44e8486
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h
@@ -0,0 +1,28 @@
+/* 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_LRME_HW_SOC_H_
+#define _CAM_LRME_HW_SOC_H_
+
+#include "cam_soc_util.h"
+
+struct cam_lrme_soc_private {
+	uint32_t cpas_handle;
+};
+
+int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw);
+int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw);
+int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t irq_handler, void *private_data);
+int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* _CAM_LRME_HW_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index f38af7d..244746b 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -810,15 +810,34 @@
  */
 static void __cam_req_mgr_sof_freeze(unsigned long data)
 {
-	struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
-	struct cam_req_mgr_core_link *link = NULL;
+	struct cam_req_mgr_timer     *timer = (struct cam_req_mgr_timer *)data;
+	struct cam_req_mgr_core_link    *link = NULL;
+	struct cam_req_mgr_core_session *session = NULL;
+	struct cam_req_mgr_message       msg;
 
 	if (!timer) {
 		CAM_ERR(CAM_CRM, "NULL timer");
 		return;
 	}
 	link = (struct cam_req_mgr_core_link *)timer->parent;
-	CAM_ERR(CAM_CRM, "SOF freeze for link %x", link->link_hdl);
+	session = (struct cam_req_mgr_core_session *)link->parent;
+
+	CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x",
+		session->session_hdl, link->link_hdl);
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.session_hdl = session->session_hdl;
+	msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_DEVICE;
+	msg.u.err_msg.request_id = 0;
+	msg.u.err_msg.link_hdl   = link->link_hdl;
+
+
+	if (cam_req_mgr_notify_message(&msg,
+		V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT))
+		CAM_ERR(CAM_CRM,
+			"Error notifying SOF freeze for session %d link 0x%x",
+			session->session_hdl, link->link_hdl);
 }
 
 /**
@@ -863,12 +882,14 @@
  * @brief    : Cleans up the mem allocated while linking
  * @link     : pointer to link, mem associated with this link is freed
  *
+ * @return   : returns if unlink for any device was success or failure
  */
-static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
+static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
 {
 	int32_t                                 i = 0;
 	struct cam_req_mgr_connected_device    *dev;
 	struct cam_req_mgr_core_dev_link_setup  link_data;
+	int                                     rc = 0;
 
 	link_data.link_enable = 0;
 	link_data.link_hdl = link->link_hdl;
@@ -881,7 +902,11 @@
 		if (dev != NULL) {
 			link_data.dev_hdl = dev->dev_hdl;
 			if (dev->ops && dev->ops->link_setup)
-				dev->ops->link_setup(&link_data);
+				rc = dev->ops->link_setup(&link_data);
+				if (rc)
+					CAM_ERR(CAM_CRM,
+						"Unlink failed dev_hdl %d",
+						dev->dev_hdl);
 			dev->dev_hdl = 0;
 			dev->parent = NULL;
 			dev->ops = NULL;
@@ -896,6 +921,7 @@
 	link->num_devs = 0;
 	link->max_delay = 0;
 
+	return rc;
 }
 
 /**
@@ -2024,8 +2050,12 @@
 
 	cam_req_mgr_workq_destroy(&link->workq);
 
-	/* Cleanuprequest tables */
-	__cam_req_mgr_destroy_link_info(link);
+	/* Cleanup request tables and unlink devices */
+	rc = __cam_req_mgr_destroy_link_info(link);
+	if (rc) {
+		CAM_ERR(CAM_CORE, "Unlink failed. Cannot proceed");
+		return rc;
+	}
 
 	/* Free memory holding data of linked devs */
 	__cam_req_mgr_destroy_subdev(link->l_dev);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index c316dbb..49c3c56e 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -462,7 +462,7 @@
 	return rc;
 }
 
-int cam_req_mgr_notify_frame_message(struct cam_req_mgr_message *msg,
+int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg,
 	uint32_t id,
 	uint32_t type)
 {
@@ -481,7 +481,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(cam_req_mgr_notify_frame_message);
+EXPORT_SYMBOL(cam_req_mgr_notify_message);
 
 void cam_video_device_cleanup(void)
 {
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
index 77faed9..93278b8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
@@ -43,7 +43,7 @@
 #define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type)        \
 	(type *)((char *)ev.u.data)
 
-int cam_req_mgr_notify_frame_message(struct cam_req_mgr_message *msg,
+int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg,
 	uint32_t id,
 	uint32_t type);
 
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
index 1d2169b..f357941 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -317,6 +317,8 @@
 	}
 
 	hdl_tbl->hdl[idx].state = HDL_FREE;
+	hdl_tbl->hdl[idx].ops   = NULL;
+	hdl_tbl->hdl[idx].priv  = NULL;
 	clear_bit(idx, hdl_tbl->bitmap);
 	spin_unlock_bh(&hdl_tbl_lock);
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index f151b9b..d7a6504 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -730,17 +730,30 @@
 					reg_addr++;
 			} else {
 				if ((i + 1) <= cci_dev->payload_size) {
-					if (i2c_msg->data_type ==
-						CAMERA_SENSOR_I2C_TYPE_DWORD) {
+					switch (i2c_msg->data_type) {
+					case CAMERA_SENSOR_I2C_TYPE_DWORD:
 						data[i++] = (i2c_cmd->reg_data &
 							0xFF000000) >> 24;
+						/* fallthrough */
+					case CAMERA_SENSOR_I2C_TYPE_3B:
 						data[i++] = (i2c_cmd->reg_data &
 							0x00FF0000) >> 16;
+						/* fallthrough */
+					case CAMERA_SENSOR_I2C_TYPE_WORD:
+						data[i++] = (i2c_cmd->reg_data &
+							0x0000FF00) >> 8;
+						/* fallthrough */
+					case CAMERA_SENSOR_I2C_TYPE_BYTE:
+						data[i++] = i2c_cmd->reg_data &
+							0x000000FF;
+						break;
+					default:
+						CAM_ERR(CAM_CCI,
+							"invalid data type: %d",
+							i2c_msg->data_type);
+						return -EINVAL;
 					}
-					data[i++] = (i2c_cmd->reg_data &
-						0x0000FF00) >> 8; /* MSB */
-					data[i++] = i2c_cmd->reg_data &
-						0x000000FF; /* LSB */
+
 					if (c_ctrl->cmd ==
 						MSM_CCI_I2C_WRITE_SEQ)
 						reg_addr++;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
index 9eca4c7..d9b43a4 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -259,6 +259,7 @@
 		return -ENOMEM;
 
 	o_ctrl->soc_info.pdev = pdev;
+	o_ctrl->pdev = pdev;
 	o_ctrl->soc_info.dev = &pdev->dev;
 	o_ctrl->soc_info.dev_name = pdev->name;
 
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
index e72a1f0..1e087a1 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -14,3 +14,4 @@
 header-y += msm_sde_rotator.h
 header-y += radio-iris.h
 header-y += radio-iris-commands.h
+header-y += cam_lrme.h
diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h
index 4a63292..afd109f 100644
--- a/include/uapi/media/cam_isp.h
+++ b/include/uapi/media/cam_isp.h
@@ -84,7 +84,9 @@
 #define CAM_ISP_DSP_MODE_ROUND                  2
 
 /* ISP Generic Cmd Buffer Blob types */
-#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG    0
+#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG      0
+#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG    1
+#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG       2
 
 /* Query devices */
 /**
@@ -248,7 +250,7 @@
 	uint32_t                       framedrop_pattern;
 	uint32_t                       framedrop_period;
 	uint32_t                       reserved;
-};
+} __attribute__((packed));
 
 /**
  * struct cam_isp_resource_hfr_config - Resource HFR configuration
@@ -261,7 +263,7 @@
 	uint32_t                       num_ports;
 	uint32_t                       reserved;
 	struct cam_isp_port_hfr_config port_hfr_config[1];
-};
+} __attribute__((packed));
 
 /**
  * struct cam_isp_dual_split_params - dual isp spilt parameters
@@ -317,6 +319,60 @@
 	uint32_t                           reserved;
 	struct cam_isp_dual_split_params   split_params;
 	struct cam_isp_dual_stripe_config  stripes[1];
-};
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_clock_config - Clock configuration
+ *
+ * @usage_type:                 Usage type (Single/Dual)
+ * @num_rdi:                    Number of RDI votes
+ * @left_pix_hz:                Pixel Clock for Left ISP
+ * @right_pix_hz:               Pixel Clock for Right ISP, valid only if Dual
+ * @rdi_hz:                     RDI Clock. ISP clock will be max of RDI and
+ *                              PIX clocks. For a particular context which ISP
+ *                              HW the RDI is allocated to is not known to UMD.
+ *                              Hence pass the clock and let KMD decide.
+ */
+struct cam_isp_clock_config {
+	uint32_t                       usage_type;
+	uint32_t                       num_rdi;
+	uint64_t                       left_pix_hz;
+	uint64_t                       right_pix_hz;
+	uint64_t                       rdi_hz[1];
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_bw_vote - Bandwidth vote information
+ *
+ * @resource_id:                Resource ID
+ * @reserved:                   Reserved field for alignment
+ * @cam_bw_bps:                 Bandwidth vote for CAMNOC
+ * @ext_bw_bps:                 Bandwidth vote for path-to-DDR after CAMNOC
+ */
+
+struct cam_isp_bw_vote {
+	uint32_t                       resource_id;
+	uint32_t                       reserved;
+	uint64_t                       cam_bw_bps;
+	uint64_t                       ext_bw_bps;
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_bw_config - Bandwidth configuration
+ *
+ * @usage_type:                 Usage type (Single/Dual)
+ * @num_rdi:                    Number of RDI votes
+ * @left_pix_vote:              Bandwidth vote for left ISP
+ * @right_pix_vote:             Bandwidth vote for right ISP
+ * @rdi_vote:                   RDI bandwidth requirements
+ */
+
+struct cam_isp_bw_config {
+	uint32_t                       usage_type;
+	uint32_t                       num_rdi;
+	struct cam_isp_bw_vote         left_pix_vote;
+	struct cam_isp_bw_vote         right_pix_vote;
+	struct cam_isp_bw_vote         rdi_vote[1];
+} __attribute__((packed));
 
 #endif /* __UAPI_CAM_ISP_H__ */
diff --git a/include/uapi/media/cam_lrme.h b/include/uapi/media/cam_lrme.h
new file mode 100644
index 0000000..97d9578
--- /dev/null
+++ b/include/uapi/media/cam_lrme.h
@@ -0,0 +1,65 @@
+#ifndef __UAPI_CAM_LRME_H__
+#define __UAPI_CAM_LRME_H__
+
+#include "cam_defs.h"
+
+/* LRME Resource Types */
+
+enum CAM_LRME_IO_TYPE {
+	CAM_LRME_IO_TYPE_TAR,
+	CAM_LRME_IO_TYPE_REF,
+	CAM_LRME_IO_TYPE_RES,
+	CAM_LRME_IO_TYPE_DS2,
+};
+
+#define CAM_LRME_INPUT_PORT_TYPE_TAR (1 << 0)
+#define CAM_LRME_INPUT_PORT_TYPE_REF (1 << 1)
+
+#define CAM_LRME_OUTPUT_PORT_TYPE_DS2 (1 << 0)
+#define CAM_LRME_OUTPUT_PORT_TYPE_RES (1 << 1)
+
+#define CAM_LRME_DEV_MAX 1
+
+
+struct cam_lrme_hw_version {
+	uint32_t gen;
+	uint32_t rev;
+	uint32_t step;
+};
+
+struct cam_lrme_dev_cap {
+	struct cam_lrme_hw_version clc_hw_version;
+	struct cam_lrme_hw_version bus_rd_hw_version;
+	struct cam_lrme_hw_version bus_wr_hw_version;
+	struct cam_lrme_hw_version top_hw_version;
+	struct cam_lrme_hw_version top_titan_version;
+};
+
+/**
+ * struct cam_lrme_query_cap_cmd - LRME query device capability payload
+ *
+ * @dev_iommu_handle: LRME iommu handles for secure/non secure
+ *      modes
+ * @cdm_iommu_handle: Iommu handles for secure/non secure modes
+ * @num_devices: number of hardware devices
+ * @dev_caps: Returned device capability array
+ */
+struct cam_lrme_query_cap_cmd {
+	struct cam_iommu_handle device_iommu;
+	struct cam_iommu_handle cdm_iommu;
+	uint32_t num_devices;
+	struct cam_lrme_dev_cap dev_caps[CAM_LRME_DEV_MAX];
+};
+
+struct cam_lrme_soc_info {
+	uint64_t clock_rate;
+	uint64_t bandwidth;
+	uint64_t reserved[4];
+};
+
+struct cam_lrme_acquire_args {
+	struct cam_lrme_soc_info lrme_soc_info;
+};
+
+#endif /* __UAPI_CAM_LRME_H__ */
+
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 9b7d055..233d84e 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -355,14 +355,14 @@
  * @error_type: type of error
  * @request_id: request id of frame
  * @device_hdl: device handle
- * @reserved: reserved field
+ * @linke_hdl: link_hdl
  * @resource_size: size of the resource
  */
 struct cam_req_mgr_error_msg {
 	uint32_t error_type;
 	uint32_t request_id;
 	int32_t device_hdl;
-	int32_t reserved;
+	int32_t link_hdl;
 	uint64_t resource_size;
 };