Merge branch 'next-i2c' of git://aeryn.fluff.org.uk/bjdooks/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Jun 2009 20:15:59 +0000 (13:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Jun 2009 20:15:59 +0000 (13:15 -0700)
* 'next-i2c' of git://aeryn.fluff.org.uk/bjdooks/linux:
  i2c-ocores: Can add I2C devices to the bus
  i2c-s3c2410: move to using platform idtable to match devices
  i2c: OMAP3: Better noise suppression for fast/standard modes
  i2c: OMAP2/3: Fix scll/sclh calculations
  i2c: Blackfin TWI: implement I2C_FUNC_SMBUS_I2C_BLOCK functionality
  i2c: Blackfin TWI: fix transfer errors with repeat start
  i2c: Blackfin TWI: fix REPEAT START mode doesn't repeat
  i2c: Blackfin TWI: make sure we don't end up with a CLKDIV=0

Documentation/i2c/busses/i2c-ocores
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-s3c2410.c
include/linux/i2c-ocores.h

index cfcebb10d14edb0e70af97d2b4ec0df4378eed05..c269aaa2f26a1aefde7bf60a069d9f544c13c009 100644 (file)
@@ -20,6 +20,8 @@ platform_device with the base address and interrupt number. The
 dev.platform_data of the device should also point to a struct
 ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the
 distance between registers and the input clock speed.
+There is also a possibility to attach a list of i2c_board_info which
+the i2c-ocores driver will add to the bus upon creation.
 
 E.G. something like:
 
@@ -36,9 +38,24 @@ static struct resource ocores_resources[] = {
        },
 };
 
+/* optional board info */
+struct i2c_board_info ocores_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("tsc2003", 0x48),
+               .platform_data = &tsc2003_platform_data,
+               .irq = TSC_IRQ
+       },
+       {
+               I2C_BOARD_INFO("adv7180", 0x42 >> 1),
+               .irq = ADV_IRQ
+       }
+};
+
 static struct ocores_i2c_platform_data myi2c_data = {
        .regstep        = 2,            /* two bytes between registers */
        .clock_khz      = 50000,        /* input clock of 50MHz */
+       .devices        = ocores_i2c_board_info, /* optional table of devices */
+       .num_devices    = ARRAY_SIZE(ocores_i2c_board_info), /* table size */
 };
 
 static struct platform_device myi2c = {
index f1c6ca7e285235bd2033831929bec4d22e259672..c8460fa9cfac751b8c236d9ad171f823376951d7 100644 (file)
@@ -298,7 +298,7 @@ config I2C_BLACKFIN_TWI
 config I2C_BLACKFIN_TWI_CLK_KHZ
        int "Blackfin TWI I2C clock (kHz)"
        depends on I2C_BLACKFIN_TWI
-       range 10 400
+       range 21 400
        default 50
        help
          The unit of the TWI clock is kHz.
index fc548b3d002e581fe29bd351aa48c11356650e2c..26d8987e69bf171f2e0431789b4192da2a461a51 100644 (file)
@@ -104,9 +104,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) | STOP);
                else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-                               iface->cur_msg+1 < iface->msg_num)
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | RSTART);
+                        iface->cur_msg + 1 < iface->msg_num) {
+                       if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+                               write_MASTER_CTL(iface,
+                                       read_MASTER_CTL(iface) | RSTART | MDIR);
+                       else
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+               }
                SSYNC();
                /* Clear status */
                write_INT_STAT(iface, XMTSERV);
@@ -134,9 +139,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                                read_MASTER_CTL(iface) | STOP);
                        SSYNC();
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-                               iface->cur_msg+1 < iface->msg_num) {
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | RSTART);
+                          iface->cur_msg + 1 < iface->msg_num) {
+                       if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+                               write_MASTER_CTL(iface,
+                                       read_MASTER_CTL(iface) | RSTART | MDIR);
+                       else
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
                        SSYNC();
                }
                /* Clear interrupt source */
@@ -196,8 +205,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);
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | MEN | MDIR);
                        SSYNC();
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
                                iface->cur_msg+1 < iface->msg_num) {
@@ -222,18 +229,19 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        }
 
                        if (iface->pmsg[iface->cur_msg].len <= 255)
