1
0
uboot-1.1.4-kirkwood/board/eltec/elppc/mpc107_i2c.c

321 lines
6.6 KiB
C
Raw Normal View History

2024-01-07 23:57:24 +01:00
/*
* (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;
}
/*----------------------------------------------------------------------------*/