* [PATCH] OpenCores I2C bus driver
@ 2006-04-21 9:05 Peter Korsgaard
2006-04-21 21:19 ` Jeff Garzik
0 siblings, 1 reply; 15+ messages in thread
From: Peter Korsgaard @ 2006-04-21 9:05 UTC (permalink / raw)
To: lm-sensors; +Cc: linux-kernel
Hi,
The following patch adds support for the OpenCores I2C controller IP
core (See http://www.opencores.org/projects.cgi/web/i2c/overview).
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
drivers/i2c/busses/Kconfig | 11 +
drivers/i2c/busses/Makefile | 1
drivers/i2c/busses/i2c-ocores.c | 358 ++++++++++++++++++++++++++++++++++++++++
include/linux/i2c-ocores.h | 20 ++
4 files changed, 390 insertions(+)
Index: linux/drivers/i2c/busses/Kconfig
===================================================================
--- linux.orig/drivers/i2c/busses/Kconfig 2006-04-19 10:24:35.000000000 +0200
+++ linux/drivers/i2c/busses/Kconfig 2006-04-19 10:24:38.000000000 +0200
@@ -517,4 +517,15 @@
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on I2C
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
endmenu
Index: linux/drivers/i2c/busses/Makefile
===================================================================
--- linux.orig/drivers/i2c/busses/Makefile 2006-03-20 06:53:29.000000000 +0100
+++ linux/drivers/i2c/busses/Makefile 2006-04-19 10:24:38.000000000 +0200
@@ -40,6 +40,7 @@
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
Index: linux/drivers/i2c/busses/i2c-ocores.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/drivers/i2c/busses/i2c-ocores.c 2006-04-21 10:51:05.000000000 +0200
@@ -0,0 +1,358 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-ocores.h>
+
+struct ocores_i2c {
+ void __iomem *base;
+ int regstep;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+};
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4
+#define OCI2C_STATUS 4
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_NACK 0x80
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_IF 0x01
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+static __inline__ void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg * i2c->regstep);
+}
+
+static __inline__ u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg * i2c->regstep);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR))
+ {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up_interruptible(&i2c->wait);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST)
+ {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE))
+ {
+ i2c->state =
+ (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK)
+ {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+ else
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+ /* end of msg? */
+ if (i2c->pos == msg->len)
+ {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) /* end? */
+ {
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART))
+ {
+ u8 addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ }
+ else
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ }
+ else
+ {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state == STATE_READ)
+ {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ }
+ else
+ {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ocores_i2c *i2c = dev_id;
+
+ ocores_process(i2c);
+
+ return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA,
+ (i2c->msg->addr << 1) |
+ ((i2c->msg->flags & I2C_M_RD) ? 1:0));
+
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (wait_event_interruptible_timeout(i2c->wait,
+ (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ*5))
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+ else
+ return -ETIMEDOUT;
+}
+
+static void ocores_init(struct ocores_i2c *i2c,
+ struct ocores_i2c_platform_data *pdata)
+{
+ int prescale;
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, 0);
+
+ prescale = (pdata->clock_khz / (5*100)) - 1;
+ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(i2c, OCI2C_CONTROL, 0xc0);
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+};
+
+static struct i2c_adapter ocores_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ocores",
+ .class = I2C_CLASS_HWMON,
+ .algo = &ocores_algorithm,
+ .timeout = 2,
+ .retries = 1
+};
+
+
+static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+{
+ struct ocores_i2c* i2c;
+ struct ocores_i2c_platform_data* pdata;
+ struct resource *res, *res2;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+
+ i2c->base = ioremap(res->start, res->end - res->start + 1);
+ if (!i2c->base)
+ {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ i2c->regstep = pdata->regstep;
+ ocores_init(i2c, pdata);
+
+ init_waitqueue_head(&i2c->wait);
+ ret = request_irq(res2->start, ocores_isr, 0,
+ pdev->name, i2c);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = ocores_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ goto add_adapter_failed;
+ }
+
+ return 0;
+
+ add_adapter_failed:
+ free_irq(res2->start, i2c);
+ request_irq_failed:
+ iounmap(i2c->base);
+ map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+ kfree(i2c);
+
+ return ret;
+}
+
+static int __devexit ocores_i2c_remove(struct platform_device* pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /* disable i2c logic */
+ oc_setreg(i2c, OCI2C_CONTROL, 0);
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, i2c);
+
+ iounmap(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(i2c);
+
+ return 0;
+}
+
+static struct platform_driver ocores_i2c_driver = {
+ .probe = ocores_i2c_probe,
+ .remove = ocores_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ocores-i2c",
+ },
+};
+
+static int __init ocores_i2c_init(void)
+{
+ return platform_driver_register(&ocores_i2c_driver);
+}
+
+static void __exit ocores_i2c_exit(void)
+{
+ platform_driver_unregister(&ocores_i2c_driver);
+}
+
+module_init(ocores_i2c_init);
+module_exit(ocores_i2c_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
Index: linux/include/linux/i2c-ocores.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/i2c-ocores.h 2006-04-21 10:54:43.000000000 +0200
@@ -0,0 +1,20 @@
+/*
+ * i2c-ocores.h - definitions for the i2c-ocores interface
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _LINUX_I2C_OCORES_H
+#define _LINUX_I2C_OCORES_H
+
+struct ocores_i2c_platform_data {
+ u32 regstep; /* distance between registers */
+ u32 clock_khz; /* input clock in KHz */
+};
+
+#endif /* _LINUX_I2C_OCORES_H */
+
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
@ 2006-04-21 12:34 Peter Korsgaard
2006-05-14 9:09 ` Rudolf Marek
` (10 more replies)
0 siblings, 11 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-04-21 12:34 UTC (permalink / raw)
To: lm-sensors
Hi,
The following patch adds support for the OpenCores I2C controller IP
core (See http://www.opencores.org/projects.cgi/web/i2c/overview).
Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
---
drivers/i2c/busses/Kconfig | 11 +
drivers/i2c/busses/Makefile | 1
drivers/i2c/busses/i2c-ocores.c | 358 ++++++++++++++++++++++++++++++++++++++++
include/linux/i2c-ocores.h | 20 ++
4 files changed, 390 insertions(+)
Index: linux/drivers/i2c/busses/Kconfig
=================================--- linux.orig/drivers/i2c/busses/Kconfig 2006-04-19 10:24:35.000000000 +0200
+++ linux/drivers/i2c/busses/Kconfig 2006-04-19 10:24:38.000000000 +0200
@@ -517,4 +517,15 @@
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on I2C
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
endmenu
Index: linux/drivers/i2c/busses/Makefile
=================================--- linux.orig/drivers/i2c/busses/Makefile 2006-03-20 06:53:29.000000000 +0100
+++ linux/drivers/i2c/busses/Makefile 2006-04-19 10:24:38.000000000 +0200
@@ -40,6 +40,7 @@
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
Index: linux/drivers/i2c/busses/i2c-ocores.c
=================================--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/drivers/i2c/busses/i2c-ocores.c 2006-04-21 10:51:05.000000000 +0200
@@ -0,0 +1,358 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
+ *
+ * Peter Korsgaard <jacmet at sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-ocores.h>
+
+struct ocores_i2c {
+ void __iomem *base;
+ int regstep;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+};
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4
+#define OCI2C_STATUS 4
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_NACK 0x80
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_IF 0x01
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+static __inline__ void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg * i2c->regstep);
+}
+
+static __inline__ u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg * i2c->regstep);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if ((i2c->state = STATE_DONE) || (i2c->state = STATE_ERROR))
+ {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up_interruptible(&i2c->wait);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST)
+ {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if ((i2c->state = STATE_START) || (i2c->state = STATE_WRITE))
+ {
+ i2c->state + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK)
+ {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+ else
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+ /* end of msg? */
+ if (i2c->pos = msg->len)
+ {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) /* end? */
+ {
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART))
+ {
+ u8 addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ }
+ else
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ }
+ else
+ {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state = STATE_READ)
+ {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos = (msg->len-1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ }
+ else
+ {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ocores_i2c *i2c = dev_id;
+
+ ocores_process(i2c);
+
+ return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA,
+ (i2c->msg->addr << 1) |
+ ((i2c->msg->flags & I2C_M_RD) ? 1:0));
+
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (wait_event_interruptible_timeout(i2c->wait,
+ (i2c->state = STATE_ERROR) ||
+ (i2c->state = STATE_DONE), HZ*5))
+ return (i2c->state = STATE_DONE) ? num : -EIO;
+ else
+ return -ETIMEDOUT;
+}
+
+static void ocores_init(struct ocores_i2c *i2c,
+ struct ocores_i2c_platform_data *pdata)
+{
+ int prescale;
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, 0);
+
+ prescale = (pdata->clock_khz / (5*100)) - 1;
+ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(i2c, OCI2C_CONTROL, 0xc0);
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+};
+
+static struct i2c_adapter ocores_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ocores",
+ .class = I2C_CLASS_HWMON,
+ .algo = &ocores_algorithm,
+ .timeout = 2,
+ .retries = 1
+};
+
+
+static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+{
+ struct ocores_i2c* i2c;
+ struct ocores_i2c_platform_data* pdata;
+ struct resource *res, *res2;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+
+ i2c->base = ioremap(res->start, res->end - res->start + 1);
+ if (!i2c->base)
+ {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ i2c->regstep = pdata->regstep;
+ ocores_init(i2c, pdata);
+
+ init_waitqueue_head(&i2c->wait);
+ ret = request_irq(res2->start, ocores_isr, 0,
+ pdev->name, i2c);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = ocores_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ goto add_adapter_failed;
+ }
+
+ return 0;
+
+ add_adapter_failed:
+ free_irq(res2->start, i2c);
+ request_irq_failed:
+ iounmap(i2c->base);
+ map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+ kfree(i2c);
+
+ return ret;
+}
+
+static int __devexit ocores_i2c_remove(struct platform_device* pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /* disable i2c logic */
+ oc_setreg(i2c, OCI2C_CONTROL, 0);
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, i2c);
+
+ iounmap(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(i2c);
+
+ return 0;
+}
+
+static struct platform_driver ocores_i2c_driver = {
+ .probe = ocores_i2c_probe,
+ .remove = ocores_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ocores-i2c",
+ },
+};
+
+static int __init ocores_i2c_init(void)
+{
+ return platform_driver_register(&ocores_i2c_driver);
+}
+
+static void __exit ocores_i2c_exit(void)
+{
+ platform_driver_unregister(&ocores_i2c_driver);
+}
+
+module_init(ocores_i2c_init);
+module_exit(ocores_i2c_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet at sunsite.dk>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
Index: linux/include/linux/i2c-ocores.h
=================================--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/i2c-ocores.h 2006-04-21 10:54:43.000000000 +0200
@@ -0,0 +1,20 @@
+/*
+ * i2c-ocores.h - definitions for the i2c-ocores interface
+ *
+ * Peter Korsgaard <jacmet at sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _LINUX_I2C_OCORES_H
+#define _LINUX_I2C_OCORES_H
+
+struct ocores_i2c_platform_data {
+ u32 regstep; /* distance between registers */
+ u32 clock_khz; /* input clock in KHz */
+};
+
+#endif /* _LINUX_I2C_OCORES_H */
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 9:05 [PATCH] OpenCores I2C bus driver Peter Korsgaard
@ 2006-04-21 21:19 ` Jeff Garzik
0 siblings, 0 replies; 15+ messages in thread
From: Jeff Garzik @ 2006-04-21 21:19 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: lm-sensors, linux-kernel
Peter Korsgaard wrote:
> Hi,
>
> The following patch adds support for the OpenCores I2C controller IP
> core (See http://www.opencores.org/projects.cgi/web/i2c/overview).
>
> Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
Very cool... I'm glad to see opencores stuff making it into the
upstream kernel.
One day I hope to see the OpenRISC port in the upstream kernel...
Jeff
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] OpenCores I2C bus driver
@ 2006-04-21 21:19 ` Jeff Garzik
0 siblings, 0 replies; 15+ messages in thread
From: Jeff Garzik @ 2006-04-21 21:19 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: lm-sensors, linux-kernel
Peter Korsgaard wrote:
> Hi,
>
> The following patch adds support for the OpenCores I2C controller IP
> core (See http://www.opencores.org/projects.cgi/web/i2c/overview).
>
> Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Very cool... I'm glad to see opencores stuff making it into the
upstream kernel.
One day I hope to see the OpenRISC port in the upstream kernel...
Jeff
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
@ 2006-05-14 9:09 ` Rudolf Marek
2006-05-18 17:18 ` Peter Korsgaard
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Rudolf Marek @ 2006-05-14 9:09 UTC (permalink / raw)
To: lm-sensors
Hello,
Sorry for delay we all had lot of other stuff to do. I checked your driver and
it seems very good. Please check my comments in the code.
Regards
Rudolf
> Index: linux/drivers/i2c/busses/Kconfig
> =================================> --- linux.orig/drivers/i2c/busses/Kconfig 2006-04-19 10:24:35.000000000 +0200
> +++ linux/drivers/i2c/busses/Kconfig 2006-04-19 10:24:38.000000000 +0200
> @@ -517,4 +517,15 @@
> This driver can also be built as a module. If so, the module
> will be called i2c-mv64xxx.
>
> +config I2C_OCORES
> + tristate "OpenCores I2C Controller"
> + depends on I2C
Really no experimental? How long is driver used?
> + help
> + If you say yes to this option, support will be included for the
> + OpenCores I2C controller. For details see
> + http://www.opencores.org/projects.cgi/web/i2c/overview
> +
> + This driver can also be built as a module. If so, the module
> + will be called i2c-ocores.
> +
> endmenu
> Index: linux/drivers/i2c/busses/Makefile
> =================================> --- linux.orig/drivers/i2c/busses/Makefile 2006-03-20 06:53:29.000000000 +0100
> +++ linux/drivers/i2c/busses/Makefile 2006-04-19 10:24:38.000000000 +0200
> @@ -40,6 +40,7 @@
> obj-$(CONFIG_I2C_VIA) += i2c-via.o
> obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
> obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
> +obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
I think rest of files is alphabetic order
> obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
> obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
>
> Index: linux/drivers/i2c/busses/i2c-ocores.c
> =================================> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux/drivers/i2c/busses/i2c-ocores.c 2006-04-21 10:51:05.000000000 +0200
> @@ -0,0 +1,358 @@
> +/*
> + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
> + * (http://www.opencores.org/projects.cgi/web/i2c/overview).
> + *
> + * Peter Korsgaard <jacmet at sunsite.dk>
Should have (C) and year
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/config.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/io.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/wait.h>
> +#include <linux/i2c-ocores.h>
> +
> +struct ocores_i2c {
> + void __iomem *base;
> + int regstep;
> + wait_queue_head_t wait;
> + struct i2c_adapter adap;
> + struct i2c_msg *msg;
> + int pos;
> + int nmsgs;
> + int state; /* see STATE_ */
> +};
> +
> +/* registers */
> +#define OCI2C_PRELOW 0
> +#define OCI2C_PREHIGH 1
> +#define OCI2C_CONTROL 2
> +#define OCI2C_DATA 3
> +#define OCI2C_CMD 4
> +#define OCI2C_STATUS 4
> +
> +#define OCI2C_CMD_START 0x91
> +#define OCI2C_CMD_STOP 0x41
> +#define OCI2C_CMD_READ 0x21
> +#define OCI2C_CMD_WRITE 0x11
> +#define OCI2C_CMD_READ_ACK 0x21
> +#define OCI2C_CMD_READ_NACK 0x29
> +#define OCI2C_CMD_IACK 0x01
> +
> +#define OCI2C_STAT_BUSY 0x40
> +#define OCI2C_STAT_TIP 0x02
> +#define OCI2C_STAT_NACK 0x80
> +#define OCI2C_STAT_ARBLOST 0x20
> +#define OCI2C_STAT_IF 0x01
> +
> +#define STATE_DONE 0
> +#define STATE_START 1
> +#define STATE_WRITE 2
> +#define STATE_READ 3
> +#define STATE_ERROR 4
> +
> +static __inline__ void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
> +{
> + iowrite8(value, i2c->base + reg * i2c->regstep);
> +}
> +
> +static __inline__ u8 oc_getreg(struct ocores_i2c *i2c, int reg)
> +{
> + return ioread8(i2c->base + reg * i2c->regstep);
> +}
> +
> +static void ocores_process(struct ocores_i2c *i2c)
> +{
> + struct i2c_msg *msg = i2c->msg;
> + u8 stat = oc_getreg(i2c, OCI2C_STATUS);
> +
> + if ((i2c->state = STATE_DONE) || (i2c->state = STATE_ERROR))
> + {
> + /* stop has been sent */
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
> + wake_up_interruptible(&i2c->wait);
> + return;
> + }
> +
> + /* error? */
> + if (stat & OCI2C_STAT_ARBLOST)
> + {
> + i2c->state = STATE_ERROR;
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
> + return;
> + }
> +
> + if ((i2c->state = STATE_START) || (i2c->state = STATE_WRITE))
> + {
> + i2c->state > + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
> +
> + if (stat & OCI2C_STAT_NACK)
> + {
> + i2c->state = STATE_ERROR;
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
> + return;
> + }
> + }
> + else
> + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
> +
> + /* end of msg? */
> + if (i2c->pos = msg->len)
> + {
> + i2c->nmsgs--;
> + i2c->msg++;
> + i2c->pos = 0;
> + msg = i2c->msg;
> +
> + if (i2c->nmsgs) /* end? */
> + {
> + /* send start? */
> + if (!(msg->flags & I2C_M_NOSTART))
> + {
> + u8 addr = (msg->addr << 1);
> +
> + if (msg->flags & I2C_M_RD)
> + addr |= 1;
> +
> + i2c->state = STATE_START;
> +
> + oc_setreg(i2c, OCI2C_DATA, addr);
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
> + return;
> + }
> + else
> + i2c->state = (msg->flags & I2C_M_RD)
> + ? STATE_READ : STATE_WRITE;
> + }
> + else
> + {
> + i2c->state = STATE_DONE;
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
> + return;
> + }
> + }
> +
> + if (i2c->state = STATE_READ)
> + {
> + oc_setreg(i2c, OCI2C_CMD, i2c->pos = (msg->len-1) ?
> + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
> + }
> + else
> + {
> + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
> + }
> +}
> +
> +static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
> +{
> + struct ocores_i2c *i2c = dev_id;
> +
> + ocores_process(i2c);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> + struct ocores_i2c *i2c = i2c_get_adapdata(adap);
> +
> + i2c->msg = msgs;
> + i2c->pos = 0;
> + i2c->nmsgs = num;
> + i2c->state = STATE_START;
> +
> + oc_setreg(i2c, OCI2C_DATA,
> + (i2c->msg->addr << 1) |
> + ((i2c->msg->flags & I2C_M_RD) ? 1:0));
> +
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
> +
> + if (wait_event_interruptible_timeout(i2c->wait,
> + (i2c->state = STATE_ERROR) ||
> + (i2c->state = STATE_DONE), HZ*5))
> + return (i2c->state = STATE_DONE) ? num : -EIO;
> + else
> + return -ETIMEDOUT;
> +}
> +
> +static void ocores_init(struct ocores_i2c *i2c,
> + struct ocores_i2c_platform_data *pdata)
> +{
> + int prescale;
> +
> + /* make sure the device is disabled */
> + oc_setreg(i2c, OCI2C_CONTROL, 0);
Well I started to read the driver from a flow and this is the first occurrence
to write to some register :). I think much better handling of reserved bits is
to read them from device change bits I know and then write all back.
I'm also surprised that the device has no ID/revision regs which might be handy
for future extensions
> +
> + prescale = (pdata->clock_khz / (5*100)) - 1;
No checks for evil values?
> + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
> + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
> +
> + /* Init the device */
> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
> + oc_setreg(i2c, OCI2C_CONTROL, 0xc0);
and here again
> +}
> +
> +
> +static u32 ocores_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static struct i2c_algorithm ocores_algorithm = {
> + .master_xfer = ocores_xfer,
> + .functionality = ocores_func,
> +};
> +
> +static struct i2c_adapter ocores_adapter = {
> + .owner = THIS_MODULE,
> + .name = "i2c-ocores",
> + .class = I2C_CLASS_HWMON,
> + .algo = &ocores_algorithm,
> + .timeout = 2,
> + .retries = 1
> +};
> +
> +
> +static int __devinit ocores_i2c_probe(struct platform_device *pdev)
> +{
> + struct ocores_i2c* i2c;
> + struct ocores_i2c_platform_data* pdata;
> + struct resource *res, *res2;
> + int ret;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res)
> + return -ENODEV;
> +
> + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!res2)
> + return -ENODEV;
> +
> + pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
> + if (!pdata)
> + return -ENODEV;
> +
> + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
> + if (!i2c)
> + return -ENOMEM;
> +
> + if (!request_mem_region(res->start, res->end - res->start + 1,
> + pdev->name)) {
> + dev_err(&pdev->dev, "Memory region busy\n");
> + ret = -EBUSY;
> + goto request_mem_failed;
> + }
> +
> + i2c->base = ioremap(res->start, res->end - res->start + 1);
> + if (!i2c->base)
> + {
> + dev_err(&pdev->dev, "Unable to map registers\n");
> + ret = -EIO;
> + goto map_failed;
> + }
> +
> + i2c->regstep = pdata->regstep;
> + ocores_init(i2c, pdata);
> +
> + init_waitqueue_head(&i2c->wait);
> + ret = request_irq(res2->start, ocores_isr, 0,
> + pdev->name, i2c);
> + if (ret)
> + {
> + dev_err(&pdev->dev, "Cannot claim IRQ\n");
> + goto request_irq_failed;
> + }
> +
> + /* hook up driver to tree */
> + platform_set_drvdata(pdev, i2c);
> + i2c->adap = ocores_adapter;
> + i2c_set_adapdata(&i2c->adap, i2c);
> + i2c->adap.dev.parent = &pdev->dev;
> +
> + /* add i2c adapter to i2c tree */
> + ret = i2c_add_adapter(&i2c->adap);
> + if (ret)
> + {
> + dev_err(&pdev->dev, "Failed to add adapter\n");
> + goto add_adapter_failed;
> + }
> +
> + return 0;
> +
> + add_adapter_failed:
> + free_irq(res2->start, i2c);
> + request_irq_failed:
> + iounmap(i2c->base);
> + map_failed:
> + release_mem_region(res->start, res->end - res->start + 1);
> + request_mem_failed:
> + kfree(i2c);
> +
> + return ret;
> +}
> +
> +static int __devexit ocores_i2c_remove(struct platform_device* pdev)
> +{
> + struct ocores_i2c *i2c = platform_get_drvdata(pdev);
> + struct resource *res;
> +
> + /* disable i2c logic */
> + oc_setreg(i2c, OCI2C_CONTROL, 0);
> +
> + /* remove adapter & data */
> + i2c_del_adapter(&i2c->adap);
> + platform_set_drvdata(pdev, NULL);
> +
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (res)
> + free_irq(res->start, i2c);
> +
> + iounmap(i2c->base);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (res)
> + release_mem_region(res->start, res->end - res->start + 1);
> +
> + kfree(i2c);
> +
> + return 0;
> +}
> +
> +static struct platform_driver ocores_i2c_driver = {
> + .probe = ocores_i2c_probe,
> + .remove = ocores_i2c_remove,
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "ocores-i2c",
> + },
> +};
> +
> +static int __init ocores_i2c_init(void)
> +{
> + return platform_driver_register(&ocores_i2c_driver);
> +}
> +
> +static void __exit ocores_i2c_exit(void)
> +{
> + platform_driver_unregister(&ocores_i2c_driver);
> +}
> +
> +module_init(ocores_i2c_init);
> +module_exit(ocores_i2c_exit);
> +
> +MODULE_AUTHOR("Peter Korsgaard <jacmet at sunsite.dk>");
> +MODULE_DESCRIPTION("OpenCores I2C bus driver");
> +MODULE_LICENSE("GPL");
> Index: linux/include/linux/i2c-ocores.h
> =================================> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux/include/linux/i2c-ocores.h 2006-04-21 10:54:43.000000000 +0200
> @@ -0,0 +1,20 @@
> +/*
> + * i2c-ocores.h - definitions for the i2c-ocores interface
> + *
> + * Peter Korsgaard <jacmet at sunsite.dk>
> + *
(C) 2006 perhaps
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_I2C_OCORES_H
> +#define _LINUX_I2C_OCORES_H
> +
> +struct ocores_i2c_platform_data {
> + u32 regstep; /* distance between registers */
> + u32 clock_khz; /* input clock in KHz */
> +};
> +
> +#endif /* _LINUX_I2C_OCORES_H */
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
2006-05-14 9:09 ` Rudolf Marek
@ 2006-05-18 17:18 ` Peter Korsgaard
2006-05-18 20:37 ` Greg KH
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-05-18 17:18 UTC (permalink / raw)
To: lm-sensors
>>>>> "Rudolf" = Rudolf Marek <r.marek at sh.cvut.cz> writes:
Hi,
Rudolf> Sorry for delay we all had lot of other stuff to do. I
Rudolf> checked your driver and it seems very good. Please check my
Rudolf> comments in the code.
No problem, I've had a busy week as well..
Perhaps worth noticing: This is not the latest version of the
patch. Andrew added it to -mm after I posted it and a few small
fixes/cleanups were done. On the 27th of April it was forwarded to
Greg and dropped from -mm.
I'm afraid I've lost track of it since :/ I expect Greg to wait until
2.6.17 gets released before pushing it upstream, but I don't see it in
his git tree..
Greg, where are you hiding it? ;)
>> +config I2C_OCORES
>> + tristate "OpenCores I2C Controller"
>> + depends on I2C
Rudolf> Really no experimental? How long is driver used?
I've been using it for a month or two (on 2 different designs) and the
core logic is based on a eCos driver that I have been using for around
a year.
But we can mark it experimental if you want, I don't feel strongly
about it.
>> obj-$(CONFIG_I2C_VIA) += i2c-via.o
>> obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
>> obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
>> +obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
Rudolf> I think rest of files is alphabetic order
Ok, I'll fix that.
>> + * Peter Korsgaard <jacmet at sunsite.dk>
Rudolf> Should have (C) and year
Really? Isn't that just extra noise that's bound to get out of date?
>> + /* make sure the device is disabled */
>> + oc_setreg(i2c, OCI2C_CONTROL, 0);
Rudolf> Well I started to read the driver from a flow and this is the
Rudolf> first occurrence to write to some register :).
There's also regiser access in ocores_process.
Rudolf> I think much better handling of reserved bits is to read them
Rudolf> from device change bits I know and then write all back.
Yes, that could be done for CONTROL as it's r/w - I'll change that.
Rudolf> I'm also surprised that the device has no ID/revision regs
Rudolf> which might be handy for future extensions
Yeah, but as it's a quite simple device (implemented in FPGA) that was
probably considered overkill.
>> + prescale = (pdata->clock_khz / (5*100)) - 1;
Rudolf> No checks for evil values?
Currently not. It would be a bit hard to define what a valid value
is. Do you think it's needed? This is data provided by the platform
code just like the base address and IRQ number (that we also don't
validate).
>> + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
>> + oc_setreg(i2c, OCI2C_CONTROL, 0xc0);
Rudolf> and here again
I'll add defines for the CONTROL bits and only change the needed bits.
Thanks for your comments!
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
2006-05-14 9:09 ` Rudolf Marek
2006-05-18 17:18 ` Peter Korsgaard
@ 2006-05-18 20:37 ` Greg KH
2006-05-19 5:00 ` Peter Korsgaard
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Greg KH @ 2006-05-18 20:37 UTC (permalink / raw)
To: lm-sensors
On Thu, May 18, 2006 at 07:18:58PM +0200, Peter Korsgaard wrote:
> >>>>> "Rudolf" = Rudolf Marek <r.marek at sh.cvut.cz> writes:
>
> Hi,
>
> Rudolf> Sorry for delay we all had lot of other stuff to do. I
> Rudolf> checked your driver and it seems very good. Please check my
> Rudolf> comments in the code.
>
> No problem, I've had a busy week as well..
>
> Perhaps worth noticing: This is not the latest version of the
> patch. Andrew added it to -mm after I posted it and a few small
> fixes/cleanups were done. On the 27th of April it was forwarded to
> Greg and dropped from -mm.
>
> I'm afraid I've lost track of it since :/ I expect Greg to wait until
> 2.6.17 gets released before pushing it upstream, but I don't see it in
> his git tree..
>
> Greg, where are you hiding it? ;)
Unless Jean sent it to me, I'm not taking i2c patches, as he is the
maintainer and I am merely the conduit to Linus and Andrew.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (2 preceding siblings ...)
2006-05-18 20:37 ` Greg KH
@ 2006-05-19 5:00 ` Peter Korsgaard
2006-05-20 6:05 ` Peter Korsgaard
` (6 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-05-19 5:00 UTC (permalink / raw)
To: lm-sensors
>>>>> "Greg" = Greg KH <greg at kroah.com> writes:
Hi,
Greg> Unless Jean sent it to me, I'm not taking i2c patches, as he is the
Greg> maintainer and I am merely the conduit to Linus and Andrew.
Ok, sorry about that - I just saw you were in the To: and Jean just
CC'ed so I assumed you took it.
Jean, did you take the patch?
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (3 preceding siblings ...)
2006-05-19 5:00 ` Peter Korsgaard
@ 2006-05-20 6:05 ` Peter Korsgaard
2006-05-20 8:59 ` Jean Delvare
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-05-20 6:05 UTC (permalink / raw)
To: lm-sensors
>>>>> "Jean" = Jean Delvare <khali at linux-fr.org> writes:
Hi,
Jean> No, I didn't. I was waiting for it to be reviewed (thanks Rudolf!) and
Jean> updated accordingly. If you have something ready now, please send the
Jean> updated patch here and I'll take it.
OK, I'll send an updated patch later today..
Jean> If you are using quilt, please add "QUILT_NO_DIFF_INDEX=1" to your
Jean> ~/.quiltrc file, this is how Linus wants the patches.
Noted.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (4 preceding siblings ...)
2006-05-20 6:05 ` Peter Korsgaard
@ 2006-05-20 8:59 ` Jean Delvare
2006-05-20 16:56 ` Peter Korsgaard
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jean Delvare @ 2006-05-20 8:59 UTC (permalink / raw)
To: lm-sensors
Hi Peter,
Greg> Unless Jean sent it to me, I'm not taking i2c patches, as he is the
Greg> maintainer and I am merely the conduit to Linus and Andrew.
Peter> Ok, sorry about that - I just saw you were in the To: and Jean just
Peter> CC'ed so I assumed you took it.
Peter>
Peter> Jean, did you take the patch?
No, I didn't. I was waiting for it to be reviewed (thanks Rudolf!) and
updated accordingly. If you have something ready now, please send the
updated patch here and I'll take it.
Remember that we enjoy having documentation for i2c bus drivers under
Documentation/i2c/busses.
If you are using quilt, please add "QUILT_NO_DIFF_INDEX=1" to your
~/.quiltrc file, this is how Linus wants the patches.
Thanks,
--
Jean Delvare
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (5 preceding siblings ...)
2006-05-20 8:59 ` Jean Delvare
@ 2006-05-20 16:56 ` Peter Korsgaard
2006-05-27 15:52 ` Peter Korsgaard
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-05-20 16:56 UTC (permalink / raw)
To: lm-sensors
>>>>> "Peter" = Peter Korsgaard <jacmet at sunsite.dk> writes:
Jean> No, I didn't. I was waiting for it to be reviewed (thanks Rudolf!) and
Jean> updated accordingly. If you have something ready now, please send the
Jean> updated patch here and I'll take it.
Peter> OK, I'll send an updated patch later today..
And here it is - Changes since last time:
- Minor cleanups from Andrew Morton (2.6.17-rc3-mm1)
- Better handling of reserved bits as suggested by Rudolf Marek
- Documentation
The following patch adds support for the OpenCores I2C controller IP
core (See http://www.opencores.org/projects.cgi/web/i2c/overview).
Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
Signed-off-by: Andrew Morton <akpm at osdl.org>
---
Documentation/i2c/busses/i2c-ocores | 50 +++++
drivers/i2c/busses/Kconfig | 11 +
drivers/i2c/busses/Makefile | 1
drivers/i2c/busses/i2c-ocores.c | 344 ++++++++++++++++++++++++++++++++++++
include/linux/i2c-ocores.h | 19 +
5 files changed, 425 insertions(+)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/drivers/i2c/busses/i2c-ocores.c 2006-05-20 21:47:12.000000000 +0200
@@ -0,0 +1,344 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
+ *
+ * Peter Korsgaard <jacmet at sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-ocores.h>
+
+struct ocores_i2c {
+ void __iomem *base;
+ int regstep;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+};
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4
+#define OCI2C_STATUS 4
+
+#define OCI2C_CTRL_IEN 0x40
+#define OCI2C_CTRL_EN 0x80
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_IF 0x01
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_NACK 0x80
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg * i2c->regstep);
+}
+
+static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg * i2c->regstep);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if ((i2c->state = STATE_DONE) || (i2c->state = STATE_ERROR)) {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up(&i2c->wait);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if ((i2c->state = STATE_START) || (i2c->state = STATE_WRITE)) {
+ i2c->state + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ } else
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+ /* end of msg? */
+ if (i2c->pos = msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) { /* end? */
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ u8 addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ } else
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ } else {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state = STATE_READ) {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos = (msg->len-1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ } else {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ocores_i2c *i2c = dev_id;
+
+ ocores_process(i2c);
+
+ return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA,
+ (i2c->msg->addr << 1) |
+ ((i2c->msg->flags & I2C_M_RD) ? 1:0));
+
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state = STATE_ERROR) ||
+ (i2c->state = STATE_DONE), HZ))
+ return (i2c->state = STATE_DONE) ? num : -EIO;
+ else
+ return -ETIMEDOUT;
+}
+
+static void ocores_init(struct ocores_i2c *i2c,
+ struct ocores_i2c_platform_data *pdata)
+{
+ int prescale;
+ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ prescale = (pdata->clock_khz / (5*100)) - 1;
+ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+};
+
+static struct i2c_adapter ocores_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ocores",
+ .class = I2C_CLASS_HWMON,
+ .algo = &ocores_algorithm,
+ .timeout = 2,
+ .retries = 1
+};
+
+
+static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+{
+ struct ocores_i2c *i2c;
+ struct ocores_i2c_platform_data *pdata;
+ struct resource *res, *res2;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+
+ i2c->base = ioremap(res->start, res->end - res->start + 1);
+ if (!i2c->base) {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ i2c->regstep = pdata->regstep;
+ ocores_init(i2c, pdata);
+
+ init_waitqueue_head(&i2c->wait);
+ ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = ocores_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ goto add_adapter_failed;
+ }
+
+ return 0;
+
+ add_adapter_failed:
+ free_irq(res2->start, i2c);
+ request_irq_failed:
+ iounmap(i2c->base);
+ map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+ kfree(i2c);
+
+ return ret;
+}
+
+static int __devexit ocores_i2c_remove(struct platform_device* pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /* disable i2c logic */
+ oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
+ & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, i2c);
+
+ iounmap(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(i2c);
+
+ return 0;
+}
+
+static struct platform_driver ocores_i2c_driver = {
+ .probe = ocores_i2c_probe,
+ .remove = ocores_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ocores-i2c",
+ },
+};
+
+static int __init ocores_i2c_init(void)
+{
+ return platform_driver_register(&ocores_i2c_driver);
+}
+
+static void __exit ocores_i2c_exit(void)
+{
+ platform_driver_unregister(&ocores_i2c_driver);
+}
+
+module_init(ocores_i2c_init);
+module_exit(ocores_i2c_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet at sunsite.dk>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
--- linux.orig/drivers/i2c/busses/Kconfig 2006-05-20 15:42:00.000000000 +0200
+++ linux/drivers/i2c/busses/Kconfig 2006-05-20 21:56:52.000000000 +0200
@@ -273,6 +273,17 @@
This driver can also be built as a module. If so, the module
will be called i2c-nforce2.
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on I2C
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
config I2C_PARPORT
tristate "Parallel port adapter"
depends on I2C && PARPORT
--- linux.orig/drivers/i2c/busses/Makefile 2006-05-20 15:42:00.000000000 +0200
+++ linux/drivers/i2c/busses/Makefile 2006-05-20 21:56:52.000000000 +0200
@@ -23,6 +23,7 @@
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/i2c-ocores.h 2006-05-20 15:42:23.000000000 +0200
@@ -0,0 +1,19 @@
+/*
+ * i2c-ocores.h - definitions for the i2c-ocores interface
+ *
+ * Peter Korsgaard <jacmet at sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _LINUX_I2C_OCORES_H
+#define _LINUX_I2C_OCORES_H
+
+struct ocores_i2c_platform_data {
+ u32 regstep; /* distance between registers */
+ u32 clock_khz; /* input clock in KHz */
+};
+
+#endif /* _LINUX_I2C_OCORES_H */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/Documentation/i2c/busses/i2c-ocores 2006-05-20 21:56:04.000000000 +0200
@@ -0,0 +1,50 @@
+Kernel driver i2c-ocores
+
+Supported adapters:
+ * OpenCores.org I2C controller by Richard Herveille (see datasheet link)
+ Datasheet: http://www.opencores.org/projects.cgi/web/i2c/overview
+
+Author: Peter Korsgaard <jacmet at sunsite.dk>
+
+Description
+-----------
+
+i2c-ocores is an i2c bus driver for the OpenCores.org I2C controller
+IP core by Richard Herveille.
+
+Usage
+-----
+
+i2c-ocores uses the platform bus, so you need to provide a struct
+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.
+
+E.G. something like:
+
+static struct resource ocores_resources[] = {
+ [0] = {
+ .start = MYI2C_BASEADDR,
+ .end = MYI2C_BASEADDR + 8,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MYI2C_IRQ,
+ .end = MYI2C_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct ocores_i2c_platform_data myi2c_data = {
+ .regstep = 2, /* two bytes between registers */
+ .clock_khz = 50000, /* input clock of 50MHz */
+};
+
+static struct platform_device myi2c = {
+ .name = "ocores-i2c",
+ .id = 0,
+ .dev.platform_data = &myi2c_data,
+ .num_resources = ARRAY_SIZE(ocores_resources),
+ .resource = ocores_resources,
+};
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (6 preceding siblings ...)
2006-05-20 16:56 ` Peter Korsgaard
@ 2006-05-27 15:52 ` Peter Korsgaard
2006-06-04 15:00 ` Jean Delvare
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-05-27 15:52 UTC (permalink / raw)
To: lm-sensors
>>>>> "Peter" = Peter Korsgaard <jacmet at sunsite.dk> writes:
Peter> And here it is - Changes since last time:
Peter> - Minor cleanups from Andrew Morton (2.6.17-rc3-mm1)
Peter> - Better handling of reserved bits as suggested by Rudolf Marek
Peter> - Documentation
Comments?
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (7 preceding siblings ...)
2006-05-27 15:52 ` Peter Korsgaard
@ 2006-06-04 15:00 ` Jean Delvare
2006-06-06 13:49 ` Peter Korsgaard
2006-06-06 17:28 ` Jean Delvare
10 siblings, 0 replies; 15+ messages in thread
From: Jean Delvare @ 2006-06-04 15:00 UTC (permalink / raw)
To: lm-sensors
Hi Peter,
> >>>>> "Peter" = Peter Korsgaard <jacmet at sunsite.dk> writes:
>
> Peter> And here it is - Changes since last time:
>
> Peter> - Minor cleanups from Andrew Morton (2.6.17-rc3-mm1)
> Peter> - Better handling of reserved bits as suggested by Rudolf Marek
> Peter> - Documentation
>
> Comments?
Sorry for the long delay. I finally took some time to (briefly) review
your code. It looks OK overall, and I've applied it with the following
changes I hope you'll approve:
* Reorder includes, asm/* must come after linux/*.
* Tag ocores_i2c_driver.remove __devexit_p().
* Tag the driver EXPERIMENTAL for now. You can send a patch later to
remove that tag once it has spent some times in Linus' tree and is
believed to be completely safe and operational.
* In the documentation, replace the .dev.platform_data construct in struct
initialization, as I seem to remember not all compilers accept it.
Also don't initialize .id to 0 as this is the default for a static
struct.
* A few coding style adjustments.
I also have a few comments about things which looked suspicious to me,
but which I didn't dare to change:
> /* registers */
> #define OCI2C_PRELOW 0
> #define OCI2C_PREHIGH 1
> #define OCI2C_CONTROL 2
> #define OCI2C_DATA 3
> #define OCI2C_CMD 4
> #define OCI2C_STATUS 4
Two registers with the same number? If it's true this deserves a
comment, methinks.
> static struct i2c_adapter ocores_adapter = {
> .owner = THIS_MODULE,
> .name = "i2c-ocores",
> .class = I2C_CLASS_HWMON,
> .algo = &ocores_algorithm,
> .timeout = 2,
> .retries = 1,
> };
Why define .timeout and .retries if you don't use them in your driver?
If you want to change that (or anything else for that matter) please
send an incremental patch. The patch as I applied it for now is
(temporarily) available here:
http://khali.linux-fr.org/devel/i2c/linux-2.6/i2c-opencores-new-driver.patch
Last, I would like you to become the maintainer for this new driver if
you feel like it. If you accept, please send a patch to MAINTAINERS and
I'll apply it.
Thanks,
--
Jean Delvare
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (8 preceding siblings ...)
2006-06-04 15:00 ` Jean Delvare
@ 2006-06-06 13:49 ` Peter Korsgaard
2006-06-06 17:28 ` Jean Delvare
10 siblings, 0 replies; 15+ messages in thread
From: Peter Korsgaard @ 2006-06-06 13:49 UTC (permalink / raw)
To: lm-sensors
>>>>> "Jean" = Jean Delvare <khali at linux-fr.org> writes:
Jean> Hi Peter,
>> >>>>> "Peter" = Peter Korsgaard <jacmet at sunsite.dk> writes:
>>
Peter> And here it is - Changes since last time:
>>
Peter> - Minor cleanups from Andrew Morton (2.6.17-rc3-mm1)
Peter> - Better handling of reserved bits as suggested by Rudolf Marek
Peter> - Documentation
>>
>> Comments?
Jean> Sorry for the long delay. I finally took some time to (briefly) review
Jean> your code. It looks OK overall, and I've applied it with the following
Jean> changes I hope you'll approve:
No problem - Thanks for the review. Your changes looks fine to me.
>> #define OCI2C_CMD 4
>> #define OCI2C_STATUS 4
Jean> Two registers with the same number? If it's true this deserves a
Jean> comment, methinks.
Yes, comment added in patch below.
>> static struct i2c_adapter ocores_adapter = {
>> .owner = THIS_MODULE,
>> .name = "i2c-ocores",
>> .class = I2C_CLASS_HWMON,
>> .algo = &ocores_algorithm,
>> .timeout = 2,
>> .retries = 1,
>> };
Jean> Why define .timeout and .retries if you don't use them in your driver?
Sorry, I guess that was a case of too much cut'n'paste - fixed below.
Jean> Last, I would like you to become the maintainer for this new driver if
Jean> you feel like it. If you accept, please send a patch to MAINTAINERS and
Jean> I'll apply it.
Added below.
Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
---
MAINTAINERS | 6 ++++++
drivers/i2c/busses/i2c-ocores.c | 6 ++----
2 files changed, 8 insertions(+), 4 deletions(-)
--- linux.orig/MAINTAINERS 2006-06-06 16:59:27.000000000 +0200
+++ linux/MAINTAINERS 2006-06-06 17:05:19.000000000 +0200
@@ -2045,6 +2045,12 @@
L: linux-fbdev-devel at lists.sourceforge.net
S: Maintained
+OPENCORES I2C BUS DRIVER
+P: Peter Korsgaard
+M: jacmet at sunsite.dk
+L: lm-sensors at lm-sensors.org
+S: Maintained
+
ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
P: Mark Fasheh
M: mark.fasheh at oracle.com
--- linux.orig/drivers/i2c/busses/i2c-ocores.c 2006-06-06 16:59:19.000000000 +0200
+++ linux/drivers/i2c/busses/i2c-ocores.c 2006-06-06 17:02:18.000000000 +0200
@@ -38,8 +38,8 @@
#define OCI2C_PREHIGH 1
#define OCI2C_CONTROL 2
#define OCI2C_DATA 3
-#define OCI2C_CMD 4
-#define OCI2C_STATUS 4
+#define OCI2C_CMD 4 /* write only */
+#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
#define OCI2C_CTRL_IEN 0x40
#define OCI2C_CTRL_EN 0x80
@@ -209,8 +209,6 @@
.name = "i2c-ocores",
.class = I2C_CLASS_HWMON,
.algo = &ocores_algorithm,
- .timeout = 2,
- .retries = 1,
};
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [lm-sensors] [PATCH] OpenCores I2C bus driver
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
` (9 preceding siblings ...)
2006-06-06 13:49 ` Peter Korsgaard
@ 2006-06-06 17:28 ` Jean Delvare
10 siblings, 0 replies; 15+ messages in thread
From: Jean Delvare @ 2006-06-06 17:28 UTC (permalink / raw)
To: lm-sensors
Hi Peter,
> > > #define OCI2C_CMD 4
> > > #define OCI2C_STATUS 4
>
> Jean> Two registers with the same number? If it's true this deserves a
> Jean> comment, methinks.
>
> Yes, comment added in patch below.
>
> >> static struct i2c_adapter ocores_adapter = {
> >> .owner = THIS_MODULE,
> >> .name = "i2c-ocores",
> >> .class = I2C_CLASS_HWMON,
> >> .algo = &ocores_algorithm,
> >> .timeout = 2,
> >> .retries = 1,
> >> };
>
> Jean> Why define .timeout and .retries if you don't use them in your driver?
>
> Sorry, I guess that was a case of too much cut'n'paste - fixed below.
>
> Jean> Last, I would like you to become the maintainer for this new driver if
> Jean> you feel like it. If you accept, please send a patch to MAINTAINERS and
> Jean> I'll apply it.
>
> Added below.
>
> Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
> ---
> MAINTAINERS | 6 ++++++
> drivers/i2c/busses/i2c-ocores.c | 6 ++----
> 2 files changed, 8 insertions(+), 4 deletions(-)
Applied, thanks.
--
Jean Delvare
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2006-06-06 17:28 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-21 9:05 [PATCH] OpenCores I2C bus driver Peter Korsgaard
2006-04-21 21:19 ` [lm-sensors] " Jeff Garzik
2006-04-21 21:19 ` Jeff Garzik
-- strict thread matches above, loose matches on Subject: below --
2006-04-21 12:34 [lm-sensors] " Peter Korsgaard
2006-05-14 9:09 ` Rudolf Marek
2006-05-18 17:18 ` Peter Korsgaard
2006-05-18 20:37 ` Greg KH
2006-05-19 5:00 ` Peter Korsgaard
2006-05-20 6:05 ` Peter Korsgaard
2006-05-20 8:59 ` Jean Delvare
2006-05-20 16:56 ` Peter Korsgaard
2006-05-27 15:52 ` Peter Korsgaard
2006-06-04 15:00 ` Jean Delvare
2006-06-06 13:49 ` Peter Korsgaard
2006-06-06 17:28 ` Jean Delvare
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.