]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
mgcoge, mgsuvd: add board specific I2C deblocking mechanism.
authorHeiko Schocher <hs@denx.de>
Wed, 15 Oct 2008 07:39:08 +0000 (09:39 +0200)
committerWolfgang Denk <wd@denx.de>
Sat, 18 Oct 2008 19:54:02 +0000 (21:54 +0200)
As documented in doc/I2C_Edge_Conditions, adding a
board specific deblocking mechanism via CFG_I2C_INIT_BOARD
for the mgcoge and mgsuvd board.

This code was originally written by Keymile in association
with Anatech and Atmel in 1998. The Code toggels the SCL
until the SCA line goes to HIGH (max. 16 times).
And after this, a start condition is sent.

This is another approach to deblock the I2C Bus. The
soft I2C driver actually sends 9 clocks with SDA High,
and then a stop at the end, to deblock the I2C Bus.

Maybe we should use the approach from Keymile as
the new standard?

Signed-off-by: Heiko Schocher <hs@denx.de>
board/keymile/common/common.c [new file with mode: 0644]
board/keymile/mgcoge/Makefile
board/keymile/mgsuvd/Makefile
include/configs/mgcoge.h
include/configs/mgsuvd.h

diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c
new file mode 100644 (file)
index 0000000..0f57015
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * (C) Copyright 2008
+ * Heiko Schocher, DENX Software Engineering, hs@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
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <ioports.h>
+#include <malloc.h>
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#endif
+
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+#include <i2c.h>
+#endif
+
+extern int i2c_soft_read_pin (void);
+
+#if defined(CFG_I2C_INIT_BOARD)
+#define DELAY_ABORT_SEQ                62
+#define DELAY_HALF_PERIOD      (500 / (CFG_I2C_SPEED / 1000))
+
+#if defined(CONFIG_MGCOGE)
+#define SDA_MASK       0x00010000
+#define SCL_MASK       0x00020000
+static void set_pin (int state, unsigned long mask)
+{
+       volatile ioport_t *iop = ioport_addr ((immap_t *)CFG_IMMR, 3);
+
+       if (state)
+               iop->pdat |= (mask);
+       else
+               iop->pdat &= ~(mask);
+
+       iop->pdir |= (mask);
+}
+
+static int get_pin (unsigned long mask)
+{
+       volatile ioport_t *iop = ioport_addr ((immap_t *)CFG_IMMR, 3);
+
+       iop->pdir &= ~(mask);
+       return (0 != (iop->pdat & (mask)));
+}
+
+static void set_sda (int state)
+{
+       set_pin (state, SDA_MASK);
+}
+
+static void set_scl (int state)
+{
+       set_pin (state, SCL_MASK);
+}
+
+static int get_sda (void)
+{
+       return get_pin (SDA_MASK);
+}
+
+static int get_scl (void)
+{
+       return get_pin (SCL_MASK);
+}
+
+#if defined(CONFIG_HARD_I2C)
+static void setports (int gpio)
+{
+       volatile ioport_t *iop = ioport_addr ((immap_t *)CFG_IMMR, 3);
+
+       if (gpio) {
+               iop->ppar &= ~(SDA_MASK | SCL_MASK);
+               iop->podr &= ~(SDA_MASK | SCL_MASK);
+       } else {
+               iop->ppar |= (SDA_MASK | SCL_MASK);
+               iop->pdir &= ~(SDA_MASK | SCL_MASK);
+               iop->podr |= (SDA_MASK | SCL_MASK);
+       }
+}
+#endif
+#endif
+
+#if defined(CONFIG_MGSUVD)
+static void set_sda (int state)
+{
+       I2C_SDA(state);
+}
+
+static void set_scl (int state)
+{
+       I2C_SCL(state);
+}
+
+static int get_sda (void)
+{
+       return i2c_soft_read_pin ();
+}
+
+static int get_scl (void)
+{
+       int     val;
+
+       *(unsigned short *)(I2C_BASE_DIR) &=  ~SCL_CONF;
+       udelay (1);
+       val = *(unsigned char *)(I2C_BASE_PORT);
+
+       return ((val & SCL_BIT) == SCL_BIT);
+}
+
+#endif
+
+static void writeStartSeq (void)
+{
+       set_sda (1);
+       udelay (DELAY_HALF_PERIOD);
+       set_scl (1);
+       udelay (DELAY_HALF_PERIOD);
+       set_sda (0);
+       udelay (DELAY_HALF_PERIOD);
+       set_scl (0);
+       udelay (DELAY_HALF_PERIOD);
+}
+
+/* I2C is a synchronous protocol and resets of the processor in the middle
+   of an access can block the I2C Bus until a powerdown of the full unit is
+   done. This function toggles the SCL until the SCL and SCA line are
+   released, but max. 16 times, after this a I2C start-sequence is sent.
+   This I2C Deblocking mechanism was developed by Keymile in association
+   with Anatech and Atmel in 1998.
+ */
+static int i2c_make_abort (void)
+{
+       int     scl_state = 0;
+       int     sda_state = 0;
+       int     i = 0;
+       int     ret = 0;
+
+       if (!get_sda ()) {
+               ret = -1;
+               while (i < 16) {
+                       i++;
+                       set_scl (0);
+                       udelay (DELAY_ABORT_SEQ);
+                       set_scl (1);
+                       udelay (DELAY_ABORT_SEQ);
+                       scl_state = get_scl ();
+                       sda_state = get_sda ();
+                       if (scl_state && sda_state) {
+                               ret = 0;
+                               break;
+                       }
+               }
+       }
+       if (ret == 0) {
+               for (i =0; i < 5; i++) {
+                       writeStartSeq ();
+               }
+       }
+       get_sda ();
+       return ret;
+}
+
+/**
+ * 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_HARD_I2C)
+       volatile immap_t *immap = (immap_t *)CFG_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
+
+       /* Now run the AbortSequence() */
+       i2c_make_abort ();
+
+#if defined(CONFIG_HARD_I2C)
+       /* Set the PortPins back to use for I2C */
+       setports (0);
+#endif
+}
+#endif
index e00295d62e8e61db8d93a4708f5c7750699660b1..0cad8210f2d51e9b7844d049e691f7919b6a178f 100644 (file)
@@ -28,7 +28,7 @@ endif
 
 LIB    = $(obj)lib$(BOARD).a
 
-COBJS  := $(BOARD).o
+COBJS  := $(BOARD).o ../common/common.o
 
 SRCS   := $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS   := $(addprefix $(obj),$(COBJS))
index efdd410b0c480f84157cc9ba162197cbf38c8fbc..b2145f9ff7043831c4f543f8ef98e42ca7ee6d0b 100644 (file)
@@ -28,7 +28,7 @@ endif
 
 LIB    = $(obj)lib$(BOARD).a
 
-COBJS  = $(BOARD).o
+COBJS  = $(BOARD).o ../common/common.o
 
 SRCS   := $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS   := $(addprefix $(obj),$(COBJS))
index bfbbd455ac09edc5d3a887bdd18474d89e19bb10..398e092686d6ad16da7ec9b0f4cbb51e957f9624 100644 (file)
 #define CONFIG_I2C_MULTI_BUS   1
 #define CONFIG_I2C_CMD_TREE    1
 #define CFG_MAX_I2C_BUS                2
+#define CFG_I2C_INIT_BOARD     1
 
 /* EEprom support */
 #define CFG_I2C_EEPROM_ADDR_LEN        1
index c569c81638560e026dd9b4ffb421286745fdb05a..20485750ea1513959ad904265421e970c90c6220 100644 (file)
 #define CONFIG_I2C_MULTI_BUS   1
 #define CONFIG_I2C_CMD_TREE    1
 #define CFG_MAX_I2C_BUS                2
+#define CFG_I2C_INIT_BOARD     1
 
 /* EEprom support */
 #define CFG_I2C_EEPROM_ADDR_LEN        1