Submitting a sign off for:
Patch 3/4: Perform more extensive I2C bus normalization and slave reset
This patch attempt to perform a more extensive I2C bus initialization
and slave reset procedure for the 2 I2C buses controlled by the cx23418.
The normalization procedure tries to get any slaves to let go of the bus
lines and put the bus in an idle state by clocking the bus for a few
cycles and sending a stop condition.
The slave device reset procedure is a procedure recommended by the
datasheet for the ATMEL Serial EEPROM that is found on my HVR-1600.
This patch is a blind effort to help people with HVR-1600 I2C problems.
In my personal testing, it did not introduce problems for me.
Refer to:
1. I2C Bus Specification and User Manual:
http://www.nxp.com/acrobat_download/usermanuals/UM10204_3.pdf
2. ATMEL AT24C02B Two Wire Serial EEPROM datasheet:
http://www.atmel.com/dyn/resources/prod_documents/doc5126.pdf
-Andy
I consider the quote from the ATMEL datasheet in the comments as "fair
use" under US copyright law, since it is short and I cited the source
reference. Feel free to remove the quote if you have concerns.
Signed-off-by: G. Andrew Walls <[EMAIL PROTECTED]>
--- cx18-f763c5864f9a/linux/drivers/media/video/cx18/cx18-i2c.c.change2 2008-04-17 19:08:28.000000000 -0400
+++ cx18-f763c5864f9a/linux/drivers/media/video/cx18/cx18-i2c.c 2008-04-17 20:47:20.000000000 -0400
@@ -261,6 +261,115 @@ 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);
+ }
+
+ /* 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);
+
+ /* Emit START */
+ 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);
+
+ 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;
@@ -429,12 +538,16 @@ int init_cx18_i2c(struct cx18 *cx)
write_reg(0x00c00000, 0xc730c4); /* Clear any stale intrs */
write_reg(0x00021c0f & ~4, CX18_REG_I2C_1_WR); /* Hw I2C1 Clock Freq ~100kHz */
- 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");
write_reg(0x00021c0f & ~4, CX18_REG_I2C_2_WR); /* Hw I2C2 Clock Freq ~100kHz */
- 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-devel mailing list
[email protected]
http://ivtvdriver.org/mailman/listinfo/ivtv-devel