www.pudn.com > MPC8241BSP.rar > i2c.c


 
/*************************************************************************** 
 *     Copyright Motorola, Inc. 1989-2001 ALL RIGHTS RESERVED 
 * 
 *  $ID:$ 
 * 
 * You are hereby granted a copyright license to use, modify, and 
 * distribute the SOFTWARE, also know as DINK32 (Dynamic Interactive Nano  
 * Kernel for 32-bit processors) solely in conjunction with the development  
 * and marketing of your products which use and incorporate microprocessors  
 * which implement the PowerPC(TM) architecture manufactured by  
 * Motorola and provided you comply with all of the following restrictions  
 * i) this entire notice is retained without alteration in any 
 * modified and/or redistributed versions, and  
 * ii) that such modified versions are clearly identified as such.  
 * No licenses are granted by implication, estoppel or 
 * otherwise under any patents or trademarks of Motorola, Inc. 
 *  
 * The SOFTWARE is provided on an "AS IS" basis and without warranty. To 
 * the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS ALL 
 * WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED WARRANTIES OF 
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY  
 * AGAINST INFRINGEMENT WITH REGARD TO THE SOFTWARE  
 * (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY ACCOMPANYING  
 * WRITTEN MATERIALS. 
 *  
 * To the maximum extent permitted by applicable law, IN NO EVENT SHALL 
 * MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING WITHOUT  
 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS  
 * INTERRUPTION, LOSS OF BUSINESS INFORMATION, 
 * OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE 
 * SOFTWARE. 
 * Motorola assumes no responsibility for the maintenance and support of 
 * the SOFTWARE. 
 ************************************************************************/ 
#include "i2c_export.h" 
#include "i2c.h" 
/*#define I2CDBG0 */ 
 
 
/* Define a macro to use an optional application-layer print function, if 
 * one was passed to the I2C library during initialization.  If there was 
 * no function pointer passed, this protects against calling it.  Also define 
 * the global variable that holds the passed pointer. 
 */ 
/*#define PRINT if ( app_print ) app_print 
static int (*app_print)(char *,...);*/ 
	  
/******************* Internal to I2C Driver *****************/ 
static unsigned int ByteToXmit = 0; 
static unsigned int XmitByte = 0; 
static unsigned char *XmitBuf = 0; 
static unsigned int XmitBufEmptyStop =0; 
static unsigned int ByteToRcv = 0; 
static unsigned int RcvByte = 0; 
static unsigned char *RcvBuf = 0; 
static unsigned int RcvBufFulStop = 0; 
static unsigned int MasterRcvAddress = 0; 
static unsigned int GlobalTimer = 0; 
 
/* Set by call to get_eumbbar during I2C_Initialize. 
 * This could be globally available to the I2C library, but there is 
 * an advantage to passing it as a parameter: it is already in a register 
 * and doesn't have to be loaded from memory.  Also, that is the way the 
 * I2C library was already implemented and I don't want to change it without 
 * a more detailed analysis. 
 * It is being set as a global variable in I2C_Initialize to hide it from  
 * the DINK application layer, because it is Kahlua-specific.  I think that  
 * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in 
 * a Kahlua-specific library dealing with the embedded utilities memory block. 
 * Right now, get_eumbbar is defined in dink32/kahlua.s.  The other two are 
 * defined in dink32/drivers/i2c/i2c2.s. 
 */ 
static unsigned int Global_eumbbar = 0; 
extern unsigned int get_eumbbar(); 
void         delay(); 
void I2cRead (unsigned char); 
unsigned int I2cInit (void); 
unsigned char READ_BUFFER[256]={0}; 
unsigned char WRITE_BUFFER[256]={0}; 
 
/*extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg ); 
#pragma Alias( load_runtime_reg, "load_runtime_reg" )*/ 
 
/*extern unsigned int store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val ); 
#pragma Alias( store_runtime_reg, "store_runtime_reg" )*/ 
 
/************************** API *****************/ 
 
/* Application Program Interface (API) are the calls provided by the I2C  
 * library to upper layer applications (i.e., DINK) to access the Kahlua 
 * I2C bus interface.  The functions and values that are part of this API 
 * are declared in i2c_export.h. 
 */ 
 
/*  Initialize I2C unit with the following: 
 *  driver's slave address 
 *  interrupt enabled 
 *  optional pointer to application layer print function 
 * 
 *  These parameters may be added: 
 *  desired clock rate 
 *  digital filter frequency sampling rate 
 * 
 *  This function must be called before I2C unit can be used. 
 */ 
