From fb1f9020609ead93fcec4b0dd02511a46294c147 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Oct 2009 07:42:53 -0300 Subject: 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov519.c | 53 +++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'drivers/media/video/gspca/ov519.c') diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 994a5e927d2..91e9b23a3a0 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 -- cgit v1.2.3-70-g09d2