[linux-dvb] [PATCH] make the registers of the stv0297 visible for other applications (e.g. i2cdump)

Trent Piepho xyzzy at speakeasy.org
Mon Jun 11 06:56:00 CEST 2007

On Wed, 6 Jun 2007, Oliver Endriss wrote:
> e9hack wrote:
> > Trent Piepho wrote:
> > >
> > > Does the stv0297 require that no other i2c traffic, to a different device,
> > > appear between the write and the read?  Something like:
> > >
> > > S stv_addr_W A reg_addr A P
> > > S tuner_addr_W A tuner_data1 A tuner_data2 A P
> > > S stv_addr_R A reg_data NA P
> > >
> > > Will the i2c message to the tuner between the two parts of the stv register
> > > reading sequence be a problem?
> >
> > The tuner may be a problem, because the stv0297 is the gate for the tuner i2c-bus.
> Correct. Since the I2C gate closes after the following stop condition,
> we have a problem, if another I2C transfer happens between gate open and
> PLL access:
> (1) S stv_addr_W A ...open_gate... P
> (2) S eeprom_addr_W A reg_addr A Sr eeprom_addr_R A reg_data NA P
> (3) S pll_addr_W A ...pll_data... P
> will not work because the I2C gate closes after (2)!

This could be fixed if there was an I2C_M_STOP flag.  Have the stv0297 or
another demod that has an i2c gate register a new "bridge" i2c adapter.

The master_xfer function for this bridge i2c adapter just puts a message to
turn on the i2c gate in front of the transaction and then hands it off the
the real i2c adapter.  Since it's a single atomic transaction, you don't need
to worry about another device sneaking in at (2) and closing the gate.  If
the device is behind the i2c gate, like the tuner, it's attached to the
bridge i2c adapter, and if it's not, like the eeprom, it's attached to the
real i2c adapter.

It would look something like this:

struct stv0299_state {
	i2c_adapter	*i2c_adap;
	u8      	i2c_addr;
static int stv0299_master_xfer(struct i2c_adapter *adap,
		               struct i2c_msg msg[], int num)
	static char buf[] = { 0x05, 0xb5 };
	struct stv0299_state *st = i2c_get_adapdata(adap);
	struct i2c_msg gate_msg = { .addr = st->i2c_addr, .flags = I2C_M_STOP,
	                            .buf = buf, .len = sizeof(buf) };
	struct i2c_msg *msg_out;
	int ret;

	msg_out = kmalloc((num + 1) * sizeof(struct i2c_msg), GPF_ATOMIC);
	memcpy(msg_out, &gate_msg, sizeof(struct i2c_msg));
	memcpy(msg_out+1, msg, num * sizeof(struct i2c_msg));

	ret = i2c_transfer(st->i2c_adap, msg_out, num+1);
	return ret;

The code for i2c_transfer() that I posted in the patch for I2C_M_STOP will
automatically split this into two transactions around the I2C_M_STOP flag,
but both will occur before the i2c adapter's mutex is released so no other
message can sneak in.

More information about the linux-dvb mailing list