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..99d319b --- /dev/null +++ b/cpu/mcf52x2/i2c.c @@ -0,0 +1,654 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2006-2007 + * 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 + */ + +#include +#ifdef CONFIG_HARD_I2C + +#undef CFG_I2C_DEBUG + +DECLARE_GLOBAL_DATA_PTR; + +#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_calc_fdr +*** +******************************************************************************/ + +int i2c_calc_fdr(int speed, int * realspeed) +{ + int fdr; + int cnt; + int actspeed; + int calcspeed; + + calcspeed = CFG_CLK / MCFI2C_Divider[20]; /* smales prescaler */ + + if (speed> calcspeed) + { + fdr = -20; + } + else + { + fdr=0x1F; /* gretest prescaler */ + 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; + } + } + } + *realspeed = actspeed; + return fdr; +} + +/***************************************************************************** +****f* i2c/i2c_init +*** +******************************************************************************/ + +void i2c_init(int speed, int slaveaddr) +{ + int fdr; + int cnt; + int realspeed; + + /* Search Clock Divider for real speed near speed */ + + fdr=i2c_calc_fdr(speed,&realspeed); + if (fdr < 0) fdr *= -1; + if (gd->flags & GD_FLG_RELOC) { + } + else + { + printf("Speed %d Hz ",realspeed,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_get_bus_speed +*** +******************************************************************************/ + +unsigned int i2c_get_bus_speed(void) +{ + return CFG_CLK / MCFI2C_Divider[MCFI2C_I2FDR & 0x3F]; +} + +/***************************************************************************** +****f* i2c_set_bus_speed +*** +******************************************************************************/ + +int i2c_set_bus_speed(unsigned int speed) +{ + int fdr; + int realspeed; + + fdr=i2c_calc_fdr(speed,&realspeed); + if (fdr >= 0) + { + MCFI2C_I2FDR = MCFI2C_I2FDR_IC(fdr); + return 0; + } + else + { + return -1; + } +} + +/***************************************************************************** + ****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 */ diff --git a/include/asm-m68k/m5282.h b/include/asm-m68k/m5282.h index e5058a4..0569607 100644 --- a/include/asm-m68k/m5282.h +++ b/include/asm-m68k/m5282.h @@ -347,6 +347,11 @@ #define MCFSDRAMC_DMR_V (0x00000001) #define MCFWTM_WCR (*(vu_short *)(CFG_MBAR+0x00140000)) +#define MCFWTM_WCR_EN (0x0001) +#define MCFWTM_WCR_HALTED (0x0002) +#define MCFWTM_WCR_DOZE (0x0004) +#define MCFWTM_WCR_WAIT (0x0008) + #define MCFWTM_WMR (*(vu_short *)(CFG_MBAR+0x00140002)) #define MCFWTM_WCNTR (*(vu_short *)(CFG_MBAR+0x00140004)) #define MCFWTM_WSR (*(vu_short *)(CFG_MBAR+0x00140006)) @@ -373,6 +378,42 @@ #define MCFCSM_CSCR_PS_32 (0x0000) #define MCFCSM_CSCR_PS_8 (0x0040) #define MCFCSM_CSCR_PS_16 (0x0080) +#define MCFCSM_CSCR_BEM(x) ((x & 1)<<5) +#define MCFCSM_CSCR_BEM_R (0) +#define MCFCSM_CSCR_BEM_RW (1<<5) + +/********************************************************************* +* +* Inter-IC (I2C) Module +* +*********************************************************************/ + +/* Read/Write access macros for general use */ +#define MCFI2C_I2ADR (*(vu_char *)(CFG_MBAR+0x00000300)) +#define MCFI2C_I2FDR (*(vu_char *)(CFG_MBAR+0x00000304)) +#define MCFI2C_I2CR (*(vu_char *)(CFG_MBAR+0x00000308)) +#define MCFI2C_I2SR (*(vu_char *)(CFG_MBAR+0x0000030C)) +#define MCFI2C_I2DR (*(vu_char *)(CFG_MBAR+0x00000310)) + +/* Bit level definitions and macros */ +#define MCFI2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) + +#define MCFI2C_I2FDR_IC(x) (((x)&0x3F)) + +#define MCFI2C_I2CR_IEN (0x80) +#define MCFI2C_I2CR_IIEN (0x40) +#define MCFI2C_I2CR_MSTA (0x20) +#define MCFI2C_I2CR_MTX (0x10) +#define MCFI2C_I2CR_TXAK (0x08) +#define MCFI2C_I2CR_RSTA (0x04) + +#define MCFI2C_I2SR_ICF (0x80) +#define MCFI2C_I2SR_IAAS (0x40) +#define MCFI2C_I2SR_IBB (0x20) +#define MCFI2C_I2SR_IAL (0x10) +#define MCFI2C_I2SR_SRW (0x04) +#define MCFI2C_I2SR_IIF (0x02) +#define MCFI2C_I2SR_RXAK (0x01) /********************************************************************* * @@ -541,5 +582,75 @@ #define MCFCFM_CMD_PGERS 0x40 #define MCFCFM_CMD_MASERS 0x41 +/********************************************************************* +* +* Interupt Controller (ICM) Module +* +*********************************************************************/ + +#define MCFICM_IMRH0 (*(vu_long*) (CFG_MBAR+0x00000C08)) +#define MCFICM_IMRH0_FEC_GRA 0x00000001 +#define MCFICM_IMRH0_FEC_EBERR 0x00000002 +#define MCFICM_IMRH0_FEC_BABT 0x00000004 +#define MCFICM_IMRH0_FEC_BABR 0x00000008 +#define MCFICM_IMRH0_PMM 0x00000010 +#define MCFICM_IMRH0_QADC_CF1 0x00000020 +#define MCFICM_IMRH0_QADC_CF2 0x00000040 +#define MCFICM_IMRH0_QADC_PF1 0x00000080 + +#define MCFICM_IMRH0_QADC_PF2 0x00000100 +#define MCFICM_IMRH0_GPTA_TOF 0x00000200 +#define MCFICM_IMRH0_GPTA_PAIF 0x00000400 +#define MCFICM_IMRH0_GPTA_PAOVF 0x00000800 +#define MCFICM_IMRH0_GPTA_C0F 0x00001000 +#define MCFICM_IMRH0_GPTA_C1F 0x00002000 +#define MCFICM_IMRH0_GPTA_C2F 0x00004000 +#define MCFICM_IMRH0_GPTA_C3F 0x00008000 + +#define MCFICM_IMRH0_GPTB_TOF 0x00010000 +#define MCFICM_IMRH0_GPTB_PAIF 0x00020000 +#define MCFICM_IMRH0_GPTB_PAOVF 0x00040000 +#define MCFICM_IMRH0_GPTB_C0F 0x00080000 +#define MCFICM_IMRH0_GPTB_C1F 0x00100000 +#define MCFICM_IMRH0_GPTB_C2F 0x00200000 +#define MCFICM_IMRH0_GPTB_C3F 0x00400000 +#define MCFICM_IMRH0_PIT0 0x00800000 + +#define MCFICM_IMRH0_PIT1 0x01000000 +#define MCFICM_IMRH0_PIT2 0x02000000 +#define MCFICM_IMRH0_PIT3 0x04000000 +#define MCFICM_IMRH0_CFM_CBEIF 0x08000000 +#define MCFICM_IMRH0_CFM_CCIF 0x10000000 +#define MCFICM_IMRH0_CFM_PVIF 0x20000000 +#define MCFICM_IMRH0_CFM_AEIF 0x40000000 +#define MCFICM_IMRH0_63 0x80000000 + +#define MCFICM_ICR_IL 3 +#define MCFICM_ICR_IP 0 + +#define MCFICM_ICR_PIT0 (*(vu_char*) (CFG_MBAR+0x00000C77)) +#define MCFICM_ICR_PIT1 (*(vu_char*) (CFG_MBAR+0x00000C78)) +#define MCFICM_ICR_PIT2 (*(vu_char*) (CFG_MBAR+0x00000C79)) +#define MCFICM_ICR_PIT3 (*(vu_char*) (CFG_MBAR+0x00000C7A)) + +/********************************************************************* +* +* Vectors +* +*********************************************************************/ + +#define MCFVECTOR_INTC0_OFFSET 64 + +#define MCFVECTOR_UART0 MCFVECTOR_INTC0_OFFSET+13 +#define MCFVECTOR_UART1 MCFVECTOR_INTC0_OFFSET+14 +#define MCFVECTOR_UART2 MCFVECTOR_INTC0_OFFSET+15 + +#define MCFVECTOR_I2C MCFVECTOR_INTC0_OFFSET+17 + +#define MCFVECTOR_PIT0 MCFVECTOR_INTC0_OFFSET+55 +#define MCFVECTOR_PIT1 MCFVECTOR_INTC0_OFFSET+56 +#define MCFVECTOR_PIT2 MCFVECTOR_INTC0_OFFSET+57 +#define MCFVECTOR_PIT3 MCFVECTOR_INTC0_OFFSET+58 + /****************************************************************************/ #endif /* m5282_h */