Some upcoming changes in inteldrm(4) KMS land require us to do I2C
transfer doing stupid bit banging. But this doesn't work unless I
slightly adjust the timings in our generic I2C bit banging code. I'm
not sure if the device I'm talking to is just not up to spec or if the
delay loops in the kernel are simply not accurate enough. Increasing
the delays slightly seems to fix the problem.
I don't expect any problems for other users of this code. We'll just
be talking to I2C slave devices at a slighly lower clock rate. Might
even make things work more reliable. But since it is always good to
test things, I'd like to give gdiumiic(4) users (found on some laptops
supported by OpenBSD/loongson) the opportunity to test this.
Thanks,
Mark
Index: i2c_bitbang.c
===================================================================
RCS file: /cvs/src/sys/dev/i2c/i2c_bitbang.c,v
retrieving revision 1.3
diff -u -p -r1.3 i2c_bitbang.c
--- i2c_bitbang.c 13 Jan 2006 23:56:46 -0000 1.3
+++ i2c_bitbang.c 31 Mar 2013 10:30:32 -0000
@@ -62,11 +62,11 @@ i2c_bitbang_send_start(void *v, int flag
BB_DIR(OUTPUT);
BB_SET(SDA | SCL);
- delay(5); /* bus free time (4.7 uS) */
+ delay(6); /* bus free time (4.7 uS) */
BB_SET( SCL);
- delay(4); /* start hold time (4.0 uS) */
+ delay(5); /* start hold time (4.0 uS) */
BB_SET( 0);
- delay(5); /* clock low time (4.7 uS) */
+ delay(6); /* clock low time (4.7 uS) */
return (0);
}
@@ -79,7 +79,7 @@ i2c_bitbang_send_stop(void *v, int flags
BB_DIR(OUTPUT);
BB_SET( SCL);
- delay(4); /* stop setup time (4.0 uS) */
+ delay(5); /* stop setup time (4.0 uS) */
BB_SET(SDA | SCL);
return (0);
@@ -115,11 +115,11 @@ i2c_bitbang_read_byte(void *v, uint8_t *
for (i = 0; i < 8; i++) {
val <<= 1;
BB_SET(SDA | SCL);
- delay(4); /* clock high time (4.0 uS) */
+ delay(5); /* clock high time (4.0 uS) */
if (BB_READ & SDA)
val |= 1;
BB_SET(SDA );
- delay(5); /* clock low time (4.7 uS) */
+ delay(6); /* clock low time (4.7 uS) */
}
bit = (flags & I2C_F_LAST) ? SDA : 0;
@@ -127,13 +127,13 @@ i2c_bitbang_read_byte(void *v, uint8_t *
BB_SET(bit );
delay(1); /* data setup time (250 nS) */
BB_SET(bit | SCL);
- delay(4); /* clock high time (4.0 uS) */
+ delay(5); /* clock high time (4.0 uS) */
BB_SET(bit );
- delay(5); /* clock low time (4.7 uS) */
+ delay(6); /* clock low time (4.7 uS) */
BB_DIR(INPUT);
BB_SET(SDA );
- delay(5);
+ delay(6);
if ((flags & (I2C_F_STOP | I2C_F_LAST)) == (I2C_F_STOP | I2C_F_LAST))
(void) i2c_bitbang_send_stop(v, flags, ops);
@@ -157,20 +157,20 @@ i2c_bitbang_write_byte(void *v, uint8_t
BB_SET(bit );
delay(1); /* data setup time (250 nS) */
BB_SET(bit | SCL);
- delay(4); /* clock high time (4.0 uS) */
+ delay(5); /* clock high time (4.0 uS) */
BB_SET(bit );
- delay(5); /* clock low time (4.7 uS) */
+ delay(6); /* clock low time (4.7 uS) */
}
BB_DIR(INPUT);
BB_SET(SDA );
- delay(5);
+ delay(6);
BB_SET(SDA | SCL);
- delay(4);
+ delay(5);
error = (BB_READ & SDA) ? EIO : 0;
BB_SET(SDA );
- delay(5);
+ delay(6);
if (flags & I2C_F_STOP)
(void) i2c_bitbang_send_stop(v, flags, ops);