summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Huang <chahuang@nvidia.com>2011-12-05 15:51:51 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-15 12:09:47 +0530
commit5ca29dcf3a0d121c7aa74fd2d3488f1a83cb760f (patch)
tree4135812e099dae2076b2eeab8f10f388da746e97
parente79602a83fcf33c655a16b6a96bc79b396e157be (diff)
media: video: ov5650: optimize i2c write table seq
Combines i2c cmds that have sequential addresses into one bulk i2c write cmd. This will save the overheads of slave addr + offset and the latency time. bug 816814 Change-Id: I7b3808e8af17dd805452672e4386033d8383fb91 Signed-off-by: Charlie Huang <chahuang@nvidia.com> Reviewed-on: http://git-master/r/68326 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
-rw-r--r--drivers/media/video/tegra/ov5650.c162
1 files changed, 115 insertions, 47 deletions
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c
index fa03cc5e2ba9..d90e10a8837d 100644
--- a/drivers/media/video/tegra/ov5650.c
+++ b/drivers/media/video/tegra/ov5650.c
@@ -22,6 +22,8 @@
#include <media/ov5650.h>
#include <media/tegra_camera.h>
+#define SIZEOF_I2C_TRANSBUF 32
+
struct ov5650_reg {
u16 addr;
u16 val;
@@ -39,6 +41,7 @@ struct ov5650_info {
enum StereoCameraMode camera_mode;
struct ov5650_sensor left;
struct ov5650_sensor right;
+ u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
static struct ov5650_info *stereo_ov5650_info;
@@ -777,7 +780,7 @@ static int ov5650_read_reg(struct i2c_client *client, u16 addr, u8 *val)
msg[0].buf = data;
/* high byte goes out first */
- data[0] = (u8) (addr >> 8);;
+ data[0] = (u8) (addr >> 8);
data[1] = (u8) (addr & 0xff);
msg[1].addr = client->addr;
@@ -824,12 +827,11 @@ static int ov5650_write_reg(struct i2c_client *client, u16 addr, u8 val)
int err;
struct i2c_msg msg;
unsigned char data[3];
- int retry = 0;
if (!client->adapter)
return -ENODEV;
- data[0] = (u8) (addr >> 8);;
+ data[0] = (u8) (addr >> 8);
data[1] = (u8) (addr & 0xff);
data[2] = (u8) (val & 0xff);
@@ -838,15 +840,11 @@ static int ov5650_write_reg(struct i2c_client *client, u16 addr, u8 val)
msg.len = 3;
msg.buf = data;
- do {
- err = i2c_transfer(client->adapter, &msg, 1);
- if (err == 1)
- return 0;
- retry++;
- pr_err("ov5650: i2c transfer failed, retrying %x %x\n",
- addr, val);
- usleep_range(3000, 3250);
- } while (retry <= OV5650_MAX_RETRIES);
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ pr_err("ov5650: i2c transfer failed, retrying %x %x\n", addr, val);
return err;
}
@@ -875,14 +873,66 @@ static int ov5650_write_reg_helper(struct ov5650_info *info,
return ret;
}
+static int ov5650_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ pr_err("ov5650: i2c bulk transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ov5650_write_bulk_reg_helper(struct ov5650_info *info, int len)
+{
+ int ret;
+ switch (info->camera_mode) {
+ case Main:
+ case StereoCameraMode_Left:
+ ret = ov5650_write_bulk_reg(info->left.i2c_client,
+ info->i2c_trans_buf, len);
+ break;
+ case StereoCameraMode_Stereo:
+ ret = ov5650_write_bulk_reg(info->left.i2c_client,
+ info->i2c_trans_buf, len);
+ if (ret)
+ break;
+ ret = ov5650_write_bulk_reg(info->right.i2c_client,
+ info->i2c_trans_buf, len);
+ break;
+ case StereoCameraMode_Right:
+ ret = ov5650_write_bulk_reg(info->right.i2c_client,
+ info->i2c_trans_buf, len);
+ break;
+ default:
+ return -1;
+ }
+ return ret;
+}
+
static int ov5650_write_table(struct ov5650_info *info,
const struct ov5650_reg table[],
const struct ov5650_reg override_list[],
int num_override_regs)
{
int err;
- const struct ov5650_reg *next;
- int i;
+ const struct ov5650_reg *next, *n_next;
+ u8 *b_ptr = info->i2c_trans_buf;
+ unsigned int buf_filled = 0;
+ unsigned int i;
u16 val;
for (next = table; next->addr != OV5650_TABLE_END; next++) {
@@ -892,7 +942,6 @@ static int ov5650_write_table(struct ov5650_info *info,
}
val = next->val;
-
/* When an override list is passed in, replace the reg */
/* value to write if the reg is in the list */
if (override_list) {
@@ -904,9 +953,28 @@ static int ov5650_write_table(struct ov5650_info *info,
}
}
- err = ov5650_write_reg_helper(info, next->addr, val);
+ if (!buf_filled) {
+ b_ptr = info->i2c_trans_buf;
+ *b_ptr++ = next->addr >> 8;
+ *b_ptr++ = next->addr & 0xff;
+ buf_filled = 2;
+ }
+ *b_ptr++ = val;
+ buf_filled++;
+
+ n_next = next + 1;
+ if (n_next->addr != OV5650_TABLE_END &&
+ n_next->addr != OV5650_TABLE_WAIT_MS &&
+ buf_filled < SIZEOF_I2C_TRANSBUF &&
+ n_next->addr == next->addr + 1) {
+ continue;
+ }
+
+ err = ov5650_write_bulk_reg_helper(info, buf_filled);
if (err)
return err;
+
+ buf_filled = 0;
}
return 0;
}
@@ -960,7 +1028,6 @@ static int ov5650_set_mode(struct ov5650_info *info, struct ov5650_mode *mode)
if (err)
return err;
}
-
last_mode = mode_table[sensor_mode];
err = ov5650_write_table(info, mode_table[sensor_mode],
@@ -1060,44 +1127,44 @@ static int ov5650_set_binning(struct ov5650_info *info, u8 enable)
return -EIO;
if (!enable) {
- ret = ov5650_write_reg_helper(info,
- OV5650_ARRAY_CONTROL_01,
- array_ctrl_reg |
- (OV5650_H_BINNING_BIT | OV5650_H_SUBSAMPLING_BIT));
+ ret = ov5650_write_reg_helper(info,
+ OV5650_ARRAY_CONTROL_01,
+ array_ctrl_reg |
+ (OV5650_H_BINNING_BIT | OV5650_H_SUBSAMPLING_BIT));
- if (ret < 0)
- goto exit;
+ if (ret < 0)
+ goto exit;
- ret = ov5650_write_reg_helper(info,
- OV5650_ANALOG_CONTROL_D,
- analog_ctrl_reg & ~OV5650_V_BINNING_BIT);
+ ret = ov5650_write_reg_helper(info,
+ OV5650_ANALOG_CONTROL_D,
+ analog_ctrl_reg & ~OV5650_V_BINNING_BIT);
- if (ret < 0)
- goto exit;
+ if (ret < 0)
+ goto exit;
- ret = ov5650_write_reg_helper(info,
- OV5650_TIMING_TC_REG_18,
- timing_reg | OV5650_V_SUBSAMPLING_BIT);
+ ret = ov5650_write_reg_helper(info,
+ OV5650_TIMING_TC_REG_18,
+ timing_reg | OV5650_V_SUBSAMPLING_BIT);
- if (ret < 0)
- goto exit;
+ if (ret < 0)
+ goto exit;
- if (info->mode == OV5650_MODE_1296x972)
- val = 0x1A2;
- else
- /* FIXME: this value is not verified yet. */
- val = 0x1A8;
+ if (info->mode == OV5650_MODE_1296x972)
+ val = 0x1A2;
+ else
+ /* FIXME: this value is not verified yet. */
+ val = 0x1A8;
- ret = ov5650_write_reg_helper(info,
- OV5650_TIMING_CONTROL_HS_HIGH,
- (val >> 8));
+ ret = ov5650_write_reg_helper(info,
+ OV5650_TIMING_CONTROL_HS_HIGH,
+ (val >> 8));
- if (ret < 0)
- goto exit;
+ if (ret < 0)
+ goto exit;
- ret = ov5650_write_reg_helper(info,
- OV5650_TIMING_CONTROL_HS_LOW,
- (val & 0xFF));
+ ret = ov5650_write_reg_helper(info,
+ OV5650_TIMING_CONTROL_HS_LOW,
+ (val & 0xFF));
} else {
ret = ov5650_write_reg_helper(info,
OV5650_ARRAY_CONTROL_01,
@@ -1145,7 +1212,8 @@ exit:
ret |= ov5650_write_reg_helper(info,
OV5650_SRM_GRUP_ACCESS,
- (OV5650_GROUP_HOLD_BIT | OV5650_GROUP_LAUNCH_BIT | OV5650_GROUP_ID(3)));
+ (OV5650_GROUP_HOLD_BIT | OV5650_GROUP_LAUNCH_BIT |
+ OV5650_GROUP_ID(3)));
return ret;
}