Merge "msm: cam: reqmgr: Add request manager driver" into msm-4.9
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index 9344c64..f8c864f 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o  cam_req_mgr_workq.o
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
new file mode 100644
index 0000000..a34703c
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -0,0 +1,659 @@
+/* Copyright (c) 2016-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/of_platform.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "cam_req_mgr_interface.h"
+#include "cam_req_mgr_util.h"
+#include "cam_req_mgr_core.h"
+#include "cam_req_mgr_workq.h"
+
+/* Forward declarations */
+static int cam_req_mgr_cb_notify_sof(
+	struct cam_req_mgr_sof_notify *sof_data);
+
+
+static struct cam_req_mgr_core_device *g_crm_core_dev;
+
+static struct cam_req_mgr_crm_cb cam_req_mgr_ops = {
+	.notify_sof = cam_req_mgr_cb_notify_sof,
+	.notify_err = NULL,
+	.add_req = NULL,
+};
+
+/**
+ * cam_req_mgr_pvt_find_link()
+ *
+ * @brief: Finds link matching with handle within session
+ * @session: session indetifier
+ * @link_hdl: link handle
+ *
+ * Returns pointer to link matching handle
+ */
+static struct cam_req_mgr_core_link *cam_req_mgr_pvt_find_link(
+	struct cam_req_mgr_core_session *session, int32_t link_hdl)
+{
+	int32_t i;
+	struct cam_req_mgr_core_link *link = NULL;
+
+	if (!session) {
+		CRM_ERR("NULL session ptr");
+		return NULL;
+	}
+
+	spin_lock(&session->lock);
+	for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+		link = &session->links[i];
+		spin_lock(&link->lock);
+		if (link->link_hdl == link_hdl) {
+			CRM_DBG("Link found p_delay %d",
+				 link->max_pipeline_delay);
+			spin_unlock(&link->lock);
+			break;
+		}
+		spin_unlock(&link->lock);
+	}
+	if (i >= MAX_LINKS_PER_SESSION)
+		link = NULL;
+	spin_unlock(&session->lock);
+
+	return link;
+}
+
+/**
+ * cam_req_mgr_process_sof()
+ *
+ * @brief: This runs in workque thread context. Call core funcs to check
+ * which peding requests can be processed.
+ * @data:contains information about frame_id, link etc.
+ *
+ * Returns 0 on success.
+ */
+static int cam_req_mgr_process_sof(void *priv, void *data)
+{
+	int ret = 0, i = 0;
+	struct cam_req_mgr_sof_notify *sof_data = NULL;
+	struct cam_req_mgr_core_link *link = NULL;
+	struct cam_req_mgr_connected_device *device = NULL;
+	struct cam_req_mgr_apply_request apply_req;
+
+	if (!data || !priv) {
+		CRM_ERR("input args NULL %pK %pK", data, priv);
+		ret = -EINVAL;
+		goto end;
+	}
+	link = (struct cam_req_mgr_core_link *)priv;
+	sof_data = (struct cam_req_mgr_sof_notify *)data;
+
+	CRM_DBG("link_hdl %x frame_id %lld",
+		sof_data->link_hdl,
+		sof_data->frame_id);
+
+	apply_req.link_hdl = sof_data->link_hdl;
+	/* @TODO: go through request table and issue
+	 * request id based on dev status
+	 */
+	apply_req.request_id = sof_data->frame_id;
+	apply_req.report_if_bubble = 0;
+
+	CRM_DBG("link %pK l_dev %pK num_dev %d",
+		link, link->l_devices, link->num_connections);
+	for (i = 0; i < link->num_connections; i++) {
+		device = &link->l_devices[i];
+		if (device != NULL) {
+			CRM_DBG("dev_id %d dev_hdl %x ops %pK p_delay %d",
+				device->dev_info.dev_id, device->dev_hdl,
+				device->ops, device->dev_info.p_delay);
+			apply_req.dev_hdl = device->dev_hdl;
+			if (device->ops && device->ops->apply_req) {
+				ret = device->ops->apply_req(&apply_req);
+				/* Error handling for this failure is pending */
+				if (ret < 0)
+					CRM_ERR("Failure:%d dev=%d", ret,
+						device->dev_info.dev_id);
+			}
+
+		}
+	}
+
+end:
+	return ret;
+}
+
+/**
+ * cam_req_mgr_notify_sof()
+ *
+ * @brief: SOF received from device, sends trigger through workqueue
+ * @sof_data: contains information about frame_id, link etc.
+ *
+ * Returns 0 on success
+ */
+static int cam_req_mgr_cb_notify_sof(struct cam_req_mgr_sof_notify *sof_data)
+{
+	int                           ret = 0;
+	struct crm_workq_task        *task = NULL;
+	struct cam_req_mgr_core_link *link = NULL;
+
+	if (!sof_data) {
+		CRM_ERR("sof_data is NULL");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	CRM_DBG("link_hdl %x frame_id %lld",
+		sof_data->link_hdl,
+		sof_data->frame_id);
+
+	link = (struct cam_req_mgr_core_link *)
+		cam_get_device_priv(sof_data->link_hdl);
+	if (!link) {
+		CRM_DBG("link ptr NULL %x", sof_data->link_hdl);
+		ret = -EINVAL;
+		goto end;
+
+	}
+
+	task = cam_req_mgr_workq_get_task(link->workq);
+	if (!task) {
+		CRM_ERR("no empty task frame %lld", sof_data->frame_id);
+		ret = -EBUSY;
+		goto end;
+	}
+	task->type = CRM_WORKQ_TASK_NOTIFY_SOF;
+	task->u.notify_sof.frame_id = sof_data->frame_id;
+	task->u.notify_sof.link_hdl = sof_data->link_hdl;
+	task->u.notify_sof.dev_hdl = sof_data->dev_hdl;
+	task->process_cb = &cam_req_mgr_process_sof;
+	task->priv = link;
+	cam_req_mgr_workq_enqueue_task(task);
+
+end:
+	return ret;
+}
+
+/**
+ * cam_req_mgr_pvt_reserve_link()
+ *
+ * @brief: Reserves one link data struct within session
+ * @session: session identifier
+ *
+ * Returns pointer to link reserved
+ */
+static struct cam_req_mgr_core_link *cam_req_mgr_pvt_reserve_link(
+	struct cam_req_mgr_core_session *session)
+{
+	int32_t i;
+	struct cam_req_mgr_core_link *link;
+
+	if (!session) {
+		CRM_ERR("NULL session ptr");
+		return NULL;
+	}
+
+	spin_lock(&session->lock);
+	for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+		link = &session->links[i];
+		spin_lock(&link->lock);
+		if (link->link_state == CAM_CRM_LINK_STATE_AVAILABLE) {
+			link->num_connections = 0;
+			link->max_pipeline_delay = 0;
+			memset(link->req_table, 0,
+				sizeof(struct cam_req_mgr_request_table));
+			link->link_state = CAM_CRM_LINK_STATE_IDLE;
+			spin_unlock(&link->lock);
+			break;
+		}
+		spin_unlock(&link->lock);
+	}
+	CRM_DBG("Link available (total %d)", session->num_active_links);
+	spin_unlock(&session->lock);
+
+	if (i >= MAX_LINKS_PER_SESSION)
+		link = NULL;
+
+	return link;
+}
+
+/**
+ * cam_req_mgr_pvt_create_subdevs()
+ *
+ * @brief: Create new crm  subdev to link with realtime devices
+ * @l_devices: list of subdevs internal to crm
+ * @num_dev: num of subdevs to be created for link
+ *
+ * Returns pointer to allocated list of devices
+ */
+static struct cam_req_mgr_connected_device *
+	cam_req_mgr_pvt_create_subdevs(int32_t num_dev)
+{
+	struct cam_req_mgr_connected_device *l_devices;
+
+	l_devices = (struct cam_req_mgr_connected_device *)
+		kzalloc(sizeof(struct cam_req_mgr_connected_device) * num_dev,
+		GFP_KERNEL);
+	if (!l_devices)
+		CRM_DBG("Insufficient memory %lu",
+			sizeof(struct cam_req_mgr_connected_device) * num_dev);
+
+	return l_devices;
+}
+
+/**
+ * cam_req_mgr_pvt_destroy_subdev()
+ *
+ * @brief: Cleans up the subdevs allocated by crm for link
+ * @l_device: pointer to list of subdevs crm created
+ *
+ * Returns 0 for success
+ */
+static int cam_req_mgr_pvt_destroy_subdev(
+	struct cam_req_mgr_connected_device **l_device)
+{
+	int ret = 0;
+
+	if (!(*l_device))
+		ret = -EINVAL;
+	else {
+		kfree(*l_device);
+		*l_device = NULL;
+	}
+
+	return ret;
+}
+
+int cam_req_mgr_create_session(
+	struct cam_req_mgr_session_info *ses_info)
+{
+	int ret = 0;
+	int32_t i;
+	int32_t session_hdl;
+	struct cam_req_mgr_core_session *cam_session;
+
+	if (!ses_info) {
+		CRM_ERR("NULL session info pointer");
+		return -EINVAL;
+	}
+	mutex_lock(&g_crm_core_dev->crm_lock);
+	cam_session = (struct cam_req_mgr_core_session *)
+		kzalloc(sizeof(*cam_session), GFP_KERNEL);
+	if (!cam_session) {
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	session_hdl = cam_create_session_hdl((void *)cam_session);
+	if (session_hdl < 0) {
+		CRM_ERR("unable to create session_hdl = %x", session_hdl);
+		ret = session_hdl;
+		goto session_hdl_failed;
+	}
+	ses_info->session_hdl = session_hdl;
+	cam_session->session_hdl = session_hdl;
+
+	spin_lock_init(&cam_session->lock);
+	cam_session->num_active_links = 0;
+
+	for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+		spin_lock_init(&cam_session->links[i].lock);
+		cam_session->links[i].link_state = CAM_CRM_LINK_STATE_AVAILABLE;
+		INIT_LIST_HEAD(&cam_session->links[i].link_head);
+		cam_session->links[i].workq = NULL;
+	}
+	list_add(&cam_session->entry, &g_crm_core_dev->session_head);
+
+	mutex_unlock(&g_crm_core_dev->crm_lock);
+	return ret;
+
+session_hdl_failed:
+	kfree(cam_session);
+end:
+	mutex_unlock(&g_crm_core_dev->crm_lock);
+	return ret;
+}
+
+int cam_req_mgr_destroy_session(
+		struct cam_req_mgr_session_info *ses_info)
+{
+	int ret;
+	int32_t i;
+	struct cam_req_mgr_core_session *cam_session;
+	struct cam_req_mgr_core_link *link = NULL;
+
+	if (!ses_info) {
+		CRM_ERR("NULL session info pointer");
+		return -EINVAL;
+	}
+
+	mutex_lock(&g_crm_core_dev->crm_lock);
+	cam_session = (struct cam_req_mgr_core_session *)
+		cam_get_device_priv(ses_info->session_hdl);
+	if (cam_session == NULL) {
+		CRM_ERR("failed to get session priv");
+		ret = -ENOENT;
+		goto end;
+
+	}
+	spin_lock(&cam_session->lock);
+	for (i = 0; i < cam_session->num_active_links; i++) {
+		link = &cam_session->links[i];
+		CRM_ERR("session %x active_links %d hdl %x connections %d",
+			ses_info->session_hdl,
+			cam_session->num_active_links,
+			link->link_hdl, link->num_connections);
+	}
+	list_del(&cam_session->entry);
+	spin_unlock(&cam_session->lock);
+	kfree(cam_session);
+
+	ret = cam_destroy_session_hdl(ses_info->session_hdl);
+	if (ret)
+		CRM_ERR("unable to destroy session_hdl = %x ret %d",
+			ses_info->session_hdl, ret);
+
+end:
+	mutex_unlock(&g_crm_core_dev->crm_lock);
+	return ret;
+
+}
+
+int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info)
+{
+	int ret = 0;
+	int32_t i, link_hdl;
+	char buf[128];
+	struct cam_create_dev_hdl root_dev;
+	struct cam_req_mgr_core_session *cam_session;
+	struct cam_req_mgr_core_link *link;
+	struct cam_req_mgr_core_dev_link_setup link_data;
+	struct cam_req_mgr_connected_device *l_devices;
+	enum cam_pipeline_delay max_delay = CAM_PIPELINE_DELAY_0;
+
+	if (!link_info) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) {
+		CRM_ERR("Invalid num devices %d", link_info->num_devices);
+		return -EINVAL;
+	}
+
+	cam_session = (struct cam_req_mgr_core_session *)
+		cam_get_device_priv(link_info->session_hdl);
+	if (!cam_session) {
+		CRM_ERR("NULL session pointer");
+		return -EINVAL;
+	}
+
+	link = cam_req_mgr_pvt_reserve_link(cam_session);
+	if (!link) {
+		CRM_ERR("NULL link pointer");
+		return -EINVAL;
+	}
+
+	memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl));
+	root_dev.session_hdl = link_info->session_hdl;
+	root_dev.priv = (void *)link;
+
+	link_hdl = cam_create_device_hdl(&root_dev);
+	if (link_hdl < 0) {
+		CRM_ERR("Insufficient memory to create new device handle");
+		ret = link_hdl;
+		goto link_hdl_fail;
+	}
+
+	l_devices = cam_req_mgr_pvt_create_subdevs(link_info->num_devices);
+	if (!l_devices) {
+		ret = -ENOMEM;
+		goto create_subdev_failed;
+	}
+
+	for (i = 0; i < link_info->num_devices; i++) {
+		l_devices[i].dev_hdl = link_info->dev_hdls[i];
+		l_devices[i].parent = (void *)link;
+		l_devices[i].ops = (struct cam_req_mgr_kmd_ops *)
+			cam_get_device_ops(link_info->dev_hdls[i]);
+		link_data.dev_hdl = l_devices[i].dev_hdl;
+		l_devices[i].dev_info.dev_hdl = l_devices[i].dev_hdl;
+		if (l_devices[i].ops) {
+			if (l_devices[i].ops->get_dev_info) {
+				ret = l_devices[i].ops->get_dev_info(
+					&l_devices[i].dev_info);
+				if (ret < 0 ||
+					l_devices[i].dev_info.p_delay >=
+					CAM_PIPELINE_DELAY_MAX ||
+					l_devices[i].dev_info.p_delay <
+					CAM_PIPELINE_DELAY_0) {
+					CRM_ERR("get device info failed");
+					goto error;
+				} else {
+					CRM_DBG("%x: connected: %s, delay %d",
+						link_info->session_hdl,
+						l_devices[i].dev_info.name,
+						l_devices[i].dev_info.p_delay);
+					if (l_devices[i].dev_info.p_delay >
+						max_delay)
+					max_delay =
+						l_devices[i].dev_info.p_delay;
+				}
+			}
+		} else {
+			CRM_ERR("FATAL: device ops NULL");
+			ret = -ENXIO;
+			goto error;
+		}
+	}
+
+	link_data.link_enable = true;
+	link_data.link_hdl = link_hdl;
+	link_data.crm_cb = &cam_req_mgr_ops;
+	link_data.max_delay = max_delay;
+
+	/* After getting info about all devices, establish link */
+	for (i = 0; i < link_info->num_devices; i++) {
+		l_devices[i].dev_hdl = link_info->dev_hdls[i];
+		l_devices[i].parent = (void *)link;
+		l_devices[i].ops = (struct cam_req_mgr_kmd_ops *)
+			cam_get_device_ops(link_info->dev_hdls[i]);
+		link_data.dev_hdl = l_devices[i].dev_hdl;
+		l_devices[i].dev_info.dev_hdl = l_devices[i].dev_hdl;
+		if (l_devices[i].ops) {
+			if (l_devices[i].ops->link_setup) {
+				ret = l_devices[i].ops->link_setup(&link_data);
+				if (ret < 0) {
+					/* TODO check handlng of this failure */
+					CRM_ERR("link setup failed");
+					goto error;
+				}
+			}
+		}
+		list_add_tail(&l_devices[i].entry, &link->link_head);
+	}
+
+	/* Create worker for current link */
+	snprintf(buf, sizeof(buf), "%x-%x", link_info->session_hdl, link_hdl);
+	ret = cam_req_mgr_workq_create(buf, &link->workq);
+	if (ret < 0) {
+		CRM_ERR("FATAL: unable to create worker");
+		goto error;
+	}
+
+	link_info->link_hdl = link_hdl;
+	spin_lock(&link->lock);
+	link->l_devices = l_devices;
+	link->link_hdl = link_hdl;
+	link->parent = (void *)cam_session;
+	link->num_connections = link_info->num_devices;
+	link->link_state = CAM_CRM_LINK_STATE_READY;
+	spin_unlock(&link->lock);
+
+	spin_lock(&cam_session->lock);
+	cam_session->num_active_links++;
+	spin_unlock(&cam_session->lock);
+
+	return ret;
+
+error:
+	cam_req_mgr_pvt_destroy_subdev(&l_devices);
+create_subdev_failed:
+	cam_destroy_device_hdl(link_hdl);
+link_hdl_fail:
+	spin_lock(&link->lock);
+	link->link_state = CAM_CRM_LINK_STATE_AVAILABLE;
+	spin_unlock(&link->lock);
+
+	return ret;
+}
+
+int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info)
+{
+	int ret = 0;
+	int32_t i = 0;
+	struct cam_req_mgr_core_session *cam_session;
+	struct cam_req_mgr_core_link *link;
+	struct cam_req_mgr_connected_device *device;
+	struct cam_req_mgr_core_dev_link_setup link_data;
+
+	if (!unlink_info) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+	cam_session = (struct cam_req_mgr_core_session *)
+	cam_get_device_priv(unlink_info->session_hdl);
+	if (!cam_session) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	link = cam_req_mgr_pvt_find_link(cam_session,
+		unlink_info->link_hdl);
+	if (!link) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	ret = cam_destroy_device_hdl(link->link_hdl);
+	if (ret < 0) {
+		CRM_ERR("error in destroying dev handle %d %x",
+			ret, link->link_hdl);
+		ret = -EINVAL;
+	}
+	link_data.link_enable = false;
+	link_data.link_hdl = link->link_hdl;
+	link_data.crm_cb = NULL;
+	for (i = 0; i < link->num_connections; i++) {
+		device = &link->l_devices[i];
+		link_data.dev_hdl = device->dev_hdl;
+		if (device->ops && device->ops->link_setup)
+			device->ops->link_setup(&link_data);
+		device->dev_hdl = 0;
+		device->parent = NULL;
+		device->ops = NULL;
+		list_del(&device->entry);
+	}
+	/* Destroy worker of link */
+	cam_req_mgr_workq_destroy(link->workq);
+	spin_lock(&link->lock);
+	link->link_state = CAM_CRM_LINK_STATE_AVAILABLE;
+	link->parent = NULL;
+	link->num_connections = 0;
+	link->link_hdl = 0;
+	link->workq = NULL;
+	spin_unlock(&link->lock);
+
+	spin_lock(&cam_session->lock);
+	cam_session->num_active_links--;
+	spin_unlock(&cam_session->lock);
+
+	ret = cam_req_mgr_pvt_destroy_subdev(&link->l_devices);
+	if (ret < 0) {
+		CRM_ERR("error while destroying subdev link %x",
+			link_data.link_hdl);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int cam_req_mgr_schedule_request(
+			struct cam_req_mgr_sched_request *sched_req)
+{
+	if (!sched_req) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	/* This function handles ioctl, implementation pending */
+	return 0;
+}
+
+int cam_req_mgr_sync_mode(
+			struct cam_req_mgr_sync_mode *sync_links)
+{
+	if (!sync_links) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	/* This function handles ioctl, implementation pending */
+	return 0;
+}
+
+int cam_req_mgr_flush_requests(
+			struct cam_req_mgr_flush_info *flush_info)
+{
+	if (!flush_info) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	/* This function handles ioctl, implementation pending */
+	return 0;
+}
+
+
+int cam_req_mgr_core_device_init(void)
+{
+	CRM_DBG("Enter g_crm_core_dev %pK", g_crm_core_dev);
+
+	if (g_crm_core_dev) {
+		CRM_WARN("core device is already initialized");
+		return 0;
+	}
+	g_crm_core_dev = (struct cam_req_mgr_core_device *)
+		kzalloc(sizeof(*g_crm_core_dev), GFP_KERNEL);
+	if (!g_crm_core_dev)
+		return -ENOMEM;
+
+	CRM_DBG("g_crm_core_dev %pK", g_crm_core_dev);
+	INIT_LIST_HEAD(&g_crm_core_dev->session_head);
+	mutex_init(&g_crm_core_dev->crm_lock);
+
+	return 0;
+}
+
+int cam_req_mgr_core_device_deinit(void)
+{
+	if (!g_crm_core_dev) {
+		CRM_ERR("NULL pointer");
+		return -EINVAL;
+	}
+
+	CRM_DBG("g_crm_core_dev %pK", g_crm_core_dev);
+	mutex_destroy(&g_crm_core_dev->crm_lock);
+	kfree(g_crm_core_dev);
+	g_crm_core_dev = NULL;
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
new file mode 100644
index 0000000..7679f20
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
@@ -0,0 +1,273 @@
+/* Copyright (c) 2016-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_H_
+#define _CAM_REQ_MGR_CORE_H_
+
+#include "cam_req_mgr_interface.h"
+#include "cam_req_mgr_core_defs.h"
+
+#define CAM_REQ_MGR_MAX_LINKED_DEV 16
+
+/**
+ * enum crm_req_status
+ * State machine for life cycle of request in link
+ * EMPTY - indicates req slot is empty
+ * PENDING - indicates req slot is waiting for reqs from all devs
+ * READY - indicates req slot is ready to be sent to devs
+ * APPLIED - indicates req slot is sent to devices
+ * INVALID - indicates req slot is not in valid state
+ */
+enum crm_req_status {
+	CRM_REQ_STATUS_EMPTY,
+	CRM_REQ_STATUS_PENDING,
+	CRM_REQ_STATUS_READY,
+	CRM_REQ_STATUS_APPLIED,
+	CRM_REQ_STATUS_INVALID,
+};
+
+/**
+ * enum cam_req_mgr_link_state
+ * State machine for life cycle of link in crm
+ * AVAILABLE - indicates link is not in use
+ * IDLE - indicates link is reserved but not initialized
+ * READY - indicates link is initialized and ready for operation
+ * STREAMING - indicates link is receiving triggers and requests
+ * BUBBLE_DETECTED - indicates device on link is in bad shape
+ * ROLLBACK_STARTED - indicates link had triggered error recovery
+ * MAX - indicates link max as invalid
+ */
+enum cam_req_mgr_link_state {
+	CAM_CRM_LINK_STATE_AVAILABLE,
+	CAM_CRM_LINK_STATE_IDLE,
+	CAM_CRM_LINK_STATE_READY,
+	CAM_CRM_LINK_STATE_STREAMING,
+	CAM_CRM_LINK_STATE_BUBBLE_DETECTED,
+	CAM_CRM_LINK_STATE_ROLLBACK_STARTED,
+	CAM_CRM_LINK_STATE_DEVICE_STATE_MAX,
+};
+
+/**
+ * struct cam_req_mgr_request_slot
+ * @idx: device handle
+ * @req_status: state machine for life cycle of a request
+ * @request_id: request id value
+ */
+struct cam_req_mgr_request_slot {
+	int32_t idx;
+	enum crm_req_status req_status;
+	int64_t request_id;
+};
+
+/**
+ * struct cam_req_mgr_request_queue
+ * @read_index: idx currently being processed
+ * @write_index: idx at which incoming req is stored
+ * @num_slots: num of req slots i.e. queue depth
+ * @req_slot: slots which hold the request info
+ */
+struct cam_req_mgr_request_queue {
+	int32_t read_index;
+	int32_t write_index;
+	uint32_t num_slots;
+	struct cam_req_mgr_request_slot *req_slot;
+};
+
+/**
+ * struct cam_req_mgr_frame_settings
+ * @request_id: request id to apply
+ * @frame_id: frame id for debug purpose
+ */
+struct cam_req_mgr_frame_settings {
+	int64_t request_id;
+	int64_t frame_id;
+};
+
+/**
+ * struct cam_req_mgr_request_table
+ * @pipeline_delay: pipeline delay of this req table
+ * @l_devices: list of devices belonging to this p_delay
+ * @dev_mask: each dev hdl has unique bit assigned, dev mask tracks if all devs
+ *  received req id packet from UMD to process
+ */
+struct cam_req_mgr_request_table {
+	uint32_t pipeline_delay;
+	struct list_head l_devices;
+	uint32_t dev_mask;
+};
+
+/**
+ * struct cam_req_mgr_connected_device
+ *- Device Properties
+ * @dev_hdl: device handle
+ * @dev_bit: unique bit assigned to device in link
+ * -Device progress status
+ * @available_req_id: tracks latest available req id at this device
+ * @processing_req_id: tracks request id currently processed
+ * - Device characteristics
+ * @dev_info: holds dev characteristics such as pipeline delay, dev name
+ * @ops: holds func pointer to call methods on this device
+ * @parent: pvt data - Pointer to parent link device its connected with
+ * @entry: entry to the list of connected devices in link
+ */
+struct cam_req_mgr_connected_device {
+	int32_t dev_hdl;
+	int64_t dev_bit;
+	int64_t available_req_id;
+	int64_t processing_req_id;
+	struct cam_req_mgr_device_info dev_info;
+	struct cam_req_mgr_kmd_ops *ops;
+	void *parent;
+	struct list_head entry;
+};
+
+/**
+ * struct cam_req_mgr_core_link
+ * - Link Properties
+ * @link_hdl: Link identifier
+ * @num_connections: num of connected devices to this link
+ * @max_pipeline_delay: Max of pipeline delay of all connected devs
+ * - Input request queue
+ * @in_requests: Queue to hold incoming request hints from CSL
+ * @workq: Pointer to handle workq related jobs
+ * - List of connected devices
+ * @l_devices: List of connected devices to this link
+ * @fs_list: Holds the request id which each device in link will consume.
+ * @req_table: table to keep track of req ids recived at each dev handle
+ * - Link private data
+ * @link_state: link state cycle
+ * @parent: pvt data - like session info
+ * @link_head: List head of connected devices
+ * @lock: spin lock to guard link data operations
+ */
+struct cam_req_mgr_core_link {
+	int32_t link_hdl;
+	int32_t num_connections;
+	enum cam_pipeline_delay max_pipeline_delay;
+	struct cam_req_mgr_request_queue in_requests;
+	struct cam_req_mgr_core_workq *workq;
+	struct cam_req_mgr_connected_device *l_devices;
+	struct cam_req_mgr_frame_settings fs_list[CAM_REQ_MGR_MAX_LINKED_DEV];
+	struct cam_req_mgr_request_table req_table[CAM_PIPELINE_DELAY_MAX];
+	enum cam_req_mgr_link_state link_state;
+	void *parent;
+	struct list_head link_head;
+	spinlock_t lock;
+};
+
+/**
+ * struct cam_req_mgr_core_session
+ * - Session Properties
+ * @session_hdl: session identifier
+ * @num_active_links: num of active links for current session
+ * - Links of this session
+ * @links: pointer to array of links within session
+ * - Session private data
+ * @entry: pvt data - entry in the list of sessions
+ * @lock: pvt data - spin lock to guard session data
+ */
+struct cam_req_mgr_core_session {
+	int32_t session_hdl;
+	uint32_t num_active_links;
+	struct cam_req_mgr_core_link links[MAX_LINKS_PER_SESSION];
+	struct list_head entry;
+	spinlock_t lock;
+};
+
+/**
+ * struct cam_req_mgr_core_device
+ * - Core camera request manager data struct
+ * @session_head: list head holding sessions
+ * @crm_lock: mutex lock to protect session creation & destruction
+ */
+struct cam_req_mgr_core_device {
+	struct list_head session_head;
+	struct mutex crm_lock;
+};
+
+/* cam_req_mgr_dev to cam_req_mgr_core internal functions */
+/**
+ * cam_req_mgr_create_session()
+ * @brief: creates session
+ * @ses_info: output param for session handle
+ *
+ * Called as part of session creation.
+ */
+int cam_req_mgr_create_session(
+	struct cam_req_mgr_session_info *ses_info);
+
+/**
+ * cam_req_mgr_destroy_session()
+ * @brief: destroy session
+ * @ses_info: session handle info, input param
+ *
+ * Called as part of session destroy
+ * return success/failure
+ */
+int cam_req_mgr_destroy_session(
+	struct cam_req_mgr_session_info *ses_info);
+
+/**
+ * cam_req_mgr_link()
+ * @brief: creates a link for a session
+ * @link_info: handle and session info to create a link
+ *
+ * Link is formed in a session for multiple devices. It creates
+ * a unique link handle for the link and is specific to a
+ * session. Returns link handle
+ */
+int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info);
+
+/**
+ * cam_req_mgr_unlink()
+ * @brief: destroy a link in a session
+ * @unlink_info: session and link handle info
+ *
+ * Link is destroyed in a session
+ */
+int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info);
+
+/**
+ * cam_req_mgr_schedule_request()
+ * @brief: Request is scheduled
+ * @sched_req: request id, session and link id info, bubble recovery info
+ */
+int cam_req_mgr_schedule_request(
+	struct cam_req_mgr_sched_request *sched_req);
+
+/**
+ * cam_req_mgr_sync_mode()
+ * @brief: sync for links in a session
+ * @sync_links: session, links info and master link info
+ */
+int cam_req_mgr_sync_mode(struct cam_req_mgr_sync_mode *sync_links);
+
+/**
+ * cam_req_mgr_flush_requests()
+ * @brief: flush all requests
+ * @flush_info: requests related to link and session
+ */
+int cam_req_mgr_flush_requests(
+	struct cam_req_mgr_flush_info *flush_info);
+
+/**
+ * cam_req_mgr_core_device_init()
+ * @brief: initialize crm core
+ */
+int cam_req_mgr_core_device_init(void);
+
+/**
+ * cam_req_mgr_core_device_deinit()
+ * @brief: cleanp crm core
+ */
+int cam_req_mgr_core_device_deinit(void);
+#endif
+
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core_defs.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core_defs.h
new file mode 100644
index 0000000..cf2fe7f
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core_defs.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2016-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 CRM_TRACE_ENABLE 0
+#define CRM_DEBUG_MUTEX 0
+
+#if (CRM_TRACE_ENABLE == 1)
+	#define CRM_DBG(fmt, args...) do { \
+	trace_printk("%d: [crm_dbg] "fmt"\n", __LINE__, ##args); \
+	pr_debug("%s:%d "fmt"\n", __func__, __LINE__, ##args); \
+	} while (0)
+
+	#define CRM_WARN(fmt, args...) do { \
+	trace_printk("%d: [crm_warn] "fmt"\n", __LINE__, ##args); \
+	pr_warn("%s:%d "fmt"\n", __func__, __LINE__, ##args); \
+	} while (0)
+
+	#define CRM_ERR(fmt, args...) do { \
+	trace_printk("%d: [crm_err] "fmt"\n", __LINE__, ##args); \
+	pr_err("%s:%d "fmt"\n", __func__, __LINE__, ##args);\
+	} while (0)
+#else
+	#define CRM_DBG(fmt, args...) pr_debug("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+
+	#define CRM_WARN(fmt, args...) pr_warn("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+
+	#define CRM_ERR(fmt, args...) pr_err("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+#endif
+#endif
+
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index dfa04ec..2dba2c8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -21,6 +21,8 @@
 #include <media/v4l2-ioctl.h>
 #include <media/cam_req_mgr.h>
 #include "cam_req_mgr_dev.h"
+#include "cam_req_mgr_util.h"
+#include "cam_req_mgr_core.h"
 #include "cam_dev_mgr_util.h"
 
 #define CAM_REQ_MGR_EVENT_MAX 30
@@ -92,8 +94,76 @@
 	g_dev.v4l2_dev = NULL;
 }
 
+static int cam_req_mgr_open(struct file *filep)
+{
+	int rc;
+
+	mutex_lock(&g_dev.cam_lock);
+	if (g_dev.open_cnt >= 1) {
+		rc = -EALREADY;
+		goto end;
+	}
+
+	rc = v4l2_fh_open(filep);
+	if (rc) {
+		pr_err("v4l2_fh_open failed: %d\n", rc);
+		goto end;
+	}
+
+	spin_lock_bh(&g_dev.cam_eventq_lock);
+	g_dev.cam_eventq = filep->private_data;
+	spin_unlock_bh(&g_dev.cam_eventq_lock);
+
+	g_dev.open_cnt++;
+
+end:
+	mutex_unlock(&g_dev.cam_lock);
+	return rc;
+}
+
+static unsigned int cam_req_mgr_poll(struct file *f,
+	struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	struct v4l2_fh *eventq = f->private_data;
+
+	if (!eventq)
+		return -EINVAL;
+
+	poll_wait(f, &eventq->wait, pll_table);
+	if (v4l2_event_pending(eventq))
+		rc = POLLPRI;
+
+	return rc;
+}
+
+static int cam_req_mgr_close(struct file *filep)
+{
+	mutex_lock(&g_dev.cam_lock);
+
+	if (g_dev.open_cnt <= 0) {
+		mutex_unlock(&g_dev.cam_lock);
+		return -EINVAL;
+	}
+
+	g_dev.open_cnt--;
+	v4l2_fh_release(filep);
+
+	spin_lock_bh(&g_dev.cam_eventq_lock);
+	g_dev.cam_eventq = NULL;
+	spin_unlock_bh(&g_dev.cam_eventq_lock);
+
+	cam_req_mgr_util_free_hdls();
+	mutex_unlock(&g_dev.cam_lock);
+
+	return 0;
+}
+
 static struct v4l2_file_operations g_cam_fops = {
 	.owner  = THIS_MODULE,
+	.open   = cam_req_mgr_open,
+	.poll   = cam_req_mgr_poll,
+	.release = cam_req_mgr_close,
 	.unlocked_ioctl   = video_ioctl2,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl32 = video_ioctl2,
@@ -112,9 +182,151 @@
 	return v4l2_event_unsubscribe(fh, sub);
 }
 
+static long cam_private_ioctl(struct file *file, void *fh,
+	bool valid_prio, unsigned int cmd, void *arg)
+{
+	int rc;
+	struct cam_control *k_ioctl;
+
+	if ((!arg) || (cmd != VIDIOC_CAM_CONTROL))
+		return -EINVAL;
+
+	k_ioctl = (struct cam_control *)arg;
+
+	if (!k_ioctl->handle)
+		return -EINVAL;
+
+	switch (k_ioctl->op_code) {
+	case CAM_REQ_MGR_CREATE_SESSION: {
+		struct cam_req_mgr_session_info ses_info;
+
+		if (k_ioctl->size != sizeof(ses_info))
+			return -EINVAL;
+
+		if (copy_from_user(&ses_info,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_create_session(&ses_info);
+		if (!rc)
+			if (copy_to_user((void *)k_ioctl->handle,
+				&ses_info, k_ioctl->size))
+				rc = -EFAULT;
+		}
+		break;
+
+	case CAM_REQ_MGR_DESTROY_SESSION: {
+		struct cam_req_mgr_session_info ses_info;
+
+		if (k_ioctl->size != sizeof(ses_info))
+			return -EINVAL;
+
+		if (copy_from_user(&ses_info,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_destroy_session(&ses_info);
+		}
+		break;
+
+	case CAM_REQ_MGR_LINK: {
+		struct cam_req_mgr_link_info link_info;
+
+		if (k_ioctl->size != sizeof(link_info))
+			return -EINVAL;
+
+		if (copy_from_user(&link_info,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_link(&link_info);
+		if (!rc)
+			if (copy_to_user((void *)k_ioctl->handle,
+				&link_info, k_ioctl->size))
+				rc = -EFAULT;
+		}
+		break;
+
+	case CAM_REQ_MGR_UNLINK: {
+		struct cam_req_mgr_unlink_info unlink_info;
+
+		if (k_ioctl->size != sizeof(unlink_info))
+			return -EINVAL;
+
+		if (copy_from_user(&unlink_info,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_unlink(&unlink_info);
+		}
+		break;
+
+	case CAM_REQ_MGR_SCHED_REQ: {
+		struct cam_req_mgr_sched_request sched_req;
+
+		if (k_ioctl->size != sizeof(sched_req))
+			return -EINVAL;
+
+		if (copy_from_user(&sched_req,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_schedule_request(&sched_req);
+		}
+		break;
+
+	case CAM_REQ_MGR_FLUSH_REQ: {
+		struct cam_req_mgr_flush_info flush_info;
+
+		if (k_ioctl->size != sizeof(flush_info))
+			return -EINVAL;
+
+		if (copy_from_user(&flush_info,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_flush_requests(&flush_info);
+		}
+		break;
+
+	case CAM_REQ_MGR_SYNC_MODE: {
+		struct cam_req_mgr_sync_mode sync_mode;
+
+		if (k_ioctl->size != sizeof(sync_mode))
+			return -EINVAL;
+
+		if (copy_from_user(&sync_mode,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			return -EFAULT;
+		}
+
+		rc = cam_req_mgr_sync_mode(&sync_mode);
+		}
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return rc;
+}
+
 static const struct v4l2_ioctl_ops g_cam_ioctl_ops = {
 	.vidioc_subscribe_event = cam_subscribe_event,
 	.vidioc_unsubscribe_event = cam_unsubscribe_event,
+	.vidioc_default = cam_private_ioctl,
 };
 
 static int cam_video_device_setup(void)
@@ -231,6 +443,8 @@
 
 static int cam_req_mgr_remove(struct platform_device *pdev)
 {
+	cam_req_mgr_core_device_deinit();
+	cam_req_mgr_util_deinit();
 	cam_media_device_cleanup();
 	cam_video_device_cleanup();
 	cam_v4l2_device_cleanup();
@@ -256,12 +470,32 @@
 	if (rc)
 		goto video_setup_fail;
 
+	g_dev.open_cnt = 0;
+	mutex_init(&g_dev.cam_lock);
+	spin_lock_init(&g_dev.cam_eventq_lock);
 	g_dev.subdev_nodes_created = false;
 	mutex_init(&g_dev.dev_lock);
+
+	rc = cam_req_mgr_util_init();
+	if (rc) {
+		pr_err("cam req mgr util init is failed\n");
+		goto req_mgr_util_fail;
+	}
+
+	rc = cam_req_mgr_core_device_init();
+	if (rc) {
+		pr_err("core device setup failed\n");
+		goto req_mgr_core_fail;
+	}
+
 	g_dev.state = true;
 
 	return rc;
 
+req_mgr_core_fail:
+	cam_req_mgr_util_deinit();
+req_mgr_util_fail:
+	cam_video_device_cleanup();
 video_setup_fail:
 	cam_media_device_cleanup();
 media_setup_fail:
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
index c70e0e4..430e46e 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
@@ -22,6 +22,10 @@
  * @count: number of subdevices registered.
  * @dev_lock: lock for the subdevice count.
  * @state: state of the root device.
+ * @open_cnt: open count of subdev
+ * @cam_lock: per file handle lock
+ * @cam_eventq: event queue
+ * @cam_eventq_lock: lock for event queue
  */
 struct cam_req_mgr_device {
 	struct video_device *video;
@@ -30,6 +34,10 @@
 	int count;
 	struct mutex dev_lock;
 	bool state;
+	int32_t open_cnt;
+	struct mutex cam_lock;
+	struct v4l2_fh  *cam_eventq;
+	spinlock_t cam_eventq_lock;
 };
 
 #endif /* _CAM_REQ_MGR_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
new file mode 100644
index 0000000..174a725
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
@@ -0,0 +1,249 @@
+/* Copyright (c) 2016-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_INTERFACE_H
+#define _CAM_REQ_MGR_INTERFACE_H
+
+#include <linux/types.h>
+#include <media/cam_req_mgr.h>
+#include "cam_req_mgr_core_defs.h"
+#include "cam_req_mgr_util.h"
+
+/* Forward declarations */
+struct cam_req_mgr_sof_notify;
+struct cam_req_mgr_error_notify;
+struct cam_req_mgr_add_request;
+struct cam_req_mgr_device_info;
+struct cam_req_mgr_core_dev_link_setup;
+struct cam_req_mgr_apply_request;
+
+/*Ops table for req mgr - kmd communication */
+
+/* Request Manager -- camera device driver interface */
+/**
+ * @brief: camera kernel drivers  to cam req mgr communication
+ *
+ * @cam_req_mgr_notify_sof: for device which generates sof to inform CRM
+ * @cam_req_mgr_notify_err: device use this to inform about different errors.
+ * @cam_req_mgr_add_req: to info CRm about new rqeuest received from userspace
+ */
+typedef int (*cam_req_mgr_notify_sof)(struct cam_req_mgr_sof_notify *);
+typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *);
+typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *);
+
+/**
+ * @brief: cam req mgr to camera device drivers
+ *
+ * @cam_req_mgr_get_dev_info: to fetch details about device linked
+ * @cam_req_mgr_link_setup: to establish link with device for a session
+ * @cam_req_mgr_notify_err: to broadcast error happened on link for request id
+ * @cam_req_mgr_apply_req: CRM asks device to apply certain request id.
+ */
+typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *);
+typedef int (*cam_req_mgr_link_setup)(
+	struct cam_req_mgr_core_dev_link_setup *);
+typedef int (*cam_req_mgr_apply_req)(struct cam_req_mgr_apply_request *);
+
+/**
+ * @brief: cam_req_mgr_crm_cb - func table
+ *
+ * @notify_sof: payload for sof indication event
+ * @notify_err: payload for different error occurred at device
+ * @add_req: pauload to inform which device and what request is received
+ */
+struct cam_req_mgr_crm_cb {
+	cam_req_mgr_notify_sof  notify_sof;
+	cam_req_mgr_notify_err  notify_err;
+	cam_req_mgr_add_req     add_req;
+};
+
+/**
+ * @brief: cam_req_mgr_kmd_ops - func table
+ *
+ * @get_dev_info: payload to fetch device details
+ * @link_setup: payload to establish link with device
+ * @apply_req: payload to apply request id on a device linked
+ */
+struct cam_req_mgr_kmd_ops {
+	cam_req_mgr_get_dev_info      get_dev_info;
+	cam_req_mgr_link_setup        link_setup;
+	cam_req_mgr_apply_req         apply_req;
+};
+
+/**
+ * enum cam_pipeline_delay
+ * @brief: enumerator for different pipeline delays in camera
+ *
+ * @DELAY_0: device processed settings on same frame
+ * @DELAY_1: device processed settings after 1 frame
+ * @DELAY_2: device processed settings after 2 frames
+ * @DELAY_MAX: maximum supported pipeline delay
+ */
+enum cam_pipeline_delay {
+	CAM_PIPELINE_DELAY_0,
+	CAM_PIPELINE_DELAY_1,
+	CAM_PIPELINE_DELAY_2,
+	CAM_PIPELINE_DELAY_MAX,
+};
+
+/**
+ * enum cam_req_status
+ * @brief: enumerator for request status
+ *
+ * @SUCCESS: device processed settings successfully
+ * @FAILED: device processed settings failed
+ * @MAX: invalid status value
+ */
+enum cam_req_status {
+	CAM_REQ_STATUS_SUCCESS,
+	CAM_REQ_STATUS_FAILED,
+	CAM_REQ_STATUS_MAX,
+};
+
+/**
+ * enum cam_req_mgr_device_error
+ * @brief: enumerator for different errors occurred at device
+ *
+ * @NOT_FOUND: settings asked by request manager is not found
+ * @BUBBLE: device hit timing issue and is able to recover
+ * @FATAL: device is in bad shape and can not recover from error
+ * @PAGE_FAULT: Page fault while accessing memory
+ * @OVERFLOW: Bus Overflow for IFE/VFE
+ * @TIMEOUT: Timeout from cci or bus.
+ * @MAX: Invalid error value
+ */
+enum cam_req_mgr_device_error {
+	CRM_KMD_ERR_NOT_FOUND,
+	CRM_KMD_ERR_BUBBLE,
+	CRM_KMD_ERR_FATAL,
+	CRM_KMD_ERR_PAGE_FAULT,
+	CRM_KMD_ERR_OVERFLOW,
+	CRM_KMD_ERR_TIMEOUT,
+	CRM_KMD_ERR_MAX,
+};
+
+/**
+ * enum cam_req_mgr_device_id
+ * @brief: enumerator for different devices in subsystem
+ *
+ * @CAM_REQ_MGR: request manager itself
+ * @SENSOR: sensor device
+ * @FLASH: LED flash or dual LED device
+ * @ACTUATOR: lens mover
+ * @IFE: Image processing device
+ * @EXTERNAL_1: third party device
+ * @EXTERNAL_2: third party device
+ * @EXTERNAL_3: third party device
+ * @MAX: invalid device id
+ */
+enum cam_req_mgr_device_id {
+	CAM_REQ_MGR_DEVICE,
+	CAM_REQ_MGR_DEVICE_SENSOR,
+	CAM_REQ_MGR_DEVICE_FLASH,
+	CAM_REQ_MGR_DEVICE_ACTUATOR,
+	CAM_REQ_MGR_DEVICE_IFE,
+	CAM_REQ_MGR_DEVICE_EXTERNAL_1,
+	CAM_REQ_MGR_DEVICE_EXTERNAL_2,
+	CAM_REQ_MGR_DEVICE_EXTERNAL_3,
+	CAM_REQ_MGR_DEVICE_ID_MAX,
+};
+
+/* Camera device driver to Req Mgr device interface */
+/**
+ * struct cam_req_mgr_sof_notify
+ * @link_hdl: link identifier
+ * @dev_hdl: device handle which has sent this req id
+ * @frame_id: frame id for internal tracking
+ */
+struct cam_req_mgr_sof_notify {
+	int32_t link_hdl;
+	int32_t dev_hdl;
+	int64_t frame_id;
+};
+
+/**
+ * struct cam_req_mgr_error_notify
+ * @link_hdl: link identifier
+ * @dev_hdl: device handle which has sent this req id
+ * @req_id: req id which hit error
+ * @error: what error device hit while processing this req
+ *
+ */
+struct cam_req_mgr_error_notify {
+	int32_t link_hdl;
+	int32_t dev_hdl;
+	int64_t req_id;
+	enum cam_req_mgr_device_error error;
+};
+
+/**
+ * struct cam_req_mgr_add_request
+ * @link_hdl: link identifier
+ * @dev_hdl: device handle which has sent this req id
+ * @req_id: req id which device is ready to process
+ *
+ */
+struct cam_req_mgr_add_request {
+	int32_t link_hdl;
+	int32_t dev_hdl;
+	int64_t req_id;
+};
+
+
+/* CRM to KMD devices */
+/**
+ * struct cam_req_mgr_device_info
+ * @dev_hdl: Input_param : device handle for reference
+ * @name: link link or unlink
+ * @dev_id: device id info
+ * @p_delay: delay between time settings applied and take effect
+ *
+ */
+struct cam_req_mgr_device_info {
+	int32_t dev_hdl;
+	char name[256];
+	enum cam_req_mgr_device_id dev_id;
+	enum cam_pipeline_delay p_delay;
+};
+
+/**
+ * struct cam_req_mgr_core_dev_link_setup
+ * @link_enable: link link or unlink
+ * @link_hdl: link identifier
+ * @dev_hdl: device handle for reference
+ * @max_delay: max pipeline delay on this link
+ * @crm_cb: callback funcs to communicate with req mgr
+ *
+ */
+struct cam_req_mgr_core_dev_link_setup {
+	bool link_enable;
+	int32_t link_hdl;
+	int32_t dev_hdl;
+	enum cam_pipeline_delay max_delay;
+	struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * struct cam_req_mgr_apply_request
+ * @link_id: link identifier
+ * @dev_hdl: device handle for cross check
+ * @request_id: request id settings to apply
+ * @report_if_bubble: report to crm if failure in applying
+ *
+ */
+struct cam_req_mgr_apply_request {
+	int32_t link_hdl;
+	int32_t dev_hdl;
+	int64_t request_id;
+	int32_t report_if_bubble;
+};
+#endif
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
new file mode 100644
index 0000000..4f75a19
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -0,0 +1,335 @@
+/* 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-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <media/cam_req_mgr.h>
+#include "cam_req_mgr_util.h"
+
+#ifdef CONFIG_CAM_REQ_MGR_UTIL_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static struct cam_req_mgr_util_hdl_tbl *hdl_tbl;
+static struct mutex hdl_tbl_mutex = __MUTEX_INITIALIZER(hdl_tbl_mutex);
+
+int cam_req_mgr_util_init(void)
+{
+	int rc = 0;
+	int bitmap_size;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (hdl_tbl) {
+		rc = -EINVAL;
+		pr_err("Hdl_tbl is already present\n");
+		goto hdl_tbl_check_failed;
+	}
+
+	hdl_tbl = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL);
+	if (!hdl_tbl) {
+		rc = -ENOMEM;
+		goto hdl_tbl_alloc_failed;
+	}
+
+	bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES) * sizeof(long);
+	hdl_tbl->bitmap = kzalloc(sizeof(bitmap_size), GFP_KERNEL);
+	if (!hdl_tbl->bitmap) {
+		rc = -ENOMEM;
+		goto bitmap_alloc_fail;
+	}
+	hdl_tbl->bits = bitmap_size * BITS_PER_BYTE;
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return rc;
+
+bitmap_alloc_fail:
+	kfree(hdl_tbl);
+	hdl_tbl = NULL;
+hdl_tbl_alloc_failed:
+hdl_tbl_check_failed:
+	mutex_unlock(&hdl_tbl_mutex);
+	return rc;
+}
+
+int cam_req_mgr_util_deinit(void)
+{
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		mutex_unlock(&hdl_tbl_mutex);
+		return -EINVAL;
+	}
+
+	kfree(hdl_tbl->bitmap);
+	hdl_tbl->bitmap = NULL;
+	kfree(hdl_tbl);
+	hdl_tbl = NULL;
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return 0;
+}
+
+int cam_req_mgr_util_free_hdls(void)
+{
+	int i = 0;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		mutex_unlock(&hdl_tbl_mutex);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) {
+		if (hdl_tbl->hdl[i].state == HDL_ACTIVE) {
+			pr_err("Dev handle = %x session_handle = %x\n",
+				hdl_tbl->hdl[i].hdl_value,
+				hdl_tbl->hdl[i].session_hdl);
+			hdl_tbl->hdl[i].state = HDL_FREE;
+			clear_bit(i, hdl_tbl->bitmap);
+		}
+	}
+	bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES);
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return 0;
+}
+
+static int32_t cam_get_free_handle_index(void)
+{
+	int idx;
+
+	idx = find_first_zero_bit(hdl_tbl->bitmap, hdl_tbl->bits);
+
+	if (idx >= CAM_REQ_MGR_MAX_HANDLES || idx < 0)
+		return -ENOSR;
+
+	set_bit(idx, hdl_tbl->bitmap);
+
+	return idx;
+}
+
+int32_t cam_create_session_hdl(void *priv)
+{
+	int idx;
+	int rand = 0;
+	int32_t handle = 0;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		mutex_unlock(&hdl_tbl_mutex);
+		return -EINVAL;
+	}
+
+	idx = cam_get_free_handle_index();
+	if (idx < 0) {
+		pr_err("Unable to create session handle\n");
+		mutex_unlock(&hdl_tbl_mutex);
+		return idx;
+	}
+
+	get_random_bytes(&rand, CAM_REQ_MGR_RND1_BYTES);
+	handle = GET_DEV_HANDLE(rand, HDL_TYPE_SESSION, idx);
+	hdl_tbl->hdl[idx].session_hdl = handle;
+	hdl_tbl->hdl[idx].hdl_value = handle;
+	hdl_tbl->hdl[idx].type = HDL_TYPE_SESSION;
+	hdl_tbl->hdl[idx].state = HDL_ACTIVE;
+	hdl_tbl->hdl[idx].priv = priv;
+	hdl_tbl->hdl[idx].ops = NULL;
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return handle;
+}
+
+int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data)
+{
+	int idx;
+	int rand = 0;
+	int32_t handle;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		mutex_unlock(&hdl_tbl_mutex);
+		return -EINVAL;
+	}
+
+	idx = cam_get_free_handle_index();
+	if (idx < 0) {
+		pr_err("Unable to create device handle\n");
+		mutex_unlock(&hdl_tbl_mutex);
+		return idx;
+	}
+
+	get_random_bytes(&rand, CAM_REQ_MGR_RND1_BYTES);
+	handle = GET_DEV_HANDLE(rand, HDL_TYPE_DEV, idx);
+	hdl_tbl->hdl[idx].session_hdl = hdl_data->session_hdl;
+	hdl_tbl->hdl[idx].hdl_value = handle;
+	hdl_tbl->hdl[idx].type = HDL_TYPE_DEV;
+	hdl_tbl->hdl[idx].state = HDL_ACTIVE;
+	hdl_tbl->hdl[idx].priv = hdl_data->priv;
+	hdl_tbl->hdl[idx].ops = hdl_data->ops;
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return handle;
+}
+
+void *cam_get_device_priv(int32_t dev_hdl)
+{
+	int idx;
+	int type;
+	void *priv;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		goto device_priv_fail;
+	}
+
+	idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl);
+	if (idx >= CAM_REQ_MGR_MAX_HANDLES) {
+		pr_err("Invalid idx\n");
+		goto device_priv_fail;
+	}
+
+	if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) {
+		pr_err("Invalid state\n");
+		goto device_priv_fail;
+	}
+
+	type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl);
+	if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) {
+		pr_err("Invalid type\n");
+		goto device_priv_fail;
+	}
+
+	if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) {
+		pr_err("Invalid hdl\n");
+		goto device_priv_fail;
+	}
+
+	priv = hdl_tbl->hdl[idx].priv;
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return priv;
+
+device_priv_fail:
+	mutex_unlock(&hdl_tbl_mutex);
+	return NULL;
+}
+
+void *cam_get_device_ops(int32_t dev_hdl)
+{
+	int idx;
+	int type;
+	void *ops;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		goto device_ops_fail;
+	}
+
+	idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl);
+	if (idx >= CAM_REQ_MGR_MAX_HANDLES) {
+		pr_err("Invalid idx\n");
+		goto device_ops_fail;
+	}
+
+	if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) {
+		pr_err("Invalid state\n");
+		goto device_ops_fail;
+	}
+
+	type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl);
+	if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) {
+		pr_err("Invalid type\n");
+		goto device_ops_fail;
+	}
+
+	if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) {
+		pr_err("Invalid hdl\n");
+		goto device_ops_fail;
+	}
+
+	ops = hdl_tbl->hdl[idx].ops;
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return ops;
+
+device_ops_fail:
+	mutex_unlock(&hdl_tbl_mutex);
+	return NULL;
+}
+
+static int cam_destroy_hdl(int32_t dev_hdl, int dev_hdl_type)
+{
+	int idx;
+	int type;
+
+	mutex_lock(&hdl_tbl_mutex);
+	if (!hdl_tbl) {
+		pr_err("Hdl tbl is NULL\n");
+		goto destroy_hdl_fail;
+	}
+
+	idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl);
+	if (idx >= CAM_REQ_MGR_MAX_HANDLES) {
+		pr_err("Invalid idx\n");
+		goto destroy_hdl_fail;
+	}
+
+	if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) {
+		pr_err("Invalid state\n");
+		goto destroy_hdl_fail;
+	}
+
+	type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl);
+	if (type != dev_hdl_type) {
+		pr_err("Invalid type %d, %d\n", type, dev_hdl_type);
+		goto destroy_hdl_fail;
+	}
+
+	if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) {
+		pr_err("Invalid hdl\n");
+		goto destroy_hdl_fail;
+	}
+
+	hdl_tbl->hdl[idx].state = HDL_FREE;
+	clear_bit(idx, hdl_tbl->bitmap);
+	mutex_unlock(&hdl_tbl_mutex);
+
+	return 0;
+
+destroy_hdl_fail:
+	mutex_unlock(&hdl_tbl_mutex);
+	return -EINVAL;
+}
+
+int cam_destroy_device_hdl(int32_t dev_hdl)
+{
+	return cam_destroy_hdl(dev_hdl, HDL_TYPE_DEV);
+}
+
+int cam_destroy_session_hdl(int32_t dev_hdl)
+{
+	return cam_destroy_hdl(dev_hdl, HDL_TYPE_SESSION);
+}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h
new file mode 100644
index 0000000..21cd6dd
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.h
@@ -0,0 +1,172 @@
+/* Copyright (c) 2016-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_UTIL_API_H_
+#define _CAM_REQ_MGR_UTIL_API_H_
+
+#include <media/cam_req_mgr.h>
+#include "cam_req_mgr_util_priv.h"
+
+/**
+ * state of a handle(session/device)
+ * @HDL_FREE: free handle
+ * @HDL_ACTIVE: active handles
+ */
+enum hdl_state {
+	HDL_FREE,
+	HDL_ACTIVE
+};
+
+/**
+ * handle type
+ * @HDL_TYPE_DEV: for device and link
+ * @HDL_TYPE_SESSION: for session
+ */
+enum hdl_type {
+	HDL_TYPE_DEV = 1,
+	HDL_TYPE_SESSION
+};
+
+/**
+ * struct handle
+ * @session_hdl: session handle
+ * @hdl_value: Allocated handle
+ * @type: session/device handle
+ * @state: free/used
+ * @ops: ops structure
+ * @priv: private data of a handle
+ */
+struct handle {
+	int32_t session_hdl;
+	uint32_t hdl_value;
+	enum hdl_type type;
+	enum hdl_state state;
+	void *ops;
+	void *priv;
+};
+
+/**
+ * struct cam_req_mgr_util_hdl_tbl
+ * @hdl: row of handles
+ * @bitmap: bit map to get free hdl row idx
+ * @bits: size of bit map in bits
+ */
+struct cam_req_mgr_util_hdl_tbl {
+	struct handle hdl[CAM_REQ_MGR_MAX_HANDLES];
+	void *bitmap;
+	size_t bits;
+};
+
+/**
+ * cam_req_mgr_util APIs for KMD drivers and cam_req_mgr
+ * @session_hdl: session_hdl info
+ * @v4l2_sub_dev_flag: flag to create v4l2 sub device
+ * @media_entity_flag: flag for media entity
+ * @reserved: reserved field
+ * @ops: ops pointer for a device handle
+ * @priv: private data for a device handle
+ */
+struct cam_create_dev_hdl {
+	int32_t session_hdl;
+	int32_t v4l2_sub_dev_flag;
+	int32_t media_entity_flag;
+	int32_t reserved;
+	void *ops;
+	void *priv;
+};
+
+/**
+ * cam_create_session_hdl() - create a session handle
+ * @priv: private data for a session handle
+ *
+ * cam_req_mgr core calls this function to get
+ * a unique session handle. Returns a unique session
+ * handle
+ */
+int32_t cam_create_session_hdl(void *priv);
+
+/**
+ * cam_create_device_hdl() - create a device handle
+ * @hdl_data: session hdl, flags, ops and priv dara as input
+ *
+ * cam_req_mgr_core calls this function to get
+ * session and link handles
+ * KMD drivers calls this function to create
+ * a device handle. Returns a unique device handle
+ */
+int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data);
+
+/**
+ * cam_get_device_priv() - get private data of a handle
+ * @dev_hdl: handle for a session/link/device
+ *
+ * cam_req_mgr_core and KMD drivers use this function to
+ * get private data of a handle. Returns a private data
+ * structure pointer.
+ */
+void *cam_get_device_priv(int32_t dev_hdl);
+
+/**
+ * cam_get_device_ops() - get ops of a handle
+ * @dev_hdl: handle for a session/link/device
+ *
+ * cam_req_mgr_core and KMD drivers use this function to
+ * get ops of a handle. Returns a pointer to ops.
+ */
+void *cam_get_device_ops(int32_t dev_hdl);
+
+/**
+ * cam_destroy_device_hdl() - destroy device handle
+ * @dev_hdl: handle for a link/device.
+ *
+ * Returns success/failure
+ */
+int32_t cam_destroy_device_hdl(int32_t dev_hdl);
+
+/**
+ * cam_destroy_session_hdl() - destroy device handle
+ * @dev_hdl: handle for a session
+ *
+ * Returns success/failure
+ */
+int32_t cam_destroy_session_hdl(int32_t dev_hdl);
+
+
+/* Internal functions */
+/**
+ * cam_req_mgr_util_init() - init function of cam_req_mgr_util
+ *
+ * This is called as part of probe function to initialize
+ * handle table, bitmap, locks
+ */
+int cam_req_mgr_util_init(void);
+
+/**
+ * cam_req_mgr_util_deinit() - deinit function of cam_req_mgr_util
+ *
+ * This function is called in case of probe failure
+ */
+int32_t cam_req_mgr_util_deinit(void);
+
+/**
+ * cam_req_mgr_util_free_hdls() - free handles in case of crash
+ *
+ * Called from cam_req_mgr_dev release function to make sure
+ * all data structures are cleaned to avoid leaks
+ *
+ * cam_req_mgr core can call this function at the end of
+ * camera to make sure all stale entries are printed and
+ * cleaned
+ */
+int32_t cam_req_mgr_util_free_hdls(void);
+
+#endif /* _CAM_REQ_MGR_UTIL_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util_priv.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util_priv.h
new file mode 100644
index 0000000..8624442
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util_priv.h
@@ -0,0 +1,49 @@
+/* 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_UTIL_PRIV_H_
+#define _CAM_REQ_MGR_UTIL_PRIV_H_
+
+/**
+ * handle format:
+ * @bits (0-7): handle index
+ * @bits (8-11): handle type
+ * @bits (12-15): reserved
+ * @bits (16-23): random bits
+ * @bits (24-31): zeros
+ */
+
+#define CAM_REQ_MGR_HDL_SIZE            32
+#define CAM_REQ_MGR_RND1_SIZE           8
+#define CAM_REQ_MGR_RVD_SIZE            4
+#define CAM_REQ_MGR_HDL_TYPE_SIZE       4
+#define CAM_REQ_MGR_HDL_IDX_SIZE        8
+
+#define CAM_REQ_MGR_RND1_POS            24
+#define CAM_REQ_MGR_RVD_POS             16
+#define CAM_REQ_MGR_HDL_TYPE_POS        12
+
+#define CAM_REQ_MGR_RND1_BYTES          1
+
+#define CAM_REQ_MGR_HDL_TYPE_MASK      ((1 << CAM_REQ_MGR_HDL_TYPE_SIZE) - 1)
+
+#define GET_DEV_HANDLE(rnd1, type, idx) \
+	((rnd1 << (CAM_REQ_MGR_RND1_POS - CAM_REQ_MGR_RND1_SIZE)) | \
+	(0x0  << (CAM_REQ_MGR_RVD_POS - CAM_REQ_MGR_RVD_SIZE)) | \
+	(type << (CAM_REQ_MGR_HDL_TYPE_POS - CAM_REQ_MGR_HDL_TYPE_SIZE)) | \
+	(idx << (CAM_REQ_MGR_HDL_IDX_POS - CAM_REQ_MGR_HDL_IDX_SIZE))) \
+
+#define CAM_REQ_MGR_GET_HDL_IDX(hdl) (hdl & CAM_REQ_MGR_HDL_IDX_MASK)
+#define CAM_REQ_MGR_GET_HDL_TYPE(hdl) \
+	((hdl >> CAM_REQ_MGR_HDL_IDX_POS) & CAM_REQ_MGR_HDL_TYPE_MASK)
+
+#endif
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
new file mode 100644
index 0000000..e327723
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -0,0 +1,222 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_req_mgr_workq.h"
+
+/* workqueue's task manager methods */
+struct crm_workq_task *cam_req_mgr_workq_get_task(
+	struct cam_req_mgr_core_workq *workq)
+{
+	struct crm_workq_task *task = NULL;
+
+	if (!workq)
+		return NULL;
+
+	spin_lock(&workq->task.lock);
+	task = list_first_entry(&workq->task.empty_head,
+		struct crm_workq_task, entry);
+	if (task) {
+		atomic_sub(1, &workq->task.free_cnt);
+		list_del_init(&task->entry);
+	}
+	spin_unlock(&workq->task.lock);
+
+	return task;
+}
+
+static void cam_req_mgr_workq_put_task(struct crm_workq_task *task)
+{
+	struct cam_req_mgr_core_workq *workq =
+		(struct cam_req_mgr_core_workq *)task->parent;
+
+	task->cancel = 0;
+	task->process_cb = NULL;
+	task->priv = NULL;
+	list_add_tail(&task->entry,
+		&workq->task.empty_head);
+	atomic_add(1, &workq->task.free_cnt);
+}
+
+/**
+ * cam_req_mgr_process_task() - Process the enqueued task
+ * @task: pointer to task worker thread shall process
+ */
+static int cam_req_mgr_process_task(struct crm_workq_task *task)
+{
+	struct cam_req_mgr_core_workq *workq = NULL;
+
+	if (!task)
+		return -EINVAL;
+
+	workq = (struct cam_req_mgr_core_workq *)task->parent;
+
+	switch (task->type) {
+	case CRM_WORKQ_TASK_SCHED_REQ:
+	case CRM_WORKQ_TASK_DEV_ADD_REQ:
+	case CRM_WORKQ_TASK_NOTIFY_SOF:
+	case CRM_WORKQ_TASK_NOTIFY_ACK:
+	case CRM_WORKQ_TASK_NOTIFY_ERR:
+		if (task->process_cb)
+			task->process_cb(task->priv, &task->u);
+		else
+			CRM_WARN("FATAL:no task handler registered for workq!");
+		break;
+	case CRM_WORKQ_TASK_GET_DEV_INFO:
+	case CRM_WORKQ_TASK_SETUP_LINK:
+	case CRM_WORKQ_TASK_APPLY_REQ:
+		/* These tasks are not expected to be queued to
+		 * workque at the present
+		 */
+		CRM_DBG("Not supported");
+		break;
+	case CRM_WORKQ_TASK_INVALID:
+	default:
+		CRM_ERR("Invalid task type %x", task->type);
+		break;
+	}
+	cam_req_mgr_workq_put_task(task);
+
+	return 0;
+}
+
+/**
+ * cam_req_mgr_process_workq() - main loop handling
+ * @w: workqueue task pointer
+ */
+static void cam_req_mgr_process_workq(struct work_struct *w)
+{
+	struct cam_req_mgr_core_workq *workq = NULL;
+	struct crm_workq_task *task, *task_save;
+
+	if (!w) {
+		CRM_ERR("NULL task pointer can not schedule");
+		return;
+	}
+	workq = (struct cam_req_mgr_core_workq *)
+		container_of(w, struct cam_req_mgr_core_workq, work);
+
+	spin_lock(&workq->task.lock);
+	list_for_each_entry_safe(task, task_save,
+		&workq->task.process_head, entry) {
+		atomic_sub(1, &workq->task.pending_cnt);
+		list_del_init(&task->entry);
+		cam_req_mgr_process_task(task);
+	}
+	spin_unlock(&workq->task.lock);
+	CRM_DBG("processed task %p free_cnt %d",
+		task, atomic_read(&workq->task.free_cnt));
+}
+
+int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task)
+{
+	int rc = 0;
+	struct cam_req_mgr_core_workq *workq = NULL;
+
+	if (!task) {
+		CRM_WARN("NULL task pointer can not schedule");
+		rc = -EINVAL;
+		goto end;
+	}
+	workq = (struct cam_req_mgr_core_workq *)task->parent;
+	if (!workq) {
+		CRM_WARN("NULL worker pointer suspect mem corruption");
+		rc = -EINVAL;
+		goto end;
+	}
+	if (!workq->job) {
+		CRM_WARN("NULL worker pointer suspect mem corruption");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	spin_lock(&workq->task.lock);
+	if (task->cancel == 1) {
+		cam_req_mgr_workq_put_task(task);
+		CRM_WARN("task aborted and queued back to pool");
+		rc = 0;
+		spin_unlock(&workq->task.lock);
+		goto end;
+	}
+	list_add_tail(&task->entry,
+		&workq->task.process_head);
+	atomic_add(1, &workq->task.pending_cnt);
+	CRM_DBG("enq task %p pending_cnt %d",
+		task, atomic_read(&workq->task.pending_cnt));
+	spin_unlock(&workq->task.lock);
+
+	queue_work(workq->job, &workq->work);
+
+end:
+	return rc;
+}
+
+int cam_req_mgr_workq_create(char *name, struct cam_req_mgr_core_workq **workq)
+{
+	int32_t i;
+	struct crm_workq_task  *task;
+	struct cam_req_mgr_core_workq *crm_workq = NULL;
+	char buf[128] = "crm_workq-";
+
+	if (!*workq) {
+		crm_workq = (struct cam_req_mgr_core_workq *)
+			kzalloc(sizeof(struct cam_req_mgr_core_workq),
+			GFP_KERNEL);
+		if (crm_workq == NULL)
+			return -ENOMEM;
+
+		strlcat(buf, name, sizeof(buf));
+		CRM_DBG("create workque crm_workq-%s", name);
+		crm_workq->job = alloc_workqueue(buf,
+			WQ_HIGHPRI | WQ_UNBOUND, 0, NULL);
+		if (!crm_workq->job) {
+			kfree(crm_workq);
+			return -ENOMEM;
+		}
+
+		/* Workq attributes initialization */
+		INIT_WORK(&crm_workq->work, cam_req_mgr_process_workq);
+
+		/* Task attributes initialization */
+		spin_lock_init(&crm_workq->task.lock);
+		atomic_set(&crm_workq->task.pending_cnt, 0);
+		atomic_set(&crm_workq->task.free_cnt, 0);
+		INIT_LIST_HEAD(&crm_workq->task.process_head);
+		INIT_LIST_HEAD(&crm_workq->task.empty_head);
+		memset(crm_workq->task.pool, 0,
+			sizeof(struct crm_workq_task) *
+			CRM_WORKQ_NUM_TASKS);
+		for (i = 0; i < CRM_WORKQ_NUM_TASKS; i++) {
+			task = &crm_workq->task.pool[i];
+			task->parent = (void *)crm_workq;
+			/* Put all tasks in free pool */
+			cam_req_mgr_workq_put_task(task);
+		}
+		*workq = crm_workq;
+		CRM_DBG("free tasks %d",
+			atomic_read(&crm_workq->task.free_cnt));
+	}
+
+	return 0;
+}
+
+void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq *crm_workq)
+{
+	CRM_DBG("destroy workque %p", crm_workq);
+	if (crm_workq) {
+		if (crm_workq->job) {
+			destroy_workqueue(crm_workq->job);
+			crm_workq->job = NULL;
+		}
+		kfree(crm_workq);
+		crm_workq = NULL;
+	}
+}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
new file mode 100644
index 0000000..6b36abc
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
@@ -0,0 +1,146 @@
+/* Copyright (c) 2016-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_WORKER_H_
+#define _CAM_WORKER_H_
+
+#include<linux/kernel.h>
+#include<linux/module.h>
+#include<linux/init.h>
+#include<linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include "cam_req_mgr_core.h"
+
+/* Macros */
+#define CRM_WORKQ_NUM_TASKS 30
+
+/**enum crm_workq_task_type
+ * @codes: to identify which type of task is present
+ */
+enum crm_workq_task_type {
+	CRM_WORKQ_TASK_GET_DEV_INFO,
+	CRM_WORKQ_TASK_SETUP_LINK,
+	CRM_WORKQ_TASK_SCHED_REQ,
+	CRM_WORKQ_TASK_DEV_ADD_REQ,
+	CRM_WORKQ_TASK_APPLY_REQ,
+	CRM_WORKQ_TASK_NOTIFY_SOF,
+	CRM_WORKQ_TASK_NOTIFY_ACK,
+	CRM_WORKQ_TASK_NOTIFY_ERR,
+	CRM_WORKQ_TASK_INVALID,
+};
+
+/** struct crm_workq_task
+ * @type: type of task
+ * u -
+ * @csl_req: contains info of  incoming reqest from CSL to CRM
+ * @dev_req: contains tracking info of available req id at device
+ * @apply_req: contains info of which request is applied at device
+ * @notify_sof: contains notification from IFE to CRM about SOF trigger
+ * @notify_err: contains error inf happened while processing request
+ * @dev_info: contains info about which device is connected with CRM
+ * @link_setup: contains info about new link being setup
+ * -
+ * @process_cb: registered callback called by workq when task enqueued is ready
+ *  for processing in workq thread context
+ * @parent: workq's parent is link which is enqqueing taks to this workq
+ * @entry: list head of this list entry is worker's empty_head
+ * @cancel: if caller has got free task from pool but wants to abort or put
+ *  back without using it
+ * @priv: when task is enqueuer caller can attach cookie
+ */
+struct crm_workq_task {
+	enum crm_workq_task_type type;
+	union {
+		struct cam_req_mgr_sched_request csl_req;
+		struct cam_req_mgr_add_request dev_req;
+		struct cam_req_mgr_apply_request apply_req;
+		struct cam_req_mgr_sof_notify notify_sof;
+		struct cam_req_mgr_error_notify notify_err;
+		struct cam_req_mgr_device_info dev_info;
+		struct cam_req_mgr_core_dev_link_setup link_setup;
+	} u;
+	int (*process_cb)(void *, void *);
+	void *parent;
+	struct list_head entry;
+	uint8_t cancel;
+	void *priv;
+};
+
+/** struct crm_core_worker
+ * @work: work token used by workqueue
+ * @job: workqueue internal job struct
+ *task -
+ * @lock: lock for task structs
+ * @pending_cnt:  num of tasks pending to be processed
+ * @free_cnt:  num of free/available tasks
+ * @process_head: list  head of tasks pending process
+ * @empty_head: list  head of available tasks which can be used
+ * or acquired in order to enqueue a task to workq
+ * @pool: pool  of tasks used for handling events in workq context
+ *@num_task : size of tasks pool
+ */
+struct cam_req_mgr_core_workq {
+	struct work_struct work;
+	struct workqueue_struct *job;
+
+	struct {
+		spinlock_t lock;
+		atomic_t pending_cnt;
+		atomic_t free_cnt;
+
+		struct list_head process_head;
+		struct list_head empty_head;
+		struct crm_workq_task pool[CRM_WORKQ_NUM_TASKS];
+	} task;
+};
+
+/**
+ * cam_req_mgr_workq_create()
+ * @brief: create a workqueue
+ * @name: Name of the workque to be allocated,
+ * it is combination of session handle and link handle
+ * @workq: Double pointer worker
+ * This function will allocate and create workqueue and pass
+ * the worker pointer to caller.
+ */
+int cam_req_mgr_workq_create(char *name,
+	struct cam_req_mgr_core_workq **workq);
+
+/**
+ * cam_req_mgr_workq_destroy()
+ * @brief: destroy workqueue
+ * @workq: pointer to worker data struct
+ * this function will destroy workqueue and clean up resources
+ * associated with worker such as tasks.
+ */
+void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq *workq);
+
+/**
+ * cam_req_mgr_workq_enqueue_task()
+ * @brief: Enqueue task in worker queue
+ * @task: task to be processed by worker
+ * process callback func
+ */
+int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task);
+
+/**
+ * cam_req_mgr_workq_get_task()
+ * @brief: Returns empty task pointer for use
+ * @workq: workque used for processing
+ */
+struct crm_workq_task *cam_req_mgr_workq_get_task(
+	struct cam_req_mgr_core_workq *workq);
+
+#endif