|  | /* | 
|  | * (C) Copyright 2002 ELTEC Elektronik AG | 
|  | * Frank Gottschling <fgottschling@eltec.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 | 
|  | */ | 
|  |  | 
|  | /* includes */ | 
|  | #include <common.h> | 
|  | #include "srom.h" | 
|  |  | 
|  | /* locals */ | 
|  | static unsigned long mpc107_eumb_addr = 0; | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | /* | 
|  | * calculate checksum for ELTEC revision srom | 
|  | */ | 
|  | unsigned long el_srom_checksum (ptr, size) | 
|  | register unsigned char *ptr; | 
|  | unsigned long size; | 
|  | { | 
|  | u_long f, accu = 0; | 
|  | u_int  i; | 
|  | u_char byte; | 
|  |  | 
|  | for (; size; size--) | 
|  | { | 
|  | byte = *ptr++; | 
|  | for (i = 8; i; i--) | 
|  | { | 
|  | f =  ((byte & 1) ^ (accu & 1)) ? 0x84083001 : 0; | 
|  | accu >>= 1; accu ^= f; | 
|  | byte >>= 1; | 
|  | } | 
|  | } | 
|  | return(accu); | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | static int mpc107_i2c_wait ( unsigned long timeout ) | 
|  | { | 
|  | unsigned long x; | 
|  |  | 
|  | while (((x = in32r(MPC107_I2CSR)) & 0x82) != 0x82) | 
|  | { | 
|  | if (!timeout--) | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (x & 0x10) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  | out32r(MPC107_I2CSR, 0); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | static int mpc107_i2c_wait_idle ( unsigned long timeout ) | 
|  | { | 
|  | while (in32r(MPC107_I2CSR) & 0x20) | 
|  | { | 
|  | if (!timeout--) | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | int mpc107_i2c_read_byte ( | 
|  | unsigned char device, | 
|  | unsigned char block, | 
|  | unsigned char offset ) | 
|  | { | 
|  | unsigned long timeout = MPC107_I2C_TIMEOUT; | 
|  | int data; | 
|  |  | 
|  | if (!mpc107_eumb_addr) | 
|  | return -6; | 
|  |  | 
|  | mpc107_i2c_wait_idle (timeout); | 
|  |  | 
|  | /* Start with MEN */ | 
|  | out32r(MPC107_I2CCR, 0x80); | 
|  |  | 
|  | /* Start as master */ | 
|  | out32r(MPC107_I2CCR, 0xB0); | 
|  | out32r(MPC107_I2CDR, (0xA0 | device | block)); | 
|  |  | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_read Error 1\n"); | 
|  | return -2; | 
|  | } | 
|  |  | 
|  | if (in32r(MPC107_I2CSR)&0x1) | 
|  | { | 
|  | /* Generate STOP condition; device busy or not existing */ | 
|  | out32r(MPC107_I2CCR, 0x80); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Data address */ | 
|  | out32r(MPC107_I2CDR, offset); | 
|  |  | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_read Error 2\n"); | 
|  | return -3; | 
|  | } | 
|  |  | 
|  | /* Switch to read - restart */ | 
|  | out32r(MPC107_I2CCR, 0xB4); | 
|  | out32r(MPC107_I2CDR, (0xA1 | device | block)); | 
|  |  | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_read Error 3\n"); | 
|  | return -4; | 
|  | } | 
|  |  | 
|  | out32r(MPC107_I2CCR, 0xA8); /* no ACK */ | 
|  | in32r(MPC107_I2CDR); | 
|  |  | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_read Error 4\n"); | 
|  | return -5; | 
|  | } | 
|  | /* Generate STOP condition */ | 
|  | out32r(MPC107_I2CCR, 0x88); | 
|  |  | 
|  | /* read */ | 
|  | data = in32r(MPC107_I2CDR); | 
|  |  | 
|  | return (data); | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | int mpc107_i2c_write_byte ( | 
|  | unsigned char device, | 
|  | unsigned char block, | 
|  | unsigned char offset, | 
|  | unsigned char val ) | 
|  | { | 
|  |  | 
|  | unsigned long timeout = MPC107_I2C_TIMEOUT; | 
|  |  | 
|  | if (!mpc107_eumb_addr) | 
|  | return -6; | 
|  |  | 
|  | mpc107_i2c_wait_idle(timeout); | 
|  |  | 
|  | /* Start with MEN */ | 
|  | out32r(MPC107_I2CCR, 0x80); | 
|  |  | 
|  | /* Start as master */ | 
|  | out32r(MPC107_I2CCR, 0xB0); | 
|  | out32r(MPC107_I2CDR, (0xA0 | device | block)); | 
|  |  | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_write Error 1\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Data address */ | 
|  | out32r(MPC107_I2CDR, offset); | 
|  |  | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_write Error 2\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Write */ | 
|  | out32r(MPC107_I2CDR, val); | 
|  | if (mpc107_i2c_wait(timeout) < 0) | 
|  | { | 
|  | printf("mpc107_i2c_write Error 3\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Generate Stop Condition */ | 
|  | out32r(MPC107_I2CCR, 0x80); | 
|  |  | 
|  | /* Return ACK or no ACK */ | 
|  | return (in32r(MPC107_I2CSR) & 0x01); | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | int mpc107_srom_load ( | 
|  | unsigned char addr, | 
|  | unsigned char *pBuf, | 
|  | int          cnt, | 
|  | unsigned char device, | 
|  | unsigned char block ) | 
|  | { | 
|  | register int i; | 
|  | int val; | 
|  | int timeout; | 
|  |  | 
|  | for (i = 0; i < cnt; i++) | 
|  | { | 
|  | timeout=100; | 
|  | do | 
|  | { | 
|  | val = mpc107_i2c_read_byte (device, block, addr); | 
|  | if (val < -1) | 
|  | { | 
|  | printf("i2c_read_error %d at dev %x block %x addr %x\n", | 
|  | val, device, block, addr); | 
|  | return -1; | 
|  | } | 
|  | else if (timeout==0) | 
|  | { | 
|  | printf ("i2c_read_error: timeout at dev %x block %x addr %x\n", | 
|  | device, block, addr); | 
|  | return -1; | 
|  | } | 
|  | timeout--; | 
|  | } while (val == -1); /* if no ack: try again! */ | 
|  |  | 
|  | *pBuf++ = (unsigned char)val; | 
|  | addr++; | 
|  |  | 
|  | if ((addr == 0) && (i != cnt-1))    /* is it the same block ? */ | 
|  | { | 
|  | if (block == FIRST_BLOCK) | 
|  | block = SECOND_BLOCK; | 
|  | else | 
|  | { | 
|  | printf ("ic2_read_error: read beyond 2. block !\n"); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | } | 
|  | udelay(100000); | 
|  | return (cnt); | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | int mpc107_srom_store ( | 
|  | unsigned char addr, | 
|  | unsigned char *pBuf, | 
|  | int          cnt, | 
|  | unsigned char device, | 
|  | unsigned char block ) | 
|  | { | 
|  | register int i; | 
|  |  | 
|  | for (i = 0; i < cnt; i++) | 
|  | { | 
|  | while (mpc107_i2c_write_byte (device,block,addr,*pBuf) == 1); | 
|  | addr++; | 
|  | pBuf++; | 
|  |  | 
|  | if ((addr == 0) && (i != cnt-1))     /* is it the same block ? */ | 
|  | { | 
|  | if (block == FIRST_BLOCK) | 
|  | block = SECOND_BLOCK; | 
|  | else | 
|  | { | 
|  | printf ("ic2_write_error: write beyond 2. block !\n"); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | } | 
|  | udelay(100000); | 
|  | return(cnt); | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ | 
|  |  | 
|  | int mpc107_i2c_init ( unsigned long eumb_addr, unsigned long divider ) | 
|  | { | 
|  | unsigned long x; | 
|  |  | 
|  | if (eumb_addr) | 
|  | mpc107_eumb_addr = eumb_addr; | 
|  | else | 
|  | return -1; | 
|  |  | 
|  | /* Set I2C clock */ | 
|  | x = in32r(MPC107_I2CFDR) & 0xffffff00; | 
|  | out32r(MPC107_I2CFDR, (x | divider)); | 
|  |  | 
|  | /* Clear arbitration */ | 
|  | out32r(MPC107_I2CSR, 0); | 
|  |  | 
|  | return mpc107_eumb_addr; | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------*/ |