]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/i2c/busses/i2c-omap.c
OMAP: I2C: convert 'rev1' flag to generic 'rev' u8
[linux-2.6-omap-h63xx.git] / drivers / i2c / busses / i2c-omap.c
index 0f7cbe8f5cefc7e11d239efd55d4f913cad9efa5..3ac510d9c9ba81741f81fd4ec1a01116d4bd1b11 100644 (file)
@@ -9,8 +9,9 @@
  * Additional contributions by:
  *     Tony Lindgren <tony@atomide.com>
  *     Imre Deak <imre.deak@nokia.com>
- *     Juha Yrjölä <juha.yrjola@nokia.com>
+ *     Juha Yrjölä <juha.yrjola@solidboot.com>
  *     Syed Khasim <x0khasim@ti.com>
+ *     Nishant Menon <nm@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/completion.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
+/* I2C controller revisions */
+#define OMAP_I2C_REV_2                 0x20
 
-/* Hack to enable zero length transfers and smbus quick until clean fix
-   is available */
-#define OMAP_HACK
+/* I2C controller revisions present on specific hardware */
+#define OMAP_I2C_REV_ON_2430           0x36
+#define OMAP_I2C_REV_ON_3430           0x3C
 
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -64,8 +67,8 @@
 #define OMAP_I2C_BUFSTAT_REG           0x40
 
 /* I2C Interrupt Enable Register (OMAP_I2C_IE): */
-#define OMAP_I2C_IE_XDR                (1 << 14)       /* TX Buffer draining int enable */
-#define OMAP_I2C_IE_RDR                (1 << 13)       /* RX Buffer draining int enable */
+#define OMAP_I2C_IE_XDR                (1 << 14)       /* TX Buffer drain int enable */
+#define OMAP_I2C_IE_RDR                (1 << 13)       /* RX Buffer drain int enable */
 #define OMAP_I2C_IE_XRDY       (1 << 4)        /* TX data ready int enable */
 #define OMAP_I2C_IE_RRDY       (1 << 3)        /* RX data ready int enable */
 #define OMAP_I2C_IE_ARDY       (1 << 2)        /* Access ready int enable */
@@ -143,7 +146,7 @@ struct omap_i2c_dev {
                                                 * fifo_size==0 implies no fifo
                                                 * if set, should be trsh+1
                                                 */
-       unsigned                rev1:1;
+       u8                      rev;
        unsigned                b_hw:1;         /* bad h/w fixes */
        unsigned                idle:1;
        u16                     iestate;        /* Saved interrupt register */
@@ -169,28 +172,17 @@ static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
                        return -ENODEV;
                }
        }
