]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/i2c/busses/i2c-omap.c
i2c-omap: Use I2C interface clock also on OMAP16xx CPUs
[linux-2.6-omap-h63xx.git] / drivers / i2c / busses / i2c-omap.c
index fb412559b8a1bf7c03e497d58b4daaa80ace19cd..6c58b1bfe1b1480bdab80d1e626bd6ffd67af66c 100644 (file)
@@ -53,7 +53,7 @@
 static const char driver_name[] = "i2c_omap";
 
 #define MODULE_NAME "OMAP I2C"
-#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(500)) /* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) /* timeout waiting for the controller to respond */
 
 #define DEFAULT_OWN            1       /* default own I2C address */
 #define MAX_MESSAGES           65536   /* max number of messages */
@@ -161,22 +161,18 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
        return __raw_readw(i2c_dev->base + reg);
 }
 
-#ifdef CONFIG_ARCH_OMAP24XX
-static int omap_i2c_get_clocks(struct omap_i2c_dev *dev, int bus)
+static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
 {
-       if (!cpu_is_omap24xx())
-               return 0;
-
-       dev->iclk = clk_get(NULL,
-               bus == 1 ? "i2c1_ick" : "i2c2_ick");
-       if (IS_ERR(dev->iclk)) {
-               return -ENODEV;
+       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+               dev->iclk = clk_get(dev->dev, "i2c_ick");
+               if (IS_ERR(dev->iclk))
+                       return -ENODEV;
        }
 
-       dev->fclk = clk_get(NULL,
-               bus == 1 ? "i2c1_fck" : "i2c2_fck");
+       dev->fclk = clk_get(dev->dev, "i2c_fck");
        if (IS_ERR(dev->fclk)) {
-               clk_put(dev->fclk);
+               if (dev->iclk != NULL)
+                       clk_put(dev->iclk);
                return -ENODEV;
        }
 
@@ -186,28 +182,27 @@ static int omap_i2c_get_clocks(struct omap_i2c_dev *dev, int bus)
 static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
 {
        clk_put(dev->fclk);
-       clk_put(dev->iclk);
+       dev->fclk = NULL;
+       if (dev->iclk != NULL) {
+               clk_put(dev->iclk);
+               dev->iclk = NULL;
+       }
 }
 
 static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
 {
-       clk_enable(dev->iclk);
+       if (dev->iclk != NULL)
+               clk_enable(dev->iclk);
        clk_enable(dev->fclk);
 }
 
 static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
 {
-       clk_disable(dev->iclk);
+       if (dev->iclk != NULL)
+               clk_disable(dev->iclk);
        clk_disable(dev->fclk);
 }
 
-#else
-#define omap_i2c_get_clocks(x, y)              0
-#define omap_i2c_enable_clocks(x)      do {} while (0)
-#define omap_i2c_disable_clocks(x)     do {} while (0)
-#define omap_i2c_put_clocks(x)         do {} while (0)
-#endif
-
 static void omap_i2c_reset(struct omap_i2c_dev *dev)
 {
        u16 psc;
@@ -403,7 +398,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
                        break;
        }
 
-       if (r == 0 && num > 1)
+       if (r == 0)
                r = num;
 out:
        omap_i2c_disable_clocks(dev);
@@ -429,6 +424,60 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
        omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
 }
 
