- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / drivers / i2c / busses / i2c-bfin-twi.c
index f1e14dd..fb26e5c 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/portmux.h>
 #include <asm/irq.h>
 
-#define POLL_TIMEOUT       (2 * HZ)
-
 /* SMBus mode*/
 #define TWI_I2C_MODE_STANDARD          1
 #define TWI_I2C_MODE_STANDARDSUB       2
@@ -44,8 +42,6 @@ struct bfin_twi_iface {
        int                     cur_mode;
        int                     manual_stop;
        int                     result;
-       int                     timeout_count;
-       struct timer_list       timeout_timer;
        struct i2c_adapter      adap;
        struct completion       complete;
        struct i2c_msg          *pmsg;
@@ -85,14 +81,15 @@ static const u16 pin_req[2][3] = {
        {P_TWI1_SCL, P_TWI1_SDA, 0},
 };
 
-static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
+                                       unsigned short twi_int_status)
 {
-       unsigned short twi_int_status = read_INT_STAT(iface);
        unsigned short mast_stat = read_MASTER_STAT(iface);
 
        if (twi_int_status & XMTSERV) {
                /* Transmit next data */
                if (iface->writeNum > 0) {
+                       SSYNC();
                        write_XMT_DATA8(iface, *(iface->transPtr++));
                        iface->writeNum--;
                }
@@ -114,10 +111,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                                write_MASTER_CTL(iface,
                                        (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
                }
-               SSYNC();
-               /* Clear status */
-               write_INT_STAT(iface, XMTSERV);
-               SSYNC();
        }
        if (twi_int_status & RCVSERV) {
                if (iface->readNum > 0) {
@@ -139,7 +132,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                } else if (iface->manual_stop) {
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) | STOP);
-                       SSYNC();
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
                           iface->cur_msg + 1 < iface->msg_num) {
                        if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
@@ -148,44 +140,37 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        else
                                write_MASTER_CTL(iface,
                                        (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
-                       SSYNC();
                }
-               /* Clear interrupt source */
-               write_INT_STAT(iface, RCVSERV);
-               SSYNC();
        }
        if (twi_int_status & MERR) {
-               write_INT_STAT(iface, MERR);
                write_INT_MASK(iface, 0);
                write_MASTER_STAT(iface, 0x3e);
                write_MASTER_CTL(iface, 0);
-               SSYNC();
                iface->result = -EIO;
-               /* if both err and complete int stats are set, return proper
-                * results.
+
+               if (mast_stat & LOSTARB)
+                       dev_dbg(&iface->adap.dev, "Lost Arbitration\n");
+               if (mast_stat & ANAK)
+                       dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n");
+               if (mast_stat & DNAK)
+                       dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n");
+               if (mast_stat & BUFRDERR)
+                       dev_dbg(&iface->adap.dev, "Buffer Read Error\n");
+               if (mast_stat & BUFWRERR)
+                       dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
+
+               /* If it is a quick transfer, only address without data,
+                * not an err, return 1.
                 */
-               if (twi_int_status & MCOMP) {
-                       write_INT_STAT(iface, MCOMP);
-                       write_INT_MASK(iface, 0);
-                       write_MASTER_CTL(iface, 0);
-                       SSYNC();
-                       /* If it is a quick transfer, only address bug no data,
-                        * not an err, return 1.
-                        */
-                       if (iface->writeNum == 0 && (mast_stat & BUFRDERR))
-                               iface->result = 1;
-                       /* If address not acknowledged return -1,
-                        * else return 0.
-                        */
-                       else if (!(mast_stat & ANAK))
-                               iface->result = 0;
-               }
+               if (iface->cur_mode == TWI_I2C_MODE_STANDARD &&
+                       iface->transPtr == NULL &&
+                       (twi_int_status & MCOMP) && (mast_stat & DNAK))
+                       iface->result = 1;
+
                complete(&iface->complete);
                return;
        }
        if (twi_int_status & MCOMP) {
-               write_INT_STAT(iface, MCOMP);
-               SSYNC();
                if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
                        if (iface->readNum == 0) {
                                /* set the read number to 1 and ask for manual
@@ -207,7 +192,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        /* remove restart bit and enable master receive */
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) & ~RSTART);
-                       SSYNC();
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
                                iface->cur_msg+1 < iface->msg_num) {
                        iface->cur_msg++;
@@ -226,7 +210,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                                        write_XMT_DATA8(iface,
                                                *(iface->transPtr++));
                                        iface->writeNum--;
-                                       SSYNC();
                                }
                        }
 
@@ -244,15 +227,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        /* remove restart bit and enable master receive */
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) & ~RSTART);
-                       SSYNC();
                } else {
                        iface->result = 1;
                        write_INT_MASK(iface, 0);
                        write_MASTER_CTL(iface, 0);
-                       SSYNC();
-                       complete(&iface->complete);
                }
        }
+       complete(&iface->complete);
 }
 
 /* Interrupt handler */
