summaryrefslogtreecommitdiff
path: root/drivers/i2c/algos
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/i2c/algos
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/i2c/algos')
-rw-r--r--drivers/i2c/algos/Kconfig70
-rw-r--r--drivers/i2c/algos/Makefile14
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c573
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.c812
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.h117
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c399
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.h26
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c507
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.h76
-rw-r--r--drivers/i2c/algos/i2c-algo-sgi.c189
-rw-r--r--drivers/i2c/algos/i2c-algo-sibyte.c222
11 files changed, 3005 insertions, 0 deletions
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
new file mode 100644
index 000000000000..30408015d231
--- /dev/null
+++ b/drivers/i2c/algos/Kconfig
@@ -0,0 +1,70 @@
+#
+# Character device configuration
+#
+
+menu "I2C Algorithms"
+ depends on I2C
+
+config I2C_ALGOBIT
+ tristate "I2C bit-banging interfaces"
+ depends on I2C
+ help
+ This allows you to use a range of I2C adapters called bit-banging
+ adapters. Say Y if you own an I2C adapter belonging to this class
+ and then say Y to the specific driver for you adapter below.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-algo-bit.
+
+config I2C_ALGOPCF
+ tristate "I2C PCF 8584 interfaces"
+ depends on I2C
+ help
+ This allows you to use a range of I2C adapters called PCF adapters.
+ Say Y if you own an I2C adapter belonging to this class and then say
+ Y to the specific driver for you adapter below.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-algo-pcf.
+
+config I2C_ALGOPCA
+ tristate "I2C PCA 9564 interfaces"
+ depends on I2C
+ help
+ This allows you to use a range of I2C adapters called PCA adapters.
+ Say Y if you own an I2C adapter belonging to this class and then say
+ Y to the specific driver for you adapter below.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-algo-pca.
+
+config I2C_ALGOITE
+ tristate "ITE I2C Algorithm"
+ depends on MIPS_ITE8172 && I2C
+ help
+ This supports the use of the ITE8172 I2C interface found on some MIPS
+ systems. Say Y if you have one of these. You should also say Y for
+ the ITE I2C peripheral driver support below.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-algo-ite.
+
+config I2C_ALGO8XX
+ tristate "MPC8xx CPM I2C interface"
+ depends on 8xx && I2C
+
+config I2C_ALGO_SIBYTE
+ tristate "SiByte SMBus interface"
+ depends on SIBYTE_SB1xxx_SOC && I2C
+ help
+ Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+
+config I2C_ALGO_SGI
+ tristate "I2C SGI interfaces"
+ depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
+ help
+ Supports the SGI interfaces like the ones found on SGI Indy VINO
+ or SGI O2 MACE.
+
+endmenu
+
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
new file mode 100644
index 000000000000..867fe1f67401
--- /dev/null
+++ b/drivers/i2c/algos/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the i2c algorithms
+#
+
+obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
+obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
+obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
+obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
+obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o
+obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
+
+ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
new file mode 100644
index 000000000000..fb5b732238ed
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -0,0 +1,573 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-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. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+ <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x;
+#define DEB2(x) if (i2c_debug>=2) x;
+#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
+#define DEBPROTO(x) if (i2c_debug>=9) { x; }
+ /* debug the protocol by showing transferred bits */
+
+
+/* ----- global variables --------------------------------------------- */
+
+/* module parameters:
+ */
+static int i2c_debug;
+static int bit_test; /* see if the line-setting functions work */
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define setsda(adap,val) adap->setsda(adap->data, val)
+#define setscl(adap,val) adap->setscl(adap->data, val)
+#define getsda(adap) adap->getsda(adap->data)
+#define getscl(adap) adap->getscl(adap->data)
+
+static inline void sdalo(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap,0);
+ udelay(adap->udelay);
+}
+
+static inline void sdahi(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap,1);
+ udelay(adap->udelay);
+}
+
+static inline void scllo(struct i2c_algo_bit_data *adap)
+{
+ setscl(adap,0);
+ udelay(adap->udelay);
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static inline int sclhi(struct i2c_algo_bit_data *adap)
+{
+ unsigned long start;
+
+ setscl(adap,1);
+
+ /* Not all adapters have scl sense line... */
+ if (adap->getscl == NULL ) {
+ udelay(adap->udelay);
+ return 0;
+ }
+
+ start=jiffies;
+ while (! getscl(adap) ) {
+ /* the hw knows how to read the clock line,
+ * so we wait until it actually gets high.
+ * This is safer as some chips may hold it low
+ * while they are processing data internally.
+ */
+ if (time_after_eq(jiffies, start+adap->timeout)) {
+ return -ETIMEDOUT;
+ }
+ cond_resched();
+ }
+ DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
+ udelay(adap->udelay);
+ return 0;
+}
+
+
+/* --- other auxiliary functions -------------------------------------- */
+static void i2c_start(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl, sda are high */
+ DEBPROTO(printk("S "));
+ sdalo(adap);
+ scllo(adap);
+}
+
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+{
+ /* scl, sda may not be high */
+ DEBPROTO(printk(" Sr "));
+ setsda(adap,1);
+ sclhi(adap);
+ udelay(adap->udelay);
+
+ sdalo(adap);
+ scllo(adap);
+}
+
+
+static void i2c_stop(struct i2c_algo_bit_data *adap)
+{
+ DEBPROTO(printk("P\n"));
+ /* assert: scl is low */
+ sdalo(adap);
+ sclhi(adap);
+ sdahi(adap);
+}
+
+
+
+/* send a byte without start cond., look for arbitration,
+ check ackn. from slave */
+/* returns:
+ * 1 if the device acknowledged
+ * 0 if the device did not ack
+ * -ETIMEDOUT if an error occurred (while raising the scl line)
+ */
+static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
+{
+ int i;
+ int sb;
+ int ack;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ for ( i=7 ; i>=0 ; i-- ) {
+ sb = c & ( 1 << i );
+ setsda(adap,sb);
+ udelay(adap->udelay);
+ DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
+ if (sclhi(adap)<0) { /* timed out */
+ sdahi(adap); /* we don't want to block the net */
+ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
+ return -ETIMEDOUT;
+ };
+ /* do arbitration here:
+ * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
+ */
+ setscl(adap, 0 );
+ udelay(adap->udelay);
+ }
+ sdahi(adap);
+ if (sclhi(adap)<0){ /* timeout */
+ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff));
+ return -ETIMEDOUT;
+ };
+ /* read ack: SDA should be pulled down by slave */
+ ack=getsda(adap); /* ack: sda is pulled low ->success. */
+ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack));
+
+ DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
+ DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
+ scllo(adap);
+ return 0==ack; /* return 1 if device acked */
+ /* assert: scl is low (sda undef) */
+}
+
+
+static int i2c_inb(struct i2c_adapter *i2c_adap)
+{
+ /* read byte via i2c port, without start/stop sequence */
+ /* acknowledge is sent in i2c_read. */
+ int i;
+ unsigned char indata=0;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ sdahi(adap);
+ for (i=0;i<8;i++) {
+ if (sclhi(adap)<0) { /* timeout */
+ DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i));
+ return -ETIMEDOUT;
+ };
+ indata *= 2;
+ if ( getsda(adap) )
+ indata |= 0x01;
+ scllo(adap);
+ }
+ /* assert: scl is low */
+ DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
+
+ DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
+ return (int) (indata & 0xff);
+}
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
+ int scl,sda;
+
+ if (adap->getscl==NULL)
+ printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
+ "SCL is not readable.\n");
+
+ sda=getsda(adap);
+ scl=(adap->getscl==NULL?1:getscl(adap));
+ printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
+ if (!scl || !sda ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
+ goto bailout;
+ }
+
+ sdalo(adap);
+ sda=getsda(adap);
+ scl=(adap->getscl==NULL?1:getscl(adap));
+ printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
+ if ( 0 != sda ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
+ goto bailout;
+ }
+ if ( 0 == scl ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
+ "while pulling SDA low!\n");
+ goto bailout;
+ }
+
+ sdahi(adap);
+ sda=getsda(adap);
+ scl=(adap->getscl==NULL?1:getscl(adap));
+ printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
+ if ( 0 == sda ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
+ goto bailout;
+ }
+ if ( 0 == scl ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
+ "while pulling SDA high!\n");
+ goto bailout;
+ }
+
+ scllo(adap);
+ sda=getsda(adap);
+ scl=(adap->getscl==NULL?0:getscl(adap));
+ printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
+ if ( 0 != scl ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
+ goto bailout;
+ }
+ if ( 0 == sda ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
+ "while pulling SCL low!\n");
+ goto bailout;
+ }
+
+ sclhi(adap);
+ sda=getsda(adap);
+ scl=(adap->getscl==NULL?1:getscl(adap));
+ printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
+ if ( 0 == scl ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
+ goto bailout;
+ }
+ if ( 0 == sda ) {
+ printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
+ "while pulling SCL high!\n");
+ goto bailout;
+ }
+ printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+ return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+/* try_address tries to contact a chip for a number of
+ * times before it gives up.
+ * return values:
+ * 1 chip answered
+ * 0 chip did not answer
+ * -x transmission error
+ */
+static inline int try_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ int i,ret = -1;
+ for (i=0;i<=retries;i++) {
+ ret = i2c_outb(i2c_adap,addr);
+ if (ret==1)
+ break; /* success! */
+ i2c_stop(adap);
+ udelay(5/*adap->udelay*/);
+ if (i==retries) /* no success */
+ break;
+ i2c_start(adap);
+ udelay(adap->udelay);
+ }
+ DEB2(if (i)
+ printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
+ i+1, addr & 1 ? "read" : "write", addr>>1,
+ ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" )
+ );
+ return ret;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ char c;
+ const char *temp = msg->buf;
+ int count = msg->len;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ int retval;
+ int wrcount=0;
+
+ while (count > 0) {
+ c = *temp;
+ DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff));
+ retval = i2c_outb(i2c_adap,c);
+ if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */
+ count--;
+ temp++;
+ wrcount++;
+ } else { /* arbitration or no acknowledge */
+ dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
+ i2c_stop(adap);
+ return (retval<0)? retval : -EFAULT;
+ /* got a better one ?? */
+ }
+#if 0
+ /* from asm/delay.h */
+ __delay(adap->mdelay * (loops_per_sec / 1000) );
+#endif
+ }
+ return wrcount;
+}
+
+static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ int inval;
+ int rdcount=0; /* counts bytes read */
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ char *temp = msg->buf;
+ int count = msg->len;
+
+ while (count > 0) {
+ inval = i2c_inb(i2c_adap);
+/*printk("%#02x ",inval); if ( ! (count % 16) ) printk("\n"); */
+ if (inval>=0) {
+ *temp = inval;
+ rdcount++;
+ } else { /* read timed out */
+ printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n");
+ break;
+ }
+
+ temp++;
+ count--;
+
+ if (msg->flags & I2C_M_NO_RD_ACK)
+ continue;
+
+ if ( count > 0 ) { /* send ack */
+ sdalo(adap);
+ DEBPROTO(printk(" Am "));
+ } else {
+ sdahi(adap); /* neg. ack on last byte */
+ DEBPROTO(printk(" NAm "));
+ }
+ if (sclhi(adap)<0) { /* timeout */
+ sdahi(adap);
+ printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
+ return -ETIMEDOUT;
+ };
+ scllo(adap);
+ sdahi(adap);
+ }
+ return rdcount;
+}
+
+/* doAddress initiates the transfer by generating the start condition (in
+ * try_address) and transmits the address in the necessary format to handle
+ * reads, writes as well as 10bit-addresses.
+ * returns:
+ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
+ * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
+ * -ETIMEDOUT, for example if the lines are stuck...)
+ */
+static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ unsigned short flags = msg->flags;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ unsigned char addr;
+ int ret, retries;
+
+ retries = nak_ok ? 0 : i2c_adap->retries;
+
+ if ( (flags & I2C_M_TEN) ) {
+ /* a ten bit address */
+ addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+ DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+ /* try extended address code...*/
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ printk(KERN_ERR "died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
+ if ((ret != 1) && !nak_ok) {
+ /* the chip did not ack / xmission error occurred */
+ printk(KERN_ERR "died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ if ( flags & I2C_M_RD ) {
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret!=1) && !nak_ok) {
+ printk(KERN_ERR "died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = ( msg->addr << 1 );
+ if (flags & I2C_M_RD )
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR )
+ addr ^= 1;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret!=1) && !nak_ok)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int bit_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_msg *pmsg;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ int i,ret;
+ unsigned short nak_ok;
+
+ i2c_start(adap);
+ for (i=0;i<num;i++) {
+ pmsg = &msgs[i];
+ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ if (i) {
+ i2c_repstart(adap);
+ }
+ ret = bit_doAddress(i2c_adap, pmsg);
+ if ((ret != 0) && !nak_ok) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n"
+ ,msgs[i].addr,i));
+ return (ret<0) ? ret : -EREMOTEIO;
+ }
+ }
+ if (pmsg->flags & I2C_M_RD ) {
+ /* read bytes into buffer*/
+ ret = readbytes(i2c_adap, pmsg);
+ DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
+ if (ret < pmsg->len ) {
+ return (ret<0)? ret : -EREMOTEIO;
+ }
+ } else {
+ /* write bytes from buffer */
+ ret = sendbytes(i2c_adap, pmsg);
+ DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
+ if (ret < pmsg->len ) {
+ return (ret<0) ? ret : -EREMOTEIO;
+ }
+ }
+ }
+ i2c_stop(adap);
+ return num;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm i2c_bit_algo = {
+ .name = "Bit-shift algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = bit_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+ struct i2c_algo_bit_data *bit_adap = adap->algo_data;
+
+ if (bit_test) {
+ int ret = test_bus(bit_adap, adap->name);
+ if (ret<0)
+ return -ENODEV;
+ }
+
+ DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
+
+ /* register new adapter to i2c module... */
+
+ adap->id |= i2c_bit_algo.id;
+ adap->algo = &i2c_bit_algo;
+
+ adap->timeout = 100; /* default values, should */
+ adap->retries = 3; /* be replaced by defines */
+
+ i2c_add_adapter(adap);
+ return 0;
+}
+
+
+int i2c_bit_del_bus(struct i2c_adapter *adap)
+{
+ return i2c_del_adapter(adap);
+}
+
+EXPORT_SYMBOL(i2c_bit_add_bus);
+EXPORT_SYMBOL(i2c_bit_del_bus);
+
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(bit_test, bool, 0);
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
new file mode 100644
index 000000000000..68e9e6832ca0
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -0,0 +1,812 @@
+/*
+ -------------------------------------------------------------------------
+ i2c-algo-ite.c i2c driver algorithms for ITE adapters
+
+ Hai-Pao Fan, MontaVista Software, Inc.
+ hpfan@mvista.com or source@mvista.com
+
+ Copyright 2000 MontaVista Software Inc.
+
+ ---------------------------------------------------------------------------
+ This file was highly leveraged from i2c-algo-pcf.c, which was created
+ by Simon G. Vogl and Hans Berglund:
+
+
+ Copyright (C) 1995-1997 Simon G. Vogl
+ 1998-2000 Hans Berglund
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+ Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+ <mbailey@littlefeet-inc.com> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-ite.h>
+#include "i2c-algo-ite.h"
+
+#define PM_DSR IT8172_PCI_IO_BASE + IT_PM_DSR
+#define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04
+#define GPIO_CCR IT8172_PCI_IO_BASE + IT_GPCCR
+
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
+#define DEF_TIMEOUT 16
+
+
+/* module parameters:
+ */
+static int i2c_debug;
+static int iic_test; /* see if the line-setting functions work */
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define get_clock(adap) adap->getclock(adap->data)
+#define iic_outw(adap, reg, val) adap->setiic(adap->data, reg, val)
+#define iic_inw(adap, reg) adap->getiic(adap->data, reg)
+
+
+/* --- other auxiliary functions -------------------------------------- */
+
+static void iic_start(struct i2c_algo_iic_data *adap)
+{
+ iic_outw(adap,ITE_I2CHCR,ITE_CMD);
+}
+
+static void iic_stop(struct i2c_algo_iic_data *adap)
+{
+ iic_outw(adap,ITE_I2CHCR,0);
+ iic_outw(adap,ITE_I2CHSR,ITE_I2CHSR_TDI);
+}
+
+static void iic_reset(struct i2c_algo_iic_data *adap)
+{
+ iic_outw(adap, PM_IBSR, iic_inw(adap, PM_IBSR) | 0x80);
+}
+
+
+static int wait_for_bb(struct i2c_algo_iic_data *adap)
+{
+ int timeout = DEF_TIMEOUT;
+ short status;
+
+ status = iic_inw(adap, ITE_I2CHSR);
+#ifndef STUB_I2C
+ while (timeout-- && (status & ITE_I2CHSR_HB)) {
+ udelay(1000); /* How much is this? */
+ status = iic_inw(adap, ITE_I2CHSR);
+ }
+#endif
+ if (timeout<=0) {
+ printk(KERN_ERR "Timeout, host is busy\n");
+ iic_reset(adap);
+ }
+ return(timeout<=0);
+}
+
+/* After we issue a transaction on the IIC bus, this function
+ * is called. It puts this process to sleep until we get an interrupt from
+ * from the controller telling us that the transaction we requested in complete.
+ */
+static int wait_for_pin(struct i2c_algo_iic_data *adap, short *status) {
+
+ int timeout = DEF_TIMEOUT;
+
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk("Timeout waiting for host not busy\n");)
+ return -EIO;
+ }
+ timeout = DEF_TIMEOUT;
+
+ *status = iic_inw(adap, ITE_I2CHSR);
+#ifndef STUB_I2C
+ while (timeout-- && !(*status & ITE_I2CHSR_TDI)) {
+ adap->waitforpin();
+ *status = iic_inw(adap, ITE_I2CHSR);
+ }
+#endif
+ if (timeout <= 0)
+ return(-1);
+ else
+ return(0);
+}
+
+static int wait_for_fe(struct i2c_algo_iic_data *adap, short *status)
+{
+ int timeout = DEF_TIMEOUT;
+
+ *status = iic_inw(adap, ITE_I2CFSR);
+#ifndef STUB_I2C
+ while (timeout-- && (*status & ITE_I2CFSR_FE)) {
+ udelay(1000);
+ iic_inw(adap, ITE_I2CFSR);
+ }
+#endif
+ if (timeout <= 0)
+ return(-1);
+ else
+ return(0);
+}
+
+static int iic_init (struct i2c_algo_iic_data *adap)
+{
+ short i;
+
+ /* Clear bit 7 to set I2C to normal operation mode */
+ i=iic_inw(adap, PM_DSR)& 0xff7f;
+ iic_outw(adap, PM_DSR, i);
+
+ /* set IT_GPCCR port C bit 2&3 as function 2 */
+ i = iic_inw(adap, GPIO_CCR) & 0xfc0f;
+ iic_outw(adap,GPIO_CCR,i);
+
+ /* Clear slave address/sub-address */
+ iic_outw(adap,ITE_I2CSAR, 0);
+ iic_outw(adap,ITE_I2CSSAR, 0);
+
+ /* Set clock counter register */
+ iic_outw(adap,ITE_I2CCKCNT, get_clock(adap));
+
+ /* Set START/reSTART/STOP time registers */
+ iic_outw(adap,ITE_I2CSHDR, 0x0a);
+ iic_outw(adap,ITE_I2CRSUR, 0x0a);
+ iic_outw(adap,ITE_I2CPSUR, 0x0a);
+
+ /* Enable interrupts on completing the current transaction */
+ iic_outw(adap,ITE_I2CHCR, ITE_I2CHCR_IE | ITE_I2CHCR_HCE);
+
+ /* Clear transfer count */
+ iic_outw(adap,ITE_I2CFBCR, 0x0);
+
+ DEB2(printk("iic_init: Initialized IIC on ITE 0x%x\n",
+ iic_inw(adap, ITE_I2CHSR)));
+ return 0;
+}
+
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
+#if 0
+ int scl,sda;
+ sda=getsda(adap);
+ if (adap->getscl==NULL) {
+ printk("test_bus: Warning: Adapter can't read from clock line - skipping test.\n");
+ return 0;
+ }
+ scl=getscl(adap);
+ printk("test_bus: Adapter: %s scl: %d sda: %d -- testing...\n",
+ name,getscl(adap),getsda(adap));
+ if (!scl || !sda ) {
+ printk("test_bus: %s seems to be busy.\n",adap->name);
+ goto bailout;
+ }
+ sdalo(adap);
+ printk("test_bus:1 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 != getsda(adap) ) {
+ printk("test_bus: %s SDA stuck high!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("test_bus: %s SCL unexpected low while pulling SDA low!\n",
+ name);
+ goto bailout;
+ }
+ sdahi(adap);
+ printk("test_bus:2 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 == getsda(adap) ) {
+ printk("test_bus: %s SDA stuck low!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("test_bus: %s SCL unexpected low while SDA high!\n",
+ adap->name);
+ goto bailout;
+ }
+ scllo(adap);
+ printk("test_bus:3 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 != getscl(adap) ) {
+
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("test_bus: %s SDA unexpected low while pulling SCL low!\n",
+ name);
+ goto bailout;
+ }
+ sclhi(adap);
+ printk("test_bus:4 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 == getscl(adap) ) {
+ printk("test_bus: %s SCL stuck low!\n",name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("test_bus: %s SDA unexpected low while SCL high!\n",
+ name);
+ goto bailout;
+ }
+ printk("test_bus: %s passed test.\n",name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+ return -ENODEV;
+#endif
+ return (0);
+}
+
+/* ----- Utility functions
+ */
+
+
+/* Verify the device we want to talk to on the IIC bus really exists. */
+static inline int try_address(struct i2c_algo_iic_data *adap,
+ unsigned int addr, int retries)
+{
+ int i, ret = -1;
+ short status;
+
+ for (i=0;i<retries;i++) {
+ iic_outw(adap, ITE_I2CSAR, addr);
+ iic_start(adap);
+ if (wait_for_pin(adap, &status) == 0) {
+ if ((status & ITE_I2CHSR_DNE) == 0) {
+ iic_stop(adap);
+ iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
+ ret=1;
+ break; /* success! */
+ }
+ }
+ iic_stop(adap);
+ udelay(adap->udelay);
+ }
+ DEB2(if (i) printk("try_address: needed %d retries for 0x%x\n",i,
+ addr));
+ return ret;
+}
+
+
+static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
+ int count)
+{
+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+ int wrcount=0, timeout;
+ short status;
+ int loops, remainder, i, j;
+ union {
+ char byte[2];
+ unsigned short word;
+ } tmp;
+
+ iic_outw(adap, ITE_I2CSSAR, (unsigned short)buf[wrcount++]);
+ count--;
+ if (count == 0)
+ return -EIO;
+
+ loops = count / 32; /* 32-byte FIFO */
+ remainder = count % 32;
+
+ if(loops) {
+ for(i=0; i<loops; i++) {
+
+ iic_outw(adap, ITE_I2CFBCR, 32);
+ for(j=0; j<32/2; j++) {
+ tmp.byte[1] = buf[wrcount++];
+ tmp.byte[0] = buf[wrcount++];
+ iic_outw(adap, ITE_I2CFDR, tmp.word);
+ }
+
+ /* status FIFO overrun */
+ iic_inw(adap, ITE_I2CFSR);
+ iic_inw(adap, ITE_I2CFBCR);
+
+ iic_outw(adap, ITE_I2CHCR, ITE_WRITE); /* Issue WRITE command */
+
+ /* Wait for transmission to complete */
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write timeout.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ }
+ }
+ if(remainder) {
+ iic_outw(adap, ITE_I2CFBCR, remainder);
+ for(i=0; i<remainder/2; i++) {
+ tmp.byte[1] = buf[wrcount++];
+ tmp.byte[0] = buf[wrcount++];
+ iic_outw(adap, ITE_I2CFDR, tmp.word);
+ }
+
+ /* status FIFO overrun */
+ iic_inw(adap, ITE_I2CFSR);
+ iic_inw(adap, ITE_I2CFBCR);
+
+ iic_outw(adap, ITE_I2CHCR, ITE_WRITE); /* Issue WRITE command */
+
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write timeout.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#ifndef STUB_I2C
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#endif
+ }
+ iic_stop(adap);
+ return wrcount;
+}
+
+
+static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count,
+ int sread)
+{
+ int rdcount=0, i, timeout;
+ short status;
+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+ int loops, remainder, j;
+ union {
+ char byte[2];
+ unsigned short word;
+ } tmp;
+
+ loops = count / 32; /* 32-byte FIFO */
+ remainder = count % 32;
+
+ if(loops) {
+ for(i=0; i<loops; i++) {
+ iic_outw(adap, ITE_I2CFBCR, 32);
+ if (sread)
+ iic_outw(adap, ITE_I2CHCR, ITE_SREAD);
+ else
+ iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */
+
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read timeout.\n", i2c_adap->name);
+ return (-1);
+ }
+#ifndef STUB_I2C
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name);
+ return (-1);
+ }
+#endif
+
+ timeout = wait_for_fe(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name);
+ return (-1);
+ }
+
+ for(j=0; j<32/2; j++) {
+ tmp.word = iic_inw(adap, ITE_I2CFDR);
+ buf[rdcount++] = tmp.byte[1];
+ buf[rdcount++] = tmp.byte[0];
+ }
+
+ /* status FIFO underrun */
+ iic_inw(adap, ITE_I2CFSR);
+
+ }
+ }
+
+
+ if(remainder) {
+ remainder=(remainder+1)/2 * 2;
+ iic_outw(adap, ITE_I2CFBCR, remainder);
+ if (sread)
+ iic_outw(adap, ITE_I2CHCR, ITE_SREAD);
+ else
+ iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */
+
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read timeout.\n", i2c_adap->name);
+ return (-1);
+ }
+#ifndef STUB_I2C
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name);
+ return (-1);
+ }
+#endif
+ timeout = wait_for_fe(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name);
+ return (-1);
+ }
+
+ for(i=0; i<(remainder+1)/2; i++) {
+ tmp.word = iic_inw(adap, ITE_I2CFDR);
+ buf[rdcount++] = tmp.byte[1];
+ buf[rdcount++] = tmp.byte[0];
+ }
+
+ /* status FIFO underrun */
+ iic_inw(adap, ITE_I2CFSR);
+
+ }
+
+ iic_stop(adap);
+ return rdcount;
+}
+
+
+/* This function implements combined transactions. Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+#if 0
+static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+ int i;
+ struct i2c_msg *pmsg;
+ int ret;
+
+ DEB2(printk("Beginning combined transaction\n"));
+
+ for(i=0; i<(num-1); i++) {
+ pmsg = &msgs[i];
+ if(pmsg->flags & I2C_M_RD) {
+ DEB2(printk(" This one is a read\n"));
+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER);
+ }
+ else if(!(pmsg->flags & I2C_M_RD)) {
+ DEB2(printk("This one is a write\n"));
+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER);
+ }
+ }
+ /* Last read or write segment needs to be terminated with a stop */
+ pmsg = &msgs[i];
+
+ if(pmsg->flags & I2C_M_RD) {
+ DEB2(printk("Doing the last read\n"));
+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+ }
+ else if(!(pmsg->flags & I2C_M_RD)) {
+ DEB2(printk("Doing the last write\n"));
+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+ }
+
+ return ret;
+}
+#endif
+
+
+/* Whenever we initiate a transaction, the first byte clocked
+ * onto the bus after the start condition is the address (7 bit) of the
+ * device we want to talk to. This function manipulates the address specified
+ * so that it makes sense to the hardware when written to the IIC peripheral.
+ *
+ * Note: 10 bit addresses are not supported in this driver, although they are
+ * supported by the hardware. This functionality needs to be implemented.
+ */
+static inline int iic_doAddress(struct i2c_algo_iic_data *adap,
+ struct i2c_msg *msg, int retries)
+{
+ unsigned short flags = msg->flags;
+ unsigned int addr;
+ int ret;
+
+/* Ten bit addresses not supported right now */
+ if ( (flags & I2C_M_TEN) ) {
+#if 0
+ addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+ DEB2(printk("addr0: %d\n",addr));
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("iic_doAddress: died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ iic_outw(adap,msg->addr & 0x7f);
+ if (ret != 1) {
+ printk("iic_doAddress: died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ if ( flags & I2C_M_RD ) {
+ i2c_repstart(adap);
+ addr |= 0x01;
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("iic_doAddress: died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+#endif
+ } else {
+
+ addr = ( msg->addr << 1 );
+
+#if 0
+ if (flags & I2C_M_RD )
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR )
+ addr ^= 1;
+#endif
+
+ if (iic_inw(adap, ITE_I2CSAR) != addr) {
+ iic_outw(adap, ITE_I2CSAR, addr);
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("iic_doAddress: died at address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+
+/* Description: Prepares the controller for a transaction (clearing status
+ * registers, data buffers, etc), and then calls either iic_readbytes or
+ * iic_sendbytes to do the actual transaction.
+ *
+ * still to be done: Before we issue a transaction, we should
+ * verify that the bus is not busy or in some unknown state.
+ */
+static int iic_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i = 0;
+ int ret, timeout;
+
+ pmsg = &msgs[i];
+
+ if(!pmsg->len) {
+ DEB2(printk("iic_xfer: read/write length is 0\n");)
+ return -EIO;
+ }
+ if(!(pmsg->flags & I2C_M_RD) && (!(pmsg->len)%2) ) {
+ DEB2(printk("iic_xfer: write buffer length is not odd\n");)
+ return -EIO;
+ }
+
+ /* Wait for any pending transfers to complete */
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk("iic_xfer: Timeout waiting for host not busy\n");)
+ return -EIO;
+ }
+
+ /* Flush FIFO */
+ iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
+
+ /* Load address */
+ ret = iic_doAddress(adap, pmsg, i2c_adap->retries);
+ if (ret)
+ return -EIO;
+
+#if 0
+ /* Combined transaction (read and write) */
+ if(num > 1) {
+ DEB2(printk("iic_xfer: Call combined transaction\n"));
+ ret = iic_combined_transaction(i2c_adap, msgs, num);
+ }
+#endif
+
+ DEB3(printk("iic_xfer: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+ i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+
+ if(pmsg->flags & I2C_M_RD) /* Read */
+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, 0);
+ else { /* Write */
+ udelay(1000);
+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
+ }
+
+ if (ret != pmsg->len)
+ DEB3(printk("iic_xfer: error or fail on read/write %d bytes.\n",ret));
+ else
+ DEB3(printk("iic_xfer: read/write %d bytes.\n",ret));
+
+ return ret;
+}
+
+
+/* Implements device specific ioctls. Higher level ioctls can
+ * be found in i2c-core.c and are typical of any i2c controller (specifying
+ * slave address, timeouts, etc). These ioctls take advantage of any hardware
+ * features built into the controller for which this algorithm-adapter set
+ * was written. These ioctls allow you to take control of the data and clock
+ * lines and set the either high or low,
+ * similar to a GPIO pin.
+ */
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+
+ struct i2c_algo_iic_data *adap = adapter->algo_data;
+ struct i2c_iic_msg s_msg;
+ char *buf;
+ int ret;
+
+ if (cmd == I2C_SREAD) {
+ if(copy_from_user(&s_msg, (struct i2c_iic_msg *)arg,
+ sizeof(struct i2c_iic_msg)))
+ return -EFAULT;
+ buf = kmalloc(s_msg.len, GFP_KERNEL);
+ if (buf== NULL)
+ return -ENOMEM;
+
+ /* Flush FIFO */
+ iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
+
+ /* Load address */
+ iic_outw(adap, ITE_I2CSAR,s_msg.addr<<1);
+ iic_outw(adap, ITE_I2CSSAR,s_msg.waddr & 0xff);
+
+ ret = iic_readbytes(adapter, buf, s_msg.len, 1);
+ if (ret>=0) {
+ if(copy_to_user( s_msg.buf, buf, s_msg.len) )
+ ret = -EFAULT;
+ }
+ kfree(buf);
+ }
+ return 0;
+}
+
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm iic_algo = {
+ .name = "ITE IIC algorithm",
+ .id = I2C_ALGO_IIC,
+ .master_xfer = iic_xfer,
+ .algo_control = algo_control, /* ioctl */
+ .functionality = iic_func,
+};
+
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_iic_add_bus(struct i2c_adapter *adap)
+{
+ struct i2c_algo_iic_data *iic_adap = adap->algo_data;
+
+ if (iic_test) {
+ int ret = test_bus(iic_adap, adap->name);
+ if (ret<0)
+ return -ENODEV;
+ }
+
+ DEB2(printk("i2c-algo-ite: hw routines for %s registered.\n",
+ adap->name));
+
+ /* register new adapter to i2c module... */
+
+ adap->id |= iic_algo.id;
+ adap->algo = &iic_algo;
+
+ adap->timeout = 100; /* default values, should */
+ adap->retries = 3; /* be replaced by defines */
+ adap->flags = 0;
+
+ i2c_add_adapter(adap);
+ iic_init(iic_adap);
+
+ return 0;
+}
+
+
+int i2c_iic_del_bus(struct i2c_adapter *adap)
+{
+ int res;
+ if ((res = i2c_del_adapter(adap)) < 0)
+ return res;
+ DEB2(printk("i2c-algo-ite: adapter unregistered: %s\n",adap->name));
+
+ return 0;
+}
+
+
+int __init i2c_algo_iic_init (void)
+{
+ printk(KERN_INFO "ITE iic (i2c) algorithm module\n");
+ return 0;
+}
+
+
+void i2c_algo_iic_exit(void)
+{
+ return;
+}
+
+
+EXPORT_SYMBOL(i2c_iic_add_bus);
+EXPORT_SYMBOL(i2c_iic_del_bus);
+
+/* The MODULE_* macros resolve to nothing if MODULES is not defined
+ * when this file is compiled.
+ */
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("ITE iic algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(iic_test, bool, 0);
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available");
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
+
+
+/* This function resolves to init_module (the function invoked when a module
+ * is loaded via insmod) when this file is compiled with MODULES defined.
+ * Otherwise (i.e. if you want this driver statically linked to the kernel),
+ * a pointer to this function is stored in a table and called
+ * during the initialization of the kernel (in do_basic_setup in /init/main.c)
+ *
+ * All this functionality is complements of the macros defined in linux/init.h
+ */
+module_init(i2c_algo_iic_init);
+
+
+/* If MODULES is defined when this file is compiled, then this function will
+ * resolved to cleanup_module.
+ */
+module_exit(i2c_algo_iic_exit);
diff --git a/drivers/i2c/algos/i2c-algo-ite.h b/drivers/i2c/algos/i2c-algo-ite.h
new file mode 100644
index 000000000000..a8ca3c9b546a
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-ite.h
@@ -0,0 +1,117 @@
+/*
+ --------------------------------------------------------------------
+ i2c-ite.h: Global defines for the I2C controller on board the
+ ITE MIPS processor.
+ --------------------------------------------------------------------
+ Hai-Pao Fan, MontaVista Software, Inc.
+ hpfan@mvista.com or source@mvista.com
+
+ Copyright 2001 MontaVista Software Inc.
+
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+
+ */
+
+#ifndef I2C_ITE_H
+#define I2C_ITE_H 1
+
+#include <asm/it8172/it8172.h>
+
+/* I2C Registers */
+#define ITE_I2CHCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x30
+#define ITE_I2CHSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x34
+#define ITE_I2CSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x38
+#define ITE_I2CSSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x3c
+#define ITE_I2CCKCNT IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x48
+#define ITE_I2CSHDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x4c
+#define ITE_I2CRSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x50
+#define ITE_I2CPSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x54
+
+#define ITE_I2CFDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x70
+#define ITE_I2CFBCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x74
+#define ITE_I2CFCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x78
+#define ITE_I2CFSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x7c
+
+
+/* Host Control Register ITE_I2CHCR */
+#define ITE_I2CHCR_HCE 0x01 /* Enable I2C Host Controller */
+#define ITE_I2CHCR_IE 0x02 /* Enable the interrupt after completing
+ the current transaction */
+#define ITE_I2CHCR_CP_W 0x00 /* bit2-4 000 - Write */
+#define ITE_I2CHCR_CP_R 0x08 /* 010 - Current address read */
+#define ITE_I2CHCR_CP_S 0x10 /* 100 - Sequential read */
+#define ITE_I2CHCR_ST 0x20 /* Initiates the I2C host controller to execute
+ the command and send the data programmed in
+ all required registers to I2C bus */
+#define ITE_CMD ITE_I2CHCR_HCE | ITE_I2CHCR_IE | ITE_I2CHCR_ST
+#define ITE_WRITE ITE_CMD | ITE_I2CHCR_CP_W
+#define ITE_READ ITE_CMD | ITE_I2CHCR_CP_R
+#define ITE_SREAD ITE_CMD | ITE_I2CHCR_CP_S
+
+/* Host Status Register ITE_I2CHSR */
+#define ITE_I2CHSR_DB 0x01 /* Device is busy, receives NACK response except
+ in the first and last bytes */
+#define ITE_I2CHSR_DNE 0x02 /* Target address on I2C bus does not exist */
+#define ITE_I2CHSR_TDI 0x04 /* R/W Transaction on I2C bus was completed */
+#define ITE_I2CHSR_HB 0x08 /* Host controller is processing transactions */
+#define ITE_I2CHSR_FER 0x10 /* Error occurs in the FIFO */
+
+/* Slave Address Register ITE_I2CSAR */
+#define ITE_I2CSAR_SA_MASK 0xfe /* Target I2C device address */
+#define ITE_I2CSAR_ASO 0x0100 /* Output 1/0 to I2CAS port when the
+ next slave address is addressed */
+
+/* Slave Sub-address Register ITE_I2CSSAR */
+#define ITE_I2CSSAR_SUBA_MASK 0xff /* Target I2C device sub-address */
+
+/* Clock Counter Register ITE_I2CCKCNT */
+#define ITE_I2CCKCNT_STOP 0x00 /* stop I2C clock */
+#define ITE_I2CCKCNT_HPCC_MASK 0x7f /* SCL high period counter */
+#define ITE_I2CCKCNT_LPCC_MASK 0x7f00 /* SCL low period counter */
+
+/* START Hold Time Register ITE_I2CSHDR */
+/* value is counted based on 16 MHz internal clock */
+#define ITE_I2CSHDR_FM 0x0a /* START condition at fast mode */
+#define ITE_I2CSHDR_SM 0x47 /* START contition at standard mode */
+
+/* (Repeated) START Setup Time Register ITE_I2CRSUR */
+/* value is counted based on 16 MHz internal clock */
+#define ITE_I2CRSUR_FM 0x0a /* repeated START condition at fast mode */
+#define ITE_I2CRSUR_SM 0x50 /* repeated START condition at standard mode */
+
+/* STOP setup Time Register ITE_I2CPSUR */
+
+/* FIFO Data Register ITE_I2CFDR */
+#define ITE_I2CFDR_MASK 0xff
+
+/* FIFO Byte Count Register ITE_I2CFBCR */
+#define ITE_I2CFBCR_MASK 0x3f
+
+/* FIFO Control Register ITE_I2CFCR */
+#define ITE_I2CFCR_FLUSH 0x01 /* Flush FIFO and reset the FIFO point
+ and I2CFSR */
+/* FIFO Status Register ITE_I2CFSR */
+#define ITE_I2CFSR_FO 0x01 /* FIFO is overrun when write */
+#define ITE_I2CFSR_FU 0x02 /* FIFO is underrun when read */
+#define ITE_I2CFSR_FF 0x04 /* FIFO is full when write */
+#define ITE_I2CFSR_FE 0x08 /* FIFO is empty when read */
+
+#endif /* I2C_ITE_H */
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
new file mode 100644
index 000000000000..c3d912cbbbc3
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -0,0 +1,399 @@
+/*
+ * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
+ * Copyright (C) 2004 Arcom Control Systems
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+#include "i2c-algo-pca.h"
+
+#define DRIVER "i2c-algo-pca"
+
+#define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0)
+#define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0)
+#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0)
+
+static int i2c_debug=0;
+
+#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val)
+#define pca_inw(adap, reg) adap->read_byte(adap, reg)
+
+#define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
+#define pca_clock(adap) adap->get_clock(adap)
+#define pca_own(adap) adap->get_own(adap)
+#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
+#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
+#define pca_wait(adap) adap->wait_for_interrupt(adap)
+
+/*
+ * Generate a start condition on the i2c bus.
+ *
+ * returns after the start condition has occured
+ */
+static void pca_start(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== START\n");
+ sta |= I2C_PCA_CON_STA;
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+ pca_wait(adap);
+}
+
+/*
+ * Generate a repeated start condition on the i2c bus
+ *
+ * return after the repeated start condition has occured
+ */
+static void pca_repeated_start(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== REPEATED START\n");
+ sta |= I2C_PCA_CON_STA;
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+ pca_wait(adap);
+}
+
+/*
+ * Generate a stop condition on the i2c bus
+ *
+ * returns after the stop condition has been generated
+ *
+ * STOPs do not generate an interrupt or set the SI flag, since the
+ * part returns the the idle state (0xf8). Hence we don't need to
+ * pca_wait here.
+ */
+static void pca_stop(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== STOP\n");
+ sta |= I2C_PCA_CON_STO;
+ sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+}
+
+/*
+ * Send the slave address and R/W bit
+ *
+ * returns after the address has been sent
+ */
+static void pca_address(struct i2c_algo_pca_data *adap,
+ struct i2c_msg *msg)
+{
+ int sta = pca_get_con(adap);
+ int addr;
+
+ addr = ( (0x7f & msg->addr) << 1 );
+ if (msg->flags & I2C_M_RD )
+ addr |= 1;
+ DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
+ msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
+
+ pca_outw(adap, I2C_PCA_DAT, addr);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+
+ pca_wait(adap);
+}
+
+/*
+ * Transmit a byte.
+ *
+ * Returns after the byte has been transmitted
+ */
+static void pca_tx_byte(struct i2c_algo_pca_data *adap,
+ __u8 b)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== WRITE %#04x\n", b);
+ pca_outw(adap, I2C_PCA_DAT, b);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+
+ pca_wait(adap);
+}
+
+/*
+ * Receive a byte
+ *
+ * returns immediately.
+ */
+static void pca_rx_byte(struct i2c_algo_pca_data *adap,
+ __u8 *b, int ack)
+{
+ *b = pca_inw(adap, I2C_PCA_DAT);
+ DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
+}
+
+/*
+ * Setup ACK or NACK for next received byte and wait for it to arrive.
+ *
+ * Returns after next byte has arrived.
+ */
+static void pca_rx_ack(struct i2c_algo_pca_data *adap,
+ int ack)
+{
+ int sta = pca_get_con(adap);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA);
+
+ if ( ack )
+ sta |= I2C_PCA_CON_AA;
+
+ pca_set_con(adap, sta);
+ pca_wait(adap);
+}
+
+/*
+ * Reset the i2c bus / SIO
+ */
+static void pca_reset(struct i2c_algo_pca_data *adap)
+{
+ /* apparently only an external reset will do it. not a lot can be done */
+ printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n");
+}
+
+static int pca_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *msg = NULL;
+ int curmsg;
+ int numbytes = 0;
+ int state;
+ int ret;
+
+ state = pca_status(adap);
+ if ( state != 0xF8 ) {
+ dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state );
+ /* FIXME: what to do. Force stop ? */
+ return -EREMOTEIO;
+ }
+
+ DEB1("{{{ XFER %d messages\n", num);
+
+ if (i2c_debug>=2) {
+ for (curmsg = 0; curmsg < num; curmsg++) {
+ int addr, i;
+ msg = &msgs[curmsg];
+
+ addr = (0x7f & msg->addr) ;
+
+ if (msg->flags & I2C_M_RD )
+ printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
+ curmsg, msg->len, addr, (addr<<1) | 1);
+ else {
+ printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s",
+ curmsg, msg->len, addr, addr<<1,
+ msg->len == 0 ? "" : ", ");
+ for(i=0; i < msg->len; i++)
+ printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", ");
+ printk("]\n");
+ }
+ }
+ }
+
+ curmsg = 0;
+ ret = -EREMOTEIO;
+ while (curmsg < num) {
+ state = pca_status(adap);
+
+ DEB3("STATE is 0x%02x\n", state);
+ msg = &msgs[curmsg];
+
+ switch (state) {
+ case 0xf8: /* On reset or stop the bus is idle */
+ pca_start(adap);
+ break;
+
+ case 0x08: /* A START condition has been transmitted */
+ case 0x10: /* A repeated start condition has been transmitted */
+ pca_address(adap, msg);
+ break;
+
+ case 0x18: /* SLA+W has been transmitted; ACK has been received */
+ case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
+ if (numbytes < msg->len) {
+ pca_tx_byte(adap, msg->buf[numbytes]);
+ numbytes++;
+ break;
+ }
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ pca_repeated_start(adap);
+ break;
+
+ case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after SLA+W\n");
+ pca_stop(adap);
+ goto out;
+
+ case 0x40: /* SLA+R has been transmitted; ACK has been received */
+ pca_rx_ack(adap, msg->len > 1);
+ break;
+
+ case 0x50: /* Data bytes has been received; ACK has been returned */
+ if (numbytes < msg->len) {
+ pca_rx_byte(adap, &msg->buf[numbytes], 1);
+ numbytes++;
+ pca_rx_ack(adap, numbytes < msg->len - 1);
+ break;
+ }
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ pca_repeated_start(adap);
+ break;
+
+ case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after SLA+R\n");
+ pca_stop(adap);
+ goto out;
+
+ case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after data byte\n");
+ goto out;
+
+ case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
+ DEB2("Arbitration lost\n");
+ goto out;
+
+ case 0x58: /* Data byte has been received; NOT ACK has been returned */
+ if ( numbytes == msg->len - 1 ) {
+ pca_rx_byte(adap, &msg->buf[numbytes], 0);
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ pca_repeated_start(adap);
+ } else {
+ DEB2("NOT ACK sent after data byte received. "
+ "Not final byte. numbytes %d. len %d\n",
+ numbytes, msg->len);
+ pca_stop(adap);
+ goto out;
+ }
+ break;
+ case 0x70: /* Bus error - SDA stuck low */
+ DEB2("BUS ERROR - SDA Stuck low\n");
+ pca_reset(adap);
+ goto out;
+ case 0x90: /* Bus error - SCL stuck low */
+ DEB2("BUS ERROR - SCL Stuck low\n");
+ pca_reset(adap);
+ goto out;
+ case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
+ DEB2("BUS ERROR - Illegal START or STOP\n");
+ pca_reset(adap);
+ goto out;
+ default:
+ printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state);
+ break;
+ }
+
+ }
+
+ ret = curmsg;
+ out:
+ DEB1(KERN_CRIT "}}} transfered %d/%d messages. "
+ "status is %#04x. control is %#04x\n",
+ curmsg, num, pca_status(adap),
+ pca_get_con(adap));
+ return ret;
+}
+
+static u32 pca_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int pca_init(struct i2c_algo_pca_data *adap)
+{
+ static int freqs[] = {330,288,217,146,88,59,44,36};
+ int own, clock;
+
+ own = pca_own(adap);
+ clock = pca_clock(adap);
+ DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own);
+ DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]);
+
+ pca_outw(adap, I2C_PCA_ADR, own << 1);
+
+ pca_set_con(adap, I2C_PCA_CON_ENSIO | clock);
+ udelay(500); /* 500 µs for oscilator to stabilise */
+
+ return 0;
+}
+
+static struct i2c_algorithm pca_algo = {
+ .name = "PCA9564 algorithm",
+ .id = I2C_ALGO_PCA,
+ .master_xfer = pca_xfer,
+ .functionality = pca_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pca_add_bus(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pca_data *pca_adap = adap->algo_data;
+ int rval;
+
+ /* register new adapter to i2c module... */
+
+ adap->id |= pca_algo.id;
+ adap->algo = &pca_algo;
+
+ adap->timeout = 100; /* default values, should */
+ adap->retries = 3; /* be replaced by defines */
+
+ rval = pca_init(pca_adap);
+
+ if (!rval)
+ i2c_add_adapter(adap);
+
+ return rval;
+}
+
+int i2c_pca_del_bus(struct i2c_adapter *adap)
+{
+ return i2c_del_adapter(adap);
+}
+
+EXPORT_SYMBOL(i2c_pca_add_bus);
+EXPORT_SYMBOL(i2c_pca_del_bus);
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, 0);
diff --git a/drivers/i2c/algos/i2c-algo-pca.h b/drivers/i2c/algos/i2c-algo-pca.h
new file mode 100644
index 000000000000..2fee07e05211
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pca.h
@@ -0,0 +1,26 @@
+#ifndef I2C_PCA9564_H
+#define I2C_PCA9564_H 1
+
+#define I2C_PCA_STA 0x00 /* STATUS Read Only */
+#define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */
+#define I2C_PCA_DAT 0x01 /* DATA Read/Write */
+#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */
+#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */
+
+#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */
+#define I2C_PCA_CON_ENSIO 0x40 /* Enable */
+#define I2C_PCA_CON_STA 0x20 /* Start */
+#define I2C_PCA_CON_STO 0x10 /* Stop */
+#define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */
+#define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */
+
+#define I2C_PCA_CON_330kHz 0x00
+#define I2C_PCA_CON_288kHz 0x01
+#define I2C_PCA_CON_217kHz 0x02
+#define I2C_PCA_CON_146kHz 0x03
+#define I2C_PCA_CON_88kHz 0x04
+#define I2C_PCA_CON_59kHz 0x05
+#define I2C_PCA_CON_44kHz 0x06
+#define I2C_PCA_CON_36kHz 0x07
+
+#endif /* I2C_PCA9564_H */
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
new file mode 100644
index 000000000000..8d087dac32af
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -0,0 +1,507 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-1997 Simon G. Vogl
+ 1998-2000 Hans Berglund
+
+ 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. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+ Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+ <mbailey@littlefeet-inc.com> */
+
+/* Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
+ messages, proper stop/repstart signaling during receive,
+ added detect code */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include "i2c-algo-pcf.h"
+
+
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
+#define DEBPROTO(x) if (i2c_debug>=9) x;
+ /* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 16
+
+/* module parameters:
+ */
+static int i2c_debug;
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
+#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl)
+#define get_own(adap) adap->getown(adap->data)
+#define get_clock(adap) adap->getclock(adap->data)
+#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
+#define i2c_inb(adap) adap->getpcf(adap->data, 0)
+
+/* --- other auxiliary functions -------------------------------------- */
+
+static void i2c_start(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk("S "));
+ set_pcf(adap, 1, I2C_PCF_START);
+}
+
+static void i2c_repstart(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk(" Sr "));
+ set_pcf(adap, 1, I2C_PCF_REPSTART);
+}
+
+
+static void i2c_stop(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk("P\n"));
+ set_pcf(adap, 1, I2C_PCF_STOP);
+}
+
+static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
+
+ int timeout = DEF_TIMEOUT;
+ int status;
+
+ status = get_pcf(adap, 1);
+#ifndef STUB_I2C
+ while (timeout-- && !(status & I2C_PCF_BB)) {
+ udelay(100); /* wait for 100 us */
+ status = get_pcf(adap, 1);
+ }
+#endif
+ if (timeout <= 0) {
+ printk(KERN_ERR "Timeout waiting for Bus Busy\n");
+ }
+
+ return (timeout<=0);
+}
+
+
+static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
+
+ int timeout = DEF_TIMEOUT;
+
+ *status = get_pcf(adap, 1);
+#ifndef STUB_I2C
+ while (timeout-- && (*status & I2C_PCF_PIN)) {
+ adap->waitforpin();
+ *status = get_pcf(adap, 1);
+ }
+ if (*status & I2C_PCF_LAB) {
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+ *status));
+ /* Cleanup from LAB-- reset and enable ESO.
+ * This resets the PCF8584; since we've lost the bus, no
+ * further attempts should be made by callers to clean up
+ * (no i2c_stop() etc.)
+ */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ /* TODO: we should pause for a time period sufficient for any
+ * running I2C transaction to complete-- the arbitration
+ * logic won't work properly until the next START is seen.
+ */
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
+ get_pcf(adap,1)));
+ return(-EINTR);
+ }
+#endif
+ if (timeout <= 0)
+ return(-1);
+ else
+ return(0);
+}
+
+/*
+ * This should perform the 'PCF8584 initialization sequence' as described
+ * in the Philips IC12 data book (1995, Aug 29).
+ * There should be a 30 clock cycle wait after reset, I assume this
+ * has been fulfilled.
+ * There should be a delay at the end equal to the longest I2C message
+ * to synchronize the BB-bit (in multimaster systems). How long is
+ * this? I assume 1 second is always long enough.
+ *
+ * vdovikin: added detect code for PCF8584
+ */
+static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+{
+ unsigned char temp;
+
+ DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1)));
+
+ /* S1=0x80: S0 selected, serial interface off */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ /* check to see S1 now used as R/W ctrl -
+ PCF8584 does that when ESO is zero */
+ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+ return -ENXIO; /* definetly not PCF8584 */
+ }
+
+ /* load own address in S0, effective address is (own << 1) */
+ i2c_outb(adap, get_own(adap));
+ /* check it's really written */
+ if ((temp = i2c_inb(adap)) != get_own(adap)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* S1=0xA0, next byte in S2 */
+ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+ /* check to see S2 now selected */
+ if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* load clock register S2 */
+ i2c_outb(adap, get_clock(adap));
+ /* check it's really written, the only 5 lowest bits does matter */
+ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* Enable serial interface, idle, S0 selected */
+ set_pcf(adap, 1, I2C_PCF_IDLE);
+
+ /* check to see PCF is really idled and we can access status register */
+ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ printk(KERN_DEBUG "i2c-algo-pcf.o: deteted and initialized PCF8584.\n");
+
+ return 0;
+}
+
+
+/* ----- Utility functions
+ */
+
+static inline int try_address(struct i2c_algo_pcf_data *adap,
+ unsigned char addr, int retries)
+{
+ int i, status, ret = -1;
+ int wfp;
+ for (i=0;i<retries;i++) {
+ i2c_outb(adap, addr);
+ i2c_start(adap);
+ status = get_pcf(adap, 1);
+ if ((wfp = wait_for_pin(adap, &status)) >= 0) {
+ if ((status & I2C_PCF_LRB) == 0) {
+ i2c_stop(adap);
+ break; /* success! */
+ }
+ }
+ if (wfp == -EINTR) {
+ /* arbitration lost */
+ udelay(adap->udelay);
+ return -EINTR;
+ }
+ i2c_stop(adap);
+ udelay(adap->udelay);
+ }
+ DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i,
+ addr));
+ return ret;
+}
+
+
+static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+ int count, int last)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wrcount, status, timeout;
+
+ for (wrcount=0; wrcount<count; ++wrcount) {
+ DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
+ buf[wrcount]&0xff));
+ i2c_outb(adap, buf[wrcount]);
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ if (timeout == -EINTR) {
+ /* arbitration lost */
+ return -EINTR;
+ }
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#ifndef STUB_I2C
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n");
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#endif
+ }
+ if (last) {
+ i2c_stop(adap);
+ }
+ else {
+ i2c_repstart(adap);
+ }
+
+ return (wrcount);
+}
+
+
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+ int count, int last)
+{
+ int i, status;
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wfp;
+
+ /* increment number of bytes to read by one -- read dummy byte */
+ for (i = 0; i <= count; i++) {
+
+ if ((wfp = wait_for_pin(adap, &status))) {
+ if (wfp == -EINTR) {
+ /* arbitration lost */
+ return -EINTR;
+ }
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
+ return (-1);
+ }
+
+#ifndef STUB_I2C
+ if ((status & I2C_PCF_LRB) && (i != count)) {
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n");
+ return (-1);
+ }
+#endif
+
+ if (i == count - 1) {
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ } else
+ if (i == count) {
+ if (last) {
+ i2c_stop(adap);
+ } else {
+ i2c_repstart(adap);
+ }
+ };
+
+ if (i) {
+ buf[i - 1] = i2c_inb(adap);
+ } else {
+ i2c_inb(adap); /* dummy read */
+ }
+ }
+
+ return (i - 1);
+}
+
+
+static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+ struct i2c_msg *msg, int retries)
+{
+ unsigned short flags = msg->flags;
+ unsigned char addr;
+ int ret;
+ if ( (flags & I2C_M_TEN) ) {
+ /* a ten bit address */
+ addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+ DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+ /* try extended address code...*/
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk(KERN_ERR "died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ i2c_outb(adap,msg->addr & 0x7f);
+/* Status check comes here */
+ if (ret != 1) {
+ printk(KERN_ERR "died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ if ( flags & I2C_M_RD ) {
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk(KERN_ERR "died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = ( msg->addr << 1 );
+ if (flags & I2C_M_RD )
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR )
+ addr ^= 1;
+ i2c_outb(adap, addr);
+ }
+ return 0;
+}
+
+static int pcf_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i;
+ int ret=0, timeout, status;
+
+
+ /* Check for bus busy */
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
+ "Timeout waiting for BB in pcf_xfer\n");)
+ return -EIO;
+ }
+
+ for (i = 0;ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);)
+
+ ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
+
+ /* Send START */
+ if (i == 0) {
+ i2c_start(adap);
+ }
+
+ /* Wait for PIN (pending interrupt NOT) */
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ if (timeout == -EINTR) {
+ /* arbitration lost */
+ return (-EINTR);
+ }
+ i2c_stop(adap);
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
+ "for PIN(1) in pcf_xfer\n");)
+ return (-EREMOTEIO);
+ }
+
+#ifndef STUB_I2C
+ /* Check LRB (last rcvd bit - slave ack) */
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
+ return (-EREMOTEIO);
+ }
+#endif
+
+ DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+ i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+
+ /* Read */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read bytes into buffer*/
+ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
+
+ if (ret != pmsg->len) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+ "only read %d bytes.\n",ret));
+ } else {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
+ }
+ } else { /* Write */
+ ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
+
+ if (ret != pmsg->len) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+ "only wrote %d bytes.\n",ret));
+ } else {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+ }
+ }
+ }
+
+ return (i);
+}
+
+static u32 pcf_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm pcf_algo = {
+ .name = "PCF8584 algorithm",
+ .id = I2C_ALGO_PCF,
+ .master_xfer = pcf_xfer,
+ .functionality = pcf_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pcf_add_bus(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
+ int rval;
+
+ DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
+
+ /* register new adapter to i2c module... */
+
+ adap->id |= pcf_algo.id;
+ adap->algo = &pcf_algo;
+
+ adap->timeout = 100; /* default values, should */
+ adap->retries = 3; /* be replaced by defines */
+
+ rval = pcf_init_8584(pcf_adap);
+ if (!rval)
+ i2c_add_adapter(adap);
+ return rval;
+}
+
+
+int i2c_pcf_del_bus(struct i2c_adapter *adap)
+{
+ return i2c_del_adapter(adap);
+}
+
+EXPORT_SYMBOL(i2c_pcf_add_bus);
+EXPORT_SYMBOL(i2c_pcf_del_bus);
+
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff --git a/drivers/i2c/algos/i2c-algo-pcf.h b/drivers/i2c/algos/i2c-algo-pcf.h
new file mode 100644
index 000000000000..5263a9eeb8d7
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pcf.h
@@ -0,0 +1,76 @@
+/* -------------------------------------------------------------------- */
+/* i2c-pcf8584.h: PCF 8584 global defines */
+/* -------------------------------------------------------------------- */
+/* Copyright (C) 1996 Simon G. Vogl
+ 1999 Hans Berglund
+
+ 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. */
+/* -------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl> */
+
+#ifndef I2C_PCF8584_H
+#define I2C_PCF8584_H 1
+
+/* ----- Control register bits ---------------------------------------- */
+#define I2C_PCF_PIN 0x80
+#define I2C_PCF_ESO 0x40
+#define I2C_PCF_ES1 0x20
+#define I2C_PCF_ES2 0x10
+#define I2C_PCF_ENI 0x08
+#define I2C_PCF_STA 0x04
+#define I2C_PCF_STO 0x02
+#define I2C_PCF_ACK 0x01
+
+#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
+#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK)
+
+/* ----- Status register bits ----------------------------------------- */
+/*#define I2C_PCF_PIN 0x80 as above*/
+
+#define I2C_PCF_INI 0x40 /* 1 if not initialized */
+#define I2C_PCF_STS 0x20
+#define I2C_PCF_BER 0x10
+#define I2C_PCF_AD0 0x08
+#define I2C_PCF_LRB 0x08
+#define I2C_PCF_AAS 0x04
+#define I2C_PCF_LAB 0x02
+#define I2C_PCF_BB 0x01
+
+/* ----- Chip clock frequencies --------------------------------------- */
+#define I2C_PCF_CLK3 0x00
+#define I2C_PCF_CLK443 0x10
+#define I2C_PCF_CLK6 0x14
+#define I2C_PCF_CLK 0x18
+#define I2C_PCF_CLK12 0x1c
+
+/* ----- transmission frequencies ------------------------------------- */
+#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
+#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
+#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
+#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
+
+
+/* ----- Access to internal registers according to ES1,ES2 ------------ */
+/* they are mapped to the data port ( a0 = 0 ) */
+/* available when ESO == 0 : */
+
+#define I2C_PCF_OWNADR 0
+#define I2C_PCF_INTREG I2C_PCF_ES2
+#define I2C_PCF_CLKREG I2C_PCF_ES1
+
+#endif /* I2C_PCF8584_H */
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
new file mode 100644
index 000000000000..422721b241e5
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -0,0 +1,189 @@
+/*
+ * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-sgi.h>
+
+
+#define SGI_I2C_FORCE_IDLE (0 << 0)
+#define SGI_I2C_NOT_IDLE (1 << 0)
+#define SGI_I2C_WRITE (0 << 1)
+#define SGI_I2C_READ (1 << 1)
+#define SGI_I2C_RELEASE_BUS (0 << 2)
+#define SGI_I2C_HOLD_BUS (1 << 2)
+#define SGI_I2C_XFER_DONE (0 << 4)
+#define SGI_I2C_XFER_BUSY (1 << 4)
+#define SGI_I2C_ACK (0 << 5)
+#define SGI_I2C_NACK (1 << 5)
+#define SGI_I2C_BUS_OK (0 << 7)
+#define SGI_I2C_BUS_ERR (1 << 7)
+
+#define get_control() adap->getctrl(adap->data)
+#define set_control(val) adap->setctrl(adap->data, val)
+#define read_data() adap->rdata(adap->data)
+#define write_data(val) adap->wdata(adap->data, val)
+
+
+static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if ((get_control() & SGI_I2C_XFER_BUSY) == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ if (wait_xfer_done(adap))
+ return -ETIMEDOUT;
+ for (i = 0; i < adap->ack_timeout; i++) {
+ if ((get_control() & SGI_I2C_NACK) == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int force_idle(struct i2c_algo_sgi_data *adap)
+{
+ int i;
+
+ set_control(SGI_I2C_FORCE_IDLE);
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if ((get_control() & SGI_I2C_NOT_IDLE) == 0)
+ goto out;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+out:
+ if (get_control() & SGI_I2C_BUS_ERR)
+ return -EIO;
+ return 0;
+}
+
+static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
+ int rd)
+{
+ if (rd)
+ set_control(SGI_I2C_NOT_IDLE);
+ /* Check if bus is idle, eventually force it to do so */
+ if (get_control() & SGI_I2C_NOT_IDLE)
+ if (force_idle(adap))
+ return -EIO;
+ /* Write out the i2c chip address and specify operation */
+ set_control(SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
+ if (rd)
+ addr |= 1;
+ write_data(addr);
+ if (wait_ack(adap))
+ return -EIO;
+ return 0;
+}
+
+static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ set_control(SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
+ for (i = 0; i < len; i++) {
+ if (wait_xfer_done(adap))
+ return -EIO;
+ buf[i] = read_data();
+ }
+ set_control(SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
+
+ return 0;
+
+}
+
+static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ /* We are already in write state */
+ for (i = 0; i < len; i++) {
+ write_data(buf[i]);
+ if (wait_ack(adap))
+ return -EIO;
+ }
+ return 0;
+}
+
+static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *p;
+ int i, err = 0;
+
+ for (i = 0; !err && i < num; i++) {
+ p = &msgs[i];
+ err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+ if (err || !p->len)
+ continue;
+ if (p->flags & I2C_M_RD)
+ err = i2c_read(adap, p->buf, p->len);
+ else
+ err = i2c_write(adap, p->buf, p->len);
+ }
+
+ return err;
+}
+
+static u32 sgi_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm sgi_algo = {
+ .name = "SGI algorithm",
+ .id = I2C_ALGO_SGI,
+ .master_xfer = sgi_xfer,
+ .functionality = sgi_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_sgi_add_bus(struct i2c_adapter *adap)
+{
+ adap->id |= sgi_algo.id;
+ adap->algo = &sgi_algo;
+
+ return i2c_add_adapter(adap);
+}
+
+
+int i2c_sgi_del_bus(struct i2c_adapter *adap)
+{
+ return i2c_del_adapter(adap);
+}
+
+EXPORT_SYMBOL(i2c_sgi_add_bus);
+EXPORT_SYMBOL(i2c_sgi_del_bus);
+
+MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
+MODULE_DESCRIPTION("I2C-Bus SGI algorithm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
new file mode 100644
index 000000000000..35789bb7126a
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-sibyte.c
@@ -0,0 +1,222 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-sibyte.c i2c driver algorithms for bit-shift adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2001,2002,2003 Broadcom Corporation
+ Copyright (C) 1995-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. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+ Frodo Looijaard <frodol@dds.nl>. */
+
+/* Ported for SiByte SOCs by Broadcom Corporation. */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_smbus.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-sibyte.h>
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+/* ----- global variables --------------------------------------------- */
+
+/* module parameters:
+ */
+static int bit_scan=0; /* have a look at what's hanging 'round */
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+ int data_bytes = 0;
+ int error;
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ csr_out32((V_SMB_ADDR(addr) | (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_LB(data->byte), SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 2;
+ } else {
+ csr_out32(V_SMB_LB(data->word & 0xff), SMB_CSR(adap, R_SMB_DATA));
+ csr_out32(V_SMB_MB(data->word >> 8), SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ default:
+ return -1; /* XXXKW better error code? */
+ }
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+ if (error & M_SMB_ERROR) {
+ /* Clear error bit by writing a 1 */
+ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+ return -1; /* XXXKW better error code? */
+ }
+
+ if (data_bytes == 1)
+ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+ if (data_bytes == 2)
+ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+ return 0;
+}
+
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm i2c_sibyte_algo = {
+ .name = "SiByte algorithm",
+ .id = I2C_ALGO_SIBYTE,
+ .smbus_xfer = smbus_xfer,
+ .algo_control = algo_control, /* ioctl */
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+ int i;
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+ /* register new adapter to i2c module... */
+
+ i2c_adap->id |= i2c_sibyte_algo.id;
+ i2c_adap->algo = &i2c_sibyte_algo;
+
+ /* Set the frequency to 100 kHz */
+ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+ /* scan bus */
+ if (bit_scan) {
+ union i2c_smbus_data data;
+ int rc;
+ printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
+ i2c_adap->name);
+ for (i = 0x00; i < 0x7f; i++) {
+ /* XXXKW is this a realistic probe? */
+ rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (!rc) {
+ printk("(%02x)",i);
+ } else
+ printk(".");
+ }
+ printk("\n");
+ }
+
+ i2c_add_adapter(i2c_adap);
+
+ return 0;
+}
+
+
+int i2c_sibyte_del_bus(struct i2c_adapter *adap)
+{
+ int res;
+
+ if ((res = i2c_del_adapter(adap)) < 0)
+ return res;
+
+ return 0;
+}
+
+int __init i2c_algo_sibyte_init (void)
+{
+ printk("i2c-algo-sibyte.o: i2c SiByte algorithm module\n");
+ return 0;
+}
+
+
+EXPORT_SYMBOL(i2c_sibyte_add_bus);
+EXPORT_SYMBOL(i2c_sibyte_del_bus);
+
+#ifdef MODULE
+MODULE_AUTHOR("Kip Walker, Broadcom Corp.");
+MODULE_DESCRIPTION("SiByte I2C-Bus algorithm");
+MODULE_PARM(bit_scan, "i");
+MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+ return i2c_algo_sibyte_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif