From: greg@kroah.com (Greg KH)
To: linux-kernel@vger.kernel.org, sensors@stimpy.netroedge.com
Subject: [PATCH] i2c driver fixes for 2.6.0-test5
Date: Thu, 19 May 2005 06:24:18 +0000 [thread overview]
Message-ID: <10642734272108@kroah.com> (raw)
In-Reply-To: <10642734271040@kroah.com>
In-Reply-To: <1064273416272@kroah.com>
ChangeSet 1.1315.1.23, 2003/09/22 14:21:09-07:00, greg@kroah.com
[PATCH] I2C: move the scx200* drivers to drivers/i2c/busses
drivers/i2c/scx200_acb.c | 553 ----------------------------------------
drivers/i2c/scx200_i2c.c | 133 ---------
drivers/i2c/Kconfig | 38 --
drivers/i2c/Makefile | 2
drivers/i2c/busses/Kconfig | 38 ++
drivers/i2c/busses/Makefile | 2
drivers/i2c/busses/scx200_acb.c | 553 ++++++++++++++++++++++++++++++++++++++++
drivers/i2c/busses/scx200_i2c.c | 132 +++++++++
8 files changed, 725 insertions(+), 726 deletions(-)
diff -Nru a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
--- a/drivers/i2c/Kconfig Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/Kconfig Mon Sep 22 16:12:15 2003
@@ -48,44 +48,6 @@
This support is also available as a module. If so, the module
will be called i2c-algo-bit.
-config SCx200_I2C
- tristate "NatSemi SCx200 I2C using GPIO pins"
- depends on SCx200 && I2C_ALGOBIT
- help
- Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
-
- If you don't know what to do here, say N.
-
- This support is also available as a module. If so, the module
- will be called scx200_i2c.
-
-config SCx200_I2C_SCL
- int "GPIO pin used for SCL"
- depends on SCx200_I2C
- default "12"
- help
- Enter the GPIO pin number used for the SCL signal. This value can
- also be specified with a module parameter.
-
-config SCx200_I2C_SDA
- int "GPIO pin used for SDA"
- depends on SCx200_I2C
- default "13"
- help
- Enter the GPIO pin number used for the SSA signal. This value can
- also be specified with a module parameter.
-
-config SCx200_ACB
- tristate "NatSemi SCx200 ACCESS.bus"
- depends on I2C_ALGOBIT!=n && I2C
- help
- Enable the use of the ACCESS.bus controllers of a SCx200 processor.
-
- If you don't know what to do here, say N.
-
- This support is also available as a module. If so, the module
- will be called scx200_acb.
-
config I2C_ALGOPCF
tristate "I2C PCF 8584 interfaces"
depends on I2C
diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile
--- a/drivers/i2c/Makefile Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/Makefile Mon Sep 22 16:12:15 2003
@@ -9,8 +9,6 @@
obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o
obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o
obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o
-obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
-obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/busses/Kconfig Mon Sep 22 16:12:15 2003
@@ -166,6 +166,44 @@
This driver can also be built as a module. If so, the module
will be called i2c-savage4.
+config SCx200_I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins"
+ depends on SCx200 && I2C_ALGOBIT
+ help
+ Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_i2c.
+
+config SCx200_I2C_SCL
+ int "GPIO pin used for SCL"
+ depends on SCx200_I2C
+ default "12"
+ help
+ Enter the GPIO pin number used for the SCL signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_I2C_SDA
+ int "GPIO pin used for SDA"
+ depends on SCx200_I2C
+ default "13"
+ help
+ Enter the GPIO pin number used for the SSA signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_ACB
+ tristate "NatSemi SCx200 ACCESS.bus"
+ depends on I2C_ALGOBIT!=n && I2C
+ help
+ Enable the use of the ACCESS.bus controllers of a SCx200 processor.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_acb.
+
config I2C_SIS5595
tristate "SiS 5595"
depends on I2C && PCI && EXPERIMENTAL
diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
--- a/drivers/i2c/busses/Makefile Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/busses/Makefile Mon Sep 22 16:12:15 2003
@@ -23,3 +23,5 @@
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
diff -Nru a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/busses/scx200_acb.c Mon Sep 22 16:12:15 2003
@@ -0,0 +1,553 @@
+/* linux/drivers/i2c/scx200_acb.c
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 ACCESS.bus support
+
+ Based on i2c-keywest.c which is:
+ Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ 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, or (at your option) any later version.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+ implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+ state_idle,
+ state_address,
+ state_command,
+ state_repeat_start,
+ state_quick,
+ state_read,
+ state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+ "idle",
+ "address",
+ "command",
+ "repeat_start",
+ "quick",
+ "read",
+ "write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+ struct scx200_acb_iface *next;
+ struct i2c_adapter adapter;
+ unsigned base;
+ struct semaphore sem;
+
+ /* State machine data */
+ enum scx200_acb_state state;
+ int result;
+ u8 address_byte;
+ u8 command;
+ u8 *ptr;
+ char needs_reset;
+ unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA (iface->base + 0)
+#define ACBST (iface->base + 1)
+#define ACBST_SDAST 0x40 /* SDA Status */
+#define ACBST_BER 0x20
+#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
+#define ACBST_STASTR 0x08 /* Stall After Start */
+#define ACBST_MASTER 0x02
+#define ACBCST (iface->base + 2)
+#define ACBCST_BB 0x02
+#define ACBCTL1 (iface->base + 3)
+#define ACBCTL1_STASTRE 0x80
+#define ACBCTL1_NMINTE 0x40
+#define ACBCTL1_ACK 0x10
+#define ACBCTL1_STOP 0x02
+#define ACBCTL1_START 0x01
+#define ACBADDR (iface->base + 4)
+#define ACBCTL2 (iface->base + 5)
+#define ACBCTL2_ENABLE 0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+ const char *errmsg;
+
+ DBG("state %s, status = 0x%02x\n",
+ scx200_acb_state_name[iface->state], status);
+
+ if (status & ACBST_BER) {
+ errmsg = "bus error";
+ goto error;
+ }
+ if (!(status & ACBST_MASTER)) {
+ errmsg = "not master";
+ goto error;
+ }
+ if (status & ACBST_NEGACK)
+ goto negack;
+
+ switch (iface->state) {
+ case state_idle:
+ dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
+ break;
+
+ case state_address:
+ /* Do a pointer write first */
+ outb(iface->address_byte & ~1, ACBSDA);
+
+ iface->state = state_command;
+ break;
+
+ case state_command:
+ outb(iface->command, ACBSDA);
+
+ if (iface->address_byte & 1)
+ iface->state = state_repeat_start;
+ else
+ iface->state = state_write;
+ break;
+
+ case state_repeat_start:
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+ /* fallthrough */
+
+ case state_quick:
+ if (iface->address_byte & 1) {
+ if (iface->len = 1)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_read;
+ } else {
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_write;
+ }
+ break;
+
+ case state_read:
+ /* Set ACK if receiving the last byte */
+ if (iface->len = 1)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+ *iface->ptr++ = inb(ACBSDA);
+ --iface->len;
+
+ if (iface->len = 0) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ }
+
+ break;
+
+ case state_write:
+ if (iface->len = 0) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ break;
+ }
+
+ outb(*iface->ptr++, ACBSDA);
+ --iface->len;
+
+ break;
+ }
+
+ return;
+
+ negack:
+ DBG("negative acknowledge in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -ENXIO;
+
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+ return;
+
+ error:
+ dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg,
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface)
+{
+ dev_err(&iface->adapter.dev, "timeout in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+ u8 status = 0;
+ unsigned long timeout;
+
+ timeout = jiffies + POLL_TIMEOUT;
+ while (time_before(jiffies, timeout)) {
+ status = inb(ACBST);
+ if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+ scx200_acb_machine(iface, status);
+ return;
+ }
+ schedule_timeout(HZ/100+1);
+ }
+
+ scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+ /* Polling mode */
+ outb(0, ACBCTL1);
+ /* Disable slave address */
+ outb(0, ACBADDR);
+ /* Enable the ACCESS.bus device */
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+ /* Free STALL after START */
+ outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+ /* Send a STOP */
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ /* Clear BER, NEGACK and STASTR bits */
+ outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+ /* Clear BB bit */
+ outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+ u16 address, unsigned short flags,
+ char rw, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
+ int len;
+ u8 *buffer;
+ u16 cur_word;
+ int rc;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ len = 0;
+ buffer = NULL;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (rw = I2C_SMBUS_READ) {
+ len = 1;
+ buffer = &data->byte;
+ } else {
+ len = 1;
+ buffer = &command;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ len = 1;
+ buffer = &data->byte;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ len = 2;
+ cur_word = cpu_to_le16(data->word);
+ buffer = (u8 *)&cur_word;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ len = data->block[0];
+ buffer = &data->block[1];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+ size, address, command, len, rw = I2C_SMBUS_READ);
+
+ if (!len && rw = I2C_SMBUS_READ) {
+ dev_warn(&adapter->dev, "zero length read\n");
+ return -EINVAL;
+ }
+
+ if (len && !buffer) {
+ dev_warn(&adapter->dev, "nonzero length but no buffer\n");
+ return -EFAULT;
+ }
+
+ down(&iface->sem);
+
+ iface->address_byte = address<<1;
+ if (rw = I2C_SMBUS_READ)
+ iface->address_byte |= 1;
+ iface->command = command;
+ iface->ptr = buffer;
+ iface->len = len;
+ iface->result = -EINVAL;
+ iface->needs_reset = 0;
+
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+ if (size = I2C_SMBUS_QUICK || size = I2C_SMBUS_BYTE)
+ iface->state = state_quick;
+ else
+ iface->state = state_address;
+
+#ifdef POLLED_MODE
+ while (iface->state != state_idle)
+ scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */
+
+ if (iface->needs_reset)
+ scx200_acb_reset(iface);
+
+ rc = iface->result;
+
+ up(&iface->sem);
+
+ if (rc = 0 && size = I2C_SMBUS_WORD_DATA && rw = I2C_SMBUS_READ)
+ data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+ printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+ if (buffer) {
+ int i;
+ printk(" data:");
+ for (i = 0; i < len; ++i)
+ printk(" %02x", buffer[i]);
+ }
+ printk("\n");
+#endif
+
+ return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+ .name = "NatSemi SCx200 ACCESS.bus",
+ .id = I2C_ALGO_SMBUS,
+ .smbus_xfer = scx200_acb_smbus_xfer,
+ .functionality = scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+ u8 val;
+
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+
+ if (inb(ACBCTL2) != 0x70) {
+ DBG("ACBCTL2 readback failed\n");
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if (val) {
+ DBG("disabled, but ACBCTL1=0x%02x\n", val);
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+ DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int __init scx200_acb_create(int base, int index)
+{
+ struct scx200_acb_iface *iface;
+ struct i2c_adapter *adapter;
+ int rc = 0;
+ char description[64];
+
+ iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ if (!iface) {
+ printk(KERN_ERR NAME ": can't allocate memory\n");
+ rc = -ENOMEM;
+ goto errout;
+ }
+
+ memset(iface, 0, sizeof(*iface));
+ adapter = &iface->adapter;
+ i2c_set_adapdata(adapter, iface);
+ snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
+ adapter->owner = THIS_MODULE;
+ adapter->id = I2C_ALGO_SMBUS;
+ adapter->algo = &scx200_acb_algorithm;
+
+ init_MUTEX(&iface->sem);
+
+ snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+ if (request_region(base, 8, description) = 0) {
+ dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n",
+ base, base + 8-1);
+ rc = -EBUSY;
+ goto errout;
+ }
+ iface->base = base;
+
+ rc = scx200_acb_probe(iface);
+ if (rc) {
+ dev_warn(&adapter->dev, "probe failed\n");
+ goto errout;
+ }
+
+ scx200_acb_reset(iface);
+
+ if (i2c_add_adapter(adapter) < 0) {
+ dev_err(&adapter->dev, "failed to register\n");
+ rc = -ENODEV;
+ goto errout;
+ }
+
+ lock_kernel();
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ unlock_kernel();
+
+ return 0;
+
+ errout:
+ if (iface) {
+ if (iface->base)
+ release_region(iface->base, 8);
+ kfree(iface);
+ }
+ return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+ int i;
+ int rc;
+
+ printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+ /* Verify that this really is a SCx200 processor */
+ if (pci_find_device(PCI_VENDOR_ID_NS,
+ PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+ NULL) = NULL)
+ return -ENODEV;
+
+ rc = -ENXIO;
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] > 0)
+ rc = scx200_acb_create(base[i], i);
+ }
+ if (scx200_acb_list)
+ return 0;
+ return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+ struct scx200_acb_iface *iface;
+ lock_kernel();
+ while ((iface = scx200_acb_list) != NULL) {
+ scx200_acb_list = iface->next;
+ unlock_kernel();
+
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+ lock_kernel();
+ }
+ unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+ Local variables:
+ compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+ c-basic-offset: 8
+ End:
+*/
+
diff -Nru a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/busses/scx200_i2c.c Mon Sep 22 16:12:15 2003
@@ -0,0 +1,132 @@
+/* linux/drivers/i2c/scx200_i2c.c
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 I2C bus on GPIO pins
+
+ Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+ 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, or
+ (at your option) any later version.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+ scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+ scx200_gpio_set(sda, state);
+}
+
+static int scx200_i2c_getscl(void *data)
+{
+ return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+ return scx200_gpio_get(sda);
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+ NULL,
+ scx200_i2c_setsda,
+ scx200_i2c_setscl,
+ scx200_i2c_getsda,
+ scx200_i2c_getscl,
+ 10, 10, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+ .owner = THIS_MODULE,
+ .algo_data = &scx200_i2c_data,
+ .name = "NatSemi SCx200 I2C",
+};
+
+int scx200_i2c_init(void)
+{
+ printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+ if (!scx200_gpio_present()) {
+ printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n",
+ scl, sda);
+
+ if (scl = -1 || sda = -1 || scl = sda) {
+ printk(KERN_ERR NAME ": scl and sda must be specified\n");
+ return -EINVAL;
+ }
+
+ /* Configure GPIOs as open collector outputs */
+ scx200_gpio_configure(scl, ~2, 5);
+ scx200_gpio_configure(sda, ~2, 5);
+
+ if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+ printk(KERN_ERR NAME ": adapter %s registration failed\n",
+ scx200_i2c_ops.name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+ i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+ Local variables:
+ compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+ c-basic-offset: 8
+ End:
+*/
diff -Nru a/drivers/i2c/scx200_acb.c b/drivers/i2c/scx200_acb.c
--- a/drivers/i2c/scx200_acb.c Mon Sep 22 16:12:15 2003
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,553 +0,0 @@
-/* linux/drivers/i2c/scx200_acb.c
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- National Semiconductor SCx200 ACCESS.bus support
-
- Based on i2c-keywest.c which is:
- Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
- 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, or (at your option) any later version.
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/smp_lock.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include <linux/scx200.h>
-
-#define NAME "scx200_acb"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
-MODULE_LICENSE("GPL");
-
-#define MAX_DEVICES 4
-static int base[MAX_DEVICES] = { 0x840 };
-MODULE_PARM(base, "1-4i");
-MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
-
-#define DEBUG 0
-
-#if DEBUG
-#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
-#else
-#define DBG(x...)
-#endif
-
-/* The hardware supports interrupt driven mode too, but I haven't
- implemented that. */
-#define POLLED_MODE 1
-#define POLL_TIMEOUT (HZ)
-
-enum scx200_acb_state {
- state_idle,
- state_address,
- state_command,
- state_repeat_start,
- state_quick,
- state_read,
- state_write,
-};
-
-static const char *scx200_acb_state_name[] = {
- "idle",
- "address",
- "command",
- "repeat_start",
- "quick",
- "read",
- "write",
-};
-
-/* Physical interface */
-struct scx200_acb_iface
-{
- struct scx200_acb_iface *next;
- struct i2c_adapter adapter;
- unsigned base;
- struct semaphore sem;
-
- /* State machine data */
- enum scx200_acb_state state;
- int result;
- u8 address_byte;
- u8 command;
- u8 *ptr;
- char needs_reset;
- unsigned len;
-};
-
-/* Register Definitions */
-#define ACBSDA (iface->base + 0)
-#define ACBST (iface->base + 1)
-#define ACBST_SDAST 0x40 /* SDA Status */
-#define ACBST_BER 0x20
-#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
-#define ACBST_STASTR 0x08 /* Stall After Start */
-#define ACBST_MASTER 0x02
-#define ACBCST (iface->base + 2)
-#define ACBCST_BB 0x02
-#define ACBCTL1 (iface->base + 3)
-#define ACBCTL1_STASTRE 0x80
-#define ACBCTL1_NMINTE 0x40
-#define ACBCTL1_ACK 0x10
-#define ACBCTL1_STOP 0x02
-#define ACBCTL1_START 0x01
-#define ACBADDR (iface->base + 4)
-#define ACBCTL2 (iface->base + 5)
-#define ACBCTL2_ENABLE 0x01
-
-/************************************************************************/
-
-static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
-{
- const char *errmsg;
-
- DBG("state %s, status = 0x%02x\n",
- scx200_acb_state_name[iface->state], status);
-
- if (status & ACBST_BER) {
- errmsg = "bus error";
- goto error;
- }
- if (!(status & ACBST_MASTER)) {
- errmsg = "not master";
- goto error;
- }
- if (status & ACBST_NEGACK)
- goto negack;
-
- switch (iface->state) {
- case state_idle:
- dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
- break;
-
- case state_address:
- /* Do a pointer write first */
- outb(iface->address_byte & ~1, ACBSDA);
-
- iface->state = state_command;
- break;
-
- case state_command:
- outb(iface->command, ACBSDA);
-
- if (iface->address_byte & 1)
- iface->state = state_repeat_start;
- else
- iface->state = state_write;
- break;
-
- case state_repeat_start:
- outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
- /* fallthrough */
-
- case state_quick:
- if (iface->address_byte & 1) {
- if (iface->len = 1)
- outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
- else
- outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
- outb(iface->address_byte, ACBSDA);
-
- iface->state = state_read;
- } else {
- outb(iface->address_byte, ACBSDA);
-
- iface->state = state_write;
- }
- break;
-
- case state_read:
- /* Set ACK if receiving the last byte */
- if (iface->len = 1)
- outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
- else
- outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
-
- *iface->ptr++ = inb(ACBSDA);
- --iface->len;
-
- if (iface->len = 0) {
- iface->result = 0;
- iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- }
-
- break;
-
- case state_write:
- if (iface->len = 0) {
- iface->result = 0;
- iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- break;
- }
-
- outb(*iface->ptr++, ACBSDA);
- --iface->len;
-
- break;
- }
-
- return;
-
- negack:
- DBG("negative acknowledge in state %s\n",
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -ENXIO;
-
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
- return;
-
- error:
- dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg,
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -EIO;
- iface->needs_reset = 1;
-}
-
-static void scx200_acb_timeout(struct scx200_acb_iface *iface)
-{
- dev_err(&iface->adapter.dev, "timeout in state %s\n",
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -EIO;
- iface->needs_reset = 1;
-}
-
-#ifdef POLLED_MODE
-static void scx200_acb_poll(struct scx200_acb_iface *iface)
-{
- u8 status = 0;
- unsigned long timeout;
-
- timeout = jiffies + POLL_TIMEOUT;
- while (time_before(jiffies, timeout)) {
- status = inb(ACBST);
- if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
- scx200_acb_machine(iface, status);
- return;
- }
- schedule_timeout(HZ/100+1);
- }
-
- scx200_acb_timeout(iface);
-}
-#endif /* POLLED_MODE */
-
-static void scx200_acb_reset(struct scx200_acb_iface *iface)
-{
- /* Disable the ACCESS.bus device and Configure the SCL
- frequency: 16 clock cycles */
- outb(0x70, ACBCTL2);
- /* Polling mode */
- outb(0, ACBCTL1);
- /* Disable slave address */
- outb(0, ACBADDR);
- /* Enable the ACCESS.bus device */
- outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
- /* Free STALL after START */
- outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
- /* Send a STOP */
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- /* Clear BER, NEGACK and STASTR bits */
- outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
- /* Clear BB bit */
- outb(inb(ACBCST) | ACBCST_BB, ACBCST);
-}
-
-static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
- u16 address, unsigned short flags,
- char rw, u8 command, int size,
- union i2c_smbus_data *data)
-{
- struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
- int len;
- u8 *buffer;
- u16 cur_word;
- int rc;
-
- switch (size) {
- case I2C_SMBUS_QUICK:
- len = 0;
- buffer = NULL;
- break;
- case I2C_SMBUS_BYTE:
- if (rw = I2C_SMBUS_READ) {
- len = 1;
- buffer = &data->byte;
- } else {
- len = 1;
- buffer = &command;
- }
- break;
- case I2C_SMBUS_BYTE_DATA:
- len = 1;
- buffer = &data->byte;
- break;
- case I2C_SMBUS_WORD_DATA:
- len = 2;
- cur_word = cpu_to_le16(data->word);
- buffer = (u8 *)&cur_word;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- len = data->block[0];
- buffer = &data->block[1];
- break;
- default:
- return -EINVAL;
- }
-
- DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
- size, address, command, len, rw = I2C_SMBUS_READ);
-
- if (!len && rw = I2C_SMBUS_READ) {
- dev_warn(&adapter->dev, "zero length read\n");
- return -EINVAL;
- }
-
- if (len && !buffer) {
- dev_warn(&adapter->dev, "nonzero length but no buffer\n");
- return -EFAULT;
- }
-
- down(&iface->sem);
-
- iface->address_byte = address<<1;
- if (rw = I2C_SMBUS_READ)
- iface->address_byte |= 1;
- iface->command = command;
- iface->ptr = buffer;
- iface->len = len;
- iface->result = -EINVAL;
- iface->needs_reset = 0;
-
- outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
-
- if (size = I2C_SMBUS_QUICK || size = I2C_SMBUS_BYTE)
- iface->state = state_quick;
- else
- iface->state = state_address;
-
-#ifdef POLLED_MODE
- while (iface->state != state_idle)
- scx200_acb_poll(iface);
-#else /* POLLED_MODE */
-#error Interrupt driven mode not implemented
-#endif /* POLLED_MODE */
-
- if (iface->needs_reset)
- scx200_acb_reset(iface);
-
- rc = iface->result;
-
- up(&iface->sem);
-
- if (rc = 0 && size = I2C_SMBUS_WORD_DATA && rw = I2C_SMBUS_READ)
- data->word = le16_to_cpu(cur_word);
-
-#if DEBUG
- printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
- if (buffer) {
- int i;
- printk(" data:");
- for (i = 0; i < len; ++i)
- printk(" %02x", buffer[i]);
- }
- printk("\n");
-#endif
-
- return rc;
-}
-
-static u32 scx200_acb_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm scx200_acb_algorithm = {
- .name = "NatSemi SCx200 ACCESS.bus",
- .id = I2C_ALGO_SMBUS,
- .smbus_xfer = scx200_acb_smbus_xfer,
- .functionality = scx200_acb_func,
-};
-
-struct scx200_acb_iface *scx200_acb_list;
-
-int scx200_acb_probe(struct scx200_acb_iface *iface)
-{
- u8 val;
-
- /* Disable the ACCESS.bus device and Configure the SCL
- frequency: 16 clock cycles */
- outb(0x70, ACBCTL2);
-
- if (inb(ACBCTL2) != 0x70) {
- DBG("ACBCTL2 readback failed\n");
- return -ENXIO;
- }
-
- outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
-
- val = inb(ACBCTL1);
- if (val) {
- DBG("disabled, but ACBCTL1=0x%02x\n", val);
- return -ENXIO;
- }
-
- outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
-
- outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
-
- val = inb(ACBCTL1);
- if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
- DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int __init scx200_acb_create(int base, int index)
-{
- struct scx200_acb_iface *iface;
- struct i2c_adapter *adapter;
- int rc = 0;
- char description[64];
-
- iface = kmalloc(sizeof(*iface), GFP_KERNEL);
- if (!iface) {
- printk(KERN_ERR NAME ": can't allocate memory\n");
- rc = -ENOMEM;
- goto errout;
- }
-
- memset(iface, 0, sizeof(*iface));
- adapter = &iface->adapter;
- i2c_set_adapdata(adapter, iface);
- snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
- adapter->owner = THIS_MODULE;
- adapter->id = I2C_ALGO_SMBUS;
- adapter->algo = &scx200_acb_algorithm;
-
- init_MUTEX(&iface->sem);
-
- snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
- if (request_region(base, 8, description) = 0) {
- dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n",
- base, base + 8-1);
- rc = -EBUSY;
- goto errout;
- }
- iface->base = base;
-
- rc = scx200_acb_probe(iface);
- if (rc) {
- dev_warn(&adapter->dev, "probe failed\n");
- goto errout;
- }
-
- scx200_acb_reset(iface);
-
- if (i2c_add_adapter(adapter) < 0) {
- dev_err(&adapter->dev, "failed to register\n");
- rc = -ENODEV;
- goto errout;
- }
-
- lock_kernel();
- iface->next = scx200_acb_list;
- scx200_acb_list = iface;
- unlock_kernel();
-
- return 0;
-
- errout:
- if (iface) {
- if (iface->base)
- release_region(iface->base, 8);
- kfree(iface);
- }
- return rc;
-}
-
-static int __init scx200_acb_init(void)
-{
- int i;
- int rc;
-
- printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
-
- /* Verify that this really is a SCx200 processor */
- if (pci_find_device(PCI_VENDOR_ID_NS,
- PCI_DEVICE_ID_NS_SCx200_BRIDGE,
- NULL) = NULL)
- return -ENODEV;
-
- rc = -ENXIO;
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] > 0)
- rc = scx200_acb_create(base[i], i);
- }
- if (scx200_acb_list)
- return 0;
- return rc;
-}
-
-static void __exit scx200_acb_cleanup(void)
-{
- struct scx200_acb_iface *iface;
- lock_kernel();
- while ((iface = scx200_acb_list) != NULL) {
- scx200_acb_list = iface->next;
- unlock_kernel();
-
- i2c_del_adapter(&iface->adapter);
- release_region(iface->base, 8);
- kfree(iface);
- lock_kernel();
- }
- unlock_kernel();
-}
-
-module_init(scx200_acb_init);
-module_exit(scx200_acb_cleanup);
-
-/*
- Local variables:
- compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
- c-basic-offset: 8
- End:
-*/
-
diff -Nru a/drivers/i2c/scx200_i2c.c b/drivers/i2c/scx200_i2c.c
--- a/drivers/i2c/scx200_i2c.c Mon Sep 22 16:12:15 2003
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,133 +0,0 @@
-/* linux/drivers/i2c/scx200_i2c.c
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- National Semiconductor SCx200 I2C bus on GPIO pins
-
- Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
-
- 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, or
- (at your option) any later version.
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-#include <linux/scx200_gpio.h>
-
-#define NAME "scx200_i2c"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(scl, "i");
-MODULE_PARM_DESC(scl, "GPIO line for SCL");
-MODULE_PARM(sda, "i");
-MODULE_PARM_DESC(sda, "GPIO line for SDA");
-
-static int scl = CONFIG_SCx200_I2C_SCL;
-static int sda = CONFIG_SCx200_I2C_SDA;
-
-static void scx200_i2c_setscl(void *data, int state)
-{
- scx200_gpio_set(scl, state);
-}
-
-static void scx200_i2c_setsda(void *data, int state)
-{
- scx200_gpio_set(sda, state);
-}
-
-static int scx200_i2c_getscl(void *data)
-{
- return scx200_gpio_get(scl);
-}
-
-static int scx200_i2c_getsda(void *data)
-{
- return scx200_gpio_get(sda);
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-
-static struct i2c_algo_bit_data scx200_i2c_data = {
- NULL,
- scx200_i2c_setsda,
- scx200_i2c_setscl,
- scx200_i2c_getsda,
- scx200_i2c_getscl,
- 10, 10, 100, /* waits, timeout */
-};
-
-static struct i2c_adapter scx200_i2c_ops = {
- .owner = THIS_MODULE,
- .id = I2C_HW_B_VELLE,
- .algo_data = &scx200_i2c_data,
- .name = "NatSemi SCx200 I2C",
-};
-
-int scx200_i2c_init(void)
-{
- printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
-
- if (!scx200_gpio_present()) {
- printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
- return -ENODEV;
- }
-
- printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n",
- scl, sda);
-
- if (scl = -1 || sda = -1 || scl = sda) {
- printk(KERN_ERR NAME ": scl and sda must be specified\n");
- return -EINVAL;
- }
-
- /* Configure GPIOs as open collector outputs */
- scx200_gpio_configure(scl, ~2, 5);
- scx200_gpio_configure(sda, ~2, 5);
-
- if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
- printk(KERN_ERR NAME ": adapter %s registration failed\n",
- scx200_i2c_ops.name);
- return -ENODEV;
- }
-
- return 0;
-}
-
-void scx200_i2c_cleanup(void)
-{
- i2c_bit_del_bus(&scx200_i2c_ops);
-}
-
-module_init(scx200_i2c_init);
-module_exit(scx200_i2c_cleanup);
-
-/*
- Local variables:
- compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
- c-basic-offset: 8
- End:
-*/
WARNING: multiple messages have this Message-ID (diff)
From: Greg KH <greg@kroah.com>
To: linux-kernel@vger.kernel.org, sensors@stimpy.netroedge.com
Subject: Re: [PATCH] i2c driver fixes for 2.6.0-test5
Date: Mon, 22 Sep 2003 16:30:27 -0700 [thread overview]
Message-ID: <10642734272108@kroah.com> (raw)
In-Reply-To: <10642734271040@kroah.com>
ChangeSet 1.1315.1.23, 2003/09/22 14:21:09-07:00, greg@kroah.com
[PATCH] I2C: move the scx200* drivers to drivers/i2c/busses
drivers/i2c/scx200_acb.c | 553 ----------------------------------------
drivers/i2c/scx200_i2c.c | 133 ---------
drivers/i2c/Kconfig | 38 --
drivers/i2c/Makefile | 2
drivers/i2c/busses/Kconfig | 38 ++
drivers/i2c/busses/Makefile | 2
drivers/i2c/busses/scx200_acb.c | 553 ++++++++++++++++++++++++++++++++++++++++
drivers/i2c/busses/scx200_i2c.c | 132 +++++++++
8 files changed, 725 insertions(+), 726 deletions(-)
diff -Nru a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
--- a/drivers/i2c/Kconfig Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/Kconfig Mon Sep 22 16:12:15 2003
@@ -48,44 +48,6 @@
This support is also available as a module. If so, the module
will be called i2c-algo-bit.
-config SCx200_I2C
- tristate "NatSemi SCx200 I2C using GPIO pins"
- depends on SCx200 && I2C_ALGOBIT
- help
- Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
-
- If you don't know what to do here, say N.
-
- This support is also available as a module. If so, the module
- will be called scx200_i2c.
-
-config SCx200_I2C_SCL
- int "GPIO pin used for SCL"
- depends on SCx200_I2C
- default "12"
- help
- Enter the GPIO pin number used for the SCL signal. This value can
- also be specified with a module parameter.
-
-config SCx200_I2C_SDA
- int "GPIO pin used for SDA"
- depends on SCx200_I2C
- default "13"
- help
- Enter the GPIO pin number used for the SSA signal. This value can
- also be specified with a module parameter.
-
-config SCx200_ACB
- tristate "NatSemi SCx200 ACCESS.bus"
- depends on I2C_ALGOBIT!=n && I2C
- help
- Enable the use of the ACCESS.bus controllers of a SCx200 processor.
-
- If you don't know what to do here, say N.
-
- This support is also available as a module. If so, the module
- will be called scx200_acb.
-
config I2C_ALGOPCF
tristate "I2C PCF 8584 interfaces"
depends on I2C
diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile
--- a/drivers/i2c/Makefile Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/Makefile Mon Sep 22 16:12:15 2003
@@ -9,8 +9,6 @@
obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o
obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o
obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o
-obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
-obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/busses/Kconfig Mon Sep 22 16:12:15 2003
@@ -166,6 +166,44 @@
This driver can also be built as a module. If so, the module
will be called i2c-savage4.
+config SCx200_I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins"
+ depends on SCx200 && I2C_ALGOBIT
+ help
+ Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_i2c.
+
+config SCx200_I2C_SCL
+ int "GPIO pin used for SCL"
+ depends on SCx200_I2C
+ default "12"
+ help
+ Enter the GPIO pin number used for the SCL signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_I2C_SDA
+ int "GPIO pin used for SDA"
+ depends on SCx200_I2C
+ default "13"
+ help
+ Enter the GPIO pin number used for the SSA signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_ACB
+ tristate "NatSemi SCx200 ACCESS.bus"
+ depends on I2C_ALGOBIT!=n && I2C
+ help
+ Enable the use of the ACCESS.bus controllers of a SCx200 processor.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_acb.
+
config I2C_SIS5595
tristate "SiS 5595"
depends on I2C && PCI && EXPERIMENTAL
diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
--- a/drivers/i2c/busses/Makefile Mon Sep 22 16:12:15 2003
+++ b/drivers/i2c/busses/Makefile Mon Sep 22 16:12:15 2003
@@ -23,3 +23,5 @@
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
diff -Nru a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/busses/scx200_acb.c Mon Sep 22 16:12:15 2003
@@ -0,0 +1,553 @@
+/* linux/drivers/i2c/scx200_acb.c
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 ACCESS.bus support
+
+ Based on i2c-keywest.c which is:
+ Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ 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, or (at your option) any later version.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+ implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+ state_idle,
+ state_address,
+ state_command,
+ state_repeat_start,
+ state_quick,
+ state_read,
+ state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+ "idle",
+ "address",
+ "command",
+ "repeat_start",
+ "quick",
+ "read",
+ "write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+ struct scx200_acb_iface *next;
+ struct i2c_adapter adapter;
+ unsigned base;
+ struct semaphore sem;
+
+ /* State machine data */
+ enum scx200_acb_state state;
+ int result;
+ u8 address_byte;
+ u8 command;
+ u8 *ptr;
+ char needs_reset;
+ unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA (iface->base + 0)
+#define ACBST (iface->base + 1)
+#define ACBST_SDAST 0x40 /* SDA Status */
+#define ACBST_BER 0x20
+#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
+#define ACBST_STASTR 0x08 /* Stall After Start */
+#define ACBST_MASTER 0x02
+#define ACBCST (iface->base + 2)
+#define ACBCST_BB 0x02
+#define ACBCTL1 (iface->base + 3)
+#define ACBCTL1_STASTRE 0x80
+#define ACBCTL1_NMINTE 0x40
+#define ACBCTL1_ACK 0x10
+#define ACBCTL1_STOP 0x02
+#define ACBCTL1_START 0x01
+#define ACBADDR (iface->base + 4)
+#define ACBCTL2 (iface->base + 5)
+#define ACBCTL2_ENABLE 0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+ const char *errmsg;
+
+ DBG("state %s, status = 0x%02x\n",
+ scx200_acb_state_name[iface->state], status);
+
+ if (status & ACBST_BER) {
+ errmsg = "bus error";
+ goto error;
+ }
+ if (!(status & ACBST_MASTER)) {
+ errmsg = "not master";
+ goto error;
+ }
+ if (status & ACBST_NEGACK)
+ goto negack;
+
+ switch (iface->state) {
+ case state_idle:
+ dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
+ break;
+
+ case state_address:
+ /* Do a pointer write first */
+ outb(iface->address_byte & ~1, ACBSDA);
+
+ iface->state = state_command;
+ break;
+
+ case state_command:
+ outb(iface->command, ACBSDA);
+
+ if (iface->address_byte & 1)
+ iface->state = state_repeat_start;
+ else
+ iface->state = state_write;
+ break;
+
+ case state_repeat_start:
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+ /* fallthrough */
+
+ case state_quick:
+ if (iface->address_byte & 1) {
+ if (iface->len == 1)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_read;
+ } else {
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_write;
+ }
+ break;
+
+ case state_read:
+ /* Set ACK if receiving the last byte */
+ if (iface->len == 1)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+ *iface->ptr++ = inb(ACBSDA);
+ --iface->len;
+
+ if (iface->len == 0) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ }
+
+ break;
+
+ case state_write:
+ if (iface->len == 0) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ break;
+ }
+
+ outb(*iface->ptr++, ACBSDA);
+ --iface->len;
+
+ break;
+ }
+
+ return;
+
+ negack:
+ DBG("negative acknowledge in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -ENXIO;
+
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+ return;
+
+ error:
+ dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg,
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface)
+{
+ dev_err(&iface->adapter.dev, "timeout in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+ u8 status = 0;
+ unsigned long timeout;
+
+ timeout = jiffies + POLL_TIMEOUT;
+ while (time_before(jiffies, timeout)) {
+ status = inb(ACBST);
+ if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+ scx200_acb_machine(iface, status);
+ return;
+ }
+ schedule_timeout(HZ/100+1);
+ }
+
+ scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+ /* Polling mode */
+ outb(0, ACBCTL1);
+ /* Disable slave address */
+ outb(0, ACBADDR);
+ /* Enable the ACCESS.bus device */
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+ /* Free STALL after START */
+ outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+ /* Send a STOP */
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ /* Clear BER, NEGACK and STASTR bits */
+ outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+ /* Clear BB bit */
+ outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+ u16 address, unsigned short flags,
+ char rw, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
+ int len;
+ u8 *buffer;
+ u16 cur_word;
+ int rc;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ len = 0;
+ buffer = NULL;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (rw == I2C_SMBUS_READ) {
+ len = 1;
+ buffer = &data->byte;
+ } else {
+ len = 1;
+ buffer = &command;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ len = 1;
+ buffer = &data->byte;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ len = 2;
+ cur_word = cpu_to_le16(data->word);
+ buffer = (u8 *)&cur_word;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ len = data->block[0];
+ buffer = &data->block[1];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+ size, address, command, len, rw == I2C_SMBUS_READ);
+
+ if (!len && rw == I2C_SMBUS_READ) {
+ dev_warn(&adapter->dev, "zero length read\n");
+ return -EINVAL;
+ }
+
+ if (len && !buffer) {
+ dev_warn(&adapter->dev, "nonzero length but no buffer\n");
+ return -EFAULT;
+ }
+
+ down(&iface->sem);
+
+ iface->address_byte = address<<1;
+ if (rw == I2C_SMBUS_READ)
+ iface->address_byte |= 1;
+ iface->command = command;
+ iface->ptr = buffer;
+ iface->len = len;
+ iface->result = -EINVAL;
+ iface->needs_reset = 0;
+
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+ iface->state = state_quick;
+ else
+ iface->state = state_address;
+
+#ifdef POLLED_MODE
+ while (iface->state != state_idle)
+ scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */
+
+ if (iface->needs_reset)
+ scx200_acb_reset(iface);
+
+ rc = iface->result;
+
+ up(&iface->sem);
+
+ if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+ data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+ printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+ if (buffer) {
+ int i;
+ printk(" data:");
+ for (i = 0; i < len; ++i)
+ printk(" %02x", buffer[i]);
+ }
+ printk("\n");
+#endif
+
+ return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+ .name = "NatSemi SCx200 ACCESS.bus",
+ .id = I2C_ALGO_SMBUS,
+ .smbus_xfer = scx200_acb_smbus_xfer,
+ .functionality = scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+ u8 val;
+
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+
+ if (inb(ACBCTL2) != 0x70) {
+ DBG("ACBCTL2 readback failed\n");
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if (val) {
+ DBG("disabled, but ACBCTL1=0x%02x\n", val);
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+ DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int __init scx200_acb_create(int base, int index)
+{
+ struct scx200_acb_iface *iface;
+ struct i2c_adapter *adapter;
+ int rc = 0;
+ char description[64];
+
+ iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ if (!iface) {
+ printk(KERN_ERR NAME ": can't allocate memory\n");
+ rc = -ENOMEM;
+ goto errout;
+ }
+
+ memset(iface, 0, sizeof(*iface));
+ adapter = &iface->adapter;
+ i2c_set_adapdata(adapter, iface);
+ snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
+ adapter->owner = THIS_MODULE;
+ adapter->id = I2C_ALGO_SMBUS;
+ adapter->algo = &scx200_acb_algorithm;
+
+ init_MUTEX(&iface->sem);
+
+ snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+ if (request_region(base, 8, description) == 0) {
+ dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n",
+ base, base + 8-1);
+ rc = -EBUSY;
+ goto errout;
+ }
+ iface->base = base;
+
+ rc = scx200_acb_probe(iface);
+ if (rc) {
+ dev_warn(&adapter->dev, "probe failed\n");
+ goto errout;
+ }
+
+ scx200_acb_reset(iface);
+
+ if (i2c_add_adapter(adapter) < 0) {
+ dev_err(&adapter->dev, "failed to register\n");
+ rc = -ENODEV;
+ goto errout;
+ }
+
+ lock_kernel();
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ unlock_kernel();
+
+ return 0;
+
+ errout:
+ if (iface) {
+ if (iface->base)
+ release_region(iface->base, 8);
+ kfree(iface);
+ }
+ return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+ int i;
+ int rc;
+
+ printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+ /* Verify that this really is a SCx200 processor */
+ if (pci_find_device(PCI_VENDOR_ID_NS,
+ PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+ NULL) == NULL)
+ return -ENODEV;
+
+ rc = -ENXIO;
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] > 0)
+ rc = scx200_acb_create(base[i], i);
+ }
+ if (scx200_acb_list)
+ return 0;
+ return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+ struct scx200_acb_iface *iface;
+ lock_kernel();
+ while ((iface = scx200_acb_list) != NULL) {
+ scx200_acb_list = iface->next;
+ unlock_kernel();
+
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+ lock_kernel();
+ }
+ unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+ Local variables:
+ compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+ c-basic-offset: 8
+ End:
+*/
+
diff -Nru a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/busses/scx200_i2c.c Mon Sep 22 16:12:15 2003
@@ -0,0 +1,132 @@
+/* linux/drivers/i2c/scx200_i2c.c
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 I2C bus on GPIO pins
+
+ Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+ 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, or
+ (at your option) any later version.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+ scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+ scx200_gpio_set(sda, state);
+}
+
+static int scx200_i2c_getscl(void *data)
+{
+ return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+ return scx200_gpio_get(sda);
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+ NULL,
+ scx200_i2c_setsda,
+ scx200_i2c_setscl,
+ scx200_i2c_getsda,
+ scx200_i2c_getscl,
+ 10, 10, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+ .owner = THIS_MODULE,
+ .algo_data = &scx200_i2c_data,
+ .name = "NatSemi SCx200 I2C",
+};
+
+int scx200_i2c_init(void)
+{
+ printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+ if (!scx200_gpio_present()) {
+ printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n",
+ scl, sda);
+
+ if (scl == -1 || sda == -1 || scl == sda) {
+ printk(KERN_ERR NAME ": scl and sda must be specified\n");
+ return -EINVAL;
+ }
+
+ /* Configure GPIOs as open collector outputs */
+ scx200_gpio_configure(scl, ~2, 5);
+ scx200_gpio_configure(sda, ~2, 5);
+
+ if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+ printk(KERN_ERR NAME ": adapter %s registration failed\n",
+ scx200_i2c_ops.name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+ i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+ Local variables:
+ compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+ c-basic-offset: 8
+ End:
+*/
diff -Nru a/drivers/i2c/scx200_acb.c b/drivers/i2c/scx200_acb.c
--- a/drivers/i2c/scx200_acb.c Mon Sep 22 16:12:15 2003
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,553 +0,0 @@
-/* linux/drivers/i2c/scx200_acb.c
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- National Semiconductor SCx200 ACCESS.bus support
-
- Based on i2c-keywest.c which is:
- Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
- 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, or (at your option) any later version.
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/smp_lock.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include <linux/scx200.h>
-
-#define NAME "scx200_acb"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
-MODULE_LICENSE("GPL");
-
-#define MAX_DEVICES 4
-static int base[MAX_DEVICES] = { 0x840 };
-MODULE_PARM(base, "1-4i");
-MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
-
-#define DEBUG 0
-
-#if DEBUG
-#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
-#else
-#define DBG(x...)
-#endif
-
-/* The hardware supports interrupt driven mode too, but I haven't
- implemented that. */
-#define POLLED_MODE 1
-#define POLL_TIMEOUT (HZ)
-
-enum scx200_acb_state {
- state_idle,
- state_address,
- state_command,
- state_repeat_start,
- state_quick,
- state_read,
- state_write,
-};
-
-static const char *scx200_acb_state_name[] = {
- "idle",
- "address",
- "command",
- "repeat_start",
- "quick",
- "read",
- "write",
-};
-
-/* Physical interface */
-struct scx200_acb_iface
-{
- struct scx200_acb_iface *next;
- struct i2c_adapter adapter;
- unsigned base;
- struct semaphore sem;
-
- /* State machine data */
- enum scx200_acb_state state;
- int result;
- u8 address_byte;
- u8 command;
- u8 *ptr;
- char needs_reset;
- unsigned len;
-};
-
-/* Register Definitions */
-#define ACBSDA (iface->base + 0)
-#define ACBST (iface->base + 1)
-#define ACBST_SDAST 0x40 /* SDA Status */
-#define ACBST_BER 0x20
-#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
-#define ACBST_STASTR 0x08 /* Stall After Start */
-#define ACBST_MASTER 0x02
-#define ACBCST (iface->base + 2)
-#define ACBCST_BB 0x02
-#define ACBCTL1 (iface->base + 3)
-#define ACBCTL1_STASTRE 0x80
-#define ACBCTL1_NMINTE 0x40
-#define ACBCTL1_ACK 0x10
-#define ACBCTL1_STOP 0x02
-#define ACBCTL1_START 0x01
-#define ACBADDR (iface->base + 4)
-#define ACBCTL2 (iface->base + 5)
-#define ACBCTL2_ENABLE 0x01
-
-/************************************************************************/
-
-static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
-{
- const char *errmsg;
-
- DBG("state %s, status = 0x%02x\n",
- scx200_acb_state_name[iface->state], status);
-
- if (status & ACBST_BER) {
- errmsg = "bus error";
- goto error;
- }
- if (!(status & ACBST_MASTER)) {
- errmsg = "not master";
- goto error;
- }
- if (status & ACBST_NEGACK)
- goto negack;
-
- switch (iface->state) {
- case state_idle:
- dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
- break;
-
- case state_address:
- /* Do a pointer write first */
- outb(iface->address_byte & ~1, ACBSDA);
-
- iface->state = state_command;
- break;
-
- case state_command:
- outb(iface->command, ACBSDA);
-
- if (iface->address_byte & 1)
- iface->state = state_repeat_start;
- else
- iface->state = state_write;
- break;
-
- case state_repeat_start:
- outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
- /* fallthrough */
-
- case state_quick:
- if (iface->address_byte & 1) {
- if (iface->len == 1)
- outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
- else
- outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
- outb(iface->address_byte, ACBSDA);
-
- iface->state = state_read;
- } else {
- outb(iface->address_byte, ACBSDA);
-
- iface->state = state_write;
- }
- break;
-
- case state_read:
- /* Set ACK if receiving the last byte */
- if (iface->len == 1)
- outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
- else
- outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
-
- *iface->ptr++ = inb(ACBSDA);
- --iface->len;
-
- if (iface->len == 0) {
- iface->result = 0;
- iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- }
-
- break;
-
- case state_write:
- if (iface->len == 0) {
- iface->result = 0;
- iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- break;
- }
-
- outb(*iface->ptr++, ACBSDA);
- --iface->len;
-
- break;
- }
-
- return;
-
- negack:
- DBG("negative acknowledge in state %s\n",
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -ENXIO;
-
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
- return;
-
- error:
- dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg,
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -EIO;
- iface->needs_reset = 1;
-}
-
-static void scx200_acb_timeout(struct scx200_acb_iface *iface)
-{
- dev_err(&iface->adapter.dev, "timeout in state %s\n",
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -EIO;
- iface->needs_reset = 1;
-}
-
-#ifdef POLLED_MODE
-static void scx200_acb_poll(struct scx200_acb_iface *iface)
-{
- u8 status = 0;
- unsigned long timeout;
-
- timeout = jiffies + POLL_TIMEOUT;
- while (time_before(jiffies, timeout)) {
- status = inb(ACBST);
- if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
- scx200_acb_machine(iface, status);
- return;
- }
- schedule_timeout(HZ/100+1);
- }
-
- scx200_acb_timeout(iface);
-}
-#endif /* POLLED_MODE */
-
-static void scx200_acb_reset(struct scx200_acb_iface *iface)
-{
- /* Disable the ACCESS.bus device and Configure the SCL
- frequency: 16 clock cycles */
- outb(0x70, ACBCTL2);
- /* Polling mode */
- outb(0, ACBCTL1);
- /* Disable slave address */
- outb(0, ACBADDR);
- /* Enable the ACCESS.bus device */
- outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
- /* Free STALL after START */
- outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
- /* Send a STOP */
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- /* Clear BER, NEGACK and STASTR bits */
- outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
- /* Clear BB bit */
- outb(inb(ACBCST) | ACBCST_BB, ACBCST);
-}
-
-static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
- u16 address, unsigned short flags,
- char rw, u8 command, int size,
- union i2c_smbus_data *data)
-{
- struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
- int len;
- u8 *buffer;
- u16 cur_word;
- int rc;
-
- switch (size) {
- case I2C_SMBUS_QUICK:
- len = 0;
- buffer = NULL;
- break;
- case I2C_SMBUS_BYTE:
- if (rw == I2C_SMBUS_READ) {
- len = 1;
- buffer = &data->byte;
- } else {
- len = 1;
- buffer = &command;
- }
- break;
- case I2C_SMBUS_BYTE_DATA:
- len = 1;
- buffer = &data->byte;
- break;
- case I2C_SMBUS_WORD_DATA:
- len = 2;
- cur_word = cpu_to_le16(data->word);
- buffer = (u8 *)&cur_word;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- len = data->block[0];
- buffer = &data->block[1];
- break;
- default:
- return -EINVAL;
- }
-
- DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
- size, address, command, len, rw == I2C_SMBUS_READ);
-
- if (!len && rw == I2C_SMBUS_READ) {
- dev_warn(&adapter->dev, "zero length read\n");
- return -EINVAL;
- }
-
- if (len && !buffer) {
- dev_warn(&adapter->dev, "nonzero length but no buffer\n");
- return -EFAULT;
- }
-
- down(&iface->sem);
-
- iface->address_byte = address<<1;
- if (rw == I2C_SMBUS_READ)
- iface->address_byte |= 1;
- iface->command = command;
- iface->ptr = buffer;
- iface->len = len;
- iface->result = -EINVAL;
- iface->needs_reset = 0;
-
- outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
-
- if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
- iface->state = state_quick;
- else
- iface->state = state_address;
-
-#ifdef POLLED_MODE
- while (iface->state != state_idle)
- scx200_acb_poll(iface);
-#else /* POLLED_MODE */
-#error Interrupt driven mode not implemented
-#endif /* POLLED_MODE */
-
- if (iface->needs_reset)
- scx200_acb_reset(iface);
-
- rc = iface->result;
-
- up(&iface->sem);
-
- if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
- data->word = le16_to_cpu(cur_word);
-
-#if DEBUG
- printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
- if (buffer) {
- int i;
- printk(" data:");
- for (i = 0; i < len; ++i)
- printk(" %02x", buffer[i]);
- }
- printk("\n");
-#endif
-
- return rc;
-}
-
-static u32 scx200_acb_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm scx200_acb_algorithm = {
- .name = "NatSemi SCx200 ACCESS.bus",
- .id = I2C_ALGO_SMBUS,
- .smbus_xfer = scx200_acb_smbus_xfer,
- .functionality = scx200_acb_func,
-};
-
-struct scx200_acb_iface *scx200_acb_list;
-
-int scx200_acb_probe(struct scx200_acb_iface *iface)
-{
- u8 val;
-
- /* Disable the ACCESS.bus device and Configure the SCL
- frequency: 16 clock cycles */
- outb(0x70, ACBCTL2);
-
- if (inb(ACBCTL2) != 0x70) {
- DBG("ACBCTL2 readback failed\n");
- return -ENXIO;
- }
-
- outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
-
- val = inb(ACBCTL1);
- if (val) {
- DBG("disabled, but ACBCTL1=0x%02x\n", val);
- return -ENXIO;
- }
-
- outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
-
- outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
-
- val = inb(ACBCTL1);
- if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
- DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int __init scx200_acb_create(int base, int index)
-{
- struct scx200_acb_iface *iface;
- struct i2c_adapter *adapter;
- int rc = 0;
- char description[64];
-
- iface = kmalloc(sizeof(*iface), GFP_KERNEL);
- if (!iface) {
- printk(KERN_ERR NAME ": can't allocate memory\n");
- rc = -ENOMEM;
- goto errout;
- }
-
- memset(iface, 0, sizeof(*iface));
- adapter = &iface->adapter;
- i2c_set_adapdata(adapter, iface);
- snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
- adapter->owner = THIS_MODULE;
- adapter->id = I2C_ALGO_SMBUS;
- adapter->algo = &scx200_acb_algorithm;
-
- init_MUTEX(&iface->sem);
-
- snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
- if (request_region(base, 8, description) == 0) {
- dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n",
- base, base + 8-1);
- rc = -EBUSY;
- goto errout;
- }
- iface->base = base;
-
- rc = scx200_acb_probe(iface);
- if (rc) {
- dev_warn(&adapter->dev, "probe failed\n");
- goto errout;
- }
-
- scx200_acb_reset(iface);
-
- if (i2c_add_adapter(adapter) < 0) {
- dev_err(&adapter->dev, "failed to register\n");
- rc = -ENODEV;
- goto errout;
- }
-
- lock_kernel();
- iface->next = scx200_acb_list;
- scx200_acb_list = iface;
- unlock_kernel();
-
- return 0;
-
- errout:
- if (iface) {
- if (iface->base)
- release_region(iface->base, 8);
- kfree(iface);
- }
- return rc;
-}
-
-static int __init scx200_acb_init(void)
-{
- int i;
- int rc;
-
- printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
-
- /* Verify that this really is a SCx200 processor */
- if (pci_find_device(PCI_VENDOR_ID_NS,
- PCI_DEVICE_ID_NS_SCx200_BRIDGE,
- NULL) == NULL)
- return -ENODEV;
-
- rc = -ENXIO;
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] > 0)
- rc = scx200_acb_create(base[i], i);
- }
- if (scx200_acb_list)
- return 0;
- return rc;
-}
-
-static void __exit scx200_acb_cleanup(void)
-{
- struct scx200_acb_iface *iface;
- lock_kernel();
- while ((iface = scx200_acb_list) != NULL) {
- scx200_acb_list = iface->next;
- unlock_kernel();
-
- i2c_del_adapter(&iface->adapter);
- release_region(iface->base, 8);
- kfree(iface);
- lock_kernel();
- }
- unlock_kernel();
-}
-
-module_init(scx200_acb_init);
-module_exit(scx200_acb_cleanup);
-
-/*
- Local variables:
- compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
- c-basic-offset: 8
- End:
-*/
-
diff -Nru a/drivers/i2c/scx200_i2c.c b/drivers/i2c/scx200_i2c.c
--- a/drivers/i2c/scx200_i2c.c Mon Sep 22 16:12:15 2003
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,133 +0,0 @@
-/* linux/drivers/i2c/scx200_i2c.c
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- National Semiconductor SCx200 I2C bus on GPIO pins
-
- Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
-
- 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, or
- (at your option) any later version.
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-#include <linux/scx200_gpio.h>
-
-#define NAME "scx200_i2c"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(scl, "i");
-MODULE_PARM_DESC(scl, "GPIO line for SCL");
-MODULE_PARM(sda, "i");
-MODULE_PARM_DESC(sda, "GPIO line for SDA");
-
-static int scl = CONFIG_SCx200_I2C_SCL;
-static int sda = CONFIG_SCx200_I2C_SDA;
-
-static void scx200_i2c_setscl(void *data, int state)
-{
- scx200_gpio_set(scl, state);
-}
-
-static void scx200_i2c_setsda(void *data, int state)
-{
- scx200_gpio_set(sda, state);
-}
-
-static int scx200_i2c_getscl(void *data)
-{
- return scx200_gpio_get(scl);
-}
-
-static int scx200_i2c_getsda(void *data)
-{
- return scx200_gpio_get(sda);
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-
-static struct i2c_algo_bit_data scx200_i2c_data = {
- NULL,
- scx200_i2c_setsda,
- scx200_i2c_setscl,
- scx200_i2c_getsda,
- scx200_i2c_getscl,
- 10, 10, 100, /* waits, timeout */
-};
-
-static struct i2c_adapter scx200_i2c_ops = {
- .owner = THIS_MODULE,
- .id = I2C_HW_B_VELLE,
- .algo_data = &scx200_i2c_data,
- .name = "NatSemi SCx200 I2C",
-};
-
-int scx200_i2c_init(void)
-{
- printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
-
- if (!scx200_gpio_present()) {
- printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
- return -ENODEV;
- }
-
- printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n",
- scl, sda);
-
- if (scl == -1 || sda == -1 || scl == sda) {
- printk(KERN_ERR NAME ": scl and sda must be specified\n");
- return -EINVAL;
- }
-
- /* Configure GPIOs as open collector outputs */
- scx200_gpio_configure(scl, ~2, 5);
- scx200_gpio_configure(sda, ~2, 5);
-
- if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
- printk(KERN_ERR NAME ": adapter %s registration failed\n",
- scx200_i2c_ops.name);
- return -ENODEV;
- }
-
- return 0;
-}
-
-void scx200_i2c_cleanup(void)
-{
- i2c_bit_del_bus(&scx200_i2c_ops);
-}
-
-module_init(scx200_i2c_init);
-module_exit(scx200_i2c_cleanup);
-
-/*
- Local variables:
- compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
- c-basic-offset: 8
- End:
-*/
next prev parent reply other threads:[~2005-05-19 6:24 UTC|newest]
Thread overview: 125+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-09-22 23:28 [BK PATCH] i2c driver fixes for 2.6.0-test5 Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` [PATCH] " Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH [this message]
2005-05-19 6:24 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-22 23:30 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-23 8:16 ` Christoph Hellwig
2005-05-19 6:24 ` Christoph Hellwig
2003-09-23 16:19 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-23 16:22 ` Christoph Hellwig
2005-05-19 6:24 ` Christoph Hellwig
2003-09-23 19:04 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-09-23 19:08 ` Christoph Hellwig
2005-05-19 6:24 ` Christoph Hellwig
-- strict thread matches above, loose matches on Subject: below --
2003-10-10 23:10 [BK PATCH] i2c driver fixes for 2.6.0-test7 Greg KH
2005-05-19 6:24 ` Greg KH
2003-10-10 23:11 ` [PATCH] " Greg KH
2005-05-19 6:24 ` Greg KH
2003-10-10 23:11 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-10-10 23:11 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-10-10 23:11 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:32 [BK PATCH] i2c driver fixes for 2.6.0-test3 Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` [PATCH] i2c driver changes 2.6.0-test3 Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2003-08-15 18:33 ` Greg KH
2005-05-19 6:24 ` Greg KH
2005-05-19 6:24 ` Philip Pokorny
2005-05-19 6:24 ` Jean Delvare
2005-05-19 6:24 ` Mark D. Studebaker
2005-05-19 6:24 ` Jean Delvare
2005-05-19 6:24 ` Greg KH
2003-08-02 5:29 [BK PATCH] i2c driver fixes for 2.6.0-test2 Greg KH
2005-05-19 6:24 ` Greg KH
2005-05-19 6:24 ` Greg KH
2005-05-19 6:24 ` Jean Delvare
2005-05-19 6:24 ` Mark M. Hoffman
2005-05-19 6:24 ` Mark M. Hoffman
2003-08-14 5:13 ` Mark M. Hoffman
2005-05-19 6:24 ` Mark M. Hoffman
2003-08-14 21:14 ` Greg KH
2005-05-19 6:24 ` Greg KH
2005-05-19 6:24 ` Greg KH
2005-05-19 6:24 ` [BK PATCH] i2c driver fixes for 2.6.0-test5 Greg KH
2005-05-19 6:24 ` Mark M. Hoffman
2005-05-19 6:24 ` Mark M. Hoffman
2005-05-19 6:24 ` Jean Delvare
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=10642734272108@kroah.com \
--to=greg@kroah.com \
--cc=linux-kernel@vger.kernel.org \
--cc=sensors@stimpy.netroedge.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.