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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux