blob: 2c23f68571d67a46767e8aeb964548a05951a034 [file] [log] [blame]
/* Copyright (c) 2013-2014, 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 <mach/gpiomux.h>
#include "msm_sensor.h"
#include "msm_cci.h"
#include "msm_camera_io_util.h"
#include "msm_camera_i2c_mux.h"
#define GC0339_SENSOR_NAME "gc0339"
DEFINE_MSM_MUTEX(gc0339_mut);
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_err(fmt, ##args)
#else
#define CDBG(fmt, args...) do { } while (0)
#endif
static struct msm_sensor_ctrl_t gc0339_s_ctrl;
static struct msm_sensor_power_setting gc0339_power_setting[] = {
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_LOW,
.delay = 0,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_HIGH,
.delay = 0,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VIO,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VDIG,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VANA,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
.delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_LOW,
.delay = 0,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
.delay = 1,
},
};
static struct v4l2_subdev_info gc0339_subdev_info[] = {
{
.code = V4L2_MBUS_FMT_SBGGR10_1X10,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 0,
},
};
static int32_t msm_gc0339_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
return msm_sensor_i2c_probe(client, id, &gc0339_s_ctrl);
}
static const struct i2c_device_id gc0339_i2c_id[] = {
{GC0339_SENSOR_NAME, (kernel_ulong_t)&gc0339_s_ctrl},
{ }
};
static struct i2c_driver gc0339_i2c_driver = {
.id_table = gc0339_i2c_id,
.probe = msm_gc0339_i2c_probe,
.driver = {
.name = GC0339_SENSOR_NAME,
},
};
static struct msm_camera_i2c_client gc0339_sensor_i2c_client = {
.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
};
int32_t gc0339_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0, index = 0;
struct msm_sensor_power_setting_array *power_setting_array = NULL;
struct msm_sensor_power_setting *power_setting = NULL;
struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
CDBG("%s:%d\n", __func__, __LINE__);
power_setting_array = &s_ctrl->power_setting_array;
if (data->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
pr_err("%s:%d mux install\n", __func__, __LINE__);
msm_gpiomux_install(
(struct msm_gpiomux_config *)
data->gpio_conf->cam_gpiomux_conf_tbl,
data->gpio_conf->cam_gpiomux_conf_tbl_size);
}
rc = msm_camera_request_gpio_table(
data->gpio_conf->cam_gpio_req_tbl,
data->gpio_conf->cam_gpio_req_tbl_size, 1);
if (rc < 0) {
pr_err("%s: request gpio failed\n", __func__);
return rc;
}
for (index = 0; index < power_setting_array->size; index++) {
CDBG("%s index %d\n", __func__, index);
power_setting = &power_setting_array->power_setting[index];
CDBG("%s type %d\n", __func__, power_setting->seq_type);
switch (power_setting->seq_type) {
case SENSOR_CLK:
if (power_setting->seq_val >= s_ctrl->clk_info_size) {
pr_err("%s clk index %d >= max %d\n", __func__,
power_setting->seq_val,
s_ctrl->clk_info_size);
goto power_up_failed;
}
if (power_setting->config_val)
s_ctrl->clk_info[power_setting->seq_val].
clk_rate = power_setting->config_val;
rc = msm_cam_clk_enable(s_ctrl->dev,
&s_ctrl->clk_info[0],
(struct clk **)&power_setting->data[0],
s_ctrl->clk_info_size,
1);
if (rc < 0) {
pr_err("%s: clk enable failed\n",
__func__);
goto power_up_failed;
}
break;
case SENSOR_GPIO:
if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
!data->gpio_conf->gpio_num_info) {
pr_err("%s gpio index %d >= max %d\n", __func__,
power_setting->seq_val,
SENSOR_GPIO_MAX);
goto power_up_failed;
}
pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__,
data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val]);
if (data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val])
gpio_set_value_cansleep(
data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val],
power_setting->config_val);
break;
case SENSOR_VREG:
if (power_setting->seq_val >= CAM_VREG_MAX) {
pr_err("%s vreg index %d >= max %d\n", __func__,
power_setting->seq_val,
SENSOR_GPIO_MAX);
goto power_up_failed;
}
msm_camera_config_single_vreg(s_ctrl->dev,
&data->cam_vreg[power_setting->seq_val],
(struct regulator **)&power_setting->data[0],
1);
break;
default:
pr_err("%s error power seq type %d\n", __func__,
power_setting->seq_type);
break;
}
if (power_setting->delay > 20) {
msleep(power_setting->delay);
} else if (power_setting->delay) {
usleep_range(power_setting->delay * 1000,
(power_setting->delay * 1000) + 1000);
}
}
if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
s_ctrl->sensor_i2c_client, MSM_CCI_INIT);
if (rc < 0) {
pr_err("%s cci_init failed\n", __func__);
goto power_up_failed;
}
}
s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
s_ctrl->sensor_i2c_client,
0xfc,
0x10, MSM_CAMERA_I2C_BYTE_DATA);
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);
goto power_up_failed;
}
CDBG("%s exit\n", __func__);
return 0;
power_up_failed:
pr_err("%s:%d failed\n", __func__, __LINE__);
if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
}
for (index--; index >= 0; index--) {
CDBG("%s index %d\n", __func__, index);
power_setting = &power_setting_array->power_setting[index];
CDBG("%s type %d\n", __func__, power_setting->seq_type);
switch (power_setting->seq_type) {
case SENSOR_CLK:
msm_cam_clk_enable(s_ctrl->dev,
&s_ctrl->clk_info[0],
(struct clk **)&power_setting->data[0],
s_ctrl->clk_info_size,
0);
break;
case SENSOR_GPIO:
if (data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val])
gpio_set_value_cansleep(
data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val],
GPIOF_OUT_INIT_LOW);
break;
case SENSOR_VREG:
msm_camera_config_single_vreg(s_ctrl->dev,
&data->cam_vreg[power_setting->seq_val],
(struct regulator **)&power_setting->data[0],
0);
break;
default:
pr_err("%s error power seq type %d\n", __func__,
power_setting->seq_type);
break;
}
if (power_setting->delay > 20) {
msleep(power_setting->delay);
} else if (power_setting->delay) {
usleep_range(power_setting->delay * 1000,
(power_setting->delay * 1000) + 1000);
}
}
msm_camera_request_gpio_table(
data->gpio_conf->cam_gpio_req_tbl,
data->gpio_conf->cam_gpio_req_tbl_size, 0);
return rc;
}
int32_t gc0339_power_down(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t index = 0;
struct msm_sensor_power_setting_array *power_setting_array = NULL;
struct msm_sensor_power_setting *power_setting = NULL;
struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
CDBG("%s:%d\n", __func__, __LINE__);
power_setting_array = &s_ctrl->power_setting_array;
if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
}
s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
s_ctrl->sensor_i2c_client,
0xfc,
0x01, MSM_CAMERA_I2C_BYTE_DATA);
for (index = (power_setting_array->size - 1); index >= 0; index--) {
CDBG("%s index %d\n", __func__, index);
power_setting = &power_setting_array->power_setting[index];
CDBG("%s type %d\n", __func__, power_setting->seq_type);
switch (power_setting->seq_type) {
case SENSOR_CLK:
msm_cam_clk_enable(s_ctrl->dev,
&s_ctrl->clk_info[0],
(struct clk **)&power_setting->data[0],
s_ctrl->clk_info_size,
0);
break;
case SENSOR_GPIO:
if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
!data->gpio_conf->gpio_num_info) {
pr_err("%s gpio index %d >= max %d\n", __func__,
power_setting->seq_val,
SENSOR_GPIO_MAX);
continue;
}
if (data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val])
gpio_set_value_cansleep(
data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val],
GPIOF_OUT_INIT_LOW);
break;
case SENSOR_VREG:
if (power_setting->seq_val >= CAM_VREG_MAX) {
pr_err("%s vreg index %d >= max %d\n", __func__,
power_setting->seq_val,
SENSOR_GPIO_MAX);
continue;
}
msm_camera_config_single_vreg(s_ctrl->dev,
&data->cam_vreg[power_setting->seq_val],
(struct regulator **)&power_setting->data[0],
0);
break;
default:
pr_err("%s error power seq type %d\n", __func__,
power_setting->seq_type);
break;
}
if (power_setting->delay > 20) {
msleep(power_setting->delay);
} else if (power_setting->delay) {
usleep_range(power_setting->delay * 1000,
(power_setting->delay * 1000) + 1000);
}
}
msm_camera_request_gpio_table(
data->gpio_conf->cam_gpio_req_tbl,
data->gpio_conf->cam_gpio_req_tbl_size, 0);
CDBG("%s exit\n", __func__);
return 0;
}
int32_t gc0339_match_id(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
uint16_t chipid = 0;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
s_ctrl->sensor_i2c_client,
s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
&chipid, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: read id failed\n", __func__,
s_ctrl->sensordata->sensor_name);
return rc;
}
if (chipid != s_ctrl->sensordata->slave_info->sensor_id) {
pr_err("msm_sensor_match_id chip id doesnot match\n");
return -ENODEV;
}
return rc;
}
int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl,
void __user *argp)
{
struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp;
long rc = 0;
int32_t i = 0;
mutex_lock(s_ctrl->msm_sensor_mutex);
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.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;
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]);
break;
case CFG_GET_SENSOR_INIT_PARAMS:
cdata->cfg.sensor_init_params =
*s_ctrl->sensordata->sensor_init_params;
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_SET_SLAVE_INFO: {
struct msm_camera_sensor_slave_info sensor_slave_info;
struct msm_sensor_power_setting_array *power_setting_array;
int slave_index = 0;
if (copy_from_user(&sensor_slave_info,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_sensor_slave_info))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
/* Update sensor slave address */
if (sensor_slave_info.slave_addr) {
s_ctrl->sensor_i2c_client->cci_client->sid =
sensor_slave_info.slave_addr >> 1;
}
/* Update sensor address type */
s_ctrl->sensor_i2c_client->addr_type =
sensor_slave_info.addr_type;
/* Update power up / down sequence */
s_ctrl->power_setting_array =
sensor_slave_info.power_setting_array;
power_setting_array = &s_ctrl->power_setting_array;
power_setting_array->power_setting = kzalloc(
power_setting_array->size *
sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
if (!power_setting_array->power_setting) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -ENOMEM;
break;
}
if (copy_from_user(power_setting_array->power_setting,
(void *)
sensor_slave_info.power_setting_array.power_setting,
power_setting_array->size *
sizeof(struct msm_sensor_power_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
s_ctrl->free_power_setting = true;
CDBG("%s sensor id %x\n", __func__,
sensor_slave_info.slave_addr);
CDBG("%s sensor addr type %d\n", __func__,
sensor_slave_info.addr_type);
CDBG("%s sensor reg %x\n", __func__,
sensor_slave_info.sensor_id_info.sensor_id_reg_addr);
CDBG("%s sensor id %x\n", __func__,
sensor_slave_info.sensor_id_info.sensor_id);
for (slave_index = 0; slave_index <
power_setting_array->size; slave_index++) {
CDBG("%s i %d power setting %d %d %ld %d\n", __func__,
slave_index,
power_setting_array->power_setting[slave_index].
seq_type,
power_setting_array->power_setting[slave_index].
seq_val,
power_setting_array->power_setting[slave_index].
config_val,
power_setting_array->power_setting[slave_index].
delay);
}
break;
}
case CFG_WRITE_I2C_ARRAY: {
struct msm_camera_i2c_reg_setting conf_array;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
if (copy_from_user(&conf_array,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_reg_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
}
if (conf_array.addr_type == MSM_CAMERA_I2C_WORD_ADDR
|| conf_array.data_type == MSM_CAMERA_I2C_WORD_DATA
|| !conf_array.size)
break;
reg_setting = kzalloc(conf_array.size *
(sizeof(struct msm_camera_i2c_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 *)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;
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
s_ctrl->sensor_i2c_client, &conf_array);
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 (copy_from_user(&conf_array,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_seq_reg_setting))) {
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 *)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->func_tbl->sensor_power_up)
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
else
rc = -EFAULT;
break;
case CFG_POWER_DOWN:
if (s_ctrl->func_tbl->sensor_power_down)
rc = s_ctrl->func_tbl->sensor_power_down(
s_ctrl);
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 (copy_from_user(stop_setting,
(void *)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;
stop_setting->reg_setting = kzalloc(stop_setting->size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!stop_setting->reg_setting) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -ENOMEM;
break;
}
if (copy_from_user(stop_setting->reg_setting,
(void *)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;
}
default:
rc = -EFAULT;
break;
}
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
static struct msm_sensor_fn_t gc0339_sensor_fn_t = {
.sensor_power_up = gc0339_power_up,
.sensor_power_down = gc0339_power_down,
.sensor_match_id = gc0339_match_id,
.sensor_config = gc0339_config,
};
static struct msm_sensor_ctrl_t gc0339_s_ctrl = {
.sensor_i2c_client = &gc0339_sensor_i2c_client,
.power_setting_array.power_setting = gc0339_power_setting,
.power_setting_array.size = ARRAY_SIZE(gc0339_power_setting),
.msm_sensor_mutex = &gc0339_mut,
.sensor_v4l2_subdev_info = gc0339_subdev_info,
.sensor_v4l2_subdev_info_size = ARRAY_SIZE(gc0339_subdev_info),
.func_tbl = &gc0339_sensor_fn_t,
};
static const struct of_device_id gc0339_dt_match[] = {
{.compatible = "shinetech,gc0339", .data = &gc0339_s_ctrl},
{}
};
MODULE_DEVICE_TABLE(of, gc0339_dt_match);
static struct platform_driver gc0339_platform_driver = {
.driver = {
.name = "shinetech,gc0339",
.owner = THIS_MODULE,
.of_match_table = gc0339_dt_match,
},
};
static int32_t gc0339_platform_probe(struct platform_device *pdev)
{
int32_t rc = 0;
const struct of_device_id *match;
match = of_match_device(gc0339_dt_match, &pdev->dev);
rc = msm_sensor_platform_probe(pdev, match->data);
return rc;
}
static int __init gc0339_init_module(void)
{
int32_t rc = 0;
rc = platform_driver_probe(&gc0339_platform_driver,
gc0339_platform_probe);
if (!rc)
return rc;
return i2c_add_driver(&gc0339_i2c_driver);
}
static void __exit gc0339_exit_module(void)
{
if (gc0339_s_ctrl.pdev) {
msm_sensor_free_sensor_data(&gc0339_s_ctrl);
platform_driver_unregister(&gc0339_platform_driver);
} else
i2c_del_driver(&gc0339_i2c_driver);
return;
}
module_init(gc0339_init_module);
module_exit(gc0339_exit_module);
MODULE_DESCRIPTION("gc0339");
MODULE_LICENSE("GPL v2");