]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/i2c/soft_i2c.c
i2c: switch from AT91 legacy to ATMEL legacy
[karo-tx-uboot.git] / drivers / i2c / soft_i2c.c
index 19c364b136e5c196f5f70d15885ab7b23cf98927..dfea54ae73308c5f665bbe4606bc49c90e8b19cc 100644 (file)
@@ -1,24 +1,12 @@
 /*
+ * (C) Copyright 2009
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ * Changes for multibus/multiadapter I2C support.
+ *
  * (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
+ * SPDX-License-Identifier:    GPL-2.0+
  *
  * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
  * vanbaren@cideas.com.  It was heavily influenced by LiMon, written by
 #include <common.h>
 #ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
 #include <ioports.h>
+#include <asm/io.h>
 #endif
-#ifdef CONFIG_AT91RM9200               /* need this for the at91rm9200 */
+#if defined(CONFIG_AVR32)
+#include <asm/arch/portmux.h>
+#endif
+#if defined(CONFIG_AT91FAMILY)
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch/at91_pio.h>
+#ifdef CONFIG_ATMEL_LEGACY
+#include <asm/arch/gpio.h>
+#endif
 #endif
 #ifdef CONFIG_IXP425                   /* only valid for IXP425 */
 #include <asm/arch/ixp425.h>
 #endif
-#ifdef CONFIG_LPC2292
-#include <asm/arch/hardware.h>
+#if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
+#include <asm/io.h>
 #endif
 #include <i2c.h>
 
+#if defined(CONFIG_SOFT_I2C_GPIO_SCL)
+# include <asm/gpio.h>
+
+# ifndef I2C_GPIO_SYNC
+#  define I2C_GPIO_SYNC
+# endif
+
+# ifndef I2C_INIT
+#  define I2C_INIT \
+       do { \
+               gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \
+               gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \
+       } while (0)
+# endif
+
+# ifndef I2C_ACTIVE
+#  define I2C_ACTIVE do { } while (0)
+# endif
+
+# ifndef I2C_TRISTATE
+#  define I2C_TRISTATE do { } while (0)
+# endif
+
+# ifndef I2C_READ
+#  define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA)
+# endif
+
+# ifndef I2C_SDA
+#  define I2C_SDA(bit) \
+       do { \
+               if (bit) \
+                       gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \
+               else \
+                       gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \
+               I2C_GPIO_SYNC; \
+       } while (0)
+# endif
+
+# ifndef I2C_SCL
+#  define I2C_SCL(bit) \
+       do { \
+               gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \
+               I2C_GPIO_SYNC; \
+       } while (0)
+# endif
+
+# ifndef I2C_DELAY
+#  define I2C_DELAY udelay(5)  /* 1/4 I2C clock duration */
+# endif
+
+#endif
+
 /* #define     DEBUG_I2C       */
 
-#ifdef DEBUG_I2C
 DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef        I2C_SOFT_DECLARATIONS
+# if defined(CONFIG_MPC8260)
+#  define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = \
+               ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT);
+# elif defined(CONFIG_8xx)
+#  define I2C_SOFT_DECLARATIONS        volatile immap_t *immr = \
+               (immap_t *)CONFIG_SYS_IMMR;
+# else
+#  define I2C_SOFT_DECLARATIONS
+# endif
 #endif
 
+#if !defined(CONFIG_SYS_I2C_SOFT_SPEED)
+#define CONFIG_SYS_I2C_SOFT_SPEED CONFIG_SYS_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_I2C_SOFT_SLAVE)
+#define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
+#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
 
-#if defined(CONFIG_I2C_MULTI_BUS)
-static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
-#endif /* CONFIG_I2C_MULTI_BUS */
-
 /*-----------------------------------------------------------------------
  * Local functions
  */
+#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
 static void  send_reset        (void);
+#endif
 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);
 
+#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
 /*-----------------------------------------------------------------------
  * 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
@@ -109,6 +169,7 @@ static void send_reset(void)
        send_stop();
        I2C_TRISTATE;
 }
+#endif
 
 /*-----------------------------------------------------------------------
  * START: High -> Low on SDA while SCL is High
@@ -146,7 +207,6 @@ static void send_stop(void)
        I2C_TRISTATE;
 }
 
-
 /*-----------------------------------------------------------------------
  * ack should be I2C_ACK or I2C_NOACK
  */
@@ -166,7 +226,6 @@ static void send_ack(int ack)
        I2C_DELAY;
 }
 
-
 /*-----------------------------------------------------------------------
  * Send 8 bits and look for an acknowledgement.
  */
@@ -208,39 +267,6 @@ static int write_byte(uchar data)
        return(nack);   /* not a nack is an ack */
 }
 
