On Thu, 2008-05-15 at 20:23 -0400, Andy Walls wrote:
> On Thu, 2008-05-15 at 12:28 -0700, Michael wrote:

> > > 
> > > Ok.  So at first glance, you don't have the same I2C bus problems that
> > > other users seem to have.  Other users appear to have PCI bus problems
> > > which I think causes the cx18 driver to mess up I2C control registers
> > > and hence I2C transactions.
> > > 
> > > Your log file, on the other hand, indicates that there are no PCI bus
> > > problems AFAICT, but that initial communications on the i2c bus with the
> > > EEPROM is returning all 0 bits. 
> > > 
> > > In examining the log there is a "glitch" in the log file that looks like
> > > this:
> > > 
> > > May 13 15:14:29 localhost kernel: cx180 i2c: cx18_getscl: read 
> > > CX18_REG_I2C_1_RD 
> > > = 0x4
> > > May 13 15:14:29 localhost kernel: cx180 i2c: cx18_setscl: On entry 
> > > CX18_REG_I2C_1_WR = 0x21c09
> > > May 13 15:14:29 localhost kernel: cx180 i2c: cx18_setscl: Wrote    
> > > CX18_REG_I2_REG_I2C_1_WR = 0x21c0a  <------
> > > May 13 15:14:29 localhost kernel: cx180 i2c: cx18_setscl: Wrote    
> > > CX18_REG_I2C_1_WR = 0x21c0b
> > > May 13 15:14:29 localhost kernel: cx180 i2c: cx18_setscl: Readback 
> > > CX18_REG_I2C_1_WR = 0x21c0b
> > > May 13 15:14:29 localhost kernel: cx180 i2c: cx18_getscl: read 
> > > CX18_REG_I2C_1_RD 
> > > = 0x4
> > > 
> > > Normally these sorts of misprints don't bother me with verbose logging,
> > > since it usually simply means the log facility couldn't keep up at the
> > > moment.  However, it is the *only* such glitch in the log, and it
> > > happens during the sequence where the EEPROM's final address bits are
> > > being put out on the I2C bus.
> > > 
> > > Thus, I can't say for sure that you have a stuck device on the I2C bus,
> > > or if some kernel bug is causing a problem in addressing the EERPOM.
> > > 
> > > In the log, subsequent transactions to another device on the same I2C
> > > work just fine.
> > > 
> > > 
> > > 
> > > So for courses of action:
> > > 
> > > For me to do:
> > > 1. Provide an I2C bus startup normalization sequence patch, to hopefully
> > > cause the I2C bus and devices to get "unstuck" on module load.  (And
> > > also turn any initial "glitch" or kernel bug into a don't care
> > > condition).

Michael,

I have attached a patch that performs more aggressive i2c bus
initialization for the i2c buses controlled by the cx23418.  The patch
cuases the cx18 driver on modprobe to initialize both i2c buses by
clocking ten bits and a stop marker to no particular device, and then
send an EEPROM reset sequence on the i2c buses as described in the ATMEL
serial EEPROM datasheet.

This patch depends on the previous patch you have applied, so you should
not back out the previous patch before applying this one.

If the patch works, your EEPROM will be recognized properly every time,
without you needing to specify any special module options.

-Andy


 
> > > For you, if you desire:
> > > 1. A few unloads and reloads of the cx18 module, to see if there is any
> > > correlation between a "glitch" showing up early in the log and the
> > > EEPROM read working properly or not.
> > > 
> > > 2. Try slowing down the i2c bus clock for the cx18 driver.  The patched
> > > module you have built has a new option: i2c_clock_period.  Slowing down
> > > the i2c bus clock may mitigate the problem.  The default is a 10 usec
> > > clock period.  The maximum can be very long, but much more than 4500
> > > usec caused a serious kernel hang on my machine.
> > > 
> > > So maybe you can try:
> > > 
> > >     # modprobe -r cx18 i2c-algo-bit
> > >     # modprobe i2c-algo-bit debug=1
> > >     # modprobe cx18 debug=323 i2c_clock_period=200
> > > 
> > > You can try longer clock periods if you like, but beware your machine
> > > could hang badly, requiring a hard shutdown.
> > >     
> > > 
> > 
> > When I run the test, do you want me to do another logger test, or attach 
> > anything?
> 
> Only one log sequence, no matter how things turn out.
> 
> 1. If you can reliably have the EEPROM recognized, over several trials,
> by simply increasing the clock period, then I'd also like to know what
> the smallest i2c_clock_period is that works reliably for you.  At this
> point though, you'll have 1 known good workaround.  (I'm not optimistic
> that this will be the case though.)
> 
> 2.  If you still can't get the EEPROM to be recognized reliably, just
> sned the log when you use the default clock period of 10 usec.  I'd like
> to see what i2c_algo_bit gripes about in the log, so hopefully, it's
> built with DEBUG in your kernel.  (If it isn't, don't worry about it -
> the solution is probably the same whether I have debug logging from
> i2c_algo_bit or not.)
> 
> 
> Again, I owe you a patch, that I have high confidence will fix your
> problem.  So you don't have to go through the above, if you don't want
> to.  I'll probably be able to get a patch to you tomorrow. 
> 
> -Andy

diff -r 9a37062d703b linux/drivers/media/video/cx18/cx18-i2c.c
--- a/linux/drivers/media/video/cx18/cx18-i2c.c	Fri May 16 09:34:06 2008 -0400
+++ b/linux/drivers/media/video/cx18/cx18-i2c.c	Fri May 16 10:28:01 2008 -0400
@@ -332,6 +332,111 @@ static struct i2c_client cx18_i2c_client
 	.name = "cx18 internal",
 };
 
