Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb1f9020 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

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: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a511ba94
Loading
Loading
Loading
Loading
+43 −10
Original line number Original line Diff line number Diff line
@@ -103,6 +103,7 @@ struct sd {
	u8 sensor_addr;
	u8 sensor_addr;
	int sensor_width;
	int sensor_width;
	int sensor_height;
	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
/* 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)
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) {
	switch (sd->bridge) {
	case BRIDGE_OV511:
	case BRIDGE_OV511:
	case BRIDGE_OV511PLUS:
	case BRIDGE_OV511PLUS:
		return ov511_i2c_w(sd, reg, value);
		ret = ov511_i2c_w(sd, reg, value);
		break;
	case BRIDGE_OV518:
	case BRIDGE_OV518:
	case BRIDGE_OV518PLUS:
	case BRIDGE_OV518PLUS:
	case BRIDGE_OV519:
	case BRIDGE_OV519:
		return ov518_i2c_w(sd, reg, value);
		ret = ov518_i2c_w(sd, reg, value);
		break;
	case BRIDGE_OVFX2:
	case BRIDGE_OVFX2:
		return ovfx2_i2c_w(sd, reg, value);
		ret = ovfx2_i2c_w(sd, reg, value);
		break;
	case BRIDGE_W9968CF:
	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)
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) {
	switch (sd->bridge) {
	case BRIDGE_OV511:
	case BRIDGE_OV511:
	case BRIDGE_OV511PLUS:
	case BRIDGE_OV511PLUS:
		return ov511_i2c_r(sd, reg);
		ret = ov511_i2c_r(sd, reg);
		break;
	case BRIDGE_OV518:
	case BRIDGE_OV518:
	case BRIDGE_OV518PLUS:
	case BRIDGE_OV518PLUS:
	case BRIDGE_OV519:
	case BRIDGE_OV519:
		return ov518_i2c_r(sd, reg);
		ret = ov518_i2c_r(sd, reg);
		break;
	case BRIDGE_OVFX2:
	case BRIDGE_OVFX2:
		return ovfx2_i2c_r(sd, reg);
		ret = ovfx2_i2c_r(sd, reg);
		break;
	case BRIDGE_W9968CF:
	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
/* Writes bits at positions specified by mask to an I2C reg. Bits that are in