msm: camera: icp: Enable camera ICP driver

Add the support for Image control processor which routes
the requests from the user mode driver to ICP via HFI
interface. Acknowledges the response for requests
back to user mode driver.

Change-Id: I2d49463effda1d651b9cbd32ee3d24a8a67d4485
Signed-off-by: Lakshmi Narayana Kalavala <lkalaval@codeaurora.org>
Signed-off-by: Sagar Gore <sgore@codeaurora.org>
Signed-off-by: Suresh Vankadara <svankada@codeaurora.org>
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index ada427c..2e71d05 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/
+obj-$(CONFIG_SPECTRA_CAMERA) += icp/
diff --git a/drivers/media/platform/msm/camera/cam_core/Makefile b/drivers/media/platform/msm/camera/cam_core/Makefile
index 417de13..60f94d1 100644
--- a/drivers/media/platform/msm/camera/cam_core/Makefile
+++ b/drivers/media/platform/msm/camera/cam_core/Makefile
@@ -1,3 +1,4 @@
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
 
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_context_utils.o cam_node.o cam_subdev.o
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 56b34f5..17b3c7c 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -358,4 +358,3 @@
 
 	return 0;
 }
-
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 c7329cf..37a5c03 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -22,6 +22,8 @@
 
 /* max request number */
 #define CAM_CTX_REQ_MAX              20