-       /* For I2C operations on 2430 we need 96Mhz clock */
-       if (cpu_is_omap2430()) {
-               dev->fclk = clk_get(dev->dev, "i2chs_fck");
-               if (IS_ERR(dev->fclk)) {
-                       if (dev->iclk != NULL) {
-                               clk_put(dev->iclk);
-                               dev->iclk = NULL;
-                       }
-                       dev->fclk = NULL;
-                       return -ENODEV;
-               }
-       } else {
-               dev->fclk = clk_get(dev->dev, "i2c_fck");
-               if (IS_ERR(dev->fclk)) {
-                       if (dev->iclk != NULL) {
-                               clk_put(dev->iclk);
-                               dev->iclk = NULL;
-                       }
-                       dev->fclk = NULL;
-                       return -ENODEV;
+
+       dev->fclk = clk_get(dev->dev, "i2c_fck");
+       if (IS_ERR(dev->fclk)) {
+               if (dev->iclk != NULL) {
+                       clk_put(dev->iclk);
+                       dev->iclk = NULL;
                }
+               dev->fclk = NULL;
+               return -ENODEV;
        }
+
        return 0;
 }
 
@@ -206,6 +198,8 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
 
 static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 {
+       WARN_ON(!dev->idle);
+
        if (dev->iclk != NULL)
                clk_enable(dev->iclk);
        clk_enable(dev->fclk);
@@ -218,18 +212,18 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
 {
        u16 iv;
 
+       WARN_ON(dev->idle);
+
        dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
        omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
-       if (dev->rev1)
-               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
-       else
+       if (dev->rev < OMAP_I2C_REV_2) {
+               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
+       } else {
                omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
-       /*
-        * The wmb() is to ensure that the I2C interrupt mask write
-        * reaches the I2C controller before the dev->idle store
-        * occurs.
-        */
-       wmb();
+
+               /* Flush posted write before the dev->idle store occurs */
+               omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+       }
        dev->idle = 1;
        clk_disable(dev->fclk);
        if (dev->iclk != NULL)
@@ -244,7 +238,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        unsigned long timeout;
        unsigned long internal_clk = 0;
 
-       if (!dev->rev1) {
+       if (dev->rev >= OMAP_I2C_REV_2) {
                omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
                /* For some reason we need to set the EN bit before the
                 * reset done bit gets set. */
@@ -373,16 +367,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
                             struct i2c_msg *msg, int stop)
 {
        struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
-#ifdef OMAP_HACK
-       u8 zero_byte = 0;
-#endif
        int r;
        u16 w;
 
        dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
                msg->addr, msg->len, msg->flags, stop);
 
-#ifndef OMAP_HACK
        if (msg->len == 0)
                return -EINVAL;
 
@@ -392,27 +382,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        dev->buf = msg->buf;
        dev->buf_len = msg->len;
 
-#else
-
-       omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
-       /* REVISIT: Remove this hack when we can get I2C chips from board-*.c
-        *          files
-        * Sigh, seems we can't do zero length transactions. Thus, we
-        * can't probe for devices w/o actually sending/receiving at least
-        * a single byte. So we'll set count to 1 for the zero length
-        * transaction case and hope we don't cause grief for some
-        * arbitrary device due to random byte write/read during
-        * probes.
-        */
-       if (msg->len == 0) {
-               dev->buf = &zero_byte;
-               dev->buf_len = 1;
-       } else {
-               dev->buf = msg->buf;
-               dev->buf_len = msg->len;
-       }
-#endif
-
        omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
 
        /* Clear the FIFO Buffers */
@@ -439,22 +408,33 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
 
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
 
+       /*
+        * Don't write stt and stp together on some hardware.
+        */
        if (dev->b_hw && stop) {
                unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
+               u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+               while (con & OMAP_I2C_CON_STT) {
+                       con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
 
-               /* H/w behavior: dont write stt and stp together.. */
-               while (omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & OMAP_I2C_CON_STT) {
                        /* Let the user know if i2c is in a bad state */
-                       if (time_after (jiffies, delay)) {
+                       if (time_after(jiffies, delay)) {
                                dev_err(dev->dev, "controller timed out "
                                "waiting for start condition to finish\n");
                                return -ETIMEDOUT;
                        }
+                       cpu_relax();
                }
+
                w |= OMAP_I2C_CON_STP;
                w &= ~OMAP_I2C_CON_STT;
                omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
        }
+
+       /*
+        * REVISIT: We should abort the transfer on signals, but the bus goes
+        * into arbitration and we're currently unable to recover from it.
+        */
        r = wait_for_completion_timeout(&dev->cmd_complete,
                                        OMAP_I2C_TIMEOUT);
        dev->buf_len = 0;
@@ -503,7 +483,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
        omap_i2c_unidle(dev);
 
-       if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+       r = omap_i2c_wait_for_bb(dev);
+       if (r < 0)
                goto out;
 
        for (i = 0; i < num; i++) {
@@ -522,11 +503,7 @@ out:
 static u32
 omap_i2c_func(struct i2c_adapter *adap)
 {
-#ifndef OMAP_HACK
        return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
-#else
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-#endif
 }
 
 static inline void
@@ -600,7 +577,7 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
        return IRQ_HANDLED;
 }
 #else
-#define omap_i2c_rev1_isr              0
+#define omap_i2c_rev1_isr              NULL
 #endif
 
 static irqreturn_t
@@ -640,8 +617,11 @@ omap_i2c_isr(int this_irq, void *dev_id)
                if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
                        u8 num_bytes = 1;
                        if (dev->fifo_size) {
-                               num_bytes = (stat & OMAP_I2C_STAT_RRDY) ? dev->fifo_size :
-                                               omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG);
+                               if (stat & OMAP_I2C_STAT_RRDY)
+                                       num_bytes = dev->fifo_size;
+                               else
+                                       num_bytes = omap_i2c_read_reg(dev,
+                                                       OMAP_I2C_BUFSTAT_REG);
                        }
                        while (num_bytes) {
                                num_bytes--;
@@ -659,22 +639,28 @@ omap_i2c_isr(int this_irq, void *dev_id)
                                        }
                                } else {
                                        if (stat & OMAP_I2C_STAT_RRDY)
-                                               dev_err(dev->dev, "RRDY IRQ while no data "
-                                                               "requested\n");
+                                               dev_err(dev->dev,
+                                                       "RRDY IRQ while no data"
+                                                               " requested\n");
                                        if (stat & OMAP_I2C_STAT_RDR)
-                                               dev_err(dev->dev, "RDR IRQ while no data "
-                                                               "requested\n");
+                                               dev_err(dev->dev,
+                                                       "RDR IRQ while no data"
+                                                               " requested\n");
                                        break;
                                }
                        }
-                       omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+                       omap_i2c_ack_stat(dev,
+                               stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
                        continue;
                }
                if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
                        u8 num_bytes = 1;
                        if (dev->fifo_size) {
-                               num_bytes = (stat & OMAP_I2C_STAT_XRDY) ? dev->fifo_size :
-                                               omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG);
+                               if (stat & OMAP_I2C_STAT_XRDY)
+                                       num_bytes = dev->fifo_size;
+                               else
+                                       num_bytes = omap_i2c_read_reg(dev,
+                                                       OMAP_I2C_BUFSTAT_REG);
                        }
                        while (num_bytes) {
                                num_bytes--;
@@ -692,16 +678,19 @@ omap_i2c_isr(int this_irq, void *dev_id)
                                        }
                                } else {
                                        if (stat & OMAP_I2C_STAT_XRDY)
-                                               dev_err(dev->dev, "XRDY IRQ while no "
-                                                               "data to send\n");
+                                               dev_err(dev->dev,
+                                                       "XRDY IRQ while no "
+                                                       "data to send\n");
                                        if (stat & OMAP_I2C_STAT_XDR)
-                                               dev_err(dev->dev, "XDR IRQ while no "
-                                                               "data to send\n");
+                                               dev_err(dev->dev,
+                                                       "XDR IRQ while no "
+                                                       "data to send\n");
                                        break;
                                }
                                omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
                        }