I2C_Status I2C_Initialize( 
        unsigned char addr, 
        I2C_INTERRUPT_MODE en_int, 
        int (*p)(char *,...)) 
{ 
  I2CStatus status; 
  /* establish the pointer, if there is one, to the application's "printf" */ 
  /*app_print = p;*/ 
 
  /* If this is the first call, get the embedded utilities memory block 
   * base address.  I'm not sure what to do about error handling here: 
   * if a non-zero value is returned, accept it. 
   */ 
  if ( Global_eumbbar == 0) 
     Global_eumbbar = get_eumbbar(); 
  if ( Global_eumbbar == 0) 
  { 
    printf( "I2C_Initialize: can't find EUMBBAR\n" ); 
    return I2C_ERROR; 
  } 
 
  /* validate the I2C address */ 
  if (addr & 0x80) 
  { 
    printf( "I2C_Initialize, I2C address invalid:  %d 0x%x\n",  
      (unsigned int)addr, (unsigned int)addr );  
    return I2C_ERROR; 
  } 
 
  /* Call the internal I2C library function to perform work. 
   * Accept the default frequency sampling rate (no way to set it currently, 
   * via I2C_Init) and set the clock frequency to something reasonable. 
   */ 
  status = I2C_Init( Global_eumbbar, (unsigned char)0x31, addr, en_int); 
  if (status != I2CSUCCESS) 
  { 
    printf( "I2C_Initialize: error in initiation\n" ); 
    return I2C_ERROR; 
  } 
 
  /* all is well */ 
  return I2C_SUCCESS; 
} 
 
 
/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV 
 * are implemented.  Both are only in polling mode. 
 * 
 * en_int controls interrupt/polling mode 
 * act is the type of transaction 
 * i2c_addr is the I2C address of the slave device 
 * data_addr is the address of the data on the slave device 
 * len is the length of data to send or receive 
 * buffer is the address of the data buffer 
 * stop = I2C_NO_STOP, don't signal STOP at end of transaction 
 *        I2C_STOP, signal STOP at end of transaction 
 * retry is the timeout retry value, currently ignored 
 * rsta = I2C_NO_RESTART, this is not continuation of existing transaction 
 *        I2C_RESTART, this is a continuation of existing transaction 
 */ 
I2C_Status I2C_do_transaction( I2C_INTERRUPT_MODE en_int, 
                               I2C_TRANSACTION_MODE act, 
                               unsigned char i2c_addr, 
                               unsigned char data_addr, 
                               int len, 
                               char *buffer, 
                               I2C_STOP_MODE stop, 
                               int retry, 
                               I2C_RESTART_MODE rsta) 
{ 
  I2C_Status status; 
  unsigned char data_addr_buffer[1]; 
 
#if 1 
/* This is a temporary work-around.  The I2C library breaks the protocol 
 * if it attempts to handle a data transmission in more than one 
 * transaction, so the data address and the actual data bytes are put 
 * into a single buffer before sending it to the library internal functions. 
 * The problem is related to being able to restart a transaction without 
 * sending the I2C device address or repeating the data address.  It may take 
 * a day or two to sort it all out, so I'll have to get back to it later. 
 * Look at I2C_Start to see about using some status flags (I'm not sure that 
 * "stop" and "rsta" are enough to reflect the states, maybe so; but the logic 
 * in the library is insufficient) to control correct handling of the protocol. 
 */ 
unsigned char dummy_buffer[257]; 
if (act == I2C_MASTER_XMIT) 
{ 
int i; 
for (i=1;i<=len;i++)dummy_buffer[i]=buffer[i-1]; 
dummy_buffer[0]=data_addr; 
  status = I2C_do_buffer(en_int, act, i2c_addr, 1 + len,  
    dummy_buffer, stop, retry, rsta);  
  if (status != I2C_SUCCESS) 
  { 
    printf( "I2C_do_transaction: can't perform data transfer\n"); 
    return I2C_ERROR; 
  } 
return I2C_SUCCESS; 
} 
#endif /* end of temp work-around */ 
 
  /* validate requested transaction type */ 
  if ((act != I2C_MASTER_XMIT) && (act != I2C_MASTER_RCV)) 
  { 
    printf( "I2C_do_transaction, invalid transaction request:  %d\n", act); 
    return I2C_ERROR; 
  } 
 
  /* range check the I2C address */ 
  if (i2c_addr & 0x80) 
  { 
    printf( "I2C_do_transaction, I2C address out of range:  %d 0x%x\n",  
      (unsigned int)i2c_addr, (unsigned int)i2c_addr );  
    return I2C_ERROR; 
  } else { 
    data_addr_buffer[0] = data_addr; 
  } 
 
  /* We first have to contact the slave device and transmit the data address. 
   * Be careful about the STOP and restart stuff.  We don't want to signal STOP  
   * after sending the data address, but this could be a continuation if the 
   * application didn't release the bus after the previous transaction, by 
   * not sending a STOP after it. 
   */ 
  status = I2C_do_buffer(en_int, I2C_MASTER_XMIT, i2c_addr, 1,  
   data_addr_buffer, I2C_NO_STOP, retry, rsta);  
  if (status != I2C_SUCCESS) 
  { 
#ifdef I2CDBG0 
    printf( "I2C_do_transaction: can't send data address for read\n"); 
#endif 
    return I2C_ERROR; 
  } 
 
  /* The data transfer will be a continuation. */ 
  rsta = I2C_RESTART; 
 
  /* now handle the user data */ 
  status = I2C_do_buffer(en_int, act, i2c_addr, len,  
    buffer, stop, retry, rsta);  
  if (status != I2C_SUCCESS) 
  { 
#ifdef I2CDBG0 
    printf( "I2C_do_transaction: can't perform data transfer\n"); 
#endif 
    return I2C_ERROR; 
  } 
 
  /* all is well */ 
  return I2C_SUCCESS; 
} 
 
/* This function performs the work for I2C_do_transaction.  The work is 
 * split into this function to enable I2C_do_transaction to first transmit 
 * the data address to the I2C slave device without putting the data address 
 * into the first byte of the buffer. 
 * 
 * en_int controls interrupt/polling mode 
 * act is the type of transaction 
 * i2c_addr is the I2C address of the slave device 
 * len is the length of data to send or receive 
 * buffer is the address of the data buffer 
 * stop = I2C_NO_STOP, don't signal STOP at end of transaction 
 *        I2C_STOP, signal STOP at end of transaction 
 * retry is the timeout retry value, currently ignored 
 * rsta = I2C_NO_RESTART, this is not continuation of existing transaction 
 *        I2C_RESTART, this is a continuation of existing transaction 
 */ 
