diff --git a/cpu/mcf52x2/Makefile b/cpu/mcf52x2/Makefile index 70d57cf..071fc60 100644 --- a/cpu/mcf52x2/Makefile +++ b/cpu/mcf52x2/Makefile @@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a START = -COBJS = serial.o interrupts.o cpu.o speed.o cpu_init.o fec.o +COBJS = serial.o interrupts.o cpu.o speed.o cpu_init.o fec.o i2c.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mcf52x2/i2c.c b/cpu/mcf52x2/i2c.c new file mode 100644 index 0000000..3f4daa2 --- /dev/null +++ b/cpu/mcf52x2/i2c.c @@ -0,0 +1,596 @@ +/* + * (C) Copyright 2006 + * Jens Scharsig @ BuS Elektronik GmbH & Co. KG + * + * 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 + */ + +#undef CFG_I2C_DEBUG +#include + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_HARD_I2C + +#include + +#if defined(CONFIG_M5280) || defined(CONFIG_M5281) || defined(CONFIG_M5282) + +#include + + +unsigned short MCFI2C_Divider[0x40] = { 28, 30, 34, 30, 44, 48, 56, 68, + 80, 88, 104, 128, 144, 160, 192, 240, + 288, 320, 384, 480, 576, 640, 768, 960, + 1152,1280,1536,1920,2304,2560,3072,3840, + 20, 22, 24, 26, 28, 32, 36, 40, + 48, 56, 64, 72, 80, 96, 112, 128, + 160, 192, 224, 256, 320, 384, 448, 512, + 640, 768, 896,1024,1280,1536,1792,2048}; + +#define I2C_TIMEOUT 1000 /* Milliseconds */ + +/***************************************************************************** +****f* i2c/i2c_init +*** +******************************************************************************/ + +void i2c_init(int speed, int slaveaddr) +{ + int fdr; + int cnt; + int actspeed; + int calcspeed; + + /* Search Clock Divider for real speed near speed */ + + fdr=0x1F; + actspeed=CFG_CLK / MCFI2C_Divider[fdr]; + + for (cnt=0;cnt<=0x3F;cnt++) + { + calcspeed = CFG_CLK / MCFI2C_Divider[cnt]; + if ((actspeed < calcspeed) && (calcspeed <= speed)) + { + fdr = cnt; + actspeed=calcspeed; + } + } + if (gd->flags & GD_FLG_RELOC) { + } + else + { + printf("Speed %d Hz ",actspeed,speed); + } + + MCFI2C_I2ADR = CFG_I2C_SLAVE; + + MCFI2C_I2FDR = MCFI2C_I2FDR_IC(fdr); + + MCFI2C_I2CR = MCFI2C_I2CR_IEN; + + MCFGPIO_PASPAR |= 0x0F; /* PAS0 and PAS1 as I2C Port */ + + + if (MCFI2C_I2SR & MCFI2C_I2SR_IBB) + { + MCFI2C_I2CR = 0; + MCFI2C_I2CR = 0xA0; + cnt = MCFI2C_I2DR; + MCFI2C_I2SR = 0; + MCFI2C_I2CR = 0; + MCFGPIO_PASPAR &= ~0x0F; + + MCFGPIO_CLRAS = ~0x01; + MCFGPIO_DDRAS |= 0x01; + for (cnt=0;cnt<=9;cnt++) + { + MCFGPIO_CLRAS = 0xFE; + udelay(10); + MCFGPIO_SETAS = 0x01; + udelay(10); + } + MCFGPIO_PASPAR |= 0x0F; /* PAS0 and PAS1 as I2C Port */ + MCFI2C_I2CR = MCFI2C_I2CR_IEN; + }; + +} + +/***************************************************************************** + ****f* i2c/i2c_waitidle + * FUNCTION + * Waits while I2C-Bus is busy + * RESULT + * >1, if I2C-Bus is idle , 0 Timeout + *** +******************************************************************************/ + +int i2c_waitidle(void) +{ + int timeout; + timeout = I2C_TIMEOUT*100; + while ((MCFI2C_I2SR & MCFI2C_I2SR_IBB) && (timeout>0)) + { + #ifdef CFG_I2C_DEBUG + printf("i",MCFI2C_I2SR); + #endif + timeout--; + udelay(10); + } + if (timeout==0) + { + printf("I2C Error: Bus idle timeout\n"); + } + return timeout; +} + +/***************************************************************************** + ****f* i2c/i2c_waitbusy + * FUNCTION + * Waits until I2C-Bus is busy + * RESULT + * >1, if I2C-Bus is busy , 0 Timeout + *** +******************************************************************************/ + +int i2c_waitbusy(void) +{ + int timeout; + timeout = I2C_TIMEOUT * 100; + while ((!(MCFI2C_I2SR & MCFI2C_I2SR_IBB)) && (timeout>0)) + { + #ifdef CFG_I2C_DEBUG + printf("b",MCFI2C_I2SR); + #endif + timeout--; + udelay(10); + } + if (timeout==0) + { + printf("I2C Error: Bus busy timeout\n"); + } + return timeout; +} + +/***************************************************************************** + ****f* i2c/i2c_start + * FUNCTION + * generates a stop condition + * RESULT + * 0 = sucess, >1 = error + *** +******************************************************************************/ + +int i2c_stop(void) +{ + MCFI2C_I2CR &= ~MCFI2C_I2CR_MSTA; + #ifdef CFG_I2C_DEBUG + printf(" Stop \n"); + #endif + return 0; +} + +/***************************************************************************** + ****f* i2c/i2c_datacomplete + * FUNCTION + * Waits until data transfer is complete + * RESULT + * >1, if data transfer is complete , 0 Timeout + *** +******************************************************************************/ + +int i2c_datacomplete(void) +{ + int timeout; + timeout = I2C_TIMEOUT*100; + while ((!(MCFI2C_I2SR & MCFI2C_I2SR_IIF)) && (timeout>0)) + { + #ifdef CFG_I2C_DEBUG + printf("d",MCFI2C_I2SR); + #endif + timeout--; + udelay(10); + } + MCFI2C_I2SR &= ~MCFI2C_I2SR_IIF; + + if (timeout==0) + { + printf("I2C Error: data transfer complete timeout\n"); + } + if (((MCFI2C_I2SR & MCFI2C_I2SR_RXAK)) && (MCFI2C_I2CR & MCFI2C_I2CR_MTX)) + { + #ifdef CFG_I2C_DEBUG + printf("RX_NACK",MCFI2C_I2SR); + #endif + timeout=0; + i2c_stop(); + } + return timeout; +} + +/***************************************************************************** + ****f* i2c/i2c_start + * FUNCTION + * generates a start condition and send the chip address + * PARAMETERS + * uchar chip - chip address + * uchar readdata - set to start a read opperation + * RESULT + * 0 = sucess, >1 = error + *** +******************************************************************************/ + +int i2c_start(uchar chip, uchar readdata) +{ + int error; + #ifdef CFG_I2C_DEBUG + printf("Start 0x%2.2x ",chip); + #endif + MCFI2C_I2CR |= MCFI2C_I2CR_MSTA | MCFI2C_I2CR_MTX; + if (readdata) + { + MCFI2C_I2DR = MCFI2C_I2ADR_ADDR(chip) | 0x01; + } + else + { + MCFI2C_I2DR = MCFI2C_I2ADR_ADDR(chip); + } + error = 1; + if (i2c_waitbusy()) + { + if (i2c_datacomplete()) + { + #ifdef CFG_I2C_DEBUG + printf("Address send\n"); + #endif + error=0; + } + } + return error; +} + +/***************************************************************************** + ****f* i2c/i2c_restart + * FUNCTION + * generates a restart condition and send the chip address + * PARAMETERS + * uchar chip - chip address + * uchar readdata - set to start a read opperation + * RESULT + * 0 = sucess, >1 = error + *** +******************************************************************************/ + +int i2c_restart(uchar chip, uchar readdata) +{ + int error; + MCFI2C_I2CR |= MCFI2C_I2CR_MSTA | MCFI2C_I2CR_RSTA; + if (readdata) + { + MCFI2C_I2DR = MCFI2C_I2ADR_ADDR(chip) | 0x01; + } + else + { + MCFI2C_I2DR = MCFI2C_I2ADR_ADDR(chip); + } + error = 1; + if (i2c_waitbusy()) + { + if (i2c_datacomplete()) + { + #ifdef CFG_I2C_DEBUG + printf("Address send\n"); + #endif + error=0; + } + } + return error; +} + +/***************************************************************************** + ****f* i2c/i2c_receive + * FUNCTION + * receives n Bytes from I2C Device + * PARAMETERS + * char *Buffer - receive buffer + * int len - receive buffer size + * RESULT + * 0 = sucess, >1 = error + *** +******************************************************************************/ + +int i2c_receive(uchar *buffer, int len) +{ + int error; + int ptr; + error = 0; + ptr = 0; + + MCFI2C_I2CR &= ~(MCFI2C_I2CR_MTX | MCFI2C_I2CR_TXAK); + if (len==1) + { + #ifdef CFG_I2C_DEBUG + printf(" TXAK"); + #endif + MCFI2C_I2CR |= MCFI2C_I2CR_TXAK; + } + buffer[0] = MCFI2C_I2DR; + #ifdef CFG_I2C_DEBUG + printf(" dummy"); + #endif + + while ((len>0) && (error == 0)) + { + if (i2c_datacomplete()) + { + if (len==2) + { + #ifdef CFG_I2C_DEBUG + printf(" TXAK"); + #endif + MCFI2C_I2CR |= MCFI2C_I2CR_TXAK; + } + if (len==1) + { + i2c_stop(); + } + buffer[ptr] = MCFI2C_I2DR; + #ifdef CFG_I2C_DEBUG + printf(" %2.2x",(uchar) buffer[ptr]); + #endif + ptr++; + len--; + } + else + { + error = 1; + } + } + return error; +} + +/***************************************************************************** + ****f* i2c/i2c_send + * FUNCTION + * sends n Bytes to I2C Device + * PARAMETERS + * char *Buffer - send buffer + * int len - send buffer size + * RESULT + * 0 = sucess, >1 = error + *** +******************************************************************************/ + +int i2c_send(uchar *buffer, int len) +{ + int error; + int ptr; + error = 0; + ptr = 0; + while ((len>0) && (error == 0)) + { + #ifdef CFG_I2C_DEBUG + printf(" 0x%2.2x ",buffer[ptr]); + #endif + MCFI2C_I2DR = buffer[ptr]; + ptr++; + len--; + if (!(i2c_datacomplete())) error = 1; + } + return error; +} + +/* + * Probe the given I2C chip address. Returns 0 if a chip responded, + * not 0 on failure. + */ +int i2c_probe(uchar chip) +{ + int result; + uchar buffer[2]; + result=1; + if (chip != CFG_I2C_SLAVE) + { + if (i2c_waitidle()) + { + if (!i2c_start(chip,1)) + { + if (!i2c_receive(&buffer[0],1)) + { + result=0; + } + } + } + } + return result; +} + +/* + * Read interface: + * chip: I2C chip address, range 0..127 + * addr: Memory (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: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + uchar bufaddr[2]; + int error; + + error=0; + #ifdef CFG_I2C_DEBUG + printf("I2C_Read"); + printf(" 0x%2.2x ",addr); + #endif + if (i2c_waitidle()) + { + while (MCFI2C_I2SR & MCFI2C_I2SR_IBB); + + bufaddr[0] = (addr >>8) & 0xFF; + bufaddr[1] = addr & 0xFF; + + error |= i2c_start(chip,0); + #ifdef CFG_I2C_DEBUG + printf("\nI2C_Read"); + #endif + switch (alen) + { + case 0: + #ifdef CFG_I2C_DEBUG + printf(" no address"); + #endif + break; + case 1: + #ifdef CFG_I2C_DEBUG + printf(" byte address"); + #endif + error |= i2c_send(&bufaddr[1],1); + break; + case 2: + #ifdef CFG_I2C_DEBUG + printf(" word address"); + #endif + error |= i2c_send(&bufaddr[0],2); + break; + default: + printf("Address length %d not supported\n",alen); + error=1; + } + #ifdef CFG_I2C_DEBUG + printf("\nI2C_Read Restart"); + #endif + error |= i2c_restart(chip,1); + #ifdef CFG_I2C_DEBUG + printf("\nI2C_Read Receive"); + #endif + error |= i2c_receive(buffer,len); + } + else + { + error=1; + } + return error; +} + +/* + * Write interface: + * chip: I2C chip address, range 0..127 + * addr: Memory (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: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + uchar bufaddr[2]; + int error; + + error=0; + #ifdef CFG_I2C_DEBUG + printf("I2C_Write 0x%2.2x@0x%2.2x ",addr,chip); + #endif + if (i2c_waitidle()) + { + bufaddr[0] = (addr >>8) & 0xFF; + bufaddr[1] = addr & 0xFF; + + error |= i2c_start(chip,0); + #ifdef CFG_I2C_DEBUG + printf("\nI2C_Write"); + #endif + switch (alen) + { + case 0: + #ifdef CFG_I2C_DEBUG + printf(" no address"); + #endif + break; + case 1: + #ifdef CFG_I2C_DEBUG + printf(" byte address"); + #endif + error |= i2c_send(&bufaddr[1],1); + break; + case 2: + #ifdef CFG_I2C_DEBUG + printf(" word address"); + #endif + error |= i2c_send(&bufaddr[0],2); + break; + default: + printf("Address length %d not supported\n",alen); + error=1; + } + #ifdef CFG_I2C_DEBUG + printf("\nI2C_Read Receive"); + #endif + error |= i2c_send(buffer,len); + error |= i2c_stop(); + } + else + { + error = 1; + } + return error; +} + +/* + * Utility routines to read/write registers. + */ + +#else + #error Hard I2C not implementetd for this CPU +#endif + +uchar i2c_reg_read(uchar chip, uchar reg) +{ + uchar buf; + + #ifdef CFG_I2C_DEBUG + printf("Reg_Read: 0x%2.2x ",reg); + #endif + i2c_read(chip, reg, 1, &buf, 1); + + return buf; +} + +void i2c_reg_write(uchar chip, uchar reg, uchar val) +{ + #ifdef CFG_I2C_DEBUG + printf("Reg_Write: 0x%2.2x ",reg); + #endif + i2c_write(chip, reg, 1, &val, 1); + + return; +} + +#endif + +/* EOF */