+#define CAM_CTX_CFG_MAX              20
+#define CAM_CTX_RES_MAX              20
 
 /**
  * enum cam_ctx_state -  context top level states
@@ -43,13 +45,29 @@
  * @status:                Request status
  * @request_id:            Request id
  * @req_priv:              Derived request object
+ * @hw_update_entries:     Hardware update entries
+ * @num_hw_update_entries: Number of hardware update entries
+ * @in_map_entries:        Entries for in fences
+ * @num_in_map_entries:    Number of in map entries
+ * @out_map_entries:       Entries for out fences
+ * @num_out_map_entries:   Number of out map entries
+ * @num_in_acked:          Number of in fence acked
+ * @num_out_acked:         Number of out fence acked
  *
  */
 struct cam_ctx_request {
-	struct list_head   list;
-	uint32_t           status;
-	uint64_t           request_id;
-	void              *req_priv;
+	struct list_head              list;
+	uint32_t                      status;
+	uint64_t                      request_id;
+	void                          *req_priv;
+	struct cam_hw_update_entry    hw_update_entries[CAM_CTX_CFG_MAX];
+	uint32_t                      num_hw_update_entries;
+	struct cam_hw_fence_map_entry in_map_entries[CAM_CTX_CFG_MAX];
+	uint32_t                      num_in_map_entries;
+	struct cam_hw_fence_map_entry out_map_entries[CAM_CTX_CFG_MAX];
+	uint32_t                      num_out_map_entries;
+	uint32_t                      num_in_acked;
+	uint32_t                      num_out_acked;
 };
 
 /**
@@ -132,6 +150,7 @@
  * @state:                 Current state for top level state machine
  * @state_machine:         Top level state machine
  * @ctx_priv:              Private context pointer
+ * @ctxt_to_hw_map:        Context to hardware mapping pointer
  *
  */
 struct cam_context {
@@ -159,6 +178,7 @@
 	struct cam_ctx_ops          *state_machine;
 
 	void                        *ctx_priv;
+	void                        *ctxt_to_hw_map;
 };
 
 /**
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
new file mode 100644
index 0000000..21a61ff
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -0,0 +1,481 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CTXT-UTILS %s:%d " fmt, __func__, __LINE__
+
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <media/cam_sync.h>
+#include <media/cam_defs.h>
+
+#include "cam_sync_api.h"
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+#include "cam_node.h"
+#include "cam_context.h"
+
+int cam_context_buf_done_from_hw(struct cam_context *ctx,
+	void *done_event_data, uint32_t bubble_state)
+{
+	int rc = 0;
+	int i, j;
+	struct cam_ctx_request *req;
+	struct cam_hw_done_event_data *done =
+		(struct cam_hw_done_event_data *)done_event_data;
+
+	if (list_empty(&ctx->active_req_list)) {
+		pr_err("Buf done with no active request\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	req = list_first_entry(&ctx->active_req_list,
+		struct cam_ctx_request, list);
+
+	for (i = 0; i < done->num_handles; i++) {
+		for (j = 0; j < req->num_out_map_entries; j++) {
+			if (done->resource_handle[i] ==
+				req->out_map_entries[j].resource_handle)
+				break;
+		}
+
+		if (j == req->num_out_map_entries) {
+			pr_err("Can not find matching lane handle 0x%x\n",
+				done->resource_handle[i]);
+			rc = -EINVAL;
+			continue;
+		}
+
+		cam_sync_signal(req->out_map_entries[j].sync_id,
+			CAM_SYNC_STATE_SIGNALED_SUCCESS);
+		req->num_out_acked++;
+		trace_printk("Sync success req %lld, reset sync id 0x%x\n",
+			req->request_id,
+			req->out_map_entries[j].sync_id);
+
+		req->out_map_entries[j].sync_id = -1;
+	}
+
+	if (req->num_out_acked == req->num_out_map_entries) {
+		list_del_init(&req->list);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+end:
+	return rc;
+}
+
+int cam_context_apply_req_to_hw(struct cam_context *ctx,
+	struct cam_req_mgr_apply_request *apply)
+{
+	int rc = 0;
+	struct cam_ctx_request *req;
+	struct cam_hw_config_args cfg;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if (list_empty(&ctx->pending_req_list)) {
+		pr_err("No available request for Apply id %lld\n",
+			apply->request_id);
+		rc = -EFAULT;
+		goto end;
+	}
+
+	spin_lock(&ctx->lock);
+	req = list_first_entry(&ctx->pending_req_list,
+		struct cam_ctx_request, list);
+	list_del_init(&req->list);
+	spin_unlock(&ctx->lock);
+
+	cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+	cfg.hw_update_entries = req->hw_update_entries;
+	cfg.num_hw_update_entries = req->num_hw_update_entries;
+	cfg.out_map_entries = req->out_map_entries;
+	cfg.num_out_map_entries = req->num_out_map_entries;
+	cfg.priv = (void *)&req->request_id;
+	list_add_tail(&req->list, &ctx->active_req_list);
+
+	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
+	if (rc)
+		list_del_init(&req->list);
+
+end:
+	return rc;
+}
+
+int32_t cam_context_release_dev_to_hw(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc = 0;
+	int i;
+	struct cam_hw_release_args arg;
+	struct cam_ctx_request *req;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if (ctx->ctxt_to_hw_map) {
+		arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+		ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv,
+			&arg);
+		ctx->ctxt_to_hw_map = NULL;
+	}
+
+	ctx->session_hdl = 0;
+	ctx->dev_hdl = 0;
+	ctx->link_hdl = 0;
+
+	while (!list_empty(&ctx->active_req_list)) {
+		req = list_first_entry(&ctx->active_req_list,
+			struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_warn("signal fence in active list. fence num %d\n",
+			req->num_out_map_entries);
+		for (i = 0; i < req->num_out_map_entries; i++) {
+			if (req->out_map_entries[i].sync_id != -1)
+				cam_sync_signal(req->out_map_entries[i].sync_id,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		}
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+	/* flush the pending queue */
+	while (!list_empty(&ctx->pending_req_list)) {
+		req = list_first_entry(&ctx->pending_req_list,
+			struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_debug("signal fence in pending list. fence num %d\n",
+			req->num_out_map_entries);
+		for (i = 0; i < req->num_out_map_entries; i++)
+			if (req->out_map_entries[i].sync_id != -1)
+				cam_sync_signal(req->out_map_entries[i].sync_id,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+end:
+	return rc;
+}
+
+void cam_context_sync_callback(int32_t sync_obj, int status, void *data)
+{
+	struct cam_context *ctx = data;
+	struct cam_ctx_request *req = NULL;
+	struct cam_req_mgr_apply_request apply;
+
+	spin_lock(&ctx->lock);
+	if (!list_empty(&ctx->pending_req_list))
+		req = list_first_entry(&ctx->pending_req_list,
+			struct cam_ctx_request, list);
+	spin_unlock(&ctx->lock);
+
+	if (!req) {
+		pr_err("No more request obj free\n");
+		return;
+	}
+
+	req->num_in_acked++;
+	if (req->num_in_acked == req->num_in_map_entries) {
+		apply.request_id = req->request_id;
+		trace_printk("async cb for request :%llu",
+			req->request_id);
+		cam_context_apply_req_to_hw(ctx, &apply);
+	}
+}
+
+int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc = 0;
+	struct cam_ctx_request *req = NULL;
+	struct cam_hw_prepare_update_args cfg;
+	uint64_t packet_addr;
+	struct cam_packet *packet;
+	size_t len = 0;
+	int32_t i = 0;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	spin_lock(&ctx->lock);
+	if (!list_empty(&ctx->free_req_list)) {
+		req = list_first_entry(&ctx->free_req_list,
+			struct cam_ctx_request, list);
+		list_del_init(&req->list);
+	}
+	spin_unlock(&ctx->lock);
+
+	if (!req) {
+		pr_err("No more request obj free\n");
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	memset(req, 0, sizeof(*req));
+	INIT_LIST_HEAD(&req->list);
+
+	/* for config dev, only memory handle is supported */
+	/* map packet from the memhandle */
+	rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle,
+		(uint64_t *) &packet_addr,
+		&len);
+	if (rc != 0) {
+		pr_err("Can not get packet address\n");
+		rc = -EINVAL;
+		goto free_req;
+	}
+
+	packet = (struct cam_packet *) (packet_addr + cmd->offset);
+	pr_debug("pack_handle %llx\n", cmd->packet_handle);
+	pr_debug("packet address is 0x%llx\n", packet_addr);
+	pr_debug("packet with length %zu, offset 0x%llx\n",
+		len, cmd->offset);
+	pr_debug("Packet request id 0x%llx\n",
+		packet->header.request_id);
+	pr_debug("Packet size 0x%x\n", packet->header.size);
+	pr_debug("packet op %d\n", packet->header.op_code);
+
+	/* preprocess the configuration */
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.packet = packet;
+	cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+	cfg.max_hw_update_entries = CAM_CTX_CFG_MAX;
+	cfg.num_hw_update_entries = req->num_hw_update_entries;
+	cfg.hw_update_entries = req->hw_update_entries;
+	cfg.max_out_map_entries = CAM_CTX_CFG_MAX;
+	cfg.out_map_entries = req->out_map_entries;
+	cfg.max_in_map_entries = CAM_CTX_CFG_MAX;
+	cfg.in_map_entries = req->in_map_entries;
+
+	rc = ctx->hw_mgr_intf->hw_prepare_update(
+		ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
+	if (rc != 0) {
+		pr_err("Prepare config packet failed in HW layer\n");
+		rc = -EFAULT;
+		goto free_req;
+	}
+	req->num_hw_update_entries = cfg.num_hw_update_entries;
+	req->num_out_map_entries = cfg.num_out_map_entries;
+	req->num_in_map_entries = cfg.num_in_map_entries;
+	req->request_id = packet->header.request_id;
+	req->status = 1;
+	req->req_priv = cfg.priv;
+
+	if (req->num_in_map_entries > 0) {
+		spin_lock(&ctx->lock);
+		list_add_tail(&req->list, &ctx->pending_req_list);
+		spin_unlock(&ctx->lock);
+		for (i = 0; i < req->num_in_map_entries; i++) {
+			trace_printk("register in fence callback: %d\n",
+				req->in_map_entries[i].sync_id);
+			rc = cam_sync_register_callback(
+					cam_context_sync_callback,
+					(void *)ctx,
+					req->in_map_entries[i].sync_id);
+			pr_debug("register in fence callback: %d ret = %d\n",
+				req->in_map_entries[i].sync_id, rc);
+		}
+		goto end;
+	}
+
+	return rc;
+
+free_req:
+	spin_lock(&ctx->lock);
+	list_add_tail(&req->list, &ctx->free_req_list);
+	spin_unlock(&ctx->lock);
+end:
+	pr_debug("Config dev successful\n");
+	return rc;
+}
+
+int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc;
+	struct cam_hw_acquire_args param;
+	struct cam_create_dev_hdl req_hdl_param;
+	struct cam_hw_release_args release;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	pr_debug("acquire cmd: session_hdl 0x%x, num_resources %d\n",
+		cmd->session_handle, cmd->num_resources);
+	pr_debug(" handle type %d, res %lld\n", cmd->handle_type,
+		cmd->resource_hdl);
+
+	if (cmd->num_resources > CAM_CTX_RES_MAX) {
+		pr_err("Too much resources in the acquire\n");
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	/* for now we only support user pointer */
+	if (cmd->handle_type != 1)  {
+		pr_err("Only user pointer is supported");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	/* fill in parameters */
+	param.context_data = ctx;
+	param.event_cb = ctx->irq_cb_intf;
+	param.num_acq = cmd->num_resources;
+	param.acquire_info = cmd->resource_hdl;
+
+	pr_debug("ctx %pK: acquire hw resource: hw_intf: 0x%pK, priv 0x%pK",
+		ctx, ctx->hw_mgr_intf, ctx->hw_mgr_intf->hw_mgr_priv);
+	pr_debug("acquire_hw_func 0x%pK\n", ctx->hw_mgr_intf->hw_acquire);
+
+	/* call HW manager to reserve the resource */
+	rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv,
+		&param);
+	if (rc != 0) {
+		pr_err("Acquire device failed\n");
+		goto end;
+	}
+
+	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
+
+	/* if hw resource acquire successful, acquire dev handle */
+	req_hdl_param.session_hdl = cmd->session_handle;
+	/* bridge is not ready for these flags. so false for now */
+	req_hdl_param.v4l2_sub_dev_flag = 0;
+	req_hdl_param.media_entity_flag = 0;
+	req_hdl_param.priv = ctx;
+
+	pr_debug("get device handle from bridge\n");
+	ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param);
+	if (ctx->dev_hdl <= 0) {
+		rc = -EFAULT;
+		pr_err("Can not create device handle\n");
+		goto free_hw;
+	}
+	cmd->dev_handle = ctx->dev_hdl;
+
+	/* store session information */
+	ctx->session_hdl = cmd->session_handle;
+
+	pr_err("dev_handle = %x\n", cmd->dev_handle);
+	return rc;
+
+free_hw:
+	release.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+	ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release);
+	ctx->ctxt_to_hw_map = NULL;
+end:
+	return rc;
+}
+
+int32_t cam_context_start_dev_to_hw(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc = 0;
+	struct cam_hw_start_args arg;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if ((cmd->session_handle != ctx->session_hdl) ||
+		(cmd->dev_handle != ctx->dev_hdl)) {
+		pr_err("Invalid session hdl[%d], dev_handle[%d]\n",
+			cmd->session_handle, cmd->dev_handle);
+		rc = -EPERM;
+		goto end;
+	}
+
+	if (ctx->hw_mgr_intf->hw_start) {
+		rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
+				&arg);
+		if (rc) {
+			/* HW failure. user need to clean up the resource */
+			pr_err("Start HW failed\n");
+			goto end;
+		}
+	}
+
+	pr_debug("start device success\n");
+end:
+	return rc;
+}
+
+int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx)
+{
+	int rc = 0;
+	uint32_t i;
+	struct cam_hw_stop_args stop;
+	struct cam_ctx_request *req;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	/* stop hw first */
+	if (ctx->ctxt_to_hw_map) {
+		stop.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+		if (ctx->hw_mgr_intf->hw_stop)
+			ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
+				&stop);
+	}
+
+	/* flush pending and active queue */
+	while (!list_empty(&ctx->pending_req_list)) {
+		req = list_first_entry(&ctx->pending_req_list,
+				struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_debug("signal fence in pending list. fence num %d\n",
+			req->num_out_map_entries);
+		for (i = 0; i < req->num_out_map_entries; i++)
+			if (req->out_map_entries[i].sync_id != -1)
+				cam_sync_signal(req->out_map_entries[i].sync_id,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+	while (!list_empty(&ctx->active_req_list)) {
+		req = list_first_entry(&ctx->active_req_list,
+				struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_debug("signal fence in active list. fence num %d\n",
+			req->num_out_map_entries);
+		for (i = 0; i < req->num_out_map_entries; i++)
+			if (req->out_map_entries[i].sync_id != -1)
+				cam_sync_signal(req->out_map_entries[i].sync_id,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+end:
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.h b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.h
new file mode 100644
index 0000000..f7982eb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.h
@@ -0,0 +1,32 @@
+/* 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_CONTEXT_UTILS_H_
+#define _CAM_CONTEXT_UTILS_H_
+
+#include <linux/types.h>
+
+int cam_context_buf_done_from_hw(struct cam_context *ctx,
+	void *done_event_data, uint32_t bubble_state);
+int cam_context_apply_req_to_hw(struct cam_context *ctx,
+	struct cam_req_mgr_apply_request *apply);
+int32_t cam_context_release_dev_to_hw(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd);
+int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd);
+int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd);
+int32_t cam_context_start_dev_to_hw(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd);
+int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx);
+
+#endif /* _CAM_CONTEXT_UTILS_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_core_defs.h b/drivers/media/platform/msm/camera/cam_core/cam_core_defs.h
new file mode 100644
index 0000000..3498836
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_core_defs.h
@@ -0,0 +1,44 @@
+/* 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_REQ_MGR_CORE_DEFS_H_
+#define _CAM_REQ_MGR_CORE_DEFS_H_
+
+#define CAM_CORE_TRACE_ENABLE 0
+
+#if (CAM_CORE_TRACE_ENABLE == 1)
+	#define CAM_CORE_DBG(fmt, args...) do { \
+	trace_printk("%d: [cam_core_dbg] "fmt"\n", __LINE__, ##args); \
+	pr_debug("%s:%d "fmt"\n", __func__, __LINE__, ##args); \
+	} while (0)
+
+	#define CAM_CORE_WARN(fmt, args...) do { \
+	trace_printk("%d: [cam_core_warn] "fmt"\n", __LINE__, ##args); \
+	pr_warn("%s:%d "fmt"\n", __func__, __LINE__, ##args); \
+	} while (0)
+
+	#define CAM_CORE_ERR(fmt, args...) do { \
+	trace_printk("%d: [cam_core_err] "fmt"\n", __LINE__, ##args); \
+	pr_err("%s:%d "fmt"\n", __func__, __LINE__, ##args);\
+	} while (0)
+#else
+	#define CAM_CORE_DBG(fmt, args...) pr_debug("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+
+	#define CAM_CORE_WARN(fmt, args...) pr_warn("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+
+	#define CAM_CORE_ERR(fmt, args...) pr_err("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+#endif
+
+#endif /* _CAM_REQ_MGR_CORE_DEFS_H_ */
+
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
index db605e7..f72a1d7 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -36,6 +36,7 @@
  * @offset:                Memory offset
  * @len:                   Size of the configuration
  * @flags:                 Flags for the config entry(eg. DMI)
+ * @addr:                  Address of hardware update entry
  *
  */
 struct cam_hw_update_entry {
@@ -43,6 +44,7 @@
 	uint32_t           offset;
 	uint32_t           len;
 	uint32_t           flags;
+	uint64_t           addr;
 };
 
 /**
@@ -137,6 +139,7 @@
  * @max_in_map_entries:    Maximum input fence mapping supported
  * @in_map_entries:        Actual input fence mapping list (returned)
  * @num_in_map_entries:    Number of acutal input fence mapping (returned)
+ * @priv:                  Private pointer of hw update
  *
  */
 struct cam_hw_prepare_update_args {
@@ -151,6 +154,7 @@
 	uint32_t                        max_in_map_entries;
 	struct cam_hw_fence_map_entry  *in_map_entries;
 	uint32_t                        num_in_map_entries;
+	void                           *priv;
 };
 
 /**
@@ -159,12 +163,18 @@
  * @ctxt_to_hw_map:        HW context from the acquire
  * @num_hw_update_entries: Number of hardware update entries
  * @hw_update_entries:     Hardware update list
+ * @out_map_entries:       Out map info
+ * @num_out_map_entries:   Number of out map entries
+ * @priv:                  Private pointer
  *
  */
 struct cam_hw_config_args {
-	void                        *ctxt_to_hw_map;
-	uint32_t                     num_hw_update_entries;
-	struct cam_hw_update_entry  *hw_update_entries;
+	void                           *ctxt_to_hw_map;
+	uint32_t                        num_hw_update_entries;
+	struct cam_hw_update_entry     *hw_update_entries;
+	struct cam_hw_fence_map_entry  *out_map_entries;
+	uint32_t                        num_out_map_entries;
+	void                           *priv;
 };
 
 /**
@@ -189,6 +199,8 @@
  * @hw_write:              Function pointer for Write hardware registers
  * @hw_cmd:                Function pointer for any customized commands for the
  *                         hardware manager
+ * @download_fw:           Function pointer for firmware downloading
+ * @hw_close:              Function pointer for subdev close
  *
  */
 struct cam_hw_mgr_intf {
@@ -204,6 +216,8 @@
 	int (*hw_read)(void *hw_priv, void *read_args);
 	int (*hw_write)(void *hw_priv, void *write_args);
 	int (*hw_cmd)(void *hw_priv, void *write_args);
+	int (*download_fw)(void *hw_priv, void *fw_download_args);
+	int (*hw_close)(void *hw_priv, void *hw_close_args);
 };
 
 #endif /* _CAM_HW_MGR_INTF_H_ */
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 ef60822..17f6973 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -21,13 +21,16 @@
 {
 	int rc = -EFAULT;
 
-	if (!query)
+	if (!query) {
+		pr_err("%s: Invalid params\n", __func__);
 		return -EINVAL;
+	}
 
 	if (node->hw_mgr_intf.hw_get_caps) {
 		rc = node->hw_mgr_intf.hw_get_caps(
 			node->hw_mgr_intf.hw_mgr_priv, query);
 	}
+
 	return rc;
 }
 
@@ -47,7 +50,6 @@
 		list_del_init(&ctx->list);
 	}
 	mutex_unlock(&node->list_mutex);
-
 	if (!ctx) {
 		rc = -ENOMEM;
 		goto err;
@@ -254,8 +256,8 @@
 		memset(node, 0, sizeof(*node));
 
 	pr_debug("%s: deinit complete!\n", __func__);
-	return 0;
 
+	return 0;
 }
 
 int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
@@ -274,7 +276,6 @@
 	strlcpy(node->name, name, sizeof(node->name));
 
 	memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf));
-
 	node->crm_node_intf.apply_req = __cam_node_apply_req;
 	node->crm_node_intf.get_dev_info = __cam_node_get_dev_info;
 	node->crm_node_intf.link_setup = __cam_node_link_setup;
@@ -318,15 +319,18 @@
 			rc = -EFAULT;
 			break;
 		}
+
 		rc = __cam_node_handle_query_cap(node, &query);
 		if (rc) {
 			pr_err("%s: querycap is failed(rc = %d)\n",
 				__func__,  rc);
 			break;
 		}
+
 		if (copy_to_user((void __user *)cmd->handle, &query,
 			sizeof(query)))
 			rc = -EFAULT;
+
 		break;
 	}
 	case CAM_ACQUIRE_DEV: {
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_subdev.c b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
index 429474b..a89981d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
@@ -148,6 +148,7 @@
 	sd->sd_flags =
 		V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 	sd->ent_function = dev_type;
+
 	rc = cam_register_subdev(sd);
 	if (rc) {
 		pr_err("%s: cam_register_subdev() failed for dev: %s!\n",
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 019a775..7bc26ec 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
@@ -196,6 +196,7 @@
 	hdl_tbl->hdl[idx].ops = hdl_data->ops;
 	spin_unlock_bh(&hdl_tbl_lock);
 
+	pr_debug("%s: handle = %x\n", __func__, handle);
 	return handle;
 }
 
diff --git a/drivers/media/platform/msm/camera/icp/Makefile b/drivers/media/platform/msm/camera/icp/Makefile
new file mode 100644
index 0000000..c42b162
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/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/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+
+obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_subdev.o cam_icp_context.o hfi.o
diff --git a/drivers/media/platform/msm/camera/icp/cam_icp_context.c b/drivers/media/platform/msm/camera/icp/cam_icp_context.c
new file mode 100644
index 0000000..41290f4
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/cam_icp_context.c
@@ -0,0 +1,195 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-ICP-CTXT %s:%d " fmt, __func__, __LINE__
+
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <media/cam_sync.h>
+#include <media/cam_defs.h>
+#include "cam_sync_api.h"
+#include "cam_node.h"
+#include "cam_context.h"
+#include "cam_context_utils.h"
+#include "cam_icp_context.h"
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+
+static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_acquire_dev_to_hw(ctx, cmd);
+	if (!rc)
+		ctx->state = CAM_CTX_ACQUIRED;
+
+	return rc;
+}
+
+static int __cam_icp_release_dev_in_acquired(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_release_dev_to_hw(ctx, cmd);
+	if (rc)
+		pr_err("Unable to release device\n");
+
+	ctx->state = CAM_CTX_AVAILABLE;
+	return rc;
+}
+
+static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_start_dev_to_hw(ctx, cmd);
+	if (!rc)
+		ctx->state = CAM_CTX_READY;
+
+	return rc;
+}
+
+static int __cam_icp_config_dev_in_ready(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_prepare_dev_to_hw(ctx, cmd);
+	if (rc)
+		pr_err("Unable to prepare device\n");
+
+	return rc;
+}
+
+static int __cam_icp_stop_dev_in_ready(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_stop_dev_to_hw(ctx);
+	if (rc)
+		pr_err("Unable to stop device\n");
+
+	ctx->state = CAM_CTX_ACQUIRED;
+	return rc;
+}
+
+static int __cam_icp_release_dev_in_ready(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = __cam_icp_stop_dev_in_ready(ctx, NULL);
+	if (rc)
+		pr_err("Unable to stop device\n");
+
+	rc = __cam_icp_release_dev_in_acquired(ctx, cmd);
+	if (rc)
+		pr_err("Unable to stop device\n");
+
+	return rc;
+}
+
+static int __cam_icp_handle_buf_done_in_ready(void *ctx,
+	uint32_t evt_id, void *done)
+{
+	return cam_context_buf_done_from_hw(ctx, done, 0);
+}
+
+static struct cam_ctx_ops
+	cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = {
+	/* Uninit */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Available */
+	{
+		.ioctl_ops = {
+			.acquire_dev = __cam_icp_acquire_dev_in_available,
+		},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Acquired */
+	{
+		.ioctl_ops = {
+			.release_dev = __cam_icp_release_dev_in_acquired,
+			.start_dev = __cam_icp_start_dev_in_acquired,
+			.config_dev = __cam_icp_config_dev_in_ready,
+		},
+		.crm_ops = {},
+		.irq_ops = __cam_icp_handle_buf_done_in_ready,
+	},
+	/* Ready */
+	{
+		.ioctl_ops = {
+			.stop_dev = __cam_icp_stop_dev_in_ready,
+			.release_dev = __cam_icp_release_dev_in_ready,
+			.config_dev = __cam_icp_config_dev_in_ready,
+		},
+		.crm_ops = {},
+		.irq_ops = __cam_icp_handle_buf_done_in_ready,
+	},
+	/* Activated */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+};
+
+int cam_icp_context_init(struct cam_icp_context *ctx,
+	struct cam_hw_mgr_intf *hw_intf)
+{
+	int rc;
+
+	if ((!ctx) || (!ctx->base) || (!hw_intf)) {
+		pr_err("Invalid params: %pK %pK\n", ctx, hw_intf);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = cam_context_init(ctx->base, NULL, hw_intf, ctx->req_base,
+		CAM_CTX_REQ_MAX);
+	if (rc) {
+		pr_err("Camera Context Base init failed!\n");
+		goto err;
+	}
+
+	ctx->base->state_machine = cam_icp_ctx_state_machine;
+	ctx->base->ctx_priv = ctx;
+	ctx->ctxt_to_hw_map = NULL;
+
+err:
+	return rc;
+}
+
+int cam_icp_context_deinit(struct cam_icp_context *ctx)
+{
+	if ((!ctx) || (!ctx->base)) {
+		pr_err("Invalid params: %pK\n", ctx);
+		return -EINVAL;
+	}
+
+	cam_context_deinit(ctx->base);
+	memset(ctx, 0, sizeof(*ctx));
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/icp/cam_icp_context.h b/drivers/media/platform/msm/camera/icp/cam_icp_context.h
new file mode 100644
index 0000000..709fc56
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/cam_icp_context.h
@@ -0,0 +1,48 @@
+/* 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_ICP_CONTEXT_H_
+#define _CAM_ICP_CONTEXT_H_
+
+#include "cam_context.h"
+
+/**
+ * struct cam_icp_context - icp context
+ * @base: icp context object
+ * @state_machine: state machine for ICP context
+ * @req_base: common request structure
+ * @state: icp context state
+ * @ctxt_to_hw_map: context to FW handle mapping
+ */
+struct cam_icp_context {
+	struct cam_context *base;
+	struct cam_ctx_ops *state_machine;
+	struct cam_ctx_request req_base[CAM_CTX_REQ_MAX];
+	uint32_t state;
+	void *ctxt_to_hw_map;
+};
+
+/**
+ * cam_icp_context_init() - ICP context init
+ * @ctx: Pointer to context
+ * @hw_intf: Pointer to ICP hardware interface
+ */
+int cam_icp_context_init(struct cam_icp_context *ctx,
+	struct cam_hw_mgr_intf *hw_intf);
+
+/**
+ * cam_icp_context_deinit() - ICP context deinit
+ * @ctx: Pointer to context
+ */
+int cam_icp_context_deinit(struct cam_icp_context *ctx);
+
+#endif /* _CAM_ICP_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/icp/cam_icp_subdev.c
new file mode 100644
index 0000000..703561d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/cam_icp_subdev.c
@@ -0,0 +1,259 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-ICP %s:%d " fmt, __func__, __LINE__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/cam_req_mgr.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_req_mgr_dev.h"
+#include "cam_subdev.h"
+#include "cam_node.h"
+#include "cam_context.h"
+#include "cam_icp_context.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+
+#define CAM_ICP_DEV_NAME        "cam-icp"
+
+struct cam_icp_subdev {
+	struct cam_subdev sd;
+	struct cam_node *node;
+	struct cam_context ctx[CAM_CTX_MAX];
+	struct cam_icp_context ctx_icp[CAM_CTX_MAX];
+	struct mutex icp_lock;
+	int32_t open_cnt;
+	int32_t reserved;
+};
+
+static struct cam_icp_subdev g_icp_dev;
+
+static const struct of_device_id cam_icp_dt_match[] = {
+	{.compatible = "qcom,cam-icp"},
+	{}
+};
+
+static int cam_icp_subdev_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
+	struct cam_node *node = v4l2_get_subdevdata(sd);
+	int rc = 0;
+
+	mutex_lock(&g_icp_dev.icp_lock);
+	if (g_icp_dev.open_cnt >= 1) {
+		pr_err("ICP subdev is already opened\n");
+		rc = -EALREADY;
+		goto end;
+	}
+
+	if (!node) {
+		pr_err("Invalid args\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	hw_mgr_intf = &node->hw_mgr_intf;
+	rc = hw_mgr_intf->download_fw(hw_mgr_intf->hw_mgr_priv, NULL);
+	if (rc < 0) {
+		pr_err("FW download failed\n");
+		goto end;
+	}
+	g_icp_dev.open_cnt++;
+end:
+	mutex_unlock(&g_icp_dev.icp_lock);
+	return rc;
+}
+
+static int cam_icp_subdev_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
+	struct cam_node *node = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&g_icp_dev.icp_lock);
+	if (g_icp_dev.open_cnt <= 0) {
+		pr_err("ICP subdev is already closed\n");
+		rc = -EINVAL;
+		goto end;
+	}
+	g_icp_dev.open_cnt--;
+	if (!node) {
+		pr_err("Invalid args\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	hw_mgr_intf = &node->hw_mgr_intf;
+	if (!hw_mgr_intf) {
+		pr_err("hw_mgr_intf is not initialized\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = hw_mgr_intf->hw_close(hw_mgr_intf->hw_mgr_priv, NULL);
+	if (rc < 0) {
+		pr_err("HW close failed\n");
+		goto end;
+	}
+
+end:
+	mutex_unlock(&g_icp_dev.icp_lock);
+	return 0;
+}
+
+const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = {
+	.open = cam_icp_subdev_open,
+	.close = cam_icp_subdev_close,
+};
+
+static int cam_icp_probe(struct platform_device *pdev)
+{
+	int rc = 0, i = 0;
+	struct cam_node *node;
+	struct cam_hw_mgr_intf *hw_mgr_intf;
+
+	if (!pdev) {
+		pr_err("pdev is NULL\n");
+		return -EINVAL;
+	}
+
+	memset(&g_icp_dev, 0, sizeof(g_icp_dev));
+
+	g_icp_dev.sd.pdev = pdev;
+	g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops;
+	rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME,
+		CAM_ICP_DEVICE_TYPE);
+	if (rc) {
+		pr_err("ICP cam_subdev_probe failed!\n");
+		goto probe_fail;
+	}
+
+	node = (struct cam_node *) g_icp_dev.sd.token;
+
+	hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL);
+	if (!hw_mgr_intf) {
+		rc = -EINVAL;
+		goto hw_alloc_fail;
+	}
+
+	rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf);
+	if (rc) {
+		pr_err("ICP HW manager init failed: %d\n", rc);
+		goto hw_init_fail;
+	}
+
+	pr_debug("Initializing the ICP contexts\n");
+	for (i = 0; i < CAM_CTX_MAX; i++) {
+		g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i];
+		rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i],
+					hw_mgr_intf);
+		if (rc) {
+			pr_err("ICP context init failed!\n");
+			goto ctx_fail;
+		}
+	}
+
+	pr_debug("Initializing the ICP Node\n");
+	rc = cam_node_init(node, hw_mgr_intf, g_icp_dev.ctx,
+				CAM_CTX_MAX, CAM_ICP_DEV_NAME);
+	if (rc) {
+		pr_err("ICP node init failed!\n");
+		goto ctx_fail;
+	}
+
+	g_icp_dev.open_cnt = 0;
+	mutex_init(&g_icp_dev.icp_lock);
+
+	return rc;
+
+ctx_fail:
+	for (--i; i >= 0; i--)
+		cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
+hw_init_fail:
+	kfree(hw_mgr_intf);
+hw_alloc_fail:
+	cam_subdev_remove(&g_icp_dev.sd);
+probe_fail:
+	return rc;
+}
+
+static int cam_icp_remove(struct platform_device *pdev)
+{
+	int i;
+	struct v4l2_subdev *sd;
+	struct cam_subdev *subdev;
+
+	if (!pdev) {
+		pr_err("pdev is NULL\n");
+		return -EINVAL;
+	}
+
+	sd = platform_get_drvdata(pdev);
+	if (!sd) {
+		pr_err("V4l2 subdev is NULL\n");
+		return -EINVAL;
+	}
+
+	subdev = v4l2_get_subdevdata(sd);
+	if (!subdev) {
+		pr_err("cam subdev is NULL\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_CTX_MAX; i++)
+		cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
+	cam_node_deinit(g_icp_dev.node);
+	cam_subdev_remove(&g_icp_dev.sd);
+	mutex_destroy(&g_icp_dev.icp_lock);
+
+	return 0;
+}
+
+static struct platform_driver cam_icp_driver = {
+	.probe = cam_icp_probe,
+	.remove = cam_icp_remove,
+	.driver = {
+		.name = "cam_icp",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_icp_dt_match,
+	},
+};
+
+static int __init cam_icp_init_module(void)
+{
+	return platform_driver_register(&cam_icp_driver);
+}
+
+static void __exit cam_icp_exit_module(void)
+{
+	platform_driver_unregister(&cam_icp_driver);
+}
+module_init(cam_icp_init_module);
+module_exit(cam_icp_exit_module);
+MODULE_DESCRIPTION("MSM ICP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
new file mode 100644
index 0000000..1e42f75
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
@@ -0,0 +1,105 @@
+/* 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 _HFI_INTF_H_
+#define _HFI_INTF_H_
+
+#include <linux/types.h>
+
+/**
+ * struct hfi_mem
+ * @len: length of memory
+ * @kva: kernel virtual address
+ * @iova: IO virtual address
+ * @reserved: reserved field
+ */
+struct hfi_mem {
+	uint64_t len;
+	uint64_t kva;
+	uint32_t iova;
+	uint32_t reserved;
+};
+
+/**
+ * struct hfi_mem_info
+ * @qtbl: qtable hfi memory
+ * @cmd_q: command queue hfi memory for host to firmware communication
+ * @msg_q: message queue hfi memory for firmware to host communication
+ * @dbg_q: debug queue hfi memory for firmware debug information
+ * @sec_heap: secondary heap hfi memory for firmware
+ * @icp_base: icp base address
+ */
+struct hfi_mem_info {
+	struct hfi_mem qtbl;
+	struct hfi_mem cmd_q;
+	struct hfi_mem msg_q;
+	struct hfi_mem dbg_q;
+	struct hfi_mem sec_heap;
+	void __iomem *icp_base;
+};
+
+/**
+ * hfi_write_cmd() - function for hfi write
+ * @cmd_ptr: pointer to command data for hfi write
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int hfi_write_cmd(void *cmd_ptr);
+
+/**
+ * hfi_read_message() - function for hfi read
+ * @pmsg: buffer to place read message for hfi queue
+ * @q_id: queue id
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int hfi_read_message(uint32_t *pmsg, uint8_t q_id);
+
+/**
+ * hfi_init() - function initialize hfi after firmware download
+ * @event_driven_mode: event mode
+ * @hfi_mem: hfi memory info
+ * @icp_base: icp base address
+ * @debug: debug flag
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
+	void *__iomem icp_base, bool debug);
+
+/**
+ * hfi_get_hw_caps() - hardware capabilities from firmware
+ * @query_caps: holds query information from hfi
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int hfi_get_hw_caps(void *query_caps);
+
+/**
+ * hfi_send_system_cmd() - send hfi system command to firmware
+ * @type: type of system command
+ * @data: command data
+ * @size: size of command data
+ */
+void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size);
+
+/**
+ * cam_hfi_enable_cpu() - enable A5 CPU
+ * @icp_base: icp base address
+ */
+void cam_hfi_enable_cpu(void __iomem *icp_base);
+/**
+ * cam_hfi_deinit() - cleanup HFI
+ */
+void cam_hfi_deinit(void);
+
+#endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
new file mode 100644
index 0000000..d1bbe01
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
@@ -0,0 +1,308 @@
+/* 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_HFI_REG_H_
+#define _CAM_HFI_REG_H_
+
+#include <linux/types.h>
+#include "hfi_intf.h"
+
+
+/* start of ICP CSR registers */
+#define HFI_REG_A5_HW_VERSION                   0x0
+#define HFI_REG_A5_CSR_NSEC_RESET               0x4
+#define HFI_REG_A5_CSR_A5_CONTROL               0x8
+#define HFI_REG_A5_CSR_ETM                      0xC
+#define HFI_REG_A5_CSR_A2HOSTINTEN              0x10
+#define HFI_REG_A5_CSR_A2HOSTINT                0x14
+#define HFI_REG_A5_CSR_A2HOSTINTCLR             0x18
+#define HFI_REG_A5_CSR_A2HOSTINTSTATUS          0x1C
+#define HFI_REG_A5_CSR_A2HOSTINTSET             0x20
+#define HFI_REG_A5_CSR_HOST2ICPINT              0x30
+#define HFI_REG_A5_CSR_A5_STATUS                0x200
+#define HFI_REG_A5_QGIC2_LM_ID                  0x204
+#define HFI_REG_A5_SPARE                        0x400
+
+/* general purpose registers from */
+#define HFI_REG_FW_VERSION                      0x44
+#define HFI_REG_HOST_ICP_INIT_REQUEST           0x48
+#define HFI_REG_ICP_HOST_INIT_RESPONSE          0x4C
+#define HFI_REG_SHARED_MEM_PTR                  0x50
+#define HFI_REG_SHARED_MEM_SIZE                 0x54
+#define HFI_REG_QTBL_PTR                        0x58
+#define HFI_REG_UNCACHED_HEAP_PTR               0x5C
+#define HFI_REG_UNCACHED_HEAP_SIZE              0x60
+/* end of ICP CSR registers */
+
+/* flags for ICP CSR registers */
+#define ICP_FLAG_CSR_WAKE_UP_EN                 (1 << 4)
+#define ICP_FLAG_CSR_A5_EN                      (1 << 9)
+#define ICP_CSR_EN_CLKGATE_WFI                  (1 << 12)
+#define ICP_CSR_EDBGRQ                          (1 << 14)
+#define ICP_CSR_DBGSWENABLE                     (1 << 22)
+
+/* start of Queue table and queues */
+#define MAX_ICP_HFI_QUEUES                      4
+#define ICP_QHDR_TX_TYPE_MASK                   0xFF000000
+#define ICP_QHDR_RX_TYPE_MASK                   0x00FF0000
+#define ICP_QHDR_PRI_TYPE_MASK                  0x0000FF00
+#define ICP_QHDR_Q_ID_MASK                      0x000000FF
+
+#define ICP_CMD_Q_SIZE_IN_BYTES                 4096
+#define ICP_MSG_Q_SIZE_IN_BYTES                 4096
+#define ICP_DBG_Q_SIZE_IN_BYTES                 8192
+
+#define ICP_SHARED_MEM_IN_BYTES                 (1024 * 1024)
+#define ICP_UNCACHED_HEAP_SIZE_IN_BYTES         (2 * 1024 * 1024)
+#define ICP_HFI_MAX_MSG_SIZE_IN_WORDS           128
+
+#define ICP_HFI_QTBL_HOSTID1                    0x01000000
+#define ICP_HFI_QTBL_STATUS_ENABLED             0x00000001
+#define ICP_HFI_NUMBER_OF_QS                    3
+#define ICP_HFI_NUMBER_OF_ACTIVE_QS             3
+#define ICP_HFI_QTBL_OFFSET                     0
+#define ICP_HFI_VAR_SIZE_PKT                    0
+#define ICP_HFI_MAX_MSG_SIZE_IN_WORDS           128
+
+
+/* Queue Header type masks. Use these to access bitfields in qhdr_type */
+#define HFI_MASK_QHDR_TX_TYPE                   0xFF000000
+#define HFI_MASK_QHDR_RX_TYPE                   0x00FF0000
+#define HFI_MASK_QHDR_PRI_TYPE                  0x0000FF00
+#define HFI_MASK_QHDR_Q_ID_TYPE                 0x000000FF
+
+
+#define TX_EVENT_DRIVEN_MODE_1                  0
+#define RX_EVENT_DRIVEN_MODE_1                  0
+#define TX_EVENT_DRIVEN_MODE_2                  0x01000000
+#define RX_EVENT_DRIVEN_MODE_2                  0x00010000
+#define TX_EVENT_POLL_MODE_2                    0x02000000
+#define RX_EVENT_POLL_MODE_2                    0x00020000
+#define U32_OFFSET                              0x1
+#define BYTE_WORD_SHIFT                         2
+
+/**
+ * @INVALID: Invalid state
+ * @FW_LOAD_DONE: Firmware load is completed
+ * @FW_RESP_DONE: Firmware response is received
+ * @FW_START_SENT: firmware start is send
+ * @FW_READY: firmware is ready to accept commands
+ */
+enum hfi_state {
+	INVALID,
+	FW_LOAD_DONE,
+	FW_RESP_DONE,
+	FW_START_SENT,
+	FW_READY
+};
+
+/**
+ * @RESET: init success
+ * @SET: init failed
+ */
+enum reg_settings {
+	RESET,
+	SET
+};
+
+/**
+ * @INTR_DISABLE: Disable interrupt
+ * @INTR_ENABLE: Enable interrupt
+ */
+enum intr_status {
+	INTR_DISABLE,
+	INTR_ENABLE
+};
+
+/**
+ * @ICP_INIT_RESP_RESET: reset init state
+ * @ICP_INIT_RESP_SUCCESS: init success
+ * @ICP_INIT_RESP_FAILED: init failed
+ */
+enum host_init_resp {
+	ICP_INIT_RESP_RESET,
+	ICP_INIT_RESP_SUCCESS,
+	ICP_INIT_RESP_FAILED
+};
+
+/**
+ * @ICP_INIT_REQUEST_RESET: reset init request
+ * @ICP_INIT_REQUEST_SET: set init request
+ */
+enum host_init_request {
+	ICP_INIT_REQUEST_RESET,
+	ICP_INIT_REQUEST_SET
+};
+
+/**
+ * @QHDR_INACTIVE: Queue is inactive
+ * @QHDR_ACTIVE: Queue is active
+ */
+enum qhdr_status {
+	QHDR_INACTIVE,
+	QHDR_ACTIVE
+};
+
+/**
+ * @INTR_MODE: event driven mode 1, each send and receive generates interrupt
+ * @WM_MODE: event driven mode 2, interrupts based on watermark mechanism
+ * @POLL_MODE: poll method
+ */
+enum qhdr_event_drv_type {
+	INTR_MODE,
+	WM_MODE,
+	POLL_MODE
+};
+
+/**
+ * @TX_INT: event driven mode 1, each send and receive generates interrupt
+ * @TX_INT_WM: event driven mode 2, interrupts based on watermark mechanism
+ * @TX_POLL: poll method
+ * @ICP_QHDR_TX_TYPE_MASK defines position in qhdr_type
+ */
+enum qhdr_tx_type {
+	TX_INT,
+	TX_INT_WM,
+	TX_POLL
+};
+
+/**
+ * @RX_INT: event driven mode 1, each send and receive generates interrupt
+ * @RX_INT_WM: event driven mode 2, interrupts based on watermark mechanism
+ * @RX_POLL: poll method
+ * @ICP_QHDR_RX_TYPE_MASK defines position in qhdr_type
+ */
+enum qhdr_rx_type {
+	RX_INT,
+	RX_INT_WM,
+	RX_POLL
+};
+
+/**
+ * @Q_CMD: Host to FW command queue
+ * @Q_MSG: FW to Host message queue
+ * @Q_DEBUG: FW to Host debug queue
+ * @ICP_QHDR_Q_ID_MASK defines position in qhdr_type
+ */
+enum qhdr_q_id {
+	Q_CMD,
+	Q_MSG,
+	Q_DBG
+};
+
+/**
+ * struct hfi_qtbl_hdr
+ * @qtbl_version: Queue table version number
+ *                Higher 16 bits: Major version
+ *                Lower 16 bits: Minor version
+ * @qtbl_size: Queue table size from version to last parametr in qhdr entry
+ * @qtbl_qhdr0_offset: Offset to the start of first qhdr
+ * @qtbl_qhdr_size: Queue header size in bytes
+ * @qtbl_num_q: Total number of queues in Queue table
+ * @qtbl_num_active_q: Total number of active queues
+ */
+struct hfi_qtbl_hdr {
+	uint32_t qtbl_version;
+	uint32_t qtbl_size;
+	uint32_t qtbl_qhdr0_offset;
+	uint32_t qtbl_qhdr_size;
+	uint32_t qtbl_num_q;
+	uint32_t qtbl_num_active_q;
+} __packed;
+
+/**
+ * struct hfi_q_hdr
+ * @qhdr_status: Queue status, qhdr_state define possible status
+ * @qhdr_start_addr: Queue start address in non cached memory
+ * @qhdr_type: qhdr_tx, qhdr_rx, qhdr_q_id and priority defines qhdr type
+ * @qhdr_q_size: Queue size
+ *		Number of queue packets if qhdr_pkt_size is non-zero
+ *		Queue size in bytes if qhdr_pkt_size is zero
+ * @qhdr_pkt_size: Size of queue packet entries
+ *		0x0: variable queue packet size
+ *		non zero: size of queue packet entry, fixed
+ * @qhdr_pkt_drop_cnt: Number of packets dropped by sender
+ * @qhdr_rx_wm: Receiver watermark, applicable in event driven mode
+ * @qhdr_tx_wm: Sender watermark, applicable in event driven mode
+ * @qhdr_rx_req: Receiver sets this bit if queue is empty
+ * @qhdr_tx_req: Sender sets this bit if queue is full
+ * @qhdr_rx_irq_status: Receiver sets this bit and triggers an interrupt to
+ *		the sender after packets are dequeued. Sender clears this bit
+ * @qhdr_tx_irq_status: Sender sets this bit and triggers an interrupt to
+ *		the receiver after packets are queued. Receiver clears this bit
+ * @qhdr_read_idx: Read index
+ * @qhdr_write_idx: Write index
+ */
+struct hfi_q_hdr {
+	uint32_t dummy[15];
+	uint32_t qhdr_status;
+	uint32_t dummy1[15];
+	uint32_t qhdr_start_addr;
+	uint32_t dummy2[15];
+	uint32_t qhdr_type;
+	uint32_t dummy3[15];
+	uint32_t qhdr_q_size;
+	uint32_t dummy4[15];
+	uint32_t qhdr_pkt_size;
+	uint32_t dummy5[15];
+	uint32_t qhdr_pkt_drop_cnt;
+	uint32_t dummy6[15];
+	uint32_t qhdr_rx_wm;
+	uint32_t dummy7[15];
+	uint32_t qhdr_tx_wm;
+	uint32_t dummy8[15];
+	uint32_t qhdr_rx_req;
+	uint32_t dummy9[15];
+	uint32_t qhdr_tx_req;
+	uint32_t dummy10[15];
+	uint32_t qhdr_rx_irq_status;
+	uint32_t dummy11[15];
+	uint32_t qhdr_tx_irq_status;
+	uint32_t dummy12[15];
+	uint32_t qhdr_read_idx;
+	uint32_t dummy13[15];
+	uint32_t qhdr_write_idx;
+	uint32_t dummy14[15];
+};
+
+/**
+ * struct hfi_q_tbl
+ * @q_tbl_hdr: Queue table header
+ * @q_hdr: Queue header info, it holds info of cmd, msg and debug queues
+ */
+struct hfi_qtbl {
+	struct hfi_qtbl_hdr q_tbl_hdr;
+	struct hfi_q_hdr q_hdr[MAX_ICP_HFI_QUEUES];
+};
+
+/**
+ * struct hfi_info
+ * @map: Hfi shared memory info
+ * @smem_size: Shared memory size
+ * @uncachedheap_size: uncached heap size
+ * @msgpacket_buf: message buffer
+ * @hfi_state: State machine for hfi
+ * @cmd_q_lock: Lock for command queue
+ * @csr_base: CSR base address
+ */
+struct hfi_info {
+	struct hfi_mem_info map;
+	uint32_t smem_size;
+	uint32_t uncachedheap_size;
+	uint32_t msgpacket_buf[ICP_HFI_MAX_MSG_SIZE_IN_WORDS];
+	uint8_t hfi_state;
+	struct mutex cmd_q_lock;
+	struct mutex msg_q_lock;
+	void __iomem *csr_base;
+};
+
+#endif /* _CAM_HFI_REG_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_session_defs.h
new file mode 100644
index 0000000..837efec
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_session_defs.h
@@ -0,0 +1,428 @@
+/* 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_HFI_SESSION_DEFS_H
+#define _CAM_HFI_SESSION_DEFS_H
+
+#include <linux/types.h>
+
+#define HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO             0x1
+#define HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS         0x2
+#define HFI_IPEBPS_CMD_OPCODE_BPS_ABORT                 0x3
+#define HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY               0x4
+
+#define HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO             0x5
+#define HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS         0x6
+#define HFI_IPEBPS_CMD_OPCODE_IPE_ABORT                 0x7
+#define HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY               0x8
+
+#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_IPE          0x9
+#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_BPS          0xa
+#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_BPS          0xb
+#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_IPE          0xc
+
+#define HFI_IPEBPS_HANDLE_TYPE_BPS                      0x1
+#define HFI_IPEBPS_HANDLE_TYPE_IPE_RT                   0x2
+#define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT               0x3
+
+/**
+ * struct hfi_cmd_abort_destroy
+ * @user_data: user supplied data
+ *
+ * IPE/BPS destroy/abort command
+ * @HFI_IPEBPS_CMD_OPCODE_IPE_ABORT
+ * @HFI_IPEBPS_CMD_OPCODE_BPS_ABORT
+ * @HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY
+ * @HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY
+ */
+struct hfi_cmd_abort_destroy {
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_cmd_chaining_ops
+ * @wait_hdl: current session handle waits on wait_hdl to complete operation
+ * @user_data: user supplied argument
+ *
+ * this structure for chaining opcodes
+ * BPS_WAITS_FOR_IPE
+ * BPS_WAITS_FOR_BPS
+ * IPE_WAITS_FOR_BPS
+ * IPE_WAITS_FOR_IPE
+ */
+struct hfi_cmd_chaining_ops {
+	uint32_t wait_hdl;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_cmd_create_handle
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @handle_type: IPE/BPS firmware session handle type
+ * @user_data1: caller provided data1
+ * @user_data2: caller provided data2
+ *
+ * create firmware session handle
+ */
+struct hfi_cmd_create_handle {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t handle_type;
+	uint64_t user_data1;
+	uint64_t user_data2;
+} __packed;
+
+/**
+ * struct hfi_cmd_ipebps_async
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @opcode: opcode for IPE/BPS async operation
+ *          CONFIG_IO: configures I/O for IPE/BPS handle
+ *          FRAME_PROCESS: image frame to be processed by IPE/BPS
+ *          ABORT: abort all processing frames of IPE/BPS handle
+ *          DESTROY: destroy earlier created IPE/BPS handle
+ *          BPS_WAITS_FOR_IPE: sync for BPS to wait for IPE
+ *          BPS_WAITS_FOR_BPS: sync for BPS to wait for BPS
+ *          IPE_WAITS_FOR_IPE: sync for IPE to wait for IPE
+ *          IPE_WAITS_FOR_BPS: sync for IPE to wait for BPS
+ * @num_fw_handles: number of IPE/BPS firmware handles in fw_handles array
+ * @fw_handles: IPE/BPS handles array
+ * @payload: command payload for IPE/BPS opcodes
+ * @direct: points to actual payload
+ * @indirect: points to address of payload
+ *
+ * sends async command to the earlier created IPE or BPS handle
+ * for asynchronous operation.
+ */
+struct hfi_cmd_ipebps_async {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t opcode;
+	uint64_t user_data1;
+	uint64_t user_data2;
+	uint32_t num_fw_handles;
+	uint32_t fw_handles[1];
+	union {
+		uint32_t direct[1];
+		uint32_t indirect;
+	} payload;
+} __packed;
+
+/**
+ * struct hfi_msg_create_handle_ack
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @err_type: error code
+ * @fw_handle: output param for IPE/BPS handle
+ * @user_data1: user provided data1
+ * @user_data2: user provided data2
+ *
+ * ack for create handle command of IPE/BPS
+ * @HFI_MSG_IPEBPS_CREATE_HANDLE_ACK
+ */
+struct hfi_msg_create_handle_ack {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t err_type;
+	uint32_t fw_handle;
+	uint64_t user_data1;
+	uint64_t user_data2;
+} __packed;
+
+/**
+ * struct hfi_msg_ipebps_async
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @opcode: opcode of IPE/BPS async operation
+ * @user_data1: user provided data1
+ * @user_data2: user provided data2
+ * @err_type: error code
+ * @msg_data: IPE/BPS async done message data
+ *
+ * result of IPE/BPS async command
+ * @HFI_MSG_IPEBPS_ASYNC_COMMAND_ACK
+ */
+struct hfi_msg_ipebps_async_ack {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t opcode;
+	uint64_t user_data1;
+	uint64_t user_data2;
+	uint32_t err_type;
+	uint32_t msg_data[1];
+} __packed;
+
+/**
+ * struct hfi_msg_frame_process_done
+ * @result: result of frame process command
+ * @scratch_buffer_address: address of scratch buffer
+ */
+struct hfi_msg_frame_process_done {
+	uint32_t result;
+	uint32_t scratch_buffer_address;
+};
+
+/**
+ * struct hfi_msg_chaining_op
+ * @status: return status
+ * @user_data: user data provided as part of chaining ops
+ *
+ * IPE/BPS wait response
+ */
+struct hfi_msg_chaining_op {
+	uint32_t status;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_msg_abort_destroy
+ * @status: return status
+ * @user_data: user data provided as part of abort/destroy ops
+ *
+ * IPE/BPS abort/destroy response
+ */
+struct hfi_msg_abort_destroy {
+	uint32_t status;
+	uint64_t user_data;
+} __packed;
+
+#define MAX_NUM_OF_IMAGE_PLANES	2
+
+enum hfi_ipe_io_images {
+	IPE_INPUT_IMAGE_FULL,
+	IPE_INPUT_IMAGE_DS4,
+	IPE_INPUT_IMAGE_DS16,
+	IPE_INPUT_IMAGE_DS64,
+	IPE_INPUT_IMAGE_FULL_REF,
+	IPE_INPUT_IMAGE_DS4_REF,
+	IPE_INPUT_IMAGE_DS16_REF,
+	IPE_INPUT_IMAGE_DS64_REF,
+	IPE_OUTPUT_IMAGE_DISPLAY,
+	IPE_OUTPUT_IMAGE_VIDEO,
+	IPE_OUTPUT_IMAGE_FULL_REF,
+	IPE_OUTPUT_IMAGE_DS4_REF,
+	IPE_OUTPUT_IMAGE_DS16_REF,
+	IPE_OUTPUT_IMAGE_DS64_REF,
+	IPE_INPUT_IMAGE_FIRST = IPE_INPUT_IMAGE_FULL,
+	IPE_INPUT_IMAGE_LAST = IPE_INPUT_IMAGE_DS64_REF,
+	IPE_OUTPUT_IMAGE_FIRST = IPE_OUTPUT_IMAGE_DISPLAY,
+	IPE_OUTPUT_IMAGE_LAST = IPE_OUTPUT_IMAGE_DS64_REF,
+	IPE_IO_IMAGES_MAX
+};
+
+enum hfi_ipe_image_format {
+	IMAGE_FORMAT_INVALID,
+	IMAGE_FORMAT_MIPI_8,
+	IMAGE_FORMAT_MIPI_10,
+	IMAGE_FORMAT_MIPI_12,
+	IMAGE_FORMAT_MIPI_14,
+	IMAGE_FORMAT_BAYER_8,
+	IMAGE_FORMAT_BAYER_10,
+	IMAGE_FORMAT_BAYER_12,
+	IMAGE_FORMAT_BAYER_14,
+	IMAGE_FORMAT_PDI_10,
+	IMAGE_FORMAT_PD_10,
+	IMAGE_FORMAT_PD_8,
+	IMAGE_FORMAT_INDICATIONS,
+	IMAGE_FORMAT_REFINEMENT,
+	IMAGE_FORMAT_UBWC_TP_10,
+	IMAGE_FORMAT_UBWC_NV_12,
+	IMAGE_FORMAT_UBWC_NV12_4R,
+	IMAGE_FORMAT_UBWC_P010,
+	IMAGE_FORMAT_LINEAR_TP_10,
+	IMAGE_FORMAT_LINEAR_P010,
+	IMAGE_FORMAT_LINEAR_NV12,
+	IMAGE_FORMAT_LINEAR_PLAIN_16,
+	IMAGE_FORMAT_YUV422_8,
+	IMAGE_FORMAT_YUV422_10,
+	IMAGE_FORMAT_STATISTICS_BAYER_GRID,
+	IMAGE_FORMAT_STATISTICS_BAYER_HISTOGRAM,
+	IMAGE_FORMAT_MAX
+};
+
+enum hfi_ipe_plane_format {
+	PLANE_FORMAT_INVALID = 0,
+	PLANE_FORMAT_MIPI_8,
+	PLANE_FORMAT_MIPI_10,
+	PLANE_FORMAT_MIPI_12,
+	PLANE_FORMAT_MIPI_14,
+	PLANE_FORMAT_BAYER_8,
+	PLANE_FORMAT_BAYER_10,
+	PLANE_FORMAT_BAYER_12,
+	PLANE_FORMAT_BAYER_14,
+	PLANE_FORMAT_PDI_10,
+	PLANE_FORMAT_PD_10,
+	PLANE_FORMAT_PD_8,
+	PLANE_FORMAT_INDICATIONS,
+	PLANE_FORMAT_REFINEMENT,
+	PLANE_FORMAT_UBWC_TP_10_Y,
+	PLANE_FORMAT_UBWC_TP_10_C,
+	PLANE_FORMAT_UBWC_NV_12_Y,
+	PLANE_FORMAT_UBWC_NV_12_C,
+	PLANE_FORMAT_UBWC_NV_12_4R_Y,
+	PLANE_FORMAT_UBWC_NV_12_4R_C,
+	PLANE_FORMAT_UBWC_P010_Y,
+	PLANE_FORMAT_UBWC_P010_C,
+	PLANE_FORMAT_LINEAR_TP_10_Y,
+	PLANE_FORMAT_LINEAR_TP_10_C,
+	PLANE_FORMAT_LINEAR_P010_Y,
+	PLANE_FORMAT_LINEAR_P010_C,
+	PLANE_FORMAT_LINEAR_NV12_Y,
+	PLANE_FORMAT_LINEAR_NV12_C,
+	PLANE_FORMAT_LINEAR_PLAIN_16_Y,
+	PLANE_FORMAT_LINEAR_PLAIN_16_C,
+	PLANE_FORMAT_YUV422_8,
+	PLANE_FORMAT_YUV422_10,
+	PLANE_FORMAT_STATISTICS_BAYER_GRID,
+	PLANE_FORMAT_STATISTICS_BAYER_HISTOGRAM,
+	PLANE_FORMAT_MAX
+};
+
+enum hfi_ipe_bayer_pixel_order {
+	FIRST_PIXEL_R,
+	FIRST_PIXEL_GR,
+	FIRST_PIXEL_B,
+	FIRST_PIXEL_GB,
+	FIRST_PIXEL_MAX
+};
+
+enum hfi_ipe_pixel_pack_alignment {
+	PIXEL_LSB_ALIGNED,
+	PIXEL_MSB_ALIGNED,
+};
+
+enum hfi_ipe_yuv_422_order {
+	PIXEL_ORDER_Y_U_Y_V,
+	PIXEL_ORDER_Y_V_Y_U,
+	PIXEL_ORDER_U_Y_V_Y,
+	PIXEL_ORDER_V_Y_U_Y,
+	PIXEL_ORDER_YUV422_MAX
+};
+
+enum ubwc_write_client {
+	IPE_WR_CLIENT_0 = 0,
+	IPE_WR_CLIENT_1,
+	IPE_WR_CLIENT_5,
+	IPE_WR_CLIENT_6,
+	IPE_WR_CLIENT_7,
+	IPE_WR_CLIENT_8,
+	IPE_WR_CLIENT_MAX
+};
+
+/**
+ * struct image_info
+ * @format: image format
+ * @img_width: image width
+ * @img_height: image height
+ * @bayer_order: pixel order
+ * @pix_align: alignment
+ * @yuv422_order: YUV order
+ * @byte_swap: byte swap
+ */
+struct image_info {
+	enum hfi_ipe_image_format format;
+	uint32_t img_width;
+	uint32_t img_height;
+	enum hfi_ipe_bayer_pixel_order bayer_order;
+	enum hfi_ipe_pixel_pack_alignment pix_align;
+	enum hfi_ipe_yuv_422_order yuv422_order;
+	uint32_t byte_swap;
+} __packed;
+
+/**
+ * struct buffer_layout
+ * @buf_stride: buffer stride
+ * @buf_height: buffer height
+ */
+struct buffer_layout {
+	uint32_t buf_stride;
+	uint32_t buf_height;
+} __packed;
+
+/**
+ * struct image_desc
+ * @info: image info
+ * @buf_layout: buffer layout
+ * @meta_buf_layout: meta buffer layout
+ */
+struct image_desc {
+	struct image_info info;
+	struct buffer_layout buf_layout[MAX_NUM_OF_IMAGE_PLANES];
+	struct buffer_layout meta_buf_layout[MAX_NUM_OF_IMAGE_PLANES];
+} __packed;
+
+/**
+ * struct hfi_cmd_ipe_config
+ * @images: images descreptions
+ * @user_data: user supplied data
+ *
+ * payload for IPE async command
+ */
+struct hfi_cmd_ipe_config {
+	struct image_desc images[IPE_IO_IMAGES_MAX];
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct frame_buffers
+ * @buf_ptr: buffer pointers for all planes
+ * @meta_buf_ptr: meta buffer pointers for all planes
+ */
+struct frame_buffers {
+	uint32_t buf_ptr[MAX_NUM_OF_IMAGE_PLANES];
+	uint32_t meta_buf_ptr[MAX_NUM_OF_IMAGE_PLANES];
+} __packed;
+
+/**
+ * struct hfi_msg_ipe_config
+ * @rc: result of ipe config command
+ * @scratch_mem_size: scratch mem size for a config
+ * @user_data: user data
+ */
+struct hfi_msg_ipe_config {
+	uint32_t rc;
+	uint32_t scratch_mem_size;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_msg_bps_common
+ * @rc: result of ipe config command
+ * @user_data: user data
+ */
+struct hfi_msg_bps_common {
+	uint32_t rc;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct ipe_bps_destroy
+ * @user_data: user data
+ */
+struct ipe_bps_destroy {
+	uint64_t userdata;
+};
+
+/**
+ * struct hfi_msg_ipe_frame_process
+ * @status: result of ipe frame process command
+ * @scratch_buf_addr: address of scratch buffer
+ * @user_data: user data
+ */
+struct hfi_msg_ipe_frame_process {
+	uint32_t status;
+	uint32_t scratch_buf_addr;
+	uint64_t user_data;
+} __packed;
+
+#endif /* _CAM_HFI_SESSION_DEFS_H */
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_sys_defs.h
new file mode 100644
index 0000000..e7163ac
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_sys_defs.h
@@ -0,0 +1,483 @@
+/* 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 _HFI_DEFS_H_
+#define _HFI_DEFS_H_
+
+#include <linux/types.h>
+
+/*
+ * Following base acts as common starting points
+ * for all enumerations.
+ */
+#define HFI_COMMON_BASE                 0x0
+
+/* HFI Domain base offset for commands and messages */
+#define HFI_DOMAIN_SHFT                 (24)
+#define HFI_DOMAIN_BMSK                 (0x7 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_ICP             (0x0 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_IPE_BPS         (0x1 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_CDM             (0x2 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_DBG             (0x3 << HFI_DOMAIN_SHFT)
+
+/* Command base offset for commands */
+#define HFI_CMD_START_OFFSET            0x10000
+
+/* Command base offset for messages */
+#define HFI_MSG_START_OFFSET            0x20000
+
+/* System Level Error types */
+#define HFI_ERR_SYS_NONE                (HFI_COMMON_BASE)
+#define HFI_ERR_SYS_FATAL               (HFI_COMMON_BASE + 0x1)
+#define HFI_ERR_SYS_VERSION_MISMATCH    (HFI_COMMON_BASE + 0x2)
+#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN  (HFI_COMMON_BASE + 0x3)
+#define HFI_ERR_SYS_UNSUPPORT_CMD       (HFI_COMMON_BASE + 0x4)
+#define HFI_ERR_SYS_CMDFAILED           (HFI_COMMON_BASE + 0x5)
+#define HFI_ERR_SYS_CMDSIZE             (HFI_COMMON_BASE + 0x6)
+
+/* System Level Event types */
+#define HFI_EVENT_SYS_ERROR             (HFI_COMMON_BASE + 0x1)
+#define HFI_EVENT_ICP_ERROR             (HFI_COMMON_BASE + 0x2)
+#define HFI_EVENT_IPE_BPS_ERROR         (HFI_COMMON_BASE + 0x3)
+#define HFI_EVENT_CDM_ERROR             (HFI_COMMON_BASE + 0x4)
+#define HFI_EVENT_DBG_ERROR             (HFI_COMMON_BASE + 0x5)
+
+/* Core level start Ranges for errors */
+#define HFI_ERR_ICP_START               (HFI_COMMON_BASE + 0x64)
+#define HFI_ERR_IPE_BPS_START           (HFI_ERR_ICP_START + 0x64)
+#define HFI_ERR_CDM_START               (HFI_ERR_IPE_BPS_START + 0x64)
+#define HFI_ERR_DBG_START               (HFI_ERR_CDM_START + 0x64)
+
+/*ICP Core level  error messages */
+#define HFI_ERR_NO_RES                  (HFI_ERR_ICP_START + 0x1)
+#define HFI_ERR_UNSUPPORTED_RES         (HFI_ERR_ICP_START + 0x2)
+#define HFI_ERR_UNSUPPORTED_PROP        (HFI_ERR_ICP_START + 0x3)
+#define HFI_ERR_INIT_EXPECTED           (HFI_ERR_ICP_START + 0x4)
+#define HFI_ERR_INIT_IGNORED            (HFI_ERR_ICP_START + 0x5)
+
+/* System level commands */
+#define HFI_CMD_COMMON_START \
+		(HFI_DOMAIN_BASE_ICP + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_SYS_INIT               (HFI_CMD_COMMON_START + 0x1)
+#define HFI_CMD_SYS_PC_PREP            (HFI_CMD_COMMON_START + 0x2)
+#define HFI_CMD_SYS_SET_PROPERTY       (HFI_CMD_COMMON_START + 0x3)
+#define HFI_CMD_SYS_GET_PROPERTY       (HFI_CMD_COMMON_START + 0x4)
+#define HFI_CMD_SYS_PING               (HFI_CMD_COMMON_START + 0x5)
+#define HFI_CMD_SYS_RESET              (HFI_CMD_COMMON_START + 0x6)
+
+/* Core level commands */
+/* IPE/BPS core Commands */
+#define HFI_CMD_IPE_BPS_COMMON_START \
+		(HFI_DOMAIN_BASE_IPE_BPS + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_IPEBPS_CREATE_HANDLE \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0x8)
+#define HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0xa)
+#define HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0xe)
+
+/* CDM core Commands */
+#define HFI_CMD_CDM_COMMON_START \
+		(HFI_DOMAIN_BASE_CDM + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_CDM_TEST_START (HFI_CMD_CDM_COMMON_START + 0x800)
+#define HFI_CMD_CDM_END        (HFI_CMD_CDM_COMMON_START + 0xFFF)
+
+/* Debug/Test Commands */
+#define HFI_CMD_DBG_COMMON_START \
+		(HFI_DOMAIN_BASE_DBG + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_DBG_TEST_START  (HFI_CMD_DBG_COMMON_START + 0x800)
+#define HFI_CMD_DBG_END         (HFI_CMD_DBG_COMMON_START + 0xFFF)
+
+/* System level messages */
+#define HFI_MSG_ICP_COMMON_START \
+		(HFI_DOMAIN_BASE_ICP + HFI_MSG_START_OFFSET + 0x0)
+#define HFI_MSG_SYS_INIT_DONE           (HFI_MSG_ICP_COMMON_START + 0x1)
+#define HFI_MSG_SYS_PC_PREP_DONE        (HFI_MSG_ICP_COMMON_START + 0x2)
+#define HFI_MSG_SYS_DEBUG               (HFI_MSG_ICP_COMMON_START + 0x3)
+#define HFI_MSG_SYS_IDLE                (HFI_MSG_ICP_COMMON_START + 0x4)
+#define HFI_MSG_SYS_PROPERTY_INFO       (HFI_MSG_ICP_COMMON_START + 0x5)
+#define HFI_MSG_SYS_PING_ACK            (HFI_MSG_ICP_COMMON_START + 0x6)
+#define HFI_MSG_SYS_RESET_ACK           (HFI_MSG_ICP_COMMON_START + 0x7)
+#define HFI_MSG_EVENT_NOTIFY            (HFI_MSG_ICP_COMMON_START + 0x8)
+
+/* Core level Messages */
+/* IPE/BPS core Messages */
+#define HFI_MSG_IPE_BPS_COMMON_START \
+		(HFI_DOMAIN_BASE_IPE_BPS + HFI_MSG_START_OFFSET + 0x0)
+#define HFI_MSG_IPEBPS_CREATE_HANDLE_ACK \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x08)
+#define HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x0a)
+#define HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x0e)
+#define HFI_MSG_IPE_BPS_TEST_START	\
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x800)
+#define HFI_MSG_IPE_BPS_END \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0xFFF)
+
+/* CDM core Messages */
+#define HFI_MSG_CDM_COMMON_START \
+		(HFI_DOMAIN_BASE_CDM + HFI_MSG_START_OFFSET + 0x0)
+#define  HFI_MSG_PRI_CDM_PAYLOAD_ACK    (HFI_MSG_CDM_COMMON_START + 0xa)
+#define  HFI_MSG_PRI_LLD_PAYLOAD_ACK    (HFI_MSG_CDM_COMMON_START + 0xb)
+#define HFI_MSG_CDM_TEST_START          (HFI_MSG_CDM_COMMON_START + 0x800)
+#define HFI_MSG_CDM_END                 (HFI_MSG_CDM_COMMON_START + 0xFFF)
+
+/* core level test command ranges */
+/* ICP core level test command range */
+#define HFI_CMD_ICP_TEST_START          (HFI_CMD_ICP_COMMON_START + 0x800)
+#define HFI_CMD_ICP_END                 (HFI_CMD_ICP_COMMON_START + 0xFFF)
+
+/* IPE/BPS core level test command range */
+#define HFI_CMD_IPE_BPS_TEST_START \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0x800)
+#define HFI_CMD_IPE_BPS_END (HFI_CMD_IPE_BPS_COMMON_START + 0xFFF)
+
+/* ICP core level test message range */
+#define HFI_MSG_ICP_TEST_START  (HFI_MSG_ICP_COMMON_START + 0x800)
+#define HFI_MSG_ICP_END         (HFI_MSG_ICP_COMMON_START + 0xFFF)
+
+/* ICP core level Debug test message range */
+#define HFI_MSG_DBG_COMMON_START \
+		(HFI_DOMAIN_BASE_DBG + 0x0)
+#define HFI_MSG_DBG_TEST_START  (HFI_MSG_DBG_COMMON_START + 0x800)
+#define HFI_MSG_DBG_END         (HFI_MSG_DBG_COMMON_START + 0xFFF)
+
+/* System  level property base offset */
+#define HFI_PROPERTY_ICP_COMMON_START  (HFI_DOMAIN_BASE_ICP + 0x0)
+
+#define HFI_PROP_SYS_DEBUG_CFG         (HFI_PROPERTY_ICP_COMMON_START + 0x1)
+#define HFI_PROP_SYS_IMAGE_VER         (HFI_PROPERTY_ICP_COMMON_START + 0x3)
+#define HFI_PROP_SYS_SUPPORTED         (HFI_PROPERTY_ICP_COMMON_START + 0x4)
+
+/* Capabilities reported at sys init */
+#define HFI_CAPS_PLACEHOLDER_1         (HFI_COMMON_BASE + 0x1)
+#define HFI_CAPS_PLACEHOLDER_2         (HFI_COMMON_BASE + 0x2)
+
+/* Section describes different debug levels (HFI_DEBUG_MSG_X)
+ * available for debug messages from FW
+ */
+#define  HFI_DEBUG_MSG_LOW      0x00000001
+#define  HFI_DEBUG_MSG_MEDIUM   0x00000002
+#define  HFI_DEBUG_MSG_HIGH     0x00000004
+#define  HFI_DEBUG_MSG_ERROR    0x00000008
+#define  HFI_DEBUG_MSG_FATAL    0x00000010
+/* Messages containing performance data */
+#define  HFI_DEBUG_MSG_PERF     0x00000020
+/* Disable ARM9 WFI in low power mode. */
+#define  HFI_DEBUG_CFG_WFI      0x01000000
+/* Disable ARM9 watchdog. */
+#define  HFI_DEBUG_CFG_ARM9WD   0x10000000
+
+/* Debug Msg Communication types:
+ * Section describes different modes (HFI_DEBUG_MODE_X)
+ * available to communicate the debug messages
+ */
+ /* Debug message output through   the interface debug queue. */
+#define HFI_DEBUG_MODE_QUEUE     0x00000001
+ /* Debug message output through QDSS. */
+#define HFI_DEBUG_MODE_QDSS      0x00000002
+
+
+#define HFI_DEBUG_MSG_LOW        0x00000001
+#define HFI_DEBUG_MSG_MEDIUM     0x00000002
+#define HFI_DEBUG_MSG_HIGH       0x00000004
+#define HFI_DEBUG_MSG_ERROR      0x00000008
+#define HFI_DEBUG_MSG_FATAL      0x00000010
+#define HFI_DEBUG_MSG_PERF       0x00000020
+#define HFI_DEBUG_CFG_WFI        0x01000000
+#define HFI_DEBUG_CFG_ARM9WD     0x10000000
+
+#define HFI_DEBUG_MODE_QUEUE     0x00000001
+#define HFI_DEBUG_MODE_QDSS      0x00000002
+
+/**
+ * start of sys command packet types
+ * These commands are used to get system level information
+ * from firmware
+ */
+
+/**
+ * struct hfi_caps_support
+ * payload to report caps through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED
+ * @type: capability type
+ * @min: minimum supported value for the capability
+ * @max: maximum supported value for the capability
+ * @step_size: supported steps between min-max
+ */
+struct hfi_caps_support {
+	uint32_t type;
+	uint32_t min;
+	uint32_t max;
+	uint32_t step_size;
+} __packed;
+
+/**
+ * struct hfi_caps_support_info
+ * capability report through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED
+ * @num_caps: number of capabilities listed
+ * @caps_data: capabilities info array
+ */
+struct hfi_caps_support_info {
+	uint32_t num_caps;
+	struct hfi_caps_support caps_data[1];
+} __packed;
+
+/**
+ * struct hfi_debug
+ * payload structure to configure HFI_PROPERTY_SYS_DEBUG_CONFIG
+ * @debug_config: it is a result of HFI_DEBUG_MSG_X values that
+ *                are OR-ed together to specify the debug message types
+ *                to otput
+ * @debug_mode: debug message output through debug queue/qdss
+ * @HFI_PROPERTY_SYS_DEBUG_CONFIG
+ */
+struct hfi_debug {
+	uint32_t debug_config;
+	uint32_t debug_mode;
+} __packed;
+
+
+/**
+ * struct hfi_cmd_sys_init
+ * command to initialization of system session
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @HFI_CMD_SYS_INIT
+ */
+struct hfi_cmd_sys_init {
+	uint32_t size;
+	uint32_t pkt_type;
+} __packed;
+
+/**
+ * struct hfi_cmd_pc_prep
+ * command to firmware to prepare for power collapse
+ * @eize: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @HFI_CMD_SYS_PC_PREP
+ */
+struct hfi_cmd_pc_prep {
+	uint32_t size;
+	uint32_t pkt_type;
+} __packed;
+
+/**
+ * struct hfi_cmd_prop
+ * command to get/set properties of firmware
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @num_prop: number of properties queried/set
+ * @prop_data: array of property IDs being queried. size depends on num_prop
+ *             array of property IDs and associated structure pairs in set
+ * @HFI_CMD_SYS_GET_PROPERTY
+ * @HFI_CMD_SYS_SET_PROPERTY
+ */
+struct hfi_cmd_prop {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_cmd_ping_pkt
+ * ping command pings the firmware to confirm whether
+ * it is alive.
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @user_data: client data, firmware returns this data
+ *             as part of HFI_MSG_SYS_PING_ACK
+ * @HFI_CMD_SYS_PING
+ */
+struct hfi_cmd_ping_pkt {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_cmd_sys_reset_pkt
+ * sends the reset command to FW. FW responds in the same type
+ * of packet. so can be used for reset_ack_pkt type also
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @user_data: client data, firmware returns this data
+ *             as part of HFI_MSG_SYS_RESET_ACK
+ * @HFI_CMD_SYS_RESET
+ */
+
+struct hfi_cmd_sys_reset_pkt {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint64_t user_data;
+} __packed;
+
+/* end of sys command packet types */
+
+/* start of sys message packet types */
+
+/**
+ * struct hfi_prop
+ * structure to report maximum supported features of firmware.
+ */
+struct hfi_sys_support {
+	uint32_t place_holder;
+} __packed;
+
+/**
+ * struct hfi_supported_prop
+ * structure to report HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED
+ * for a session
+ * @num_prop: number of properties supported
+ * @prop_data: array of supported property IDs
+ */
+struct hfi_supported_prop {
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_image_version
+ * system image version
+ * @major: major version number
+ * @minor: minor version number
+ * @ver_name_size: size of version name
+ * @ver_name: image version name
+ */
+struct hfi_image_version {
+	uint32_t major;
+	uint32_t minor;
+	uint32_t ver_name_size;
+	uint8_t  ver_name[1];
+} __packed;
+
+/**
+ * struct hfi_msg_init_done
+ * system init done message from firmware. Many system level properties
+ * are returned with the packet
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @err_type: error code associated with response
+ * @num_prop: number of default capability info
+ * @prop_data: array of property ids and corresponding structure pairs
+ */
+struct hfi_msg_init_done {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t err_type;
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_msg_pc_prep_done
+ * system power collapse preperation done message
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @err_type: error code associated with the response
+ */
+struct hfi_msg_pc_prep_done {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t err_type;
+} __packed;
+
+/**
+ * struct hfi_msg_prop
+ * system property info from firmware
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @num_prop: number of property info structures
+ * @prop_data: array of property IDs and associated structure pairs
+ */
+struct hfi_msg_prop {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_msg_idle
+ * system idle message from firmware
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ */
+struct hfi_msg_idle {
+	uint32_t size;
+	uint32_t pkt_type;
+} __packed;
+
+/**
+ * struct hfi_msg_ping_ack
+ * system ping ack message
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @user_data: this data is sent as part of ping command from host
+ */
+struct hfi_msg_ping_ack {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_msg_debug
+ * system debug message defination
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @msg_type: debug message type
+ * @msg_size: size of debug message in bytes
+ * @timestamp_hi: most significant 32 bits of the 64 bit timestamp field.
+ *                timestamp shall be interpreted as a signed 64-bit value
+ *                representing microseconds.
+ * @timestamp_lo: least significant 32 bits of the 64 bit timestamp field.
+ *                timestamp shall be interpreted as a signed 64-bit value
+ *                representing microseconds.
+ * @msg_data: message data in string form
+ */
+struct hfi_msg_debug {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t msg_type;
+	uint32_t msg_size;
+	uint32_t timestamp_hi;
+	uint32_t timestamp_lo;
+	uint8_t  msg_data[1];
+} __packed;
+/**
+ * struct hfi_msg_event_notify
+ * event notify message
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @fw_handle: firmware session handle
+ * @event_id: session event id
+ * @event_data1: event data corresponding to event ID
+ * @event_data2: event data corresponding to event ID
+ * @ext_event_data: info array, interpreted based on event_data1
+ * and event_data2
+ */
+struct hfi_msg_event_notify {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t fw_handle;
+	uint32_t event_id;
+	uint32_t event_data1;
+	uint32_t event_data2;
+	uint32_t ext_event_data[1];
+} __packed;
+/**
+ * end of sys message packet types
+ */
+
+#endif /* _HFI_DEFS_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/hfi.c b/drivers/media/platform/msm/camera/icp/hfi.c
new file mode 100644
index 0000000..4315865
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/hfi.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "HFI-FW %s:%d " fmt, __func__, __LINE__
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <asm/errno.h>
+#include <linux/timer.h>
+#include <media/cam_icp.h>
+#include "cam_io_util.h"
+#include "hfi_reg.h"
+#include "hfi_sys_defs.h"
+#include "hfi_session_defs.h"
+#include "hfi_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+
+#define HFI_VERSION_INFO_MAJOR_VAL  1
+#define HFI_VERSION_INFO_MINOR_VAL  1
+#define HFI_VERSION_INFO_STEP_VAL   0
+#define HFI_VERSION_INFO_STEP_VAL   0
+#define HFI_VERSION_INFO_MAJOR_BMSK  0xFF000000
+#define HFI_VERSION_INFO_MAJOR_SHFT  24
+#define HFI_VERSION_INFO_MINOR_BMSK  0xFFFF00
+#define HFI_VERSION_INFO_MINOR_SHFT  8
+#define HFI_VERSION_INFO_STEP_BMSK   0xFF
+#define HFI_VERSION_INFO_STEP_SHFT  0
+
+#undef  HFI_DBG
+#define HFI_DBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct hfi_info *g_hfi;
+unsigned int g_icp_mmu_hdl;
+
+int hfi_write_cmd(void *cmd_ptr)
+{
+	uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp;
+	uint32_t *write_q, *write_ptr;
+	struct hfi_qtbl *q_tbl;
+	struct hfi_q_hdr *q;
+	int rc = 0;
+	int i = 0;
+
+	if (!cmd_ptr) {
+		pr_err("Invalid args\n");
+		return -EINVAL;
+	}
+
+	if (!g_hfi || g_hfi->hfi_state < FW_START_SENT) {
+		pr_err("FW not ready yet\n");
+		return -EIO;
+	}
+
+	mutex_lock(&g_hfi->cmd_q_lock);
+
+	q_tbl = (struct hfi_qtbl *)g_hfi->map.qtbl.kva;
+	q = &q_tbl->q_hdr[Q_CMD];
+
+	write_q = (uint32_t *)g_hfi->map.cmd_q.kva;
+
+	size_in_words = (*(uint32_t *)cmd_ptr) >> BYTE_WORD_SHIFT;
+	if (!size_in_words) {
+		pr_debug("failed");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	HFI_DBG("size_in_words : %u\n", size_in_words);
+	HFI_DBG("q->qhdr_write_idx %x\n", q->qhdr_write_idx);
+
+	read_idx = q->qhdr_read_idx;
+
+	empty_space = (q->qhdr_write_idx >= read_idx) ?
+		(q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) :
+		(read_idx - q->qhdr_write_idx);
+	if (empty_space <= size_in_words) {
+		pr_err("failed");
+		rc = -EIO;
+		goto err;
+	}
+	HFI_DBG("empty_space : %u\n", empty_space);
+
+	new_write_idx = q->qhdr_write_idx + size_in_words;
+	write_ptr = (uint32_t *)(write_q + q->qhdr_write_idx);
+
+	if (new_write_idx < q->qhdr_q_size) {
+		memcpy(write_ptr, (uint8_t *)cmd_ptr,
+			size_in_words << BYTE_WORD_SHIFT);
+	} else {
+		new_write_idx -= q->qhdr_q_size;
+		temp = (size_in_words - new_write_idx) << BYTE_WORD_SHIFT;
+		memcpy(write_ptr, (uint8_t *)cmd_ptr, temp);
+		memcpy(write_q, (uint8_t *)cmd_ptr + temp,
+			new_write_idx << BYTE_WORD_SHIFT);
+	}
+	for (i = 0; i < size_in_words; i++)
+		pr_debug("%x\n", write_ptr[i]);
+
+	q->qhdr_write_idx = new_write_idx;
+	HFI_DBG("q->qhdr_write_idx %x\n", q->qhdr_write_idx);
+	cam_io_w((uint32_t)INTR_ENABLE,
+		g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
+err:
+	mutex_unlock(&g_hfi->cmd_q_lock);
+	return 0;
+}
+
+int hfi_read_message(uint32_t *pmsg, uint8_t q_id)
+{
+	struct hfi_qtbl *q_tbl_ptr;
+	struct hfi_q_hdr *q;
+	uint32_t new_read_idx, size_in_words, temp;
+	uint32_t *read_q, *read_ptr;
+	int rc = 0;
+	int i = 0;
+
+	if (!pmsg || q_id > Q_DBG) {
+		pr_err("Inavlid args\n");
+		return -EINVAL;
+	}
+
+	q_tbl_ptr = (struct hfi_qtbl *)g_hfi->map.qtbl.kva;
+	q = &q_tbl_ptr->q_hdr[q_id];
+
+	if ((g_hfi->hfi_state < FW_START_SENT) ||
+		(q->qhdr_read_idx == q->qhdr_write_idx)) {
+		pr_debug("FW or Q not ready, hfi state : %u, r idx : %u, w idx : %u\n",
+			g_hfi->hfi_state, q->qhdr_read_idx, q->qhdr_write_idx);
+		return -EIO;
+	}
+
+	mutex_lock(&g_hfi->msg_q_lock);
+
+	if (q_id == Q_CMD)
+		read_q = (uint32_t *)g_hfi->map.cmd_q.kva;
+	else if (q_id == Q_MSG)
+		read_q = (uint32_t *)g_hfi->map.msg_q.kva;
+	else
+		read_q = (uint32_t *)g_hfi->map.dbg_q.kva;
+
+	read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx);
+	size_in_words = (*read_ptr) >> BYTE_WORD_SHIFT;
+
+	HFI_DBG("size_in_words : %u\n", size_in_words);
+	HFI_DBG("read_ptr : %pK\n", (void *)read_ptr);
+
+	if ((size_in_words == 0) ||
+		(size_in_words > ICP_HFI_MAX_MSG_SIZE_IN_WORDS)) {
+		pr_err("invalid HFI message packet size - 0x%08x\n",
+			size_in_words << BYTE_WORD_SHIFT);
+		q->qhdr_read_idx = q->qhdr_write_idx;
+		rc = -EIO;
+		goto err;
+	}
+
+	new_read_idx = q->qhdr_read_idx + size_in_words;
+	HFI_DBG("new_read_idx : %u\n", new_read_idx);
+
+	if (new_read_idx < q->qhdr_q_size) {
+		memcpy(pmsg, read_ptr, size_in_words << BYTE_WORD_SHIFT);
+	} else {
+		new_read_idx -= q->qhdr_q_size;
+		temp = (size_in_words - new_read_idx) << BYTE_WORD_SHIFT;
+		memcpy(pmsg, read_ptr, temp);
+		memcpy((uint8_t *)pmsg + temp, read_q,
+			new_read_idx << BYTE_WORD_SHIFT);
+	}
+
+	for (i = 0; i < size_in_words; i++)
+		pr_debug("%x\n", read_ptr[i]);
+
+	q->qhdr_read_idx = new_read_idx;
+err:
+	mutex_unlock(&g_hfi->msg_q_lock);
+	HFI_DBG("Exit\n");
+	return 0;
+}
+
+void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size)
+{
+	switch (type) {
+	case HFI_CMD_SYS_INIT: {
+		struct hfi_cmd_sys_init init;
+
+		memset(&init, 0, sizeof(init));
+
+		init.size = sizeof(struct hfi_cmd_sys_init);
+		init.pkt_type = type;
+		hfi_write_cmd(&init);
+	}
+		break;
+	case HFI_CMD_SYS_PC_PREP: {
+		struct hfi_cmd_pc_prep prep;
+
+		prep.size = sizeof(struct hfi_cmd_pc_prep);
+		prep.pkt_type = type;
+		hfi_write_cmd(&prep);
+	}
+		break;
+	case HFI_CMD_SYS_SET_PROPERTY: {
+		struct hfi_cmd_prop prop;
+
+		if ((uint32_t)data == (uint32_t)HFI_PROP_SYS_DEBUG_CFG) {
+			prop.size = sizeof(struct hfi_cmd_prop);
+			prop.pkt_type = type;
+			prop.num_prop = 1;
+			prop.prop_data[0] = HFI_PROP_SYS_DEBUG_CFG;
+			hfi_write_cmd(&prop);
+		}
+	}
+		break;
+	case HFI_CMD_SYS_GET_PROPERTY:
+		break;
+	case HFI_CMD_SYS_PING: {
+		struct hfi_cmd_ping_pkt ping;
+
+		ping.size = sizeof(struct hfi_cmd_ping_pkt);
+		ping.pkt_type = type;
+		ping.user_data = (uint64_t)data;
+		hfi_write_cmd(&ping);
+	}
+		break;
+	case HFI_CMD_SYS_RESET: {
+		struct hfi_cmd_sys_reset_pkt reset;
+
+		reset.size = sizeof(struct hfi_cmd_sys_reset_pkt);
+		reset.pkt_type = type;
+		reset.user_data = (uint64_t)data;
+		hfi_write_cmd(&reset);
+	}
+		break;
+	case HFI_CMD_IPEBPS_CREATE_HANDLE: {
+		struct hfi_cmd_create_handle handle;
+
+		handle.size = sizeof(struct hfi_cmd_create_handle);
+		handle.pkt_type = type;
+		handle.handle_type = (uint32_t)data;
+		handle.user_data1 = 0;
+		hfi_write_cmd(&handle);
+	}
+		break;
+	case HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT:
+		break;
+	default:
+		pr_err("command not supported :%d\n", type);
+		break;
+	}
+}
+
+
+int hfi_get_hw_caps(void *query_buf)
+{
+	int i = 0;
+	struct cam_icp_query_cap_cmd *query_cmd = NULL;
+
+	if (!query_buf) {
+		pr_err("%s: query buf is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	query_cmd = (struct cam_icp_query_cap_cmd *)query_buf;
+	query_cmd->fw_version.major = 0x12;
+	query_cmd->fw_version.minor = 0x12;
+	query_cmd->fw_version.revision = 0x12;
+
+	query_cmd->api_version.major = 0x13;
+	query_cmd->api_version.minor = 0x13;
+	query_cmd->api_version.revision = 0x13;
+
+	query_cmd->num_ipe = 2;
+	query_cmd->num_bps = 1;
+
+	for (i = 0; i < CAM_ICP_DEV_TYPE_MAX; i++) {
+		query_cmd->dev_ver[i].dev_type = i;
+		query_cmd->dev_ver[i].hw_ver.major = 0x34 + i;
+		query_cmd->dev_ver[i].hw_ver.minor = 0x34 + i;
+		query_cmd->dev_ver[i].hw_ver.incr = 0x34 + i;
+	}
+	return 0;
+}
+
+
+void cam_hfi_enable_cpu(void __iomem *icp_base)
+{
+	cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN,
+			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+	cam_io_w((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
+}
+
+int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
+		void __iomem *icp_base, bool debug)
+{
+	int rc = 0;
+	struct hfi_qtbl *qtbl;
+	struct hfi_qtbl_hdr *qtbl_hdr;
+	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
+	uint32_t hw_version, fw_version;
+	uint32_t status;
+
+	if (!g_hfi) {
+		g_hfi = kzalloc(sizeof(struct hfi_info), GFP_KERNEL);
+		if (!g_hfi) {
+			rc = -ENOMEM;
+			goto alloc_fail;
+		}
+	}
+
+	pr_debug("g_hfi: %pK\n", (void *)g_hfi);
+	if (g_hfi->hfi_state != INVALID) {
+		pr_err("hfi_init: invalid state\n");
+		return -EINVAL;
+	}
+
+	g_hfi->hfi_state = FW_LOAD_DONE;
+	memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map));
+
+	if (debug) {
+		cam_io_w_mb(
+		(uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN |
+		ICP_CSR_EDBGRQ | ICP_CSR_DBGSWENABLE),
+		icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+		msleep(100);
+		cam_io_w_mb((uint32_t)(ICP_FLAG_CSR_A5_EN |
+		ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI),
+		icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+	} else {
+		cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
+			ICP_FLAG_CSR_WAKE_UP_EN,
+			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+	}
+
+	mutex_init(&g_hfi->cmd_q_lock);
+	mutex_init(&g_hfi->msg_q_lock);
+
+	g_hfi->csr_base = icp_base;
+
+	qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
+	qtbl_hdr = &qtbl->q_tbl_hdr;
+	qtbl_hdr->qtbl_version = 0xFFFFFFFF;
+	qtbl_hdr->qtbl_size = sizeof(struct hfi_qtbl);
+	qtbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_qtbl_hdr);
+	qtbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_q_hdr);
+	qtbl_hdr->qtbl_num_q = ICP_HFI_NUMBER_OF_QS;
+	qtbl_hdr->qtbl_num_active_q = ICP_HFI_NUMBER_OF_QS;
+
+	/* setup host-to-firmware command queue */
+	pr_debug("updating the command queue info\n");
+	cmd_q_hdr = &qtbl->q_hdr[Q_CMD];
+	cmd_q_hdr->qhdr_status = QHDR_ACTIVE;
+	cmd_q_hdr->qhdr_start_addr = hfi_mem->cmd_q.iova;
+	cmd_q_hdr->qhdr_q_size =  ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	cmd_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT;
+	cmd_q_hdr->qhdr_pkt_drop_cnt = RESET;
+	cmd_q_hdr->qhdr_read_idx = RESET;
+	cmd_q_hdr->qhdr_write_idx = RESET;
+
+	/* setup firmware-to-Host message queue */
+	pr_debug("updating the message queue info\n");
+	msg_q_hdr = &qtbl->q_hdr[Q_MSG];
+	msg_q_hdr->qhdr_status = QHDR_ACTIVE;
+	msg_q_hdr->qhdr_start_addr = hfi_mem->msg_q.iova;
+	msg_q_hdr->qhdr_q_size = ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	msg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT;
+	msg_q_hdr->qhdr_pkt_drop_cnt = RESET;
+	msg_q_hdr->qhdr_read_idx = RESET;
+	msg_q_hdr->qhdr_write_idx = RESET;
+
+	/* setup firmware-to-Host message queue */
+	pr_debug("updating the debug queue info\n");
+	dbg_q_hdr = &qtbl->q_hdr[Q_DBG];
+	dbg_q_hdr->qhdr_status = QHDR_ACTIVE;
+	dbg_q_hdr->qhdr_start_addr = hfi_mem->dbg_q.iova;
+	dbg_q_hdr->qhdr_q_size = ICP_DBG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	dbg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT;
+	dbg_q_hdr->qhdr_pkt_drop_cnt = RESET;
+	dbg_q_hdr->qhdr_read_idx = RESET;
+	dbg_q_hdr->qhdr_write_idx = RESET;
+	pr_debug("Done updating the debug queue info\n");
+
+	switch (event_driven_mode) {
+	case INTR_MODE:
+		cmd_q_hdr->qhdr_type = Q_CMD;
+		cmd_q_hdr->qhdr_rx_wm = SET;
+		cmd_q_hdr->qhdr_tx_wm = SET;
+		cmd_q_hdr->qhdr_rx_req = SET;
+		cmd_q_hdr->qhdr_tx_req = RESET;
+		cmd_q_hdr->qhdr_rx_irq_status = RESET;
+		cmd_q_hdr->qhdr_tx_irq_status = RESET;
+
+		msg_q_hdr->qhdr_type = Q_MSG;
+		msg_q_hdr->qhdr_rx_wm = SET;
+		msg_q_hdr->qhdr_tx_wm = SET;
+		msg_q_hdr->qhdr_rx_req = SET;
+		msg_q_hdr->qhdr_tx_req = RESET;
+		msg_q_hdr->qhdr_rx_irq_status = RESET;
+		msg_q_hdr->qhdr_tx_irq_status = RESET;
+
+		dbg_q_hdr->qhdr_type = Q_DBG;
+		dbg_q_hdr->qhdr_rx_wm = SET;
+		dbg_q_hdr->qhdr_tx_wm = SET;
+		dbg_q_hdr->qhdr_rx_req = SET;
+		dbg_q_hdr->qhdr_tx_req = RESET;
+		dbg_q_hdr->qhdr_rx_irq_status = RESET;
+		dbg_q_hdr->qhdr_tx_irq_status = RESET;
+
+		break;
+
+	case POLL_MODE:
+		cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_POLL_MODE_2 |
+			RX_EVENT_POLL_MODE_2;
+		msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_POLL_MODE_2 |
+			RX_EVENT_POLL_MODE_2;
+		dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_POLL_MODE_2 |
+			RX_EVENT_POLL_MODE_2;
+		break;
+
+	case WM_MODE:
+		cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_DRIVEN_MODE_2 |
+			RX_EVENT_DRIVEN_MODE_2;
+		cmd_q_hdr->qhdr_rx_wm = SET;
+		cmd_q_hdr->qhdr_tx_wm = SET;
+		cmd_q_hdr->qhdr_rx_req = RESET;
+		cmd_q_hdr->qhdr_tx_req = SET;
+		cmd_q_hdr->qhdr_rx_irq_status = RESET;
+		cmd_q_hdr->qhdr_tx_irq_status = RESET;
+
+		msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_DRIVEN_MODE_2 |
+			RX_EVENT_DRIVEN_MODE_2;
+		msg_q_hdr->qhdr_rx_wm = SET;
+		msg_q_hdr->qhdr_tx_wm = SET;
+		msg_q_hdr->qhdr_rx_req = SET;
+		msg_q_hdr->qhdr_tx_req = RESET;
+		msg_q_hdr->qhdr_rx_irq_status = RESET;
+		msg_q_hdr->qhdr_tx_irq_status = RESET;
+
+		dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_DRIVEN_MODE_2 |
+			RX_EVENT_DRIVEN_MODE_2;
+		dbg_q_hdr->qhdr_rx_wm = SET;
+		dbg_q_hdr->qhdr_tx_wm = SET;
+		dbg_q_hdr->qhdr_rx_req = SET;
+		dbg_q_hdr->qhdr_tx_req = RESET;
+		dbg_q_hdr->qhdr_rx_irq_status = RESET;
+		dbg_q_hdr->qhdr_tx_irq_status = RESET;
+		break;
+
+	default:
+		pr_err("Invalid event driven mode :%u", event_driven_mode);
+		break;
+	}
+
+	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+	cam_io_w((uint32_t)0x7400000, icp_base + HFI_REG_SHARED_MEM_PTR);
+	cam_io_w((uint32_t)0x6400000, icp_base + HFI_REG_SHARED_MEM_SIZE);
+	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
+	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+		icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
+	cam_io_w((uint32_t)ICP_INIT_REQUEST_SET,
+		icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
+
+	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
+	pr_debug("hw version : %u[%x]\n", hw_version, hw_version);
+
+	do {
+		msleep(500);
+		status = cam_io_r(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
+	} while (status != ICP_INIT_RESP_SUCCESS);
+
+	if (status == ICP_INIT_RESP_SUCCESS) {
+		g_hfi->hfi_state = FW_RESP_DONE;
+		rc = 0;
+	} else {
+		rc = -ENODEV;
+		pr_err("FW initialization failed");
+		goto regions_fail;
+	}
+
+	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+	g_hfi->hfi_state = FW_START_SENT;
+
+	pr_debug("fw version : %u[%x]\n", fw_version, fw_version);
+	pr_debug("hfi init is successful\n");
+	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+
+	return rc;
+regions_fail:
+	kzfree(g_hfi);
+alloc_fail:
+	return rc;
+}
+
+
+void cam_hfi_deinit(void)
+{
+	kfree(g_hfi);
+	g_hfi = NULL;
+}
+
+void icp_enable_fw_debug(void)
+{
+	hfi_send_system_cmd(HFI_CMD_SYS_SET_PROPERTY,
+		(uint64_t)HFI_PROP_SYS_DEBUG_CFG, 0);
+}
+
+int icp_ping_fw(void)
+{
+	hfi_send_system_cmd(HFI_CMD_SYS_PING,
+		(uint64_t)0x12123434, 0);
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/Makefile
new file mode 100644
index 0000000..8e95286
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/Makefile
@@ -0,0 +1,9 @@
+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/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw_mgr/ a5_hw/ ipe_hw/ bps_hw/
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/Makefile
new file mode 100644
index 0000000..a4df0b8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/Makefile
@@ -0,0 +1,11 @@
+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/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/a5_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += a5_dev.o a5_core.o a5_soc.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
new file mode 100644
index 0000000..f562bb9
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
@@ -0,0 +1,459 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "A5-CORE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/elf.h>
+#include <media/cam_icp.h>
+#include "cam_io_util.h"
+#include "cam_a5_hw_intf.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "a5_core.h"
+#include "a5_soc.h"
+#include "cam_soc_util.h"
+#include "cam_io_util.h"
+#include "hfi_intf.h"
+#include "hfi_sys_defs.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+static int cam_a5_cpas_vote(struct cam_a5_device_core_info *core_info,
+	struct cam_icp_cpas_vote *cpas_vote)
+{
+	int rc = 0;
+
+	if (cpas_vote->ahb_vote_valid)
+		rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
+			&cpas_vote->ahb_vote);
+
+	if (cpas_vote->axi_vote_valid)
+		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
+			&cpas_vote->axi_vote);
+
+	if (rc)
+		pr_err("cpas vote is failed: %d\n", rc);
+
+	return rc;
+}
+
+static int32_t cam_icp_validate_fw(const uint8_t *elf)
+{
+	struct elf32_hdr *elf_hdr;
+
+	if (!elf) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	elf_hdr = (struct elf32_hdr *)elf;
+
+	if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG)) {
+		pr_err("ICP elf identifier is failed\n");
+		return -EINVAL;
+	}
+
+	/* check architecture */
+	if (elf_hdr->e_machine != EM_ARM) {
+		pr_err("unsupported arch\n");
+		return -EINVAL;
+	}
+
+	/* check elf bit format */
+	if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
+		pr_err("elf doesn't support 32 bit format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int32_t cam_icp_get_fw_size(const uint8_t *elf, uint32_t *fw_size)
+{
+	int32_t rc = 0;
+	int32_t i = 0;
+	uint32_t num_prg_hdrs;
+	unsigned char *icp_prg_hdr_tbl;
+	uint32_t seg_mem_size = 0;
+	struct elf32_hdr *elf_hdr;
+	struct elf32_phdr *prg_hdr;
+
+	if (!elf || !fw_size) {
+		pr_err("invalid args\n");
+		return -EINVAL;
+	}
+
+	*fw_size = 0;
+
+	elf_hdr = (struct elf32_hdr *)elf;
+	num_prg_hdrs = elf_hdr->e_phnum;
+	icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff;
+	prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0];
+
+	if (!prg_hdr) {
+		pr_err("failed to get elf program header attr\n");
+		return -EINVAL;
+	}
+
+	pr_debug("num_prg_hdrs = %d\n", num_prg_hdrs);
+	for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) {
+		if (prg_hdr->p_flags == 0)
+			continue;
+
+		seg_mem_size = (prg_hdr->p_memsz + prg_hdr->p_align - 1) &
+					~(prg_hdr->p_align - 1);
+		seg_mem_size += prg_hdr->p_vaddr;
+		pr_debug("p_memsz = %x p_align = %x p_vaddr = %x seg_mem_size = %x\n",
+			(int)prg_hdr->p_memsz, (int)prg_hdr->p_align,
+			(int)prg_hdr->p_vaddr, (int)seg_mem_size);
+		if (*fw_size < seg_mem_size)
+			*fw_size = seg_mem_size;
+
+	}
+
+	if (*fw_size == 0) {
+		pr_err("invalid elf fw file\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t cam_icp_program_fw(const uint8_t *elf,
+		struct cam_a5_device_core_info *core_info)
+{
+	int32_t rc = 0;
+	uint32_t num_prg_hdrs;
+	unsigned char *icp_prg_hdr_tbl;
+	int32_t i = 0;
+	u8 *dest;
+	u8 *src;
+	struct elf32_hdr *elf_hdr;
+	struct elf32_phdr *prg_hdr;
+
+	elf_hdr = (struct elf32_hdr *)elf;
+	num_prg_hdrs = elf_hdr->e_phnum;
+	icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff;
+	prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0];
+
+	if (!prg_hdr) {
+		pr_err("failed to get elf program header attr\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) {
+		if (prg_hdr->p_flags == 0)
+			continue;
+
+		pr_debug("Loading FW header size: %u\n", prg_hdr->p_filesz);
+		if (prg_hdr->p_filesz != 0) {
+			src = (u8 *)((u8 *)elf + prg_hdr->p_offset);
+			dest = (u8 *)(((u8 *)core_info->fw_kva_addr) +
+						prg_hdr->p_vaddr);
+
+			memcpy_toio(dest, src, prg_hdr->p_filesz);
+			pr_debug("fw kva: %pK, p_vaddr: 0x%x\n",
+					dest, prg_hdr->p_vaddr);
+		}
+	}
+
+	return rc;
+}
+
+static int32_t cam_a5_download_fw(void *device_priv)
+{
+	int32_t rc = 0;
+	uint32_t fw_size;
+	const uint8_t *fw_start = NULL;
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+	struct platform_device         *pdev = NULL;
+	struct a5_soc_info *cam_a5_soc_info = NULL;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	hw_info = core_info->a5_hw_info;
+	pdev = soc_info->pdev;
+	cam_a5_soc_info = soc_info->soc_private;
+
+	rc = request_firmware(&core_info->fw_elf, "CAMERA_ICP.elf", &pdev->dev);
+	pr_debug("request_firmware: %d\n", rc);
+	if (rc < 0) {
+		pr_err("Failed to locate fw\n");
+		return rc;
+	}
+
+	if (!core_info->fw_elf) {
+		pr_err("request_firmware is failed\n");
+		return -EINVAL;
+	}
+
+	fw_start = core_info->fw_elf->data;
+	rc = cam_icp_validate_fw(fw_start);
+	if (rc < 0) {
+		pr_err("fw elf validation failed\n");
+		return -EINVAL;
+	}
+
+	rc = cam_icp_get_fw_size(fw_start, &fw_size);
+	if (rc < 0) {
+		pr_err("unable to get fw file size\n");
+		return rc;
+	}
+	pr_debug("cam_icp_get_fw_size: %u\n", fw_size);
+
+	/* Check FW firmware memory allocation is OK or not */
+	pr_debug("cam_icp_get_fw_size: %u %llu\n",
+		fw_size, core_info->fw_buf_len);
+
+	if (core_info->fw_buf_len < fw_size) {
+		pr_err("fw allocation failed\n");
+		goto fw_alloc_failed;
+	}
+
+	/* download fw */
+	rc = cam_icp_program_fw(fw_start, core_info);
+	if (rc < 0) {
+		pr_err("fw program is failed\n");
+		goto fw_program_failed;
+	}
+
+	return 0;
+fw_program_failed:
+fw_alloc_failed:
+	return rc;
+}
+
+int cam_a5_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+
+	rc = cam_cpas_start(core_info->cpas_handle,
+		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
+	if (rc < 0) {
+		pr_err("cpass start failed: %d\n", rc);
+		return rc;
+	}
+
+	rc = cam_a5_enable_soc_resources(soc_info);
+	if (rc < 0) {
+		pr_err("soc enable is failed\n");
+		rc = cam_cpas_stop(core_info->cpas_handle);
+		return rc;
+	}
+
+	return 0;
+}
+
+int cam_a5_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	rc = cam_a5_disable_soc_resources(soc_info);
+	if (rc < 0)
+		pr_err("soc enable is failed\n");
+
+	rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc < 0)
+		pr_err("cpas stop is failed: %d\n", rc);
+
+	return 0;
+}
+
+irqreturn_t cam_a5_irq(int irq_num, void *data)
+{
+	struct cam_hw_info *a5_dev = data;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+	uint32_t irq_status = 0;
+
+	if (!data) {
+		pr_err("Invalid cam_dev_info or query_cap args\n");
+		return IRQ_HANDLED;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	hw_info = core_info->a5_hw_info;
+
+	irq_status = cam_io_r_mb(soc_info->reg_map[A5_SIERRA_BASE].mem_base +
+				core_info->a5_hw_info->a5_host_int_status);
+
+	cam_io_w_mb(irq_status,
+			soc_info->reg_map[A5_SIERRA_BASE].mem_base +
+			core_info->a5_hw_info->a5_host_int_clr);
+
+	pr_debug("irq_status = %x\n", irq_status);
+	if (irq_status & A5_HOST_INT)
+		pr_debug("A5 to Host interrupt, read msg Q\n");
+
+	if ((irq_status & A5_WDT_0) ||
+		(irq_status & A5_WDT_1)) {
+		pr_err_ratelimited("watch dog interrupt from A5\n");
+	}
+
+	if (core_info->irq_cb.icp_hw_mgr_cb)
+		core_info->irq_cb.icp_hw_mgr_cb(irq_status,
+					core_info->irq_cb.data);
+	return IRQ_HANDLED;
+}
+
+int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (cmd_type >= CAM_ICP_A5_CMD_MAX) {
+		pr_err("Invalid command : %x\n", cmd_type);
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	hw_info = core_info->a5_hw_info;
+
+	switch (cmd_type) {
+	case CAM_ICP_A5_CMD_FW_DOWNLOAD:
+		rc = cam_a5_download_fw(device_priv);
+
+		break;
+	case CAM_ICP_A5_CMD_SET_FW_BUF: {
+		struct cam_icp_a5_set_fw_buf_info *fw_buf_info = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		core_info->fw_buf = fw_buf_info->iova;
+		core_info->fw_kva_addr = fw_buf_info->kva;
+		core_info->fw_buf_len = fw_buf_info->len;
+
+		pr_debug("fw buf info = %x %llx %lld\n", core_info->fw_buf,
+			core_info->fw_kva_addr, core_info->fw_buf_len);
+		break;
+	}
+	case CAM_ICP_A5_SET_IRQ_CB: {
+		struct cam_icp_a5_set_irq_cb *irq_cb = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		core_info->irq_cb.icp_hw_mgr_cb = irq_cb->icp_hw_mgr_cb;
+		core_info->irq_cb.data = irq_cb->data;
+		break;
+	}
+
+	case CAM_ICP_A5_SEND_INIT:
+		hfi_send_system_cmd(HFI_CMD_SYS_INIT, 0, 0);
+		break;
+	case CAM_ICP_A5_CMD_VOTE_CPAS: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		cam_a5_cpas_vote(core_info, cpas_vote);
+		break;
+	}
+
+	case CAM_ICP_A5_CMD_CPAS_START: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		rc = cam_cpas_start(core_info->cpas_handle,
+				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		break;
+	}
+
+	case CAM_ICP_A5_CMD_CPAS_STOP:
+		cam_cpas_stop(core_info->cpas_handle);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
new file mode 100644
index 0000000..8b84270
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
@@ -0,0 +1,87 @@
+/* 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_A5_CORE_H
+#define CAM_A5_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include "cam_a5_hw_intf.h"
+
+#define A5_QGIC_BASE            0
+#define A5_SIERRA_BASE          1
+#define A5_CSR_BASE             2
+
+#define A5_HOST_INT             0x1
+#define A5_WDT_0                0x10
+#define A5_WDT_1                0x100
+
+#define ELF_GUARD_PAGE          (2 * 1024 * 1024)
+
+struct cam_a5_device_hw_info {
+	uint32_t hw_ver;
+	uint32_t nsec_reset;
+	uint32_t a5_control;
+	uint32_t a5_host_int_en;
+	uint32_t a5_host_int;
+	uint32_t a5_host_int_clr;
+	uint32_t a5_host_int_status;
+	uint32_t a5_host_int_set;
+	uint32_t host_a5_int;
+	uint32_t fw_version;
+	uint32_t init_req;
+	uint32_t init_response;
+	uint32_t shared_mem_ptr;
+	uint32_t shared_mem_size;
+	uint32_t qtbl_ptr;
+	uint32_t uncached_heap_ptr;
+	uint32_t uncached_heap_size;
+	uint32_t a5_status;
+};
+
+/**
+ * struct cam_a5_device_hw_info
+ * @a5_hw_info: A5 hardware info
+ * @fw_elf: start address of fw start with elf header
+ * @fw: start address of fw blob
+ * @fw_buf: smmu alloc/mapped fw buffer
+ * @fw_buf_len: fw buffer length
+ * @query_cap: A5 query info from firmware
+ * @a5_acquire: Acquire information of A5
+ * @irq_cb: IRQ callback
+ * @cpas_handle: CPAS handle for A5
+ */
+struct cam_a5_device_core_info {
+	struct cam_a5_device_hw_info *a5_hw_info;
+	const struct firmware *fw_elf;
+	void *fw;
+	uint32_t fw_buf;
+	uint64_t fw_kva_addr;
+	uint64_t fw_buf_len;
+	struct cam_icp_a5_query_cap query_cap;
+	struct cam_icp_a5_acquire_dev a5_acquire[8];
+	struct cam_icp_a5_set_irq_cb irq_cb;
+	uint32_t cpas_handle;
+};
+
+int cam_a5_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_a5_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+
+irqreturn_t cam_a5_irq(int irq_num, void *data);
+#endif /* CAM_A5_CORE_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_dev.c
new file mode 100644
index 0000000..f649c3b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_dev.c
@@ -0,0 +1,197 @@
+/* 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/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include "a5_core.h"
+#include "a5_soc.h"
+#include "cam_io_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_a5_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+struct a5_soc_info cam_a5_soc_info;
+EXPORT_SYMBOL(cam_a5_soc_info);
+
+struct cam_a5_device_hw_info cam_a5_hw_info = {
+	.hw_ver = 0x0,
+	.nsec_reset = 0x4,
+	.a5_control = 0x8,
+	.a5_host_int_en = 0x10,
+	.a5_host_int = 0x14,
+	.a5_host_int_clr = 0x18,
+	.a5_host_int_status = 0x1c,
+	.a5_host_int_set = 0x20,
+	.host_a5_int = 0x30,
+	.fw_version = 0x44,
+	.init_req = 0x48,
+	.init_response = 0x4c,
+	.shared_mem_ptr = 0x50,
+	.shared_mem_size = 0x54,
+	.qtbl_ptr = 0x58,
+	.uncached_heap_ptr = 0x5c,
+	.uncached_heap_size = 0x60,
+	.a5_status = 0x200,
+};
+EXPORT_SYMBOL(cam_a5_hw_info);
+
+int cam_a5_register_cpas(struct cam_hw_soc_info *soc_info,
+			struct cam_a5_device_core_info *core_info,
+			uint32_t hw_idx)
+{
+	struct cam_cpas_register_params cpas_register_params;
+	int rc;
+
+	cpas_register_params.dev = &soc_info->pdev->dev;
+	memcpy(cpas_register_params.identifier, "icp", sizeof("icp"));
+	cpas_register_params.cam_cpas_client_cb = NULL;
+	cpas_register_params.cell_index = hw_idx;
+	cpas_register_params.userdata = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_params);
+	if (rc < 0) {
+		pr_err("cam_cpas_register_client is failed: %d\n", rc);
+		return rc;
+	}
+
+	core_info->cpas_handle = cpas_register_params.client_handle;
+	return rc;
+}
+
+int cam_a5_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct cam_hw_info *a5_dev = NULL;
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	const struct of_device_id *match_dev = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+
+	a5_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!a5_dev_intf)
+		return -ENOMEM;
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &a5_dev_intf->hw_idx);
+
+	a5_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!a5_dev) {
+		rc = -ENOMEM;
+		goto a5_dev_alloc_failure;
+	}
+
+	a5_dev->soc_info.pdev = pdev;
+	a5_dev_intf->hw_priv = a5_dev;
+	a5_dev_intf->hw_ops.init = cam_a5_init_hw;
+	a5_dev_intf->hw_ops.deinit = cam_a5_deinit_hw;
+	a5_dev_intf->hw_ops.process_cmd = cam_a5_process_cmd;
+	a5_dev_intf->hw_type = CAM_ICP_DEV_A5;
+
+	pr_debug("%s: type %d index %d\n", __func__,
+		a5_dev_intf->hw_type,
+		a5_dev_intf->hw_idx);
+
+	platform_set_drvdata(pdev, a5_dev_intf);
+
+	a5_dev->core_info = kzalloc(sizeof(struct cam_a5_device_core_info),
+					GFP_KERNEL);
+	if (!a5_dev->core_info) {
+		rc = -ENOMEM;
+		goto core_info_alloc_failure;
+	}
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_err("%s: No a5 hardware info\n", __func__);
+		rc = -EINVAL;
+		goto pr_err;
+	}
+	hw_info = (struct cam_a5_device_hw_info *)match_dev->data;
+	core_info->a5_hw_info = hw_info;
+
+	a5_dev->soc_info.soc_private = &cam_a5_soc_info;
+
+	rc = cam_a5_init_soc_resources(&a5_dev->soc_info, cam_a5_irq,
+		a5_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to init_soc\n", __func__);
+		goto init_soc_failure;
+	}
+
+	pr_debug("cam_a5_init_soc_resources : %pK\n",
+				(void *)&a5_dev->soc_info);
+	rc = cam_a5_register_cpas(&a5_dev->soc_info,
+			core_info, a5_dev_intf->hw_idx);
+	if (rc < 0) {
+		pr_err("a5 cpas registration failed\n");
+		goto cpas_reg_failed;
+	}
+	a5_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&a5_dev->hw_mutex);
+	spin_lock_init(&a5_dev->hw_lock);
+	init_completion(&a5_dev->hw_complete);
+
+	pr_debug("%s: A5%d probe successful\n", __func__,
+		a5_dev_intf->hw_idx);
+	return 0;
+
+cpas_reg_failed:
+init_soc_failure:
+pr_err:
+	kfree(a5_dev->core_info);
+core_info_alloc_failure:
+	kfree(a5_dev);
+a5_dev_alloc_failure:
+	kfree(a5_dev_intf);
+
+	return rc;
+}
+
+static const struct of_device_id cam_a5_dt_match[] = {
+	{
+		.compatible = "qcom,cam_a5",
+		.data = &cam_a5_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_a5_dt_match);
+
+static struct platform_driver cam_a5_driver = {
+	.probe = cam_a5_probe,
+	.driver = {
+		.name = "cam_a5",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_a5_dt_match,
+	},
+};
+
+static int __init cam_a5_init_module(void)
+{
+	return platform_driver_register(&cam_a5_driver);
+}
+
+static void __exit cam_a5_exit_module(void)
+{
+	platform_driver_unregister(&cam_a5_driver);
+}
+
+module_init(cam_a5_init_module);
+module_exit(cam_a5_exit_module);
+MODULE_DESCRIPTION("CAM A5 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
new file mode 100644
index 0000000..641c154
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
@@ -0,0 +1,101 @@
+/* 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/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "a5_soc.h"
+#include "cam_soc_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_a5_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+	const char *fw_name;
+	struct a5_soc_info *camp_a5_soc_info;
+	struct device_node *of_node = NULL;
+	struct platform_device *pdev = NULL;
+
+	pdev = soc_info->pdev;
+	of_node = pdev->dev.of_node;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0) {
+		pr_err("%s: get a5 dt prop is failed\n", __func__);
+		return rc;
+	}
+
+	camp_a5_soc_info = soc_info->soc_private;
+	fw_name = camp_a5_soc_info->fw_name;
+
+	rc = of_property_read_string(of_node, "fw_name", &fw_name);
+	if (rc < 0)
+		pr_err("%s: fw_name read failed\n", __func__);
+
+	return rc;
+}
+
+static int cam_a5_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t a5_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, a5_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t a5_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_a5_get_dt_properties(soc_info);
+	if (rc < 0)
+		return rc;
+
+	rc = cam_a5_request_platform_resource(soc_info, a5_irq_handler,
+		irq_data);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, true);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
+
+int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.h b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.h
new file mode 100644
index 0000000..916143d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.h
@@ -0,0 +1,29 @@
+/* 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_A5_SOC_H
+#define CAM_A5_SOC_H
+
+#include "cam_soc_util.h"
+
+struct a5_soc_info {
+	char *fw_name;
+};
+
+int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t a5_irq_handler, void *irq_data);
+
+int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/Makefile
new file mode 100644
index 0000000..6aeb5f1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/Makefile
@@ -0,0 +1,11 @@
+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/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/bps_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += bps_dev.o bps_core.o bps_soc.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
new file mode 100644
index 0000000..50863a5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "BPS-CORE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include "cam_io_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "bps_core.h"
+#include "bps_soc.h"
+#include "cam_soc_util.h"
+#include "cam_io_util.h"
+#include "cam_bps_hw_intf.h"
+#include "cam_icp_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info,
+			struct cam_icp_cpas_vote *cpas_vote)
+{
+	int rc = 0;
+
+	if (cpas_vote->ahb_vote_valid)
+		rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
+				&cpas_vote->ahb_vote);
+	if (cpas_vote->axi_vote_valid)
+		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
+				&cpas_vote->axi_vote);
+
+	if (rc < 0)
+		pr_err("cpas vote is failed: %d\n", rc);
+
+	return rc;
+}
+
+
+int cam_bps_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *bps_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+
+	rc = cam_cpas_start(core_info->cpas_handle,
+			&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
+	if (rc < 0) {
+		pr_err("cpass start failed: %d\n", rc);
+		return rc;
+	}
+
+	rc = cam_bps_enable_soc_resources(soc_info);
+	if (rc < 0) {
+		pr_err("soc enable is failed\n");
+		rc = cam_cpas_stop(core_info->cpas_handle);
+	}
+
+	return rc;
+}
+
+int cam_bps_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *bps_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	rc = cam_bps_disable_soc_resources(soc_info);
+	if (rc < 0)
+		pr_err("soc enable is failed\n");
+
+	rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc < 0)
+		pr_err("cpas stop is failed: %d\n", rc);
+
+	return rc;
+}
+
+int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *bps_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	struct cam_bps_device_hw_info *hw_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (cmd_type >= CAM_ICP_BPS_CMD_MAX) {
+		pr_err("Invalid command : %x\n", cmd_type);
+		return -EINVAL;
+	}
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+	hw_info = core_info->bps_hw_info;
+
+	switch (cmd_type) {
+	case CAM_ICP_BPS_CMD_VOTE_CPAS: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		cam_bps_cpas_vote(core_info, cpas_vote);
+		break;
+	}
+
+	case CAM_ICP_BPS_CMD_CPAS_START: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		rc = cam_cpas_start(core_info->cpas_handle,
+				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		break;
+	}
+
+	case CAM_ICP_BPS_CMD_CPAS_STOP:
+		cam_cpas_stop(core_info->cpas_handle);
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+irqreturn_t cam_bps_irq(int irq_num, void *data)
+{
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
new file mode 100644
index 0000000..67e1c03
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_BPS_CORE_H
+#define CAM_BPS_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+
+struct cam_bps_device_hw_info {
+	uint32_t reserved;
+};
+
+struct cam_bps_device_core_info {
+	struct cam_bps_device_hw_info *bps_hw_info;
+	uint32_t cpas_handle;
+};
+
+int cam_bps_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_bps_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+
+irqreturn_t cam_bps_irq(int irq_num, void *data);
+#endif /* CAM_BPS_CORE_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_dev.c
new file mode 100644
index 0000000..c3477ee
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_dev.c
@@ -0,0 +1,169 @@
+/* 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/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include "bps_core.h"
+#include "bps_soc.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_io_util.h"
+#include "cam_icp_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_bps_device_hw_info cam_bps_hw_info = {
+	.reserved = 0,
+};
+EXPORT_SYMBOL(cam_bps_hw_info);
+
+int cam_bps_register_cpas(struct cam_hw_soc_info *soc_info,
+			struct cam_bps_device_core_info *core_info,
+			uint32_t hw_idx)
+{
+	struct cam_cpas_register_params cpas_register_params;
+	int rc;
+
+	cpas_register_params.dev = &soc_info->pdev->dev;
+	memcpy(cpas_register_params.identifier, "bps", sizeof("bps"));
+	cpas_register_params.cam_cpas_client_cb = NULL;
+	cpas_register_params.cell_index = hw_idx;
+	cpas_register_params.userdata = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_params);
+	if (rc < 0) {
+		pr_err("cam_cpas_register_client is failed: %d\n", rc);
+		return rc;
+	}
+	core_info->cpas_handle = cpas_register_params.client_handle;
+
+	return rc;
+}
+
+int cam_bps_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info            *bps_dev = NULL;
+	struct cam_hw_intf            *bps_dev_intf = NULL;
+	const struct of_device_id         *match_dev = NULL;
+	struct cam_bps_device_core_info   *core_info = NULL;
+	struct cam_bps_device_hw_info     *hw_info = NULL;
+	int                                rc = 0;
+
+	bps_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!bps_dev_intf)
+		return -ENOMEM;
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &bps_dev_intf->hw_idx);
+
+	bps_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!bps_dev) {
+		kfree(bps_dev_intf);
+		return -ENOMEM;
+	}
+	bps_dev->soc_info.pdev = pdev;
+	bps_dev_intf->hw_priv = bps_dev;
+	bps_dev_intf->hw_ops.init = cam_bps_init_hw;
+	bps_dev_intf->hw_ops.deinit = cam_bps_deinit_hw;
+	bps_dev_intf->hw_ops.process_cmd = cam_bps_process_cmd;
+	bps_dev_intf->hw_type = CAM_ICP_DEV_BPS;
+	platform_set_drvdata(pdev, bps_dev_intf);
+	bps_dev->core_info = kzalloc(sizeof(struct cam_bps_device_core_info),
+					GFP_KERNEL);
+	if (!bps_dev->core_info) {
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		return -ENOMEM;
+	}
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_err("%s: No bps hardware info\n", __func__);
+		kfree(bps_dev->core_info);
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		rc = -EINVAL;
+		return rc;
+	}
+	hw_info = (struct cam_bps_device_hw_info *)match_dev->data;
+	core_info->bps_hw_info = hw_info;
+
+	rc = cam_bps_init_soc_resources(&bps_dev->soc_info, cam_bps_irq,
+		bps_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to init_soc\n", __func__);
+		kfree(bps_dev->core_info);
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		return rc;
+	}
+	pr_debug("cam_bps_init_soc_resources : %pK\n",
+		(void *)&bps_dev->soc_info);
+
+	rc = cam_bps_register_cpas(&bps_dev->soc_info,
+			core_info, bps_dev_intf->hw_idx);
+	if (rc < 0) {
+		kfree(bps_dev->core_info);
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		return rc;
+	}
+	bps_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&bps_dev->hw_mutex);
+	spin_lock_init(&bps_dev->hw_lock);
+	init_completion(&bps_dev->hw_complete);
+	pr_debug("%s: BPS%d probe successful\n", __func__,
+		bps_dev_intf->hw_idx);
+
+	return rc;
+}
+
+static const struct of_device_id cam_bps_dt_match[] = {
+	{
+		.compatible = "qcom,cam_bps",
+		.data = &cam_bps_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_bps_dt_match);
+
+static struct platform_driver cam_bps_driver = {
+	.probe = cam_bps_probe,
+	.driver = {
+		.name = "cam_bps",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_bps_dt_match,
+	},
+};
+
+static int __init cam_bps_init_module(void)
+{
+	return platform_driver_register(&cam_bps_driver);
+}
+
+static void __exit cam_bps_exit_module(void)
+{
+	platform_driver_unregister(&cam_bps_driver);
+}
+
+module_init(cam_bps_init_module);
+module_exit(cam_bps_exit_module);
+MODULE_DESCRIPTION("CAM BPS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.c
new file mode 100644
index 0000000..76884bf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.c
@@ -0,0 +1,85 @@
+/* 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/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "bps_soc.h"
+#include "cam_soc_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_bps_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0)
+		pr_err("get bps dt prop is failed\n");
+
+	return rc;
+}
+
+static int cam_bps_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t bps_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, bps_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t bps_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_bps_get_dt_properties(soc_info);
+	if (rc < 0)
+		return rc;
+
+	rc = cam_bps_request_platform_resource(soc_info, bps_irq_handler,
+		irq_data);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, false);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
+
+int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, false);
+	if (rc)
+		pr_err("%s: disable platform failed\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.h b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.h
new file mode 100644
index 0000000..b16db01
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.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_BPS_SOC_H_
+#define _CAM_BPS_SOC_H_
+
+#include "cam_soc_util.h"
+
+int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t bps_irq_handler, void *irq_data);
+
+int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* _CAM_BPS_SOC_H_*/
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/Makefile
new file mode 100644
index 0000000..4a6c3c0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/Makefile
@@ -0,0 +1,16 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/isp/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/isp/isp_hw/hw_utils/include
+ccflags-y += -Idrivers/media/platform/msm/camera/isp/isp_hw/isp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+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_req_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/a5_hw/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
new file mode 100644
index 0000000..489ded1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -0,0 +1,2007 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "ICP-HW-MGR %s:%d " fmt, __func__, __LINE__
+
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_sync_api.h"
+#include "cam_hw.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_icp_hw_mgr.h"
+#include "cam_a5_hw_intf.h"
+#include "cam_bps_hw_intf.h"
+#include "cam_ipe_hw_intf.h"
+#include "cam_smmu_api.h"
+#include "cam_mem_mgr.h"
+#include "hfi_intf.h"
+#include "hfi_reg.h"
+#include "hfi_session_defs.h"
+#include "hfi_sys_defs.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_mem_mgr.h"
+#include "a5_core.h"
+#include "hfi_sys_defs.h"
+
+#undef  ICP_DBG
+#define ICP_DBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define ICP_WORKQ_NUM_TASK 30
+#define ICP_WORKQ_TASK_CMD_TYPE 1
+#define ICP_WORKQ_TASK_MSG_TYPE 2
+
+static struct cam_icp_hw_mgr icp_hw_mgr;
+
+static int cam_icp_stop_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
+{
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!hw_mgr) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+
+	if ((!a5_dev_intf) || (!bps_dev_intf) || (!ipe0_dev_intf)) {
+		pr_err("dev intfs are NULL\n");
+		return -EINVAL;
+	}
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_A5_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_BPS_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_IPE_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	if (!ipe1_dev_intf)
+		return rc;
+
+	rc = ipe1_dev_intf->hw_ops.process_cmd(
+		ipe1_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_IPE_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	return rc;
+}
+
+static int cam_icp_start_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
+{
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!hw_mgr) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+
+	if ((!a5_dev_intf) || (!bps_dev_intf) || (!ipe0_dev_intf)) {
+		pr_err("dev intfs are null\n");
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = 640000000;
+	cpas_vote.axi_vote.uncompressed_bw = 640000000;
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc) {
+		pr_err("CAM_ICP_A5_CMD_CPAS_START is failed: %d\n", rc);
+		goto a5_cpas_start_failed;
+	}
+
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0) {
+		pr_err("CAM_ICP_BPS_CMD_CPAS_START is failed: %d\n", rc);
+		goto bps_cpas_start_failed;
+	}
+
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0) {
+		pr_err("CAM_ICP_IPE_CMD_CPAS_START is failed: %d\n", rc);
+		goto ipe0_cpas_start_failed;
+	}
+
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	if (!ipe1_dev_intf)
+		return rc;
+
+	rc = ipe1_dev_intf->hw_ops.process_cmd(
+		ipe1_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0) {
+		pr_err("CAM_ICP_IPE_CMD_CPAS_START is failed: %d\n", rc);
+		goto ipe1_cpas_start_failed;
+	}
+
+	return rc;
+
+ipe1_cpas_start_failed:
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+ipe0_cpas_start_failed:
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+bps_cpas_start_failed:
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+a5_cpas_start_failed:
+	return rc;
+}
+
+static int cam_icp_mgr_process_cmd(void *priv, void *data)
+{
+	int rc;
+	struct hfi_cmd_work_data *task_data = NULL;
+	struct cam_icp_hw_mgr *hw_mgr;
+
+	if (!data || !priv) {
+		pr_err("Invalid params%pK %pK\n", data, priv);
+		return -EINVAL;
+	}
+
+	hw_mgr = priv;
+	task_data = (struct hfi_cmd_work_data *)data;
+
+	rc = hfi_write_cmd(task_data->data);
+	if (rc < 0)
+		pr_err("unable to write\n");
+
+	ICP_DBG("task type : %u, rc : %d\n", task_data->type, rc);
+	return rc;
+}
+
+static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr)
+{
+	int i;
+	uint32_t idx;
+	uint32_t request_id;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct hfi_msg_frame_process_done *frame_done;
+	struct hfi_frame_process_info *hfi_frame_process;
+	struct cam_hw_done_event_data   buf_data;
+
+	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+	if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
+		pr_err("failed with error : %u\n", ioconfig_ack->err_type);
+		return -EIO;
+	}
+
+	frame_done =
+		(struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data;
+	if (frame_done->result) {
+		pr_err("result : %u\n", frame_done->result);
+		return -EIO;
+	}
+	ICP_DBG("result : %u\n", frame_done->result);
+
+	ctx_data = (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+	request_id = ioconfig_ack->user_data2;
+	ICP_DBG("ctx : %pK, request_id :%d\n",
+		(void *)ctx_data->context_priv, request_id);
+
+	hfi_frame_process = &ctx_data->hfi_frame_process;
+	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
+		if (hfi_frame_process->request_id[i] == request_id)
+			break;
+
+	if (i >= CAM_FRAME_CMD_MAX) {
+		pr_err("unable to find pkt in ctx data for req_id =%d\n",
+			request_id);
+		return -EINVAL;
+	}
+	idx = i;
+
+	/* send event to ctx this needs to be done in msg handler */
+	buf_data.num_handles = hfi_frame_process->num_out_resources[idx];
+	for (i = 0; i < buf_data.num_handles; i++)
+		buf_data.resource_handle[i] =
+			hfi_frame_process->out_resource[idx][i];
+
+	ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data);
+
+	/* now release memory for hfi frame process command */
+	ICP_DBG("matching request id: %d\n",
+			hfi_frame_process->request_id[idx]);
+	mutex_lock(&ctx_data->hfi_frame_process.lock);
+	hfi_frame_process->request_id[idx] = 0;
+	clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
+	mutex_unlock(&ctx_data->hfi_frame_process.lock);
+	return 0;
+}
+
+static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr)
+{
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct hfi_msg_ipe_config *ipe_config_ack = NULL;
+	struct hfi_msg_bps_common *bps_config_ack = NULL;
+
+	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+	ICP_DBG("opcode : %u\n", ioconfig_ack->opcode);
+
+	if (ioconfig_ack->opcode == HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO) {
+		ipe_config_ack =
+			(struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data);
+		if (ipe_config_ack->rc) {
+			pr_err("rc = %d err = %u\n",
+				ipe_config_ack->rc, ioconfig_ack->err_type);
+			return -EIO;
+		}
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+		mutex_lock(&ctx_data->ctx_mutex);
+		ctx_data->scratch_mem_size = ipe_config_ack->scratch_mem_size;
+		mutex_unlock(&ctx_data->ctx_mutex);
+		ICP_DBG("scratch_mem_size = %u\n",
+			ipe_config_ack->scratch_mem_size);
+	} else {
+		bps_config_ack =
+			(struct hfi_msg_bps_common *)(ioconfig_ack->msg_data);
+		if (bps_config_ack->rc) {
+			pr_err("rc : %u, opcode :%u\n",
+				bps_config_ack->rc, ioconfig_ack->opcode);
+			return -EIO;
+		}
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+	}
+	complete(&ctx_data->wait_complete);
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_msg_create_handle(uint32_t *msg_ptr)
+{
+	struct hfi_msg_create_handle_ack *create_handle_ack = NULL;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+
+	create_handle_ack = (struct hfi_msg_create_handle_ack *)msg_ptr;
+	if (!create_handle_ack) {
+		pr_err("Invalid create_handle_ack\n");
+		return -EINVAL;
+	}
+
+	ICP_DBG("err type : %u\n", create_handle_ack->err_type);
+
+	ctx_data = (struct cam_icp_hw_ctx_data *)create_handle_ack->user_data1;
+	if (!ctx_data) {
+		pr_err("Invalid ctx_data\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx_data->ctx_mutex);
+	ctx_data->fw_handle = create_handle_ack->fw_handle;
+	mutex_unlock(&ctx_data->ctx_mutex);
+	ICP_DBG("fw_handle = %x\n", ctx_data->fw_handle);
+	complete(&ctx_data->wait_complete);
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_msg_ping_ack(uint32_t *msg_ptr)
+{
+	struct hfi_msg_ping_ack *ping_ack = NULL;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+
+	ping_ack = (struct hfi_msg_ping_ack *)msg_ptr;
+	if (!ping_ack) {
+		pr_err("Empty ping ack message\n");
+		return -EINVAL;
+	}
+
+	ctx_data = (struct cam_icp_hw_ctx_data *)ping_ack->user_data;
+	if (!ctx_data) {
+		pr_err("Invalid ctx_data\n");
+		return -EINVAL;
+	}
+
+	ICP_DBG("%x %x %pK\n", ping_ack->size, ping_ack->pkt_type,
+		(void *)ping_ack->user_data);
+	complete(&ctx_data->wait_complete);
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_indirect_ack_msg(uint32_t *msg_ptr)
+{
+	int rc;
+
+	switch (msg_ptr[ICP_PACKET_IPCODE]) {
+	case HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO:
+	case HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO:
+		ICP_DBG("received HFI_IPEBPS_CMD_OPCODE_IPE/BPS_CONFIG_IO:\n");
+		rc = cam_icp_mgr_process_msg_config_io(msg_ptr);
+		if (rc < 0) {
+			pr_err("error in process_msg_config_io\n");
+			return rc;
+		}
+		break;
+
+	case HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS:
+	case HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS:
+		ICP_DBG("received OPCODE_IPE/BPS_FRAME_PROCESS:\n");
+		rc = cam_icp_mgr_process_msg_frame_process(msg_ptr);
+		if (rc < 0) {
+			pr_err("error in msg_frame_process\n");
+			return rc;
+		}
+		break;
+	default:
+		pr_err("Invalid opcode : %u\n",
+			msg_ptr[ICP_PACKET_IPCODE]);
+		break;
+	}
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr)
+{
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+
+	if (msg_ptr[ICP_PACKET_IPCODE] ==
+		HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY ||
+		msg_ptr[ICP_PACKET_IPCODE] ==
+		HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY) {
+		ICP_DBG("received HFI_IPEBPS_CMD_OPCODE_IPE/BPS_DESTROY:\n");
+		ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+		complete(&ctx_data->wait_complete);
+
+	} else {
+		pr_err("Invalid opcode : %u\n", msg_ptr[ICP_PACKET_IPCODE]);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int32_t cam_icp_mgr_process_msg(void *priv, void *data)
+{
+	int rc = 0;
+	uint32_t *msg_ptr = NULL;
+	struct hfi_msg_work_data *task_data;
+	struct cam_icp_hw_mgr *hw_mgr;
+	int read_len;
+
+	if (!data || !priv) {
+		pr_err("Invalid data\n");
+		return -EINVAL;
+	}
+
+	task_data = data;
+	hw_mgr = priv;
+	ICP_DBG("irq status : %u\n", task_data->irq_status);
+
+	read_len = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG);
+	if (read_len < 0) {
+		ICP_DBG("Unable to read msg q\n");
+		return read_len;
+	}
+
+	msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
+	ICP_DBG("packet type: %x\n", msg_ptr[ICP_PACKET_TYPE]);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	switch (msg_ptr[ICP_PACKET_TYPE]) {
+	case HFI_MSG_SYS_INIT_DONE:
+		ICP_DBG("received HFI_MSG_SYS_INIT_DONE\n");
+		complete(&hw_mgr->a5_complete);
+		break;
+
+	case HFI_MSG_SYS_PING_ACK:
+		ICP_DBG("received HFI_MSG_SYS_PING_ACK\n");
+		rc = cam_icp_mgr_process_msg_ping_ack(msg_ptr);
+		if (rc)
+			pr_err("fail process PING_ACK\n");
+		break;
+
+	case HFI_MSG_IPEBPS_CREATE_HANDLE_ACK:
+		ICP_DBG("received HFI_MSG_IPEBPS_CREATE_HANDLE_ACK\n");
+		rc = cam_icp_mgr_process_msg_create_handle(msg_ptr);
+		if (rc)
+			pr_err("fail process CREATE_HANDLE_ACK\n");
+		break;
+
+	case HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK:
+		rc = cam_icp_mgr_process_indirect_ack_msg(msg_ptr);
+		if (rc)
+			pr_err("fail process INDIRECT_ACK\n");
+		break;
+
+	case  HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK:
+		rc = cam_icp_mgr_process_direct_ack_msg(msg_ptr);
+		if (rc)
+			pr_err("fail process DIRECT_ACK\n");
+		break;
+
+	case HFI_MSG_EVENT_NOTIFY:
+		ICP_DBG("received HFI_MSG_EVENT_NOTIFY\n");
+		break;
+
+	default:
+		pr_err("invalid msg : %u\n", msg_ptr[ICP_PACKET_TYPE]);
+		break;
+	}
+
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	return rc;
+}
+
+int32_t cam_icp_hw_mgr_cb(uint32_t irq_status, void *data)
+{
+	int32_t rc = 0;
+	unsigned long flags;
+	struct cam_icp_hw_mgr *hw_mgr = data;
+	struct crm_workq_task *task;
+	struct hfi_msg_work_data *task_data;
+
+	spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work);
+	if (!task) {
+		pr_err("no empty task\n");
+		spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags);
+		return -ENOMEM;
+	}
+
+	task_data = (struct hfi_msg_work_data *)task->payload;
+	task_data->data = hw_mgr;
+	task_data->irq_status = irq_status;
+	task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
+	task->process_cb = cam_icp_mgr_process_msg;
+	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+		CRM_TASK_PRIORITY_0);
+	spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags);
+
+	return rc;
+}
+
+static int cam_icp_free_hfi_mem(void)
+{
+	cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sec_heap);
+
+	return 0;
+}
+
+static int cam_icp_allocate_hfi_mem(void)
+{
+	int rc;
+	struct cam_mem_mgr_request_desc alloc;
+	struct cam_mem_mgr_memory_desc out;
+	dma_addr_t iova;
+	uint64_t kvaddr;
+	size_t len;
+
+	pr_err("Allocating FW for iommu handle: %x\n", icp_hw_mgr.iommu_hdl);
+	rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl,
+		&iova, &kvaddr, &len);
+	if (rc < 0) {
+		pr_err("Unable to allocate FW memory\n");
+		return -ENOMEM;
+	}
+
+	icp_hw_mgr.hfi_mem.fw_buf.len = len;
+	icp_hw_mgr.hfi_mem.fw_buf.kva = kvaddr;
+	icp_hw_mgr.hfi_mem.fw_buf.iova = iova;
+	icp_hw_mgr.hfi_mem.fw_buf.smmu_hdl = icp_hw_mgr.iommu_hdl;
+
+	ICP_DBG("kva = %llX\n", kvaddr);
+	ICP_DBG("IOVA = %llX\n", iova);
+	ICP_DBG("length = %zu\n", len);
+
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate qtbl memory\n");
+		goto qtbl_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.qtbl = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("qtbl IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for cmd queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate cmd q memory\n");
+		goto cmd_q_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.cmd_q = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("cmd_q IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for msg queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate msg q memory\n");
+		goto msg_q_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.msg_q = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("msg_q IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for dbg queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate dbg q memory\n");
+		goto dbg_q_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.dbg_q = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("dbg_q IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n",  out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for sec heap queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate sec heap q memory\n");
+		goto sec_heap_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.sec_heap = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("sec_heap IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	return rc;
+
+sec_heap_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
+dbg_q_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
+msg_q_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
+cmd_q_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
+qtbl_alloc_failed:
+	cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
+	pr_err("returned with error : %d\n", rc);
+
+	return rc;
+}
+
+static int cam_icp_mgr_get_free_ctx(struct cam_icp_hw_mgr *hw_mgr)
+{
+	int i = 0;
+	int num_ctx = CAM_ICP_CTX_MAX;
+
+	for (i = 0; i < num_ctx; i++) {
+		mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex);
+		if (hw_mgr->ctx_data[i].in_use == 0) {
+			hw_mgr->ctx_data[i].in_use = 1;
+			mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex);
+			break;
+		}
+		mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex);
+	}
+
+	return i;
+}
+
+static int cam_icp_mgr_destroy_handle(
+		struct cam_icp_hw_ctx_data *ctx_data,
+		struct crm_workq_task *task)
+{
+	int rc = 0;
+	int timeout = 5000;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async destroy_cmd;
+	unsigned long rem_jiffies;
+
+	destroy_cmd.size =
+		sizeof(struct hfi_cmd_ipebps_async) +
+		sizeof(struct ipe_bps_destroy) -
+		sizeof(destroy_cmd.payload.direct);
+	destroy_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
+	if (ctx_data->icp_dev_acquire_info.dev_type == CAM_ICP_RES_TYPE_BPS)
+		destroy_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY;
+	else
+		destroy_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY;
+
+	reinit_completion(&ctx_data->wait_complete);
+	destroy_cmd.num_fw_handles = 1;
+	destroy_cmd.fw_handles[0] = ctx_data->fw_handle;
+	destroy_cmd.user_data1 = (uint64_t)ctx_data;
+	destroy_cmd.user_data2 = (uint64_t)0x0;
+	memcpy(destroy_cmd.payload.direct, &ctx_data->temp_payload,
+						sizeof(uint32_t));
+
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&destroy_cmd;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	ICP_DBG("fw_handle = %x ctx_data = %pK\n",
+		ctx_data->fw_handle, ctx_data);
+	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+			msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		pr_err("timeout/err in iconfig command: %d\n", rc);
+	}
+
+	return rc;
+}
+
+static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id)
+{
+	struct crm_workq_task *task;
+	int i = 0;
+
+	if (ctx_id >= CAM_ICP_CTX_MAX) {
+		pr_err("ctx_id is wrong: %d\n", ctx_id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	if (!hw_mgr->ctx_data[ctx_id].in_use) {
+		pr_err("ctx is already in use: %d\n", ctx_id);
+		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (task)
+		cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id], task);
+
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	hw_mgr->ctx_data[ctx_id].in_use = 0;
+	hw_mgr->ctx_data[ctx_id].fw_handle = 0;
+	hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0;
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
+	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
+		clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
+	mutex_destroy(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+
+	return 0;
+}
+
+static int cam_icp_mgr_get_ctx_from_fw_handle(struct cam_icp_hw_mgr *hw_mgr,
+							uint32_t fw_handle)
+{
+	int ctx_id;
+
+	for (ctx_id = 0; ctx_id < CAM_ICP_CTX_MAX; ctx_id++) {
+		mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+		if (hw_mgr->ctx_data[ctx_id].in_use) {
+			if (hw_mgr->ctx_data[ctx_id].fw_handle == fw_handle) {
+				mutex_unlock(
+					&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+				return ctx_id;
+			}
+		}
+		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	}
+	ICP_DBG("Invalid fw handle to get ctx\n");
+
+	return -EINVAL;
+}
+
+static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)
+{
+	struct cam_icp_hw_mgr *hw_mgr = hw_priv;
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	int rc = 0;
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+	if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) {
+		pr_err("dev intfs are wrong\n");
+		return rc;
+	}
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	rc = a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0)
+		pr_err("a5 dev de-init failed\n");
+
+	rc = bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0)
+		pr_err("bps dev de-init failed\n");
+
+	rc = ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0)
+		pr_err("ipe0 dev de-init failed\n");
+
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	if (ipe1_dev_intf) {
+		rc = ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+						NULL, 0);
+		if (rc < 0)
+			pr_err("ipe1 dev de-init failed\n");
+	}
+
+	cam_icp_free_hfi_mem();
+	hw_mgr->fw_download = false;
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	return 0;
+}
+
+static int cam_icp_mgr_download_fw(void *hw_mgr_priv, void *download_fw_args)
+{
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	struct cam_hw_info *a5_dev = NULL;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_a5_set_irq_cb irq_cb;
+	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
+	struct hfi_mem_info hfi_mem;
+	int rc = 0;
+
+	if (!hw_mgr) {
+		pr_err("hw_mgr is NULL\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	if (hw_mgr->fw_download) {
+		ICP_DBG("FW already downloaded\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return rc;
+	}
+
+	/* Allocate memory for FW and shared memory */
+	rc = cam_icp_allocate_hfi_mem();
+	if (rc < 0) {
+		pr_err("hfi mem alloc failed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return rc;
+	}
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+	if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) {
+		pr_err("dev intfs are wrong\n");
+		goto dev_intf_fail;
+	}
+
+	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
+
+	rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0) {
+		pr_err("a5 dev init failed\n");
+		goto a5_dev_init_failed;
+	}
+	rc = bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0) {
+		pr_err("bps dev init failed\n");
+		goto bps_dev_init_failed;
+	}
+	rc = ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0) {
+		pr_err("ipe0 dev init failed\n");
+		goto ipe0_dev_init_failed;
+	}
+
+	if (ipe1_dev_intf) {
+		rc = ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
+						NULL, 0);
+		if (rc < 0) {
+			pr_err("ipe1 dev init failed\n");
+			goto ipe1_dev_init_failed;
+		}
+	}
+	/* Set IRQ callback */
+	irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb;
+	irq_cb.data = hw_mgr_priv;
+	rc = a5_dev_intf->hw_ops.process_cmd(
+				a5_dev_intf->hw_priv,
+				CAM_ICP_A5_SET_IRQ_CB,
+				&irq_cb, sizeof(irq_cb));
+	if (rc < 0) {
+		pr_err("CAM_ICP_A5_SET_IRQ_CB failed\n");
+		rc = -EINVAL;
+		goto set_irq_failed;
+	}
+
+	fw_buf_info.kva = icp_hw_mgr.hfi_mem.fw_buf.kva;
+	fw_buf_info.iova = icp_hw_mgr.hfi_mem.fw_buf.iova;
+	fw_buf_info.len = icp_hw_mgr.hfi_mem.fw_buf.len;
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+			a5_dev_intf->hw_priv,
+			CAM_ICP_A5_CMD_SET_FW_BUF,
+			&fw_buf_info,
+			sizeof(fw_buf_info));
+	if (rc < 0) {
+		pr_err("CAM_ICP_A5_CMD_SET_FW_BUF failed\n");
+		goto set_irq_failed;
+	}
+
+	cam_hfi_enable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+			a5_dev_intf->hw_priv,
+			CAM_ICP_A5_CMD_FW_DOWNLOAD,
+			NULL, 0);
+	if (rc < 0) {
+		pr_err("FW download is failed\n");
+		goto set_irq_failed;
+	}
+
+	hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva;
+	hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova;
+	hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.qtbl.kva);
+	ICP_DBG("IOVA = %X\n", hfi_mem.qtbl.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.qtbl.len);
+
+	hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva;
+	hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova;
+	hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.cmd_q.kva);
+	ICP_DBG("IOVA = %X\n", hfi_mem.cmd_q.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.cmd_q.len);
+
+	hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva;
+	hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova;
+	hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.msg_q.kva);
+	ICP_DBG("IOVA = %X\n", hfi_mem.msg_q.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.msg_q.len);
+
+	hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva;
+	hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova;
+	hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.dbg_q.kva);
+	ICP_DBG("IOVA = %X\n",  hfi_mem.dbg_q.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.dbg_q.len);
+
+	hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva;
+	hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova;
+	hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len;
+
+	rc = cam_hfi_init(0, &hfi_mem,
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
+		false);
+	if (rc < 0) {
+		pr_err("hfi_init is failed\n");
+		goto set_irq_failed;
+	}
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	ICP_DBG("Sending HFI init command\n");
+	reinit_completion(&hw_mgr->a5_complete);
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_SEND_INIT,
+		NULL, 0);
+
+	ICP_DBG("Wait for INIT DONE Message\n");
+	wait_for_completion(&hw_mgr->a5_complete);
+
+	ICP_DBG("Done Waiting for INIT DONE Message\n");
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_POWER_COLLAPSE,
+		NULL, 0);
+
+	hw_mgr->fw_download = true;
+
+	rc = cam_icp_stop_cpas(hw_mgr);
+	if (rc) {
+		pr_err("cpas stop failed\n");
+		goto set_irq_failed;
+	}
+
+	hw_mgr->ctxt_cnt = 0;
+
+	return rc;
+
+set_irq_failed:
+	if (ipe1_dev_intf)
+		rc = ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+			NULL, 0);
+ipe1_dev_init_failed:
+	rc = ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+ipe0_dev_init_failed:
+	rc = bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+bps_dev_init_failed:
+	rc = a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+a5_dev_init_failed:
+dev_intf_fail:
+	cam_icp_free_hfi_mem();
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	return rc;
+}
+
+static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
+{
+	int rc = 0;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_config_args *config_args = config_hw_args;
+	uint32_t fw_handle;
+	int ctx_id = 0;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	int32_t request_id = 0;
+	struct cam_hw_update_entry *hw_update_entries;
+	struct crm_workq_task *task;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async *hfi_cmd;
+
+	if (!hw_mgr || !config_args) {
+		pr_err("Invalid arguments %pK %pK\n",
+			hw_mgr, config_args);
+		return -EINVAL;
+	}
+
+	if (!config_args->num_hw_update_entries) {
+		pr_err("No hw update enteries are available\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	fw_handle = *(uint32_t *)config_args->ctxt_to_hw_map;
+	ctx_id = cam_icp_mgr_get_ctx_from_fw_handle(hw_mgr, fw_handle);
+	if (ctx_id < 0) {
+		pr_err("Fw handle to ctx mapping is failed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	ctx_data = &hw_mgr->ctx_data[ctx_id];
+	if (!ctx_data->in_use) {
+		pr_err("ctx is not in use\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	request_id = *(uint32_t *)config_args->priv;
+	hw_update_entries = config_args->hw_update_entries;
+	ICP_DBG("req_id = %d\n", request_id);
+	ICP_DBG("fw_handle = %x req_id = %d %pK\n",
+		fw_handle, request_id, config_args->priv);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no empty task\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -ENOMEM;
+	}
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	if (!task_data) {
+		pr_err("task_data is NULL\n");
+		return -EINVAL;
+	}
+
+	task_data->data = (void *)hw_update_entries->addr;
+	hfi_cmd = (struct hfi_cmd_ipebps_async *)hw_update_entries->addr;
+	ICP_DBG("request from hfi_cmd :%llu, hfi_cmd: %pK\n",
+		hfi_cmd->user_data2, hfi_cmd);
+	task_data->request_id = request_id;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+			CRM_TASK_PRIORITY_0);
+	return rc;
+}
+
+static int cam_icp_mgr_prepare_frame_process_cmd(
+			struct cam_icp_hw_ctx_data *ctx_data,
+			struct hfi_cmd_ipebps_async *hfi_cmd,
+			uint32_t request_id,
+			uint32_t fw_cmd_buf_iova_addr)
+{
+	hfi_cmd->size = sizeof(struct hfi_cmd_ipebps_async);
+	hfi_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+	if (ctx_data->icp_dev_acquire_info.dev_type == CAM_ICP_RES_TYPE_BPS)
+		hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS;
+	else
+		hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS;
+	hfi_cmd->num_fw_handles = 1;
+	hfi_cmd->fw_handles[0] = ctx_data->fw_handle;
+	hfi_cmd->payload.indirect = fw_cmd_buf_iova_addr;
+	hfi_cmd->user_data1 = (uint64_t)ctx_data;
+	hfi_cmd->user_data2 = request_id;
+
+	ICP_DBG("ctx_data : %pK, request_id :%d cmd_buf %x\n",
+		(void *)ctx_data->context_priv,
+		request_id, fw_cmd_buf_iova_addr);
+
+	return 0;
+}
+
+static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv,
+				void *prepare_hw_update_args)
+{
+	int        rc = 0, i, j;
+	int        ctx_id = 0;
+	uint32_t   fw_handle;
+	int32_t    idx;
+	uint64_t   iova_addr, cpu_addr;
+	uint32_t   fw_cmd_buf_iova_addr;
+	uint32_t   temp;
+	uint32_t  *dst_cpu_addr;
+	uint32_t  *src_buf_iova_addr;
+	size_t     fw_cmd_buf_len;
+	size_t     dst_buf_len;
+	size_t     src_buf_size;
+	int32_t    sync_in_obj[CAM_ICP_IPE_IMAGE_MAX];
+	int32_t    merged_sync_in_obj;
+
+
+	struct cam_hw_prepare_update_args *prepare_args =
+		prepare_hw_update_args;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct cam_packet *packet = NULL;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	struct cam_buf_io_cfg *io_cfg_ptr = NULL;
+	struct cam_patch_desc *patch_desc = NULL;
+	struct hfi_cmd_ipebps_async *hfi_cmd = NULL;
+
+	if ((!prepare_args) || (!hw_mgr)) {
+		pr_err("Invalid args\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	fw_handle = *(uint32_t *)prepare_args->ctxt_to_hw_map;
+	ctx_id = cam_icp_mgr_get_ctx_from_fw_handle(hw_mgr, fw_handle);
+	if (ctx_id < 0) {
+		pr_err("Fw handle to ctx mapping is failed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	ctx_data = &hw_mgr->ctx_data[ctx_id];
+	if (!ctx_data->in_use) {
+		pr_err("ctx is not in use\n");
+		return -EINVAL;
+	}
+
+	packet = prepare_args->packet;
+	if (!packet) {
+		pr_err("received packet is NULL\n");
+		return -EINVAL;
+	}
+
+	ICP_DBG("packet header : opcode = %x size = %x",
+			packet->header.op_code,
+			packet->header.size);
+
+	ICP_DBG(" req_id = %x flags = %x\n",
+			(uint32_t)packet->header.request_id,
+			packet->header.flags);
+
+	ICP_DBG("packet data : c_off = %x c_num = %x\n",
+			packet->cmd_buf_offset,
+			packet->num_cmd_buf);
+
+	ICP_DBG("io_off = %x io_num = %x p_off = %x p_num = %x %x %x\n",
+			packet->io_configs_offset,
+			packet->num_io_configs, packet->patch_offset,
+			packet->num_patches, packet->kmd_cmd_buf_index,
+			packet->kmd_cmd_buf_offset);
+
+	if (((packet->header.op_code & 0xff) !=
+		CAM_ICP_OPCODE_IPE_UPDATE) &&
+		((packet->header.op_code & 0xff) !=
+		CAM_ICP_OPCODE_BPS_UPDATE)) {
+		pr_err("Invalid Opcode in pkt: %d\n",
+			packet->header.op_code & 0xff);
+		return -EINVAL;
+	}
+
+	if ((packet->num_cmd_buf > 1) || (!packet->num_patches) ||
+					(!packet->num_io_configs)) {
+		pr_err("wrong number of cmd/patch info: %u %u\n",
+				packet->num_cmd_buf,
+				packet->num_patches);
+		return -EINVAL;
+	}
+
+	/* process command buffer descriptors */
+	cmd_desc = (struct cam_cmd_buf_desc *)
+			((uint32_t *) &packet->payload +
+				packet->cmd_buf_offset/4);
+	ICP_DBG("packet = %pK cmd_desc = %pK size = %lu\n",
+			(void *)packet, (void *)cmd_desc,
+			sizeof(struct cam_cmd_buf_desc));
+
+	rc = cam_mem_get_io_buf(cmd_desc->mem_handle,
+		hw_mgr->iommu_hdl, &iova_addr, &fw_cmd_buf_len);
+	if (rc < 0) {
+		pr_err("unable to get src buf info for cmd buf: %x\n",
+						hw_mgr->iommu_hdl);
+		return rc;
+	}
+	ICP_DBG("cmd_buf desc cpu and iova address: %pK %zu\n",
+				(void *)iova_addr, fw_cmd_buf_len);
+	fw_cmd_buf_iova_addr = iova_addr;
+	fw_cmd_buf_iova_addr = (fw_cmd_buf_iova_addr + cmd_desc->offset);
+
+	/* process patch descriptor */
+	patch_desc = (struct cam_patch_desc *)
+			((uint32_t *) &packet->payload +
+			packet->patch_offset/4);
+	ICP_DBG("packet = %pK patch_desc = %pK size = %lu\n",
+			(void *)packet, (void *)patch_desc,
+			sizeof(struct cam_patch_desc));
+
+	for (i = 0; i < packet->num_patches; i++) {
+		rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl,
+			hw_mgr->iommu_hdl, &iova_addr, &src_buf_size);
+		if (rc < 0) {
+			pr_err("unable to get src buf address\n");
+			return rc;
+		}
+		src_buf_iova_addr = (uint32_t *)iova_addr;
+		temp = iova_addr;
+
+		rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl,
+			&cpu_addr, &dst_buf_len);
+		if (rc < 0) {
+			pr_err("unable to get dst buf address\n");
+			return rc;
+		}
+		dst_cpu_addr = (uint32_t *)cpu_addr;
+
+		ICP_DBG("i = %d patch info = %x %x %x %x\n", i,
+			patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset,
+			patch_desc[i].src_buf_hdl, patch_desc[i].src_offset);
+
+		dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr +
+			patch_desc[i].dst_offset);
+		temp += patch_desc[i].src_offset;
+
+		*dst_cpu_addr = temp;
+
+		ICP_DBG("patch is done for dst %pK with src %pK value %llx\n",
+			dst_cpu_addr, src_buf_iova_addr,
+			*((uint64_t *)dst_cpu_addr));
+	}
+
+	/* process io config out descriptors */
+	io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload +
+				packet->io_configs_offset/4);
+	ICP_DBG("packet = %pK io_cfg_ptr = %pK size = %lu\n",
+			(void *)packet, (void *)io_cfg_ptr,
+			sizeof(struct cam_buf_io_cfg));
+
+	prepare_args->num_out_map_entries = 0;
+	for (i = 0, j = 0; i < packet->num_io_configs; i++) {
+		if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) {
+			ICP_DBG("direction is i : %d :%u\n",
+					i, io_cfg_ptr[i].direction);
+			ICP_DBG("fence is i : %d :%d\n",
+					i, io_cfg_ptr[i].fence);
+			continue;
+		}
+
+		prepare_args->out_map_entries[j].sync_id = io_cfg_ptr[i].fence;
+		prepare_args->out_map_entries[j++].resource_handle =
+							io_cfg_ptr[i].fence;
+		prepare_args->num_out_map_entries++;
+		ICP_DBG(" out fence = %x index = %d\n", io_cfg_ptr[i].fence, i);
+	}
+	ICP_DBG("out buf entries processing is done\n");
+
+	/* process io config in descriptors */
+	for (i = 0, j = 0; i < packet->num_io_configs; i++) {
+		if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) {
+			sync_in_obj[j++] = io_cfg_ptr[i].fence;
+			ICP_DBG(" in fence = %x index = %d\n",
+					io_cfg_ptr[i].fence, i);
+		}
+	}
+
+	if (j == 1)
+		merged_sync_in_obj = sync_in_obj[j - 1];
+	else if (j > 1) {
+		rc = cam_sync_merge(&sync_in_obj[0], j, &merged_sync_in_obj);
+		if (rc < 0) {
+			pr_err("unable to create in merged object: %d\n",
+								rc);
+			return rc;
+		}
+	} else {
+		pr_err("no input fence provided %u\n", j);
+		return -EINVAL;
+	}
+
+	prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj;
+	prepare_args->in_map_entries[0].resource_handle =
+			ctx_data->icp_dev_acquire_info.dev_type;
+	prepare_args->num_in_map_entries = 1;
+	ICP_DBG("out buf entries processing is done\n");
+
+	mutex_lock(&ctx_data->hfi_frame_process.lock);
+	idx = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
+			ctx_data->hfi_frame_process.bits);
+	if (idx < 0 || idx >= CAM_FRAME_CMD_MAX) {
+		pr_err("request idx is wrong: %d\n", idx);
+		mutex_unlock(&ctx_data->hfi_frame_process.lock);
+		return -EINVAL;
+	}
+	set_bit(idx, ctx_data->hfi_frame_process.bitmap);
+	mutex_unlock(&ctx_data->hfi_frame_process.lock);
+
+	ctx_data->hfi_frame_process.request_id[idx] = packet->header.request_id;
+	ICP_DBG("slot[%d]: %d\n", idx,
+		ctx_data->hfi_frame_process.request_id[idx]);
+	ctx_data->hfi_frame_process.num_out_resources[idx] =
+				prepare_args->num_out_map_entries;
+	for (i = 0; i < prepare_args->num_out_map_entries; i++)
+		ctx_data->hfi_frame_process.out_resource[idx][i] =
+			prepare_args->out_map_entries[i].resource_handle;
+
+	hfi_cmd = (struct hfi_cmd_ipebps_async *)
+			&ctx_data->hfi_frame_process.hfi_frame_cmd[idx];
+
+	cam_icp_mgr_prepare_frame_process_cmd(
+			ctx_data, hfi_cmd, packet->header.request_id,
+			fw_cmd_buf_iova_addr);
+
+	prepare_args->num_hw_update_entries = 1;
+	prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
+
+	prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
+
+	ICP_DBG("slot : %d, hfi_cmd : %pK, request : %d\n",	idx,
+		(void *)hfi_cmd,
+		ctx_data->hfi_frame_process.request_id[idx]);
+
+	return rc;
+}
+
+static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args)
+{
+	int rc = 0;
+	int ctx_id = 0;
+	int i;
+	uint32_t fw_handle;
+	struct cam_hw_release_args *release_hw = release_hw_args;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+
+	if (!release_hw || !hw_mgr) {
+		pr_err("Invalid args\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx_data = &hw_mgr->ctx_data[i];
+		ICP_DBG("i = %d in_use = %u fw_handle = %u\n", i,
+				ctx_data->in_use, ctx_data->fw_handle);
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	fw_handle = *(uint32_t *)release_hw->ctxt_to_hw_map;
+	ctx_id = cam_icp_mgr_get_ctx_from_fw_handle(hw_mgr, fw_handle);
+	if (ctx_id < 0) {
+		pr_err("Invalid ctx id\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
+	if (rc) {
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	--hw_mgr->ctxt_cnt;
+	if (!hw_mgr->ctxt_cnt) {
+		ICP_DBG("stop cpas for last context\n");
+		cam_icp_stop_cpas(hw_mgr);
+	}
+	ICP_DBG("context count : %u\n", hw_mgr->ctxt_cnt);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	ICP_DBG("fw handle %d\n", fw_handle);
+	return rc;
+}
+
+static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
+			struct crm_workq_task *task, uint32_t io_buf_addr)
+{
+	int rc = 0;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async ioconfig_cmd;
+
+	ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
+	ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+	if (ctx_data->icp_dev_acquire_info.dev_type == CAM_ICP_RES_TYPE_BPS)
+		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
+	else
+		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
+
+	reinit_completion(&ctx_data->wait_complete);
+	ICP_DBG("Sending HFI_CMD_IPEBPS_ASYNC_COMMAND: opcode :%u\n",
+						ioconfig_cmd.opcode);
+	ioconfig_cmd.num_fw_handles = 1;
+	ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
+	ioconfig_cmd.payload.indirect = io_buf_addr;
+	ioconfig_cmd.user_data1 = (uint64_t)ctx_data;
+	ioconfig_cmd.user_data2 = (uint64_t)0x0;
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&ioconfig_cmd;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	ICP_DBG("fw_hdl = %x ctx_data = %pK\n", ctx_data->fw_handle, ctx_data);
+	wait_for_completion(&ctx_data->wait_complete);
+
+	return rc;
+}
+
+static int cam_icp_mgr_create_handle(uint32_t dev_type,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct crm_workq_task *task)
+{
+	struct hfi_cmd_create_handle create_handle;
+	struct hfi_cmd_work_data *task_data;
+	int rc = 0;
+
+	create_handle.size = sizeof(struct hfi_cmd_create_handle);
+	create_handle.pkt_type = HFI_CMD_IPEBPS_CREATE_HANDLE;
+	create_handle.handle_type = dev_type;
+	create_handle.user_data1 = (uint64_t)ctx_data;
+	ICP_DBG("%x %x %x %pK\n", create_handle.size,	create_handle.pkt_type,
+		create_handle.handle_type, (void *)create_handle.user_data1);
+	ICP_DBG("Sending HFI_CMD_IPEBPS_CREATE_HANDLE\n");
+
+	reinit_completion(&ctx_data->wait_complete);
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&create_handle;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	wait_for_completion(&ctx_data->wait_complete);
+
+	return rc;
+}
+
+static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data,
+	struct crm_workq_task *task)
+{
+	struct hfi_cmd_ping_pkt ping_pkt;
+	struct hfi_cmd_work_data *task_data;
+	int rc = 0;
+
+	ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
+	ping_pkt.pkt_type = HFI_CMD_SYS_PING;
+	ping_pkt.user_data = (uint64_t)ctx_data;
+	ICP_DBG("Sending HFI_CMD_SYS_PING\n");
+	ICP_DBG("%x %x %pK\n", ping_pkt.size,	ping_pkt.pkt_type,
+		(void *)ping_pkt.user_data);
+
+	init_completion(&ctx_data->wait_complete);
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&ping_pkt;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	wait_for_completion(&ctx_data->wait_complete);
+
+	return rc;
+}
+
+static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
+{
+	int rc = 0, i, bitmap_size = 0, tmp_size;
+	uint32_t ctx_id = 0;
+	uint64_t io_buf_addr;
+	size_t io_buf_size;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct cam_hw_acquire_args *args = acquire_hw_args;
+	struct cam_icp_acquire_dev_info icp_dev_acquire_info;
+	struct cam_icp_res_info *p_icp_out = NULL;
+	struct crm_workq_task *task;
+	uint8_t *tmp_acquire;
+
+	if ((!hw_mgr_priv) || (!acquire_hw_args)) {
+		pr_err("Invalid params: %pK %pK\n", hw_mgr_priv,
+			acquire_hw_args);
+		return -EINVAL;
+	}
+
+	if (args->num_acq > 1) {
+		pr_err("number of resources are wrong: %u\n", args->num_acq);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&icp_dev_acquire_info,
+			(void __user *)args->acquire_info,
+			sizeof(icp_dev_acquire_info)))
+		return -EFAULT;
+
+	if (icp_dev_acquire_info.num_out_res > ICP_IPE_MAX_OUTPUT_SUPPORTED) {
+		pr_err("num of out resources exceeding : %u\n",
+			icp_dev_acquire_info.num_out_res);
+		return -EINVAL;
+	}
+
+	ICP_DBG("%x %x %x %x %x %x %x\n",
+		icp_dev_acquire_info.dev_type,
+		icp_dev_acquire_info.in_res.format,
+		icp_dev_acquire_info.in_res.width,
+		icp_dev_acquire_info.in_res.height,
+		icp_dev_acquire_info.in_res.fps,
+		icp_dev_acquire_info.num_out_res,
+		icp_dev_acquire_info.scratch_mem_size);
+
+	tmp_size = sizeof(icp_dev_acquire_info) +
+			icp_dev_acquire_info.num_out_res *
+			sizeof(struct cam_icp_res_info);
+
+	tmp_acquire = kzalloc(tmp_size, GFP_KERNEL);
+	if (!tmp_acquire)
+		return -EINVAL;
+
+	if (copy_from_user(tmp_acquire,
+			(void __user *)args->acquire_info,
+			tmp_size)) {
+		kfree(tmp_acquire);
+		return -EFAULT;
+	}
+
+	p_icp_out =
+		(struct cam_icp_res_info *)(tmp_acquire +
+		sizeof(icp_dev_acquire_info)-
+		sizeof(struct cam_icp_res_info));
+	ICP_DBG("out[0] %x %x %x %x\n",
+		p_icp_out[0].format,
+		p_icp_out[0].width,
+		p_icp_out[0].height,
+		p_icp_out[0].fps);
+
+	ICP_DBG("out[1] %x %x %x %x\n",
+		p_icp_out[1].format,
+		p_icp_out[1].width,
+		p_icp_out[1].height,
+		p_icp_out[1].fps);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	ctx_id = cam_icp_mgr_get_free_ctx(hw_mgr);
+	if (ctx_id >= CAM_ICP_CTX_MAX) {
+		pr_err("No free ctx space in hw_mgr\n");
+		kfree(tmp_acquire);
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EFAULT;
+	}
+
+	/* Fill ctx with acquire info */
+	ctx_data = &hw_mgr->ctx_data[ctx_id];
+
+	if (!hw_mgr->ctxt_cnt++) {
+		ICP_DBG("starting cpas\n");
+		cam_icp_start_cpas(hw_mgr);
+	}
+	ICP_DBG("context count : %u\n", hw_mgr->ctxt_cnt);
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	/* Fill ctx with acquire info */
+	mutex_lock(&ctx_data->ctx_mutex);
+	ctx_data->icp_dev_acquire_info = icp_dev_acquire_info;
+	for (i = 0; i < icp_dev_acquire_info.num_out_res; i++)
+		ctx_data->icp_out_acquire_info[i] = p_icp_out[i];
+	mutex_unlock(&ctx_data->ctx_mutex);
+
+	/* Get IOCONFIG command info */
+	if (ctx_data->icp_dev_acquire_info.secure_mode)
+		rc = cam_mem_get_io_buf(
+			icp_dev_acquire_info.io_config_cmd_handle,
+			hw_mgr->iommu_sec_hdl,
+			&io_buf_addr, &io_buf_size);
+	else
+		rc = cam_mem_get_io_buf(
+			icp_dev_acquire_info.io_config_cmd_handle,
+			hw_mgr->iommu_hdl,
+			&io_buf_addr, &io_buf_size);
+
+	ICP_DBG("io_config_cmd_handle : %d\n",
+		icp_dev_acquire_info.io_config_cmd_handle);
+	ICP_DBG("io_buf_addr : %pK\n", (void *)io_buf_addr);
+	ICP_DBG("io_buf_size : %zu\n", io_buf_size);
+	if (rc < 0) {
+		pr_err("unable to get src buf info from io desc\n");
+		goto cmd_cpu_buf_failed;
+	}
+
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no free task\n");
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		goto get_create_task_failed;
+	}
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	rc = cam_icp_mgr_send_ping(ctx_data, task);
+	if (rc) {
+		pr_err("ping ack not received\n");
+		goto create_handle_failed;
+	}
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no free task\n");
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		goto get_create_task_failed;
+	}
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	/* Send create fw handle command */
+	rc = cam_icp_mgr_create_handle(icp_dev_acquire_info.dev_type,
+			ctx_data, task);
+	if (rc) {
+		pr_err("create handle failed\n");
+		goto create_handle_failed;
+	}
+
+	/* Send IOCONFIG command */
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no empty task\n");
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		goto get_ioconfig_task_failed;
+	}
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	rc = cam_icp_mgr_send_config_io(ctx_data, task, io_buf_addr);
+	if (rc) {
+		pr_err("IO Config command failed\n");
+		goto ioconfig_failed;
+	}
+
+	mutex_lock(&ctx_data->ctx_mutex);
+	ctx_data->context_priv = args->context_data;
+	args->ctxt_to_hw_map = &ctx_data->fw_handle;
+
+	bitmap_size = BITS_TO_LONGS(CAM_FRAME_CMD_MAX) * sizeof(long);
+	ctx_data->hfi_frame_process.bitmap =
+			kzalloc(sizeof(bitmap_size), GFP_KERNEL);
+	ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE;
+	mutex_init(&ctx_data->hfi_frame_process.lock);
+	mutex_unlock(&ctx_data->ctx_mutex);
+
+	hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
+
+	icp_dev_acquire_info.scratch_mem_size = ctx_data->scratch_mem_size;
+	if (copy_to_user((void __user *)args->acquire_info,
+				&icp_dev_acquire_info,
+			sizeof(icp_dev_acquire_info)))
+		goto copy_to_user_failed;
+
+	ICP_DBG("scratch mem size = %x fw_handle = %x\n",
+			(unsigned int)icp_dev_acquire_info.scratch_mem_size,
+			(unsigned int)ctx_data->fw_handle);
+	kfree(tmp_acquire);
+	return 0;
+
+copy_to_user_failed:
+ioconfig_failed:
+get_ioconfig_task_failed:
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+	if (task)
+		cam_icp_mgr_destroy_handle(ctx_data, task);
+create_handle_failed:
+get_create_task_failed:
+cmd_cpu_buf_failed:
+	--hw_mgr->ctxt_cnt;
+	if (!hw_mgr->ctxt_cnt)
+		cam_icp_stop_cpas(hw_mgr);
+	cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
+	kfree(tmp_acquire);
+	return rc;
+}
+
+static int cam_icp_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args)
+{
+	int rc = 0;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_query_cap_cmd *query_cap = hw_caps_args;
+
+	if ((!hw_mgr_priv) || (!hw_caps_args)) {
+		pr_err("Invalid params: %pK %pK\n", hw_mgr_priv, hw_caps_args);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&icp_hw_mgr.icp_caps,
+			(void __user *)query_cap->caps_handle,
+			sizeof(struct cam_icp_query_cap_cmd))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	rc = hfi_get_hw_caps(&icp_hw_mgr.icp_caps);
+	if (rc < 0) {
+		pr_err("Unable to get caps from HFI: %d\n", rc);
+		goto hfi_get_caps_fail;
+	}
+
+	icp_hw_mgr.icp_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl;
+	icp_hw_mgr.icp_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl;
+
+	if (copy_to_user((void __user *)query_cap->caps_handle,
+			&icp_hw_mgr.icp_caps,
+			sizeof(struct cam_icp_query_cap_cmd))) {
+		pr_err("copy_to_user failed\n");
+		rc = -EFAULT;
+		goto hfi_get_caps_fail;
+	}
+
+hfi_get_caps_fail:
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	return rc;
+}
+
+int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
+{
+	int count, i, rc = 0;
+	uint32_t num_dev;
+	uint32_t num_ipe_dev;
+	const char *name = NULL;
+	struct device_node *child_node = NULL;
+	struct platform_device *child_pdev = NULL;
+	struct cam_hw_intf *child_dev_intf = NULL;
+	struct cam_hw_mgr_intf *hw_mgr_intf;
+
+
+	hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
+	if (!of_node || !hw_mgr_intf) {
+		pr_err("Invalid args of_node %pK hw_mgr %pK\n",
+			of_node, hw_mgr_intf);
+		return -EINVAL;
+	}
+
+	hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr;
+	hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps;
+	hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw;
+	hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
+	hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
+	hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
+	hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
+	hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
+
+	mutex_init(&icp_hw_mgr.hw_mgr_mutex);
+	spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
+
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
+		mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex);
+
+	/* Get number of device objects */
+	count = of_property_count_strings(of_node, "compat-hw-name");
+	if (!count) {
+		pr_err("no compat hw found in dev tree, count = %d\n", count);
+		rc = -EINVAL;
+		goto num_dev_failed;
+	}
+
+	/* Get number of a5 device nodes and a5 mem allocation */
+	rc = of_property_read_u32(of_node, "num-a5", &num_dev);
+	if (rc < 0) {
+		pr_err("getting num of a5 failed\n");
+		goto num_dev_failed;
+	}
+
+	icp_hw_mgr.devices[CAM_ICP_DEV_A5] = kzalloc(
+		sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL);
+	if (!icp_hw_mgr.devices[CAM_ICP_DEV_A5]) {
+		rc = -ENOMEM;
+		goto num_dev_failed;
+	}
+
+	/* Get number of ipe device nodes and ipe mem allocation */
+	rc = of_property_read_u32(of_node, "num-ipe", &num_ipe_dev);
+	if (rc < 0) {
+		pr_err("getting number of ipe dev nodes failed\n");
+		goto num_ipe_failed;
+	}
+
+	icp_hw_mgr.devices[CAM_ICP_DEV_IPE] = kzalloc(
+		sizeof(struct cam_hw_intf *) * num_ipe_dev, GFP_KERNEL);
+	if (!icp_hw_mgr.devices[CAM_ICP_DEV_IPE]) {
+		rc = -ENOMEM;
+		goto num_ipe_failed;
+	}
+
+	/* Get number of bps device nodes and bps mem allocation */
+	rc = of_property_read_u32(of_node, "num-bps", &num_dev);
+	if (rc < 0) {
+		pr_err("read num bps devices failed\n");
+		goto num_bps_failed;
+	}
+	icp_hw_mgr.devices[CAM_ICP_DEV_BPS] = kzalloc(
+		sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL);
+	if (!icp_hw_mgr.devices[CAM_ICP_DEV_BPS]) {
+		rc = -ENOMEM;
+		goto num_bps_failed;
+	}
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(of_node, "compat-hw-name",
+								i, &name);
+		if (rc < 0) {
+			pr_err("getting dev object name failed\n");
+			goto compat_hw_name_failed;
+		}
+
+		child_node = of_find_node_by_name(NULL, name);
+		if (!child_node) {
+			pr_err("error! Cannot find node in dtsi %s\n", name);
+			rc = -ENODEV;
+			goto compat_hw_name_failed;
+		}
+
+		child_pdev = of_find_device_by_node(child_node);
+		if (!child_pdev) {
+			pr_err("failed to find device on bus %s\n",
+				child_node->name);
+			rc = -ENODEV;
+			of_node_put(child_node);
+			goto compat_hw_name_failed;
+		}
+
+		child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata(
+								child_pdev);
+		if (!child_dev_intf) {
+			pr_err("no child device\n");
+			of_node_put(child_node);
+			goto compat_hw_name_failed;
+		}
+		ICP_DBG("child_intf %pK\n", child_dev_intf);
+		ICP_DBG("child type %d index %d\n",	child_dev_intf->hw_type,
+				child_dev_intf->hw_idx);
+
+		icp_hw_mgr.devices[child_dev_intf->hw_type]
+			[child_dev_intf->hw_idx] = child_dev_intf;
+
+		of_node_put(child_node);
+	}
+
+	rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
+	if (rc < 0) {
+		pr_err("icp get iommu handle failed\n");
+		goto compat_hw_name_failed;
+	}
+
+	pr_err("mmu handle :%d\n", icp_hw_mgr.iommu_hdl);
+	rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH);
+	if (rc < 0) {
+		pr_err("icp attach failed: %d\n", rc);
+		goto icp_attach_failed;
+	}
+
+	rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
+					&icp_hw_mgr.cmd_work);
+	if (rc < 0) {
+		pr_err("unable to create a worker\n");
+		goto cmd_work_failed;
+	}
+
+	rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK,
+					&icp_hw_mgr.msg_work);
+	if (rc < 0) {
+		pr_err("unable to create a worker\n");
+		goto msg_work_failed;
+	}
+
+	icp_hw_mgr.cmd_work_data = (struct hfi_cmd_work_data *)
+		kzalloc(sizeof(struct hfi_cmd_work_data) * ICP_WORKQ_NUM_TASK,
+		GFP_KERNEL);
+	if (!icp_hw_mgr.cmd_work_data)
+		goto cmd_work_data_failed;
+
+	icp_hw_mgr.msg_work_data = (struct hfi_msg_work_data *)
+		kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK,
+		GFP_KERNEL);
+	if (!icp_hw_mgr.msg_work_data)
+		goto msg_work_data_failed;
+
+
+	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
+		icp_hw_mgr.msg_work->task.pool[i].payload =
+				&icp_hw_mgr.msg_work_data[i];
+
+	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
+		icp_hw_mgr.cmd_work->task.pool[i].payload =
+				&icp_hw_mgr.cmd_work_data[i];
+
+	init_completion(&icp_hw_mgr.a5_complete);
+
+	pr_err("Exit\n");
+	return rc;
+
+msg_work_data_failed:
+	kfree(icp_hw_mgr.cmd_work_data);
+cmd_work_data_failed:
+	cam_req_mgr_workq_destroy(&icp_hw_mgr.msg_work);
+msg_work_failed:
+	cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work);
+cmd_work_failed:
+	cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH);
+icp_attach_failed:
+	icp_hw_mgr.iommu_hdl = 0;
+compat_hw_name_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]);
+num_bps_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
+num_ipe_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
+num_dev_failed:
+	mutex_destroy(&icp_hw_mgr.hw_mgr_mutex);
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
+		mutex_destroy(&icp_hw_mgr.ctx_data[i].ctx_mutex);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
new file mode 100644
index 0000000..e5ffa7a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -0,0 +1,181 @@
+/* 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_ICP_HW_MGR_H
+#define CAM_ICP_HW_MGR_H
+
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <media/cam_icp.h>
+#include "cam_icp_hw_intf.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_hw_intf.h"
+#include "cam_a5_hw_intf.h"
+#include "hfi_session_defs.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_mem_mgr.h"
+
+#define CAM_ICP_ROLE_PARENT     1
+#define CAM_ICP_ROLE_CHILD      2
+
+#define CAM_FRAME_CMD_MAX       20
+
+#define CAM_MAX_OUT_RES         6
+
+#define ICP_WORKQ_NUM_TASK      30
+#define ICP_WORKQ_TASK_CMD_TYPE 1
+#define ICP_WORKQ_TASK_MSG_TYPE 2
+
+#define ICP_PACKET_SIZE         0
+#define ICP_PACKET_TYPE         1
+#define ICP_PACKET_IPCODE       2
+#define ICP_IPE_MAX_OUTPUT_SUPPORTED 6
+
+/**
+ * struct icp_hfi_mem_info
+ * @qtbl: Memory info of queue table
+ * @cmd_q: Memory info of command queue
+ * @msg_q: Memory info of message queue
+ * @dbg_q: Memory info of debug queue
+ * @sec_heap: Memory info of secondary heap
+ * @fw_buf: Memory info of firmware
+ */
+struct icp_hfi_mem_info {
+	struct cam_mem_mgr_memory_desc qtbl;
+	struct cam_mem_mgr_memory_desc cmd_q;
+	struct cam_mem_mgr_memory_desc msg_q;
+	struct cam_mem_mgr_memory_desc dbg_q;
+	struct cam_mem_mgr_memory_desc sec_heap;
+	struct cam_mem_mgr_memory_desc fw_buf;
+};
+
+/**
+ * struct hfi_cmd_work_data
+ * @type: Task type
+ * @data: Pointer to command data
+ * @request_id: Request id
+ */
+struct hfi_cmd_work_data {
+	uint32_t type;
+	void *data;
+	int32_t request_id;
+};
+
+/**
+ * struct hfi_msg_work_data
+ * @type: Task type
+ * @data: Pointer to message data
+ * @irq_status: IRQ status
+ */
+struct hfi_msg_work_data {
+	uint32_t type;
+	void *data;
+	uint32_t irq_status;
+};
+
+/**
+ * struct hfi_frame_process_info
+ * @hfi_frame_cmd: Frame process command info
+ * @bitmap: Bitmap for hfi_frame_cmd
+ * @bits: Used in hfi_frame_cmd bitmap
+ * @lock: Lock for hfi_frame_cmd
+ * @request_id: Request id list
+ * @num_out_resources: Number of out syncs
+ * @out_resource: Out sync info
+ */
+struct hfi_frame_process_info {
+	struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX];
+	void *bitmap;
+	size_t bits;
+	struct mutex lock;
+	int32_t request_id[CAM_FRAME_CMD_MAX];
+	uint32_t num_out_resources[CAM_FRAME_CMD_MAX];
+	uint32_t out_resource[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES];
+};
+
+/**
+ * struct cam_icp_hw_ctx_data
+ * @context_priv: Context private data
+ * @ctx_mutex: Mutex for context
+ * @fw_handle: Firmware handle
+ * @scratch_mem_size: Scratch memory size
+ * @acquire_dev_cmd: Acquire command
+ * @icp_dev_acquire_info: Acquire device info
+ * @icp_out_acquire_info: Acquire out resource info
+ * @ctxt_event_cb: Context callback function
+ * @in_use: Flag for context usage
+ * @role: Role of a context in case of chaining
+ * @chain_ctx: Peer context
+ * @hfi_frame_process: Frame process command
+ * @wait_complete: Completion info
+ * @temp_payload: Payload for destroy handle data
+ */
+struct cam_icp_hw_ctx_data {
+	void *context_priv;
+	struct mutex ctx_mutex;
+	uint32_t fw_handle;
+	uint32_t scratch_mem_size;
+	struct cam_acquire_dev_cmd acquire_dev_cmd;
+	struct cam_icp_acquire_dev_info icp_dev_acquire_info;
+	struct cam_icp_res_info icp_out_acquire_info[CAM_MAX_OUT_RES];
+	cam_hw_event_cb_func ctxt_event_cb;
+	uint32_t in_use;
+	uint32_t role;
+	struct cam_icp_hw_ctx_data *chain_ctx;
+	struct hfi_frame_process_info hfi_frame_process;
+	struct completion wait_complete;
+	struct ipe_bps_destroy temp_payload;
+};
+
+/**
+ * struct cam_icp_hw_mgr
+ * @hw_mgr_mutex: Mutex for ICP hardware manager
+ * @hw_mgr_lock: Spinlock for ICP hardware manager
+ * @devices: Devices of ICP hardware manager
+ * @ctx_data: Context data
+ * @icp_caps: ICP capabilities
+ * @fw_download: Firmware download state
+ * @iommu_hdl: Non secure IOMMU handle
+ * @iommu_sec_hdl: Secure IOMMU handle
+ * @hfi_mem: Memory for hfi
+ * @cmd_work: Work queue for hfi commands
+ * @msg_work: Work queue for hfi messages
+ * @msg_buf: Buffer for message data from firmware
+ * @dbg_buf: Buffer for debug data from firmware
+ * @a5_complete: Completion info
+ * @cmd_work_data: Pointer to command work queue task
+ * @msg_work_data: Pointer to message work queue task
+ * @ctxt_cnt: Active context count
+ */
+struct cam_icp_hw_mgr {
+	struct mutex hw_mgr_mutex;
+	spinlock_t hw_mgr_lock;
+
+	struct cam_hw_intf **devices[CAM_ICP_DEV_MAX];
+	struct cam_icp_hw_ctx_data ctx_data[CAM_ICP_CTX_MAX];
+	struct cam_icp_query_cap_cmd icp_caps;
+
+	bool fw_download;
+	int32_t iommu_hdl;
+	int32_t iommu_sec_hdl;
+	struct icp_hfi_mem_info hfi_mem;
+	struct cam_req_mgr_core_workq *cmd_work;
+	struct cam_req_mgr_core_workq *msg_work;
+	uint32_t msg_buf[256];
+	uint32_t dbg_buf[256];
+	struct completion a5_complete;
+	struct hfi_cmd_work_data *cmd_work_data;
+	struct hfi_msg_work_data *msg_work_data;
+	uint32_t ctxt_cnt;
+};
+
+#endif /* CAM_ICP_HW_MGR_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
new file mode 100644
index 0000000..2686877
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
@@ -0,0 +1,79 @@
+/* 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_A5_HW_INTF_H
+#define CAM_A5_HW_INTF_H
+
+#include <linux/timer.h>
+#include <uapi/media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_intf.h"
+
+enum cam_icp_a5_cmd_type {
+	CAM_ICP_A5_CMD_FW_DOWNLOAD,
+	CAM_ICP_A5_CMD_POWER_COLLAPSE,
+	CAM_ICP_A5_CMD_POWER_RESUME,
+	CAM_ICP_A5_CMD_SET_FW_BUF,
+	CAM_ICP_A5_CMD_ACQUIRE,
+	CAM_ICP_A5_SET_IRQ_CB,
+	CAM_ICP_A5_TEST_IRQ,
+	CAM_ICP_A5_SEND_INIT,
+	CAM_ICP_A5_CMD_VOTE_CPAS,
+	CAM_ICP_A5_CMD_CPAS_START,
+	CAM_ICP_A5_CMD_CPAS_STOP,
+	CAM_ICP_A5_CMD_MAX,
+};
+
+struct cam_icp_a5_set_fw_buf_info {
+	uint32_t iova;
+	uint64_t kva;
+	uint64_t len;
+};
+
+/**
+ * struct cam_icp_a5_query_cap - ICP query device capability payload
+ * @fw_version: firmware version info
+ * @api_version: api version info
+ * @num_ipe: number of ipes
+ * @num_bps: number of bps
+ * @num_dev: number of device capabilities in dev_caps
+ * @reserved: reserved
+ * @dev_ver: returned device capability array
+ * @CAM_QUERY_CAP IOCTL
+ */
+struct cam_icp_a5_query_cap {
+	struct cam_icp_ver fw_version;
+	struct cam_icp_ver api_version;
+	uint32_t num_ipe;
+	uint32_t num_bps;
+	uint32_t num_dev;
+	uint32_t reserved;
+	struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX];
+};
+
+struct cam_icp_a5_acquire_dev {
+	uint32_t ctx_id;
+	struct cam_icp_acquire_dev_info icp_acquire_info;
+	struct cam_icp_res_info icp_out_acquire_info[2];
+	uint32_t fw_handle;
+};
+
+struct cam_icp_a5_set_irq_cb {
+	int32_t (*icp_hw_mgr_cb)(uint32_t irq_status, void *data);
+	void *data;
+};
+
+struct cam_icp_a5_test_irq {
+	uint32_t test_irq;
+};
+#endif /* CAM_A5_HW_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
new file mode 100644
index 0000000..4427a30
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
@@ -0,0 +1,32 @@
+/* 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_BPS_HW_INTF_H
+#define CAM_BPS_HW_INTF_H
+
+#include <uapi/media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_intf.h"
+
+enum cam_icp_bps_cmd_type {
+	CAM_ICP_BPS_CMD_FW_DOWNLOAD,
+	CAM_ICP_BPS_CMD_POWER_COLLAPSE,
+	CAM_ICP_BPS_CMD_POWER_RESUME,
+	CAM_ICP_BPS_CMD_SET_FW_BUF,
+	CAM_ICP_BPS_CMD_VOTE_CPAS,
+	CAM_ICP_BPS_CMD_CPAS_START,
+	CAM_ICP_BPS_CMD_CPAS_STOP,
+	CAM_ICP_BPS_CMD_MAX,
+};
+
+#endif /* CAM_BPS_HW_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
new file mode 100644
index 0000000..9300ea8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
@@ -0,0 +1,27 @@
+/* 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_ICP_HW_INTF_H
+#define CAM_ICP_HW_INTF_H
+
+#define CAM_ICP_CTX_MAX                 8
+
+#define CAM_ICP_CMD_BUF_MAX_SIZE     128
+#define CAM_ICP_MSG_BUF_MAX_SIZE     CAM_ICP_CMD_BUF_MAX_SIZE
+
+enum cam_a5_hw_type {
+	CAM_ICP_DEV_A5,
+	CAM_ICP_DEV_IPE,
+	CAM_ICP_DEV_BPS,
+	CAM_ICP_DEV_MAX,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
new file mode 100644
index 0000000..0db66c0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
@@ -0,0 +1,32 @@
+/* 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_IPE_HW_INTF_H
+#define CAM_IPE_HW_INTF_H
+
+#include <uapi/media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_intf.h"
+
+enum cam_icp_ipe_cmd_type {
+	CAM_ICP_IPE_CMD_FW_DOWNLOAD,
+	CAM_ICP_IPE_CMD_POWER_COLLAPSE,
+	CAM_ICP_IPE_CMD_POWER_RESUME,
+	CAM_ICP_IPE_CMD_SET_FW_BUF,
+	CAM_ICP_IPE_CMD_VOTE_CPAS,
+	CAM_ICP_IPE_CMD_CPAS_START,
+	CAM_ICP_IPE_CMD_CPAS_STOP,
+	CAM_ICP_IPE_CMD_MAX,
+};
+
+#endif /* CAM_IPE_HW_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/include/cam_icp_hw_mgr_intf.h
new file mode 100644
index 0000000..2f100ca
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/include/cam_icp_hw_mgr_intf.h
@@ -0,0 +1,40 @@
+/* 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_ICP_HW_MGR_INTF_H
+#define CAM_ICP_HW_MGR_INTF_H
+
+#include <uapi/media/cam_icp.h>
+#include <uapi/media/cam_defs.h>
+#include <linux/of.h>
+#include "cam_cpas_api.h"
+
+#define ICP_TURBO_VOTE           640000000
+
+int cam_icp_hw_mgr_init(struct device_node *of_node,
+	uint64_t *hw_mgr_hdl);
+
+/**
+ * struct cam_icp_cpas_vote
+ * @ahb_vote: AHB vote info
+ * @axi_vote: AXI vote info
+ * @ahb_vote_valid: Flag for ahb vote data
+ * @axi_vote_valid: flag for axi vote data
+ */
+struct cam_icp_cpas_vote {
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote;
+	uint32_t ahb_vote_valid;
+	uint32_t axi_vote_valid;
+};
+
+#endif /* CAM_ICP_HW_MGR_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/Makefile
new file mode 100644
index 0000000..8af20ae
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/Makefile
@@ -0,0 +1,11 @@
+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/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/ipe_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += ipe_dev.o ipe_core.o ipe_soc.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
new file mode 100644
index 0000000..15cb943
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "IPE-CORE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include "cam_io_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "ipe_core.h"
+#include "ipe_soc.h"
+#include "cam_soc_util.h"
+#include "cam_io_util.h"
+#include "cam_ipe_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+static int cam_ipe_caps_vote(struct cam_ipe_device_core_info *core_info,
+	struct cam_icp_cpas_vote *cpas_vote)
+{
+	int rc = 0;
+
+	if (cpas_vote->ahb_vote_valid)
+		rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
+			&cpas_vote->ahb_vote);
+	if (cpas_vote->axi_vote_valid)
+		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
+			&cpas_vote->axi_vote);
+
+	if (rc < 0)
+		pr_err("cpas vote is failed: %d\n", rc);
+
+	return rc;
+}
+
+int cam_ipe_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *ipe_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+
+	rc = cam_cpas_start(core_info->cpas_handle,
+		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
+	if (rc < 0) {
+		pr_err("cpass start failed: %d\n", rc);
+		return rc;
+	}
+
+	rc = cam_ipe_enable_soc_resources(soc_info);
+	if (rc < 0) {
+		pr_err("soc enable is failed\n");
+		rc = cam_cpas_stop(core_info->cpas_handle);
+	}
+
+	return rc;
+}
+
+int cam_ipe_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *ipe_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	rc = cam_ipe_disable_soc_resources(soc_info);
+	if (rc < 0)
+		pr_err("soc enable is failed\n");
+
+	rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc < 0)
+		pr_err("cpas stop is failed: %d\n", rc);
+
+	return rc;
+}
+
+int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *ipe_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	struct cam_ipe_device_hw_info *hw_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (cmd_type >= CAM_ICP_IPE_CMD_MAX) {
+		pr_err("Invalid command : %x\n", cmd_type);
+		return -EINVAL;
+	}
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+	hw_info = core_info->ipe_hw_info;
+
+	switch (cmd_type) {
+	case CAM_ICP_IPE_CMD_VOTE_CPAS: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args)
+			return -EINVAL;
+
+		cam_ipe_caps_vote(core_info, cpas_vote);
+		break;
+	}
+
+	case CAM_ICP_IPE_CMD_CPAS_START: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args)
+			return -EINVAL;
+
+		rc = cam_cpas_start(core_info->cpas_handle,
+			&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		break;
+	}
+
+	case CAM_ICP_IPE_CMD_CPAS_STOP:
+		cam_cpas_stop(core_info->cpas_handle);
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+irqreturn_t cam_ipe_irq(int irq_num, void *data)
+{
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
new file mode 100644
index 0000000..4818846
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_IPE_CORE_H
+#define CAM_IPE_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+
+struct cam_ipe_device_hw_info {
+	uint32_t reserved;
+};
+
+struct cam_ipe_device_core_info {
+	struct cam_ipe_device_hw_info *ipe_hw_info;
+	uint32_t cpas_handle;
+};
+
+int cam_ipe_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_ipe_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+irqreturn_t cam_ipe_irq(int irq_num, void *data);
+
+#endif /* CAM_IPE_CORE_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_dev.c
new file mode 100644
index 0000000..0efb1de
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_dev.c
@@ -0,0 +1,176 @@
+/* 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/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include "ipe_core.h"
+#include "ipe_soc.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_io_util.h"
+#include "cam_icp_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_ipe_device_hw_info cam_ipe_hw_info = {
+	.reserved = 0,
+};
+EXPORT_SYMBOL(cam_ipe_hw_info);
+
+int cam_ipe_register_cpas(struct cam_hw_soc_info *soc_info,
+	struct cam_ipe_device_core_info *core_info,
+	uint32_t hw_idx)
+{
+	struct cam_cpas_register_params cpas_register_params;
+	int rc;
+
+	cpas_register_params.dev = &soc_info->pdev->dev;
+	memcpy(cpas_register_params.identifier, "ipe", sizeof("ipe"));
+	cpas_register_params.cam_cpas_client_cb = NULL;
+	cpas_register_params.cell_index = hw_idx;
+	cpas_register_params.userdata = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_params);
+	if (rc < 0) {
+		pr_err("cam_cpas_register_client is failed: %d\n", rc);
+		return rc;
+	}
+	core_info->cpas_handle = cpas_register_params.client_handle;
+
+	return rc;
+}
+
+int cam_ipe_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info            *ipe_dev = NULL;
+	struct cam_hw_intf            *ipe_dev_intf = NULL;
+	const struct of_device_id         *match_dev = NULL;
+	struct cam_ipe_device_core_info   *core_info = NULL;
+	struct cam_ipe_device_hw_info     *hw_info = NULL;
+	int                                rc = 0;
+
+	ipe_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!ipe_dev_intf)
+		return -ENOMEM;
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &ipe_dev_intf->hw_idx);
+
+	ipe_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!ipe_dev) {
+		kfree(ipe_dev_intf);
+		return -ENOMEM;
+	}
+	ipe_dev->soc_info.pdev = pdev;
+	ipe_dev_intf->hw_priv = ipe_dev;
+	ipe_dev_intf->hw_ops.init = cam_ipe_init_hw;
+	ipe_dev_intf->hw_ops.deinit = cam_ipe_deinit_hw;
+	ipe_dev_intf->hw_ops.process_cmd = cam_ipe_process_cmd;
+	ipe_dev_intf->hw_type = CAM_ICP_DEV_IPE;
+
+	pr_debug("%s: type %d index %d\n", __func__,
+		ipe_dev_intf->hw_type,
+		ipe_dev_intf->hw_idx);
+
+	platform_set_drvdata(pdev, ipe_dev_intf);
+
+	ipe_dev->core_info = kzalloc(sizeof(struct cam_ipe_device_core_info),
+		GFP_KERNEL);
+	if (!ipe_dev->core_info) {
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		return -ENOMEM;
+	}
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_debug("%s: No ipe hardware info\n", __func__);
+		kfree(ipe_dev->core_info);
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		rc = -EINVAL;
+		return rc;
+	}
+	hw_info = (struct cam_ipe_device_hw_info *)match_dev->data;
+	core_info->ipe_hw_info = hw_info;
+
+	rc = cam_ipe_init_soc_resources(&ipe_dev->soc_info, cam_ipe_irq,
+		ipe_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to init_soc\n", __func__);
+		kfree(ipe_dev->core_info);
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		return rc;
+	}
+
+	pr_debug("cam_ipe_init_soc_resources : %pK\n",
+		(void *)&ipe_dev->soc_info);
+	rc = cam_ipe_register_cpas(&ipe_dev->soc_info,
+		core_info, ipe_dev_intf->hw_idx);
+	if (rc < 0) {
+		kfree(ipe_dev->core_info);
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		return rc;
+	}
+	ipe_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&ipe_dev->hw_mutex);
+	spin_lock_init(&ipe_dev->hw_lock);
+	init_completion(&ipe_dev->hw_complete);
+
+	pr_debug("%s: IPE%d probe successful\n", __func__,
+		ipe_dev_intf->hw_idx);
+
+	return rc;
+}
+
+static const struct of_device_id cam_ipe_dt_match[] = {
+	{
+		.compatible = "qcom,cam_ipe",
+		.data = &cam_ipe_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_ipe_dt_match);
+
+static struct platform_driver cam_ipe_driver = {
+	.probe = cam_ipe_probe,
+	.driver = {
+		.name = "cam_ipe",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_ipe_dt_match,
+	},
+};
+
+static int __init cam_ipe_init_module(void)
+{
+	return platform_driver_register(&cam_ipe_driver);
+}
+
+static void __exit cam_ipe_exit_module(void)
+{
+	platform_driver_unregister(&cam_ipe_driver);
+}
+
+module_init(cam_ipe_init_module);
+module_exit(cam_ipe_exit_module);
+MODULE_DESCRIPTION("CAM IPE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.c
new file mode 100644
index 0000000..527e716
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.c
@@ -0,0 +1,87 @@
+/* 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/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "ipe_soc.h"
+#include "cam_soc_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_ipe_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0)
+		pr_err("get ipe dt prop is failed\n");
+
+	return rc;
+}
+
+static int cam_ipe_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t ipe_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, ipe_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t ipe_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_ipe_get_dt_properties(soc_info);
+	if (rc < 0)
+		return rc;
+
+	rc = cam_ipe_request_platform_resource(soc_info, ipe_irq_handler,
+		irq_data);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, false);
+	if (rc) {
+		pr_err("%s: enable platform failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, false);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.h
new file mode 100644
index 0000000..12ab444
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.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_IPE_SOC_H
+#define CAM_IPE_SOC_H
+
+#include "cam_soc_util.h"
+
+int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t ipe_irq_handler, void *irq_data);
+
+int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* CAM_IPE_SOC_H */