static I2C_Status I2C_do_buffer( I2C_INTERRUPT_MODE en_int, 
                                 I2C_TRANSACTION_MODE act, 
                                 unsigned char i2c_addr, 
                                 int len, 
                                 unsigned char *buffer, 
                                 I2C_STOP_MODE stop, 
                                 int retry, 
                                 I2C_RESTART_MODE rsta) 
{ 
  I2CStatus rval; 
  unsigned int dev_stat; 
  if (act == I2C_MASTER_RCV) 
  { 
    /* set up for master-receive transaction */ 
    rval = I2C_get(Global_eumbbar,i2c_addr,buffer,len,stop,rsta); 
  } else { 
    /* set up for master-transmit transaction */ 
    rval = I2C_put(Global_eumbbar,i2c_addr,buffer,len,stop,rsta); 
  } 
 
  /* validate the setup */ 
  if ( rval != I2CSUCCESS ) 
  { 
    dev_stat = load_runtime_reg( Global_eumbbar, I2CSR ); 
 
#ifdef I2CDBG0 
    printf( "Error(I2C_do_buffer): control phase, code(0x%08x), status(0x%08x)\n", rval, dev_stat); 
#endif 
    I2C_Stop( Global_eumbbar ); 
    return I2C_ERROR; 
  } 
 
  if (en_int == 1) 
  { 
    /* this should not happen, no interrupt handling yet */ 
    return I2C_SUCCESS; 
  } 
 
  /* this performs the polling action, when the transfer is completed, 
   * the status returned from I2C_Timer_Event will be I2CBUFFFULL or 
   * I2CBUFFEMPTY (rcv or xmit), I2CSUCCESS or I2CADDRESS indicates the 
   * transaction is not yet complete, anything else is an error. 
   */ 
 
	GlobalTimer = (retry / 10); 
 
  while ( rval == I2CSUCCESS || rval == I2CADDRESS ) 
  { 
    /* poll the device until something happens */ 
    do 
    { 
      rval = I2C_Timer_Event( Global_eumbbar, 0 ); 
    } 
    while ( rval == I2CNOEVENT ); 
 
    /* check for error condition */ 
    if ( rval == I2CSUCCESS || rval == I2CBUFFFULL || 
         rval == I2CBUFFEMPTY || rval == I2CADDRESS ) 
    { ; /* do nothing */ 
    } else { 
      /* report the error condition */ 
      dev_stat = load_runtime_reg( Global_eumbbar, I2CSR ); 
 
#ifdef I2CDBG0 
      printf( "Error(I2C_do_buffer):  code(0x%08x), status(0x%08x)\n", rval, dev_stat ); 
#endif 
      return I2C_ERROR; 
    } 
  } 
 
  /* all is well */ 
  return I2C_SUCCESS; 
} 
 
/** 
 * Note: 
 * 
 * In all following functions, 
 * the caller shall pass the configured embedded utility memory 
 * block base, EUMBBAR. 
 **/ 
 
/*********************************************************** 
 * function: I2C_put 
 * 
 * description: 
   Send a buffer of data to the intended rcv_addr.  
 * If stop_flag is set, after the whole buffer  
 * is sent, generate a STOP signal provided that the 
 * receiver doesn't signal the STOP in the middle. 
 * I2C is the master performing transmitting. If 
 * no STOP signal is generated at the end of current 
 * transaction, the master can generate a START signal 
 * to another slave addr. 
 * 
 * note: this is master xmit API 
 *********************************************************/ 
static I2CStatus I2C_put( unsigned int   eumbbar, 
                   unsigned char  rcv_addr,   /* receiver's address */ 
                   unsigned char *buffer_ptr, /* pointer of data to be sent */ 
                   unsigned int  length,      /* number of byte of in the buffer */ 
                   unsigned int  stop_flag,   /* 1 - signal STOP when buffer is empty 
                                               * 0 - no STOP signal when buffer is empty 
                                               */ 
                   unsigned int is_cnt )      /* 1 - this is a restart, don't check MBB 
                                               * 0 - this is a new start, check MBB 
                                               */ 
		   
{ 
    if ( buffer_ptr == 0 || length == 0 ) 
    { 
      return I2CERROR; 
    } 
 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_put\n", __FILE__, __LINE__ ); 
#endif 
	 
    XmitByte = 0; 
    ByteToXmit = length; 
    XmitBuf = buffer_ptr; 
    XmitBufEmptyStop = stop_flag; 
 
    RcvByte = 0; 
    ByteToRcv = 0; 
    RcvBuf = 0; 
 
    /* we are the master, start transaction */ 
    return I2C_Start( eumbbar, rcv_addr, XMIT, is_cnt ); 
} 
 
/*********************************************************** 
 * function: I2C_get 
 * 
 * description: 
 * Receive a buffer of data from the desired sender_addr 
 * If stop_flag is set, when the buffer is full and the  
 * sender does not signal STOP, generate a STOP signal. 
 * I2C is the master performing receiving. If no STOP signal 
 * is generated, the master can generate a START signal 
 * to another slave addr. 
 * 
 * note: this is master receive API 
 **********************************************************/ 