@@ -260,38 +241,26 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
 {
        struct bfin_twi_iface *iface = dev_id;
        unsigned long flags;
+       unsigned short twi_int_status;
 
        spin_lock_irqsave(&iface->lock, flags);
-       del_timer(&iface->timeout_timer);
-       bfin_twi_handle_interrupt(iface);
-       spin_unlock_irqrestore(&iface->lock, flags);
-       return IRQ_HANDLED;
-}
-
-static void bfin_twi_timeout(unsigned long data)
-{
-       struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&iface->lock, flags);
-       bfin_twi_handle_interrupt(iface);
-       if (iface->result == 0) {
-               iface->timeout_count--;
-               if (iface->timeout_count > 0) {
-                       iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-                       add_timer(&iface->timeout_timer);
-               } else {
-                       iface->result = -1;
-                       complete(&iface->complete);
-               }
+       while (1) {
+               twi_int_status = read_INT_STAT(iface);
+               if (!twi_int_status)
+                       break;
+               /* Clear interrupt status */
+               write_INT_STAT(iface, twi_int_status);
+               bfin_twi_handle_interrupt(iface, twi_int_status);
+               SSYNC();
        }
        spin_unlock_irqrestore(&iface->lock, flags);
+       return IRQ_HANDLED;
 }
 
 /*
- * Generic i2c master transfer entrypoint
+ * One i2c master transfer
  */
-static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
                                struct i2c_msg *msgs, int num)
 {
        struct bfin_twi_iface *iface = adap->algo_data;
@@ -319,7 +288,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
        iface->transPtr = pmsg->buf;
        iface->writeNum = iface->readNum = pmsg->len;
        iface->result = 0;
-       iface->timeout_count = 10;
        init_completion(&(iface->complete));
        /* Set Transmit device address */
        write_MASTER_ADDR(iface, pmsg->addr);
@@ -358,30 +326,41 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
                iface->manual_stop = 1;
        }
 
-       iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-       add_timer(&iface->timeout_timer);
-
        /* Master enable */
        write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
                ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
                ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
        SSYNC();
 
-       wait_for_completion(&iface->complete);
-
-       rc = iface->result;
+       while (!iface->result) {
+               if (!wait_for_completion_timeout(&iface->complete,
+                       adap->timeout)) {
+                       iface->result = -1;
+                       dev_err(&adap->dev, "master transfer timeout\n");
+               }
+       }
 
-       if (rc == 1)
-               return num;
+       if (iface->result == 1)
+               rc = iface->cur_msg + 1;
        else
-               return rc;
+               rc = iface->result;
+
+       return rc;
 }
 
 /*
- * SMBus type transfer entrypoint
+ * Generic i2c master transfer entrypoint
  */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+                               struct i2c_msg *msgs, int num)
+{
+       return bfin_twi_do_master_xfer(adap, msgs, num);
+}
 
-int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+/*
+ * One I2C SMBus transfer
+ */
+int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                        unsigned short flags, char read_write,
                        u8 command, int size, union i2c_smbus_data *data)
 {
@@ -469,7 +448,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        iface->manual_stop = 0;
        iface->read_write = read_write;
        iface->command = command;
-       iface->timeout_count = 10;
        init_completion(&(iface->complete));
 
        /* FIFO Initiation. Data in FIFO should be discarded before
@@ -486,9 +464,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        write_MASTER_ADDR(iface, addr);
        SSYNC();
 
-       iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-       add_timer(&iface->timeout_timer);
-
        switch (iface->cur_mode) {
        case TWI_I2C_MODE_STANDARDSUB:
                write_XMT_DATA8(iface, iface->command);
@@ -550,10 +525,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                                else if (iface->readNum > 255) {
                                        write_MASTER_CTL(iface, 0xff << 6);
                                        iface->manual_stop = 1;
-                               } else {
-                                       del_timer(&iface->timeout_timer);
+                               } else
                                        break;
-                               }
                        }
                }
                write_INT_MASK(iface, MCOMP | MERR |
@@ -569,7 +542,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        }
        SSYNC();
 
-       wait_for_completion(&iface->complete);
+       while (!iface->result) {
+               if (!wait_for_completion_timeout(&iface->complete,
+                       adap->timeout)) {
+                       iface->result = -1;
+                       dev_err(&adap->dev, "smbus transfer timeout\n");
+               }
+       }
 
        rc = (iface->result >= 0) ? 0 : -1;
 
@@ -577,6 +556,17 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 }
 
 /*
+ * Generic I2C SMBus transfer entrypoint
+ */
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+                       unsigned short flags, char read_write,
+                       u8 command, int size, union i2c_smbus_data *data)
+{
+       return bfin_twi_do_smbus_xfer(adap, addr, flags,
+                       read_write, command, size, data);
+}
+
+/*
  * Return what the adapter supports
  */
 static u32 bfin_twi_functionality(struct i2c_adapter *adap)
@@ -667,10 +657,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
                goto out_error_no_irq;
        }
 
-       init_timer(&(iface->timeout_timer));
-       iface->timeout_timer.function = bfin_twi_timeout;
-       iface->timeout_timer.data = (unsigned long)iface;
-
        p_adap = &iface->adap;
        p_adap->nr = pdev->id;
        strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
@@ -678,6 +664,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        p_adap->algo_data = iface;
        p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        p_adap->dev.parent = &pdev->dev;
+       p_adap->timeout = 5 * HZ;
+       p_adap->retries = 3;
 
        rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
        if (rc) {