This patch fix the i2c deblocking facility with the i2c HW-Controller.
The required delays for byte reading, the enhanced criteria for stop
the dummy read and required 5 start/stop sequences are added.

Add i2c deblocking before ivm eeprom read.

Improve i2c deblocking sequence by respecting stop hold time.

Cleaned function for deblocking. Have now one function i2c_make_abort()
available for bitbang, mpc82xx and mpc83xx harware controller.

Signed-off-by: Stefan Bigler <stefan.big...@keymile.com>
Signed-off-by: Holger Brunck <holger.bru...@keymile.com>
Signed-off-by: Heiko Schocher <h...@denx.de>
cc: Valentin Longchamp <valentin.longch...@keymile.com>
---
 board/keymile/common/common.c |  109 ++++++++++++++++++++++++++++++-----------
 1 files changed, 80 insertions(+), 29 deletions(-)

diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c
index 5b54e35..03d63c1 100644
--- a/board/keymile/common/common.c
+++ b/board/keymile/common/common.c
@@ -41,6 +41,7 @@
 #include <i2c.h>
 
 extern int i2c_soft_read_pin (void);
+extern int i2c_make_abort (void);
 
 int ivm_calc_crc (unsigned char *buf, int len)
 {
@@ -325,6 +326,9 @@ int ivm_read_eeprom (void)
        if (buf != NULL)
                dev_addr = simple_strtoul ((char *)buf, NULL, 16);
 
+       /* add deblocking here */
+       i2c_make_abort();
+
        if (i2c_read(dev_addr, 0, 1, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) 
!= 0) {
                printf ("Error reading EEprom\n");
                return -2;
@@ -334,7 +338,7 @@ int ivm_read_eeprom (void)
 }
 
 #if defined(CONFIG_SYS_I2C_INIT_BOARD)
-#define DELAY_ABORT_SEQ                62
+#define DELAY_ABORT_SEQ                62  /* @200kHz 9 clocks = 44us, 62us is 
ok */
 #define DELAY_HALF_PERIOD      (500 / (CONFIG_SYS_I2C_SPEED / 1000))
 
 #if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE)
@@ -445,8 +449,21 @@ static void writeStartSeq (void)
    This I2C Deblocking mechanism was developed by Keymile in association
    with Anatech and Atmel in 1998.
  */
-static int i2c_make_abort (void)
+int i2c_make_abort (void)
 {
+
+#if defined(CONFIG_HARD_I2C) && !defined(CONFIG_MACH_SUEN3)
+       volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
+       volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
+
+       /* disable I2C controller first, otherwhise it thinks we want to    */
+       /* talk to the slave port...                                        */
+       i2c->i2c_i2mod &= ~0x01;
+
+       /* Set the PortPins to GPIO */
+       setports (1);
+#endif
+
        int     scl_state = 0;
        int     sda_state = 0;
        int     i = 0;
@@ -473,54 +490,88 @@ static int i2c_make_abort (void)
                        writeStartSeq ();
                }
        }
+
+       /* respect stop setup time */
+       udelay (DELAY_ABORT_SEQ);
+       set_scl(1);
+       udelay (DELAY_ABORT_SEQ);
+       set_sda(1);
        get_sda ();
+
+#if defined(CONFIG_HARD_I2C)
+       /* Set the PortPins back to use for I2C */
+       setports (0);
+#endif
        return ret;
 }
 #endif
 
-/**
- * i2c_init_board - reset i2c bus. When the board is powercycled during a
- * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
- */
-void i2c_init_board(void)
-{
 #if defined(CONFIG_MPC83xx)
+static void writeStartSeq (void)
+{
+       struct fsl_i2c *dev;
+       dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
+       udelay(DELAY_ABORT_SEQ);
+       out_8 (&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
+       udelay(DELAY_ABORT_SEQ);
+       out_8 (&dev->cr, (I2C_CR_MEN));
+}
+
+int i2c_make_abort (void)
+{
        struct fsl_i2c *dev;
        dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
        uchar   dummy;
+       uchar   last;
+       int     nbr_read = 0;
+       int     i = 0;
+       int         ret = 0;
 
+       /* wait after each operation to finsh with a delay */
        out_8 (&dev->cr, (I2C_CR_MSTA));
+       udelay(DELAY_ABORT_SEQ);
        out_8 (&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
+       udelay(DELAY_ABORT_SEQ);
        dummy = in_8(&dev->dr);
-       dummy = in_8(&dev->dr);
-       if (dummy != 0xff) {
-               dummy = in_8(&dev->dr);
+       udelay(DELAY_ABORT_SEQ);
+       last = in_8(&dev->dr);
+       nbr_read++;
+
+       /* do read until the last bit is 1, but stop if the full eeprom is read 
*/
+       while (((last & 0x01) != 0x01) && (nbr_read < 
CONFIG_SYS_IVM_EEPROM_MAX_LEN)) {
+               udelay(DELAY_ABORT_SEQ);
+               last = in_8(&dev->dr);
+               nbr_read++;
        }
+       if ((last & 0x01) != 0x01)
+               ret = -2;
+       if ((last != 0xff) || (nbr_read > 1))
+               printf("[INFO] i2c abort after %d bytes (0x%02x)\n", nbr_read, 
last);
+       udelay(DELAY_ABORT_SEQ);
        out_8 (&dev->cr, (I2C_CR_MEN));
-       out_8 (&dev->cr, 0x00);
-       out_8 (&dev->cr, (I2C_CR_MEN));
+       udelay(DELAY_ABORT_SEQ);
+       /* clear status reg */
+       out_8 (&dev->sr, 0);
 
-#else
-#if defined(CONFIG_HARD_I2C) && !defined(MACH_TYPE_KM_KIRKWOOD)
-       volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
-       volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
-
-       /* disable I2C controller first, otherwhise it thinks we want to    */
-       /* talk to the slave port...                                        */
-       i2c->i2c_i2mod &= ~0x01;
+       for (i = 0; i < 5; i++) {
+               writeStartSeq ();
+       }
+       if (ret != 0) {
+               printf("[ERROR] i2c abort failed after %d bytes (0x%02x)\n", 
nbr_read, last);
+       }
+       return ret;
+}
 
-       /* Set the PortPins to GPIO */
-       setports (1);
 #endif
 
+/**
+ * i2c_init_board - reset i2c bus. When the board is powercycled during a
+ * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
+ */
+void i2c_init_board(void)
+{
        /* Now run the AbortSequence() */
        i2c_make_abort ();
-
-#if defined(CONFIG_HARD_I2C)
-       /* Set the PortPins back to use for I2C */
-       setports (0);
-#endif
-#endif
 }
 #endif
 #endif
-- 
1.7.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to