summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorCharlie Huang <chahuang@nvidia.com>2012-04-23 19:09:15 -0700
committerVarun Colbert <vcolbert@nvidia.com>2012-05-04 10:46:08 -0700
commit1b441dac644532d9d50c2dc8712a3cf0c5003856 (patch)
treefd192b81bd54564f5d4d589311b5ef7bce2c6296 /drivers/media
parent7a909302fe39d29ed83426e1b4520775392b71cc (diff)
media: video: tegra: ov5650: read sensor fuse id
The sequence of read fuse id is: 1. write to OTP index register 0x3d00. 2. read out byte from ox3d04. 3. repeat step 1 to the next byte with its index respectively. also fixed ov5650_read_reg always fail issue. bug 957657 Change-Id: I649a7765320d0d4be8111a7f523d8487b872b620 Signed-off-by: Charlie Huang <chahuang@nvidia.com> Reviewed-on: http://git-master/r/98330 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Wei Chen <wechen@nvidia.com> Reviewed-by: Frank Chen <frankc@nvidia.com> Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/tegra/ov5650.c96
1 files changed, 80 insertions, 16 deletions
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c
index 3adb46a3bb80..3cfb9560d889 100644
--- a/drivers/media/video/tegra/ov5650.c
+++ b/drivers/media/video/tegra/ov5650.c
@@ -39,6 +39,11 @@ struct ov5650_info {
enum StereoCameraMode camera_mode;
struct ov5650_sensor left;
struct ov5650_sensor right;
+ struct ov5650_sensordata sensor_data;
+ struct mutex mutex_le;
+ struct mutex mutex_ri;
+ int power_refcnt_le;
+ int power_refcnt_ri;
u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
@@ -788,7 +793,7 @@ static int ov5650_read_reg(struct i2c_client *client, u16 addr, u8 *val)
err = i2c_transfer(client->adapter, msg, 2);
- if (err != 1)
+ if (err != 2)
return -EINVAL;
*val = data[2];
@@ -1245,31 +1250,71 @@ static int ov5650_test_pattern(struct ov5650_info *info,
}
static int set_power_helper(struct ov5650_platform_data *pdata,
- int powerLevel)
+ int powerLevel, int *ref_cnt)
{
if (pdata) {
- if (powerLevel && pdata->power_on)
- pdata->power_on();
- else if (pdata->power_off)
- pdata->power_off();
+ if (powerLevel && pdata->power_on) {
+ if (*ref_cnt == 0)
+ pdata->power_on();
+ *ref_cnt = *ref_cnt + 1;
+ }
+ else if (pdata->power_off) {
+ *ref_cnt = *ref_cnt - 1;
+ if (*ref_cnt <= 0)
+ pdata->power_off();
+ }
}
return 0;
}
-static int ov5650_set_power(int powerLevel)
+static int ov5650_set_power(struct ov5650_info *info, int powerLevel)
{
pr_info("%s: powerLevel=%d camera mode=%d\n", __func__, powerLevel,
- stereo_ov5650_info->camera_mode);
+ info->camera_mode);
- if (StereoCameraMode_Left & stereo_ov5650_info->camera_mode)
- set_power_helper(stereo_ov5650_info->left.pdata, powerLevel);
+ if (StereoCameraMode_Left & info->camera_mode) {
+ mutex_lock(&info->mutex_le);
+ set_power_helper(info->left.pdata, powerLevel,
+ &info->power_refcnt_le);
+ mutex_unlock(&info->mutex_le);
+ }
- if (StereoCameraMode_Right & stereo_ov5650_info->camera_mode)
- set_power_helper(stereo_ov5650_info->right.pdata, powerLevel);
+ if (StereoCameraMode_Right & info->camera_mode) {
+ mutex_lock(&info->mutex_ri);
+ set_power_helper(info->right.pdata, powerLevel,
+ &info->power_refcnt_ri);
+ mutex_unlock(&info->mutex_ri);
+ }
return 0;
}
+static int ov5650_get_sensor_id(struct ov5650_info *info)
+{
+ int ret = 0;
+ int i;
+ u8 bak;
+
+ pr_info("%s\n", __func__);
+ if (info->sensor_data.fuse_id_size)
+ return 0;
+
+ ov5650_set_power(info, 1);
+
+ for (i = 0; i < 5; i++) {
+ ret |= ov5650_write_reg_helper(info, 0x3d00, i);
+ ret |= ov5650_read_reg_helper(info, 0x3d04,
+ &bak);
+ info->sensor_data.fuse_id[i] = bak;
+ }
+
+ if (!ret)
+ info->sensor_data.fuse_id_size = i;
+
+ ov5650_set_power(info, 0);
+ return ret;
+}
+
static long ov5650_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1280,13 +1325,13 @@ static long ov5650_ioctl(struct file *file,
case OV5650_IOCTL_SET_CAMERA_MODE:
{
if (info->camera_mode != arg) {
- err = ov5650_set_power(0);
+ err = ov5650_set_power(info, 0);
if (err) {
pr_info("%s %d\n", __func__, __LINE__);
return err;
}
info->camera_mode = arg;
- err = ov5650_set_power(1);
+ err = ov5650_set_power(info, 1);
if (err)
return err;
}
@@ -1344,6 +1389,21 @@ static long ov5650_ioctl(struct file *file,
}
return ov5650_set_group_hold(info, &ae);
}
+ case OV5650_IOCTL_GET_SENSORDATA:
+ {
+ err = ov5650_get_sensor_id(info);
+ if (err) {
+ pr_err("%s %d %d\n", __func__, __LINE__, err);
+ return err;
+ }
+ if (copy_to_user((void __user *)arg,
+ &info->sensor_data,
+ sizeof(struct ov5650_sensordata))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ }
default:
return -EINVAL;
}
@@ -1354,13 +1414,15 @@ static int ov5650_open(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
file->private_data = stereo_ov5650_info;
- ov5650_set_power(1);
+ ov5650_set_power(stereo_ov5650_info, 1);
return 0;
}
int ov5650_release(struct inode *inode, struct file *file)
{
- ov5650_set_power(0);
+ struct ov5650_info *info = file->private_data;
+
+ ov5650_set_power(info, 0);
file->private_data = NULL;
return 0;
}
@@ -1426,6 +1488,8 @@ static int left_ov5650_probe(struct i2c_client *client,
stereo_ov5650_info->left.pdata = client->dev.platform_data;
stereo_ov5650_info->left.i2c_client = client;
+ mutex_init(&stereo_ov5650_info->mutex_le);
+ mutex_init(&stereo_ov5650_info->mutex_ri);
return 0;
}