Loading drivers/i2c/algos/i2c-algo-pcf.c +115 −135 Original line number Diff line number Diff line /* ------------------------------------------------------------------------- */ /* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */ /* ------------------------------------------------------------------------- */ /* Copyright (C) 1995-1997 Simon G. Vogl 1998-2000 Hans Berglund This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey <mbailey@littlefeet-inc.com> */ /* Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple messages, proper stop/repstart signaling during receive, added detect code */ /* * i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters * * Copyright (C) 1995-1997 Simon G. Vogl * 1998-2000 Hans Berglund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey * <mbailey@littlefeet-inc.com> * * Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple * messages, proper stop/repstart signaling during receive, added detect code */ #include <linux/kernel.h> #include <linux/module.h> Loading @@ -44,11 +43,12 @@ /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 /* module parameters: /* * module parameters: */ static int i2c_debug; /* --- setting states on the bus with the right timing: --------------- */ /* 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) Loading @@ -57,7 +57,7 @@ static int i2c_debug; #define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val) #define i2c_inb(adap) adap->getpcf(adap->data, 0) /* --- other auxiliary functions -------------------------------------- */ /* other auxiliary functions */ static void i2c_start(struct i2c_algo_pcf_data *adap) { Loading @@ -71,7 +71,6 @@ static void i2c_repstart(struct i2c_algo_pcf_data *adap) set_pcf(adap, 1, I2C_PCF_REPSTART); } static void i2c_stop(struct i2c_algo_pcf_data *adap) { DEBPROTO(printk("P\n")); Loading @@ -83,16 +82,16 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) DEB2(printk(KERN_INFO "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", *status)); /* Cleanup from LAB -- reset and enable ESO. /* * Cleanup from LAB -- reset and enable ESO. * This resets the PCF8584; since we've lost the bus, no * further attempts should be made by callers to clean up * (no i2c_stop() etc.) */ set_pcf(adap, 1, I2C_PCF_PIN); set_pcf(adap, 1, I2C_PCF_ESO); /* We pause for a time period sufficient for any running /* * We pause for a time period sufficient for any running * I2C transaction to complete -- the arbitration logic won't * work properly until the next START is seen. * It is assumed the bus driver or client has set a proper value. Loading @@ -108,45 +107,45 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) get_pcf(adap, 1))); } static int wait_for_bb(struct i2c_algo_pcf_data *adap) { static int wait_for_bb(struct i2c_algo_pcf_data *adap) { int timeout = DEF_TIMEOUT; int status; status = get_pcf(adap, 1); #ifndef STUB_I2C while (timeout-- && !(status & I2C_PCF_BB)) { udelay(100); /* wait for 100 us */ status = get_pcf(adap, 1); } #endif if (timeout <= 0) { if (timeout <= 0) printk(KERN_ERR "Timeout waiting for Bus Busy\n"); } return (timeout<=0); return timeout <= 0; } static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { int timeout = DEF_TIMEOUT; *status = get_pcf(adap, 1); #ifndef STUB_I2C while (timeout-- && (*status & I2C_PCF_PIN)) { adap->waitforpin(adap->data); *status = get_pcf(adap, 1); } if (*status & I2C_PCF_LAB) { handle_lab(adap, status); return(-EINTR); return -EINTR; } #endif if (timeout <= 0) return(-1); return -1; else return(0); return 0; } /* Loading @@ -164,12 +163,15 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) { unsigned char temp; DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); /* S1=0x80: S0 selected, serial interface off */ set_pcf(adap, 1, I2C_PCF_PIN); /* check to see S1 now used as R/W ctrl - PCF8584 does that when ESO is zero */ /* * check to see S1 now used as R/W ctrl - * PCF8584 does that when ESO is zero */ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); return -ENXIO; /* definetly not PCF8584 */ Loading Loading @@ -213,10 +215,6 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) return 0; } /* ----- Utility functions */ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, int count, int last) { Loading @@ -229,33 +227,27 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { if (timeout == -EINTR) { /* arbitration lost */ return -EINTR; } if (timeout == -EINTR) return -EINTR; /* arbitration lost */ i2c_stop(adap); dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n"); return -EREMOTEIO; /* got a better one ?? */ } #ifndef STUB_I2C if (status & I2C_PCF_LRB) { i2c_stop(adap); dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n"); return -EREMOTEIO; /* got a better one ?? */ } #endif } if (last) { if (last) i2c_stop(adap); } else { else i2c_repstart(adap); } return (wrcount); return wrcount; } static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int last) { Loading @@ -267,42 +259,36 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, for (i = 0; i <= count; i++) { if ((wfp = wait_for_pin(adap, &status))) { if (wfp == -EINTR) { /* arbitration lost */ return -EINTR; } if (wfp == -EINTR) return -EINTR; /* arbitration lost */ i2c_stop(adap); dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n"); return (-1); return -1; } #ifndef STUB_I2C if ((status & I2C_PCF_LRB) && (i != count)) { i2c_stop(adap); dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n"); return (-1); return -1; } #endif if (i == count - 1) { set_pcf(adap, 1, I2C_PCF_ESO); } else if (i == count) { if (last) { } else if (i == count) { if (last) i2c_stop(adap); } else { else i2c_repstart(adap); } }; if (i) { if (i) buf[i - 1] = i2c_inb(adap); } else { else i2c_inb(adap); /* dummy read */ } } return (i - 1); return i - 1; } Loading Loading @@ -353,9 +339,8 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, ret = pcf_doAddress(adap, pmsg); /* Send START */ if (i == 0) { if (i == 0) i2c_start(adap); } /* Wait for PIN (pending interrupt NOT) */ timeout = wait_for_pin(adap, &status); Loading @@ -372,7 +357,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, goto out; } #ifndef STUB_I2C /* Check LRB (last rcvd bit - slave ack) */ if (status & I2C_PCF_LRB) { i2c_stop(adap); Loading @@ -380,14 +364,11 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, i = -EREMOTEIO; goto out; } #endif DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", i, msgs[i].addr, msgs[i].flags, msgs[i].len);) /* Read */ if (pmsg->flags & I2C_M_RD) { /* read bytes into buffer*/ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); Loading @@ -397,7 +378,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, } else { DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); } } else { /* Write */ } else { ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); Loading @@ -413,7 +394,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, out: if (adap->xfer_end) adap->xfer_end(adap->data); return (i); return i; } static u32 pcf_func(struct i2c_adapter *adap) Loading @@ -422,8 +403,7 @@ static u32 pcf_func(struct i2c_adapter *adap) I2C_FUNC_PROTOCOL_MANGLING; } /* -----exported algorithm data: ------------------------------------- */ /* exported algorithm data: */ static const struct i2c_algorithm pcf_algo = { .master_xfer = pcf_xfer, .functionality = pcf_func, Loading Loading
drivers/i2c/algos/i2c-algo-pcf.c +115 −135 Original line number Diff line number Diff line /* ------------------------------------------------------------------------- */ /* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */ /* ------------------------------------------------------------------------- */ /* Copyright (C) 1995-1997 Simon G. Vogl 1998-2000 Hans Berglund This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey <mbailey@littlefeet-inc.com> */ /* Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple messages, proper stop/repstart signaling during receive, added detect code */ /* * i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters * * Copyright (C) 1995-1997 Simon G. Vogl * 1998-2000 Hans Berglund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey * <mbailey@littlefeet-inc.com> * * Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple * messages, proper stop/repstart signaling during receive, added detect code */ #include <linux/kernel.h> #include <linux/module.h> Loading @@ -44,11 +43,12 @@ /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 /* module parameters: /* * module parameters: */ static int i2c_debug; /* --- setting states on the bus with the right timing: --------------- */ /* 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) Loading @@ -57,7 +57,7 @@ static int i2c_debug; #define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val) #define i2c_inb(adap) adap->getpcf(adap->data, 0) /* --- other auxiliary functions -------------------------------------- */ /* other auxiliary functions */ static void i2c_start(struct i2c_algo_pcf_data *adap) { Loading @@ -71,7 +71,6 @@ static void i2c_repstart(struct i2c_algo_pcf_data *adap) set_pcf(adap, 1, I2C_PCF_REPSTART); } static void i2c_stop(struct i2c_algo_pcf_data *adap) { DEBPROTO(printk("P\n")); Loading @@ -83,16 +82,16 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) DEB2(printk(KERN_INFO "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", *status)); /* Cleanup from LAB -- reset and enable ESO. /* * Cleanup from LAB -- reset and enable ESO. * This resets the PCF8584; since we've lost the bus, no * further attempts should be made by callers to clean up * (no i2c_stop() etc.) */ set_pcf(adap, 1, I2C_PCF_PIN); set_pcf(adap, 1, I2C_PCF_ESO); /* We pause for a time period sufficient for any running /* * We pause for a time period sufficient for any running * I2C transaction to complete -- the arbitration logic won't * work properly until the next START is seen. * It is assumed the bus driver or client has set a proper value. Loading @@ -108,45 +107,45 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) get_pcf(adap, 1))); } static int wait_for_bb(struct i2c_algo_pcf_data *adap) { static int wait_for_bb(struct i2c_algo_pcf_data *adap) { int timeout = DEF_TIMEOUT; int status; status = get_pcf(adap, 1); #ifndef STUB_I2C while (timeout-- && !(status & I2C_PCF_BB)) { udelay(100); /* wait for 100 us */ status = get_pcf(adap, 1); } #endif if (timeout <= 0) { if (timeout <= 0) printk(KERN_ERR "Timeout waiting for Bus Busy\n"); } return (timeout<=0); return timeout <= 0; } static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { int timeout = DEF_TIMEOUT; *status = get_pcf(adap, 1); #ifndef STUB_I2C while (timeout-- && (*status & I2C_PCF_PIN)) { adap->waitforpin(adap->data); *status = get_pcf(adap, 1); } if (*status & I2C_PCF_LAB) { handle_lab(adap, status); return(-EINTR); return -EINTR; } #endif if (timeout <= 0) return(-1); return -1; else return(0); return 0; } /* Loading @@ -164,12 +163,15 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) { unsigned char temp; DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1))); /* S1=0x80: S0 selected, serial interface off */ set_pcf(adap, 1, I2C_PCF_PIN); /* check to see S1 now used as R/W ctrl - PCF8584 does that when ESO is zero */ /* * check to see S1 now used as R/W ctrl - * PCF8584 does that when ESO is zero */ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); return -ENXIO; /* definetly not PCF8584 */ Loading Loading @@ -213,10 +215,6 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) return 0; } /* ----- Utility functions */ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, int count, int last) { Loading @@ -229,33 +227,27 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { if (timeout == -EINTR) { /* arbitration lost */ return -EINTR; } if (timeout == -EINTR) return -EINTR; /* arbitration lost */ i2c_stop(adap); dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n"); return -EREMOTEIO; /* got a better one ?? */ } #ifndef STUB_I2C if (status & I2C_PCF_LRB) { i2c_stop(adap); dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n"); return -EREMOTEIO; /* got a better one ?? */ } #endif } if (last) { if (last) i2c_stop(adap); } else { else i2c_repstart(adap); } return (wrcount); return wrcount; } static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int last) { Loading @@ -267,42 +259,36 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, for (i = 0; i <= count; i++) { if ((wfp = wait_for_pin(adap, &status))) { if (wfp == -EINTR) { /* arbitration lost */ return -EINTR; } if (wfp == -EINTR) return -EINTR; /* arbitration lost */ i2c_stop(adap); dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n"); return (-1); return -1; } #ifndef STUB_I2C if ((status & I2C_PCF_LRB) && (i != count)) { i2c_stop(adap); dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n"); return (-1); return -1; } #endif if (i == count - 1) { set_pcf(adap, 1, I2C_PCF_ESO); } else if (i == count) { if (last) { } else if (i == count) { if (last) i2c_stop(adap); } else { else i2c_repstart(adap); } }; if (i) { if (i) buf[i - 1] = i2c_inb(adap); } else { else i2c_inb(adap); /* dummy read */ } } return (i - 1); return i - 1; } Loading Loading @@ -353,9 +339,8 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, ret = pcf_doAddress(adap, pmsg); /* Send START */ if (i == 0) { if (i == 0) i2c_start(adap); } /* Wait for PIN (pending interrupt NOT) */ timeout = wait_for_pin(adap, &status); Loading @@ -372,7 +357,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, goto out; } #ifndef STUB_I2C /* Check LRB (last rcvd bit - slave ack) */ if (status & I2C_PCF_LRB) { i2c_stop(adap); Loading @@ -380,14 +364,11 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, i = -EREMOTEIO; goto out; } #endif DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", i, msgs[i].addr, msgs[i].flags, msgs[i].len);) /* Read */ if (pmsg->flags & I2C_M_RD) { /* read bytes into buffer*/ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); Loading @@ -397,7 +378,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, } else { DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); } } else { /* Write */ } else { ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); Loading @@ -413,7 +394,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, out: if (adap->xfer_end) adap->xfer_end(adap->data); return (i); return i; } static u32 pcf_func(struct i2c_adapter *adap) Loading @@ -422,8 +403,7 @@ static u32 pcf_func(struct i2c_adapter *adap) I2C_FUNC_PROTOCOL_MANGLING; } /* -----exported algorithm data: ------------------------------------- */ /* exported algorithm data: */ static const struct i2c_algorithm pcf_algo = { .master_xfer = pcf_xfer, .functionality = pcf_func, Loading