-#if defined(CONFIG_I2C_MULTI_BUS)
-/*
- * Functions for multiple I2C bus handling
- */
-unsigned int i2c_get_bus_num(void)
-{
-       return i2c_bus_num;
-}
-
-int i2c_set_bus_num(unsigned int bus)
-{
-       if (bus >= CFG_MAX_I2C_BUS)
-               return -1;
-       i2c_bus_num = bus;
-
-       return 0;
-}
-
-/* TODO: add 100/400k switching */
-unsigned int i2c_get_bus_speed(void)
-{
-       return CFG_I2C_SPEED;
-}
-
-int i2c_set_bus_speed(unsigned int speed)
-{
-       if (speed != CFG_I2C_SPEED)
-               return -1;
-
-       return 0;
-}
-#endif
-
 /*-----------------------------------------------------------------------
  * if ack == I2C_ACK, ACK the byte so can continue reading, else
  * send I2C_NOACK to end the read.
@@ -271,15 +297,17 @@ static uchar read_byte(int ack)
        return(data);
 }
 
-/*=====================================================================*/
-/*                         Public Functions                            */
-/*=====================================================================*/
-
 /*-----------------------------------------------------------------------
  * Initialization
  */
-void i2c_init (int speed, int slaveaddr)
+static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
 {
+#if defined(CONFIG_SYS_I2C_INIT_BOARD)
+       /* call board specific i2c bus reset routine before accessing the   */
+       /* environment, which might be in a chip on that bus. For details   */
+       /* about this problem see doc/I2C_Edge_Conditions.                  */
+       i2c_init_board();
+#else
        /*
         * WARNING: Do NOT save speed in a static variable: if the
         * I2C routines are called before RAM is initialized (to read
@@ -287,6 +315,7 @@ void i2c_init (int speed, int slaveaddr)
         * system will crash.
         */
        send_reset ();
+#endif
 }
 
 /*-----------------------------------------------------------------------
@@ -294,7 +323,7 @@ void i2c_init (int speed, int slaveaddr)
  * completion of EEPROM writes since the chip stops responding until
  * the write completes (typically 10mSec).
  */
-int i2c_probe(uchar addr)
+static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
 {
        int rc;
 
@@ -312,13 +341,14 @@ int i2c_probe(uchar addr)
 /*-----------------------------------------------------------------------
  * Read bytes
  */
-int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int  soft_i2c_read(struct i2c_adapter *adap, 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
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
        /*
         * EEPROM chips that implement "address overflow" are ones
         * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
@@ -330,7 +360,7 @@ int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
         * still be one byte because the extra address bits are
         * hidden in the chip address.
         */
-       chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+       chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 
        PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
                chip, addr);
@@ -357,8 +387,18 @@ int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
                        }
                        shift -= 8;
                }
-               send_stop();    /* reportedly some chips need a full stop */
+
+               /* Some I2C chips need a stop/start sequence here,
+                * other chips don't work with a full stop and need
+                * only a start.  Default behaviour is to send the
+                * stop/start sequence.
+                */
+#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
+               send_start();
+#else
+               send_stop();
                send_start();
+#endif
        }
        /*
         * Send the chip address again, this time for a read cycle.
@@ -376,7 +416,8 @@ int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 /*-----------------------------------------------------------------------
  * Write bytes
  */
-int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+                       int alen, uchar *buffer, int len)
 {
        int shift, failures = 0;
 
@@ -407,22 +448,31 @@ int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
        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
+/*
+ * Register soft i2c adapters
  */
-void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
-{
-       i2c_write(i2c_addr, reg, 1, &val, 1);
-}
+U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
+                        soft_i2c_read, soft_i2c_write, NULL,
+                        CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
+                        0)
+#if defined(I2C_SOFT_DECLARATIONS2)
+U_BOOT_I2C_ADAP_COMPLETE(soft1, soft_i2c_init, soft_i2c_probe,
+                        soft_i2c_read, soft_i2c_write, NULL,
+                        CONFIG_SYS_I2C_SOFT_SPEED_2,
+                        CONFIG_SYS_I2C_SOFT_SLAVE_2,
+                        1)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS3)
+U_BOOT_I2C_ADAP_COMPLETE(soft2, soft_i2c_init, soft_i2c_probe,
+                        soft_i2c_read, soft_i2c_write, NULL,
+                        CONFIG_SYS_I2C_SOFT_SPEED_3,
+                        CONFIG_SYS_I2C_SOFT_SLAVE_3,
+                        2)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS4)
+U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
+                        soft_i2c_read, soft_i2c_write, NULL,
+                        CONFIG_SYS_I2C_SOFT_SPEED_4,
+                        CONFIG_SYS_I2C_SOFT_SLAVE_4,
+                        3)
+#endif