diff options
Diffstat (limited to 'drivers/media/video/tegra/ov5650.c')
-rw-r--r-- | drivers/media/video/tegra/ov5650.c | 101 |
1 files changed, 81 insertions, 20 deletions
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c index a8436210561a..bac1d00c3bd0 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]; }; @@ -118,7 +123,7 @@ static struct ov5650_reg mode_start[] = { {0x4000, 0x01}, {0x401c, 0x48}, {0x401d, 0x08}, - {0x5000, 0x00}, + {0x5000, 0x06}, {0x5001, 0x00}, {0x5002, 0x00}, {0x503d, 0x00}, @@ -291,7 +296,6 @@ static struct ov5650_reg mode_2080x1164[] = { {0x401d, 0x08}, {0x4001, 0x02}, - {0x5000, 0x00}, {0x5001, 0x00}, {0x5002, 0x00}, {0x503d, 0x00}, @@ -414,7 +418,6 @@ static struct ov5650_reg mode_1920x1080[] = { {0x401d, 0x08}, {0x4001, 0x02}, - {0x5000, 0x00}, {0x5001, 0x00}, {0x5002, 0x00}, {0x503d, 0x00}, @@ -664,7 +667,6 @@ static struct ov5650_reg mode_320x240[] = { {0x3810, 0x40}, {0x3836, 0x41}, {0x505f, 0x04}, - {0x5000, 0x06}, {0x5001, 0x00}, {0x5002, 0x02}, {0x503d, 0x00}, @@ -788,7 +790,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 +1247,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 +1322,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 +1386,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 +1411,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 +1485,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; } |