i2c: New Simtec I2C bus driver
authorBen Dooks <ben@fluff.org>
Tue, 1 May 2007 21:26:34 +0000 (23:26 +0200)
committerJean Delvare <khali@hyperion.delvare>
Tue, 1 May 2007 21:26:34 +0000 (23:26 +0200)
Platform driver for the Simtec CPLD based simple I2C logic.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-simtec.c [new file with mode: 0644]

index 33a8a67f161b9b01bc324f7325b757ce71abc5d6..2178c9bebfc9d8f4c91e1a53e452c0b4fc4ae19b 100644 (file)
@@ -413,6 +413,18 @@ config I2C_SIBYTE
        help
          Supports the SiByte SOC on-chip I2C interfaces (2 channels).
 
+config I2C_SIMTEC
+       tristate "Simtec Generic I2C interface"
+       select I2C_ALGOBIT
+       help
+         If you say yes to this option, support will be inclyded for
+         the Simtec Generic I2C interface. This driver is for the
+         simple I2C bus used on newer Simtec products for general
+         I2C, such as DDC on the Simtec BBD2016A.
+
+         This driver can also be build as a module. If so, the module
+         will be called i2c-simtec.
+
 config SCx200_I2C
        tristate "NatSemi SCx200 I2C using GPIO pins"
        depends on SCx200_GPIO
index 5689165f6d6af7403646b2cc960873658e313189..3a020ea8edef28d39c5bfb09d8257160c0eca0f8 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_I2C_RPXLITE)     += i2c-rpx.o
 obj-$(CONFIG_I2C_S3C2410)      += i2c-s3c2410.o
 obj-$(CONFIG_I2C_SAVAGE4)      += i2c-savage4.o
 obj-$(CONFIG_I2C_SIBYTE)       += i2c-sibyte.o
+obj-$(CONFIG_I2C_SIMTEC)       += i2c-simtec.o
 obj-$(CONFIG_I2C_SIS5595)      += i2c-sis5595.o
 obj-$(CONFIG_I2C_SIS630)       += i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)       += i2c-sis96x.o
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
new file mode 100644 (file)
index 0000000..10af8d3
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C Controller
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+struct simtec_i2c_data {
+       struct resource         *ioarea;
+       void __iomem            *reg;
+       struct i2c_adapter       adap;
+       struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA    (1<<2)
+#define CMD_SET_SCL    (1<<3)
+
+#define STATE_SDA      (1<<0)
+#define STATE_SCL      (1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+       struct simtec_i2c_data *pd = pw;
+       writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+       struct simtec_i2c_data *pd = pw;
+       writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+       struct simtec_i2c_data *pd = pw;
+       return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+       struct simtec_i2c_data *pd = pw;
+       return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+       struct simtec_i2c_data *pd;
+       struct resource *res;
+       int size;
+       int ret;
+
+       pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+       if (pd == NULL) {
+               dev_err(&dev->dev, "cannot allocate private data\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(dev, pd);
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&dev->dev, "cannot find IO resource\n");
+               ret = -ENOENT;
+               goto err;
+       }
+
+       size = (res->end-res->start)+1;
+
+       pd->ioarea = request_mem_region(res->start, size, dev->name);
+       if (pd->ioarea == NULL) {
+               dev_err(&dev->dev, "cannot request IO\n");
+               ret = -ENXIO;
+               goto err;
+       }
+
+       pd->reg = ioremap(res->start, size);
+       if (pd->reg == NULL) {
+               dev_err(&dev->dev, "cannot map IO\n");
+               ret = -ENXIO;
+               goto err_res;
+       }
+
+       /* setup the private data */
+
+       pd->adap.owner = THIS_MODULE;
+       pd->adap.algo_data = &pd->bit;
+       pd->adap.dev.parent = &dev->dev;
+
+       strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+       pd->bit.data = pd;
+       pd->bit.setsda = simtec_i2c_setsda;
+       pd->bit.setscl = simtec_i2c_setscl;
+       pd->bit.getsda = simtec_i2c_getsda;
+       pd->bit.getscl = simtec_i2c_getscl;
+       pd->bit.timeout = HZ;
+       pd->bit.udelay = 20;
+
+       ret = i2c_bit_add_bus(&pd->adap);
+       if (ret)
+               goto err_all;
+
+       return 0;
+
+ err_all:
+       iounmap(pd->reg);
+
+ err_res:
+       release_resource(pd->ioarea);
+       kfree(pd->ioarea);
+
+ err:
+       kfree(pd);
+       return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+       struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+       i2c_del_adapter(&pd->adap);
+
+       iounmap(pd->reg);
+       release_resource(pd->ioarea);
+       kfree(pd->ioarea);
+       kfree(pd);
+
+       return 0;
+}
+
+
+/* device driver */
+
+static struct platform_driver simtec_i2c_driver = {
+       .driver         = {
+               .name           = "simtec-i2c",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = simtec_i2c_probe,
+       .remove         = simtec_i2c_remove,
+};
+
+static int __init i2c_adap_simtec_init(void)
+{
+       return platform_driver_register(&simtec_i2c_driver);
+}
+
+static void __exit i2c_adap_simtec_exit(void)
+{
+       platform_driver_unregister(&simtec_i2c_driver);
+}
+
+module_init(i2c_adap_simtec_init);
+module_exit(i2c_adap_simtec_exit);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");