Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit daff3cd0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: Add a driver to control IR CUT device"

parents c2a829c3 fd851759
Loading
Loading
Loading
Loading
+26 −0
Original line number Original line Diff line number Diff line
* QTI MSM IR CUT

Required properties:
- cell-index : ir cut filter hardware core index
- compatible :
    - "qcom,ir-cut"

Optional properties:
- gpios : should specify the gpios to be used for the ir cut filter.
- qcom,gpio-req-tbl-num : should contain index to gpios specific to ir cut filter
- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
    qcom,gpio-req-tbl-num property (in the same order)
- qcom,gpio-req-tbl-label : should contain name of gpios present in
    qcom,gpio-req-tbl-num property (in the same order)
- label : should contain unique ir cut filter name
Example:

qcom,ir-cut@60 {
		cell-index = <0>;
		compatible = "qcom,ir-cut";
		label = "led-ir-label";
		gpios = <&tlmm 60 0>;
		qcom,gpio-req-tbl-num = <0>;
		qcom,gpio-req-tbl-flags = <0>;
		qcom,gpio-req-tbl-label = "LED_IR_EN";
	};
+1 −1
Original line number Original line Diff line number Diff line
@@ -4,5 +4,5 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/
obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o
+48 −0
Original line number Original line Diff line number Diff line
@@ -760,6 +760,54 @@ int msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
		rc = -ENOMEM;
		rc = -ENOMEM;
		return rc;
		return rc;
	}
	}

	rc = of_property_read_u32(of_node, "qcom,gpio-ir-p", &val);
	if (rc != -EINVAL) {
		if (rc < 0) {
			pr_err("%s:%d read qcom,gpio-ir-p failed rc %d\n",
				__func__, __LINE__, rc);
			goto ERROR;
		} else if (val >= gpio_array_size) {
			pr_err("%s:%d qcom,gpio-ir-p invalid %d\n",
				__func__, __LINE__, val);
			rc = -EINVAL;
			goto ERROR;
		}

		gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_P] =
			gpio_array[val];
		gconf->gpio_num_info->valid[IR_CUT_FILTER_GPIO_P] = 1;

		CDBG("%s qcom,gpio-ir-p %d\n", __func__,
			gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_P]);
	} else {
		rc = 0;
	}

	rc = of_property_read_u32(of_node, "qcom,gpio-ir-m", &val);
	if (rc != -EINVAL) {
		if (rc < 0) {
			pr_err("%s:%d read qcom,gpio-ir-m failed rc %d\n",
				__func__, __LINE__, rc);
			goto ERROR;
		} else if (val >= gpio_array_size) {
			pr_err("%s:%d qcom,gpio-ir-m invalid %d\n",
				__func__, __LINE__, val);
			rc = -EINVAL;
			goto ERROR;
		}

		gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M] =
			gpio_array[val];

		gconf->gpio_num_info->valid[IR_CUT_FILTER_GPIO_M] = 1;

		CDBG("%s qcom,gpio-ir-m %d\n", __func__,
			gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M]);
	} else {
		rc = 0;
	}

	rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val);
	rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val);
	if (rc != -EINVAL) {
	if (rc != -EINVAL) {
		if (rc < 0) {
		if (rc < 0) {
+4 −0
Original line number Original line Diff line number Diff line
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
obj-$(CONFIG_MSMB_CAMERA) += msm_ir_cut.o
+665 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2016, 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) "%s:%d " fmt, __func__, __LINE__

#include <linux/module.h>
#include <linux/of_gpio.h>
#include "msm_ir_cut.h"
#include "msm_camera_dt_util.h"

#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)

DEFINE_MSM_MUTEX(msm_ir_cut_mutex);

static struct v4l2_file_operations msm_ir_cut_v4l2_subdev_fops;

static const struct of_device_id msm_ir_cut_dt_match[] = {
	{.compatible = "qcom,ir-cut", .data = NULL},
	{}
};

static struct msm_ir_cut_table msm_gpio_ir_cut_table;

static struct msm_ir_cut_table *ir_cut_table[] = {
	&msm_gpio_ir_cut_table,
};

static int32_t msm_ir_cut_get_subdev_id(
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl, void *arg)
{
	uint32_t *subdev_id = (uint32_t *)arg;

	CDBG("Enter\n");
	if (!subdev_id) {
		pr_err("failed\n");
		return -EINVAL;
	}
	if (MSM_CAMERA_PLATFORM_DEVICE != ir_cut_ctrl->ir_cut_device_type) {
		pr_err("failed\n");
		return -EINVAL;
	}

	*subdev_id = ir_cut_ctrl->pdev->id;

	CDBG("subdev_id %d\n", *subdev_id);
	CDBG("Exit\n");
	return 0;
}

static int32_t msm_ir_cut_init(
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
	struct msm_ir_cut_cfg_data_t *ir_cut_data)
{
	int32_t rc = 0;

	CDBG("Enter");

	rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(ir_cut_ctrl, ir_cut_data);

	CDBG("Exit");
	return rc;
}

static int32_t msm_ir_cut_release(
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl)
{
	int32_t rc = 0;

	if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_RELEASE) {
		pr_err("%s:%d Invalid ir_cut state = %d",
			__func__, __LINE__, ir_cut_ctrl->ir_cut_state);
		return 0;
	}

	rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(ir_cut_ctrl, NULL);
	if (rc < 0) {
		pr_err("%s:%d camera_ir_cut_on failed rc = %d",
			__func__, __LINE__, rc);
		return rc;
	}
	ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_RELEASE;
	return 0;
}

static int32_t msm_ir_cut_off(struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
	struct msm_ir_cut_cfg_data_t *ir_cut_data)
{
	int rc = 0;

	CDBG("Enter cut off\n");

	if (ir_cut_ctrl->gconf) {
		rc = msm_camera_request_gpio_table(
			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 1);

		if (rc < 0) {
			pr_err("ERR:%s:Failed in selecting state: %d\n",
				__func__, rc);

			return rc;
		}
	} else {
		pr_err("%s: No IR CUT GPIOs\n", __func__);
		return 0;
	}

	if (ir_cut_ctrl->cam_pinctrl_status) {
		rc = pinctrl_select_state(
			ir_cut_ctrl->pinctrl_info.pinctrl,
			ir_cut_ctrl->pinctrl_info.gpio_state_active);

		if (rc < 0)
			pr_err("ERR:%s:%d cannot set pin to active state: %d",
				__func__, __LINE__, rc);
	}

	CDBG("ERR:%s:gpio_conf->gpio_num_info->gpio_num[0] = %d",
		__func__,
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_P]);

	CDBG("ERR:%s:gpio_conf->gpio_num_info->gpio_num[1] = %d",
		__func__,
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_M]);

	gpio_set_value_cansleep(
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_P],
		0);

	gpio_set_value_cansleep(
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_M],
		1);

	if (ir_cut_ctrl->gconf) {
		rc = msm_camera_request_gpio_table(
			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 0);

		if (rc < 0) {
			pr_err("ERR:%s:Failed in selecting state: %d\n",
				__func__, rc);

			return rc;
		}
	} else {
		pr_err("%s: No IR CUT GPIOs\n", __func__);
		return 0;
	}

	CDBG("Exit\n");
	return 0;
}

