summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c42
-rw-r--r--include/linux/i2c-algo-bit.h6
2 files changed, 26 insertions, 22 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index fc16f9d268a3..d9d0ec49e60d 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -57,19 +57,19 @@ static int bit_test; /* see if the line-setting functions work */
static inline void sdalo(struct i2c_algo_bit_data *adap)
{
setsda(adap,0);
- udelay(adap->udelay);
+ udelay((adap->udelay + 1) / 2);
}
static inline void sdahi(struct i2c_algo_bit_data *adap)
{
setsda(adap,1);
- udelay(adap->udelay);
+ udelay((adap->udelay + 1) / 2);
}
static inline void scllo(struct i2c_algo_bit_data *adap)
{
setscl(adap,0);
- udelay(adap->udelay);
+ udelay(adap->udelay / 2);
}
/*
@@ -111,18 +111,19 @@ static void i2c_start(struct i2c_algo_bit_data *adap)
{
/* assert: scl, sda are high */
DEBPROTO(printk("S "));
- sdalo(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
scllo(adap);
}
static void i2c_repstart(struct i2c_algo_bit_data *adap)
{
- /* scl, sda may not be high */
+ /* assert: scl is low */
DEBPROTO(printk(" Sr "));
- setsda(adap,1);
+ sdahi(adap);
sclhi(adap);
-
- sdalo(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
scllo(adap);
}
@@ -133,7 +134,8 @@ static void i2c_stop(struct i2c_algo_bit_data *adap)
/* assert: scl is low */
sdalo(adap);
sclhi(adap);
- sdahi(adap);
+ setsda(adap, 1);
+ udelay(adap->udelay);
}
@@ -156,18 +158,16 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
for ( i=7 ; i>=0 ; i-- ) {
sb = c & ( 1 << i );
setsda(adap,sb);
- udelay(adap->udelay);
+ udelay((adap->udelay + 1) / 2);
DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
if (sclhi(adap)<0) { /* timed out */
- sdahi(adap); /* we don't want to block the net */
DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
return -ETIMEDOUT;
};
/* do arbitration here:
* if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
*/
- setscl(adap, 0 );
- udelay(adap->udelay);
+ scllo(adap);
}
sdahi(adap);
if (sclhi(adap)<0){ /* timeout */
@@ -204,7 +204,8 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
indata *= 2;
if ( getsda(adap) )
indata |= 0x01;
- scllo(adap);
+ setscl(adap, 0);
+ udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
}
/* assert: scl is low */
DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
@@ -315,9 +316,9 @@ static int try_address(struct i2c_adapter *i2c_adap,
if (ret == 1 || i == retries)
break;
i2c_stop(adap);
- udelay(5/*adap->udelay*/);
- i2c_start(adap);
udelay(adap->udelay);
+ yield();
+ i2c_start(adap);
}
DEB2(if (i)
printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
@@ -377,20 +378,21 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if (msg->flags & I2C_M_NO_RD_ACK)
continue;
+ /* assert: sda is high */
if ( count > 0 ) { /* send ack */
- sdalo(adap);
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
DEBPROTO(printk(" Am "));
} else {
- sdahi(adap); /* neg. ack on last byte */
+ /* neg. ack on last byte */
+ udelay((adap->udelay + 1) / 2);
DEBPROTO(printk(" NAm "));
}
if (sclhi(adap)<0) { /* timeout */
- sdahi(adap);
printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
return -ETIMEDOUT;
};
scllo(adap);
- sdahi(adap);
/* Some SMBus transactions require that we receive the
transaction length as the first read byte. */
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index d91dab886357..9ee0f800592f 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -38,8 +38,10 @@ struct i2c_algo_bit_data {
int (*getscl) (void *data);
/* local settings */
- int udelay; /* half-clock-cycle time in microsecs */
- /* i.e. clock is (500 / udelay) KHz */
+ int udelay; /* half clock cycle time in us,
+ minimum 2 us for fast-mode I2C,
+ minimum 5 us for standard-mode I2C and SMBus,
+ maximum 50 us for SMBus */
int timeout; /* in jiffies */
};