blob: c0c83e5b0e3f61ed87344dadf071905ddada922f [file] [log] [blame]
/* Copyright (c) 2011-2018, 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 "msm_sensor.h"
#include "msm_sd.h"
#include "camera.h"
#include "msm_cci.h"
#include "msm_camera_io_util.h"
#include "msm_camera_i2c_mux.h"
#include <linux/regulator/rpm-smd-regulator.h>
#include <linux/regulator/consumer.h>
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl;
static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl;
static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl)
{
int idx;
struct msm_sensor_power_setting *power_setting;
for (idx = 0; idx < ctrl->power_setting_size; idx++) {
power_setting = &ctrl->power_setting[idx];
if (power_setting->seq_type == SENSOR_CLK &&
power_setting->seq_val == SENSOR_CAM_MCLK) {
if (power_setting->config_val == 24000000) {
power_setting->config_val = 23880000;
CDBG("%s MCLK request adjusted to 23.88MHz\n"
, __func__);
}
break;
}
}
}
static void msm_sensor_misc_regulator(
struct msm_sensor_ctrl_t *sctrl, uint32_t enable)
{
int32_t rc = 0;
if (enable) {
sctrl->misc_regulator = (void *)rpm_regulator_get(
&sctrl->pdev->dev, sctrl->sensordata->misc_regulator);
if (sctrl->misc_regulator) {
rc = rpm_regulator_set_mode(sctrl->misc_regulator,
RPM_REGULATOR_MODE_HPM);
if (rc < 0) {
pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
__func__,
sctrl->sensordata->misc_regulator, rc);
rpm_regulator_put(sctrl->misc_regulator);
}
} else {
pr_err("%s: Failed to vote for rpm regulator on %s: %d\n",
__func__,
sctrl->sensordata->misc_regulator, rc);
}
} else {
if (sctrl->misc_regulator) {
rc = rpm_regulator_set_mode(
(struct rpm_regulator *)sctrl->misc_regulator,
RPM_REGULATOR_MODE_AUTO);
if (rc < 0)
pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
__func__,
sctrl->sensordata->misc_regulator, rc);
rpm_regulator_put(sctrl->misc_regulator);
}
}
}
int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
{
if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client)
return 0;
kfree(s_ctrl->sensordata->slave_info);
kfree(s_ctrl->sensordata->cam_slave_info);
kfree(s_ctrl->sensordata->actuator_info);
kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
kfree(s_ctrl->sensordata->power_info.gpio_conf);
kfree(s_ctrl->sensordata->power_info.cam_vreg);
kfree(s_ctrl->sensordata->power_info.power_setting);
kfree(s_ctrl->sensordata->power_info.power_down_setting);
kfree(s_ctrl->sensordata->csi_lane_params);
kfree(s_ctrl->sensordata->sensor_info);
if (s_ctrl->sensor_device_type == MSM_CAMERA_I2C_DEVICE) {
msm_camera_i2c_dev_put_clk_info(
&s_ctrl->sensor_i2c_client->client->dev,
&s_ctrl->sensordata->power_info.clk_info,
&s_ctrl->sensordata->power_info.clk_ptr,
s_ctrl->sensordata->power_info.clk_info_size);
} else {
msm_camera_put_clk_info(s_ctrl->pdev,
&s_ctrl->sensordata->power_info.clk_info,
&s_ctrl->sensordata->power_info.clk_ptr,
s_ctrl->sensordata->power_info.clk_info_size);
}
kfree(s_ctrl->sensordata);
return 0;
}
int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
{
struct msm_camera_power_ctrl_t *power_info;
enum msm_camera_device_type_t sensor_device_type;
struct msm_camera_i2c_client *sensor_i2c_client;
if (!s_ctrl) {
pr_err("%s:%d failed: s_ctrl %pK\n",
__func__, __LINE__, s_ctrl);
return -EINVAL;
}
if (s_ctrl->is_csid_tg_mode)
return 0;
power_info = &s_ctrl->sensordata->power_info;
sensor_device_type = s_ctrl->sensor_device_type;
sensor_i2c_client = s_ctrl->sensor_i2c_client;
if (!power_info || !sensor_i2c_client) {
pr_err("%s:%d failed: power_info %pK sensor_i2c_client %pK\n",
__func__, __LINE__, power_info, sensor_i2c_client);
return -EINVAL;
}
/* Power down secure session if it exist*/
if (s_ctrl->is_secure)
msm_camera_tz_i2c_power_down(sensor_i2c_client);
return msm_camera_power_down(power_info, sensor_device_type,
sensor_i2c_client);
}
int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
int rc;
struct msm_camera_power_ctrl_t *power_info;
struct msm_camera_i2c_client *sensor_i2c_client;
struct msm_camera_slave_info *slave_info;
const char *sensor_name;
uint32_t retry = 0;
if (!s_ctrl) {
pr_err("%s:%d failed: %pK\n",
__func__, __LINE__, s_ctrl);
return -EINVAL;
}
if (s_ctrl->is_csid_tg_mode)
return 0;
power_info = &s_ctrl->sensordata->power_info;
sensor_i2c_client = s_ctrl->sensor_i2c_client;
slave_info = s_ctrl->sensordata->slave_info;
sensor_name = s_ctrl->sensordata->sensor_name;
if (!power_info || !sensor_i2c_client || !slave_info ||
!sensor_name) {
pr_err("%s:%d failed: %pK %pK %pK %pK\n",
__func__, __LINE__, power_info,
sensor_i2c_client, slave_info, sensor_name);
return -EINVAL;
}
if (s_ctrl->set_mclk_23880000)
msm_sensor_adjust_mclk(power_info);
CDBG("Sensor %d tagged as %s\n", s_ctrl->id,
(s_ctrl->is_secure)?"SECURE":"NON-SECURE");
for (retry = 0; retry < 3; retry++) {
if (s_ctrl->is_secure) {
rc = msm_camera_tz_i2c_power_up(sensor_i2c_client);
if (rc < 0) {
#ifdef CONFIG_MSM_SEC_CCI_DEBUG
CDBG("Secure Sensor %d use cci\n", s_ctrl->id);
/* session is not secure */
s_ctrl->sensor_i2c_client->i2c_func_tbl =
&msm_sensor_cci_func_tbl;
#else /* CONFIG_MSM_SEC_CCI_DEBUG */
return rc;
#endif /* CONFIG_MSM_SEC_CCI_DEBUG */
} else {
/* session is secure */
s_ctrl->sensor_i2c_client->i2c_func_tbl =
&msm_sensor_secure_func_tbl;
}
}
rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type,
sensor_i2c_client);
if (rc < 0)
return rc;
rc = msm_sensor_check_id(s_ctrl);
if (rc < 0) {
msm_camera_power_down(power_info,
s_ctrl->sensor_device_type, sensor_i2c_client);
msleep(20);
continue;
} else {
break;
}
}
return rc;
}
static uint16_t msm_sensor_id_by_mask(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t chipid)
{
uint16_t sensor_id = chipid;
int16_t sensor_id_mask = s_ctrl->sensordata->slave_info->sensor_id_mask;
if (!sensor_id_mask)
sensor_id_mask = ~sensor_id_mask;
sensor_id &= sensor_id_mask;
sensor_id_mask &= -sensor_id_mask;
sensor_id_mask -= 1;
while (sensor_id_mask) {
sensor_id_mask >>= 1;
sensor_id >>= 1;
}
return sensor_id;
}
int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
{
int rc = 0;
uint16_t chipid = 0;
struct msm_camera_i2c_client *sensor_i2c_client;
struct msm_camera_slave_info *slave_info;
const char *sensor_name;
if (!s_ctrl) {
pr_err("%s:%d failed: %pK\n",
__func__, __LINE__, s_ctrl);
return -EINVAL;
}
sensor_i2c_client = s_ctrl->sensor_i2c_client;
slave_info = s_ctrl->sensordata->slave_info;
sensor_name = s_ctrl->sensordata->sensor_name;
if (!sensor_i2c_client || !slave_info || !sensor_name) {
pr_err("%s:%d failed: %pK %pK %pK\n",
__func__, __LINE__, sensor_i2c_client, slave_info,
sensor_name);
return -EINVAL;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
sensor_i2c_client, slave_info->sensor_id_reg_addr,
&chipid, MSM_CAMERA_I2C_WORD_DATA);
if (rc < 0) {
pr_err("%s: %s: read id failed\n", __func__, sensor_name);
return rc;
}
pr_debug("%s: read id: 0x%x expected id 0x%x:\n",
__func__, chipid, slave_info->sensor_id);
if (msm_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) {
pr_err("%s chip id %x does not match %x\n",
__func__, chipid, slave_info->sensor_id);
return -ENODEV;
}
return rc;
}
static struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
{
return container_of(container_of(sd, struct msm_sd_subdev, sd),
struct msm_sensor_ctrl_t, msm_sd);
}
static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
mutex_lock(s_ctrl->msm_sensor_mutex);
if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
kfree(s_ctrl->stop_setting.reg_setting);
s_ctrl->stop_setting.reg_setting = NULL;
if (s_ctrl->func_tbl->sensor_power_down) {
if (s_ctrl->sensordata->misc_regulator)
msm_sensor_misc_regulator(s_ctrl, 0);
rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
if (rc < 0) {
pr_err("%s:%d failed rc %d\n", __func__,
__LINE__, rc);
}
s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
s_ctrl->sensor_state);
} else {
pr_err("s_ctrl->func_tbl NULL\n");
}
}
mutex_unlock(s_ctrl->msm_sensor_mutex);
}
static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl,
void *argp)
{
/* TO-DO: Need to set AF status register address and expected value
* We need to check the AF status in the sensor register and
* set the status in the *status variable accordingly
*/
return 0;
}
static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
int rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
void *argp = (void *)arg;
if (!s_ctrl) {
pr_err("%s s_ctrl NULL\n", __func__);
return -EBADF;
}
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG:
#ifdef CONFIG_COMPAT
if (is_compat_task())
rc = s_ctrl->func_tbl->sensor_config32(s_ctrl, argp);
else
#endif
rc = s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
return rc;
case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
return msm_sensor_get_af_status(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
case MSM_SD_SHUTDOWN:
msm_sensor_stop_stream(s_ctrl);
return 0;
case MSM_SD_NOTIFY_FREEZE:
return 0;
case MSM_SD_UNNOTIFY_FREEZE:
return 0;
default:
return -ENOIOCTLCMD;
}
}
#ifdef CONFIG_COMPAT
static long msm_sensor_subdev_do_ioctl(
struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG32:
cmd = VIDIOC_MSM_SENSOR_CFG;
default:
return msm_sensor_subdev_ioctl(sd, cmd, arg);
}
}
long msm_sensor_subdev_fops_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, msm_sensor_subdev_do_ioctl);
}
static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl,
void *argp)
{
struct sensorb_cfg_data32 *cdata = (struct sensorb_cfg_data32 *)argp;
int32_t rc = 0;
int32_t i = 0;
mutex_lock(s_ctrl->msm_sensor_mutex);
CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
s_ctrl->sensordata->sensor_name, cdata->cfgtype);
switch (cdata->cfgtype) {
case CFG_GET_SENSOR_INFO:
memcpy(cdata->cfg.sensor_info.sensor_name,
s_ctrl->sensordata->sensor_name,
sizeof(cdata->cfg.sensor_info.sensor_name));
cdata->cfg.sensor_info.session_id =
s_ctrl->sensordata->sensor_info->session_id;
for (i = 0; i < SUB_MODULE_MAX; i++) {
cdata->cfg.sensor_info.subdev_id[i] =
s_ctrl->sensordata->sensor_info->subdev_id[i];
cdata->cfg.sensor_info.subdev_intf[i] =
s_ctrl->sensordata->sensor_info->subdev_intf[i];
}
cdata->cfg.sensor_info.is_mount_angle_valid =
s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
cdata->cfg.sensor_info.sensor_mount_angle =
s_ctrl->sensordata->sensor_info->sensor_mount_angle;
cdata->cfg.sensor_info.position =
s_ctrl->sensordata->sensor_info->position;
cdata->cfg.sensor_info.modes_supported =
s_ctrl->sensordata->sensor_info->modes_supported;
CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
cdata->cfg.sensor_info.sensor_name);
CDBG("%s:%d session id %d\n", __func__, __LINE__,
cdata->cfg.sensor_info.session_id);
for (i = 0; i < SUB_MODULE_MAX; i++) {
CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
cdata->cfg.sensor_info.subdev_id[i]);
CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__,
i, cdata->cfg.sensor_info.subdev_intf[i]);
}
CDBG("%s:%d mount angle valid %d value %d\n", __func__,
__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
cdata->cfg.sensor_info.sensor_mount_angle);
break;
case CFG_GET_SENSOR_INIT_PARAMS:
cdata->cfg.sensor_init_params.modes_supported =
s_ctrl->sensordata->sensor_info->modes_supported;
cdata->cfg.sensor_init_params.position =
s_ctrl->sensordata->sensor_info->position;
cdata->cfg.sensor_init_params.sensor_mount_angle =
s_ctrl->sensordata->sensor_info->sensor_mount_angle;
CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
__LINE__,
cdata->cfg.sensor_init_params.modes_supported,
cdata->cfg.sensor_init_params.position,
cdata->cfg.sensor_init_params.sensor_mount_angle);
break;
case CFG_WRITE_I2C_ARRAY:
case CFG_WRITE_I2C_ARRAY_SYNC:
case CFG_WRITE_I2C_ARRAY_SYNC_BLOCK:
case CFG_WRITE_I2C_ARRAY_ASYNC: {
struct msm_camera_i2c_reg_setting32 conf_array32;
struct msm_camera_i2c_reg_setting conf_array;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (copy_from_user(&conf_array32,
(void __user *)compat_ptr(cdata->cfg.setting),
sizeof(struct msm_camera_i2c_reg_setting32))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
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__);
rc = -EFAULT;
break;
}
reg_setting = kzalloc(conf_array.size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!reg_setting) {
rc = -ENOMEM;
break;
}
if (copy_from_user(reg_setting,
(void __user *)
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(reg_setting);
rc = -EFAULT;
break;
}
conf_array.reg_setting = reg_setting;
if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY)
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table(s_ctrl->sensor_i2c_client,
&conf_array);
else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_ASYNC)
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table_async(s_ctrl->sensor_i2c_client,
&conf_array);
else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_SYNC_BLOCK)
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table_sync_block(
s_ctrl->sensor_i2c_client,
&conf_array);
else
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table_sync(s_ctrl->sensor_i2c_client,
&conf_array);
kfree(reg_setting);
break;
}
case CFG_SLAVE_READ_I2C: {
struct msm_camera_i2c_read_config read_config;
struct msm_camera_i2c_read_config *read_config_ptr = NULL;
uint16_t local_data = 0;
uint16_t orig_slave_addr = 0, read_slave_addr = 0;
uint16_t orig_addr_type = 0, read_addr_type = 0;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
read_config_ptr =
(__force struct msm_camera_i2c_read_config *)
compat_ptr(cdata->cfg.setting);
if (copy_from_user(&read_config,
(void __user *) read_config_ptr,
sizeof(struct msm_camera_i2c_read_config))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
read_slave_addr = read_config.slave_addr;
read_addr_type = read_config.addr_type;
CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
__func__, read_config.slave_addr,
read_config.reg_addr, read_config.data_type);
if (s_ctrl->sensor_i2c_client->cci_client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->cci_client->sid;
s_ctrl->sensor_i2c_client->cci_client->sid =
read_slave_addr >> 1;
} else if (s_ctrl->sensor_i2c_client->client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->client->addr;
s_ctrl->sensor_i2c_client->client->addr =
read_slave_addr >> 1;
} else {
pr_err("%s: error: no i2c/cci client found.", __func__);
rc = -EFAULT;
break;
}
CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
__func__, orig_slave_addr,
read_slave_addr >> 1);
orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
s_ctrl->sensor_i2c_client->addr_type = read_addr_type;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
s_ctrl->sensor_i2c_client,
read_config.reg_addr,
&local_data, read_config.data_type);
if (s_ctrl->sensor_i2c_client->cci_client) {
s_ctrl->sensor_i2c_client->cci_client->sid =
orig_slave_addr;
} else if (s_ctrl->sensor_i2c_client->client) {
s_ctrl->sensor_i2c_client->client->addr =
orig_slave_addr;
}
s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
pr_debug("slave_read %x %x %x\n", read_slave_addr,
read_config.reg_addr, local_data);
if (rc < 0) {
pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
break;
}
if (copy_to_user((void __user *)(&read_config_ptr->data),
&local_data, sizeof(local_data))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
break;
}
case CFG_SLAVE_WRITE_I2C_ARRAY: {
struct msm_camera_i2c_array_write_config32 write_config32;
struct msm_camera_i2c_array_write_config write_config;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
uint16_t orig_slave_addr = 0, write_slave_addr = 0;
uint16_t orig_addr_type = 0, write_addr_type = 0;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (copy_from_user(&write_config32,
(void __user *)compat_ptr(cdata->cfg.setting),
sizeof(
struct msm_camera_i2c_array_write_config32))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
write_config.slave_addr = write_config32.slave_addr;
write_config.conf_array.addr_type =
write_config32.conf_array.addr_type;
write_config.conf_array.data_type =
write_config32.conf_array.data_type;
write_config.conf_array.delay =
write_config32.conf_array.delay;
write_config.conf_array.size =
write_config32.conf_array.size;
pr_debug("%s:CFG_SLAVE_WRITE_I2C_ARRAY:\n", __func__);
pr_debug("%s:slave_addr=0x%x, array_size=%d addr_type=%d data_type=%d\n",
__func__,
write_config.slave_addr,
write_config.conf_array.size,
write_config.conf_array.addr_type,
write_config.conf_array.data_type);
if (!write_config.conf_array.size ||
write_config.conf_array.size > I2C_REG_DATA_MAX) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
reg_setting = kzalloc(write_config.conf_array.size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!reg_setting) {
rc = -ENOMEM;
break;
}
if (copy_from_user(reg_setting,
(void __user *)
compat_ptr(
write_config32.conf_array.reg_setting),
write_config.conf_array.size *
sizeof(struct msm_camera_i2c_reg_array))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
write_config.conf_array.reg_setting = reg_setting;
write_slave_addr = write_config.slave_addr;
write_addr_type = write_config.conf_array.addr_type;
if (s_ctrl->sensor_i2c_client->cci_client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->cci_client->sid;
s_ctrl->sensor_i2c_client->cci_client->sid =
write_slave_addr >> 1;
} else if (s_ctrl->sensor_i2c_client->client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->client->addr;
s_ctrl->sensor_i2c_client->client->addr =
write_slave_addr >> 1;
} else {
pr_err("%s: error: no i2c/cci client found.",
__func__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
pr_debug("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x\n",
__func__, orig_slave_addr,
write_slave_addr >> 1);
orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
s_ctrl->sensor_i2c_client->addr_type = write_addr_type;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
s_ctrl->sensor_i2c_client, &(write_config.conf_array));
s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
if (s_ctrl->sensor_i2c_client->cci_client) {
s_ctrl->sensor_i2c_client->cci_client->sid =
orig_slave_addr;
} else if (s_ctrl->sensor_i2c_client->client) {
s_ctrl->sensor_i2c_client->client->addr =
orig_slave_addr;
} else {
pr_err("%s: error: no i2c/cci client found.\n",
__func__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
kfree(reg_setting);
break;
}
case CFG_WRITE_I2C_SEQ_ARRAY: {
struct msm_camera_i2c_seq_reg_setting32 conf_array32;
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (copy_from_user(&conf_array32,
(void __user *)compat_ptr(cdata->cfg.setting),
sizeof(struct msm_camera_i2c_seq_reg_setting32))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
conf_array.addr_type = conf_array32.addr_type;
conf_array.delay = conf_array32.delay;
conf_array.size = conf_array32.size;
if (!conf_array.size ||
conf_array.size > I2C_SEQ_REG_DATA_MAX) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
reg_setting = kzalloc(conf_array.size *
(sizeof(struct msm_camera_i2c_seq_reg_array)),
GFP_KERNEL);
if (!reg_setting) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -ENOMEM;
break;
}
if (copy_from_user(reg_setting,
(void __user *)
compat_ptr(conf_array32.reg_setting),
conf_array.size *
sizeof(struct msm_camera_i2c_seq_reg_array))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
conf_array.reg_setting = reg_setting;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_seq_table(s_ctrl->sensor_i2c_client,
&conf_array);
kfree(reg_setting);
break;
}
case CFG_POWER_UP:
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (s_ctrl->func_tbl->sensor_power_up) {
if (s_ctrl->sensordata->misc_regulator)
msm_sensor_misc_regulator(s_ctrl, 1);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
pr_err("%s:%d failed rc %d\n", __func__,
__LINE__, rc);
break;
}
s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
s_ctrl->sensor_state);
} else {
rc = -EFAULT;
}
break;
case CFG_POWER_DOWN:
if (s_ctrl->is_csid_tg_mode)
goto DONE;
kfree(s_ctrl->stop_setting.reg_setting);
s_ctrl->stop_setting.reg_setting = NULL;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (s_ctrl->func_tbl->sensor_power_down) {
if (s_ctrl->sensordata->misc_regulator)
msm_sensor_misc_regulator(s_ctrl, 0);
rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
if (rc < 0) {
pr_err("%s:%d failed rc %d\n", __func__,
__LINE__, rc);
break;
}
s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
s_ctrl->sensor_state);
} else {
rc = -EFAULT;
}
break;
case CFG_SET_STOP_STREAM_SETTING: {
struct msm_camera_i2c_reg_setting32 stop_setting32;
struct msm_camera_i2c_reg_setting *stop_setting =
&s_ctrl->stop_setting;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (copy_from_user(&stop_setting32,
(void __user *)compat_ptr((cdata->cfg.setting)),
sizeof(struct msm_camera_i2c_reg_setting32))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
stop_setting->addr_type = stop_setting32.addr_type;
stop_setting->data_type = stop_setting32.data_type;
stop_setting->delay = stop_setting32.delay;
stop_setting->size = stop_setting32.size;
if (!stop_setting->size) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
stop_setting->reg_setting = kzalloc(stop_setting->size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!stop_setting->reg_setting) {
rc = -ENOMEM;
break;
}
if (copy_from_user(stop_setting->reg_setting,
(void __user *)
compat_ptr(stop_setting32.reg_setting),
stop_setting->size *
sizeof(struct msm_camera_i2c_reg_array))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
kfree(stop_setting->reg_setting);
stop_setting->reg_setting = NULL;
stop_setting->size = 0;
rc = -EFAULT;
break;
}
break;
}
case CFG_SET_I2C_SYNC_PARAM: {
struct msm_camera_cci_ctrl cci_ctrl;
s_ctrl->sensor_i2c_client->cci_client->cid =
cdata->cfg.sensor_i2c_sync_params.cid;
s_ctrl->sensor_i2c_client->cci_client->id_map =
cdata->cfg.sensor_i2c_sync_params.csid;
CDBG("I2C_SYNC_PARAM CID:%d, line:%d delay:%d, cdid:%d\n",
s_ctrl->sensor_i2c_client->cci_client->cid,
cdata->cfg.sensor_i2c_sync_params.line,
cdata->cfg.sensor_i2c_sync_params.delay,
cdata->cfg.sensor_i2c_sync_params.csid);
cci_ctrl.cmd = MSM_CCI_SET_SYNC_CID;
cci_ctrl.cfg.cci_wait_sync_cfg.line =
cdata->cfg.sensor_i2c_sync_params.line;
cci_ctrl.cfg.cci_wait_sync_cfg.delay =
cdata->cfg.sensor_i2c_sync_params.delay;
cci_ctrl.cfg.cci_wait_sync_cfg.cid =
cdata->cfg.sensor_i2c_sync_params.cid;
cci_ctrl.cfg.cci_wait_sync_cfg.csid =
cdata->cfg.sensor_i2c_sync_params.csid;
rc = v4l2_subdev_call(s_ctrl->sensor_i2c_client->
cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
if (rc < 0) {
pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
rc = -EFAULT;
break;
}
break;
}
default:
rc = -EFAULT;
break;
}
DONE:
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
#endif
int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void *argp)
{
struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp;
int32_t rc = 0;
int32_t i = 0;
mutex_lock(s_ctrl->msm_sensor_mutex);
CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
s_ctrl->sensordata->sensor_name, cdata->cfgtype);
switch (cdata->cfgtype) {
case CFG_GET_SENSOR_INFO:
memcpy(cdata->cfg.sensor_info.sensor_name,
s_ctrl->sensordata->sensor_name,
sizeof(cdata->cfg.sensor_info.sensor_name));
cdata->cfg.sensor_info.session_id =
s_ctrl->sensordata->sensor_info->session_id;
for (i = 0; i < SUB_MODULE_MAX; i++) {
cdata->cfg.sensor_info.subdev_id[i] =
s_ctrl->sensordata->sensor_info->subdev_id[i];
cdata->cfg.sensor_info.subdev_intf[i] =
s_ctrl->sensordata->sensor_info->subdev_intf[i];
}
cdata->cfg.sensor_info.is_mount_angle_valid =
s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
cdata->cfg.sensor_info.sensor_mount_angle =
s_ctrl->sensordata->sensor_info->sensor_mount_angle;
cdata->cfg.sensor_info.position =
s_ctrl->sensordata->sensor_info->position;
cdata->cfg.sensor_info.modes_supported =
s_ctrl->sensordata->sensor_info->modes_supported;
CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
cdata->cfg.sensor_info.sensor_name);
CDBG("%s:%d session id %d\n", __func__, __LINE__,
cdata->cfg.sensor_info.session_id);
for (i = 0; i < SUB_MODULE_MAX; i++) {
CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
cdata->cfg.sensor_info.subdev_id[i]);
CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__,
i, cdata->cfg.sensor_info.subdev_intf[i]);
}
CDBG("%s:%d mount angle valid %d value %d\n", __func__,
__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
cdata->cfg.sensor_info.sensor_mount_angle);
break;
case CFG_GET_SENSOR_INIT_PARAMS:
cdata->cfg.sensor_init_params.modes_supported =
s_ctrl->sensordata->sensor_info->modes_supported;
cdata->cfg.sensor_init_params.position =
s_ctrl->sensordata->sensor_info->position;
cdata->cfg.sensor_init_params.sensor_mount_angle =
s_ctrl->sensordata->sensor_info->sensor_mount_angle;
CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
__LINE__,
cdata->cfg.sensor_init_params.modes_supported,
cdata->cfg.sensor_init_params.position,
cdata->cfg.sensor_init_params.sensor_mount_angle);
break;
case CFG_WRITE_I2C_ARRAY:
case CFG_WRITE_I2C_ARRAY_SYNC:
case CFG_WRITE_I2C_ARRAY_SYNC_BLOCK:
case CFG_WRITE_I2C_ARRAY_ASYNC: {
struct msm_camera_i2c_reg_setting conf_array;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (copy_from_user(&conf_array,
(void __user *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_reg_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
if (!conf_array.size ||
conf_array.size > I2C_REG_DATA_MAX) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
reg_setting = kzalloc(conf_array.size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!reg_setting) {
rc = -ENOMEM;
break;
}
if (copy_from_user(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(reg_setting);
rc = -EFAULT;
break;
}
conf_array.reg_setting = reg_setting;
if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY)
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table(s_ctrl->sensor_i2c_client,
&conf_array);
else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_ASYNC)
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table_async(s_ctrl->sensor_i2c_client,
&conf_array);
else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_SYNC_BLOCK)
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table_sync_block(
s_ctrl->sensor_i2c_client,
&conf_array);
else
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_table_sync(s_ctrl->sensor_i2c_client,
&conf_array);
kfree(reg_setting);
break;
}
case CFG_SLAVE_READ_I2C: {
struct msm_camera_i2c_read_config read_config;
struct msm_camera_i2c_read_config *read_config_ptr = NULL;
uint16_t local_data = 0;
uint16_t orig_slave_addr = 0, read_slave_addr = 0;
uint16_t orig_addr_type = 0, read_addr_type = 0;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
read_config_ptr =
(struct msm_camera_i2c_read_config *)cdata->cfg.setting;
if (copy_from_user(&read_config,
(void __user *)read_config_ptr,
sizeof(struct msm_camera_i2c_read_config))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
read_slave_addr = read_config.slave_addr;
read_addr_type = read_config.addr_type;
CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
__func__, read_config.slave_addr,
read_config.reg_addr, read_config.data_type);
if (s_ctrl->sensor_i2c_client->cci_client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->cci_client->sid;
s_ctrl->sensor_i2c_client->cci_client->sid =
read_slave_addr >> 1;
} else if (s_ctrl->sensor_i2c_client->client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->client->addr;
s_ctrl->sensor_i2c_client->client->addr =
read_slave_addr >> 1;
} else {
pr_err("%s: error: no i2c/cci client found.", __func__);
rc = -EFAULT;
break;
}
CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
__func__, orig_slave_addr,
read_slave_addr >> 1);
orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
s_ctrl->sensor_i2c_client->addr_type = read_addr_type;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
s_ctrl->sensor_i2c_client,
read_config.reg_addr,
&local_data, read_config.data_type);
if (s_ctrl->sensor_i2c_client->cci_client) {
s_ctrl->sensor_i2c_client->cci_client->sid =
orig_slave_addr;
} else if (s_ctrl->sensor_i2c_client->client) {
s_ctrl->sensor_i2c_client->client->addr =
orig_slave_addr;
}
s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
if (rc < 0) {
pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
break;
}
if (copy_to_user((void __user *)(&read_config_ptr->data),
&local_data, sizeof(local_data))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
break;
}
case CFG_SLAVE_WRITE_I2C_ARRAY: {
struct msm_camera_i2c_array_write_config write_config;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
uint16_t orig_slave_addr = 0, write_slave_addr = 0;
uint16_t orig_addr_type = 0, write_addr_type = 0;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (copy_from_user(&write_config,
(void __user *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_array_write_config))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__);
CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
write_config.slave_addr,
write_config.conf_array.size);
if (!write_config.conf_array.size ||
write_config.conf_array.size > I2C_REG_DATA_MAX) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
reg_setting = kzalloc(write_config.conf_array.size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!reg_setting) {
rc = -ENOMEM;
break;
}
if (copy_from_user(reg_setting,
(void __user *)
(write_config.conf_array.reg_setting),
write_config.conf_array.size *
sizeof(struct msm_camera_i2c_reg_array))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
write_config.conf_array.reg_setting = reg_setting;
write_slave_addr = write_config.slave_addr;
write_addr_type = write_config.conf_array.addr_type;
if (s_ctrl->sensor_i2c_client->cci_client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->cci_client->sid;
s_ctrl->sensor_i2c_client->cci_client->sid =
write_slave_addr >> 1;
} else if (s_ctrl->sensor_i2c_client->client) {
orig_slave_addr =
s_ctrl->sensor_i2c_client->client->addr;
s_ctrl->sensor_i2c_client->client->addr =
write_slave_addr >> 1;
} else {
pr_err("%s: error: no i2c/cci client found.", __func__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
__func__, orig_slave_addr,
write_slave_addr >> 1);
orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
s_ctrl->sensor_i2c_client->addr_type = write_addr_type;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
s_ctrl->sensor_i2c_client, &(write_config.conf_array));
s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
if (s_ctrl->sensor_i2c_client->cci_client) {
s_ctrl->sensor_i2c_client->cci_client->sid =
orig_slave_addr;
} else if (s_ctrl->sensor_i2c_client->client) {
s_ctrl->sensor_i2c_client->client->addr =
orig_slave_addr;
} else {
pr_err("%s: error: no i2c/cci client found.", __func__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
kfree(reg_setting);
break;
}
case CFG_WRITE_I2C_SEQ_ARRAY: {
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (copy_from_user(&conf_array,
(void __user *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_seq_reg_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
if (!conf_array.size ||
conf_array.size > I2C_SEQ_REG_DATA_MAX) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
reg_setting = kzalloc(conf_array.size *
(sizeof(struct msm_camera_i2c_seq_reg_array)),
GFP_KERNEL);
if (!reg_setting) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -ENOMEM;
break;
}
if (copy_from_user(reg_setting,
(void __user *)conf_array.reg_setting,
conf_array.size *
sizeof(struct msm_camera_i2c_seq_reg_array))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
kfree(reg_setting);
rc = -EFAULT;
break;
}
conf_array.reg_setting = reg_setting;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
i2c_write_seq_table(s_ctrl->sensor_i2c_client,
&conf_array);
kfree(reg_setting);
break;
}
case CFG_POWER_UP:
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (s_ctrl->func_tbl->sensor_power_up) {
if (s_ctrl->sensordata->misc_regulator)
msm_sensor_misc_regulator(s_ctrl, 1);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
pr_err("%s:%d failed rc %d\n", __func__,
__LINE__, rc);
break;
}
s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
s_ctrl->sensor_state);
} else {
rc = -EFAULT;
}
break;
case CFG_POWER_DOWN:
if (s_ctrl->is_csid_tg_mode)
goto DONE;
kfree(s_ctrl->stop_setting.reg_setting);
s_ctrl->stop_setting.reg_setting = NULL;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
break;
}
if (s_ctrl->func_tbl->sensor_power_down) {
if (s_ctrl->sensordata->misc_regulator)
msm_sensor_misc_regulator(s_ctrl, 0);
rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
if (rc < 0) {
pr_err("%s:%d failed rc %d\n", __func__,
__LINE__, rc);
break;
}
s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
s_ctrl->sensor_state);
} else {
rc = -EFAULT;
}
break;
case CFG_SET_STOP_STREAM_SETTING: {
struct msm_camera_i2c_reg_setting *stop_setting =
&s_ctrl->stop_setting;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
if (s_ctrl->is_csid_tg_mode)
goto DONE;
if (copy_from_user(stop_setting,
(void __user *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_reg_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
reg_setting = stop_setting->reg_setting;
if (!stop_setting->size) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
stop_setting->reg_setting = kzalloc(stop_setting->size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!stop_setting->reg_setting) {
rc = -ENOMEM;
break;
}
if (copy_from_user(stop_setting->reg_setting,
(void __user *)reg_setting,
stop_setting->size *
sizeof(struct msm_camera_i2c_reg_array))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
kfree(stop_setting->reg_setting);
stop_setting->reg_setting = NULL;
stop_setting->size = 0;
rc = -EFAULT;
break;
}
break;
}
case CFG_SET_I2C_SYNC_PARAM: {
struct msm_camera_cci_ctrl cci_ctrl;
s_ctrl->sensor_i2c_client->cci_client->cid =
cdata->cfg.sensor_i2c_sync_params.cid;
s_ctrl->sensor_i2c_client->cci_client->id_map =
cdata->cfg.sensor_i2c_sync_params.csid;
CDBG("I2C_SYNC_PARAM CID:%d, line:%d delay:%d, cdid:%d\n",
s_ctrl->sensor_i2c_client->cci_client->cid,
cdata->cfg.sensor_i2c_sync_params.line,
cdata->cfg.sensor_i2c_sync_params.delay,
cdata->cfg.sensor_i2c_sync_params.csid);
cci_ctrl.cmd = MSM_CCI_SET_SYNC_CID;
cci_ctrl.cfg.cci_wait_sync_cfg.line =
cdata->cfg.sensor_i2c_sync_params.line;
cci_ctrl.cfg.cci_wait_sync_cfg.delay =
cdata->cfg.sensor_i2c_sync_params.delay;
cci_ctrl.cfg.cci_wait_sync_cfg.cid =
cdata->cfg.sensor_i2c_sync_params.cid;
cci_ctrl.cfg.cci_wait_sync_cfg.csid =
cdata->cfg.sensor_i2c_sync_params.csid;
rc = v4l2_subdev_call(s_ctrl->sensor_i2c_client->
cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
if (rc < 0) {
pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
rc = -EFAULT;
break;
}
break;
}
default:
rc = -EFAULT;
break;
}
DONE:
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl)
{
int rc;
if (s_ctrl->func_tbl->sensor_match_id)
rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
else
rc = msm_sensor_match_id(s_ctrl);
if (rc < 0)
pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc);
return rc;
}
static int msm_sensor_power(struct v4l2_subdev *sd, int on)
{
int rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
mutex_lock(s_ctrl->msm_sensor_mutex);
if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
s_ctrl->func_tbl->sensor_power_down(s_ctrl);
s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
}
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = {
.ioctl = msm_sensor_subdev_ioctl,
.s_power = msm_sensor_power,
};
static struct v4l2_subdev_ops msm_sensor_subdev_ops = {
.core = &msm_sensor_subdev_core_ops,
};
static struct msm_sensor_fn_t msm_sensor_func_tbl = {
.sensor_config = msm_sensor_config,
#ifdef CONFIG_COMPAT
.sensor_config32 = msm_sensor_config32,
#endif
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
.sensor_match_id = msm_sensor_match_id,
};
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_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl,
.i2c_write_table_async = msm_camera_cci_i2c_write_table_async,
.i2c_write_table_sync = msm_camera_cci_i2c_write_table_sync,
.i2c_write_table_sync_block = msm_camera_cci_i2c_write_table_sync_block,
};
static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
.i2c_read = msm_camera_qup_i2c_read,
.i2c_read_seq = msm_camera_qup_i2c_read_seq,
.i2c_write = msm_camera_qup_i2c_write,
.i2c_write_table = msm_camera_qup_i2c_write_table,
.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
.i2c_write_table_w_microdelay =
msm_camera_qup_i2c_write_table_w_microdelay,
.i2c_write_conf_tbl = msm_camera_qup_i2c_write_conf_tbl,
.i2c_write_table_async = msm_camera_qup_i2c_write_table,
.i2c_write_table_sync = msm_camera_qup_i2c_write_table,
.i2c_write_table_sync_block = msm_camera_qup_i2c_write_table,
};
static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl = {
.i2c_read = msm_camera_tz_i2c_read,
.i2c_read_seq = msm_camera_tz_i2c_read_seq,
.i2c_write = msm_camera_tz_i2c_write,
.i2c_write_table = msm_camera_tz_i2c_write_table,
.i2c_write_seq_table = msm_camera_tz_i2c_write_seq_table,
.i2c_write_table_w_microdelay =
msm_camera_tz_i2c_write_table_w_microdelay,
.i2c_util = msm_sensor_tz_i2c_util,
.i2c_write_conf_tbl = msm_camera_tz_i2c_write_conf_tbl,
.i2c_write_table_async = msm_camera_tz_i2c_write_table_async,
.i2c_write_table_sync = msm_camera_tz_i2c_write_table_sync,
.i2c_write_table_sync_block = msm_camera_tz_i2c_write_table_sync_block,
};
int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl)
{
struct msm_camera_cci_client *cci_client = NULL;
unsigned long mount_pos = 0;
/* Validate input parameters */
if (!s_ctrl) {
pr_err("%s:%d failed: invalid params s_ctrl %pK\n", __func__,
__LINE__, s_ctrl);
return -EINVAL;
}
if (!s_ctrl->sensor_i2c_client) {
pr_err("%s:%d failed: invalid params sensor_i2c_client %pK\n",
__func__, __LINE__, s_ctrl->sensor_i2c_client);
return -EINVAL;
}
/* Initialize cci_client */
s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof(
struct msm_camera_cci_client), GFP_KERNEL);
if (!s_ctrl->sensor_i2c_client->cci_client)
return -ENOMEM;
if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
cci_client = s_ctrl->sensor_i2c_client->cci_client;
/* Get CCI subdev */
cci_client->cci_subdev = msm_cci_get_subdev();
if (s_ctrl->is_secure)
msm_camera_tz_i2c_register_sensor((void *)s_ctrl);
/* Update CCI / I2C function table */
if (!s_ctrl->sensor_i2c_client->i2c_func_tbl)
s_ctrl->sensor_i2c_client->i2c_func_tbl =
&msm_sensor_cci_func_tbl;
} else {
if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) {
CDBG("%s:%d\n", __func__, __LINE__);
s_ctrl->sensor_i2c_client->i2c_func_tbl =
&msm_sensor_qup_func_tbl;
}
}
/* Update function table driven by ioctl */
if (!s_ctrl->func_tbl)
s_ctrl->func_tbl = &msm_sensor_func_tbl;
/* Update v4l2 subdev ops table */
if (!s_ctrl->sensor_v4l2_subdev_ops)
s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
/* Update sensor mount angle and position in media entity flag */
mount_pos = s_ctrl->sensordata->sensor_info->position << 16;
mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info->
sensor_mount_angle / 90) << 8);
s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
return 0;
}