static int32_t msm_ir_cut_on(
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
	struct msm_ir_cut_cfg_data_t *ir_cut_data)
{
	int rc = 0;

	CDBG("Enter ir cut on\n");

	if (ir_cut_ctrl->gconf) {
		rc = msm_camera_request_gpio_table(
			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 1);

		if (rc < 0) {
			pr_err("ERR:%s:Failed in selecting state: %d\n",
				__func__, rc);

			return rc;
		}
	} else {
		pr_err("%s: No IR CUT GPIOs\n", __func__);
		return 0;
	}

	if (ir_cut_ctrl->cam_pinctrl_status) {
		rc = pinctrl_select_state(
			ir_cut_ctrl->pinctrl_info.pinctrl,
			ir_cut_ctrl->pinctrl_info.gpio_state_active);

		if (rc < 0)
			pr_err("ERR:%s:%d cannot set pin to active state: %d",
				__func__, __LINE__, rc);
	}

	CDBG("ERR:%s: gpio_conf->gpio_num_info->gpio_num[0] = %d",
		__func__,
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_P]);

	CDBG("ERR:%s: gpio_conf->gpio_num_info->gpio_num[1] = %d",
		__func__,
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_M]);

	gpio_set_value_cansleep(
		ir_cut_ctrl->gconf->gpio_num_info->
			gpio_num[IR_CUT_FILTER_GPIO_P],
		1);

	gpio_set_value_cansleep(
		ir_cut_ctrl->gconf->
			gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M],
		1);

	if (ir_cut_ctrl->gconf) {
		rc = msm_camera_request_gpio_table(
			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 0);

		if (rc < 0) {
			pr_err("ERR:%s:Failed in selecting state: %d\n",
				__func__, rc);

			return rc;
		}
	} else {
		pr_err("%s: No IR CUT GPIOs\n", __func__);
		return 0;
	}
	CDBG("Exit\n");
	return 0;
}

