diff options
author | Charlie Huang <chahuang@nvidia.com> | 2012-04-23 19:09:15 -0700 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2012-05-04 10:46:08 -0700 |
commit | 1b441dac644532d9d50c2dc8712a3cf0c5003856 (patch) | |
tree | fd192b81bd54564f5d4d589311b5ef7bce2c6296 /drivers/media | |
parent | 7a909302fe39d29ed83426e1b4520775392b71cc (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.c | 96 |
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; } |