-                       omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                       omap_i2c_ack_stat(dev,
+                               stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
                        continue;
                }
                if (stat & OMAP_I2C_STAT_ROVR) {
@@ -728,8 +717,9 @@ omap_i2c_probe(struct platform_device *pdev)
        struct omap_i2c_dev     *dev;
        struct i2c_adapter      *adap;
        struct resource         *mem, *irq, *ioarea;
+       void *isr;
        int r;
-       u32 *speed = NULL;
+       u32 speed = 0;
 
        /* NOTE: driver uses the static register mapping */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -757,11 +747,12 @@ omap_i2c_probe(struct platform_device *pdev)
        }
 
        if (pdev->dev.platform_data != NULL)
-               speed = (u32 *) pdev->dev.platform_data;
+               speed = *(u32 *)pdev->dev.platform_data;
        else
-               *speed = 100; /* Defualt speed */
+               speed = 100;    /* Defualt speed */
 
-       dev->speed = *speed;
+       dev->speed = speed;
+       dev->idle = 1;
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
        dev->base = ioremap(mem->start, mem->end - mem->start + 1);
@@ -777,17 +768,19 @@ omap_i2c_probe(struct platform_device *pdev)
 
        omap_i2c_unidle(dev);
 
-       if (cpu_is_omap15xx())
-               dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+       dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
        if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+               u16 s;
+
                /* Set up the fifo size - Get total size */
-               dev->fifo_size = 0x8 <<
-                       ((omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3);
+               s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
+               dev->fifo_size = 0x8 << s;
+
                /*
-                * Set up notification threshold as half the total available size
-                * This is to ensure that we can handle the status on int call back
-                * latencies
+                * Set up notification threshold as half the total available
+                * size. This is to ensure that we can handle the status on int
+                * call back latencies.
                 */
                dev->fifo_size = (dev->fifo_size / 2);
                dev->b_hw = 1; /* Enable hardware fixes */
@@ -796,16 +789,18 @@ omap_i2c_probe(struct platform_device *pdev)
        /* reset ASAP, clearing any IRQs */
        omap_i2c_init(dev);
 
-       r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
-                       0, pdev->name, dev);
+       isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr;
+       r = request_irq(dev->irq, isr, 0, pdev->name, dev);
 
        if (r) {
                dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
                goto err_unuse_clocks;
        }
-       r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+
        dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
-                pdev->id, r >> 4, r & 0xf, dev->speed);
+                pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
+       omap_i2c_idle(dev);
 
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
@@ -823,8 +818,6 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_free_irq;
        }
 
-       omap_i2c_idle(dev);
-
        return 0;
 
 err_free_irq:
@@ -873,14 +866,14 @@ static struct platform_driver omap_i2c_driver = {
 };
 
 /* I2C may be needed to bring up other drivers */
-static int __devinit
+static int __init
 omap_i2c_init_driver(void)
 {
        return platform_driver_register(&omap_i2c_driver);
 }
 subsys_initcall(omap_i2c_init_driver);
 
-static void __devexit omap_i2c_exit_driver(void)
+static void __exit omap_i2c_exit_driver(void)
 {
        platform_driver_unregister(&omap_i2c_driver);
 }