summaryrefslogtreecommitdiff
path: root/drivers/media/video/gspca/ov519.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2009-10-16 07:42:53 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 18:40:45 -0200
commitfb1f9020609ead93fcec4b0dd02511a46294c147 (patch)
tree867752434af3591fa3f57abaf315d8b40d3348b9 /drivers/media/video/gspca/ov519.c
parenta511ba947600ae263f8c29c86020ba66a901d3e5 (diff)
V4L/DVB (13179): gspca_ov519: cache sensor regs to avoid unnecessary slow i2c reads / writes
Cache sensor regs to avoid unnecessary slow i2c reads / writes, this speeds up sd_start a bit with most bridges and a lot (from 5 seconds down to 0.3 seconds) with W996xCF cams, as this avoids very slow bit bang IO over USB i2c reads. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca/ov519.c')
-rw-r--r--drivers/media/video/gspca/ov519.c53
1 files changed, 43 insertions, 10 deletions
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 994a5e927d2d..91e9b23a3a01 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -103,6 +103,7 @@ struct sd {
u8 sensor_addr;
int sensor_width;
int sensor_height;
+ int sensor_reg_cache[256];
};
/* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -2210,38 +2211,70 @@ static int ovfx2_i2c_r(struct sd *sd, __u8 reg)
static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
{
+ int ret = -1;
+
+ if (sd->sensor_reg_cache[reg] == value)
+ return 0;
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- return ov511_i2c_w(sd, reg, value);
+ ret = ov511_i2c_w(sd, reg, value);
+ break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
case BRIDGE_OV519:
- return ov518_i2c_w(sd, reg, value);
+ ret = ov518_i2c_w(sd, reg, value);
+ break;
case BRIDGE_OVFX2:
- return ovfx2_i2c_w(sd, reg, value);
+ ret = ovfx2_i2c_w(sd, reg, value);
+ break;
case BRIDGE_W9968CF:
- return w9968cf_i2c_w(sd, reg, value);
+ ret = w9968cf_i2c_w(sd, reg, value);
+ break;
+ }
+
+ if (ret >= 0) {
+ /* Up on sensor reset empty the register cache */
+ if (reg == 0x12 && (value & 0x80))
+ memset(sd->sensor_reg_cache, -1,
+ sizeof(sd->sensor_reg_cache));
+ else
+ sd->sensor_reg_cache[reg] = value;
}
- return -1; /* Should never happen */
+
+ return ret;
}
static int i2c_r(struct sd *sd, __u8 reg)
{
+ int ret;
+
+ if (sd->sensor_reg_cache[reg] != -1)
+ return sd->sensor_reg_cache[reg];
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- return ov511_i2c_r(sd, reg);
+ ret = ov511_i2c_r(sd, reg);
+ break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
case BRIDGE_OV519:
- return ov518_i2c_r(sd, reg);
+ ret = ov518_i2c_r(sd, reg);
+ break;
case BRIDGE_OVFX2:
- return ovfx2_i2c_r(sd, reg);
+ ret = ovfx2_i2c_r(sd, reg);
+ break;
case BRIDGE_W9968CF:
- return w9968cf_i2c_r(sd, reg);
+ ret = w9968cf_i2c_r(sd, reg);
+ break;
}
- return -1; /* Should never happen */
+
+ if (ret >= 0)
+ sd->sensor_reg_cache[reg] = ret;
+
+ return ret;
}
/* Writes bits at positions specified by mask to an I2C reg. Bits that are in