msm: camera: Add IR-LED and IR-cut filter driver

Add camera IR-LED and IR-CUT filter driver.

Change-Id: I9865635c2d1ec3df4a96fa6f229fc67ecd7c4fd9
Signed-off-by: Om Parkash <oparkash@codeaurora.org>
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/Makefile
new file mode 100644
index 0000000..2444a34
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/Makefile
@@ -0,0 +1,10 @@
+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_sensor_module/cam_res_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_ir_led_dev.o cam_ir_led_soc.o cam_ir_led_core.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.c
new file mode 100644
index 0000000..144578a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 2019, 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_ir_led_core.h"
+
+static int cam_ir_cut_on(struct cam_ir_led_ctrl *ictrl)
+{
+	if (!ictrl) {
+		CAM_ERR(CAM_IR_LED, "Ir_led control Null");
+		return -EINVAL;
+	}
+
+	gpio_direction_output(
+		ictrl->soc_info.gpio_data->cam_gpio_common_tbl[4].gpio, 0);
+	gpio_direction_input(
+		ictrl->soc_info.gpio_data->cam_gpio_common_tbl[3].gpio);
+
+	return 0;
+}
+
+static int cam_ir_cut_off(struct cam_ir_led_ctrl *ictrl)
+{
+	if (!ictrl) {
+		CAM_ERR(CAM_IR_LED, "Ir_led control Null");
+		return -EINVAL;
+	}
+
+	gpio_direction_output(
+		ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, 0);
+	gpio_direction_output(
+		ictrl->soc_info.gpio_data->cam_gpio_common_tbl[3].gpio, 0);
+	gpio_direction_input(
+		ictrl->soc_info.gpio_data->cam_gpio_common_tbl[4].gpio);
+
+	return 0;
+}
+
+static int cam_ir_led_set_intensity(struct cam_ir_led_ctrl *ictrl,
+			uint32_t ir_led_intensity)
+{
+	CAM_INFO(CAM_IR_LED, "ir_led_intensity=%d", ir_led_intensity);
+	switch (ir_led_intensity) {
+	case IRLED_INTENSITY_OFF:
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio,
+			0);
+		break;
+
+	case IRLED_INTENSITY_LEVEL1:
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio,
+			1);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio,
+			1);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio,
+			1);
+		break;
+
+	case IRLED_INTENSITY_LEVEL2:
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio,
+			1);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio,
+			0);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio,
+			1);
+		break;
+	case IRLED_INTENSITY_LEVEL3:
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio,
+			1);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio,
+			1);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio,
+			0);
+		break;
+	case IRLED_INTENSITY_LEVEL4:
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio,
+			1);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio,
+			0);
+		gpio_direction_output(
+			ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio,
+			0);
+		break;
+	}
+	return 0;
+}
+
+int cam_ir_led_parser(struct cam_ir_led_ctrl *ictrl, void *arg)
+{
+	int rc = 0;
+	uint32_t  *cmd_buf =  NULL;
+	uintptr_t generic_ptr;
+	uint32_t  *offset = NULL;
+	size_t len_of_buffer;
+	struct cam_control *ioctl_ctrl = NULL;
+	struct cam_packet *csl_packet = NULL;
+	struct cam_config_dev_cmd config;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	struct cam_ir_led_set_on_off *cam_ir_led_info = NULL;
+
+	if (!ictrl || !arg) {
+		CAM_ERR(CAM_IR_LED, "ictrl/arg is NULL");
+		return -EINVAL;
+	}
+	/* getting CSL Packet */
+	ioctl_ctrl = (struct cam_control *)arg;
+
+	if (copy_from_user((&config), u64_to_user_ptr(ioctl_ctrl->handle),
+		sizeof(config))) {
+		CAM_ERR(CAM_IR_LED, "Copy cmd handle from user failed");
+		rc = -EFAULT;
+		return rc;
+	}
+
+	rc = cam_mem_get_cpu_buf(config.packet_handle,
+		(uintptr_t *)&generic_ptr, &len_of_buffer);
+	if (rc) {
+		CAM_ERR(CAM_IR_LED, "Failed in getting the buffer : %d", rc);
+		return rc;
+	}
+
+	if (config.offset > len_of_buffer) {
+		CAM_ERR(CAM_IR_LED,
+			"offset is out of bounds: offset: %lld len: %zu",
+			config.offset, len_of_buffer);
+		return -EINVAL;
+	}
+
+	/* Add offset to the ir_led csl header */
+	csl_packet = (struct cam_packet *)(uintptr_t)(generic_ptr +
+			config.offset);
+
+	offset = (uint32_t *)((uint8_t *)&csl_packet->payload +
+		csl_packet->cmd_buf_offset);
+	cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+	rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle,
+		(uintptr_t *)&generic_ptr, &len_of_buffer);
+	if (rc < 0) {
+		CAM_ERR(CAM_IR_LED, "Failed to get the command Buffer");
+		return -EINVAL;
+	}
+
+	cmd_buf = (uint32_t *)((uint8_t *)generic_ptr +
+		cmd_desc->offset);
+	cam_ir_led_info = (struct cam_ir_led_set_on_off *)cmd_buf;
+
+	switch (csl_packet->header.op_code & 0xFFFFFF) {
+	case CAM_IR_LED_PACKET_OPCODE_ON:
+		CAM_INFO(CAM_IR_LED, ":CAM_IR_LED_PACKET_OPCODE_ON");
+		cam_ir_cut_on(ictrl);
+		cam_ir_led_set_intensity(ictrl,
+				cam_ir_led_info->ir_led_intensity);
+		break;
+	case CAM_IR_LED_PACKET_OPCODE_OFF:
+		CAM_INFO(CAM_IR_LED, "CAM_IR_LED_PACKET_OPCODE_OFF");
+		cam_ir_cut_off(ictrl);
+		break;
+	case CAM_PKT_NOP_OPCODE:
+		CAM_INFO(CAM_IR_LED, "CAM_IR_LED: CAM_PKT_NOP_OPCODE");
+		break;
+	default:
+		CAM_ERR(CAM_IR_LED, "Wrong Opcode : %d",
+			(csl_packet->header.op_code & 0xFFFFFF));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int cam_ir_led_stop_dev(struct cam_ir_led_ctrl *ictrl)
+{
+	int rc = 0;
+
+	rc = cam_ir_cut_off(ictrl);
+
+	return rc;
+}
+
+int cam_ir_led_release_dev(struct cam_ir_led_ctrl *ictrl)
+{
+	int rc = 0;
+
+	if (ictrl->device_hdl != -1) {
+		rc = cam_destroy_device_hdl(ictrl->device_hdl);
+		if (rc)
+			CAM_ERR(CAM_IR_LED,
+				"Failed in destroying device handle rc = %d",
+				rc);
+		ictrl->device_hdl = -1;
+	}
+
+	return rc;
+}
+
+void cam_ir_led_shutdown(struct cam_ir_led_ctrl *ictrl)
+{
+	int rc;
+
+	if (ictrl->ir_led_state == CAM_IR_LED_STATE_INIT)
+		return;
+
+	if ((ictrl->ir_led_state == CAM_IR_LED_STATE_CONFIG) ||
+		(ictrl->ir_led_state == CAM_IR_LED_STATE_START)) {
+		rc = cam_ir_led_stop_dev(ictrl);
+		if (rc)
+			CAM_ERR(CAM_IR_LED, "Stop Failed rc: %d", rc);
+	}
+
+	rc = cam_ir_led_release_dev(ictrl);
+	if (rc)
+		CAM_ERR(CAM_IR_LED, "Release failed rc: %d", rc);
+
+	ictrl->ir_led_state = CAM_IR_LED_STATE_INIT;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.h
new file mode 100644
index 0000000..6d50a40
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_core.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2019, 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_IR_LED_CORE_H_
+#define _CAM_IR_LED_CORE_H_
+#include "cam_ir_led_dev.h"
+
+#define IRLED_INTENSITY_OFF    0
+#define IRLED_INTENSITY_LEVEL1 1
+#define IRLED_INTENSITY_LEVEL2 2
+#define IRLED_INTENSITY_LEVEL3 3
+#define IRLED_INTENSITY_LEVEL4 4
+#define IRLED_INTENSITY_MAX    5
+
+
+int cam_ir_led_parser(struct cam_ir_led_ctrl *fctrl, void *arg);
+void cam_ir_led_shutdown(struct cam_ir_led_ctrl *ir_led_ctrl);
+int cam_ir_led_stop_dev(struct cam_ir_led_ctrl *ir_led_ctrl);
+int cam_ir_led_release_dev(struct cam_ir_led_ctrl *fctrl);
+#endif /*_CAM_IR_LED_CORE_H_*/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c
new file mode 100644
index 0000000..3ba7745
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c
@@ -0,0 +1,384 @@
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include "cam_ir_led_dev.h"
+#include "cam_ir_led_soc.h"
+#include "cam_ir_led_core.h"
+
+static int32_t cam_ir_led_driver_cmd(struct cam_ir_led_ctrl *ictrl,
+		void *arg, struct cam_ir_led_private_soc *soc_private)
+{
+	int rc = 0;
+	struct cam_control *cmd = (struct cam_control *)arg;
+
+		CAM_ERR(CAM_IR_LED, "%s, IN", __func__);
+	if (!ictrl || !arg) {
+		CAM_ERR(CAM_IR_LED, "ictrl/arg is NULL with arg:%pK ictrl%pK",
+			ictrl, arg);
+		return -EINVAL;
+	}
+
+	if (cmd->handle_type != CAM_HANDLE_USER_POINTER) {
+		CAM_ERR(CAM_IR_LED, "Invalid handle type: %d",
+			cmd->handle_type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&(ictrl->ir_led_mutex));
+	switch (cmd->op_code) {
+	case CAM_ACQUIRE_DEV: {
+		struct cam_sensor_acquire_dev ir_led_acq_dev;
+		struct cam_create_dev_hdl dev_hdl;
+
+		CAM_DBG(CAM_IR_LED, "CAM_ACQUIRE_DEV");
+
+		if (ictrl->ir_led_state != CAM_IR_LED_STATE_INIT) {
+			CAM_ERR(CAM_IR_LED,
+				" Cannot apply Acquire dev: Prev state: %d",
+				ictrl->ir_led_state);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+
+		rc = copy_from_user(&ir_led_acq_dev,
+			u64_to_user_ptr(cmd->handle),
+			sizeof(ir_led_acq_dev));
+		if (rc) {
+			CAM_ERR(CAM_IR_LED, "Failed Copy from User rc=%d", rc);
+			goto release_mutex;
+		}
+
+		dev_hdl.priv = ictrl;
+
+		ir_led_acq_dev.device_handle =
+			cam_create_device_hdl(&dev_hdl);
+		ictrl->device_hdl =
+			ir_led_acq_dev.device_handle;
+
+		rc = copy_to_user(u64_to_user_ptr(cmd->handle), &ir_led_acq_dev,
+			sizeof(struct cam_sensor_acquire_dev));
+		if (rc) {
+			CAM_ERR(CAM_IR_LED, "Failed Copy to User rc=%d", rc);
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+		ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE;
+		break;
+	}
+	case CAM_RELEASE_DEV: {
+		CAM_DBG(CAM_IR_LED, "CAM_RELEASE_DEV");
+		if ((ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) ||
+			(ictrl->ir_led_state == CAM_IR_LED_STATE_START)) {
+			CAM_WARN(CAM_IR_LED,
+				" Cannot apply Release dev: Prev state:%d",
+				ictrl->ir_led_state);
+		}
+
+		if (ictrl->device_hdl == -1 &&
+			ictrl->ir_led_state == CAM_IR_LED_STATE_ACQUIRE) {
+			CAM_ERR(CAM_IR_LED,
+				" Invalid Handle: device hdl: %d",
+				ictrl->device_hdl);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = cam_ir_led_release_dev(ictrl);
+		if (rc)
+			CAM_ERR(CAM_IR_LED,
+				" Failed in destroying the device Handle rc= %d",
+				rc);
+		ictrl->ir_led_state = CAM_IR_LED_STATE_INIT;
+		break;
+	}
+	case CAM_QUERY_CAP: {
+		struct cam_ir_led_query_cap_info ir_led_cap = {0};
+
+		CAM_DBG(CAM_IR_LED, "CAM_QUERY_CAP");
+		ir_led_cap.slot_info = ictrl->soc_info.index;
+
+		if (copy_to_user(u64_to_user_ptr(cmd->handle), &ir_led_cap,
+			sizeof(struct cam_ir_led_query_cap_info))) {
+			CAM_ERR(CAM_IR_LED, " Failed Copy to User");
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+		break;
+	}
+	case CAM_START_DEV: {
+		CAM_DBG(CAM_IR_LED, "CAM_START_DEV");
+		if ((ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) ||
+			(ictrl->ir_led_state == CAM_IR_LED_STATE_START)) {
+			CAM_ERR(CAM_IR_LED,
+				"Cannot apply Start Dev: Prev state: %d",
+				ictrl->ir_led_state);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		ictrl->ir_led_state = CAM_IR_LED_STATE_START;
+
+		break;
+	}
+	case CAM_STOP_DEV: {
+		CAM_DBG(CAM_IR_LED, "CAM_STOP_DEV ENTER");
+		if (ictrl->ir_led_state != CAM_IR_LED_STATE_START) {
+			CAM_WARN(CAM_IR_LED,
+				" Cannot apply Stop dev: Prev state is: %d",
+				ictrl->ir_led_state);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = cam_ir_led_stop_dev(ictrl);
+		if (rc) {
+			CAM_ERR(CAM_IR_LED, "Failed STOP_DEV: rc=%d\n", rc);
+			goto release_mutex;
+		}
+		ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE;
+		break;
+	}
+	case CAM_CONFIG_DEV: {
+		CAM_DBG(CAM_IR_LED, "CAM_CONFIG_DEV");
+		rc = cam_ir_led_parser(ictrl, arg);
+		if (rc) {
+			CAM_ERR(CAM_IR_LED, "Failed CONFIG_DEV: rc=%d\n", rc);
+			goto release_mutex;
+		}
+		break;
+	}
+	default:
+		CAM_ERR(CAM_IR_LED, "Invalid Opcode: %d", cmd->op_code);
+		rc = -EINVAL;
+	}
+
+release_mutex:
+	mutex_unlock(&(ictrl->ir_led_mutex));
+	return rc;
+}
+
+static const struct of_device_id cam_ir_led_dt_match[] = {
+	{.compatible = "qcom,camera-ir-led", .data = NULL},
+	{}
+};
+
+static long cam_ir_led_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct cam_ir_led_ctrl *ictrl = NULL;
+	struct cam_ir_led_private_soc *soc_private = NULL;
+
+	CAM_DBG(CAM_IR_LED, "Enter");
+
+	ictrl = v4l2_get_subdevdata(sd);
+	soc_private = ictrl->soc_info.soc_private;
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL: {
+		rc = cam_ir_led_driver_cmd(ictrl, arg,
+			soc_private);
+		break;
+	}
+	default:
+		CAM_ERR(CAM_IR_LED, " Invalid ioctl cmd type");
+		rc = -EINVAL;
+		break;
+	}
+
+	CAM_DBG(CAM_IR_LED, "Exit");
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_ir_led_subdev_do_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	struct cam_control cmd_data;
+	int32_t rc = 0;
+
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		CAM_ERR(CAM_IR_LED,
+			" Failed to copy from user_ptr=%pK size=%zu",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL: {
+		rc = cam_ir_led_subdev_ioctl(sd, cmd, &cmd_data);
+		if (rc)
+			CAM_ERR(CAM_IR_LED, "cam_ir_led_ioctl failed");
+		break;
+	}
+	default:
+		CAM_ERR(CAM_IR_LED, " Invalid compat ioctl cmd_type:%d",
+			cmd);
+		rc = -EINVAL;
+	}
+
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			CAM_ERR(CAM_IR_LED,
+				" Failed to copy to user_ptr=%pK size=%zu",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+
+	return rc;
+}
+#endif
+
+static int cam_ir_led_platform_remove(struct platform_device *pdev)
+{
+	struct cam_ir_led_ctrl *ictrl;
+
+	ictrl = platform_get_drvdata(pdev);
+	if (!ictrl) {
+		CAM_ERR(CAM_IR_LED, " Ir_led device is NULL");
+		return 0;
+	}
+
+	devm_kfree(&pdev->dev, ictrl);
+
+	return 0;
+}
+
+static int cam_ir_led_subdev_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_ir_led_ctrl *ir_led_ctrl =
+		v4l2_get_subdevdata(sd);
+
+	if (!ir_led_ctrl) {
+		CAM_ERR(CAM_IR_LED, " Ir_led ctrl ptr is NULL");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ir_led_ctrl->ir_led_mutex);
+	cam_ir_led_shutdown(ir_led_ctrl);
+	mutex_unlock(&ir_led_ctrl->ir_led_mutex);
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops cam_ir_led_subdev_core_ops = {
+	.ioctl = cam_ir_led_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_ir_led_subdev_do_ioctl
+#endif
+};
+
+static struct v4l2_subdev_ops cam_ir_led_subdev_ops = {
+	.core = &cam_ir_led_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops cam_ir_led_internal_ops = {
+	.close = cam_ir_led_subdev_close,
+};
+
+static int32_t cam_ir_led_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct cam_ir_led_ctrl *ir_led_ctrl = NULL;
+
+	CAM_ERR(CAM_IR_LED, "DBG:Enter");
+	if (!pdev->dev.of_node) {
+		CAM_ERR(CAM_IR_LED, "of_node NULL");
+		return -EINVAL;
+	}
+
+	ir_led_ctrl = kzalloc(sizeof(struct cam_ir_led_ctrl), GFP_KERNEL);
+	if (!ir_led_ctrl)
+		return -ENOMEM;
+
+	ir_led_ctrl->pdev = pdev;
+	ir_led_ctrl->soc_info.pdev = pdev;
+	ir_led_ctrl->soc_info.dev = &pdev->dev;
+	ir_led_ctrl->soc_info.dev_name = pdev->name;
+
+	rc = cam_ir_led_get_dt_data(ir_led_ctrl, &ir_led_ctrl->soc_info);
+	if (rc) {
+		CAM_ERR(CAM_IR_LED, "cam_ir_led_get_dt_data failed rc=%d", rc);
+		if (ir_led_ctrl->soc_info.soc_private != NULL) {
+			kfree(ir_led_ctrl->soc_info.soc_private);
+			ir_led_ctrl->soc_info.soc_private = NULL;
+		}
+		kfree(ir_led_ctrl);
+		ir_led_ctrl = NULL;
+		return -EINVAL;
+	}
+
+	ir_led_ctrl->v4l2_dev_str.internal_ops =
+		&cam_ir_led_internal_ops;
+	ir_led_ctrl->v4l2_dev_str.ops = &cam_ir_led_subdev_ops;
+	ir_led_ctrl->v4l2_dev_str.name = CAMX_IR_LED_DEV_NAME;
+	ir_led_ctrl->v4l2_dev_str.sd_flags =
+		V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+	ir_led_ctrl->v4l2_dev_str.ent_function = CAM_IRLED_DEVICE_TYPE;
+	ir_led_ctrl->v4l2_dev_str.token = ir_led_ctrl;
+
+	rc = cam_register_subdev(&(ir_led_ctrl->v4l2_dev_str));
+	if (rc) {
+		CAM_ERR(CAM_IR_LED, "Fail to create subdev with %d", rc);
+		goto free_resource;
+	}
+	ir_led_ctrl->device_hdl = -1;
+
+	platform_set_drvdata(pdev, ir_led_ctrl);
+	v4l2_set_subdevdata(&ir_led_ctrl->v4l2_dev_str.sd, ir_led_ctrl);
+
+	mutex_init(&(ir_led_ctrl->ir_led_mutex));
+
+	ir_led_ctrl->ir_led_state = CAM_IR_LED_STATE_INIT;
+	CAM_ERR(CAM_IR_LED, "DBG:Probe success");
+	return rc;
+free_resource:
+	kfree(ir_led_ctrl);
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, cam_ir_led_dt_match);
+
+static struct platform_driver cam_ir_led_platform_driver = {
+	.probe = cam_ir_led_platform_probe,
+	.remove = cam_ir_led_platform_remove,
+	.driver = {
+		.name = "CAM-IR-LED-DRIVER",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_ir_led_dt_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
+static int __init cam_ir_led_init_module(void)
+{
+	int32_t rc = 0;
+
+	rc = platform_driver_register(&cam_ir_led_platform_driver);
+	if (rc)
+		CAM_ERR(CAM_IR_LED, "platform probe for ir_led failed");
+
+	return rc;
+}
+
+static void __exit cam_ir_led_exit_module(void)
+{
+	platform_driver_unregister(&cam_ir_led_platform_driver);
+}
+
+module_init(cam_ir_led_init_module);
+module_exit(cam_ir_led_exit_module);
+MODULE_DESCRIPTION("CAM IR_LED");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h
new file mode 100644
index 0000000..b462adb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h
@@ -0,0 +1,140 @@
+/* Copyright (c) 2019, 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_IR_LED_DEV_H_
+#define _CAM_IR_LED_DEV_H_
+
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/cam_sensor.h>
+#include <media/cam_req_mgr.h>
+#include "cam_req_mgr_util.h"
+#include "cam_req_mgr_interface.h"
+#include "cam_subdev.h"
+#include "cam_mem_mgr.h"
+#include "cam_sensor_cmn_header.h"
+#include "cam_soc_util.h"
+#include "cam_debug_util.h"
+
+#define CAMX_IR_LED_DEV_NAME "cam-ir-led-dev"
+
+#define CAM_IR_LED_PIPELINE_DELAY 1
+
+#define CAM_IR_LED_PACKET_OPCODE_OFF 0
+#define CAM_IR_LED_PACKET_OPCODE_ON  1
+
+enum cam_ir_led_switch_trigger_ops {
+	LED_SWITCH_OFF = 0,
+	LED_SWITCH_ON,
+};
+
+enum cam_ir_led_state {
+	CAM_IR_LED_STATE_INIT = 0,
+	CAM_IR_LED_STATE_ACQUIRE,
+	CAM_IR_LED_STATE_CONFIG,
+	CAM_IR_LED_STATE_START,
+};
+
+/**
+ * struct cam_ir_led_intf_params
+ * @device_hdl   : Device Handle
+ * @session_hdl  : Session Handle
+ * @link_hdl     : Link Handle
+ * @ops          : KMD operations
+ * @crm_cb       : Callback API pointers
+ */
+struct cam_ir_led_intf_params {
+	int32_t                     device_hdl;
+	int32_t                     session_hdl;
+	int32_t                     link_hdl;
+	struct cam_req_mgr_kmd_ops  ops;
+	struct cam_req_mgr_crm_cb  *crm_cb;
+};
+
+/**
+ * struct cam_ir_led_common_attr
+ * @is_settings_valid  : Notify the valid settings
+ * @request_id         : Request id provided by umd
+ * @count              : Number of led count
+ * @cmd_type           : Command buffer type
+ */
+struct cam_ir_led_common_attr {
+	bool      is_settings_valid;
+	uint64_t  request_id;
+	uint16_t  count;
+	uint8_t   cmd_type;
+};
+
+/**
+ * struct ir_led_init_packet
+ * @cmn_attr   : Provides common attributes
+ * @ir_led_type : Ir_led type(PMIC/I2C/GPIO)
+ */
+struct cam_ir_led_init_packet {
+	struct cam_ir_led_common_attr cmn_attr;
+	uint8_t                       ir_led_type;
+};
+
+/**
+ *  struct cam_ir_led_private_soc
+ * @switch_trigger_name : Switch trigger name
+ * @ir_led_trigger_name  : Ir_led trigger name array
+ * @ir_led_op_current    : Ir_led operational current
+ * @ir_led_max_current   : Max supported current for LED in ir_led mode
+ * @ir_led_max_duration  : Max turn on duration for LED in Ir_led mode
+ * @torch_trigger_name  : Torch trigger name array
+ * @torch_op_current    : Torch operational current
+ * @torch_max_current   : Max supported current for LED in torch mode
+ */
+
+struct cam_ir_led_private_soc {
+	const char   *switch_trigger_name;
+	const char   *ir_led_trigger_name;
+	uint32_t     ir_led_op_current;
+	uint32_t     ir_led_max_current;
+	uint32_t     ir_led_max_duration;
+	const char   *torch_trigger_name;
+	uint32_t     torch_op_current;
+	uint32_t     torch_max_current;
+};
+
+/**
+ *  struct cam_ir_led_ctrl
+ * @soc_info            : Soc related information
+ * @pdev                : Platform device
+ * @of_node             : Of Node ptr
+ * @v4l2_dev_str        : V4L2 device structure
+ * @ir_led_mutex        : Mutex for ir_led operations
+ * @ir_led_state        : Current ir_led state (LOW/OFF/ON/INIT)
+ * @device_hdl          : Device Handle
+ */
+struct cam_ir_led_ctrl {
+	struct cam_hw_soc_info  soc_info;
+	struct platform_device  *pdev;
+	struct device_node      *of_node;
+	struct cam_subdev       v4l2_dev_str;
+	struct mutex            ir_led_mutex;
+	enum   cam_ir_led_state ir_led_state;
+	int32_t                 device_hdl;
+};
+
+#endif /*_CAM_IR_LED_DEV_H_*/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c
new file mode 100644
index 0000000..65b5361
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2019, 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/of.h>
+#include <linux/of_gpio.h>
+#include "cam_ir_led_soc.h"
+#include "cam_res_mgr_api.h"
+
+int cam_ir_led_get_dt_data(struct cam_ir_led_ctrl *ictrl,
+	struct cam_hw_soc_info *soc_info)
+{
+	int32_t rc = 0;
+
+	if (!ictrl) {
+		CAM_ERR(CAM_IR_LED, "NULL ir_led control structure");
+		return -EINVAL;
+	}
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0) {
+		CAM_ERR(CAM_IR_LED, "get_dt_properties failed rc %d", rc);
+		return rc;
+	}
+
+	soc_info->soc_private =
+		kzalloc(sizeof(struct cam_ir_led_private_soc), GFP_KERNEL);
+	if (!soc_info->soc_private) {
+		rc = -ENOMEM;
+		goto release_soc_res;
+	}
+
+	return rc;
+
+release_soc_res:
+	cam_soc_util_release_platform_resource(soc_info);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h
new file mode 100644
index 0000000..3a9139a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2019, 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_IR_LED_SOC_H_
+#define _CAM_IR_LED_SOC_H_
+
+#include "cam_ir_led_dev.h"
+
+int cam_ir_led_get_dt_data(struct cam_ir_led_ctrl *fctrl,
+	struct cam_hw_soc_info *soc_info);
+
+#endif /*_CAM_IR_LED_SOC_H_*/