summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
commit99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch)
tree3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/i2c
parente73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff)
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/.cvsignore2
-rw-r--r--drivers/i2c/Config.in29
-rw-r--r--drivers/i2c/Makefile98
-rw-r--r--drivers/i2c/i2c-algo-bit.c655
-rw-r--r--drivers/i2c/i2c-algo-pcf.c609
-rw-r--r--drivers/i2c/i2c-core.c1369
-rw-r--r--drivers/i2c/i2c-dev.c557
-rw-r--r--drivers/i2c/i2c-elektor.c327
-rw-r--r--drivers/i2c/i2c-elv.c236
-rw-r--r--drivers/i2c/i2c-pcf8584.h78
-rw-r--r--drivers/i2c/i2c-philips-par.c232
-rw-r--r--drivers/i2c/i2c-velleman.c219
12 files changed, 4411 insertions, 0 deletions
diff --git a/drivers/i2c/.cvsignore b/drivers/i2c/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/i2c/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/i2c/Config.in b/drivers/i2c/Config.in
new file mode 100644
index 000000000..ba533aac0
--- /dev/null
+++ b/drivers/i2c/Config.in
@@ -0,0 +1,29 @@
+#
+# Character device configuration
+#
+mainmenu_option next_comment
+comment 'I2C support'
+
+tristate 'I2C support' CONFIG_I2C
+
+if [ "$CONFIG_I2C" != "n" ]; then
+
+ dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C
+ if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
+ dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT
+ dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
+ dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+ fi
+
+ dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
+ if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then
+ dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF
+ fi
+
+# This is needed for automatic patch generation: sensors code starts here
+# This is needed for automatic patch generation: sensors code ends here
+
+ dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
+
+fi
+endmenu
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
new file mode 100644
index 000000000..7c0abfc24
--- /dev/null
+++ b/drivers/i2c/Makefile
@@ -0,0 +1,98 @@
+#
+# Makefile for the kernel i2c bus driver.
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+MOD_LIST_NAME := I2C_MODULES
+
+L_TARGET := i2c.a
+MX_OBJS :=
+M_OBJS :=
+LX_OBJS :=
+L_OBJS :=
+
+# -----
+# i2c core components
+# -----
+
+ifeq ($(CONFIG_I2C),y)
+ LX_OBJS += i2c-core.o
+else
+ ifeq ($(CONFIG_I2C),m)
+ MX_OBJS += i2c-core.o
+ endif
+endif
+
+ifeq ($(CONFIG_I2C_CHARDEV),y)
+ L_OBJS += i2c-dev.o
+else
+ ifeq ($(CONFIG_I2C_CHARDEV),m)
+ M_OBJS += i2c-dev.o
+ endif
+endif
+
+# -----
+# Bit banging adapters...
+# -----
+
+ifeq ($(CONFIG_I2C_ALGOBIT),y)
+ LX_OBJS += i2c-algo-bit.o
+else
+ ifeq ($(CONFIG_I2C_ALGOBIT),m)
+ MX_OBJS += i2c-algo-bit.o
+ endif
+endif
+
+ifeq ($(CONFIG_I2C_PHILIPSPAR),y)
+ L_OBJS += i2c-philips-par.o
+else
+ ifeq ($(CONFIG_I2C_PHILIPSPAR),m)
+ M_OBJS += i2c-philips-par.o
+ endif
+endif
+
+ifeq ($(CONFIG_I2C_ELV),y)
+ L_OBJS += i2c-elv.o
+else
+ ifeq ($(CONFIG_I2C_ELV),m)
+ M_OBJS += i2c-elv.o
+ endif
+endif
+
+ifeq ($(CONFIG_I2C_VELLEMAN),y)
+ L_OBJS += i2c-velleman.o
+else
+ ifeq ($(CONFIG_I2C_VELLEMAN),m)
+ M_OBJS += i2c-velleman.o
+ endif
+endif
+
+
+
+# -----
+# PCF components
+# -----
+
+ifeq ($(CONFIG_I2C_ALGOPCF),y)
+ LX_OBJS += i2c-algo-pcf.o
+else
+ ifeq ($(CONFIG_I2C_ALGOPCF),m)
+ MX_OBJS += i2c-algo-pcf.o
+ endif
+endif
+
+ifeq ($(CONFIG_I2C_ELEKTOR),y)
+ L_OBJS += i2c-elektor.o
+else
+ ifeq ($(CONFIG_I2C_ELEKTOR),m)
+ M_OBJS += i2c-elektor.o
+ endif
+endif
+
+# This is needed for automatic patch generation: sensors code starts here
+# This is needed for automatic patch generation: sensors code ends here
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c
new file mode 100644
index 000000000..32a8514ee
--- /dev/null
+++ b/drivers/i2c/i2c-algo-bit.c
@@ -0,0 +1,655 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 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> */
+
+/* $Id: i2c-algo-bit.c,v 1.21 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020135
+#include <linux/init.h>
+#else
+#define __init
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+# include <asm/uaccess.h>
+#else
+# include <asm/segment.h>
+#endif
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/ioport.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 */
+
+/* debugging - slow down transfer to have a look at the data .. */
+/* I use this with two leds&resistors, each one connected to sda,scl */
+/* respectively. This makes sure that the algorithm works. Some chips */
+/* might not like this, as they have an internal timeout of some mils */
+/*
+#if LINUX_VERSION_CODE >= 0x02016e
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+#else
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+#endif
+*/
+
+
+/* ----- global variables --------------------------------------------- */
+
+#ifdef SLO_IO
+ int jif;
+#endif
+
+/* module parameters:
+ */
+static int i2c_debug=0;
+static int bit_test=0; /* see if the line-setting functions work */
+static int bit_scan=0; /* have a look at what's hanging 'round */
+
+/* --- 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);
+#ifdef SLO_IO
+ SLO_IO
+#endif
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static inline int sclhi(struct i2c_algo_bit_data *adap)
+{
+ int start=jiffies;
+
+ setscl(adap,1);
+
+ udelay(adap->udelay);
+
+ /* Not all adapters have scl sense line... */
+ if (adap->getscl == NULL )
+ return 0;
+
+ 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.
+ */
+ setscl(adap,1);
+ if (start+adap->timeout <= jiffies) {
+ return -ETIMEDOUT;
+ }
+#if LINUX_VERSION_CODE >= 0x02016e
+ if (current->need_resched)
+ schedule();
+#else
+ if (need_resched)
+ schedule();
+#endif
+ }
+ DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
+#ifdef SLO_IO
+ SLO_IO
+#endif
+ 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);
+ setscl(adap,1);
+ 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 occured (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 */
+ DEB2(printk(" i2c_outb:%2.2X\n",c&0xff));
+ for ( i=7 ; i>=0 ; i-- ) {
+ sb = c & ( 1 << i );
+ setsda(adap,sb);
+ udelay(adap->udelay);
+ DEBPROTO(printk("%d",sb!=0));
+ if (sclhi(adap)<0) { /* timed out */
+ sdahi(adap); /* we don't want to block the net */
+ 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 */
+ return -ETIMEDOUT;
+ };
+ /* read ack: SDA should be pulled down by slave */
+ ack=getsda(adap); /* ack: sda is pulled low ->success. */
+ DEB2(printk(" i2c_outb: getsda() = 0x%2.2x\n", ~ack ));
+
+ DEBPROTO( printk("[%2.2x]",c&0xff) );
+ DEBPROTO(if (0==ack){ printk(" A ");} else printk(" 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 */
+ DEB2(printk("i2c_inb.\n"));
+
+ sdahi(adap);
+ for (i=0;i<8;i++) {
+ if (sclhi(adap)<0) { /* timeout */
+ return -ETIMEDOUT;
+ };
+ indata *= 2;
+ if ( getsda(adap) )
+ indata |= 0x01;
+ scllo(adap);
+ }
+ /* assert: scl is low */
+ DEBPROTO(printk(" %2.2x", 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;
+ sda=getsda(adap);
+ if (adap->getscl==NULL) {
+ printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n");
+ return 0;
+ }
+ scl=getscl(adap);
+ printk("i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n",
+ name,getscl(adap),getsda(adap));
+ if (!scl || !sda ) {
+ printk("i2c-algo-bit.o: %s seems to be busy.\n",name);
+ goto bailout;
+ }
+ sdalo(adap);
+ printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getsda(adap) ) {
+ printk("i2c-algo-bit.o: %s SDA stuck high!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n",
+ name);
+ goto bailout;
+ }
+ sdahi(adap);
+ printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getsda(adap) ) {
+ printk("i2c-algo-bit.o: %s SDA stuck low!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",name);
+ goto bailout;
+ }
+ scllo(adap);
+ printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getscl(adap) ) {
+ printk("i2c-algo-bit.o: %s SCL stuck high!\n",name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n",
+ name);
+ goto bailout;
+ }
+ sclhi(adap);
+ printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getscl(adap) ) {
+ printk("i2c-algo-bit.o: %s SCL stuck low!\n",name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n",
+ name);
+ goto bailout;
+ }
+ printk("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("i2c-algo-bit.o: needed %d retries for %d\n",i,addr));
+ return ret;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ char c;
+ const char *temp = buf;
+ int retval;
+ int wrcount=0;
+
+ while (count > 0) {
+ c = *temp;
+ DEB2(printk("i2c-algo-bit.o: %s i2c_write: writing %2.2X\n",
+ i2c_adap->name, c&0xff));
+ retval = i2c_outb(i2c_adap,c);
+ if (retval>0) {
+ count--;
+ temp++;
+ wrcount++;
+ } else { /* arbitration or no acknowledge */
+ printk("i2c-algo-bit.o: %s i2c_write: error - bailout.\n",
+ i2c_adap->name);
+ 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,char *buf,int count)
+{
+ char *temp = buf;
+ int inval;
+ int rdcount=0; /* counts bytes read */
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ 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("i2c-algo-bit.o: i2c_read: i2c_inb timed out.\n");
+ break;
+ }
+
+ if ( count > 1 ) { /* 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("i2c-algo-bit.o: i2c_read: Timeout at ack\n");
+ return -ETIMEDOUT;
+ };
+ scllo(adap);
+ sdahi(adap);
+ temp++;
+ count--;
+ }
+ 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
+ * -x an error occured (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,
+ int retries)
+{
+ unsigned short flags = msg->flags;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ unsigned char addr;
+ int ret;
+ if ( (flags & I2C_M_TEN) ) {
+ /* a ten bit address */
+ addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+ DEB2(printk("addr0: %d\n",addr));
+ /* try extended address code...*/
+ ret = try_address(i2c_adap, addr, retries);
+ if (ret!=1) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
+ if (ret != 1) {
+ /* the chip did not ack / xmission error occured */
+ printk("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) {
+ printk("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = ( msg->addr << 1 );
+ if (flags & I2C_M_RD )
+ addr |= 1;
+ ret = try_address(i2c_adap, addr, retries);
+ if (ret!=1) {
+ 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;
+
+ i2c_start(adap);
+ for (i=0;i<num;i++) {
+ pmsg = &msgs[i];
+ ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries);
+ if (ret != 0) {
+ DEB2(printk("i2c-algo-bit.o: NAK from device adr %#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->buf,pmsg->len);
+ DEB2(printk("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->buf,pmsg->len);
+ DEB2(printk("i2c-algo-bit.o: wrote %d bytes.\n",ret));
+ if (ret < pmsg->len ) {
+ return (ret<0) ? ret : -EREMOTEIO;
+ }
+ }
+ if (i<num-1) {
+ i2c_repstart(adap);
+ }
+ }
+ i2c_stop(adap);
+ return num;
+}
+
+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_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm i2c_bit_algo = {
+ "Bit-shift algorithm",
+ I2C_ALGO_BIT,
+ bit_xfer,
+ NULL,
+ NULL, /* slave_xmit */
+ NULL, /* slave_recv */
+ algo_control, /* ioctl */
+ bit_func, /* functionality */
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+ int i;
+ 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(printk("i2c-algo-bit.o: hw routines for %s registered.\n",adap->name));
+
+ /* 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 */
+
+ /* scan bus */
+ if (bit_scan) {
+ int ack;
+ printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", adap->name);
+ for (i = 0x00; i < 0xff; i+=2) {
+ i2c_start(bit_adap);
+ ack = i2c_outb(adap,i);
+ i2c_stop(bit_adap);
+ if (ack>0) {
+ printk("(%02x)",i>>1);
+ } else
+ printk(".");
+ }
+ printk("\n");
+ }
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ i2c_add_adapter(adap);
+
+ return 0;
+}
+
+
+int i2c_bit_del_bus(struct i2c_adapter *adap)
+{
+
+ i2c_del_adapter(adap);
+
+ DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name));
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+int __init i2c_algo_bit_init (void)
+{
+ printk("i2c-algo-bit.o: i2c bit algorithm module\n");
+ return 0;
+}
+
+
+
+EXPORT_SYMBOL(i2c_bit_add_bus);
+EXPORT_SYMBOL(i2c_bit_del_bus);
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+
+MODULE_PARM(bit_test, "i");
+MODULE_PARM(bit_scan, "i");
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
+
+int init_module(void)
+{
+ return i2c_algo_bit_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/i2c-algo-pcf.c
new file mode 100644
index 000000000..2edf21f37
--- /dev/null
+++ b/drivers/i2c/i2c-algo-pcf.c
@@ -0,0 +1,609 @@
+
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+ 1998-99 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 even
+ Frodo Looijaard <frodol@dds.nl> */
+
+/* $Id: i2c-algo-pcf.c,v 1.15 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020135
+#include <linux/init.h>
+#else
+#define __init
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+# include <asm/uaccess.h>
+#else
+# include <asm/segment.h>
+#endif
+
+
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include "i2c-pcf8584.h"
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#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
+
+/* debugging - slow down transfer to have a look at the data .. */
+/* I use this with two leds&resistors, each one connected to sda,scl */
+/* respectively. This makes sure that the algorithm works. Some chips */
+/* might not like this, as they have an internal timeout of some mils */
+/*
+#if LINUX_VERSION_CODE >= 0x02016e
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+#else
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+#endif
+*/
+
+
+/* ----- global variables --------------------------------------------- */
+
+#ifdef SLO_IO
+ int jif;
+#endif
+
+/* module parameters:
+ */
+static int i2c_debug=1;
+static int pcf_test=0; /* see if the line-setting functions work */
+static int pcf_scan=0; /* have a look at what's hanging 'round */
+
+/* --- 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 -------------------------------------- */
+
+#if LINUX_VERSION_CODE < 0x02017f
+static void schedule_timeout(int j)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + j;
+ schedule();
+}
+#endif
+
+
+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);
+ while (timeout-- && !(status & I2C_PCF_BB)) {
+ udelay(1000); /* How much is this? */
+ status = get_pcf(adap, 1);
+ }
+ if (timeout<=0)
+ printk("Timeout waiting for Bus Busy\n");
+ /*
+ set_pcf(adap, 1, I2C_PCF_STOP);
+ */
+ return(timeout<=0);
+}
+
+
+static inline void pcf_sleep(unsigned long timeout)
+{
+ schedule_timeout( timeout * HZ);
+}
+
+
+static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
+
+ int timeout = DEF_TIMEOUT;
+
+ *status = get_pcf(adap, 1);
+ while (timeout-- && (*status & I2C_PCF_PIN)) {
+ adap->waitforpin();
+ *status = get_pcf(adap, 1);
+ }
+ 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.
+ */
+static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+{
+
+ /* S1=0x80: S0 selected, serial interface off */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+
+ /* load own address in S0, effective address is (own << 1) */
+ i2c_outb(adap, get_own(adap));
+
+ /* S1=0xA0, next byte in S2 */
+ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+
+ /* load clock register S2 */
+ i2c_outb(adap, get_clock(adap));
+
+ /* Enable serial interface, idle, S0 selected */
+ set_pcf(adap, 1, I2C_PCF_IDLE);
+
+ DEB2(printk("i2c-algo-pcf.o: irq: Initialized 8584.\n"));
+ 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_pcf_data *adap, char *name) {
+#if 0
+ int scl,sda;
+ sda=getsda(adap);
+ if (adap->getscl==NULL) {
+ printk("i2c-algo-pcf.o: Warning: Adapter can't read from clock line - skipping test.\n");
+ return 0;
+ }
+ scl=getscl(adap);
+ printk("i2c-algo-pcf.o: Adapter: %s scl: %d sda: %d -- testing...\n",
+ name,getscl(adap),getsda(adap));
+ if (!scl || !sda ) {
+ printk("i2c-algo-pcf.o: %s seems to be busy.\n",adap->name);
+ goto bailout;
+ }
+ sdalo(adap);
+ printk("i2c-algo-pcf.o:1 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getsda(adap) ) {
+ printk("i2c-algo-pcf.o: %s SDA stuck high!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c-algo-pcf.o: %s SCL unexpected low while pulling SDA low!\n",
+ name);
+ goto bailout;
+ }
+ sdahi(adap);
+ printk("i2c-algo-pcf.o:2 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getsda(adap) ) {
+ printk("i2c-algo-pcf.o: %s SDA stuck low!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("i2c-algo-pcf.o: %s SCL unexpected low while SDA high!\n",adap->name);
+ goto bailout;
+ }
+ scllo(adap);
+ printk("i2c-algo-pcf.o:3 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 != getscl(adap) ) {
+ printk("i2c-algo-pcf.o: %s SCL stuck high!\n",name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c-algo-pcf.o: %s SDA unexpected low while pulling SCL low!\n",
+ name);
+ goto bailout;
+ }
+ sclhi(adap);
+ printk("i2c-algo-pcf.o:4 scl: %d sda: %d \n",getscl(adap),getsda(adap));
+ if ( 0 == getscl(adap) ) {
+ printk("i2c-algo-pcf.o: %s SCL stuck low!\n",name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("i2c-algo-pcf.o: %s SDA unexpected low while SCL high!\n",
+ name);
+ goto bailout;
+ }
+ printk("i2c-algo-pcf.o: %s passed test.\n",name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+ return -ENODEV;
+#endif
+ 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;
+ for (i=0;i<retries;i++) {
+ i2c_outb(adap, addr);
+ i2c_start(adap);
+ status = get_pcf(adap, 1);
+ if (wait_for_pin(adap, &status) >= 0) {
+ if ((status && I2C_PCF_LRB) == 0) {
+ i2c_stop(adap);
+ break; /* success! */
+ }
+ }
+ i2c_stop(adap);
+ udelay(adap->udelay);
+ }
+ DEB2(if (i) printk("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)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wrcount, status, timeout;
+
+ for (wrcount=0; wrcount<count; ++wrcount) {
+ DEB2(printk("i2c-algo-pcf.o: %s i2c_write: writing %2.2X\n",
+ i2c_adap->name, buf[wrcount]&0xff));
+ i2c_outb(adap, buf[wrcount]);
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ printk("i2c-algo-pcf.o: %s i2c_write: error - timeout.\n",
+ i2c_adap->name);
+ i2c_stop(adap);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ if (status & I2C_PCF_LRB) {
+ printk("i2c-algo-pcf.o: %s i2c_write: error - no ack.\n",
+ i2c_adap->name);
+ i2c_stop(adap);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ }
+ return (wrcount);
+}
+
+
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+{
+ int rdcount=0, i, status, timeout, dummy=1;
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+
+ for (i=0; i<count-1; ++i) {
+ buf[rdcount] = i2c_inb(adap);
+ if (dummy) {
+ dummy = 0;
+ }
+ else
+ rdcount++;
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ printk("i2c-algo-pcf.o: i2c_read: i2c_inb timed out.\n");
+ return (-1);
+ }
+ if (status & I2C_PCF_LRB) {
+ printk("i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n");
+ return (-1);
+ }
+ }
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ buf[rdcount] = i2c_inb(adap);
+ if (dummy) {
+ dummy = 0;
+ }
+ else
+ rdcount++;
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ printk("i2c-algo-pcf.o: i2c_read: i2c_inb timed out.\n");
+ return (-1);
+ }
+ return (rdcount);
+}
+
+
+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("addr0: %d\n",addr));
+ /* try extended address code...*/
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("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("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("died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = ( msg->addr << 1 );
+ if (flags & I2C_M_RD )
+ 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, ret, timeout, status;
+
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk("i2c-algo-pcf.o: Timeout waiting for BB in pcf_xfer\n");)
+ return -EIO;
+ }
+ pmsg = &msgs[0];
+ ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
+ i2c_start(adap);
+
+ for (i=0; i<num; i++) {
+ DEB3(printk("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);)
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ DEB2(printk("i2c-algo-pcf.o: Timeout waiting for PIN(1) in pcf_xfer\n");)
+ i2c_stop(adap);
+ return (-EREMOTEIO);
+ }
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ DEB2(printk("i2c-algo-pcf.o: NAK from device adr %#2x msg #%d\n"
+ ,msgs[i].addr,i));
+ return -EREMOTEIO;
+ }
+ if (pmsg->flags & I2C_M_RD ) {
+ /* read bytes into buffer*/
+ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len);
+ DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret));
+ } else {
+ /* write bytes from buffer */
+ ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
+ DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+ }
+ if (i == (num-1)) {
+ i2c_stop(adap);
+ }
+ else {
+ i2c_repstart(adap);
+ }
+ if (pmsg->flags & I2C_M_RD ) {
+ pmsg->buf[pmsg->len-1] = i2c_inb(adap);
+ }
+ if (i != (num-1)) {
+ pmsg = &msgs[0];
+ ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ DEB2(printk("i2c-algo-pcf.o: Timeout waiting for PIN(2) in pcf_xfer\n");)
+ return (-EREMOTEIO);
+ }
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ DEB2(printk("i2c-algo-pcf.o: No LRB(2) in pcf_xfer\n");)
+ return (-EREMOTEIO);
+ }
+ }
+ }
+ return (num);
+}
+
+
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static u32 pcf_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm pcf_algo = {
+ "PCF8584 algorithm",
+ I2C_ALGO_PCF,
+ pcf_xfer,
+ NULL,
+ NULL, /* slave_xmit */
+ NULL, /* slave_recv */
+ algo_control, /* ioctl */
+ pcf_func, /* functionality */
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pcf_add_bus(struct i2c_adapter *adap)
+{
+ int i, status;
+ struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
+
+ if (pcf_test) {
+ int ret = test_bus(pcf_adap, adap->name);
+ if (ret<0)
+ return -ENODEV;
+ }
+
+ DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n",adap->name));
+
+ /* 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 */
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ i2c_add_adapter(adap);
+ pcf_init_8584(pcf_adap);
+
+ /* scan bus */
+ if (pcf_scan) {
+ printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n", adap->name);
+ for (i = 0x00; i < 0xff; i+=2) {
+ i2c_outb(pcf_adap, i);
+ i2c_start(pcf_adap);
+ if ((wait_for_pin(pcf_adap, &status) >= 0) &&
+ ((status && I2C_PCF_LRB) == 0)) {
+ printk("(%02x)",i>>1);
+ } else {
+ printk(".");
+ }
+ i2c_stop(pcf_adap);
+ udelay(pcf_adap->udelay);
+ }
+ printk("\n");
+ }
+ return 0;
+}
+
+
+int i2c_pcf_del_bus(struct i2c_adapter *adap)
+{
+ i2c_del_adapter(adap);
+ DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name));
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+int __init i2c_algo_pcf_init (void)
+{
+ printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n");
+ return 0;
+}
+
+
+EXPORT_SYMBOL(i2c_pcf_add_bus);
+EXPORT_SYMBOL(i2c_pcf_del_bus);
+
+#ifdef MODULE
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
+
+MODULE_PARM(pcf_test, "i");
+MODULE_PARM(pcf_scan, "i");
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(pcf_test, "Test if the I2C bus is available");
+MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus");
+MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
+
+
+int init_module(void)
+{
+ return i2c_algo_pcf_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
new file mode 100644
index 000000000..3d88b6c39
--- /dev/null
+++ b/drivers/i2c/i2c-core.c
@@ -0,0 +1,1369 @@
+/* i2c-core.c - a device driver for the iic-bus interface */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 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>.
+ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
+
+/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/config.h>
+
+#include <linux/i2c.h>
+
+/* ----- compatibility stuff ----------------------------------------------- */
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53)
+#include <linux/init.h>
+#else
+#define __init
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
+#define copy_from_user memcpy_fromfs
+#define copy_to_user memcpy_tofs
+#else
+#include <asm/uaccess.h>
+#endif
+
+/* ----- global defines ---------------------------------------------------- */
+
+/* exclusive access to the bus */
+#define I2C_LOCK(adap) down(&adap->lock)
+#define I2C_UNLOCK(adap) up(&adap->lock)
+
+#define ADAP_LOCK() down(&adap_lock)
+#define ADAP_UNLOCK() up(&adap_lock)
+
+#define DRV_LOCK() down(&driver_lock)
+#define DRV_UNLOCK() up(&driver_lock)
+
+#define DEB(x) if (i2c_debug>=1) x;
+#define DEB2(x) if (i2c_debug>=2) x;
+
+/* ----- global variables -------------------------------------------------- */
+
+/**** lock for writing to global variables: the adapter & driver list */
+struct semaphore adap_lock;
+struct semaphore driver_lock;
+
+/**** adapter list */
+static struct i2c_adapter *adapters[I2C_ADAP_MAX];
+static int adap_count;
+
+/**** drivers list */
+static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static int driver_count;
+
+/**** debug level */
+static int i2c_debug=1;
+static void i2c_dummy_adapter(struct i2c_adapter *adapter);
+static void i2c_dummy_client(struct i2c_client *client);
+
+/* ---------------------------------------------------
+ * /proc entry declarations
+ *----------------------------------------------------
+ */
+
+/* Note that quite some things changed within the 2.1 kernel series.
+ Some things below are somewhat difficult to read because of this. */
+
+#ifdef CONFIG_PROC_FS
+
+static int i2cproc_init(void);
+static int i2cproc_cleanup(void);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
+ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+static void monitor_bus_i2c(struct inode *inode, int fill);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+
+static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
+ loff_t *ppos);
+static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
+ int *eof , void *private);
+
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+
+static int i2cproc_bus_read(struct inode * inode, struct file * file,
+ char * buf, int count);
+static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
+ int unused);
+
+static struct proc_dir_entry proc_bus_dir =
+ {
+ /* low_ino */ 0, /* Set by proc_register_dynamic */
+ /* namelen */ 3,
+ /* name */ "bus",
+ /* mode */ S_IRUGO | S_IXUGO | S_IFDIR,
+ /* nlink */ 2, /* Corrected by proc_register[_dynamic] */
+ /* uid */ 0,
+ /* gid */ 0,
+ /* size */ 0,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36))
+ /* ops */ &proc_dir_inode_operations,
+#endif
+ };
+
+static struct proc_dir_entry proc_bus_i2c_dir =
+ {
+ /* low_ino */ 0, /* Set by proc_register_dynamic */
+ /* namelen */ 3,
+ /* name */ "i2c",
+ /* mode */ S_IRUGO | S_IFREG,
+ /* nlink */ 1,
+ /* uid */ 0,
+ /* gid */ 0,
+ /* size */ 0,
+ /* ops */ NULL,
+ /* get_info */ &read_bus_i2c
+ };
+
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+
+/* To implement the dynamic /proc/bus/i2c-? files, we need our own
+ implementation of the read hook */
+static struct file_operations i2cproc_operations = {
+ NULL,
+ i2cproc_bus_read,
+};
+
+static struct inode_operations i2cproc_inode_operations = {
+ &i2cproc_operations
+};
+
+static int i2cproc_initialized = 0;
+
+#else /* undef CONFIG_PROC_FS */
+
+#define i2cproc_init()
+#define i2cproc_cleanup()
+
+#endif /* CONFIG_PROC_FS */
+
+
+/* ---------------------------------------------------
+ * registering functions
+ * ---------------------------------------------------
+ */
+
+/* -----
+ * i2c_add_adapter is called from within the algorithm layer,
+ * when a new hw adapter registers. A new device is register to be
+ * available for clients.
+ */
+int i2c_add_adapter(struct i2c_adapter *adap)
+{
+ int i,j;
+
+ ADAP_LOCK();
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (NULL == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i) {
+ printk(KERN_WARNING
+ " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n",
+ adap->name);
+ ADAP_UNLOCK();
+ return -ENOMEM;
+ }
+
+ adapters[i] = adap;
+ adap_count++;
+ ADAP_UNLOCK();
+
+ /* init data types */
+ init_MUTEX(&adap->lock);
+
+ i2c_dummy_adapter(adap); /* actually i2c_dummy->add_adapter */
+#ifdef CONFIG_PROC_FS
+
+ if (i2cproc_initialized) {
+ char name[8];
+ struct proc_dir_entry *proc_entry;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
+ int res;
+#endif
+
+ sprintf(name,"i2c-%d", i);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ proc_entry = create_proc_entry(name,0,proc_bus);
+ if (! proc_entry) {
+ printk("i2c-core.o: Could not create /proc/bus/%s\n",
+ name);
+ return -ENOENT;
+ }
+ proc_entry->ops = &i2cproc_inode_operations;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
+ proc_entry->owner = THIS_MODULE;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+ proc_entry->fill_inode = &monitor_bus_i2c;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ adap->proc_entry = NULL;
+ if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+
+ strlen(name)+1, GFP_KERNEL))) {
+ printk("i2c-core.o: Out of memory!\n");
+ return -ENOMEM;
+ }
+ memset(proc_entry,0,sizeof(struct proc_dir_entry));
+ proc_entry->namelen = strlen(name);
+ proc_entry->name = (char *) (proc_entry + 1);
+ proc_entry->mode = S_IRUGO | S_IFREG;
+ proc_entry->nlink = 1;
+ proc_entry->ops = &i2cproc_inode_operations;
+
+ /* Nasty stuff to keep GCC satisfied */
+ {
+ char *procname;
+ (const char *) procname = proc_entry->name;
+ strcpy (procname,name);
+ }
+
+ if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) {
+ printk("i2c-core.o: Could not create %s.\n",name);
+ kfree(proc_entry);
+ return res;
+ }
+
+ adap->proc_entry = proc_entry;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+
+ adap->inode = proc_entry->low_ino;
+ }
+
+#endif /* def CONFIG_PROC_FS */
+
+ /* inform drivers of new adapters */
+ DRV_LOCK();
+ for (j=0;j<I2C_DRIVER_MAX;j++)
+ if (drivers[j]!=NULL && drivers[j]->flags&I2C_DF_NOTIFY)
+ drivers[j]->attach_adapter(adap);
+ DRV_UNLOCK();
+
+ DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",adap->name,i));
+
+ return 0;
+}
+
+
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+ int i,j;
+ ADAP_LOCK();
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adap == adapters[i])
+ break;
+ if (I2C_ADAP_MAX == i) {
+ printk( " i2c-core.o: unregister_adapter adap [%s] not found.\n",
+ adap->name);
+ ADAP_UNLOCK();
+ return -ENODEV;
+ }
+
+ i2c_dummy_adapter(adap); /* actually i2c_dummy->del_adapter */
+#ifdef CONFIG_PROC_FS
+ if (i2cproc_initialized) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ char name[8];
+ sprintf(name,"i2c-%d", i);
+ remove_proc_entry(name,proc_bus);
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ int res;
+ if (adapters[i]->proc_entry) {
+ if ((res = proc_unregister(&proc_bus_dir,
+ adapters[i]->proc_entry->low_ino))) {
+ printk("i2c-core.o: Deregistration of /proc "
+ "entry failed\n");
+ ADAP_UNLOCK();
+ return res;
+ }
+ kfree(adapters[i]->proc_entry);
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ }
+#endif /* def CONFIG_PROC_FS */
+
+ /* detach any active clients */
+ for (j=0;j<I2C_CLIENT_MAX;j++) {
+ struct i2c_client *client = adap->clients[j];
+ if ( (client!=NULL)
+ /* && (client->driver->flags & I2C_DF_NOTIFY) */ )
+ /* detaching devices is unconditional of the set notify
+ * flag, as _all_ clients that reside on the adapter
+ * must be deleted, as this would cause invalid states.
+ */
+ client->driver->detach_client(client);
+ /* i2c_detach_client(client); --- frodo */
+ }
+ /* all done, now unregister */
+ adapters[i] = NULL;
+ adap_count--;
+
+ ADAP_UNLOCK();
+ DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name));
+ return 0;
+}
+
+
+/* -----
+ * What follows is the "upwards" interface: commands for talking to clients,
+ * which implement the functions to access the physical information of the
+ * chips.
+ */
+
+int i2c_add_driver(struct i2c_driver *driver)
+{
+ int i,j;
+ DRV_LOCK();
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (NULL == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i) {
+ printk(KERN_WARNING
+ " i2c-core.o: register_driver(%s) - enlarge I2C_DRIVER_MAX.\n",
+ driver->name);
+ DRV_UNLOCK();
+ return -ENOMEM;
+ }
+
+ drivers[i] = driver;
+ driver_count++;
+
+ DRV_UNLOCK(); /* driver was successfully added */
+
+ DEB(printk("i2c-core.o: driver %s registered.\n",driver->name));
+
+ /* Notify all existing adapters and clients to dummy driver */
+ ADAP_LOCK();
+ if (driver->flags&I2C_DF_DUMMY) {
+ for (i=0; i<I2C_ADAP_MAX; i++) {
+ if (adapters[i]) {
+ driver->attach_adapter(adapters[i]);
+ for (j=0; j<I2C_CLIENT_MAX; j++)
+ if (adapters[i]->clients[j])
+ driver->detach_client(adapters[i]->clients[j]);
+ }
+ }
+ ADAP_UNLOCK();
+ return 0;
+ }
+
+ /* now look for instances of driver on our adapters
+ */
+ if ( driver->flags&I2C_DF_NOTIFY ) {
+ for (i=0;i<I2C_ADAP_MAX;i++)
+ if (adapters[i]!=NULL)
+ driver->attach_adapter(adapters[i]);
+ }
+ ADAP_UNLOCK();
+ return 0;
+}
+
+int i2c_del_driver(struct i2c_driver *driver)
+{
+ int i,j,k;
+
+ DRV_LOCK();
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (driver == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i) {
+ printk(KERN_WARNING " i2c-core.o: unregister_driver: [%s] not found\n",
+ driver->name);
+ DRV_UNLOCK();
+ return -ENODEV;
+ }
+ /* Have a look at each adapter, if clients of this driver are still
+ * attached. If so, detach them to be able to kill the driver
+ * afterwards.
+ */
+ DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n"));
+ /* removing clients does not depend on the notify flag, else
+ * invalid operation might (will!) result, when using stale client
+ * pointers.
+ */
+ ADAP_LOCK(); /* should be moved inside the if statement... */
+ if ((driver->flags&I2C_DF_DUMMY)==0)
+ for (k=0;k<I2C_ADAP_MAX;k++) {
+ struct i2c_adapter *adap = adapters[k];
+ if (adap == NULL) /* skip empty entries. */
+ continue;
+ DEB2(printk("i2c-core.o: examining adapter %s:\n",adap->name));
+ for (j=0;j<I2C_CLIENT_MAX;j++) {
+ struct i2c_client *client = adap->clients[j];
+ if (client != NULL && client->driver == driver) {
+ DEB2(printk("i2c-core.o: detaching client %s:\n",
+ client->name));
+ /*i2c_detach_client(client);*/
+ driver->detach_client(client);
+ }
+ }
+ }
+ ADAP_UNLOCK();
+ drivers[i] = NULL;
+ driver_count--;
+ DRV_UNLOCK();
+
+ DEB(printk("i2c-core.o: driver unregistered: %s\n",driver->name));
+ return 0;
+}
+
+int i2c_check_addr (struct i2c_adapter *adapter, int addr)
+{
+ int i;
+ for (i = 0; i < I2C_CLIENT_MAX ; i++)
+ if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+ return -EBUSY;
+ return 0;
+}
+
+int i2c_attach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int i;
+
+ if (i2c_check_addr(client->adapter,client->addr))
+ return -EBUSY;
+
+ for (i = 0; i < I2C_CLIENT_MAX; i++)
+ if (NULL == adapter->clients[i])
+ break;
+ if (I2C_CLIENT_MAX == i) {
+ printk(KERN_WARNING
+ " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
+ client->name);
+ return -ENOMEM;
+ }
+
+ adapter->clients[i] = client;
+ adapter->client_count++;
+ i2c_dummy_client(client);
+
+ if (adapter->client_register != NULL)
+ adapter->client_register(client);
+ DEB(printk("i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n",
+ client->name, adapter->name,i));
+ return 0;
+}
+
+
+int i2c_detach_client(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int i;
+
+ for (i = 0; i < I2C_CLIENT_MAX; i++)
+ if (client == adapter->clients[i])
+ break;
+ if (I2C_CLIENT_MAX == i) {
+ printk(KERN_WARNING " i2c-core.o: unregister_client [%s] not found\n",
+ client->name);
+ return -ENODEV;
+ }
+
+ if (adapter->client_unregister != NULL)
+ adapter->client_unregister(client);
+ /* client->driver->detach_client(client);*/
+
+ adapter->clients[i] = NULL;
+ adapter->client_count--;
+ i2c_dummy_client(client);
+
+ DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name));
+ return 0;
+}
+
+void i2c_inc_use_client(struct i2c_client *client)
+{
+
+ if (client->driver->inc_use != NULL)
+ client->driver->inc_use(client);
+
+ if (client->adapter->inc_use != NULL)
+ client->adapter->inc_use(client->adapter);
+}
+
+void i2c_dec_use_client(struct i2c_client *client)
+{
+
+ if (client->driver->dec_use != NULL)
+ client->driver->dec_use(client);
+
+ if (client->adapter->dec_use != NULL)
+ client->adapter->dec_use(client->adapter);
+}
+
+/* ----------------------------------------------------
+ * The /proc functions
+ * ----------------------------------------------------
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
+ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible
+ if some process still uses it or some file in it */
+void monitor_bus_i2c(struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+
+/* This function generates the output for /proc/bus/i2c */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof,
+ void *private)
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+{
+ int i;
+ int nr = 0;
+ /* Note that it is safe to write a `little' beyond len. Yes, really. */
+ for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++)
+ if (adapters[i]) {
+ nr += sprintf(buf+nr, "i2c-%d\t", i);
+ if (adapters[i]->algo->smbus_xfer) {
+ if (adapters[i]->algo->master_xfer)
+ nr += sprintf(buf+nr,"smbus/i2c");
+ else
+ nr += sprintf(buf+nr,"smbus ");
+ } else if (adapters[i]->algo->master_xfer)
+ nr += sprintf(buf+nr,"i2c ");
+ else
+ nr += sprintf(buf+nr,"dummy ");
+ nr += sprintf(buf+nr,"\t%-32s\t%-32s\n",
+ adapters[i]->name,
+ adapters[i]->algo->name);
+ }
+ return nr;
+}
+
+/* This function generates the output for /proc/bus/i2c-? */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
+ loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
+int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf,
+ int count)
+{
+#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ char *kbuf;
+ struct i2c_client *client;
+ int i,j,len=0;
+
+ if (count < 0)
+ return -EINVAL;
+ if (count > 4000)
+ count = 4000;
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adapters[i]->inode == inode->i_ino) {
+ /* We need a bit of slack in the kernel buffer; this makes the
+ sprintf safe. */
+ if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
+ return -ENOMEM;
+ for (j = 0; j < I2C_CLIENT_MAX; j++)
+ if ((client = adapters[i]->clients[j]))
+ /* Filter out dummy clients */
+ if (client->driver->id != I2C_DRIVERID_I2CDEV)
+ len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
+ client->addr,
+ client->name,client->driver->name);
+ if (file->f_pos+len > count)
+ len = count - file->f_pos;
+ len = len - file->f_pos;
+ if (len < 0)
+ len = 0;
+ copy_to_user (buf,kbuf+file->f_pos,len);
+ file->f_pos += len;
+ kfree(kbuf);
+ return len;
+ }
+ return -ENOENT;
+}
+
+int i2cproc_init(void)
+{
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ struct proc_dir_entry *proc_bus_i2c;
+#else
+ int res;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+
+ i2cproc_initialized = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ if (! proc_bus) {
+ printk("i2c-core.o: /proc/bus/ does not exist");
+ i2cproc_cleanup();
+ return -ENOENT;
+ }
+ proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
+ if (!proc_bus_i2c) {
+ printk("i2c-core.o: Could not create /proc/bus/i2c");
+ i2cproc_cleanup();
+ return -ENOENT;
+ }
+ proc_bus_i2c->read_proc = &read_bus_i2c;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
+ proc_bus_i2c->owner = THIS_MODULE;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+ proc_bus_i2c->fill_inode = &monitor_bus_i2c;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ i2cproc_initialized += 2;
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module
+ introduced it, or we are fucked. And 2.0.35 and earlier does not
+ export proc_dir_inode_operations, so we grab it from proc_net,
+ which also uses it. Not nice. */
+ proc_bus_dir.ops = proc_net.ops;
+ if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) {
+ printk("i2c-core.o: Could not create /proc/bus/");
+ i2cproc_cleanup();
+ return res;
+ }
+ i2cproc_initialized ++;
+ if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) {
+ printk("i2c-core.o: Could not create /proc/bus/i2c\n");
+ i2cproc_cleanup();
+ return res;
+ }
+ i2cproc_initialized ++;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ return 0;
+}
+
+int i2cproc_cleanup(void)
+{
+
+ if (i2cproc_initialized >= 1) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
+ remove_proc_entry("i2c",proc_bus);
+ i2cproc_initialized -= 2;
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
+ int res;
+ if (i2cproc_initialized >= 2) {
+ if ((res = proc_unregister(&proc_bus_dir,
+ proc_bus_i2c_dir.low_ino))) {
+ printk("i2c-core.o: could not delete "
+ "/proc/bus/i2c, module not removed.");
+ return res;
+ }
+ i2cproc_initialized --;
+ }
+ if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) {
+ printk("i2c-core.o: could not delete /proc/bus/, "
+ "module not removed.");
+ return res;
+ }
+ i2cproc_initialized --;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+ }
+ return 0;
+}
+
+
+#endif /* def CONFIG_PROC_FS */
+
+/* ---------------------------------------------------
+ * dummy driver notification
+ * ---------------------------------------------------
+ */
+
+static void i2c_dummy_adapter(struct i2c_adapter *adap)
+{
+ int i;
+ for (i=0; i<I2C_DRIVER_MAX; i++)
+ if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+ drivers[i]->attach_adapter(adap);
+}
+
+static void i2c_dummy_client(struct i2c_client *client)
+{
+ int i;
+ for (i=0; i<I2C_DRIVER_MAX; i++)
+ if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+ drivers[i]->detach_client(client);
+}
+
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
+{
+ int ret;
+
+ if (adap->algo->master_xfer) {
+ DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",adap->name,num));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_xfer(adap,msgs,num);
+ I2C_UNLOCK(adap);
+
+ return ret;
+ } else {
+ printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
+ adap->id);
+ return -ENOSYS;
+ }
+}
+
+int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
+{
+ int ret;
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msg;
+
+ if (client->adapter->algo->master_xfer) {
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ (const char *)msg.buf = buf;
+
+ DEB2(printk("i2c-core.o: master_send: writing %d bytes on %s.\n",
+ count,client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_xfer(adap,&msg,1);
+ I2C_UNLOCK(adap);
+
+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes
+ * transmitted, else error code.
+ */
+ return (ret == 1 )? count : ret;
+ } else {
+ printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
+ client->adapter->id);
+ return -ENOSYS;
+ }
+}
+
+int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
+{
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msg;
+ int ret;
+ if (client->adapter->algo->master_xfer) {
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
+
+ DEB2(printk("i2c-core.o: master_recv: reading %d bytes on %s.\n",
+ count,client->adapter->name));
+
+ I2C_LOCK(adap);
+ ret = adap->algo->master_xfer(adap,&msg,1);
+ I2C_UNLOCK(adap);
+
+ DEB2(printk("i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
+ ret, count, client->addr));
+
+ /* if everything went ok (i.e. 1 msg transmitted), return #bytes
+ * transmitted, else error code.
+ */
+ return (ret == 1 )? count : ret;
+ } else {
+ printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
+ client->adapter->id);
+ return -ENOSYS;
+ }
+}
+
+
+int i2c_control(struct i2c_client *client,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct i2c_adapter *adap = client->adapter;
+
+ DEB2(printk("i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg));
+ switch ( cmd ) {
+ case I2C_RETRIES:
+ adap->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ adap->timeout = arg;
+ break;
+ default:
+ if (adap->algo->algo_control!=NULL)
+ ret = adap->algo->algo_control(adap,cmd,arg);
+ }
+ return ret;
+}
+
+/* ----------------------------------------------------
+ * the i2c address scanning function
+ * Will not work for 10-bit addresses!
+ * ----------------------------------------------------
+ */
+int i2c_probe(struct i2c_adapter *adapter,
+ struct i2c_client_address_data *address_data,
+ i2c_client_found_addr_proc *found_proc)
+{
+ int addr,i,found,err;
+ int adap_id = i2c_adapter_id(adapter);
+
+ /* Forget it if we can't probe using SMBUS_QUICK */
+ if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
+ return -1;
+
+ for (addr = 0x00;
+ addr <= 0x7f;
+ addr++) {
+
+ /* Skip if already in use */
+ if (i2c_check_addr(adapter,addr))
+ continue;
+
+ /* If it is in one of the force entries, we don't do any detection
+ at all */
+ found = 0;
+
+ for (i = 0;
+ !found && (address_data->force[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->force[i]) ||
+ (address_data->force[i] == ANY_I2C_BUS)) &&
+ (addr == address_data->force[i+1])) {
+ DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n",
+ adap_id,addr));
+ if ((err = found_proc(adapter,addr,0,0)))
+ return err;
+ found = 1;
+ }
+ }
+ if (found)
+ continue;
+
+ /* If this address is in one of the ignores, we can forget about it
+ right now */
+ for (i = 0;
+ !found && (address_data->ignore[i] != I2C_CLIENT_END);
+ i += 2) {
+ if (((adap_id == address_data->ignore[i]) ||
+ ((address_data->ignore[i] == ANY_I2C_BUS))) &&
+ (addr == address_data->ignore[i+1])) {
+ DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, "
+ "addr %04x\n", adap_id ,addr));
+ found = 1;
+ }
+ }
+ for (i = 0;
+ !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->ignore_range[i]) ||
+ ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
+ (addr >= address_data->ignore_range[i+1]) &&
+ (addr <= address_data->ignore_range[i+2])) {
+ DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ found = 1;
+ }
+ }
+ if (found)
+ continue;
+
+ /* Now, we will do a detection, but only if it is in the normal or
+ probe entries */
+ for (i = 0;
+ !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
+ i += 1) {
+ if (addr == address_data->normal_i2c[i]) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, "
+ "addr %02x", adap_id,addr));
+ }
+ }
+
+ for (i = 0;
+ !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
+ i += 2) {
+ if ((addr >= address_data->normal_i2c_range[i]) &&
+ (addr <= address_data->normal_i2c_range[i+1])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+
+ for (i = 0;
+ !found && (address_data->probe[i] != I2C_CLIENT_END);
+ i += 2) {
+ if (((adap_id == address_data->probe[i]) ||
+ ((address_data->probe[i] == ANY_I2C_BUS))) &&
+ (addr == address_data->probe[i+1])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found probe parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+ for (i = 0;
+ !found && (address_data->probe_range[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->probe_range[i]) ||
+ (address_data->probe_range[i] == ANY_I2C_BUS)) &&
+ (addr >= address_data->probe_range[i+1]) &&
+ (addr <= address_data->probe_range[i+2])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+ if (!found)
+ continue;
+
+ /* OK, so we really should examine this address. First check
+ whether there is some client here at all! */
+ if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
+ if ((err = found_proc(adapter,addr,0,-1)))
+ return err;
+ }
+ return 0;
+}
+
+/* +++ frodo
+ * return id number for a specific adapter
+ */
+int i2c_adapter_id(struct i2c_adapter *adap)
+{
+ int i;
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adap == adapters[i])
+ return i;
+ return -1;
+}
+
+/* The SMBus parts */
+
+extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
+{
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ value,0,I2C_SMBUS_QUICK,NULL);
+}
+
+extern s32 i2c_smbus_read_byte(struct i2c_client * client)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
+ return -1;
+ else
+ return 0x0FF & data.byte;
+}
+
+extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
+{
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+}
+
+extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
+ return -1;
+ else
+ return 0x0FF & data.byte;
+}
+
+extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
+ u8 command, u8 value)
+{
+ union i2c_smbus_data data;
+ data.byte = value;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_BYTE_DATA,&data);
+}
+
+extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
+ return -1;
+ else
+ return 0x0FFFF & data.word;
+}
+
+extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
+ u8 command, u16 value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_WORD_DATA,&data);
+}
+
+extern s32 i2c_smbus_process_call(struct i2c_client * client,
+ u8 command, u16 value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_PROC_CALL, &data))
+ return -1;
+ else
+ return 0x0FFFF & data.word;
+}
+
+/* Returns the number of read bytes */
+extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
+ u8 command, u8 *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_READ,command,
+ I2C_SMBUS_BLOCK_DATA,&data))
+ return -1;
+ else {
+ for (i = 1; i <= data.block[0]; i++)
+ values[i-1] = data.block[i];
+ return data.block[0];
+ }
+}
+
+extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
+ u8 command, u8 length, u8 *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (length > 32)
+ length = 32;
+ for (i = 1; i <= length; i++)
+ data.block[i] = values[i-1];
+ data.block[0] = length;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_BLOCK_DATA,&data);
+}
+
+/* Simulate a SMBus command using the i2c protocol
+ No checking of parameters is done! */
+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
+ unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* So we need to generate a series of msgs. In the case of writing, we
+ need to use only one message; when reading, we need two. We initialize
+ most things with sane defaults, to keep the code below somewhat
+ simpler. */
+ unsigned char msgbuf0[33];
+ unsigned char msgbuf1[33];
+ int num = read_write == I2C_SMBUS_READ?2:1;
+ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
+ { addr, flags | I2C_M_RD, 0, msgbuf1 }
+ };
+ int i;
+
+ msgbuf0[0] = command;
+ switch(size) {
+ case I2C_SMBUS_QUICK:
+ msg[0].len = 0;
+ /* Special case: The read/write field is used as data */
+ msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
+ num = 1;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ /* Special case: only a read! */
+ msg[0].flags = I2C_M_RD | flags;
+ num = 1;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ msg[1].len = 1;
+ else {
+ msg[0].len = 2;
+ msgbuf0[1] = data->byte;
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ msg[1].len = 2;
+ else {
+ msg[0].len=3;
+ msgbuf0[1] = data->word & 0xff;
+ msgbuf0[2] = (data->word >> 8) & 0xff;
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ num = 2; /* Special case */
+ msg[0].len = 3;
+ msg[1].len = 2;
+ msgbuf0[1] = data->word & 0xff;
+ msgbuf0[2] = (data->word >> 8) & 0xff;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ printk("i2c-core.o: Block read not supported under "
+ "I2C emulation!\n");
+ return -1;
+ } else {
+ msg[1].len = data->block[0] + 1;
+ if (msg[1].len > 32) {
+ printk("i2c-core.o: smbus_access called with "
+ "invalid block write size (%d)\n",
+ msg[1].len);
+ return -1;
+ }
+ for (i = 1; i <= msg[1].len; i++)
+ msgbuf0[i] = data->block[i];
+ }
+ break;
+ default:
+ printk("i2c-core.o: smbus_access called with invalid size (%d)\n",
+ size);
+ return -1;
+ }
+
+ if (i2c_transfer(adapter, msg, num) < 0)
+ return -1;
+
+ if (read_write == I2C_SMBUS_READ)
+ switch(size) {
+ case I2C_SMBUS_BYTE:
+ data->byte = msgbuf0[0];
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = msgbuf1[0];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = msgbuf1[0] | (msgbuf1[1] << 8);
+ break;
+ }
+ return 0;
+}
+
+
+s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ s32 res;
+ flags = flags & I2C_M_TEN;
+ if (adapter->algo->smbus_xfer) {
+ I2C_LOCK(adapter);
+ res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
+ command,size,data);
+ I2C_UNLOCK(adapter);
+ } else
+ res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
+ command,size,data);
+ return res;
+}
+
+
+/* You should always define `functionality'; the 'else' is just for
+ backward compatibility. */
+u32 i2c_get_functionality (struct i2c_adapter *adap)
+{
+ if (adap->algo->functionality)
+ return adap->algo->functionality(adap);
+ else
+ return 0xffffffff;
+}
+
+int i2c_check_functionality (struct i2c_adapter *adap, u32 func)
+{
+ u32 adap_func = i2c_get_functionality (adap);
+ return (func & adap_func) == func;
+}
+
+
+static int __init i2c_init(void)
+{
+ printk("i2c-core.o: i2c core module\n");
+ memset(adapters,0,sizeof(adapters));
+ memset(drivers,0,sizeof(drivers));
+ adap_count=0;
+ driver_count=0;
+
+ init_MUTEX(&adap_lock);
+ init_MUTEX(&driver_lock);
+
+ i2cproc_init();
+
+ return 0;
+}
+
+#ifndef MODULE
+#ifdef CONFIG_I2C_CHARDEV
+ extern int i2c_dev_init(void);
+#endif
+#ifdef CONFIG_I2C_ALGOBIT
+ extern int algo_bit_init(void);
+#endif
+#ifdef CONFIG_I2C_BITLP
+ extern int bitlp_init(void);
+#endif
+#ifdef CONFIG_I2C_BITELV
+ extern int bitelv_init(void);
+#endif
+#ifdef CONFIG_I2C_BITVELLE
+ extern int bitvelle_init(void);
+#endif
+#ifdef CONFIG_I2C_BITVIA
+ extern int bitvia_init(void);
+#endif
+
+#ifdef CONFIG_I2C_ALGOPCF
+ extern int algo_pcf_init(void);
+#endif
+#ifdef CONFIG_I2C_PCFISA
+ extern int pcfisa_init(void);
+#endif
+
+/* This is needed for automatic patch generation: sensors code starts here */
+/* This is needed for automatic patch generation: sensors code ends here */
+
+int __init i2c_init_all(void)
+{
+ /* --------------------- global ----- */
+ i2c_init();
+
+#ifdef CONFIG_I2C_CHARDEV
+ i2c_dev_init();
+#endif
+ /* --------------------- bit -------- */
+#ifdef CONFIG_I2C_ALGOBIT
+ i2c_algo_bit_init();
+#endif
+#ifdef CONFIG_I2C_PHILIPSPAR
+ i2c_bitlp_init();
+#endif
+#ifdef CONFIG_I2C_ELV
+ i2c_bitelv_init();
+#endif
+#ifdef CONFIG_I2C_VELLEMAN
+ i2c_bitvelle_init();
+#endif
+
+ /* --------------------- pcf -------- */
+#ifdef CONFIG_I2C_ALGOPCF
+ i2c_algo_pcf_init();
+#endif
+#ifdef CONFIG_I2C_ELEKTOR
+ i2c_pcfisa_init();
+#endif
+/* This is needed for automatic patch generation: sensors code starts here */
+/* This is needed for automatic patch generation: sensors code ends here */
+
+ return 0;
+}
+
+#endif
+
+
+
+EXPORT_SYMBOL(i2c_add_adapter);
+EXPORT_SYMBOL(i2c_del_adapter);
+EXPORT_SYMBOL(i2c_add_driver);
+EXPORT_SYMBOL(i2c_del_driver);
+EXPORT_SYMBOL(i2c_attach_client);
+EXPORT_SYMBOL(i2c_detach_client);
+EXPORT_SYMBOL(i2c_inc_use_client);
+EXPORT_SYMBOL(i2c_dec_use_client);
+EXPORT_SYMBOL(i2c_check_addr);
+
+
+EXPORT_SYMBOL(i2c_master_send);
+EXPORT_SYMBOL(i2c_master_recv);
+EXPORT_SYMBOL(i2c_control);
+EXPORT_SYMBOL(i2c_transfer);
+EXPORT_SYMBOL(i2c_adapter_id);
+EXPORT_SYMBOL(i2c_probe);
+
+EXPORT_SYMBOL(i2c_smbus_xfer);
+EXPORT_SYMBOL(i2c_smbus_write_quick);
+EXPORT_SYMBOL(i2c_smbus_read_byte);
+EXPORT_SYMBOL(i2c_smbus_write_byte);
+EXPORT_SYMBOL(i2c_smbus_read_byte_data);
+EXPORT_SYMBOL(i2c_smbus_write_byte_data);
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
+EXPORT_SYMBOL(i2c_smbus_write_word_data);
+EXPORT_SYMBOL(i2c_smbus_process_call);
+EXPORT_SYMBOL(i2c_smbus_read_block_data);
+EXPORT_SYMBOL(i2c_smbus_write_block_data);
+
+EXPORT_SYMBOL(i2c_get_functionality);
+EXPORT_SYMBOL(i2c_check_functionality);
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus main module");
+MODULE_PARM(i2c_debug, "i");
+MODULE_PARM_DESC(i2c_debug,"debug level");
+
+int init_module(void)
+{
+ return i2c_init();
+}
+
+void cleanup_module(void)
+{
+ i2cproc_cleanup();
+}
+#endif
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
new file mode 100644
index 000000000..088d730fc
--- /dev/null
+++ b/drivers/i2c/i2c-dev.c
@@ -0,0 +1,557 @@
+/*
+ i2c-dev.c - i2c-bus driver, char device interface
+
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+
+ 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.
+*/
+
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+ But I have used so much of his original code and ideas that it seems
+ only fair to recognize him as co-author -- Frodo */
+
+/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+
+/* If you want debugging uncomment: */
+/* #define DEBUG */
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,51)
+#include <linux/init.h>
+#else
+#define __init
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
+#define copy_from_user memcpy_fromfs
+#define copy_to_user memcpy_tofs
+#define get_user_data(to,from) ((to) = get_user(from),0)
+#else
+#include <asm/uaccess.h>
+#define get_user_data(to,from) get_user(to,from)
+#endif
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#ifdef MODULE
+extern int init_module(void);
+extern int cleanup_module(void);
+#endif /* def MODULE */
+
+/* struct file_operations changed too often in the 2.1 series for nice code */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
+static long long i2cdev_lseek (struct file *file, long long offset, int origin);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
+static long long i2cdev_llseek (struct inode *inode, struct file *file,
+ long long offset, int origin);
+#else
+static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
+ int origin);
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
+ loff_t *offset);
+static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
+ loff_t *offset);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
+static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
+ unsigned long count);
+static long i2cdev_write (struct inode *inode, struct file *file,
+ const char *buf, unsigned long offset);
+#else
+static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
+ int count);
+static int i2cdev_write(struct inode *inode, struct file *file,
+ const char *buf, int count);
+#endif
+
+static int i2cdev_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static int i2cdev_open (struct inode *inode, struct file *file);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
+static int i2cdev_release (struct inode *inode, struct file *file);
+#else
+static void i2cdev_release (struct inode *inode, struct file *file);
+#endif
+
+
+static int i2cdev_attach_adapter(struct i2c_adapter *adap);
+static int i2cdev_detach_client(struct i2c_client *client);
+static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
+ void *arg);
+
+#ifdef MODULE
+static
+#else
+extern
+#endif
+ int __init i2c_dev_init(void);
+static int i2cdev_cleanup(void);
+
+static struct file_operations i2cdev_fops = {
+ i2cdev_lseek,
+ i2cdev_read,
+ i2cdev_write,
+ NULL, /* i2cdev_readdir */
+ NULL, /* i2cdev_select */
+ i2cdev_ioctl,
+ NULL, /* i2cdev_mmap */
+ i2cdev_open,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
+ NULL, /* i2cdev_flush */
+#endif
+ i2cdev_release,
+};
+
+#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
+static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
+
+static struct i2c_driver i2cdev_driver = {
+ /* name */ "i2c-dev dummy driver",
+ /* id */ I2C_DRIVERID_I2CDEV,
+ /* flags */ I2C_DF_DUMMY,
+ /* attach_adapter */ i2cdev_attach_adapter,
+ /* detach_client */ i2cdev_detach_client,
+ /* command */ i2cdev_command,
+ /* inc_use */ NULL,
+ /* dec_use */ NULL,
+};
+
+static struct i2c_client i2cdev_client_template = {
+ /* name */ "I2C /dev entry",
+ /* id */ 1,
+ /* flags */ 0,
+ /* addr */ -1,
+ /* adapter */ NULL,
+ /* driver */ &i2cdev_driver,
+ /* data */ NULL
+};
+
+static int i2cdev_initialized;
+
+/* Note that the lseek function is called llseek in 2.1 kernels. But things
+ are complicated enough as is. */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
+long long i2cdev_lseek (struct file *file, long long offset, int origin)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
+long long i2cdev_llseek (struct inode *inode, struct file *file,
+ long long offset, int origin)
+#else
+int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
+ int origin)
+#endif
+{
+#ifdef DEBUG
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
+ struct inode *inode = file->f_dentry->d_inode;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+ printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
+ MINOR(inode->i_rdev),(long) offset,origin);
+#endif /* DEBUG */
+ return -ESPIPE;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
+ loff_t *offset)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
+static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
+ unsigned long count)
+#else
+static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
+ int count)
+#endif
+{
+ char *tmp;
+ int ret;
+
+#ifdef DEBUG
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+ struct inode *inode = file->f_dentry->d_inode;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+#endif /* DEBUG */
+
+ struct i2c_client *client = (struct i2c_client *)file->private_data;
+
+ /* copy user space data to kernel space. */
+ tmp = kmalloc(count,GFP_KERNEL);
+ if (tmp==NULL)
+ return -ENOMEM;
+
+#ifdef DEBUG
+ printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),count);
+#endif
+
+ ret = i2c_master_recv(client,tmp,count);
+ copy_to_user(buf,tmp,count);
+ kfree(tmp);
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
+ loff_t *offset)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
+static long i2cdev_write (struct inode *inode, struct file *file,
+ const char *buf, unsigned long offset)
+#else
+static int i2cdev_write(struct inode *inode, struct file *file,
+ const char *buf, int count)
+#endif
+{
+ int ret;
+ char *tmp;
+ struct i2c_client *client = (struct i2c_client *)file->private_data;
+
+#ifdef DEBUG
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
+ struct inode *inode = file->f_dentry->d_inode;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+#endif /* DEBUG */
+
+ /* copy user space data to kernel space. */
+ tmp = kmalloc(count,GFP_KERNEL);
+ if (tmp==NULL)
+ return -ENOMEM;
+ copy_from_user(tmp,buf,count);
+
+#ifdef DEBUG
+ printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),count);
+#endif
+ ret = i2c_master_send(client,tmp,count);
+ kfree(tmp);
+ return ret;
+}
+
+int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct i2c_client *client = (struct i2c_client *)file->private_data;
+ struct i2c_smbus_ioctl_data data_arg;
+ union i2c_smbus_data temp;
+ int ver,datasize,res;
+ unsigned long funcs;
+
+#ifdef DEBUG
+ printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
+ MINOR(inode->i_rdev),cmd, arg);
+#endif /* DEBUG */
+
+ switch ( cmd ) {
+ case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
+ if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+ return -EINVAL;
+ if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+ return -EBUSY;
+ client->addr = arg;
+ return 0;
+ case I2C_TENBIT:
+ if (arg)
+ client->flags |= I2C_M_TEN;
+ else
+ client->flags &= ~I2C_M_TEN;
+ return 0;
+ case I2C_FUNCS:
+ if (! arg) {
+#ifdef DEBUG
+ printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
+#endif
+ return -EINVAL;
+ }
+ if (verify_area(VERIFY_WRITE,(unsigned long *) arg,
+ sizeof(unsigned long))) {
+#ifdef DEBUG
+ printk("i2c-dev.o: invalid argument pointer (%ld) "
+ "in IOCTL I2C_SMBUS.\n", arg);
+#endif
+ return -EINVAL;
+ }
+
+ funcs = i2c_get_functionality(client->adapter);
+ copy_to_user((unsigned long *)arg,&funcs,sizeof(unsigned long));
+ return 0;
+ case I2C_SMBUS:
+ if (! arg) {
+#ifdef DEBUG
+ printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
+#endif
+ return -EINVAL;
+ }
+ if (verify_area(VERIFY_READ,(struct i2c_smbus_ioctl_data *) arg,
+ sizeof(struct i2c_smbus_ioctl_data))) {
+#ifdef DEBUG
+ printk("i2c-dev.o: invalid argument pointer (%ld) "
+ "in IOCTL I2C_SMBUS.\n", arg);
+#endif
+ return -EINVAL;
+ }
+ copy_from_user(&data_arg,(struct i2c_smbus_ioctl_data *) arg,
+ sizeof(struct i2c_smbus_ioctl_data));
+ if ((data_arg.size != I2C_SMBUS_BYTE) &&
+ (data_arg.size != I2C_SMBUS_QUICK) &&
+ (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+ (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+ (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+ (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
+#ifdef DEBUG
+ printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
+ data_arg.size);
+#endif
+ return -EINVAL;
+ }
+ /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+ so the check is valid if size==I2C_SMBUS_QUICK too. */
+ if ((data_arg.read_write != I2C_SMBUS_READ) &&
+ (data_arg.read_write != I2C_SMBUS_WRITE)) {
+#ifdef DEBUG
+ printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+ data_arg.read_write);
+#endif
+ return -EINVAL;
+ }
+
+ /* Note that command values are always valid! */
+
+ if ((data_arg.size == I2C_SMBUS_QUICK) ||
+ ((data_arg.size == I2C_SMBUS_BYTE) &&
+ (data_arg.read_write == I2C_SMBUS_WRITE)))
+ /* These are special: we do not use data */
+ return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ data_arg.read_write, data_arg.command,
+ data_arg.size, NULL);
+
+ if (data_arg.data == NULL) {
+#ifdef DEBUG
+ printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
+#endif
+ return -EINVAL;
+ }
+
+ /* This seems unlogical but it is not: if the user wants to read a
+ value, we must write that value to user memory! */
+ ver = ((data_arg.read_write == I2C_SMBUS_WRITE) &&
+ (data_arg.size != I2C_SMBUS_PROC_CALL))?VERIFY_READ:VERIFY_WRITE;
+
+ if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || (data_arg.size == I2C_SMBUS_BYTE))
+ datasize = sizeof(data_arg.data->byte);
+ else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+ (data_arg.size == I2C_SMBUS_PROC_CALL))
+ datasize = sizeof(data_arg.data->word);
+ else /* size == I2C_SMBUS_BLOCK_DATA */
+ datasize = sizeof(data_arg.data->block);
+
+ if (verify_area(ver,data_arg.data,datasize)) {
+#ifdef DEBUG
+ printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n",
+ data_arg.data);
+#endif
+ return -EINVAL;
+ }
+
+ if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.read_write == I2C_SMBUS_WRITE))
+ copy_from_user(&temp,data_arg.data,datasize);
+ res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ data_arg.read_write,
+ data_arg.command,data_arg.size,&temp);
+ if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.read_write == I2C_SMBUS_READ)))
+ copy_to_user(data_arg.data,&temp,datasize);
+ return res;
+
+ default:
+ return i2c_control(client,cmd,arg);
+ }
+ return 0;
+}
+
+int i2cdev_open (struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct i2c_client *client;
+
+ if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
+#ifdef DEBUG
+ printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",minor);
+#endif
+ return -ENODEV;
+ }
+
+ /* Note that we here allocate a client for later use, but we will *not*
+ register this client! Yes, this is safe. No, it is not very clean. */
+ if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+ return -ENOMEM;
+ memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
+ client->adapter = i2cdev_adaps[minor];
+ file->private_data = client;
+
+ i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
+ MOD_INC_USE_COUNT;
+
+#ifdef DEBUG
+ printk("i2c-dev.o: opened i2c-%d\n",minor);
+#endif
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
+static int i2cdev_release (struct inode *inode, struct file *file)
+#else
+static void i2cdev_release (struct inode *inode, struct file *file)
+#endif
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ kfree(file->private_data);
+ file->private_data=NULL;
+#ifdef DEBUG
+ printk("i2c-dev.o: Closed: i2c-%d\n", minor);
+#endif
+ MOD_DEC_USE_COUNT;
+ i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
+ return 0;
+#endif
+}
+
+int i2cdev_attach_adapter(struct i2c_adapter *adap)
+{
+ int i;
+
+ if ((i = i2c_adapter_id(adap)) < 0) {
+ printk("i2c-dev.o: Unknown adapter ?!?\n");
+ return -ENODEV;
+ }
+ if (i >= I2CDEV_ADAPS_MAX) {
+ printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
+ return -ENODEV;
+ }
+
+ if (! i2cdev_adaps[i]) {
+ i2cdev_adaps[i] = adap;
+ printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
+ } else {
+ i2cdev_adaps[i] = NULL;
+#ifdef DEBUG
+ printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
+#endif
+ }
+
+ return 0;
+}
+
+int i2cdev_detach_client(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ return -1;
+}
+
+int __init i2c_dev_init(void)
+{
+ int res;
+
+ printk("i2c-dev.o: i2c /dev entries driver module\n");
+
+ i2cdev_initialized = 0;
+ if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
+ printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR);
+ return -EIO;
+ }
+ i2cdev_initialized ++;
+
+ if ((res = i2c_add_driver(&i2cdev_driver))) {
+ printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
+ i2cdev_cleanup();
+ return res;
+ }
+ i2cdev_initialized ++;
+ return 0;
+}
+
+int i2cdev_cleanup(void)
+{
+ int res;
+
+ if (i2cdev_initialized >= 2) {
+ if ((res = i2c_del_driver(&i2cdev_driver))) {
+ printk("i2c-dev.o: Driver deregistration failed, "
+ "module not removed.\n");
+ return res;
+ }
+ i2cdev_initialized ++;
+ }
+
+ if (i2cdev_initialized >= 1) {
+ if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
+ printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR);
+ return res;
+ }
+ i2cdev_initialized --;
+ }
+ return 0;
+}
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C /dev entries driver");
+
+int init_module(void)
+{
+ return i2c_dev_init();
+}
+
+int cleanup_module(void)
+{
+ return i2cdev_cleanup();
+}
+
+#endif /* def MODULE */
+
diff --git a/drivers/i2c/i2c-elektor.c b/drivers/i2c/i2c-elektor.c
new file mode 100644
index 000000000..fb965df0f
--- /dev/null
+++ b/drivers/i2c/i2c-elektor.c
@@ -0,0 +1,327 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+ 1998-99 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 even
+ Frodo Looijaard <frodol@dds.nl> */
+
+/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020135
+#include <linux/init.h>
+#else
+#define __init
+#endif
+#include <asm/irq.h>
+#include <asm/io.h>
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include <linux/i2c-elektor.h>
+#include "i2c-pcf8584.h"
+
+#define DEFAULT_BASE 0x300
+#define DEFAULT_IRQ 0
+#define DEFAULT_CLOCK 0x1c
+#define DEFAULT_OWN 0x55
+
+static int base = 0;
+static int irq = 0;
+static int clock = 0;
+static int own = 0;
+static int i2c_debug=0;
+static struct i2c_pcf_isa gpi;
+#if (LINUX_VERSION_CODE < 0x020301)
+static struct wait_queue *pcf_wait = NULL;
+#else
+static wait_queue_head_t pcf_wait;
+#endif
+static int pcf_pending;
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x
+#define DEBE(x) x /* error messages */
+
+
+/* --- Convenience defines for the i2c port: */
+#define BASE ((struct i2c_pcf_isa *)(data))->pi_base
+#define DATA BASE /* Adapter data port */
+#define CTRL (BASE+1) /* Adapter control port */
+
+/* ----- local functions ---------------------------------------------- */
+
+static void pcf_isa_setbyte(void *data, int ctl, int val)
+{
+ if (ctl) {
+ if (gpi.pi_irq > 0) {
+ DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val|I2C_PCF_ENI));
+ outb(val | I2C_PCF_ENI, CTRL);
+ } else {
+ DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val));
+ outb(val, CTRL);
+ }
+ } else {
+ DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val));
+ outb(val, DATA);
+ }
+}
+
+static int pcf_isa_getbyte(void *data, int ctl)
+{
+ int val;
+
+ if (ctl) {
+ val = inb(CTRL);
+ DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val));
+ } else {
+ val = inb(DATA);
+ DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val));
+ }
+ return (val);
+}
+
+static int pcf_isa_getown(void *data)
+{
+ return (gpi.pi_own);
+}
+
+
+static int pcf_isa_getclock(void *data)
+{
+ return (gpi.pi_clock);
+}
+
+
+
+#if LINUX_VERSION_CODE < 0x02017f
+static void schedule_timeout(int j)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + j;
+ schedule();
+}
+#endif
+
+#if 0
+static void pcf_isa_sleep(unsigned long timeout)
+{
+ schedule_timeout( timeout * HZ);
+}
+#endif
+
+
+static void pcf_isa_waitforpin(void) {
+
+ int timeout = 2;
+
+ if (gpi.pi_irq > 0) {
+ cli();
+ if (pcf_pending == 0) {
+#if LINUX_VERSION_CODE < 0x02017f
+ current->timeout = jiffies + timeout * HZ;
+ interruptible_sleep_on(&pcf_wait);
+#else
+ interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
+#endif
+ }
+ else
+ pcf_pending = 0;
+ sti();
+#if LINUX_VERSION_CODE < 0x02017f
+ current->timeout = 0;
+#endif
+ }
+ else {
+ udelay(100);
+ }
+}
+
+
+static void pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+
+ pcf_pending = 1;
+ wake_up_interruptible(&pcf_wait);
+}
+
+
+static int pcf_isa_init(void)
+{
+ if (check_region(gpi.pi_base, 2) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
+ }
+ if (gpi.pi_irq > 0) {
+ if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) {
+ printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq);
+ gpi.pi_irq = 0;
+ }
+ else
+ enable_irq(gpi.pi_irq);
+ }
+ return 0;
+}
+
+
+static void pcf_isa_exit(void)
+{
+ if (gpi.pi_irq > 0) {
+ disable_irq(gpi.pi_irq);
+ free_irq(gpi.pi_irq, 0);
+ }
+ release_region(gpi.pi_base , 2);
+}
+
+
+static int pcf_isa_reg(struct i2c_client *client)
+{
+ return 0;
+}
+
+
+static int pcf_isa_unreg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static void pcf_isa_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+static void pcf_isa_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+
+/* ------------------------------------------------------------------------
+ * 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_pcf_data pcf_isa_data = {
+ NULL,
+ pcf_isa_setbyte,
+ pcf_isa_getbyte,
+ pcf_isa_getown,
+ pcf_isa_getclock,
+ pcf_isa_waitforpin,
+ 80, 80, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter pcf_isa_ops = {
+ "PCF8584 ISA adapter",
+ I2C_HW_P_ELEK,
+ NULL,
+ &pcf_isa_data,
+ pcf_isa_inc_use,
+ pcf_isa_dec_use,
+ pcf_isa_reg,
+ pcf_isa_unreg,
+};
+
+int __init i2c_pcfisa_init(void)
+{
+
+ struct i2c_pcf_isa *pisa = &gpi;
+
+ printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n");
+ if (base == 0)
+ pisa->pi_base = DEFAULT_BASE;
+ else
+ pisa->pi_base = base;
+
+ if (irq == 0)
+ pisa->pi_irq = DEFAULT_IRQ;
+ else
+ pisa->pi_irq = irq;
+
+ if (clock == 0)
+ pisa->pi_clock = DEFAULT_CLOCK;
+ else
+ pisa->pi_clock = clock;
+
+ if (own == 0)
+ pisa->pi_own = DEFAULT_OWN;
+ else
+ pisa->pi_own = own;
+
+ pcf_isa_data.data = (void *)pisa;
+#if (LINUX_VERSION_CODE >= 0x020301)
+ init_waitqueue_head(&pcf_wait);
+#endif
+ if (pcf_isa_init() == 0) {
+ if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base);
+ return 0;
+}
+
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
+
+MODULE_PARM(base, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(clock, "i");
+MODULE_PARM(own, "i");
+
+int init_module(void)
+{
+ return i2c_pcfisa_init();
+}
+
+void cleanup_module(void)
+{
+ i2c_pcf_del_bus(&pcf_isa_ops);
+ pcf_isa_exit();
+}
+
+#endif
+
+
diff --git a/drivers/i2c/i2c-elv.c b/drivers/i2c/i2c-elv.c
new file mode 100644
index 000000000..1eb17cacf
--- /dev/null
+++ b/drivers/i2c/i2c-elv.c
@@ -0,0 +1,236 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-elv.c i2c-hw access for philips style parallel port adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 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> */
+
+/* $Id: i2c-elv.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020135
+#include <linux/init.h>
+#else
+#define __init
+#endif
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+# include <asm/uaccess.h>
+#else
+# include <asm/segment.h>
+#endif
+
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#define DEFAULT_BASE 0x378
+static int base=0;
+static unsigned char PortData = 0;
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) /* should be reasonable open, close &c. */
+#define DEB2(x) /* low level debugging - very slow */
+#define DEBE(x) x /* error messages */
+#define DEBINIT(x) x /* detection status messages */
+
+/* --- Convenience defines for the parallel port: */
+#define BASE (unsigned int)(data)
+#define DATA BASE /* Centronics data port */
+#define STAT (BASE+1) /* Centronics status port */
+#define CTRL (BASE+2) /* Centronics control port */
+
+
+/* ----- local functions ---------------------------------------------- */
+
+
+static void bit_elv_setscl(void *data, int state)
+{
+ if (state) {
+ PortData &= 0xfe;
+ } else {
+ PortData |=1;
+ }
+ outb(PortData, DATA);
+}
+
+static void bit_elv_setsda(void *data, int state)
+{
+ if (state) {
+ PortData &=0xfd;
+ } else {
+ PortData |=2;
+ }
+ outb(PortData, DATA);
+}
+
+static int bit_elv_getscl(void *data)
+{
+ return ( 0 == ( (inb_p(STAT)) & 0x08 ) );
+}
+
+static int bit_elv_getsda(void *data)
+{
+ return ( 0 == ( (inb_p(STAT)) & 0x40 ) );
+}
+
+static int bit_elv_init(void)
+{
+ if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
+ return -ENODEV;
+ } else {
+ /* test for ELV adap. */
+ if (inb(base+1) & 0x80) { /* BUSY should be high */
+ DEBINIT(printk("i2c-elv.o: Busy was low.\n"));
+ return -ENODEV;
+ } else {
+ outb(0x0c,base+2); /* SLCT auf low */
+ udelay(400);
+ if ( !(inb(base+1) && 0x10) ) {
+ outb(0x04,base+2);
+ DEBINIT(printk("i2c-elv.o: Select was high.\n"));
+ return -ENODEV;
+ }
+ }
+ request_region(base,(base == 0x3bc)? 3 : 8,
+ "i2c (ELV adapter)");
+ PortData = 0;
+ bit_elv_setsda((void*)base,1);
+ bit_elv_setscl((void*)base,1);
+ }
+ return 0;
+}
+
+static void bit_elv_exit(void)
+{
+ release_region( base , (base == 0x3bc)? 3 : 8 );
+}
+
+static int bit_elv_reg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int bit_elv_unreg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static void bit_elv_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+static void bit_elv_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+/* ------------------------------------------------------------------------
+ * 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 bit_elv_data = {
+ NULL,
+ bit_elv_setsda,
+ bit_elv_setscl,
+ bit_elv_getsda,
+ bit_elv_getscl,
+ 80, 80, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter bit_elv_ops = {
+ "ELV Parallel port adaptor",
+ I2C_HW_B_ELV,
+ NULL,
+ &bit_elv_data,
+ bit_elv_inc_use,
+ bit_elv_dec_use,
+ bit_elv_reg,
+ bit_elv_unreg,
+};
+
+int __init i2c_bitelv_init(void)
+{
+ printk("i2c-elv.o: i2c ELV parallel port adapter module\n");
+ if (base==0) {
+ /* probe some values */
+ base=DEFAULT_BASE;
+ bit_elv_data.data=(void*)DEFAULT_BASE;
+ if (bit_elv_init()==0) {
+ if(i2c_bit_add_bus(&bit_elv_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ } else {
+ bit_elv_ops.data=(void*)base;
+ if (bit_elv_init()==0) {
+ if(i2c_bit_add_bus(&bit_elv_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ }
+ printk("i2c-elv.o: found device at %#x.\n",base);
+ return 0;
+}
+
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter")
+;
+
+MODULE_PARM(base, "i");
+
+int init_module(void)
+{
+ return i2c_bitelv_init();
+}
+
+void cleanup_module(void)
+{
+ i2c_bit_del_bus(&bit_elv_ops);
+ bit_elv_exit();
+}
+
+#endif
diff --git a/drivers/i2c/i2c-pcf8584.h b/drivers/i2c/i2c-pcf8584.h
new file mode 100644
index 000000000..7dabbd9a9
--- /dev/null
+++ b/drivers/i2c/i2c-pcf8584.h
@@ -0,0 +1,78 @@
+/* -------------------------------------------------------------------- */
+/* 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> */
+
+/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */
+
+#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_CLK8 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/i2c-philips-par.c b/drivers/i2c/i2c-philips-par.c
new file mode 100644
index 000000000..52079eb88
--- /dev/null
+++ b/drivers/i2c/i2c-philips-par.c
@@ -0,0 +1,232 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-philips-par.c i2c-hw access for philips style parallel port adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 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> */
+
+/* $Id: i2c-philips-par.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#if LINUX_VERSION_CODE >= 0x020135
+#include <linux/init.h>
+#else
+#define __init
+#endif
+#include <asm/io.h>
+#include <linux/stddef.h>
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#define DEFAULT_BASE 0x378
+static int base=0;
+
+/* Note: all we need to know is the base address of the parallel port, so
+ * instead of having a dedicated struct to store this value, we store this
+ * int in the pointer field (=bit_lp_ops.data) itself.
+ */
+
+/* Note2: as the hw that implements the i2c bus on the parallel port is
+ * incompatible with other epp stuff etc., we access the port exclusively
+ * and don't cooperate with parport functions.
+ */
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) /* should be reasonable open, close &c. */
+#define DEB2(x) /* low level debugging - very slow */
+#define DEBE(x) x /* error messages */
+
+/* ----- printer port defines ------------------------------------------*/
+ /* Pin Port Inverted name */
+#define I2C_ON 0x20 /* 12 status N paper */
+ /* ... only for phil. not used */
+#define I2C_SDA 0x80 /* 9 data N data7 */
+#define I2C_SCL 0x08 /* 17 ctrl N dsel */
+
+#define I2C_SDAIN 0x80 /* 11 stat Y busy */
+#define I2C_SCLIN 0x08 /* 15 stat Y enable */
+
+#define I2C_DMASK 0x7f
+#define I2C_CMASK 0xf7
+
+/* --- Convenience defines for the parallel port: */
+#define BASE (unsigned int)(data)
+#define DATA BASE /* Centronics data port */
+#define STAT (BASE+1) /* Centronics status port */
+#define CTRL (BASE+2) /* Centronics control port */
+
+/* ----- local functions ---------------------------------------------- */
+
+static void bit_lp_setscl(void *data, int state)
+{
+ /*be cautious about state of the control register -
+ touch only the one bit needed*/
+ if (state) {
+ outb(inb(CTRL)|I2C_SCL, CTRL);
+ } else {
+ outb(inb(CTRL)&I2C_CMASK, CTRL);
+ }
+}
+
+static void bit_lp_setsda(void *data, int state)
+{
+ if (state) {
+ outb(I2C_DMASK , DATA);
+ } else {
+ outb(I2C_SDA , DATA);
+ }
+}
+
+static int bit_lp_getscl(void *data)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SCLIN ) );
+}
+
+static int bit_lp_getsda(void *data)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
+}
+
+static int bit_lp_init(void)
+{
+ if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(base,(base == 0x3bc)? 3 : 8,
+ "i2c (parallel port adapter)");
+ /* reset hardware to sane state */
+ bit_lp_setsda((void*)base,1);
+ bit_lp_setscl((void*)base,1);
+ }
+ return 0;
+}
+
+static void bit_lp_exit(void)
+{
+ release_region( base , (base == 0x3bc)? 3 : 8 );
+}
+
+static int bit_lp_reg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int bit_lp_unreg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static void bit_lp_inc_use(struct i2c_adapter *adap)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void bit_lp_dec_use(struct i2c_adapter *adap)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------------------
+ * 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 bit_lp_data = {
+ NULL,
+ bit_lp_setsda,
+ bit_lp_setscl,
+ bit_lp_getsda,
+ bit_lp_getscl,
+ 80, 80, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter bit_lp_ops = {
+ "Philips Parallel port adapter",
+ I2C_HW_B_LP,
+ NULL,
+ &bit_lp_data,
+ bit_lp_inc_use,
+ bit_lp_dec_use,
+ bit_lp_reg,
+ bit_lp_unreg,
+};
+
+
+int __init i2c_bitlp_init(void)
+{
+ printk("i2c-philips-par.o: i2c Philips parallel port adapter module\n");
+ if (base==0) {
+ /* probe some values */
+ base=DEFAULT_BASE;
+ bit_lp_data.data=(void*)DEFAULT_BASE;
+ if (bit_lp_init()==0) {
+ if (i2c_bit_add_bus(&bit_lp_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ } else {
+ bit_lp_data.data=(void*)base;
+ if (bit_lp_init()==0) {
+ if (i2c_bit_add_bus(&bit_lp_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ }
+ printk("i2c-philips-par.o: found device at %#x.\n",base);
+ return 0;
+}
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter");
+
+MODULE_PARM(base, "i");
+
+int init_module(void)
+{
+ return i2c_bitlp_init();
+}
+
+void cleanup_module(void)
+{
+ i2c_bit_del_bus(&bit_lp_ops);
+ bit_lp_exit();
+}
+
+#endif
+
+
+
diff --git a/drivers/i2c/i2c-velleman.c b/drivers/i2c/i2c-velleman.c
new file mode 100644
index 000000000..7a3bc3522
--- /dev/null
+++ b/drivers/i2c/i2c-velleman.c
@@ -0,0 +1,219 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-velleman.c i2c-hw access for Velleman K9000 adapters */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-96 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. */
+/* -------------------------------------------------------------------------
+
+/* $Id: i2c-velleman.c,v 1.14 1999/12/21 23:45:58 frodo Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#if LINUX_VERSION_CODE >= 0x020135
+#include <linux/init.h>
+#else
+#define __init
+#endif
+#include <linux/string.h> /* for 2.0 kernels to get NULL */
+#include <asm/errno.h> /* for 2.0 kernels to get ENODEV */
+#include <asm/io.h>
+
+/* 2.0.0 kernel compatibility */
+#if LINUX_VERSION_CODE < 0x020100
+#define MODULE_AUTHOR(noone)
+#define MODULE_DESCRIPTION(none)
+#define MODULE_PARM(no,param)
+#define MODULE_PARM_DESC(no,description)
+#define EXPORT_SYMBOL(noexport)
+#define EXPORT_NO_SYMBOLS
+#endif
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) /* should be reasonable open, close &c. */
+#define DEB2(x) /* low level debugging - very slow */
+#define DEBE(x) x /* error messages */
+
+ /* Pin Port Inverted name */
+#define I2C_SDA 0x02 /* ctrl bit 1 (inv) */
+#define I2C_SCL 0x08 /* ctrl bit 3 (inv) */
+
+#define I2C_SDAIN 0x10 /* stat bit 4 */
+#define I2C_SCLIN 0x08 /* ctrl bit 3 (inv) (reads own output) */
+
+#define I2C_DMASK 0xfd
+#define I2C_CMASK 0xf7
+
+
+/* --- Convenience defines for the parallel port: */
+#define BASE (unsigned int)(data)
+#define DATA BASE /* Centronics data port */
+#define STAT (BASE+1) /* Centronics status port */
+#define CTRL (BASE+2) /* Centronics control port */
+
+#define DEFAULT_BASE 0x378
+static int base=0;
+
+/* ----- local functions --------------------------------------------------- */
+
+static void bit_velle_setscl(void *data, int state)
+{
+ if (state) {
+ outb(inb(CTRL) & I2C_CMASK, CTRL);
+ } else {
+ outb(inb(CTRL) | I2C_SCL, CTRL);
+ }
+
+}
+
+static void bit_velle_setsda(void *data, int state)
+{
+ if (state) {
+ outb(inb(CTRL) & I2C_DMASK , CTRL);
+ } else {
+ outb(inb(CTRL) | I2C_SDA, CTRL);
+ }
+
+}
+
+static int bit_velle_getscl(void *data)
+{
+ return ( 0 == ( (inb(CTRL)) & I2C_SCLIN ) );
+}
+
+static int bit_velle_getsda(void *data)
+{
+ return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
+}
+
+static int bit_velle_init(void)
+{
+ if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
+ DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", base));
+ return -ENODEV;
+ } else {
+ request_region(base, (base == 0x3bc)? 3 : 8,
+ "i2c (Vellemann adapter)");
+ bit_velle_setsda((void*)base,1);
+ bit_velle_setscl((void*)base,1);
+ }
+ return 0;
+}
+
+static void bit_velle_exit(void)
+{
+ release_region( base , (base == 0x3bc)? 3 : 8 );
+}
+
+
+static int bit_velle_reg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int bit_velle_unreg(struct i2c_client *client)
+{
+ return 0;
+}
+
+static void bit_velle_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+static void bit_velle_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+/* ------------------------------------------------------------------------
+ * 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 bit_velle_data = {
+ NULL,
+ bit_velle_setsda,
+ bit_velle_setscl,
+ bit_velle_getsda,
+ bit_velle_getscl,
+ 10, 10, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter bit_velle_ops = {
+ "Velleman K8000",
+ I2C_HW_B_VELLE,
+ NULL,
+ &bit_velle_data,
+ bit_velle_inc_use,
+ bit_velle_dec_use,
+ bit_velle_reg,
+ bit_velle_unreg,
+};
+
+int __init i2c_bitvelle_init(void)
+{
+ printk("i2c-velleman.o: i2c Velleman K8000 adapter module\n");
+ if (base==0) {
+ /* probe some values */
+ base=DEFAULT_BASE;
+ bit_velle_data.data=(void*)DEFAULT_BASE;
+ if (bit_velle_init()==0) {
+ if(i2c_bit_add_bus(&bit_velle_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ } else {
+ bit_velle_data.data=(void*)base;
+ if (bit_velle_init()==0) {
+ if(i2c_bit_add_bus(&bit_velle_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ }
+ printk("i2c-velleman.o: found device at %#x.\n",base);
+ return 0;
+}
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter");
+
+MODULE_PARM(base, "i");
+
+int init_module(void)
+{
+ return i2c_bitvelle_init();
+}
+
+void cleanup_module(void)
+{
+ i2c_bit_del_bus(&bit_velle_ops);
+ bit_velle_exit();
+}
+
+#endif