Merge branch 'i2c-fixes-rc4' of git://aeryn.fluff.org.uk/bjdooks/linux
Linus Torvalds [Thu, 30 Jul 2009 02:39:22 +0000 (19:39 -0700)]
* 'i2c-fixes-rc4' of git://aeryn.fluff.org.uk/bjdooks/linux:
  i2c-omap: OMAP3430 Silicon Errata 1.153
  i2c-omap: In case of a NACK|ARDY|AL return from the ISR
  i2c-omap: Bug in reading the RXSTAT/TXSTAT values from the I2C_BUFFSTAT register
  i2c-sh_mobile: change module_init() to subsys_initcall()
  i2c: strncpy does not null terminate string
  i2c-s3c2410: s3c24xx_i2c_init: don't clobber IICLC value

drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sh_mobile.c

index fdd8327..d258b02 100644 (file)
@@ -672,9 +672,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
                        break;
                }
 
+               err = 0;
+complete:
                omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
 
-               err = 0;
                if (stat & OMAP_I2C_STAT_NACK) {
                        err |= OMAP_I2C_STAT_NACK;
                        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
@@ -685,16 +686,19 @@ omap_i2c_isr(int this_irq, void *dev_id)
                        err |= OMAP_I2C_STAT_AL;
                }
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
-                                       OMAP_I2C_STAT_AL))
+                                       OMAP_I2C_STAT_AL)) {
                        omap_i2c_complete_cmd(dev, err);
+                       return IRQ_HANDLED;
+               }
                if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
                        u8 num_bytes = 1;
                        if (dev->fifo_size) {
                                if (stat & OMAP_I2C_STAT_RRDY)
                                        num_bytes = dev->fifo_size;
-                               else
-                                       num_bytes = omap_i2c_read_reg(dev,
-                                                       OMAP_I2C_BUFSTAT_REG);
+                               else    /* read RXSTAT on RDR interrupt */
+                                       num_bytes = (omap_i2c_read_reg(dev,
+                                                       OMAP_I2C_BUFSTAT_REG)
+                                                       >> 8) & 0x3F;
                        }
                        while (num_bytes) {
                                num_bytes--;
@@ -731,9 +735,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
                        if (dev->fifo_size) {
                                if (stat & OMAP_I2C_STAT_XRDY)
                                        num_bytes = dev->fifo_size;
-                               else
+                               else    /* read TXSTAT on XDR interrupt */
                                        num_bytes = omap_i2c_read_reg(dev,
-                                                       OMAP_I2C_BUFSTAT_REG);
+                                                       OMAP_I2C_BUFSTAT_REG)
+                                                       & 0x3F;
                        }
                        while (num_bytes) {
                                num_bytes--;
@@ -760,6 +765,27 @@ omap_i2c_isr(int this_irq, void *dev_id)
                                                        "data to send\n");
                                        break;
                                }
+
+                               /*
+                                * OMAP3430 Errata 1.153: When an XRDY/XDR
+                                * is hit, wait for XUDF before writing data
+                                * to DATA_REG. Otherwise some data bytes can
+                                * be lost while transferring them from the
+                                * memory to the I2C interface.
+                                */
+
+                               if (cpu_is_omap34xx()) {
+                                               while (!(stat & OMAP_I2C_STAT_XUDF)) {
+                                                       if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+                                                               omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                                                               err |= OMAP_I2C_STAT_XUDF;
+                                                               goto complete;
+                                                       }
+                                                       cpu_relax();
+                                                       stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+                                               }
+                               }
+
                                omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
                        }
                        omap_i2c_ack_stat(dev,
@@ -879,7 +905,7 @@ omap_i2c_probe(struct platform_device *pdev)
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
        adap->class = I2C_CLASS_HWMON;
-       strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+       strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
        adap->algo = &omap_i2c_algo;
        adap->dev.parent = &pdev->dev;
 
index 8f42a45..20bb0ce 100644 (file)
@@ -763,11 +763,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
        dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
        dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
 
-       /* check for s3c2440 i2c controller  */
-
-       if (s3c24xx_i2c_is2440(i2c))
-               writel(0x0, i2c->regs + S3C2440_IICLC);
-
        return 0;
 }
 
index 4f3d99c..820487d 100644 (file)
@@ -637,7 +637,7 @@ static void __exit sh_mobile_i2c_adap_exit(void)
        platform_driver_unregister(&sh_mobile_i2c_driver);
 }
 
-module_init(sh_mobile_i2c_adap_init);
+subsys_initcall(sh_mobile_i2c_adap_init);
 module_exit(sh_mobile_i2c_adap_exit);
 
 MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");