static int32_t msm_ir_cut_handle_init(
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
	struct msm_ir_cut_cfg_data_t *ir_cut_data)
{
	uint32_t i = 0;
	int32_t rc = -EFAULT;
	enum msm_ir_cut_driver_type ir_cut_driver_type =
		ir_cut_ctrl->ir_cut_driver_type;

	CDBG("Enter");

	if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) {
		pr_err("%s:%d Invalid ir_cut state = %d",
			__func__, __LINE__, ir_cut_ctrl->ir_cut_state);
		return 0;
	}

	for (i = 0; i < ARRAY_SIZE(ir_cut_table); i++) {
		if (ir_cut_driver_type == ir_cut_table[i]->ir_cut_driver_type) {
			ir_cut_ctrl->func_tbl = &ir_cut_table[i]->func_tbl;
			rc = 0;
			break;
		}
	}

	if (rc < 0) {
		pr_err("%s:%d failed invalid ir_cut_driver_type %d\n",
			__func__, __LINE__, ir_cut_driver_type);
		return -EINVAL;
	}

	rc = ir_cut_ctrl->func_tbl->camera_ir_cut_init(
			ir_cut_ctrl, ir_cut_data);
	if (rc < 0) {
		pr_err("%s:%d camera_ir_cut_init failed rc = %d",
			__func__, __LINE__, rc);
		return rc;
	}

	ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_INIT;

	CDBG("Exit");
	return 0;
}

static int32_t msm_ir_cut_config(struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
	void __user *argp)
{
	int32_t rc = -EINVAL;
	struct msm_ir_cut_cfg_data_t *ir_cut_data =
		(struct msm_ir_cut_cfg_data_t *) argp;

	mutex_lock(ir_cut_ctrl->ir_cut_mutex);

	CDBG("Enter %s type %d\n", __func__, ir_cut_data->cfg_type);

	switch (ir_cut_data->cfg_type) {
	case CFG_IR_CUT_INIT:
		rc = msm_ir_cut_handle_init(ir_cut_ctrl, ir_cut_data);
		break;
	case CFG_IR_CUT_RELEASE:
		if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
			rc = ir_cut_ctrl->func_tbl->camera_ir_cut_release(
				ir_cut_ctrl);
		break;
	case CFG_IR_CUT_OFF:
		if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
			rc = ir_cut_ctrl->func_tbl->camera_ir_cut_off(
				ir_cut_ctrl, ir_cut_data);
		break;
	case CFG_IR_CUT_ON:
		if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
			rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(
				ir_cut_ctrl, ir_cut_data);
		break;
	default:
		rc = -EFAULT;
		break;
	}

	mutex_unlock(ir_cut_ctrl->ir_cut_mutex);

	CDBG("Exit %s type %d\n", __func__, ir_cut_data->cfg_type);

	return rc;
}

