[U-Boot-Users] [PATCH 07/08]: tsi108 i2c support

tsi108 i2c support.
Signed-off-by: Alexandre Bounine alexandreb@tundra.com Signed-off-by: Roy Zang tie-fei.zang@freescale.com
--- board/mpc7448hpc2/ts_i2c.h | 104 ++++++++++++++ board/mpc7448hpc2/tsi108_i2c.c | 295 ++++++++++++++++++++++++++++++++++++++++ board/mpc7448hpc2/tsi108_i2c.h | 42 ++++++ 3 files changed, 441 insertions(+), 0 deletions(-)
diff --git a/board/mpc7448hpc2/ts_i2c.h b/board/mpc7448hpc2/ts_i2c.h new file mode 100644 index 0000000..722b06f --- /dev/null +++ b/board/mpc7448hpc2/ts_i2c.h @@ -0,0 +1,104 @@ +/* + * (C) Copyright 2004-05; Tundra Semiconductor Corp. + * + * 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 + * + */ + +#ifndef _TS_I2C_H_ +#define _TS_I2C_H_ + +#define I2C_NUM_REGS_TO_TEST 0x00000004 + +/* + * I2C : Register address offset definitions + */ +#define I2C_CNTRL1 (0x00000000) +#define I2C_CNTRL2 (0x00000004) +#define I2C_RD_DATA (0x00000008) +#define I2C_TX_DATA (0x0000000c) + +/* + * I2C : Register Bit Masks and Reset Values + * definitions for every register + */ + +/* I2C_CNTRL1 : Reset Value */ +#define I2C_CNTRL1_RESET_VALUE (0x0000000a) + +/* I2C_CNTRL1 : Register Bits Masks Definitions */ +#define I2C_CNTRL1_DEVCODE (0x0000000f) +#define I2C_CNTRL1_PAGE (0x00000700) +#define I2C_CNTRL1_BYTADDR (0x00ff0000) +#define I2C_CNTRL1_I2CWRITE (0x01000000) + +/* I2C_CNTRL1 : Read/Write Bit Mask Definition */ +#define I2C_CNTRL1_RWMASK (0x01ff070f) + +/* I2C_CNTRL1 : Unused/Reserved bits Definition */ +#define I2C_CNTRL1_RESERVED (0xfe00f8f0) + +/* I2C_CNTRL2 : Reset Value */ +#define I2C_CNTRL2_RESET_VALUE (0x00000000) + +/* I2C_CNTRL2 : Register Bits Masks Definitions */ +#define I2C_CNTRL2_SIZE (0x00000003) +#define I2C_CNTRL2_LANE (0x0000000c) +#define I2C_CNTRL2_MULTIBYTE (0x00000010) +#define I2C_CNTRL2_START (0x00000100) +#define I2C_CNTRL2_WR_STATUS (0x00010000) +#define I2C_CNTRL2_RD_STATUS (0x00020000) +#define I2C_CNTRL2_I2C_TO_ERR (0x04000000) +#define I2C_CNTRL2_I2C_CFGERR (0x08000000) +#define I2C_CNTRL2_I2C_CMPLT (0x10000000) + +/* I2C_CNTRL2 : Read/Write Bit Mask Definition */ +#define I2C_CNTRL2_RWMASK (0x0000011f) + +/* I2C_CNTRL2 : Unused/Reserved bits Definition */ +#define I2C_CNTRL2_RESERVED (0xe3fcfee0) + +/* I2C_RD_DATA : Reset Value */ +#define I2C_RD_DATA_RESET_VALUE (0x00000000) + +/* I2C_RD_DATA : Register Bits Masks Definitions */ +#define I2C_RD_DATA_RBYTE0 (0x000000ff) +#define I2C_RD_DATA_RBYTE1 (0x0000ff00) +#define I2C_RD_DATA_RBYTE2 (0x00ff0000) +#define I2C_RD_DATA_RBYTE3 (0xff000000) + +/* I2C_RD_DATA : Read/Write Bit Mask Definition */ +#define I2C_RD_DATA_RWMASK (0x00000000) + +/* I2C_RD_DATA : Unused/Reserved bits Definition */ +#define I2C_RD_DATA_RESERVED (0x00000000) + +/* I2C_TX_DATA : Reset Value */ +#define I2C_TX_DATA_RESET_VALUE (0x00000000) + +/* I2C_TX_DATA : Register Bits Masks Definitions */ +#define I2C_TX_DATA_TBYTE0 (0x000000ff) +#define I2C_TX_DATA_TBYTE1 (0x0000ff00) +#define I2C_TX_DATA_TBYTE2 (0x00ff0000) +#define I2C_TX_DATA_TBYTE3 (0xff000000) + +/* I2C_TX_DATA : Read/Write Bit Mask Definition */ +#define I2C_TX_DATA_RWMASK (0xffffffff) + +/* I2C_TX_DATA : Unused/Reserved bits Definition */ +#define I2C_TX_DATA_RESERVED (0x00000000) + +#endif /* _TS_I2C_H_ */ diff --git a/board/mpc7448hpc2/tsi108_i2c.c b/board/mpc7448hpc2/tsi108_i2c.c new file mode 100644 index 0000000..447ef82 --- /dev/null +++ b/board/mpc7448hpc2/tsi108_i2c.c @@ -0,0 +1,295 @@ +/* + * (C) Copyright 2004 Tundra Semiconductor Corp. + * Author: Alex Bounine + * + * 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 "tsi108_i2c.h" + +#if (CONFIG_COMMANDS & CFG_CMD_I2C) + +#define I2C_DELAY 100000 +#undef DEBUG_I2C + +#ifdef DEBUG_I2C +#define DPRINT(x) printf(x) +#else +#define DPRINT(x) +#endif + +/* All functions assume that Tsi108 I2C block is the only master on the bus */ +/* I2C read helper function */ + +static int i2c_read_byte( + uint i2c_chan, /* I2C channel number: 0 - main, 1 - SDC SPD */ + uchar chip_addr,/* I2C device address on the bus */ + uint byte_addr, /* Byte address within I2C device */ + uchar * buffer /* pointer to data buffer */ + ) +{ + u32 temp; + u32 to_count = I2C_DELAY; + u32 op_status = TSI108_I2C_TIMEOUT_ERR; + u32 chan_offset = TSI108_I2C_OFFSET; + + DPRINT(("I2C read_byte() %d 0x%02x 0x%02x\n", + i2c_chan, chip_addr, byte_addr)); + + if (0 != i2c_chan) { + chan_offset = TSI108_I2C_SDRAM_OFFSET; + } + + /* Check if I2C operation is in progress */ + temp = *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2); + + if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | + I2C_CNTRL2_START)) + ) { + /* Set device address and operation (read = 0) */ + temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) | + ((chip_addr >> 3) & 0x0F); + *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) = + temp; + + /* Issue the read command + * (at this moment all other parameters are 0 + * (size = 1 byte, lane = 0) + */ + + *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) = + (I2C_CNTRL2_START); + + /* Wait until operation completed */ + do { + /* Read I2C operation status */ + temp = + *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + + I2C_CNTRL2); + + if (0 == + (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) + { + if (0 == + (temp & + (I2C_CNTRL2_I2C_CFGERR | + I2C_CNTRL2_I2C_TO_ERR)) + ) { + op_status = TSI108_I2C_SUCCESS; + + temp = *(u32 *) (CFG_TSI108_CSR_BASE + + chan_offset + + I2C_RD_DATA); + + *buffer = (u8) (temp & 0xFF); + } else { + /* report HW error */ + op_status = TSI108_I2C_IF_ERROR; + + DPRINT(("I2C HW error reported: 0x%02x\n", temp)); + } + + break; + } + } while (to_count--); + } else { + op_status = TSI108_I2C_IF_BUSY; + + DPRINT(("I2C Transaction start failed: 0x%02x\n", temp)); + } + + DPRINT(("I2C read_byte() status: 0x%02x\n", op_status)); + return op_status; +} + +/* + * I2C Read interface as defined in "include/i2c.h" : + * chip_addr: I2C chip address, range 0..127 + * (to read from SPD channel EEPROM use (0xD0 ... 0xD7) + * NOTE: The bit 7 in the chip_addr serves as a channel select. + * This hack is for enabling "isdram" command on Tsi108 boards + * without changes to common code. Used for I2C reads only. + * byte_addr: Memory or register address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Pointer to destination buffer for data to be read + * len: How many bytes to read + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_read(uchar chip_addr, uint byte_addr, int alen, uchar * buffer, int len) +{ + u32 op_status = TSI108_I2C_PARAM_ERR; + u32 i2c_if = 0; + + /* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/ + if (0xD0 == (chip_addr & ~0x07)) { + i2c_if = 1; + chip_addr &= 0x7F; + } + /* Check for valid I2C address */ + if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) { + while (len--) { + op_status = + i2c_read_byte(i2c_if, chip_addr, byte_addr++, + buffer++); + + if (TSI108_I2C_SUCCESS != op_status) { + DPRINT(("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len)); + + break; + } + } + } + + DPRINT(("I2C read() status: 0x%02x\n", op_status)); + return op_status; +} + +/* I2C write helper function */ + +static int i2c_write_byte(uchar chip_addr,/* I2C device address on the bus */ + uint byte_addr, /* Byte address within I2C device */ + uchar * buffer /* pointer to data buffer */ + ) +{ + u32 temp; + u32 to_count = I2C_DELAY; + u32 op_status = TSI108_I2C_TIMEOUT_ERR; + + /* Check if I2C operation is in progress */ + temp = *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2); + + if (0 == + (temp & + (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) + { + /* Place data into the I2C Tx Register */ + *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + + I2C_TX_DATA) = (u32) * buffer; + + /* Set device address and operation */ + temp = + I2C_CNTRL1_I2CWRITE | (byte_addr << 16) | + ((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F); + *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + + I2C_CNTRL1) = temp; + + /* Issue the write command (at this moment all other parameters + * are 0 (size = 1 byte, lane = 0) + */ + + *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + + I2C_CNTRL2) = (I2C_CNTRL2_START); + + op_status = TSI108_I2C_TIMEOUT_ERR; + + /* Wait until operation completed */ + do { + // Read I2C operation status + temp = + *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + + I2C_CNTRL2); + + if (0 == + (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) + { + if (0 == + (temp & + (I2C_CNTRL2_I2C_CFGERR | + I2C_CNTRL2_I2C_TO_ERR))) { + op_status = TSI108_I2C_SUCCESS; + } else { + /* report detected HW error */ + op_status = TSI108_I2C_IF_ERROR; + + DPRINT(("I2C HW error reported: 0x%02x\n", temp)); + } + + break; + } + + } while (to_count--); + } else { + op_status = TSI108_I2C_IF_BUSY; + + DPRINT(("I2C Transaction start failed: 0x%02x\n", temp)); + } + + return op_status; +} + +/* + * I2C Write interface as defined in "include/i2c.h" : + * chip_addr: I2C chip address, range 0..127 + * byte_addr: Memory or register address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Pointer to data to be written + * len: How many bytes to write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_write(uchar chip_addr, uint byte_addr, int alen, uchar * buffer, + int len) +{ + u32 op_status = TSI108_I2C_PARAM_ERR; + + /* Check for valid I2C address */ + if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) { + while (len--) { + op_status = + i2c_write_byte(chip_addr, byte_addr++, buffer++); + + if (TSI108_I2C_SUCCESS != op_status) { + DPRINT(("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len)); + + break; + } + } + } + + return op_status; +} + +/* + * I2C interface function as defined in "include/i2c.h". + * Probe the given I2C chip address by reading single byte from offset 0. + * Returns 0 if a chip responded, not 0 on failure. + */ + +int i2c_probe(uchar chip) +{ + u32 tmp; + + /* + * Try to read the first location of the chip. + * The Tsi108 HW doesn't support sending just the chip address + * and checkong for an <ACK> back. + */ + return i2c_read(chip, 0, 1, (char *)&tmp, 1); +} + +#endif /* (CONFIG_COMMANDS & CFG_CMD_I2C) */ diff --git a/board/mpc7448hpc2/tsi108_i2c.h b/board/mpc7448hpc2/tsi108_i2c.h new file mode 100644 index 0000000..f5e1ddd --- /dev/null +++ b/board/mpc7448hpc2/tsi108_i2c.h @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2004 Tundra Semiconductor Corp. + * Author: Alex Bounine + * + * 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 + * + */ + +#ifndef _TSI108_I2C_H +#define _TSI108_I2C_H +#include "ts_i2c.h" + +#define TSI108_I2C_OFFSET 0x7000 /* register block offset for general use I2C channel */ +#define TSI108_I2C_SDRAM_OFFSET 0x4400 /* register block offset for SPD I2C channel */ + +#define I2C_EEPROM_DEVCODE 0xA /* standard I2C EEPROM device code */ + +/* I2C status codes */ + +#define TSI108_I2C_SUCCESS 0 +#define TSI108_I2C_PARAM_ERR 1 +#define TSI108_I2C_TIMEOUT_ERR 2 +#define TSI108_I2C_IF_BUSY 3 +#define TSI108_I2C_IF_ERROR 4 + +#endif /* _TSI108_I2C_H */
participants (1)
-
Zang Roy-r61911