patch-2.4.13 linux/drivers/i2c/i2c-algo-pcf.c
Next file: linux/drivers/i2c/i2c-core.c
Previous file: linux/drivers/i2c/i2c-algo-ite.c
Back to the patch index
Back to the overall index
- Lines: 524
- Date:
Thu Oct 11 08:05:47 2001
- Orig file:
v2.4.12/linux/drivers/i2c/i2c-algo-pcf.c
- Orig date:
Tue Oct 9 17:06:51 2001
diff -u --recursive --new-file v2.4.12/linux/drivers/i2c/i2c-algo-pcf.c linux/drivers/i2c/i2c-algo-pcf.c
@@ -1,4 +1,3 @@
-
/* ------------------------------------------------------------------------- */
/* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */
/* ------------------------------------------------------------------------- */
@@ -24,7 +23,9 @@
Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
<mbailey@littlefeet-inc.com> */
-/* $Id: i2c-algo-pcf.c,v 1.25 2000/11/10 13:43:32 frodo Exp $ */
+/* Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
+ messages, proper stop/repstart signaling during receive,
+ added detect code */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -49,26 +50,9 @@
/* 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 */
-/*
-#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
- if (need_resched) schedule();
-*/
-
-
-/* ----- 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 i2c_debug=0;
static int pcf_scan=0; /* have a look at what's hanging 'round */
/* --- setting states on the bus with the right timing: --------------- */
@@ -80,7 +64,6 @@
#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
#define i2c_inb(adap) adap->getpcf(adap->data, 0)
-
/* --- other auxiliary functions -------------------------------------- */
static void i2c_start(struct i2c_algo_pcf_data *adap)
@@ -111,16 +94,15 @@
status = get_pcf(adap, 1);
#ifndef STUB_I2C
while (timeout-- && !(status & I2C_PCF_BB)) {
- udelay(1000); /* How much is this? */
+ udelay(100); /* wait for 100 us */
status = get_pcf(adap, 1);
}
#endif
- if (timeout<=0)
+ if (timeout <= 0) {
printk("Timeout waiting for Bus Busy\n");
- /*
- set_pcf(adap, 1, I2C_PCF_STOP);
- */
- return(timeout<=0);
+ }
+
+ return (timeout<=0);
}
@@ -147,7 +129,6 @@
return(0);
}
-
/*
* This should perform the 'PCF8584 initialization sequence' as described
* in the Philips IC12 data book (1995, Aug 29).
@@ -156,111 +137,64 @@
* There should be a delay at the end equal to the longest I2C message
* to synchronize the BB-bit (in multimaster systems). How long is
* this? I assume 1 second is always long enough.
+ *
+ * vdovikin: added detect code for PCF8584
*/
static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
{
+ unsigned char temp;
+
+ DEB3(printk("i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1)));
- /* S1=0x80: S0 selected, serial interface off */
+ /* S1=0x80: S0 selected, serial interface off */
set_pcf(adap, 1, I2C_PCF_PIN);
+ /* check to see S1 now used as R/W ctrl -
+ PCF8584 does that when ESO is zero */
+ /* PCF also resets PIN bit */
+ if ((temp = get_pcf(adap, 1)) != (0)) {
+ DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+ return -ENXIO; /* definetly not PCF8584 */
+ }
/* load own address in S0, effective address is (own << 1) */
i2c_outb(adap, get_own(adap));
+ /* check it's realy writen */
+ if ((temp = i2c_inb(adap)) != get_own(adap)) {
+ DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
/* S1=0xA0, next byte in S2 */
set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+ /* check to see S2 now selected */
+ if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) {
+ DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
/* load clock register S2 */
i2c_outb(adap, get_clock(adap));
+ /* check it's realy writen, the only 5 lowest bits does matter */
+ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
+ DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
/* Enable serial interface, idle, S0 selected */
set_pcf(adap, 1, I2C_PCF_IDLE);
- 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;
+ /* check to see PCF is realy idled and we can access status register */
+ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
+ DEB2(printk("i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+ return -ENXIO;
}
- 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);
+
+ printk("i2c-algo-pcf.o: deteted and initialized PCF8584.\n");
+
return 0;
-bailout:
- sdahi(adap);
- sclhi(adap);
- return -ENODEV;
-#endif
- return (0);
}
+
/* ----- Utility functions
*/
@@ -287,8 +221,8 @@
}
-static int pcf_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
- int count)
+static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+ int count, int last)
{
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
int wrcount, status, timeout;
@@ -313,58 +247,59 @@
}
#endif
}
- i2c_stop(adap);
+ if (last) {
+ i2c_stop(adap);
+ }
+ else {
+ i2c_repstart(adap);
+ }
+
return (wrcount);
}
-static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+ int count, int last)
{
- int rdcount=0, i, status, timeout, dummy=1;
+ int i, status;
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
-
- for (i=0; i<count; ++i) {
- buf[rdcount] = i2c_inb(adap);
- if (dummy) {
- dummy = 0;
- } else {
- rdcount++;
- }
- timeout = wait_for_pin(adap, &status);
- if (timeout) {
+
+ /* increment number of bytes to read by one -- read dummy byte */
+ for (i = 0; i <= count; i++) {
+
+ if (wait_for_pin(adap, &status)) {
i2c_stop(adap);
- printk("i2c-algo-pcf.o: i2c_read: "
- "i2c_inb timed out.\n");
+ printk("i2c-algo-pcf.o: pcf_readbytes timed out.\n");
return (-1);
}
+
#ifndef STUB_I2C
- if (status & I2C_PCF_LRB) {
+ if ((status & I2C_PCF_LRB) && (i != count)) {
i2c_stop(adap);
printk("i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n");
return (-1);
}
#endif
- }
- 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) {
- i2c_stop(adap);
- printk("i2c-algo-pcf.o: i2c_read: i2c_inb timed out.\n");
- return (-1);
- }
-
- i2c_stop(adap);
+
+ if (i == count - 1) {
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ } else
+ if (i == count) {
+ if (last) {
+ i2c_stop(adap);
+ } else {
+ i2c_repstart(adap);
+ }
+ };
- /* Read final byte from S0 register */
- buf[rdcount++] = i2c_inb(adap);
+ if (i) {
+ buf[i - 1] = i2c_inb(adap);
+ } else {
+ i2c_inb(adap); /* dummy read */
+ }
+ }
- return (rdcount);
+ return (i - 1);
}
@@ -418,16 +353,10 @@
{
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
struct i2c_msg *pmsg;
- int i = 0;
- int ret, timeout, status;
-
- pmsg = &msgs[i];
-
- /* Send address here if Read */
- if (pmsg->flags & I2C_M_RD) {
- ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
- }
+ int i;
+ int ret=0, timeout, status;
+
/* Check for bus busy */
timeout = wait_for_bb(adap);
if (timeout) {
@@ -435,60 +364,68 @@
"Timeout waiting for BB in pcf_xfer\n");)
return -EIO;
}
+
+ for (i = 0;ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+
+ DEB2(printk("i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);)
- /* Send address here if Write */
- if (!(pmsg->flags & I2C_M_RD)) {
ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
- }
- /* Send START */
- i2c_start(adap);
+
+ /* Send START */
+ if (i == 0) {
+ i2c_start(adap);
+ }
- /* Wait for PIN (pending interrupt NOT) */
- timeout = wait_for_pin(adap, &status);
- if (timeout) {
- i2c_stop(adap);
- DEB2(printk("i2c-algo-pcf.o: Timeout waiting "
- "for PIN(1) in pcf_xfer\n");)
- return (-EREMOTEIO);
- }
+ /* Wait for PIN (pending interrupt NOT) */
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ i2c_stop(adap);
+ DEB2(printk("i2c-algo-pcf.o: Timeout waiting "
+ "for PIN(1) in pcf_xfer\n");)
+ return (-EREMOTEIO);
+ }
#ifndef STUB_I2C
- /* Check LRB (last rcvd bit - slave ack) */
- if (status & I2C_PCF_LRB) {
- i2c_stop(adap);
- DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
- return (-EREMOTEIO);
- }
+ /* Check LRB (last rcvd bit - slave ack) */
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
+ return (-EREMOTEIO);
+ }
#endif
- 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);)
+ 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);)
- /* Read */
- if (pmsg->flags & I2C_M_RD) {
+ /* Read */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read bytes into buffer*/
+ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
- /* read bytes into buffer*/
- ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len);
-
- if (ret != pmsg->len) {
- DEB2(printk("i2c-algo-pcf.o: fail: "
- "only read %d bytes.\n",ret));
- } else {
- DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret));
- }
- } else { /* Write */
-
- /* Write bytes from buffer */
- ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
+ if (ret != pmsg->len) {
+ DEB2(printk("i2c-algo-pcf.o: fail: "
+ "only read %d bytes.\n",ret));
+ } else {
+ DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret));
+ }
+ } else { /* Write */
+ ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
- if (ret != pmsg->len) {
- DEB2(printk("i2c-algo-pcf.o: fail: "
- "only wrote %d bytes.\n",ret));
- } else {
- DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+ if (ret != pmsg->len) {
+ DEB2(printk("i2c-algo-pcf.o: fail: "
+ "only wrote %d bytes.\n",ret));
+ } else {
+ DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+ }
}
}
- return (num);
+
+ return (i);
}
static int algo_control(struct i2c_adapter *adapter,
@@ -524,12 +461,6 @@
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));
@@ -538,21 +469,29 @@
adap->id |= pcf_algo.id;
adap->algo = &pcf_algo;
- adap->timeout = 100; /* default values, should */
+ adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
+ if ((i = pcf_init_8584(pcf_adap))) {
+ return i;
+ }
+
#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) {
+ if (wait_for_bb(pcf_adap)) {
+ printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s - TIMEOUTed.\n",
+ adap->name);
+ break;
+ }
i2c_outb(pcf_adap, i);
i2c_start(pcf_adap);
if ((wait_for_pin(pcf_adap, &status) >= 0) &&
@@ -598,11 +537,9 @@
MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
MODULE_LICENSE("GPL");
-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");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)