diff options
Diffstat (limited to 'board/pcippc2/i2c.c')
-rw-r--r-- | board/pcippc2/i2c.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/board/pcippc2/i2c.c b/board/pcippc2/i2c.c new file mode 100644 index 0000000000..36b1d0f44d --- /dev/null +++ b/board/pcippc2/i2c.c @@ -0,0 +1,257 @@ +/* + * (C) Copyright 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 + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> + +#include "hardware.h" +#include "i2c.h" + +static void i2c_start (void); +static void i2c_stop (void); +static int i2c_write (u8 data); +static void i2c_read (u8 * data); + +static inline void i2c_port_start (void); +static inline void i2c_clock (unsigned int val); +static inline void i2c_data (unsigned int val); +static inline unsigned int + i2c_in (void); +static inline void i2c_write_bit (unsigned int val); +static inline unsigned int + i2c_read_bit (void); + +static inline void i2c_udelay (unsigned int time); + +int i2c_read_byte ( + u8 * data, + u8 dev, + u8 offset) +{ + int err = 0; + + i2c_start(); + + err = ! i2c_write(dev); + + if (! err) + { + err = ! i2c_write(offset); + } + + if (! err) + { + i2c_start(); + } + + if (! err) + { + err = ! i2c_write(dev | 0x01); + } + + if (! err) + { + i2c_read(data); + } + + i2c_stop(); + + return ! err; +} + +static inline void i2c_udelay ( + unsigned int time) +{ + int v; + + asm volatile("mtdec %0" : : "r" (time * ((CFG_BUS_CLK / 4) / 1000000))); + + do + { + asm volatile("isync; mfdec %0" : "=r" (v)); + } while (v >= 0); +} + + /* Low-level hardware access + */ + +#define BIT_GPDATA 0x80000000 +#define BIT_GPCLK 0x40000000 + +static inline void i2c_port_start (void) +{ + out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~(BIT_GPCLK | BIT_GPDATA)); + out32(REG(CPC0, GPOUT), in32(REG(CPC0, GPOUT)) & ~(BIT_GPCLK | BIT_GPDATA)); + iobarrier_rw(); + + i2c_udelay(1); +} + +static inline void i2c_clock ( + unsigned int val) +{ + if (val) + { + out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~BIT_GPCLK); + } + else + { + out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) | BIT_GPCLK); + } + + iobarrier_rw(); + + i2c_udelay(1); +} + +static inline void i2c_data ( + unsigned int val) +{ + if (val) + { + out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) & ~BIT_GPDATA); + } + else + { + out32(REG(CPC0, GPDIR), in32(REG(CPC0, GPDIR)) | BIT_GPDATA); + } + + iobarrier_rw(); + + i2c_udelay(1); +} + +static inline unsigned int i2c_in (void) +{ + unsigned int val = ((in32(REG(CPC0, GPIN)) & BIT_GPDATA) != 0)?1:0; + + iobarrier_rw(); + + return val; +} + + + /* Protocol implementation + */ + +static inline void i2c_write_bit ( + unsigned int val) +{ + i2c_data(val); + i2c_udelay(10); + i2c_clock(1); + i2c_udelay(10); + i2c_clock(0); + i2c_udelay(10); +} + +static inline unsigned int i2c_read_bit (void) +{ + unsigned int val; + + i2c_data(1); + i2c_udelay(10); + + i2c_clock(1); + i2c_udelay(10); + + val = i2c_in(); + + i2c_clock(0); + i2c_udelay(10); + + return val; +} + +unsigned int i2c_reset (void) +{ + unsigned int val; + int i; + + i2c_port_start(); + + i=0; + do { + i2c_udelay(10); + i2c_clock(0); + i2c_udelay(10); + i2c_clock(1); + i2c_udelay(10); + val = i2c_in(); + i++; + } while ((i<9)&&(val==0)); + return (val); +} + + +static void i2c_start (void) +{ + i2c_data(1); + i2c_clock(1); + i2c_udelay(10); + i2c_data(0); + i2c_udelay(10); + i2c_clock(0); + i2c_udelay(10); +} + +static void i2c_stop (void) +{ + i2c_data(0); + i2c_udelay(10); + i2c_clock(1); + i2c_udelay(10); + i2c_data(1); + i2c_udelay(10); +} + +static int i2c_write ( + u8 data) +{ + unsigned int i; + + for (i = 0; i < 8; i++) + { + i2c_write_bit(data >> 7); + data <<= 1; + } + + return i2c_read_bit() == 0; +} + +static void i2c_read ( + u8 * data) +{ + unsigned int i; + u8 val = 0; + + for (i = 0; i < 8; i++) + { + val <<= 1; + val |= i2c_read_bit(); + } + + *data = val; + i2c_write_bit(1); /* NoAck */ +} |