-                               write_MASTER_CTL(iface,
-                               iface->pmsg[iface->cur_msg].len << 6);
+                                       write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) &
+                                       (~(0xff << 6))) |
+                               (iface->pmsg[iface->cur_msg].len << 6));
                        else {
-                               write_MASTER_CTL(iface, 0xff << 6);
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) |
+                                       (0xff << 6)));
                                iface->manual_stop = 1;
                        }
                        /* remove restart bit and enable master receive */
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) & ~RSTART);
-                       write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
-                               MEN | ((iface->read_write == I2C_SMBUS_READ) ?
-                               MDIR : 0));
                        SSYNC();
                } else {
                        iface->result = 1;
@@ -441,6 +449,16 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                }
                iface->transPtr = data->block;
                break;
+       case I2C_SMBUS_I2C_BLOCK_DATA:
+               if (read_write == I2C_SMBUS_READ) {
+                       iface->readNum = data->block[0];
+                       iface->cur_mode = TWI_I2C_MODE_COMBINED;
+               } else {
+                       iface->writeNum = data->block[0];
+                       iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+               }
+               iface->transPtr = (u8 *)&data->block[1];
+               break;
        default:
                return -1;
        }
@@ -564,7 +582,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
               I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
-              I2C_FUNC_I2C;
+              I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
 }
 
 static struct i2c_algorithm bfin_twi_algorithm = {
@@ -614,6 +632,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        struct i2c_adapter *p_adap;
        struct resource *res;
        int rc;
+       unsigned int clkhilow;
 
        iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
        if (!iface) {
@@ -675,10 +694,14 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        /* Set TWI internal clock as 10MHz */
        write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
 
+       /*
+        * We will not end up with a CLKDIV=0 because no one will specify
+        * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100)
+        */
+       clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ;
+
        /* Set Twi interface clock as specified */
-       write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
-                       << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
-                       & 0xFF));
+       write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
 
        /* Enable TWI */
        write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
index e5193bf754837bda5108651679c477ecd4248456..3542c6ba98f1ab9ba8bdd5279a8400a35f11592e 100644 (file)
@@ -216,6 +216,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        struct ocores_i2c_platform_data *pdata;
        struct resource *res, *res2;
        int ret;
+       int i;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
@@ -271,6 +272,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
                goto add_adapter_failed;
        }
 
+       /* add in known devices to the bus */
+       for (i = 0; i < pdata->num_devices; i++)
+               i2c_new_device(&i2c->adap, pdata->devices + i);
+
        return 0;
 
 add_adapter_failed:
