Hi, the stv0297 doesn't understand the repeated start condition on the i2c-bus from a saa7146. The current frontend driver (stv0297.c) handles this problem by splitting the read request into a write and a read request. Other applications (e.g. i2cdump) are not able to read the registers from the stv0297. The attached patch lets solve the saa7146 this problem. If it is necessary, the driver inserts an additional stop condition and moves the following start condition into the next upload command for the saa7146. - Hartmut
Signed-off-by: Hartmut Birr <e9hack@xxxxxxxxxxxxxx> - If it is necessary, split a i2c-read-request into a write and a read request to prevent the using of a repeated start condition. diff -r 6785574f5f6e linux/drivers/media/common/saa7146_i2c.c --- a/linux/drivers/media/common/saa7146_i2c.c Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/common/saa7146_i2c.c Fri May 18 13:47:02 2007 +0200 @@ -25,7 +25,7 @@ static inline u32 saa7146_i2c_status(str sent through the saa7146. have a look at the specifications p. 122 ff to understand this. it returns the number of u32s to send, or -1 in case of an error. */ -static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) +static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op, u32 no_rep_start) { int h1, h2; int i, j, addr; @@ -34,6 +34,9 @@ static int saa7146_i2c_msg_prepare(const /* first determine size of needed memory */ for(i = 0; i < num; i++) { mem += m[i].len + 1; + if (i < num - 1 && no_rep_start && mem % 3) { + mem += 3 - mem % 3; + } } /* worst case: we need one u32 for three bytes to be send @@ -52,7 +55,17 @@ static int saa7146_i2c_msg_prepare(const /* loop through all messages */ for(i = 0; i < num; i++) { - + if (i > 0 && no_rep_start) { + /* change the last byte of the previous message to stop */ + h1 = (op_count-1)/3; h2 = (op_count-1)%3; + op[h1] &= ~(0x3 << ((3-h2)*2)); + op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2)); + /* adjust to the next u32 boundary */ + if (op_count % 3) { + op_count += 3 - op_count % 3; + } + } + /* insert the address of the i2c-slave. note: we get 7 bit i2c-addresses, so we have to perform a translation */ @@ -70,7 +83,6 @@ static int saa7146_i2c_msg_prepare(const op[h1] |= ( SAA7146_I2C_CONT << ((3-h2)*2)); op_count++; } - } /* have a look at the last byte inserted: @@ -89,13 +101,19 @@ static int saa7146_i2c_msg_prepare(const which bytes were read through the adapter and write them back to the corresponding i2c-message. but instead, we simply write back all bytes. fixme: this could be improved. */ -static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op) +static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op, u32 no_rep_start) { int i, j; int op_count = 0; /* loop through all messages */ for(i = 0; i < num; i++) { + if (i > 0 && no_rep_start) { + /* adjust to the next u32 boundary */ + if (op_count %3) { + op_count += 3 - op_count % 3; + } + } op_count++; @@ -294,7 +312,7 @@ int saa7146_i2c_transfer(struct saa7146_ } /* prepare the message(s), get number of u32s to transfer */ - count = saa7146_i2c_msg_prepare(msgs, num, buffer); + count = saa7146_i2c_msg_prepare(msgs, num, buffer, dev->i2c_no_rep_start); if ( 0 > count ) { err = -1; goto out; @@ -354,7 +372,7 @@ int saa7146_i2c_transfer(struct saa7146_ } /* if any things had to be read, get the results */ - if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) { + if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer, dev->i2c_no_rep_start)) { DEB_I2C(("could not cleanup i2c-message.\n")); err = -1; goto out; diff -r 6785574f5f6e linux/drivers/media/dvb/frontends/stv0297.c --- a/linux/drivers/media/dvb/frontends/stv0297.c Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/dvb/frontends/stv0297.c Fri May 18 13:32:45 2007 +0200 @@ -72,21 +72,9 @@ static int stv0297_readreg(struct stv029 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} }; - // this device needs a STOP between the register and data - if (state->config->stop_during_read) { - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } - } else { - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); + return -1; } return b1[0]; @@ -112,21 +100,9 @@ static int stv0297_readregs(struct stv02 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} }; - // this device needs a STOP between the register and data - if (state->config->stop_during_read) { - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } - } else { - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); + return -1; } return 0; diff -r 6785574f5f6e linux/drivers/media/dvb/frontends/stv0297.h --- a/linux/drivers/media/dvb/frontends/stv0297.h Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/dvb/frontends/stv0297.h Fri May 18 13:31:17 2007 +0200 @@ -37,9 +37,6 @@ struct stv0297_config /* does the "inversion" need inverted? */ u8 invert:1; - - /* set to 1 if the device requires an i2c STOP during reading */ - u8 stop_during_read:1; }; #if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE)) diff -r 6785574f5f6e linux/drivers/media/dvb/ttpci/av7110.c --- a/linux/drivers/media/dvb/ttpci/av7110.c Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/dvb/ttpci/av7110.c Fri May 18 13:31:58 2007 +0200 @@ -1863,7 +1863,6 @@ static struct stv0297_config nexusca_stv .demod_address = 0x1C, .inittab = nexusca_stv0297_inittab, .invert = 1, - .stop_during_read = 1, }; @@ -2207,7 +2206,7 @@ static int frontend_init(struct av7110 * break; case 0x000A: // Hauppauge/TT Nexus-CA rev1.X - + av7110->dev->i2c_no_rep_start = 1; av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; diff -r 6785574f5f6e linux/drivers/media/dvb/ttpci/budget-ci.c --- a/linux/drivers/media/dvb/ttpci/budget-ci.c Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c Fri May 18 13:33:15 2007 +0200 @@ -1059,7 +1059,6 @@ static struct stv0297_config dvbc_philip .demod_address = 0x1c, .inittab = dvbc_philips_tdm1316l_inittab, .invert = 0, - .stop_during_read = 1, }; @@ -1088,6 +1087,7 @@ static void frontend_init(struct budget_ break; case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) + budget_ci->budget.dev->i2c_no_rep_start = 1; budget_ci->tuner_pll_address = 0x61; budget_ci->budget.dvb_frontend = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); diff -r 6785574f5f6e linux/include/media/saa7146.h --- a/linux/include/media/saa7146.h Mon May 14 04:25:57 2007 +0200 +++ b/linux/include/media/saa7146.h Fri May 18 13:16:25 2007 +0200 @@ -158,6 +158,7 @@ struct saa7146_dev struct saa7146_dma d_i2c; /* pointer to i2c memory */ wait_queue_head_t i2c_wq; int i2c_op; + unsigned char i2c_no_rep_start:1; /* memories */ struct saa7146_dma d_rps0;
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb