aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Brower <ebrower@gmail.com>2005-03-30 22:30:24 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2005-03-30 22:30:24 -0800
commit2f4ce18a3d9ce87b82c26ced004e7136d2ffce63 (patch)
tree3648e4a575c23a4402ca81bcb51405bf5cd98718
parentc10d3e4b15da22c193d40c7ade107509af11e7d0 (diff)
downloadhistory-2f4ce18a3d9ce87b82c26ced004e7136d2ffce63.tar.gz
[PATCH] I2C: lost arbitration detection for PCF8584
[PATCH] lost arbitration detection for PCF8584 algo driver Patch against a slightly-dated linux-2.6 BK tree This patch provides lost arbitration detection for the PCF8584 I2C algorithm driver. The PCF8584 LAB bit is set whenever lost arbitration is detected, so we check the bit in the wait_for_pin function and if LAB is detected we return -EINTR. The -EINTR value bubbles-up all the way to the master_xfer API call so callers may detect this condition explicitly. LAB could be checked more often, at the expense of code readability/maintainability. Signed-off-by: Eric Brower <ebrower@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 66e681cb33d1ea..8d087dac32afc7 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -78,7 +78,6 @@ static void i2c_stop(struct i2c_algo_pcf_data *adap)
set_pcf(adap, 1, I2C_PCF_STOP);
}
-
static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
int timeout = DEF_TIMEOUT;
@@ -109,6 +108,26 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
adap->waitforpin();
*status = get_pcf(adap, 1);
}
+ if (*status & I2C_PCF_LAB) {
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+ *status));
+ /* Cleanup from LAB-- reset and enable ESO.
+ * This resets the PCF8584; since we've lost the bus, no
+ * further attempts should be made by callers to clean up
+ * (no i2c_stop() etc.)
+ */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ /* TODO: we should pause for a time period sufficient for any
+ * running I2C transaction to complete-- the arbitration
+ * logic won't work properly until the next START is seen.
+ */
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
+ get_pcf(adap,1)));
+ return(-EINTR);
+ }
#endif
if (timeout <= 0)
return(-1);
@@ -188,16 +207,22 @@ static inline int try_address(struct i2c_algo_pcf_data *adap,
unsigned char addr, int retries)
{
int i, status, ret = -1;
+ int wfp;
for (i=0;i<retries;i++) {
i2c_outb(adap, addr);
i2c_start(adap);
status = get_pcf(adap, 1);
- if (wait_for_pin(adap, &status) >= 0) {
+ if ((wfp = wait_for_pin(adap, &status)) >= 0) {
if ((status & I2C_PCF_LRB) == 0) {
i2c_stop(adap);
break; /* success! */
}
}
+ if (wfp == -EINTR) {
+ /* arbitration lost */
+ udelay(adap->udelay);
+ return -EINTR;
+ }
i2c_stop(adap);
udelay(adap->udelay);
}
@@ -219,6 +244,10 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
i2c_outb(adap, buf[wrcount]);
timeout = wait_for_pin(adap, &status);
if (timeout) {
+ if (timeout == -EINTR) {
+ /* arbitration lost */
+ return -EINTR;
+ }
i2c_stop(adap);
dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
return -EREMOTEIO; /* got a better one ?? */
@@ -247,11 +276,16 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
{
int i, status;
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wfp;
/* increment number of bytes to read by one -- read dummy byte */
for (i = 0; i <= count; i++) {
- if (wait_for_pin(adap, &status)) {
+ if ((wfp = wait_for_pin(adap, &status))) {
+ if (wfp == -EINTR) {
+ /* arbitration lost */
+ return -EINTR;
+ }
i2c_stop(adap);
dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
return (-1);
@@ -366,6 +400,10 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
/* Wait for PIN (pending interrupt NOT) */
timeout = wait_for_pin(adap, &status);
if (timeout) {
+ if (timeout == -EINTR) {
+ /* arbitration lost */
+ return (-EINTR);
+ }
i2c_stop(adap);
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
"for PIN(1) in pcf_xfer\n");)