Commit 424ed67c authored by Jean Delvare's avatar Jean Delvare Committed by Jean Delvare

i2c-algo-bit: Implement a 50/50 SCL duty cycle

The original i2c-algo-bit implementation uses a 33/66 SCL duty cycle
when bits are being written on the bus. While the I2C specification
doesn't forbid it, this prevents us from driving the I2C bus to its
max speed, limiting us to 66 kbps max on standard I2C busses.

Implementing a 50/50 duty cycle instead lets us max out the bandwidth
up to the theoretical max of 100 kbps on standard I2C busses. This is
particularly important when large amounts of data need to be transfered
over the bus, as is the case with some TV adapters when the firmware is
being uploaded.

In fact this change even allows, at least in theory, fast-mode I2C
support at 125, 166 and 250 kbps. There's no way to reach the
theoretical max of 400 kbps with this implementation. But I don't
think we want to put efforts in that direction anyway: software-driven
I2C is very CPU-intensive and bad for latency.

Other timing changes:
* Don't set SDA high explicitly on error, we're going to issue a stop
  condition before we leave anyway.
* If an error occurs when sending the slave address, yield the CPU
  before retrying, and remove the additional delay after the new start
  condition.
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 7c175499
...@@ -57,19 +57,19 @@ static int bit_test; /* see if the line-setting functions work */ ...@@ -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) static inline void sdalo(struct i2c_algo_bit_data *adap)
{ {
setsda(adap,0); setsda(adap,0);
udelay(adap->udelay); udelay((adap->udelay + 1) / 2);
} }
static inline void sdahi(struct i2c_algo_bit_data *adap) static inline void sdahi(struct i2c_algo_bit_data *adap)
{ {
setsda(adap,1); setsda(adap,1);
udelay(adap->udelay); udelay((adap->udelay + 1) / 2);
} }
static inline void scllo(struct i2c_algo_bit_data *adap) static inline void scllo(struct i2c_algo_bit_data *adap)
{ {
setscl(adap,0); setscl(adap,0);
udelay(adap->udelay); udelay(adap->udelay / 2);
} }
/* /*
...@@ -111,18 +111,19 @@ static void i2c_start(struct i2c_algo_bit_data *adap) ...@@ -111,18 +111,19 @@ static void i2c_start(struct i2c_algo_bit_data *adap)
{ {
/* assert: scl, sda are high */ /* assert: scl, sda are high */
DEBPROTO(printk("S ")); DEBPROTO(printk("S "));
sdalo(adap); setsda(adap, 0);
udelay(adap->udelay);
scllo(adap); scllo(adap);
} }
static void i2c_repstart(struct i2c_algo_bit_data *adap) static void i2c_repstart(struct i2c_algo_bit_data *adap)
{ {
/* scl, sda may not be high */ /* assert: scl is low */
DEBPROTO(printk(" Sr ")); DEBPROTO(printk(" Sr "));
setsda(adap,1); sdahi(adap);
sclhi(adap); sclhi(adap);
setsda(adap, 0);
sdalo(adap); udelay(adap->udelay);
scllo(adap); scllo(adap);
} }
...@@ -133,7 +134,8 @@ static void i2c_stop(struct i2c_algo_bit_data *adap) ...@@ -133,7 +134,8 @@ static void i2c_stop(struct i2c_algo_bit_data *adap)
/* assert: scl is low */ /* assert: scl is low */
sdalo(adap); sdalo(adap);
sclhi(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) ...@@ -156,18 +158,16 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
for ( i=7 ; i>=0 ; i-- ) { for ( i=7 ; i>=0 ; i-- ) {
sb = c & ( 1 << i ); sb = c & ( 1 << i );
setsda(adap,sb); setsda(adap,sb);
udelay(adap->udelay); udelay((adap->udelay + 1) / 2);
DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
if (sclhi(adap)<0) { /* timed out */ 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)); DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
return -ETIMEDOUT; return -ETIMEDOUT;
}; };
/* do arbitration here: /* do arbitration here:
* if ( sb && ! getsda(adap) ) -> ouch! Get out of here. * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
*/ */
setscl(adap, 0 ); scllo(adap);
udelay(adap->udelay);
} }
sdahi(adap); sdahi(adap);
if (sclhi(adap)<0){ /* timeout */ if (sclhi(adap)<0){ /* timeout */
...@@ -204,7 +204,8 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) ...@@ -204,7 +204,8 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
indata *= 2; indata *= 2;
if ( getsda(adap) ) if ( getsda(adap) )
indata |= 0x01; indata |= 0x01;
scllo(adap); setscl(adap, 0);
udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
} }
/* assert: scl is low */ /* assert: scl is low */
DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
...@@ -315,9 +316,9 @@ static int try_address(struct i2c_adapter *i2c_adap, ...@@ -315,9 +316,9 @@ static int try_address(struct i2c_adapter *i2c_adap,
if (ret == 1 || i == retries) if (ret == 1 || i == retries)
break; break;
i2c_stop(adap); i2c_stop(adap);
udelay(5/*adap->udelay*/);
i2c_start(adap);
udelay(adap->udelay); udelay(adap->udelay);
yield();
i2c_start(adap);
} }
DEB2(if (i) DEB2(if (i)
printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", 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) ...@@ -377,20 +378,21 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if (msg->flags & I2C_M_NO_RD_ACK) if (msg->flags & I2C_M_NO_RD_ACK)
continue; continue;
/* assert: sda is high */
if ( count > 0 ) { /* send ack */ if ( count > 0 ) { /* send ack */
sdalo(adap); setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
DEBPROTO(printk(" Am ")); DEBPROTO(printk(" Am "));
} else { } else {
sdahi(adap); /* neg. ack on last byte */ /* neg. ack on last byte */
udelay((adap->udelay + 1) / 2);
DEBPROTO(printk(" NAm ")); DEBPROTO(printk(" NAm "));
} }
if (sclhi(adap)<0) { /* timeout */ if (sclhi(adap)<0) { /* timeout */
sdahi(adap);
printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
return -ETIMEDOUT; return -ETIMEDOUT;
}; };
scllo(adap); scllo(adap);
sdahi(adap);
/* Some SMBus transactions require that we receive the /* Some SMBus transactions require that we receive the
transaction length as the first read byte. */ transaction length as the first read byte. */
......
...@@ -38,8 +38,10 @@ struct i2c_algo_bit_data { ...@@ -38,8 +38,10 @@ struct i2c_algo_bit_data {
int (*getscl) (void *data); int (*getscl) (void *data);
/* local settings */ /* local settings */
int udelay; /* half-clock-cycle time in microsecs */ int udelay; /* half clock cycle time in us,
/* i.e. clock is (500 / udelay) KHz */ 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 */ int timeout; /* in jiffies */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment