Intel ESB2 SMBus chip seems to have an issue where it momentarily
resets the HOST_BUSY bit in the host status register. This confuses
the driver waiting for an SMBus transaction to complete. This patch
adds a workaround for the same.

Signed-off-by: Chaitanya Lala <[email protected]>
---
 drivers/i2c/busses/i2c-i801.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 9d2c5ad..1a04817 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -222,6 +222,7 @@ static int i801_transaction(int xact)
        int status;
        int result;
        int timeout = 0;
+       int counter = 0;
 
        result = i801_check_pre();
        if (result < 0)
@@ -231,12 +232,34 @@ static int i801_transaction(int xact)
         * INTREN, SMBSCMD are passed in xact */
        outb_p(xact | I801_START, SMBHSTCNT);
 
+try_again:
        /* We will always wait for a fraction of a second! */
        do {
                msleep(1);
                status = inb_p(SMBHSTSTS);
        } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
 
+       /* The i801 chip resets the HOST_BUSY bit
+       *  to indicate that it has completed the transaction,
+       *  but a moment later sets it again. Seems like a glitch.
+       *  Changed code to check the value more times if its not a timeout.
+       */
+       if (timeout < MAX_TIMEOUT) {
+               msleep(1);
+               status = inb_p(SMBHSTSTS);
+               if (status  & SMBHSTSTS_HOST_BUSY) {
+                       dev_warn(&I801_dev->dev, "Busy bit set again"
+                               "(%02x)\n", status);
+                       if (++counter < 3) {
+                               dev_info(&I801_dev->dev, "Trying"
+                                       "again\n");
+                               goto try_again;
+                       }
+                       dev_err(&I801_dev->dev, "No use"
+                               " retrying-(%02x)\n", status);
+               }
+       }
+
        result = i801_check_post(status, timeout > MAX_TIMEOUT);
        if (result < 0)
                return result;
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to