Merge "msm: camera: Add laser LED support for depth sensor"
This commit is contained in:
commit
eb1237204c
10 changed files with 746 additions and 1 deletions
|
@ -205,6 +205,31 @@ Optional properties:
|
|||
(in the same order).
|
||||
- cam_vaf-supply : should contain regulator from which AF voltage is supplied
|
||||
|
||||
* Qualcomm Technologies, Inc. MSM LASER LED
|
||||
|
||||
Required properties:
|
||||
- cell-index : should contain unique identifier to differentiate
|
||||
between multiple laser led modules
|
||||
- reg : should contain i2c slave address of the laser led and length of
|
||||
data field which is 0x0
|
||||
- compatible :
|
||||
- "qcom,laser-led"
|
||||
- qcom,cci-master : should contain i2c master id to be used for this camera
|
||||
sensor
|
||||
- 0 -> MASTER 0
|
||||
- 1 -> MASTER 1
|
||||
|
||||
Optional properties:
|
||||
- qcom,cam-vreg-name : should contain names of all regulators needed by this
|
||||
laser led
|
||||
- qcom,cam-vreg-min-voltage : should contain minimum voltage level in microvolts
|
||||
for regulators mentioned in qcom,cam-vreg-name property (in the same order)
|
||||
- qcom,cam-vreg-max-voltage : should contain maximum voltage level in microvolts
|
||||
for regulators mentioned in qcom,cam-vreg-name property (in the same order)
|
||||
- qcom,cam-vreg-op-mode : should contain the maximum current in microamps
|
||||
required from the regulators mentioned in the qcom,cam-vreg-name property
|
||||
(in the same order).
|
||||
|
||||
* Qualcomm Technologies, Inc. MSM OIS
|
||||
|
||||
Required properties:
|
||||
|
@ -277,6 +302,13 @@ Example:
|
|||
qcom,cam-vreg-op-mode = <100000>;
|
||||
};
|
||||
|
||||
laserled0: qcom,laserled@0 {
|
||||
cell-index = <0>;
|
||||
reg = <0x0>;
|
||||
compatible = "qcom,laser-led";
|
||||
qcom,cci-master = <1>;
|
||||
};
|
||||
|
||||
qcom,camera@0 {
|
||||
cell-index = <0>;
|
||||
compatible = "qcom,camera";
|
||||
|
|
|
@ -5,4 +5,5 @@ 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/cci
|
||||
obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/
|
||||
obj-$(CONFIG_MSMB_CAMERA) += laser_led/
|
||||
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
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
|
||||
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
|
||||
obj-$(CONFIG_MSMB_CAMERA) += msm_laser_led.o
|
|
@ -0,0 +1,573 @@
|
|||
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include "msm_laser_led.h"
|
||||
#include "msm_camera_dt_util.h"
|
||||
#include "msm_sd.h"
|
||||
#include "msm_cci.h"
|
||||
|
||||
#undef CDBG
|
||||
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
|
||||
|
||||
DEFINE_MSM_MUTEX(msm_laser_led_mutex);
|
||||
|
||||
static struct v4l2_file_operations msm_laser_led_v4l2_subdev_fops;
|
||||
|
||||
static const struct of_device_id msm_laser_led_dt_match[] = {
|
||||
{.compatible = "qcom,laser-led", .data = NULL},
|
||||
{}
|
||||
};
|
||||
|
||||
static long msm_laser_led_subdev_ioctl(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
static int32_t msm_laser_led_get_subdev_id(
|
||||
struct msm_laser_led_ctrl_t *laser_led_ctrl, void __user *arg)
|
||||
{
|
||||
int32_t __user *subdev_id = (int32_t __user *)arg;
|
||||
|
||||
CDBG("Enter\n");
|
||||
if (!subdev_id) {
|
||||
pr_err("subdevice ID is not valid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (laser_led_ctrl->laser_led_device_type !=
|
||||
MSM_CAMERA_PLATFORM_DEVICE) {
|
||||
pr_err("device type is not matching\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &laser_led_ctrl->pdev->id,
|
||||
sizeof(int32_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
CDBG("Exit: subdev_id %d\n", laser_led_ctrl->pdev->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
|
||||
.i2c_read = msm_camera_cci_i2c_read,
|
||||
.i2c_read_seq = msm_camera_cci_i2c_read_seq,
|
||||
.i2c_write = msm_camera_cci_i2c_write,
|
||||
.i2c_write_table = msm_camera_cci_i2c_write_table,
|
||||
.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
|
||||
.i2c_write_table_w_microdelay =
|
||||
msm_camera_cci_i2c_write_table_w_microdelay,
|
||||
.i2c_util = msm_sensor_cci_i2c_util,
|
||||
.i2c_poll = msm_camera_cci_i2c_poll,
|
||||
};
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int32_t msm_laser_led_init(
|
||||
struct msm_laser_led_ctrl_t *laser_led_ctrl,
|
||||
struct msm_laser_led_cfg_data_t32 __user *laser_led_data)
|
||||
#else
|
||||
static int32_t msm_laser_led_init(
|
||||
struct msm_laser_led_ctrl_t *laser_led_ctrl,
|
||||
struct msm_laser_led_cfg_data_t __user *laser_led_data)
|
||||
#endif
|
||||
{
|
||||
int32_t rc = -EFAULT;
|
||||
struct msm_camera_cci_client *cci_client = NULL;
|
||||
|
||||
CDBG("Enter\n");
|
||||
|
||||
if (laser_led_ctrl->laser_led_state == MSM_CAMERA_LASER_LED_INIT) {
|
||||
pr_err("Invalid laser_led state = %d\n",
|
||||
laser_led_ctrl->laser_led_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_util(
|
||||
&laser_led_ctrl->i2c_client, MSM_CCI_INIT);
|
||||
if (rc < 0)
|
||||
pr_err("cci_init failed\n");
|
||||
|
||||
cci_client = laser_led_ctrl->i2c_client.cci_client;
|
||||
|
||||
if (copy_from_user(&(cci_client->sid),
|
||||
&(laser_led_data->i2c_addr),
|
||||
sizeof(uint16_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
cci_client->sid = cci_client->sid >> 1;
|
||||
cci_client->retries = 3;
|
||||
cci_client->id_map = 0;
|
||||
|
||||
if (copy_from_user(&(cci_client->i2c_freq_mode),
|
||||
&(laser_led_data->i2c_freq_mode),
|
||||
sizeof(enum i2c_freq_mode_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_INIT;
|
||||
|
||||
CDBG("Exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_laser_led_close(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_fh *fh) {
|
||||
int rc = 0;
|
||||
struct msm_laser_led_ctrl_t *l_ctrl = v4l2_get_subdevdata(sd);
|
||||
|
||||
CDBG("Enter\n");
|
||||
if (!l_ctrl) {
|
||||
pr_err("failed: subdev data is null\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(l_ctrl->laser_led_mutex);
|
||||
if (l_ctrl->laser_led_device_type == MSM_CAMERA_PLATFORM_DEVICE &&
|
||||
l_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_RELEASE) {
|
||||
rc = l_ctrl->i2c_client.i2c_func_tbl->i2c_util(
|
||||
&l_ctrl->i2c_client, MSM_CCI_RELEASE);
|
||||
if (rc < 0)
|
||||
pr_err("cci_init failed: %d\n", rc);
|
||||
}
|
||||
l_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE;
|
||||
mutex_unlock(l_ctrl->laser_led_mutex);
|
||||
CDBG("Exit\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long msm_laser_led_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);
|
||||
|
||||
CDBG("Enter\n");
|
||||
switch (cmd) {
|
||||
case VIDIOC_MSM_LASER_LED_CFG32:
|
||||
cmd = VIDIOC_MSM_LASER_LED_CFG;
|
||||
default:
|
||||
rc = msm_laser_led_subdev_ioctl(sd, cmd, arg);
|
||||
}
|
||||
|
||||
CDBG("Exit\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long msm_laser_led_subdev_fops_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return msm_laser_led_subdev_do_ioctl(file, cmd, (void *)arg);
|
||||
}
|
||||
|
||||
static int32_t msm_laser_led_control32(
|
||||
struct msm_laser_led_ctrl_t *laser_led_ctrl,
|
||||
void __user *argp)
|
||||
{
|
||||
struct msm_camera_i2c_reg_setting32 conf_array32;
|
||||
struct msm_camera_i2c_reg_setting conf_array;
|
||||
int32_t rc = 0;
|
||||
struct msm_laser_led_cfg_data_t32 laser_led_data;
|
||||
uint32_t *debug_reg;
|
||||
int i;
|
||||
uint16_t local_data;
|
||||
|
||||
if (laser_led_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_INIT) {
|
||||
pr_err("%s:%d failed: invalid state %d\n", __func__,
|
||||
__LINE__, laser_led_ctrl->laser_led_state);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_from_user(&laser_led_data,
|
||||
argp,
|
||||
sizeof(struct msm_laser_led_cfg_data_t32))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_from_user(&conf_array32,
|
||||
(compat_ptr)(laser_led_data.setting),
|
||||
sizeof(struct msm_camera_i2c_reg_setting32))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
conf_array.addr_type = conf_array32.addr_type;
|
||||
conf_array.data_type = conf_array32.data_type;
|
||||
conf_array.delay = conf_array32.delay;
|
||||
conf_array.size = conf_array32.size;
|
||||
|
||||
if (!conf_array.size ||
|
||||
conf_array.size > I2C_REG_DATA_MAX) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
conf_array.reg_setting = kzalloc(conf_array.size *
|
||||
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
|
||||
if (!conf_array.reg_setting)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(conf_array.reg_setting,
|
||||
(compat_ptr)(conf_array32.reg_setting),
|
||||
conf_array.size *
|
||||
sizeof(struct msm_camera_i2c_reg_array))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
kfree(conf_array.reg_setting);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
debug_reg = kzalloc(laser_led_data.debug_reg_size *
|
||||
(sizeof(uint32_t)), GFP_KERNEL);
|
||||
if (!debug_reg) {
|
||||
kfree(conf_array.reg_setting);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (copy_from_user(debug_reg,
|
||||
(void __user *)compat_ptr(laser_led_data.debug_reg),
|
||||
laser_led_data.debug_reg_size *
|
||||
sizeof(uint32_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
kfree(conf_array.reg_setting);
|
||||
kfree(debug_reg);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
laser_led_ctrl->i2c_client.addr_type = conf_array.addr_type;
|
||||
|
||||
rc = laser_led_ctrl->i2c_client.i2c_func_tbl->
|
||||
i2c_write_table(&(laser_led_ctrl->i2c_client),
|
||||
&conf_array);
|
||||
|
||||
for (i = 0; i < laser_led_data.debug_reg_size; i++) {
|
||||
rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_read(
|
||||
&(laser_led_ctrl->i2c_client),
|
||||
debug_reg[i],
|
||||
&local_data, conf_array.data_type);
|
||||
}
|
||||
|
||||
kfree(conf_array.reg_setting);
|
||||
kfree(debug_reg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int32_t msm_laser_led_control(
|
||||
struct msm_laser_led_ctrl_t *laser_led_ctrl,
|
||||
void __user *argp)
|
||||
{
|
||||
struct msm_camera_i2c_reg_setting conf_array;
|
||||
struct msm_laser_led_cfg_data_t laser_led_data;
|
||||
|
||||
uint32_t *debug_reg;
|
||||
int i;
|
||||
uint16_t local_data;
|
||||
int32_t rc = 0;
|
||||
|
||||
if (laser_led_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_INIT) {
|
||||
pr_err("%s:%d failed: invalid state %d\n", __func__,
|
||||
__LINE__, laser_led_ctrl->laser_led_state);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_from_user(&laser_led_data,
|
||||
argp,
|
||||
sizeof(struct msm_laser_led_cfg_data_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_from_user(&conf_array,
|
||||
(laser_led_data.setting),
|
||||
sizeof(struct msm_camera_i2c_reg_setting))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!conf_array.size ||
|
||||
conf_array.size > I2C_REG_DATA_MAX) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
conf_array.reg_setting = kzalloc(conf_array.size *
|
||||
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
|
||||
if (!conf_array.reg_setting)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(conf_array.reg_setting, (void __user *)(
|
||||
conf_array.reg_setting),
|
||||
conf_array.size *
|
||||
sizeof(struct msm_camera_i2c_reg_array))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
kfree(conf_array.reg_setting);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
debug_reg = kzalloc(laser_led_data.debug_reg_size *
|
||||
(sizeof(uint32_t)), GFP_KERNEL);
|
||||
if (!debug_reg) {
|
||||
kfree(conf_array.reg_setting);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (copy_from_user(debug_reg,
|
||||
(laser_led_data.debug_reg),
|
||||
laser_led_data.debug_reg_size *
|
||||
sizeof(uint32_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
kfree(debug_reg);
|
||||
kfree(conf_array.reg_setting);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
laser_led_ctrl->i2c_client.addr_type = conf_array.addr_type;
|
||||
|
||||
rc = laser_led_ctrl->i2c_client.i2c_func_tbl->
|
||||
i2c_write_table(&(laser_led_ctrl->i2c_client),
|
||||
&conf_array);
|
||||
|
||||
for (i = 0; i < laser_led_data.debug_reg_size; i++) {
|
||||
rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_read(
|
||||
&(laser_led_ctrl->i2c_client),
|
||||
debug_reg[i],
|
||||
&local_data, conf_array.data_type);
|
||||
}
|
||||
|
||||
kfree(conf_array.reg_setting);
|
||||
kfree(debug_reg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int32_t msm_laser_led_config(struct msm_laser_led_ctrl_t *laser_led_ctrl,
|
||||
void __user *argp)
|
||||
{
|
||||
int32_t rc = -EINVAL;
|
||||
enum msm_laser_led_cfg_type_t cfg_type;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct msm_laser_led_cfg_data_t32 __user *laser_led_data =
|
||||
(struct msm_laser_led_cfg_data_t32 __user *) argp;
|
||||
#else
|
||||
struct msm_laser_led_cfg_data_t __user *laser_led_data =
|
||||
(struct msm_laser_led_cfg_data_t __user *) argp;
|
||||
#endif
|
||||
|
||||
mutex_lock(laser_led_ctrl->laser_led_mutex);
|
||||
|
||||
if (copy_from_user(&(cfg_type),
|
||||
&(laser_led_data->cfg_type),
|
||||
sizeof(enum msm_laser_led_cfg_type_t))) {
|
||||
pr_err("%s:%d failed\n", __func__, __LINE__);
|
||||
mutex_unlock(laser_led_ctrl->laser_led_mutex);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
CDBG("type %d\n", cfg_type);
|
||||
|
||||
switch (cfg_type) {
|
||||
case CFG_LASER_LED_INIT:
|
||||
rc = msm_laser_led_init(laser_led_ctrl, laser_led_data);
|
||||
break;
|
||||
case CFG_LASER_LED_CONTROL:
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (is_compat_task())
|
||||
rc = msm_laser_led_control32(laser_led_ctrl, argp);
|
||||
else
|
||||
#endif
|
||||
rc = msm_laser_led_control(laser_led_ctrl, argp);
|
||||
break;
|
||||
default:
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(laser_led_ctrl->laser_led_mutex);
|
||||
|
||||
CDBG("Exit: type %d\n", cfg_type);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long msm_laser_led_subdev_ioctl(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct msm_laser_led_ctrl_t *lctrl = NULL;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
CDBG("Enter\n");
|
||||
|
||||
if (!sd) {
|
||||
pr_err(" v4l2 ir led subdevice is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
lctrl = v4l2_get_subdevdata(sd);
|
||||
if (!lctrl) {
|
||||
pr_err("lctrl NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (cmd) {
|
||||
case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
|
||||
return msm_laser_led_get_subdev_id(lctrl, argp);
|
||||
case VIDIOC_MSM_LASER_LED_CFG:
|
||||
return msm_laser_led_config(lctrl, argp);
|
||||
case MSM_SD_NOTIFY_FREEZE:
|
||||
return 0;
|
||||
case MSM_SD_SHUTDOWN:
|
||||
if (!lctrl->i2c_client.i2c_func_tbl) {
|
||||
pr_err("a_ctrl->i2c_client.i2c_func_tbl NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return msm_laser_led_close(sd, NULL);
|
||||
|
||||
default:
|
||||
pr_err("invalid cmd %d\n", cmd);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
CDBG("Exit\n");
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_core_ops msm_laser_led_subdev_core_ops = {
|
||||
.ioctl = msm_laser_led_subdev_ioctl,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops msm_laser_led_subdev_ops = {
|
||||
.core = &msm_laser_led_subdev_core_ops,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops msm_laser_led_internal_ops = {
|
||||
.close = msm_laser_led_close,
|
||||
};
|
||||
|
||||
static int32_t msm_laser_led_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
int32_t rc = 0;
|
||||
struct msm_laser_led_ctrl_t *laser_led_ctrl = NULL;
|
||||
struct msm_camera_cci_client *cci_client = NULL;
|
||||
|
||||
CDBG("Enter\n");
|
||||
if (!pdev->dev.of_node) {
|
||||
pr_err("IR LED device node is not present in device tree\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
laser_led_ctrl = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct msm_laser_led_ctrl_t), GFP_KERNEL);
|
||||
if (!laser_led_ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
laser_led_ctrl->pdev = pdev;
|
||||
|
||||
rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index",
|
||||
&pdev->id);
|
||||
CDBG("cell-index %d, rc %d\n", pdev->id, rc);
|
||||
if (rc < 0) {
|
||||
kfree(laser_led_ctrl);
|
||||
pr_err("reading cell index failed: rc %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master",
|
||||
&laser_led_ctrl->cci_master);
|
||||
CDBG("qcom,cci-master %d, rc %d\n", laser_led_ctrl->cci_master, rc);
|
||||
if (rc < 0 || laser_led_ctrl->cci_master >= MASTER_MAX) {
|
||||
kfree(laser_led_ctrl);
|
||||
pr_err("invalid cci master info: rc %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE;
|
||||
laser_led_ctrl->power_info.dev = &laser_led_ctrl->pdev->dev;
|
||||
laser_led_ctrl->laser_led_device_type = MSM_CAMERA_PLATFORM_DEVICE;
|
||||
laser_led_ctrl->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
|
||||
laser_led_ctrl->laser_led_mutex = &msm_laser_led_mutex;
|
||||
|
||||
laser_led_ctrl->i2c_client.cci_client = kzalloc(sizeof(
|
||||
struct msm_camera_cci_client), GFP_KERNEL);
|
||||
if (!laser_led_ctrl->i2c_client.cci_client)
|
||||
return -ENOMEM;
|
||||
|
||||
cci_client = laser_led_ctrl->i2c_client.cci_client;
|
||||
cci_client->cci_subdev = msm_cci_get_subdev();
|
||||
cci_client->cci_i2c_master = laser_led_ctrl->cci_master;
|
||||
|
||||
/* Initialize sub device */
|
||||
v4l2_subdev_init(&laser_led_ctrl->msm_sd.sd, &msm_laser_led_subdev_ops);
|
||||
v4l2_set_subdevdata(&laser_led_ctrl->msm_sd.sd, laser_led_ctrl);
|
||||
|
||||
laser_led_ctrl->msm_sd.sd.internal_ops = &msm_laser_led_internal_ops;
|
||||
laser_led_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
snprintf(laser_led_ctrl->msm_sd.sd.name,
|
||||
ARRAY_SIZE(laser_led_ctrl->msm_sd.sd.name),
|
||||
"msm_camera_laser_led");
|
||||
media_entity_init(&laser_led_ctrl->msm_sd.sd.entity, 0, NULL, 0);
|
||||
laser_led_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
|
||||
laser_led_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LASER_LED;
|
||||
laser_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
|
||||
msm_sd_register(&laser_led_ctrl->msm_sd);
|
||||
|
||||
laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE;
|
||||
|
||||
CDBG("laser_led sd name = %s\n",
|
||||
laser_led_ctrl->msm_sd.sd.entity.name);
|
||||
msm_laser_led_v4l2_subdev_fops = v4l2_subdev_fops;
|
||||
#ifdef CONFIG_COMPAT
|
||||
msm_laser_led_v4l2_subdev_fops.compat_ioctl32 =
|
||||
msm_laser_led_subdev_fops_ioctl;
|
||||
#endif
|
||||
laser_led_ctrl->msm_sd.sd.devnode->fops =
|
||||
&msm_laser_led_v4l2_subdev_fops;
|
||||
|
||||
CDBG("probe success\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(of, msm_laser_led_dt_match);
|
||||
|
||||
static struct platform_driver msm_laser_led_platform_driver = {
|
||||
.probe = msm_laser_led_platform_probe,
|
||||
.driver = {
|
||||
.name = "qcom,laser-led",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = msm_laser_led_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init msm_laser_led_init_module(void)
|
||||
{
|
||||
int32_t rc;
|
||||
|
||||
CDBG("Enter\n");
|
||||
rc = platform_driver_register(&msm_laser_led_platform_driver);
|
||||
if (!rc) {
|
||||
CDBG("Exit\n");
|
||||
return rc;
|
||||
}
|
||||
pr_err("laser-led driver register failed: %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit msm_laser_led_exit_module(void)
|
||||
{
|
||||
platform_driver_unregister(&msm_laser_led_platform_driver);
|
||||
}
|
||||
|
||||
module_init(msm_laser_led_init_module);
|
||||
module_exit(msm_laser_led_exit_module);
|
||||
MODULE_DESCRIPTION("MSM IR LED");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,57 @@
|
|||
/* 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 MSM_LASER_LED_H
|
||||
#define MSM_LASER_LED_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <soc/qcom/camera2.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/msmb_camera.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/msm_cam_sensor.h>
|
||||
#include "msm_camera_i2c.h"
|
||||
#include "msm_camera_dt_util.h"
|
||||
#include "msm_camera_io_util.h"
|
||||
#include "msm_sd.h"
|
||||
|
||||
|
||||
#define DEFINE_MSM_MUTEX(mutexname) \
|
||||
static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
|
||||
|
||||
enum msm_camera_laser_led_state_t {
|
||||
MSM_CAMERA_LASER_LED_INIT,
|
||||
MSM_CAMERA_LASER_LED_RELEASE,
|
||||
};
|
||||
|
||||
struct msm_laser_led_ctrl_t;
|
||||
|
||||
struct msm_laser_led_ctrl_t {
|
||||
struct msm_sd_subdev msm_sd;
|
||||
struct platform_device *pdev;
|
||||
struct msm_laser_led_func_t *func_tbl;
|
||||
struct msm_camera_power_ctrl_t power_info;
|
||||
struct i2c_driver *i2c_driver;
|
||||
struct platform_driver *pdriver;
|
||||
struct msm_camera_i2c_client i2c_client;
|
||||
enum msm_camera_device_type_t laser_led_device_type;
|
||||
struct v4l2_subdev sdev;
|
||||
struct v4l2_subdev_ops *laser_led_v4l2_subdev_ops;
|
||||
struct mutex *laser_led_mutex;
|
||||
enum msm_camera_laser_led_state_t laser_led_state;
|
||||
enum cci_i2c_master_t cci_master;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -297,6 +297,45 @@ static int32_t msm_sensor_fill_actuator_subdevid_by_name(
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int32_t msm_sensor_fill_laser_led_subdevid_by_name(
|
||||
struct msm_sensor_ctrl_t *s_ctrl)
|
||||
{
|
||||
int32_t rc = 0;
|
||||
struct device_node *src_node = NULL;
|
||||
uint32_t val = 0;
|
||||
int32_t *laser_led_subdev_id;
|
||||
struct msm_sensor_info_t *sensor_info;
|
||||
struct device_node *of_node = s_ctrl->of_node;
|
||||
|
||||
if (!of_node)
|
||||
return -EINVAL;
|
||||
|
||||
sensor_info = s_ctrl->sensordata->sensor_info;
|
||||
laser_led_subdev_id = &sensor_info->subdev_id[SUB_MODULE_LASER_LED];
|
||||
/* set sudev id to -1 and try to found new id */
|
||||
*laser_led_subdev_id = -1;
|
||||
|
||||
|
||||
src_node = of_parse_phandle(of_node, "qcom,laserled-src", 0);
|
||||
if (!src_node) {
|
||||
CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
|
||||
} else {
|
||||
rc = of_property_read_u32(src_node, "cell-index", &val);
|
||||
CDBG("%s qcom,laser led cell index %d, rc %d\n", __func__,
|
||||
val, rc);
|
||||
of_node_put(src_node);
|
||||
src_node = NULL;
|
||||
if (rc < 0) {
|
||||
pr_err("%s cell index not found %d\n",
|
||||
__func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
*laser_led_subdev_id = val;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int32_t msm_sensor_fill_flash_subdevid_by_name(
|
||||
struct msm_sensor_ctrl_t *s_ctrl)
|
||||
{
|
||||
|
@ -981,6 +1020,11 @@ CSID_TG:
|
|||
pr_err("%s failed %d\n", __func__, __LINE__);
|
||||
goto free_camera_info;
|
||||
}
|
||||
rc = msm_sensor_fill_laser_led_subdevid_by_name(s_ctrl);
|
||||
if (rc < 0) {
|
||||
pr_err("%s failed %d\n", __func__, __LINE__);
|
||||
goto free_camera_info;
|
||||
}
|
||||
|
||||
rc = msm_sensor_fill_ois_subdevid_by_name(s_ctrl);
|
||||
if (rc < 0) {
|
||||
|
|
|
@ -84,6 +84,15 @@ struct msm_ir_cut_cfg_data_t32 {
|
|||
enum msm_ir_cut_cfg_type_t cfg_type;
|
||||
};
|
||||
|
||||
struct msm_laser_led_cfg_data_t32 {
|
||||
enum msm_laser_led_cfg_type_t cfg_type;
|
||||
compat_uptr_t setting;
|
||||
compat_uptr_t debug_reg;
|
||||
uint32_t debug_reg_size;
|
||||
uint16_t i2c_addr;
|
||||
enum i2c_freq_mode_t i2c_freq_mode;
|
||||
};
|
||||
|
||||
struct eeprom_read_t32 {
|
||||
compat_uptr_t dbuffer;
|
||||
uint32_t num_bytes;
|
||||
|
@ -276,7 +285,10 @@ struct msm_flash_cfg_data_t32 {
|
|||
|
||||
#define VIDIOC_MSM_IR_CUT_CFG32 \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t32)
|
||||
#endif
|
||||
|
||||
#define VIDIOC_MSM_LASER_LED_CFG32 \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t32)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -88,6 +88,7 @@ enum sensor_sub_module_t {
|
|||
SUB_MODULE_EXT,
|
||||
SUB_MODULE_IR_LED,
|
||||
SUB_MODULE_IR_CUT,
|
||||
SUB_MODULE_LASER_LED,
|
||||
SUB_MODULE_MAX,
|
||||
};
|
||||
|
||||
|
@ -301,6 +302,15 @@ struct msm_ir_cut_cfg_data_t {
|
|||
enum msm_ir_cut_cfg_type_t cfg_type;
|
||||
};
|
||||
|
||||
struct msm_laser_led_cfg_data_t {
|
||||
enum msm_laser_led_cfg_type_t cfg_type;
|
||||
void __user *setting;
|
||||
void __user *debug_reg;
|
||||
uint32_t debug_reg_size;
|
||||
uint16_t i2c_addr;
|
||||
enum i2c_freq_mode_t i2c_freq_mode;
|
||||
};
|
||||
|
||||
struct msm_eeprom_cfg_data {
|
||||
enum eeprom_cfg_type_t cfgtype;
|
||||
uint8_t is_supported;
|
||||
|
@ -618,5 +628,8 @@ struct sensor_init_cfg_data {
|
|||
#define VIDIOC_MSM_IR_CUT_CFG \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t)
|
||||
|
||||
#define VIDIOC_MSM_LASER_LED_CFG \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -208,6 +208,13 @@ enum msm_ir_led_cfg_type_t {
|
|||
#define CFG_IR_LED_OFF CFG_IR_LED_OFF
|
||||
#define CFG_IR_LED_ON CFG_IR_LED_ON
|
||||
|
||||
enum msm_laser_led_cfg_type_t {
|
||||
CFG_LASER_LED_INIT,
|
||||
CFG_LASER_LED_CONTROL,
|
||||
};
|
||||
#define CFG_LASER_LED_INIT CFG_LASER_LED_INIT
|
||||
#define CFG_LASER_LED_CONTROL CFG_LASER_LED_CONTROL
|
||||
|
||||
enum msm_ir_cut_cfg_type_t {
|
||||
CFG_IR_CUT_INIT = 0,
|
||||
CFG_IR_CUT_RELEASE,
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#define MSM_CAMERA_SUBDEV_IR_CUT 18
|
||||
#define MSM_CAMERA_SUBDEV_EXT 19
|
||||
#define MSM_CAMERA_SUBDEV_TOF 20
|
||||
#define MSM_CAMERA_SUBDEV_LASER_LED 21
|
||||
#define MSM_MAX_CAMERA_SENSORS 5
|
||||
|
||||
/* The below macro is defined to put an upper limit on maximum
|
||||
|
|
Loading…
Add table
Reference in a new issue