diff options
Diffstat (limited to 'common/soft_i2c.c')
-rw-r--r-- | common/soft_i2c.c | 423 |
1 files changed, 0 insertions, 423 deletions
diff --git a/common/soft_i2c.c b/common/soft_i2c.c deleted file mode 100644 index 23db2ee..0000000 --- a/common/soft_i2c.c +++ /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); -} |