| /* | 
 |  * (C) Copyright 2002 ELTEC Elektronik AG | 
 |  * Frank Gottschling <fgottschling@eltec.de> | 
 |  * | 
 |  * SPDX-License-Identifier:	GPL-2.0+ | 
 |  */ | 
 |  | 
 | /* 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; | 
 | } | 
 |  | 
 | /*----------------------------------------------------------------------------*/ |