index ece0125a1ee520710f1e4ac18cd7b8eea83f0422..c73475dd0fba00c2dd5953b3b37ebf5837ad7f37 100644 (file)
@@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 
        if (cpu_is_omap2430() || cpu_is_omap34xx()) {
 
-               /* HSI2C controller internal clk rate should be 19.2 Mhz */
-               internal_clk = 19200;
+               /*
+                * HSI2C controller internal clk rate should be 19.2 Mhz for
+                * HS and for all modes on 2430. On 34xx we can use lower rate
+                * to get longer filter period for better noise suppression.
+                * The filter is iclk (fclk for HS) period.
+                */
+               if (dev->speed > 400 || cpu_is_omap_2430())
+                       internal_clk = 19200;
+               else if (dev->speed > 100)
+                       internal_clk = 9600;
+               else
+                       internal_clk = 4000;
                fclk_rate = clk_get_rate(dev->fclk) / 1000;
 
                /* Compute prescaler divisor */
@@ -343,17 +353,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 
                /* If configured for High Speed */
                if (dev->speed > 400) {
+                       unsigned long scl;
+
                        /* For first phase of HS mode */
-                       fsscll = internal_clk / (400 * 2) - 6;
-                       fssclh = internal_clk / (400 * 2) - 6;
+                       scl = internal_clk / 400;
+                       fsscll = scl - (scl / 3) - 7;
+                       fssclh = (scl / 3) - 5;
 
                        /* For second phase of HS mode */
-                       hsscll = fclk_rate / (dev->speed * 2) - 6;
-                       hssclh = fclk_rate / (dev->speed * 2) - 6;
+                       scl = fclk_rate / dev->speed;
+                       hsscll = scl - (scl / 3) - 7;
+                       hssclh = (scl / 3) - 5;
+               } else if (dev->speed > 100) {
+                       unsigned long scl;
+
+                       /* Fast mode */
+                       scl = internal_clk / dev->speed;
+                       fsscll = scl - (scl / 3) - 7;
+                       fssclh = (scl / 3) - 5;
                } else {
-                       /* To handle F/S modes */
-                       fsscll = internal_clk / (dev->speed * 2) - 6;
-                       fssclh = internal_clk / (dev->speed * 2) - 6;
+                       /* Standard mode */
+                       fsscll = internal_clk / (dev->speed * 2) - 7;
+                       fssclh = internal_clk / (dev->speed * 2) - 5;
                }
                scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
                sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
index 1691ef0f1ee1ee64dcd9352cf785849b26592623..079a312d36fd098422a842e53e00b59ac758f395 100644 (file)
@@ -51,6 +51,11 @@ enum s3c24xx_i2c_state {
        STATE_STOP
 };
 
+enum s3c24xx_i2c_type {
+       TYPE_S3C2410,
+       TYPE_S3C2440,
+};
+
 struct s3c24xx_i2c {
        spinlock_t              lock;
        wait_queue_head_t       wait;
@@ -88,8 +93,10 @@ struct s3c24xx_i2c {
 static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
 {
        struct platform_device *pdev = to_platform_device(i2c->dev);
+       enum s3c24xx_i2c_type type;
 
-       return !strcmp(pdev->name, "s3c2440-i2c");
+       type = platform_get_device_id(pdev)->driver_data;
+       return type == TYPE_S3C2440;
 }
 
 /* s3c24xx_i2c_master_complete
@@ -969,52 +976,41 @@ static int s3c24xx_i2c_resume(struct platform_device *dev)
 
 /* device driver for platform bus bits */
 
-static struct platform_driver s3c2410_i2c_driver = {
-       .probe          = s3c24xx_i2c_probe,
-       .remove         = s3c24xx_i2c_remove,
-       .suspend_late   = s3c24xx_i2c_suspend_late,
-       .resume         = s3c24xx_i2c_resume,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "s3c2410-i2c",
-       },
+static struct platform_device_id s3c24xx_driver_ids[] = {
+       {
+               .name           = "s3c2410-i2c",
+               .driver_data    = TYPE_S3C2410,
+       }, {
+               .name           = "s3c2440-i2c",
+               .driver_data    = TYPE_S3C2440,
+       }, { },
 };
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
 
-static struct platform_driver s3c2440_i2c_driver = {
+static struct platform_driver s3c24xx_i2c_driver = {
        .probe          = s3c24xx_i2c_probe,
        .remove         = s3c24xx_i2c_remove,
        .suspend_late   = s3c24xx_i2c_suspend_late,
        .resume         = s3c24xx_i2c_resume,
+       .id_table       = s3c24xx_driver_ids,
        .driver         = {
                .owner  = THIS_MODULE,
-               .name   = "s3c2440-i2c",
+               .name   = "s3c-i2c",
        },
 };
 
 static int __init i2c_adap_s3c_init(void)
 {
-       int ret;
-
-       ret = platform_driver_register(&s3c2410_i2c_driver);
-       if (ret == 0) {
-               ret = platform_driver_register(&s3c2440_i2c_driver);
-               if (ret)
-                       platform_driver_unregister(&s3c2410_i2c_driver);
-       }
-
-       return ret;
+       return platform_driver_register(&s3c24xx_i2c_driver);
 }
 subsys_initcall(i2c_adap_s3c_init);
 
 static void __exit i2c_adap_s3c_exit(void)
 {
-       platform_driver_unregister(&s3c2410_i2c_driver);
-       platform_driver_unregister(&s3c2440_i2c_driver);
+       platform_driver_unregister(&s3c24xx_i2c_driver);
 }
 module_exit(i2c_adap_s3c_exit);
 
 MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-i2c");
-MODULE_ALIAS("platform:s3c2440-i2c");
index 8ed591b0887ea4a2babca0ad904ea73ccc436959..4d5e57ff66144f48fce709bcf5d151b96f8f1530 100644 (file)
@@ -14,6 +14,8 @@
 struct ocores_i2c_platform_data {
        u32 regstep;   /* distance between registers */
        u32 clock_khz; /* input clock in kHz */
+       u8 num_devices; /* number of devices in the devices list */
+       struct i2c_board_info const *devices; /* devices connected to the bus */
 };
 
 #endif /* _LINUX_I2C_OCORES_H */