static long msm_ir_cut_subdev_ioctl(struct v4l2_subdev *sd,
	unsigned int cmd, void *arg)
{
	struct msm_ir_cut_ctrl_t *fctrl = NULL;
	void __user *argp = (void __user *)arg;

	CDBG("Enter\n");

	if (!sd) {
		pr_err("sd NULL\n");
		return -EINVAL;
	}
	fctrl = v4l2_get_subdevdata(sd);
	if (!fctrl) {
		pr_err("fctrl NULL\n");
		return -EINVAL;
	}
	switch (cmd) {
	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
		return msm_ir_cut_get_subdev_id(fctrl, argp);
	case VIDIOC_MSM_IR_CUT_CFG:
		return msm_ir_cut_config(fctrl, argp);
	case MSM_SD_NOTIFY_FREEZE:
		return 0;
	case MSM_SD_SHUTDOWN:
		if (!fctrl->func_tbl) {
			pr_err("fctrl->func_tbl NULL\n");
			return -EINVAL;
		} else {
			return fctrl->func_tbl->camera_ir_cut_release(fctrl);
		}
	default:
		pr_err_ratelimited("invalid cmd %d\n", cmd);
		return -ENOIOCTLCMD;
	}
	CDBG("Exit\n");
}

static struct v4l2_subdev_core_ops msm_ir_cut_subdev_core_ops = {
	.ioctl = msm_ir_cut_subdev_ioctl,
};

static struct v4l2_subdev_ops msm_ir_cut_subdev_ops = {
	.core = &msm_ir_cut_subdev_core_ops,
};
static int msm_ir_cut_close(struct v4l2_subdev *sd,
	struct v4l2_subdev_fh *fh) {

	int rc = 0;
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl = v4l2_get_subdevdata(sd);

	CDBG("Enter\n");

	if (!ir_cut_ctrl) {
		pr_err("%s: failed\n", __func__);
		return -EINVAL;
	}

	if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
		rc = ir_cut_ctrl->func_tbl->camera_ir_cut_release(
			ir_cut_ctrl);

	CDBG("Exit\n");

	return rc;
};

static const struct v4l2_subdev_internal_ops msm_ir_cut_internal_ops = {
	.close = msm_ir_cut_close,
};

static int32_t msm_ir_cut_get_gpio_dt_data(struct device_node *of_node,
		struct msm_ir_cut_ctrl_t *fctrl)
{
	int32_t rc = 0, i = 0;
	uint16_t *gpio_array = NULL;
	int16_t gpio_array_size = 0;
	struct msm_camera_gpio_conf *gconf = NULL;

	gpio_array_size = of_gpio_count(of_node);
	CDBG("%s gpio count %d\n", __func__, gpio_array_size);

	if (gpio_array_size > 0) {
		fctrl->power_info.gpio_conf =
			 kzalloc(sizeof(struct msm_camera_gpio_conf),
				 GFP_KERNEL);
		if (!fctrl->power_info.gpio_conf) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			rc = -ENOMEM;
			return rc;
		}
		gconf = fctrl->power_info.gpio_conf;

		gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t),
			GFP_KERNEL);
		if (!gpio_array)
			return -ENOMEM;
		for (i = 0; i < gpio_array_size; i++) {
			gpio_array[i] = of_get_gpio(of_node, i);
			if (((int16_t)gpio_array[i]) < 0) {
				pr_err("%s failed %d\n", __func__, __LINE__);
				rc = -EINVAL;
				goto free_gpio_array;
			}
			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
				gpio_array[i]);
		}

		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
			gpio_array, gpio_array_size);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto free_gpio_array;
		}
		kfree(gpio_array);

		if (fctrl->ir_cut_driver_type == IR_CUT_DRIVER_DEFAULT)
			fctrl->ir_cut_driver_type = IR_CUT_DRIVER_GPIO;
		CDBG("%s:%d fctrl->ir_cut_driver_type = %d", __func__, __LINE__,
			fctrl->ir_cut_driver_type);
	}

	return rc;

free_gpio_array:
	kfree(gpio_array);
	return rc;
}

