]> git.sur5r.net Git - u-boot/commitdiff
soft_i2c: move to drivers/i2c
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Thu, 28 Aug 2008 10:31:51 +0000 (12:31 +0200)
committerJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Fri, 29 Aug 2008 10:25:02 +0000 (12:25 +0200)
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
common/Makefile
common/soft_i2c.c [deleted file]
drivers/i2c/Makefile
drivers/i2c/soft_i2c.c [new file with mode: 0644]

index d974823a4bfabf00cd1bdd46c84df1d1bc785932..faeac86dc1d8c57bc5e3845f0580753f2c40205f 100644 (file)
@@ -137,7 +137,6 @@ COBJS-$(CONFIG_BITBANGMII) += miiphybb.o
 COBJS-y += miiphyutil.o
 COBJS-y += s_record.o
 COBJS-y += serial.o
-COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o
 COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
 ifdef CONFIG_CMD_USB
 COBJS-y += usb.o
diff --git a/common/soft_i2c.c b/common/soft_i2c.c
deleted file mode 100644 (file)
index 23db2ee..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * (C) Copyright 2001, 2002
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
- * vanbaren@cideas.com.  It was heavily influenced by LiMon, written by
- * Neil Russell.
- */
-
-#include <common.h>
-#ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
-#include <ioports.h>
-#endif
-#ifdef CONFIG_AT91RM9200               /* need this for the at91rm9200 */
-#include <asm/io.h>
-#include <asm/arch/hardware.h>
-#endif
-#ifdef CONFIG_IXP425                   /* only valid for IXP425 */
-#include <asm/arch/ixp425.h>
-#endif
-#ifdef CONFIG_LPC2292
-#include <asm/arch/hardware.h>
-#endif
-#include <i2c.h>
-
-/* #define     DEBUG_I2C       */
-
-#ifdef DEBUG_I2C
-DECLARE_GLOBAL_DATA_PTR;
-#endif
-
-
-/*-----------------------------------------------------------------------
- * Definitions
- */
-
-#define RETRIES                0
-
-
-#define I2C_ACK                0               /* PD_SDA level to ack a byte */
-#define I2C_NOACK      1               /* PD_SDA level to noack a byte */
-
-
-#ifdef DEBUG_I2C
-#define PRINTD(fmt,args...)    do {    \
-       if (gd->have_console)           \
-               printf (fmt ,##args);   \
-       } while (0)
-#else
-#define PRINTD(fmt,args...)
-#endif
-
-/*-----------------------------------------------------------------------
- * Local functions
- */
-static void  send_reset        (void);
-static void  send_start        (void);
-static void  send_stop (void);
-static void  send_ack  (int);
-static int   write_byte        (uchar byte);
-static uchar read_byte (int);
-
-
-/*-----------------------------------------------------------------------
- * Send a reset sequence consisting of 9 clocks with the data signal high
- * to clock any confused device back into an idle state.  Also send a
- * <stop> at the end of the sequence for belts & suspenders.
- */
-static void send_reset(void)
-{
-#ifdef CONFIG_MPC8260
-       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
-       volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
-       int j;
-
-       I2C_SCL(1);
-       I2C_SDA(1);
-#ifdef I2C_INIT
-       I2C_INIT;
-#endif
-       I2C_TRISTATE;
-       for(j = 0; j < 9; j++) {
-               I2C_SCL(0);
-               I2C_DELAY;
-               I2C_DELAY;
-               I2C_SCL(1);
-               I2C_DELAY;
-               I2C_DELAY;
-       }
-       send_stop();
-       I2C_TRISTATE;
-}
-
-/*-----------------------------------------------------------------------
- * START: High -> Low on SDA while SCL is High
- */
-static void send_start(void)
-{
-#ifdef CONFIG_MPC8260
-       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
-       volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
-
-       I2C_DELAY;
-       I2C_SDA(1);
-       I2C_ACTIVE;
-       I2C_DELAY;
-       I2C_SCL(1);
-       I2C_DELAY;
-       I2C_SDA(0);
-       I2C_DELAY;
-}
-
-/*-----------------------------------------------------------------------
- * STOP: Low -> High on SDA while SCL is High
- */
-static void send_stop(void)
-{
-#ifdef CONFIG_MPC8260
-       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
-       volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
-
-       I2C_SCL(0);
-       I2C_DELAY;
-       I2C_SDA(0);
-       I2C_ACTIVE;
-       I2C_DELAY;
-       I2C_SCL(1);
-       I2C_DELAY;
-       I2C_SDA(1);
-       I2C_DELAY;
-       I2C_TRISTATE;
-}
-
-
-/*-----------------------------------------------------------------------
- * ack should be I2C_ACK or I2C_NOACK
- */
-static void send_ack(int ack)
-{
-#ifdef CONFIG_MPC8260
-       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
-       volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
-
-       I2C_SCL(0);
-       I2C_DELAY;
-       I2C_ACTIVE;
-       I2C_SDA(ack);
-       I2C_DELAY;
-       I2C_SCL(1);
-       I2C_DELAY;
-       I2C_DELAY;
-       I2C_SCL(0);
-       I2C_DELAY;
-}
-
-
-/*-----------------------------------------------------------------------
- * Send 8 bits and look for an acknowledgement.
- */
-static int write_byte(uchar data)
-{
-#ifdef CONFIG_MPC8260
-       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
-       volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
-       int j;
-       int nack;
-
-       I2C_ACTIVE;
-       for(j = 0; j < 8; j++) {
-               I2C_SCL(0);
-               I2C_DELAY;
-               I2C_SDA(data & 0x80);
-               I2C_DELAY;
-               I2C_SCL(1);
-               I2C_DELAY;
-               I2C_DELAY;
-
-               data <<= 1;
-       }
-
-       /*
-        * Look for an <ACK>(negative logic) and return it.
-        */
-       I2C_SCL(0);
-       I2C_DELAY;
-       I2C_SDA(1);
-       I2C_TRISTATE;
-       I2C_DELAY;
-       I2C_SCL(1);
-       I2C_DELAY;
-       I2C_DELAY;
-       nack = I2C_READ;
-       I2C_SCL(0);
-       I2C_DELAY;
-       I2C_ACTIVE;
-
-       return(nack);   /* not a nack is an ack */
-}
-
-
-/*-----------------------------------------------------------------------
- * if ack == I2C_ACK, ACK the byte so can continue reading, else
- * send I2C_NOACK to end the read.
- */
-static uchar read_byte(int ack)
-{
-#ifdef CONFIG_MPC8260
-       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
-       volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
-       int  data;
-       int  j;
-
-       /*
-        * Read 8 bits, MSB first.
-        */
-       I2C_TRISTATE;
-       I2C_SDA(1);
-       data = 0;
-       for(j = 0; j < 8; j++) {
-               I2C_SCL(0);
-               I2C_DELAY;
-               I2C_SCL(1);
-               I2C_DELAY;
-               data <<= 1;
-               data |= I2C_READ;
-               I2C_DELAY;
-       }
-       send_ack(ack);
-
-       return(data);
-}
-
-/*=====================================================================*/
-/*                         Public Functions                            */
-/*=====================================================================*/
-
-/*-----------------------------------------------------------------------
- * Initialization
- */
-void i2c_init (int speed, int slaveaddr)
-{
-       /*
-        * WARNING: Do NOT save speed in a static variable: if the
-        * I2C routines are called before RAM is initialized (to read
-        * the DIMM SPD, for instance), RAM won't be usable and your
-        * system will crash.
-        */
-       send_reset ();
-}
-
-/*-----------------------------------------------------------------------
- * Probe to see if a chip is present.  Also good for checking for the
- * completion of EEPROM writes since the chip stops responding until
- * the write completes (typically 10mSec).
- */
-int i2c_probe(uchar addr)
-{
-       int rc;
-
-       /*
-        * perform 1 byte write transaction with just address byte
-        * (fake write)
-        */
-       send_start();
-       rc = write_byte ((addr << 1) | 0);
-       send_stop();
-
-       return (rc ? 1 : 0);
-}
-
-/*-----------------------------------------------------------------------
- * Read bytes
- */
-int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
-       int shift;
-       PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
-               chip, addr, alen, buffer, len);
-
-#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
-       /*
-        * EEPROM chips that implement "address overflow" are ones
-        * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
-        * address and the extra bits end up in the "chip address"
-        * bit slots. This makes a 24WC08 (1Kbyte) chip look like
-        * four 256 byte chips.
-        *
-        * Note that we consider the length of the address field to
-        * still be one byte because the extra address bits are
-        * hidden in the chip address.
-        */
-       chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
-
-       PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
-               chip, addr);
-#endif
-
-       /*
-        * Do the addressing portion of a write cycle to set the
-        * chip's address pointer.  If the address length is zero,
-        * don't do the normal write cycle to set the address pointer,
-        * there is no address pointer in this chip.
-        */
-       send_start();
-       if(alen > 0) {
-               if(write_byte(chip << 1)) {     /* write cycle */
-                       send_stop();
-                       PRINTD("i2c_read, no chip responded %02X\n", chip);
-                       return(1);
-               }
-               shift = (alen-1) * 8;
-               while(alen-- > 0) {
-                       if(write_byte(addr >> shift)) {
-                               PRINTD("i2c_read, address not <ACK>ed\n");
-                               return(1);
-                       }
-                       shift -= 8;
-               }
-               send_stop();    /* reportedly some chips need a full stop */
-               send_start();
-       }
-       /*
-        * Send the chip address again, this time for a read cycle.
-        * Then read the data.  On the last byte, we do a NACK instead
-        * of an ACK(len == 0) to terminate the read.
-        */
-       write_byte((chip << 1) | 1);    /* read cycle */
-       while(len-- > 0) {
-               *buffer++ = read_byte(len == 0);
-       }
-       send_stop();
-       return(0);
-}
-
-/*-----------------------------------------------------------------------
- * Write bytes
- */
-int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
-       int shift, failures = 0;
-
-       PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
-               chip, addr, alen, buffer, len);
-
-       send_start();
-       if(write_byte(chip << 1)) {     /* write cycle */
-               send_stop();
-               PRINTD("i2c_write, no chip responded %02X\n", chip);
-               return(1);
-       }
-       shift = (alen-1) * 8;
-       while(alen-- > 0) {
-               if(write_byte(addr >> shift)) {
-                       PRINTD("i2c_write, address not <ACK>ed\n");
-                       return(1);
-               }
-               shift -= 8;
-       }
-
-       while(len-- > 0) {
-               if(write_byte(*buffer++)) {
-                       failures++;
-               }
-       }
-       send_stop();
-       return(failures);
-}
-
-/*-----------------------------------------------------------------------
- * Read a register
- */
-uchar i2c_reg_read(uchar i2c_addr, uchar reg)
-{
-       uchar buf;
-
-       i2c_read(i2c_addr, reg, 1, &buf, 1);
-
-       return(buf);
-}
-
-/*-----------------------------------------------------------------------
- * Write a register
- */
-void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
-{
-       i2c_write(i2c_addr, reg, 1, &val, 1);
-}
index 1f25afb0ad7fb947f2e86653bd0752588bb49b8e..6079c05ade35a07bf65f3b690eda4b294ed70f67 100644 (file)
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
 COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
 COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o
 COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o
+COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o
 COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
 
 COBJS  := $(COBJS-y)
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
new file mode 100644 (file)
index 0000000..23db2ee
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
+ * vanbaren@cideas.com.  It was heavily influenced by LiMon, written by
+ * Neil Russell.
+ */
+
+#include <common.h>
+#ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
+#include <ioports.h>
+#endif
+#ifdef CONFIG_AT91RM9200               /* need this for the at91rm9200 */
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#endif
+#ifdef CONFIG_IXP425                   /* only valid for IXP425 */
+#include <asm/arch/ixp425.h>
+#endif
+#ifdef CONFIG_LPC2292
+#include <asm/arch/hardware.h>
+#endif
+#include <i2c.h>
+
+/* #define     DEBUG_I2C       */
+
+#ifdef DEBUG_I2C
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define RETRIES                0
+
+
+#define I2C_ACK                0               /* PD_SDA level to ack a byte */
+#define I2C_NOACK      1               /* PD_SDA level to noack a byte */
+
+
+#ifdef DEBUG_I2C
+#define PRINTD(fmt,args...)    do {    \
+       if (gd->have_console)           \
+               printf (fmt ,##args);   \
+       } while (0)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+/*-----------------------------------------------------------------------
+ * Local functions
+ */
+static void  send_reset        (void);
+static void  send_start        (void);
+static void  send_stop (void);
+static void  send_ack  (int);
+static int   write_byte        (uchar byte);
+static uchar read_byte (int);
+
+
+/*-----------------------------------------------------------------------
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state.  Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void send_reset(void)
+{
+#ifdef CONFIG_MPC8260
+       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+       int j;
+
+       I2C_SCL(1);
+       I2C_SDA(1);
+#ifdef I2C_INIT
+       I2C_INIT;
+#endif
+       I2C_TRISTATE;
+       for(j = 0; j < 9; j++) {
+               I2C_SCL(0);
+               I2C_DELAY;
+               I2C_DELAY;
+               I2C_SCL(1);
+               I2C_DELAY;
+               I2C_DELAY;
+       }
+       send_stop();
+       I2C_TRISTATE;
+}
+
+/*-----------------------------------------------------------------------
+ * START: High -> Low on SDA while SCL is High
+ */
+static void send_start(void)
+{
+#ifdef CONFIG_MPC8260
+       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+       I2C_DELAY;
+       I2C_SDA(1);
+       I2C_ACTIVE;
+       I2C_DELAY;
+       I2C_SCL(1);
+       I2C_DELAY;
+       I2C_SDA(0);
+       I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
+ * STOP: Low -> High on SDA while SCL is High
+ */
+static void send_stop(void)
+{
+#ifdef CONFIG_MPC8260
+       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+       I2C_SCL(0);
+       I2C_DELAY;
+       I2C_SDA(0);
+       I2C_ACTIVE;
+       I2C_DELAY;
+       I2C_SCL(1);
+       I2C_DELAY;
+       I2C_SDA(1);
+       I2C_DELAY;
+       I2C_TRISTATE;
+}
+
+
+/*-----------------------------------------------------------------------
+ * ack should be I2C_ACK or I2C_NOACK
+ */
+static void send_ack(int ack)
+{
+#ifdef CONFIG_MPC8260
+       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+       I2C_SCL(0);
+       I2C_DELAY;
+       I2C_ACTIVE;
+       I2C_SDA(ack);
+       I2C_DELAY;
+       I2C_SCL(1);
+       I2C_DELAY;
+       I2C_DELAY;
+       I2C_SCL(0);
+       I2C_DELAY;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Send 8 bits and look for an acknowledgement.
+ */
+static int write_byte(uchar data)
+{
+#ifdef CONFIG_MPC8260
+       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+       int j;
+       int nack;
+
+       I2C_ACTIVE;
+       for(j = 0; j < 8; j++) {
+               I2C_SCL(0);
+               I2C_DELAY;
+               I2C_SDA(data & 0x80);
+               I2C_DELAY;
+               I2C_SCL(1);
+               I2C_DELAY;
+               I2C_DELAY;
+
+               data <<= 1;
+       }
+
+       /*
+        * Look for an <ACK>(negative logic) and return it.
+        */
+       I2C_SCL(0);
+       I2C_DELAY;
+       I2C_SDA(1);
+       I2C_TRISTATE;
+       I2C_DELAY;
+       I2C_SCL(1);
+       I2C_DELAY;
+       I2C_DELAY;
+       nack = I2C_READ;
+       I2C_SCL(0);
+       I2C_DELAY;
+       I2C_ACTIVE;
+
+       return(nack);   /* not a nack is an ack */
+}
+
+
+/*-----------------------------------------------------------------------
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar read_byte(int ack)
+{
+#ifdef CONFIG_MPC8260
+       volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+       int  data;
+       int  j;
+
+       /*
+        * Read 8 bits, MSB first.
+        */
+       I2C_TRISTATE;
+       I2C_SDA(1);
+       data = 0;
+       for(j = 0; j < 8; j++) {
+               I2C_SCL(0);
+               I2C_DELAY;
+               I2C_SCL(1);
+               I2C_DELAY;
+               data <<= 1;
+               data |= I2C_READ;
+               I2C_DELAY;
+       }
+       send_ack(ack);
+
+       return(data);
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+void i2c_init (int speed, int slaveaddr)
+{
+       /*
+        * WARNING: Do NOT save speed in a static variable: if the
+        * I2C routines are called before RAM is initialized (to read
+        * the DIMM SPD, for instance), RAM won't be usable and your
+        * system will crash.
+        */
+       send_reset ();
+}
+
+/*-----------------------------------------------------------------------
+ * Probe to see if a chip is present.  Also good for checking for the
+ * completion of EEPROM writes since the chip stops responding until
+ * the write completes (typically 10mSec).
+ */
+int i2c_probe(uchar addr)
+{
+       int rc;
+
+       /*
+        * perform 1 byte write transaction with just address byte
+        * (fake write)
+        */
+       send_start();
+       rc = write_byte ((addr << 1) | 0);
+       send_stop();
+
+       return (rc ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------------
+ * Read bytes
+ */
+int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+       int shift;
+       PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
+               chip, addr, alen, buffer, len);
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+       /*
+        * EEPROM chips that implement "address overflow" are ones
+        * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+        * address and the extra bits end up in the "chip address"
+        * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+        * four 256 byte chips.
+        *
+        * Note that we consider the length of the address field to
+        * still be one byte because the extra address bits are
+        * hidden in the chip address.
+        */
+       chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+
+       PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
+               chip, addr);
+#endif
+
+       /*
+        * Do the addressing portion of a write cycle to set the
+        * chip's address pointer.  If the address length is zero,
+        * don't do the normal write cycle to set the address pointer,
+        * there is no address pointer in this chip.
+        */
+       send_start();
+       if(alen > 0) {
+               if(write_byte(chip << 1)) {     /* write cycle */
+                       send_stop();
+                       PRINTD("i2c_read, no chip responded %02X\n", chip);
+                       return(1);
+               }
+               shift = (alen-1) * 8;
+               while(alen-- > 0) {
+                       if(write_byte(addr >> shift)) {
+                               PRINTD("i2c_read, address not <ACK>ed\n");
+                               return(1);
+                       }
+                       shift -= 8;
+               }
+               send_stop();    /* reportedly some chips need a full stop */
+               send_start();
+       }
+       /*
+        * Send the chip address again, this time for a read cycle.
+        * Then read the data.  On the last byte, we do a NACK instead
+        * of an ACK(len == 0) to terminate the read.
+        */
+       write_byte((chip << 1) | 1);    /* read cycle */
+       while(len-- > 0) {
+               *buffer++ = read_byte(len == 0);
+       }
+       send_stop();
+       return(0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write bytes
+ */
+int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+       int shift, failures = 0;
+
+       PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
+               chip, addr, alen, buffer, len);
+
+       send_start();
+       if(write_byte(chip << 1)) {     /* write cycle */
+               send_stop();
+               PRINTD("i2c_write, no chip responded %02X\n", chip);
+               return(1);
+       }
+       shift = (alen-1) * 8;
+       while(alen-- > 0) {
+               if(write_byte(addr >> shift)) {
+                       PRINTD("i2c_write, address not <ACK>ed\n");
+                       return(1);
+               }
+               shift -= 8;
+       }
+
+       while(len-- > 0) {
+               if(write_byte(*buffer++)) {
+                       failures++;
+               }
+       }
+       send_stop();
+       return(failures);
+}
+
+/*-----------------------------------------------------------------------
+ * Read a register
+ */
+uchar i2c_reg_read(uchar i2c_addr, uchar reg)
+{
+       uchar buf;
+
+       i2c_read(i2c_addr, reg, 1, &buf, 1);
+
+       return(buf);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a register
+ */
+void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
+{
+       i2c_write(i2c_addr, reg, 1, &val, 1);
+}