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/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
index 65c2327..dac985d 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
@@ -8,3 +8,4 @@
obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_ir_led/
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_*/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index c88e969..f91c077 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-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
@@ -455,6 +455,8 @@
s_ctrl->sensordata->subdev_id[SUB_MODULE_LED_FLASH];
query_cap->ois_slot_id =
s_ctrl->sensordata->subdev_id[SUB_MODULE_OIS];
+ query_cap->ir_led_slot_id =
+ s_ctrl->sensordata->subdev_id[SUB_MODULE_IR_LED];
query_cap->slot_info =
s_ctrl->soc_info.index;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
index e997419..4ca4d41 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-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
@@ -98,6 +98,21 @@
else
sensor_info->subdev_id[SUB_MODULE_CSIPHY] = val;
+ src_node = of_parse_phandle(of_node, "ir-led-src", 0);
+ if (!src_node) {
+ CAM_DBG(CAM_SENSOR, " src_node NULL");
+ } else {
+ rc = of_property_read_u32(src_node, "cell-index", &val);
+ CAM_DBG(CAM_SENSOR, "ir led cell index %d, rc %d", val, rc);
+ if (rc < 0) {
+ CAM_ERR(CAM_SENSOR, "failed %d", rc);
+ of_node_put(src_node);
+ return rc;
+ }
+ sensor_info->subdev_id[SUB_MODULE_IR_LED] = val;
+ of_node_put(src_node);
+ }
+
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index fddff38..1c9ee1f 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-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
@@ -132,6 +132,7 @@
SUB_MODULE_CSID,
SUB_MODULE_CSIPHY,
SUB_MODULE_OIS,
+ SUB_MODULE_IR_LED,
SUB_MODULE_EXT,
SUB_MODULE_MAX,
};
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
index 9093517..81bc47b 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-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
@@ -36,6 +36,7 @@
#define CAM_OIS (1 << 20)
#define CAM_RES (1 << 21)
#define CAM_MEM (1 << 22)
+#define CAM_IR_LED (1 << 23)
/* CAM_IRQ_CTRL: For events in irq controller */
#define CAM_IRQ_CTRL (1 << 23)