static I2CStatus I2C_get( unsigned int eumbbar, 
		   unsigned char rcv_from,    /* sender's address */ 
		   unsigned char *buffer_ptr, /* pointer of receiving buffer */ 
		   unsigned int  length,      /* length of the receiving buffer */ 
		   unsigned int  stop_flag,   /* 1 - signal STOP when buffer is full 
			                       * 0 - no STOP signal when buffer is full  
				               */ 
		   unsigned int is_cnt )      /* 1 - this is a restart, don't check MBB 
					       * 0 - this is a new start, check MBB 
                                               */ 
{ 
    if ( buffer_ptr == 0 || length == 0 ) 
    { 
      return I2CERROR; 
    } 
	 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_get\n", __FILE__, __LINE__ ); 
#endif 
 
    RcvByte = 0; 
    ByteToRcv = length; 
    RcvBuf = buffer_ptr; 
    RcvBufFulStop = stop_flag; 
	 
    XmitByte = 0; 
    ByteToXmit = 0; 
    XmitBuf = 0; 
	 
    /* we are the master, start the transaction */ 
    return I2C_Start( eumbbar, rcv_from, RCV, is_cnt ); 
 
} 
 
#if 0 /* turn off dead code */ 
/********************************************************* 
 * function: I2C_write 
 * 
 * description: 
 * Send a buffer of data to the requiring master.  
 * If stop_flag is set, after the whole buffer is sent, 
 * generate a STOP signal provided that the requiring  
 * receiver doesn't signal the STOP in the middle. 
 * I2C is the slave performing transmitting. 
 * 
 * Note: this is slave xmit API. 
 * 
 *       due to the current Kahlua design, slave transmitter 
 *       shall not signal STOP since there is no way 
 *       for master to detect it, causing I2C bus hung. 
 * 
 *       For the above reason, the stop_flag is always 
 *       set, i.e., 0. 
 * 
 *       programmer shall use the timer on Kahlua to  
 *       control the interval of data byte at the  
 *       master side. 
 *******************************************************/ 
static I2CStatus I2C_write( unsigned int eumbbar, 
		     unsigned char *buffer_ptr, /* pointer of data to be sent */ 
		     unsigned int  length,      /* number of byte of in the buffer */ 
		     unsigned int  stop_flag )  /* 1 - signal STOP when buffer is empty 
			                         * 0 - no STOP signal when buffer is empty 
				                 */ 
{ 
    if ( buffer_ptr == 0 || length == 0 ) 
    { 
      return I2CERROR; 
    } 
 
    XmitByte = 0; 
    ByteToXmit = length; 
    XmitBuf = buffer_ptr; 
    XmitBufEmptyStop = 0; /* in order to avoid bus hung, ignored the user's stop_flag */ 
 
    RcvByte = 0; 
    ByteToRcv = 0; 
    RcvBuf = 0; 
	 
    /* we are the slave, just wait for being called, or pull */ 
    /* I2C_Timer_Event( eumbbar ); */ 
} 
 
/****************************************************** 
 * function: I2C_read 
 * 
 * description: 
 * Receive a buffer of data from the sending master. 
 * If stop_flag is set, when the buffer is full and the  
 * sender does not signal STOP, generate a STOP signal. 
 * I2C is the slave performing receiving. 
 * 
 * note: this is slave receive API 
 ****************************************************/ 
static I2CStatus I2C_read(unsigned int eumbbar, 
                   unsigned char *buffer_ptr, /* pointer of receiving buffer */ 
		   unsigned int  length,      /* length of the receiving buffer */ 
		   unsigned int  stop_flag )  /* 1 - signal STOP when buffer is full 
			                       * 0 - no STOP signal when buffer is full  
			 		       */ 
{ 
    if ( buffer_ptr == 0 || length == 0 ) 
    { 
      return I2CERROR; 
    } 
 
    RcvByte = 0; 
    ByteToRcv = length; 
    RcvBuf = buffer_ptr; 
    RcvBufFulStop = stop_flag; 
 
    XmitByte = 0; 
    ByteToXmit = 0; 
    XmitBuf = 0; 
	 
    /* wait for master to call us, or poll */ 
    /* I2C_Timer_Event( eumbbar ); */ 
} 
#endif /* turn off dead code */ 
 
/********************************************************* 
 * function: I2c_Timer_Event 
 * 
 * description: 
 * if interrupt is not used, this is the timer event handler. 
 * After each fixed time interval, this function can be called 
 * to check the I2C status and call appropriate function to 
 * handle the status event. 
 ********************************************************/ 
static I2CStatus I2C_Timer_Event( unsigned int eumbbar, I2CStatus (*handler)( unsigned int ) ) 
{ 
 I2C_STAT stat; 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Timer_Event\n", __FILE__, __LINE__ ); 
#endif 
	 
    stat = I2C_Get_Stat( eumbbar ); 
 
    if ( stat.mif == 1 ) 
    { 
       if ( handler == 0 ) 
       { 
	   return I2C_ISR( eumbbar ); 
       } 
       else 
       { 
	   return (*handler)( eumbbar ); 
       } 
    } 
 
	else if (stat.rxak == 1) { 
/*		printf("tick\n");*/ 
		delay( 50 ); 
 
/* { 
	int x; 
		for (x = 1000; x > 0; x--) 
			; 
   }*/ 
		if (--GlobalTimer <= 0) 
			return( I2CRCVERROR ); 
	} 
 
    return I2CNOEVENT; 
} 
 
 
/****************** Device I/O function *****************/ 
 
/****************************************************** 
 * function: I2C_Start 
 * 
 * description: Generate a START signal in the desired mode. 
 *              I2C is the master. 
 * 
 *              Return I2CSUCCESS if no error. 
 * 
 * note: 
 ****************************************************/ 