static int32_t msm_ir_cut_get_dt_data(struct device_node *of_node,
	struct msm_ir_cut_ctrl_t *fctrl)
{
	int32_t rc = 0;

	CDBG("called\n");

	if (!of_node) {
		pr_err("of_node NULL\n");
		return -EINVAL;
	}

	/* Read the sub device */
	rc = of_property_read_u32(of_node, "cell-index", &fctrl->pdev->id);
	if (rc < 0) {
		pr_err("failed rc %d\n", rc);
		return rc;
	}

	fctrl->ir_cut_driver_type = IR_CUT_DRIVER_DEFAULT;

	/* Read the gpio information from device tree */
	rc = msm_ir_cut_get_gpio_dt_data(of_node, fctrl);
	if (rc < 0) {
		pr_err("%s:%d msm_ir_cut_get_gpio_dt_data failed rc %d\n",
			__func__, __LINE__, rc);
		return rc;
	}

	return rc;
}

#ifdef CONFIG_COMPAT
static long msm_ir_cut_subdev_do_ioctl(
	struct file *file, unsigned int cmd, void *arg)
{
	int32_t rc = 0;
	struct video_device *vdev = video_devdata(file);
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
	struct msm_ir_cut_cfg_data_t32 *u32 =
		(struct msm_ir_cut_cfg_data_t32 *)arg;
	struct msm_ir_cut_cfg_data_t ir_cut_data;

	CDBG("Enter");
	ir_cut_data.cfg_type = u32->cfg_type;

	switch (cmd) {
	case VIDIOC_MSM_IR_CUT_CFG32:
		cmd = VIDIOC_MSM_IR_CUT_CFG;
		break;
	default:
		return msm_ir_cut_subdev_ioctl(sd, cmd, arg);
	}

	rc = msm_ir_cut_subdev_ioctl(sd, cmd, &ir_cut_data);

	CDBG("Exit");
	return rc;
}

static long msm_ir_cut_subdev_fops_ioctl(struct file *file,
	unsigned int cmd, unsigned long arg)
{
	return video_usercopy(file, cmd, arg, msm_ir_cut_subdev_do_ioctl);
}
#endif