+#ifdef CONFIG_ARCH_OMAP15XX
+static irqreturn_t
+omap_i2c_rev1_isr(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+       struct omap_i2c_dev *dev = dev_id;
+       u16 iv, w;
+
+       iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+       switch (iv) {
+       case 0x00:      /* None */
+               break;
+       case 0x01:      /* Arbitration lost */
+               dev_err(dev->dev, "Arbitration lost\n");
+               omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+               break;
+       case 0x02:      /* No acknowledgement */
+               omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+               break;
+       case 0x03:      /* Register access ready */
+               omap_i2c_complete_cmd(dev, 0);
+               break;
+       case 0x04:      /* Receive data ready */
+               if (dev->buf_len) {
+                       w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+                       *dev->buf++ = w;
+                       dev->buf_len--;
+                       if (dev->buf_len) {
+                               *dev->buf++ = w >> 8;
+                               dev->buf_len--;
+                       }
+               } else
+                       dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+               break;
+       case 0x05:      /* Transmit data ready */
+               if (dev->buf_len) {
+                       w = *dev->buf++;
+                       dev->buf_len--;
+                       if (dev->buf_len) {
+                               w |= *dev->buf++ << 8;
+                               dev->buf_len--;
+                       }
+                       omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+               } else
+                       dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+               break;
+       default:
+               return IRQ_NONE;
+       }
+
+       return IRQ_HANDLED;
+}
+#endif
+
 static irqreturn_t
 omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
 {
@@ -436,7 +485,6 @@ omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
        u16 bits;
        u16 stat, w;
        int count = 0;
-       u16 iv_read;
 
        bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
        while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
@@ -450,8 +498,6 @@ omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
 
                if (stat & OMAP_I2C_STAT_ARDY) {
                        omap_i2c_complete_cmd(dev, 0);
-                       if (dev->rev1)
-                               iv_read = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
                        continue;
                }
                if (stat & OMAP_I2C_STAT_RRDY) {
@@ -463,13 +509,9 @@ omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
                                        *dev->buf++ = w >> 8;
                                        dev->buf_len--;
                                }
-                               if (dev->rev1 && !dev->buf_len)
-                                       omap_i2c_complete_cmd(dev, 0);
                        } else
                                dev_err(dev->dev, "RRDY IRQ while no data requested\n");
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
-                       if (dev->rev1)
-                               iv_read = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
                        continue;
                }
                if (stat & OMAP_I2C_STAT_XRDY) {
@@ -493,11 +535,6 @@ omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
 #endif
                        omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
-                       if (dev->rev1) {
-                               iv_read = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
-                               if (!dev->buf_len)
-                                       omap_i2c_complete_cmd(dev, 0);
-                       }
                        if (bail_out)
                                omap_i2c_complete_cmd(dev, 1 << 15);
                        continue;
@@ -518,8 +555,6 @@ omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
                        dev_err(dev->dev, "Arbitration lost\n");
                        omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
                }
-               if (dev->rev1)
-                       iv_read = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
        }
 
        return count ? IRQ_HANDLED : IRQ_NONE;
@@ -579,7 +614,7 @@ omap_i2c_probe(struct platform_device *pdev)
        dev->base = (void __iomem *) IO_ADDRESS(mem->start);
        platform_set_drvdata(pdev, dev);
 
-       if ((r = omap_i2c_get_clocks(dev, pdev->id)) != 0)
+       if ((r = omap_i2c_get_clocks(dev)) != 0)
                goto do_free_mem;
 
        omap_i2c_enable_clocks(dev);
@@ -591,8 +626,12 @@ omap_i2c_probe(struct platform_device *pdev)
        /* reset ASAP, clearing any IRQs */
        omap_i2c_reset(dev);
 
-       r = request_irq(dev->irq, omap_i2c_isr, 0,
-                       driver_name, dev);
+#ifdef CONFIG_ARCH_OMAP15XX
+       r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
+                       0, driver_name, dev);
+#else
+       r = request_irq(dev->irq, omap_i2c_isr, 0, driver_name, dev);
+#endif
        if (r) {
                dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
                goto do_unuse_clocks;
@@ -623,7 +662,7 @@ omap_i2c_probe(struct platform_device *pdev)
 do_free_irq:
        free_irq(dev->irq, dev);
 do_unuse_clocks:
-       omap_i2c_enable_clocks(dev);
+       omap_i2c_disable_clocks(dev);
        omap_i2c_put_clocks(dev);
 do_free_mem:
        kfree(dev);