static I2CStatus I2C_Start( unsigned int  eumbbar, 
                     unsigned char slave_addr, /* address of the receiver */  
	                 I2C_MODE      mode,       /* XMIT(1) - put (write) 
			                                    * RCV(0)  - get (read) 
					                            */ 
		             unsigned int is_cnt )    /* 1 - this is a restart, don't check MBB 
					                           * 0 - this is a new start 
					                           */ 
{ 
 
unsigned int tmp = 0; 
 I2C_STAT stat; 
 I2C_CTRL ctrl; 
 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Start addr 0x%x mode %d cnt %d\n", __FILE__,  __LINE__ , 
      slave_addr,mode,is_cnt); 
#endif 
 
    
     ctrl = I2C_Get_Ctrl( eumbbar ); 
 
    /* first make sure I2C has been initialized */ 
    if ( ctrl.men == 0 ) 
    { 
	   return I2CERROR; 
    } 
 
    /* next make sure bus is idle */ 
    stat = I2C_Get_Stat( eumbbar ); 
	 
    if ( is_cnt == 0 && stat.mbb == 1 ) 
    { 
	   /* sorry, we lost */ 
	   return I2CBUSBUSY; 
    } 
    else if ( is_cnt == 1 && stat.mif == 1 && stat.mal == 0 ) 
    { 
	/* sorry, we lost the bus */ 
        return I2CALOSS; 
    } 
	      
 
    /* OK, I2C is enabled and we have the bus */ 
 
    /* prepare to write the slave address */ 
    ctrl.msta = 1; 
    ctrl.mtx  = 1; 
    ctrl.txak = 0;	 
    ctrl.rsta = is_cnt;   /* set the repeat start bit */ 
    I2C_Set_Ctrl( eumbbar, ctrl ); 
	 
    /* write the slave address and xmit/rcv mode bit */ 
    tmp = load_runtime_reg( eumbbar, I2CDR ); 
    tmp = ( tmp & 0xffffff00 ) | ((slave_addr & 0x007f)<<1) | ( mode == XMIT ? 0x0 : 0x1 ); 
    store_runtime_reg( eumbbar, I2CDR, tmp ); 
 
	if ( mode == RCV ) 
	{ 
		MasterRcvAddress = 1; 
	} 
	else 
	{ 
		MasterRcvAddress = 0; 
	} 
	 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Start exit\n", __FILE__, __LINE__ ); 
#endif 
	 
    /* wait for the interrupt or poll  */ 
    return I2CSUCCESS; 
} 
 
/*********************************************************** 
 * function: I2c_Stop 
 * 
 * description: Generate a STOP signal to terminate the master 
 *              transaction. 
 *              return I2CSUCCESS 
 * 
 **********************************************************/ 
static I2CStatus I2C_Stop( unsigned int eumbbar ) 
{ 
 I2C_CTRL ctrl; 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Stop enter\n", __FILE__, __LINE__ ); 
#endif 
	 
    ctrl = I2C_Get_Ctrl(eumbbar ); 
    ctrl.msta = 0; 
    I2C_Set_Ctrl( eumbbar, ctrl ); 
 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Stop exit\n", __FILE__, __LINE__ ); 
#endif 
	 
    return I2CSUCCESS; 
} 
 
/**************************************************** 
 * function: I2C_Master_Xmit 
 * 
 * description: Master sends one byte of data to  
 *              slave target 
 *  
 *              return I2CSUCCESS if the byte transmitted. 
 *              Otherwise no-zero 
 * 
 * Note: condition must meet when this function is called: 
 *       I2CSR(MIF) == 1 && I2CSR(MCF)  == 1  && I2CSR(RXAK) == 0 
 *       I2CCR(MSTA) == 1  && I2CCR(MTX) == 1 
 * 
 ***************************************************/  
static I2CStatus I2C_Master_Xmit( unsigned int eumbbar ) 
{ 
	unsigned int val; 
    if ( ByteToXmit > 0 ) 
    { 
 
      if ( ByteToXmit == XmitByte ) 
      { 
	     /* all xmitted */ 
	     ByteToXmit = 0; 
 
	     if ( XmitBufEmptyStop == 1 ) 
	     { 
	       I2C_Stop( eumbbar ); 
	     } 
 
             return I2CBUFFEMPTY; 
 
      } 
 
#ifdef I2CDBG0 
	printf( "%s(%d): xmit 0x%02x\n", __FILE__, __LINE__, *(XmitBuf + XmitByte) ); 
#endif 
	   
       val = *(XmitBuf + XmitByte); 
       val &= 0x000000ff; 
       store_runtime_reg( eumbbar, I2CDR, val ); 
       XmitByte++; 
        
       return I2CSUCCESS; 
    	 
    } 
 
    return I2CBUFFEMPTY; 
} 
 
/*********************************************** 
 * function: I2C_Master_Rcv 
 * 
 * description: master reads one byte data 
 *              from slave source 
 * 
 *              return I2CSUCCESS if no error 
 *  
 * Note: condition must meet when this function is called: 
 *       I2CSR(MIF) == 1 && I2CSR(MCF) == 1 && 
 *       I2CCR(MSTA) == 1 && I2CCR(MTX) == 0 
 *  
 ***********************************************/ 