+static int cx18_i2c_reset_slaves(struct cx18_i2c_algo_callback_data *cb_data,
+                                  struct i2c_algo_bit_data *bit_algo)
+{
+	/* 
+	 * From the datasheet for the ATMEL AT24C02B 2 wire Serial EEPROM
+	 * that is on my HVR-1600:
+	 * "2-Wire Software Reset: After an interruption in protocol, power 
+	 * loss or system reset, any 2-wire part can be reset by following
+	 * these steps:
+	 * (a) Create a start bit condition,
+	 * (b) clock 9 cycles,
+	 * (c) create another start bit followed by stop bit condition [...].
+	 * The device is ready for next communication after above steps have
+	 * been completed."
+	 */
+
+	int i, quarter_cycle, half_cycle;
+
+	half_cycle = bit_algo->udelay;
+	quarter_cycle = (half_cycle + 1)/2;
+
+	/*
+ 	* Here we assume the bus has already been normalized and
+ 	* SDA & SCL are high and have been high for the minimum bus idle time
+ 	*
+ 	* Since we're not trying to duplicate all the intricacies of
+ 	* i2c-algo-bit here, we'll be lazy and assume that none of the slaves
+ 	* will pull SDA & SCL low at a  time that would cause problems with
+ 	* the START & STOP conditions
+ 	*/
+
+	/* Emit START */
+	bit_algo->setsda(cb_data, 0);
+	udelay(half_cycle);
+	bit_algo->setscl(cb_data, 0);
+		
+	/* Clock 9 bits of nothing */
+	udelay(quarter_cycle);
+	bit_algo->setsda(cb_data, 1);
+	for (i = 0; i < 9; i++)
+	{
+		udelay(quarter_cycle);
+		bit_algo->setscl(cb_data, 1);
+		udelay(half_cycle);
+		bit_algo->setscl(cb_data, 0);
+		udelay(quarter_cycle);
+	}
+	udelay(quarter_cycle);
+
+	/* Emit Repeated START */
+	bit_algo->setscl(cb_data, 1);
+	udelay(half_cycle);
+	bit_algo->setsda(cb_data, 0);
+	udelay(half_cycle);
+	bit_algo->setscl(cb_data, 0);
+		
+	/* Emit STOP */
+	udelay(half_cycle);
+	bit_algo->setscl(cb_data, 1);
+	udelay(half_cycle);
+	bit_algo->setsda(cb_data, 1);
+
+	/* Idle bus */
+	udelay(half_cycle);
+
+	return !(bit_algo->getsda(cb_data) && bit_algo->getscl(cb_data));
+}
+
+static int cx18_i2c_normalize_bus(struct cx18_i2c_algo_callback_data *cb_data,
+                                  struct i2c_algo_bit_data *bit_algo)
+{
+	int i, quarter_cycle, half_cycle;
+
+	half_cycle = bit_algo->udelay;
+	quarter_cycle = (half_cycle + 1)/2;
+
+	/* Hopefully raise the lines */
+	bit_algo->setsda(cb_data, 1);
+	bit_algo->setscl(cb_data, 1);
+
+	/* blindly clocking 10 don't care bits without emitting a START */
+	udelay(half_cycle);
+	bit_algo->setscl(cb_data, 0);
+	for (i = 0; i < 10; i++)
+	{
+		udelay(half_cycle);
+		bit_algo->setscl(cb_data, 1);
+		udelay(half_cycle);
+		bit_algo->setscl(cb_data, 0);
+	} 
+	udelay(quarter_cycle);
+
+	/* Emit STOP */
+	bit_algo->setsda(cb_data, 0);
+	udelay(quarter_cycle);
+	bit_algo->setscl(cb_data, 1);
+	udelay(half_cycle);
+	bit_algo->setsda(cb_data, 1);
+	
+	/* Idle bus */
+	udelay(half_cycle);
+
+	return !(bit_algo->getsda(cb_data) && bit_algo->getscl(cb_data));
+}
+
 int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
 {
 	struct i2c_client *client;
@@ -506,15 +611,21 @@ int init_cx18_i2c(struct cx18 *cx)
 	/* Hw I2C1 Clock Freq ~100kHz */
 	write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
 	cx->i2c_algo_cb_data[0].wr_reg_copy = 0x00021c0f & ~4;
-	cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
-	cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
+
+ 	if (cx18_i2c_normalize_bus(&cx->i2c_algo_cb_data[0], &cx->i2c_algo[0]))
+ 		CX18_DEBUG_WARN("failed to normalize first i2c bus\n");
+ 	if (cx18_i2c_reset_slaves(&cx->i2c_algo_cb_data[0], &cx->i2c_algo[0]))
+ 		CX18_DEBUG_WARN("couldn't reset slaves on first i2c bus\n");
 
 	/* Hw I2C2 Clock Freq ~100kHz */
 	write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
 	cx->i2c_algo_cb_data[1].wr_reg_copy = 0x00021c0f & ~4;
-	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
-	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
-
+
+ 	if (cx18_i2c_normalize_bus(&cx->i2c_algo_cb_data[1], &cx->i2c_algo[1]))
+ 		CX18_DEBUG_WARN("failed to normalize second i2c bus\n");
+ 	if (cx18_i2c_reset_slaves(&cx->i2c_algo_cb_data[1], &cx->i2c_algo[1]))
+ 		CX18_DEBUG_WARN("couldn't reset slaves on second i2c bus\n");
+  
 	return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
 		i2c_bit_add_bus(&cx->i2c_adap[1]);
 }
_______________________________________________
ivtv-users mailing list
[email protected]
http://ivtvdriver.org/mailman/listinfo/ivtv-users

Reply via email to