static int32_t msm_ir_cut_platform_probe(struct platform_device *pdev)
{
	int32_t rc = 0, i = 0;
	struct msm_ir_cut_ctrl_t *ir_cut_ctrl = NULL;

	CDBG("Enter");
	if (!pdev->dev.of_node) {
		pr_err("of_node NULL\n");
		return -EINVAL;
	}

	ir_cut_ctrl = kzalloc(sizeof(struct msm_ir_cut_ctrl_t), GFP_KERNEL);
	if (!ir_cut_ctrl)
		return -ENOMEM;

	memset(ir_cut_ctrl, 0, sizeof(struct msm_ir_cut_ctrl_t));

	ir_cut_ctrl->pdev = pdev;

	rc = msm_ir_cut_get_dt_data(pdev->dev.of_node, ir_cut_ctrl);

	if (rc < 0) {
		pr_err("%s:%d msm_ir_cut_get_dt_data failed\n",
			__func__, __LINE__);
		kfree(ir_cut_ctrl);
		return -EINVAL;
	}

	rc = msm_sensor_driver_get_gpio_data(&(ir_cut_ctrl->gconf),
		(&pdev->dev)->of_node);

	if ((rc < 0) || (ir_cut_ctrl->gconf == NULL)) {
		pr_err("%s: No IR CUT GPIOs\n", __func__);

		kfree(ir_cut_ctrl);
		return -EINVAL;
	}

	CDBG("%s: gpio_request_table_size = %d\n",
		__func__,
		ir_cut_ctrl->gconf->cam_gpio_req_tbl_size);

	for (i = 0;
		i < ir_cut_ctrl->gconf->cam_gpio_req_tbl_size; i++) {
		CDBG("%s: gpio = %d\n", __func__,
			ir_cut_ctrl->gconf->cam_gpio_req_tbl[i].gpio);
		CDBG("%s: gpio-flags = %lu\n", __func__,
			ir_cut_ctrl->gconf->cam_gpio_req_tbl[i].flags);
		CDBG("%s: gconf->gpio_num_info->gpio_num[%d] = %d\n",
			__func__, i,
			ir_cut_ctrl->gconf->gpio_num_info->gpio_num[i]);
	}

	ir_cut_ctrl->cam_pinctrl_status = 1;

	rc = msm_camera_pinctrl_init(
		&(ir_cut_ctrl->pinctrl_info), &(pdev->dev));

	if (rc < 0) {
		pr_err("ERR:%s: Error in reading IR CUT pinctrl\n",
			__func__);
		ir_cut_ctrl->cam_pinctrl_status = 0;
	}

	ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_RELEASE;
	ir_cut_ctrl->power_info.dev = &ir_cut_ctrl->pdev->dev;
	ir_cut_ctrl->ir_cut_device_type = MSM_CAMERA_PLATFORM_DEVICE;
	ir_cut_ctrl->ir_cut_mutex = &msm_ir_cut_mutex;

	/* Initialize sub device */
	v4l2_subdev_init(&ir_cut_ctrl->msm_sd.sd, &msm_ir_cut_subdev_ops);
	v4l2_set_subdevdata(&ir_cut_ctrl->msm_sd.sd, ir_cut_ctrl);

	ir_cut_ctrl->msm_sd.sd.internal_ops = &msm_ir_cut_internal_ops;
	ir_cut_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	snprintf(ir_cut_ctrl->msm_sd.sd.name,
		ARRAY_SIZE(ir_cut_ctrl->msm_sd.sd.name),
		"msm_camera_ir_cut");
	media_entity_init(&ir_cut_ctrl->msm_sd.sd.entity, 0, NULL, 0);
	ir_cut_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
	ir_cut_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_IR_CUT;
	ir_cut_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
	msm_sd_register(&ir_cut_ctrl->msm_sd);

	CDBG("%s:%d ir_cut sd name = %s", __func__, __LINE__,
		ir_cut_ctrl->msm_sd.sd.entity.name);
	msm_ir_cut_v4l2_subdev_fops = v4l2_subdev_fops;
#ifdef CONFIG_COMPAT
	msm_ir_cut_v4l2_subdev_fops.compat_ioctl32 =
		msm_ir_cut_subdev_fops_ioctl;
#endif
	ir_cut_ctrl->msm_sd.sd.devnode->fops = &msm_ir_cut_v4l2_subdev_fops;

	CDBG("probe success\n");
	return rc;
}

MODULE_DEVICE_TABLE(of, msm_ir_cut_dt_match);

static struct platform_driver msm_ir_cut_platform_driver = {
	.probe = msm_ir_cut_platform_probe,
	.driver = {
		.name = "qcom,ir-cut",
		.owner = THIS_MODULE,
		.of_match_table = msm_ir_cut_dt_match,
	},
};

static int __init msm_ir_cut_init_module(void)
{
	int32_t rc = 0;

	CDBG("Enter\n");
	rc = platform_driver_register(&msm_ir_cut_platform_driver);
	if (!rc)
		return rc;

	pr_err("platform probe for ir_cut failed");

	return rc;
}

static void __exit msm_ir_cut_exit_module(void)
{
	platform_driver_unregister(&msm_ir_cut_platform_driver);
}

static struct msm_ir_cut_table msm_gpio_ir_cut_table = {
	.ir_cut_driver_type = IR_CUT_DRIVER_GPIO,
	.func_tbl = {
		.camera_ir_cut_init = msm_ir_cut_init,
		.camera_ir_cut_release = msm_ir_cut_release,
		.camera_ir_cut_off = msm_ir_cut_off,
		.camera_ir_cut_on = msm_ir_cut_on,
	},
};

module_init(msm_ir_cut_init_module);
module_exit(msm_ir_cut_exit_module);
MODULE_DESCRIPTION("MSM IR CUT");
MODULE_LICENSE("GPL v2");
Loading