static I2CStatus I2C_Master_Rcv( unsigned int eumbbar ) 
{ 
	I2C_CTRL ctrl; 
	unsigned int val; 
    if ( ByteToRcv > 0 ) 
    { 
 
      if ( ByteToRcv - RcvByte == 2 && RcvBufFulStop == 1 ) 
      { 
	    /* master requests more than or equal to 2 bytes 
	     * we are reading 2nd to last byte 
	     */ 
	 
        /* we need to set I2CCR(TXAK) to generate a STOP */ 
          ctrl = I2C_Get_Ctrl( eumbbar ); 
	      ctrl.txak = 1; 
	      I2C_Set_Ctrl( eumbbar, ctrl ); 
		   
                            /* Kahlua will automatically generate a STOP 
			                 * next time a transaction happens 
			                 */ 
 
	    /* note: the case of master requesting one byte is 
	     *       handled in I2C_ISR 
	     */ 
      } 
	 
	  /* generat a STOP before reading the last byte */ 
	  if ( RcvByte + 1 == ByteToRcv && RcvBufFulStop == 1 ) 
	  { 
		  I2C_Stop( eumbbar ); 
	  } 
 
      val = load_runtime_reg( eumbbar, I2CDR ); 
      *(RcvBuf + RcvByte) = val & 0xFF; 
 
#ifdef I2CDBG0 
	printf( "%s(%d): rcv 0x%02x\n", __FILE__, __LINE__, *(RcvBuf + RcvByte) ); 
#endif 
       
      RcvByte++; 
 
	  if ( ByteToRcv == RcvByte ) 
      { 
	    ByteToRcv = 0; 
 
        return I2CBUFFFULL;		 
      } 
	   
      return I2CSUCCESS; 
   } 
       
   return I2CBUFFFULL; 
    
} 
 
/**************************************************** 
 * function: I2C_Slave_Xmit 
 * 
 * description: Slave sends one byte of data to  
 *              requesting destination 
 *  
 *        return SUCCESS if the byte transmitted. Otherwise 
 *        No-zero 
 * 
 * Note: condition must meet when this function is called: 
 *       I2CSR(MIF) == 1 && I2CSR(MCF) == 1 &&  I2CSR(RXAK) = 0 
 *       I2CCR(MSTA) == 0  && I2CCR(MTX) == 1 
 * 
 ***************************************************/ 
static I2CStatus I2C_Slave_Xmit( unsigned int eumbbar ) 
{ 
    unsigned int val;	 
    if ( ByteToXmit > 0 ) 
    { 
 
	   if ( ByteToXmit == XmitByte ) 
	   { 
	    /* no more data to send */	     
	    ByteToXmit = 0; 
		 
	    /* do not toggle I2CCR(MTX). Doing so will cause bus-hung 
	     * since current Kahlua design does not give master a way 
	     * to detect slave stop. It is always a good idea for 
	     * master to use timer to prevent the long long delays 
	     */ 
 
             return I2CBUFFEMPTY;		 
	   } 
 
#ifdef I2CDBG 
	printf( "%s(%d): xmit 0x%02x\n", __FILE__, __LINE__, *(XmitBuf + XmitByte) );  
#endif 
	    
        val = *(XmitBuf + XmitByte); 
        val &= 0x000000ff; 
        store_runtime_reg( eumbbar, I2CDR, val ); 
        XmitByte++; 
		 
 
       return I2CSUCCESS; 
    } 
 
    return I2CBUFFEMPTY; 
} 
 
/*********************************************** 
 * function: I2C_Slave_Rcv 
 * 
 * description: slave reads one byte data 
 *              from master source 
 * 
 *              return I2CSUCCESS if no error otherwise non-zero 
 *  
 * Note: condition must meet when this function is called: 
 *       I2CSR(MIF) == 1 && I2CSR(MCF) == 1 && 
 *       I2CCR(MSTA) == 0 && I2CCR(MTX)  = 0 
 *  
 ***********************************************/ 
static I2CStatus I2C_Slave_Rcv(unsigned int eumbbar ) 
{ 
	unsigned int val; 
    I2C_CTRL ctrl; 
    if ( ByteToRcv > 0 ) 
    { 
	  val = load_runtime_reg( eumbbar, I2CDR ); 
	  *( RcvBuf + RcvByte ) = val & 0xff; 
#ifdef I2CDBG 
	printf( "%s(%d): rcv 0x%02x\n", __FILE__, __LINE__, *(RcvBuf + RcvByte) ); 
#endif	   
	  RcvByte++; 
 
        if ( ByteToRcv == RcvByte ) 
        { 
	      if ( RcvBufFulStop == 1 ) 
	      { 
	        /* all done */ 
	        ctrl = I2C_Get_Ctrl( eumbbar ); 
	        ctrl.txak = 1; 
	        I2C_Set_Ctrl( eumbbar, ctrl ); 
	      } 
 
	      ByteToRcv = 0; 
          return I2CBUFFFULL;		   
        } 
 
	    return I2CSUCCESS; 
    } 
 
    return I2CBUFFFULL; 
} 
 
/****************** Device Control Function *************/ 
 
/********************************************************* 
 * function: I2C_Init 
 * 
 * description: Initialize I2C unit with desired frequency divider, 
 *              master's listening address, with interrupt enabled 
 *              or disabled. 
 * 
 * note: 
 ********************************************************/ 
static I2CStatus I2C_Init( unsigned int eumbbar, 
		    unsigned char fdr,        /* frequency divider */  
	            unsigned char slave_addr, /* driver's address used for receiving */ 
	 	    unsigned int en_int)     /* 1 - enable I2C interrupt  
			                      * 0 - disable I2C interrup  
				              */ 
{ 
I2C_CTRL ctrl; 
unsigned int tmp; 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Init enter\n", __FILE__, __LINE__); 
#endif 
	 
    ctrl = I2C_Get_Ctrl( eumbbar ); 
 
    /* disable the I2C module before we change everything */ 
    ctrl.men = 0; 
    I2C_Set_Ctrl( eumbbar, ctrl ); 
 
    /* set the frequency diver */ 
    tmp = load_runtime_reg( eumbbar, I2CFDR ); 
    tmp = ( tmp & 0xffffffc0 ) | ( fdr & 0x3f ); 
    store_runtime_reg( eumbbar, I2CFDR, tmp ); 
 
    /* Set our listening (slave) address */ 
    tmp = load_runtime_reg( eumbbar, I2CADR ); 
    tmp = ( tmp & 0xffffff01 ) | ( ( slave_addr & 0x7f) << 1 ); 
    store_runtime_reg( eumbbar, I2CADR, tmp ); 
 
    /* enable I2C with desired interrupt setting */ 
    ctrl.men = 1; 
    ctrl.mien = en_int & 0x1; 
    I2C_Set_Ctrl( eumbbar, ctrl ); 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_Init exit\n", __FILE__, __LINE__ ); 
#endif 
	 
    return I2CSUCCESS; 
     
} 
 
/***************************************** 
 * function I2c_Get_Stat 
 * 
 * description: Query I2C Status, i.e., read I2CSR 
 * 
 ****************************************/ 
static I2C_STAT I2C_Get_Stat( unsigned int eumbbar ) 
{ 
    unsigned int temp = load_runtime_reg( eumbbar, I2CSR ); 
 I2C_STAT stat; 
#ifdef I2CDBG0 
	printf( "%s(%d): get stat = 0x%08x\n", __FILE__, __LINE__, temp ); 
#endif	 
	 
    
    stat.rsrv0 = ( temp & 0xffffff00 ) >> 8; 
    stat.mcf   = ( temp & 0x00000080 ) >> 7; 
    stat.maas  = ( temp & 0x00000040 ) >> 6; 
    stat.mbb   = ( temp & 0x00000020 ) >> 5; 
    stat.mal   = ( temp & 0x00000010 ) >> 4; 
    stat.rsrv1 = ( temp & 0x00000008 ) >> 3; 
    stat.srw   = ( temp & 0x00000004 ) >> 2; 
    stat.mif   = ( temp & 0x00000002 ) >> 1; 
    stat.rxak  = ( temp & 0x00000001 ); 
    return stat; 
} 
 
/********************************************* 
 * function: I2c_Set_Ctrl 
 * 
 * description: Change I2C Control bits, 
 *              i.e., write to I2CCR 
 * 
 ********************************************/ 
static void I2C_Set_Ctrl( unsigned int eumbbar, I2C_CTRL ctrl ) /* new control value */ 
{ 
    unsigned int temp = load_runtime_reg( eumbbar, I2CCR ); 
    temp &= 0xffffff03; 
    temp |= ( ( ctrl.men  & 0x1 ) << 7 ); 
    temp |= ( ( ctrl.mien & 0x1 ) << 6 ); 
    temp |= ( ( ctrl.msta & 0x1 ) << 5 ); 
    temp |= ( ( ctrl.mtx  & 0x1 ) << 4 ); 
    temp |= ( ( ctrl.txak & 0x1 ) << 3 ); 
    temp |= ( ( ctrl.rsta & 0x1 ) << 2 ); 
#ifdef I2CDBG0 
	printf( "%s(%d): set ctrl = 0x%08x\n", __FILE__, __LINE__, temp ); 
#endif	 
    store_runtime_reg( eumbbar, I2CCR, temp ); 
 
} 
 
/***************************************** 
 * function: I2C_Get_Ctrl 
 * 
 * description: Query I2C Control bits, 
 *              i.e., read I2CCR 
 *****************************************/ 
static I2C_CTRL I2C_Get_Ctrl( unsigned int eumbbar ) 
{ 
    union { 
        I2C_CTRL ctrl ; 
        unsigned int temp; 
    } s; 
    s.temp = load_runtime_reg( eumbbar, I2CCR ); 
#ifdef I2CDBG0 
    printf( "%s(%d): get ctrl = 0x%08x\n", __FILE__, __LINE__, s.temp ); 
#endif 
 
    return s.ctrl; 
} 
 
 
/**************************************** 
 * function: I2C_Slave_Addr 
 * 
 * description: Process slave address phase. 
 *              return I2CSUCCESS if no error 
 * 
 * note: Precondition for calling this function: 
 *       I2CSR(MIF) == 1 && 
 *       I2CSR(MAAS) == 1 
 ****************************************/ 
static I2CStatus I2C_Slave_Addr( unsigned int eumbbar ) 
{ 
    I2C_STAT stat = I2C_Get_Stat( eumbbar ); 
    I2C_CTRL ctrl = I2C_Get_Ctrl( eumbbar ); 
     
    if ( stat.srw == 1 ) 
    { 
	   /* we are asked to xmit */ 
	   ctrl.mtx = 1; 
	   I2C_Set_Ctrl( eumbbar, ctrl );    /* set MTX */ 
	   return I2C_Slave_Xmit( eumbbar ); 
    } 
 
   /* we are asked to receive data */ 
   ctrl.mtx = 0; 
   I2C_Set_Ctrl(eumbbar, ctrl ); 
   (void)load_runtime_reg( eumbbar, I2CDR ); /* do a fake read to start */ 
 
    return I2CADDRESS; 
} 
 
/*********************************************** 
 * function: I2C_ISR 
 * 
 * description: I2C Interrupt service routine 
 * 
 * note: Precondition: 
 *      I2CSR(MIF) == 1 
 **********************************************/ 
static I2CStatus I2C_ISR( unsigned int eumbbar ) 
{ 
I2C_STAT stat = I2C_Get_Stat( eumbbar ); 
I2C_CTRL ctrl = I2C_Get_Ctrl( eumbbar ); 
#ifdef I2CDBG0 
	printf( "%s(%d): I2C_ISR\n", __FILE__, __LINE__ ); 
#endif 
	 
    
    /* clear MIF */ 
    stat.mif = 0; 
 
    /* Now let see what kind of event this is */     
    if ( stat.mcf == 1 ) 
    { 
	/* transfer compete */ 
 
	/* clear the MIF bit */ 
	I2C_Set_Stat( eumbbar, stat ); 
 
	if ( ctrl.msta == 1 ) 
	{ 
	    /* master */ 
	    if ( ctrl.mtx == 1 ) 
	    { 
			/* check if this is the address phase for master receive */ 
            if ( MasterRcvAddress == 1 ) 
			{ 
				/* Yes, it is the address phase of master receive */ 
                ctrl.mtx = 0; 
                /* now check how much we want to receive */ 
                if ( ByteToRcv == 1 && RcvBufFulStop == 1 ) 
                { 
                    ctrl.txak = 1; 
                } 
				 
                I2C_Set_Ctrl( eumbbar, ctrl ); 
               (void)load_runtime_reg( eumbbar, I2CDR );  /* fake read first */ 
 
				MasterRcvAddress = 0; 
				return I2CADDRESS; 
				 
			} 
 
            /* master xmit */		 
            if ( stat.rxak == 0 ) 
            { 
		          /* slave has acknowledged */ 
		          return I2C_Master_Xmit( eumbbar ); 
            } 
 
            /* slave has not acknowledged yet, generate a STOP */ 
            if ( XmitBufEmptyStop == 1 ) 
            { 
                   ctrl.msta = 0; 
                   I2C_Set_Ctrl( eumbbar, ctrl ); 
			} 
			 
            return I2CSUCCESS; 
	    } 
	     
	    /* master receive */ 
	    return I2C_Master_Rcv( eumbbar ); 
	} 
 
	/* slave */ 
	if ( ctrl.mtx == 1 ) 
	{ 
	    /* slave xmit */ 
	    if ( stat.rxak == 0 ) 
	    { 
		/* master has acknowledged */ 
		return I2C_Slave_Xmit( eumbbar ); 
	    } 
 
	    /* master has not acknowledged, wait for STOP */ 
	    /* do nothing for preventing bus from hung */ 
	    return I2CSUCCESS; 
	} 
 
	/* slave rcv */ 
	return I2C_Slave_Rcv( eumbbar ); 
	 
    } 
    else if ( stat.maas == 1 ) 
    { 
	/* received a call from master */ 
	 
	/* clear the MIF bit */ 
	I2C_Set_Stat(eumbbar, stat ); 
	 
    /* master is calling us, process the address phase */ 
	return I2C_Slave_Addr( eumbbar ); 
    } 
    else 
    { 
       /* has to be arbitration lost */ 
       stat.mal = 0; 
       I2C_Set_Stat( eumbbar, stat ); 
 
       ctrl.msta = 0; /* return to receive mode */ 
       I2C_Set_Ctrl( eumbbar, ctrl ); 
    } 
 
    return I2CSUCCESS; 
 
} 
 
/****************************************************** 
 * function: I2C_Set_Stat 
 * 
 * description: modify the I2CSR 
 * 
 *****************************************************/ 
static void I2C_Set_Stat( unsigned int eumbbar, I2C_STAT stat ) 
{ 
    union { 
      unsigned int val; 
      I2C_STAT stat; 
    } s_tmp; 
    union { 
      unsigned int val; 
      I2C_STAT stat; 
    } s; 
    s.val = load_runtime_reg( eumbbar, I2CSR ); 
    s.val &= 0xffffff08; 
    s_tmp.stat = stat; 
    s.val |= (s_tmp.val & 0xf7); 
 
#ifdef I2CDBG0 
    printf( "%s(%d): set stat = 0x%08x\n", __FILE__, __LINE__, s.val ); 
#endif	 
	 
    store_runtime_reg( eumbbar, I2CSR, s.val ); 
     
} 
void delay( int deciseconds )		 
{ 
	int	j,k; 
 
	k = 0xfffff; 
 
	for (j = 0; j < deciseconds; j++) { 
		while (k) {					 
			k = k-1;				 
		}							 
	} 
} 
 
void I2cRead (unsigned char addr) 
{ 
	unsigned int rc; 
	rc = I2C_do_transaction(0,I2C_MASTER_RCV,addr,0,256,READ_BUFFER,I2C_NO_STOP,0,I2C_NO_RESTART); 
	 
} 
void I2cWrite (unsigned char addr) 
{ 
	unsigned int rc,i; 
	for(i=0;i<256;i++)WRITE_BUFFER[i]=i; 
	 
		 
	rc = I2C_do_transaction(0,I2C_MASTER_XMIT,addr,0,256,WRITE_BUFFER,I2C_NO_STOP,0,I2C_NO_RESTART); 
	 
} 
unsigned int I2cInit (void) 
{ 
unsigned int rc; 
rc = I2C_Initialize(0,0,0); 
if(rc) 
return 1; 
else 
return 0; 	 
}