diff options
Diffstat (limited to 'cpu/mpc824x/drivers/i2c/i2c1.c')
-rw-r--r-- | cpu/mpc824x/drivers/i2c/i2c1.c | 1243 |
1 files changed, 0 insertions, 1243 deletions
diff --git a/cpu/mpc824x/drivers/i2c/i2c1.c b/cpu/mpc824x/drivers/i2c/i2c1.c deleted file mode 100644 index 94c671e5672..00000000000 --- a/cpu/mpc824x/drivers/i2c/i2c1.c +++ /dev/null @@ -1,1243 +0,0 @@ -/************************************************************* - * - * Copyright @ Motorola, 1999 - * - ************************************************************/ -#include <common.h> - -#ifdef CONFIG_HARD_I2C -#include <i2c.h> -#include "i2c_export.h" -#include "i2c.h" - -#undef I2CDBG0 -#undef DEBUG - -/* 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 TIMEOUT (CFG_HZ/4) -#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; - -/* 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 load_runtime_reg (unsigned int eumbbar, - unsigned int reg); - -extern unsigned int store_runtime_reg (unsigned int eumbbar, - unsigned int reg, unsigned int val); - -/************************** 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) { - PRINT ("I2C_Initialize: can't find EUMBBAR\n"); - return I2C_ERROR; - } - - /* validate the I2C address */ - if (addr & 0x80) { - PRINT ("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) { - PRINT ("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; - - if (len > 256) - return I2C_ERROR; - 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) { - PRINT ("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)) { - PRINT ("I2C_do_transaction, invalid transaction request: %d\n", - act); - return I2C_ERROR; - } - - /* range check the I2C address */ - if (i2c_addr & 0x80) { - PRINT ("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) { - PRINT ("I2C_do_transaction: can't send data address for read\n"); - 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) { - PRINT ("I2C_do_transaction: can't perform data transfer\n"); - 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); - PRINT ("Error(I2C_do_buffer): control phase, code(0x%08x), status(0x%08x)\n", rval, dev_stat); - 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. - */ - while (rval == I2CSUCCESS || rval == I2CADDRESS) { - int timeval = get_timer (0); - - /* poll the device until something happens */ - do { - rval = I2C_Timer_Event (Global_eumbbar, 0); - } - while (rval == I2CNOEVENT && get_timer (timeval) < TIMEOUT); - - /* 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); - PRINT ("Error(I2C_do_buffer): code(0x%08x), status(0x%08x)\n", - rval, dev_stat); - 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 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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); - } - } - - 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 - PRINT ("%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 - PRINT ("%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 - PRINT ("%s(%d): I2C_Stop enter\n", __FILE__, __LINE__); -#endif - - ctrl = I2C_Get_Ctrl (eumbbar); - ctrl.msta = 0; - I2C_Set_Ctrl (eumbbar, ctrl); - -#ifdef I2CDBG0 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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; - I2C_STAT stat; - - temp = load_runtime_reg (eumbbar, I2CSR); - -#ifdef I2CDBG0 - PRINT ("%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 - PRINT ("%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 - PRINT ("%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_CTRL ctrl; - -#ifdef I2CDBG0 - PRINT ("%s(%d): I2C_ISR\n", __FILE__, __LINE__); -#endif - - stat = I2C_Get_Stat (eumbbar); - ctrl = I2C_Get_Ctrl (eumbbar); - - /* 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 - PRINT ("%s(%d): set stat = 0x%08x\n", __FILE__, __LINE__, s.val); -#endif - - store_runtime_reg (eumbbar, I2CSR, s.val); - -} - -/****************************************************** - * The following are routines to glue the rest of - * U-Boot to the Sandpoint I2C driver. - *****************************************************/ - -void i2c_init (int speed, int slaveadd) -{ -#ifdef CFG_I2C_INIT_BOARD - /* - * call board specific i2c bus reset routine before accessing the - * environment, which might be in a chip on that bus. For details - * about this problem see doc/I2C_Edge_Conditions. - */ - i2c_init_board(); -#endif - -#ifdef DEBUG - I2C_Initialize (0x7f, 0, (void *) printf); -#else - I2C_Initialize (0x7f, 0, 0); -#endif -} - -int i2c_probe (uchar chip) -{ - int tmp; - - /* - * Try to read the first location of the chip. The underlying - * driver doesn't appear to support sending just the chip address - * and looking for an <ACK> back. - */ - udelay(10000); - return i2c_read (chip, 0, 1, (char *)&tmp, 1); -} - -int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) -{ - I2CStatus status; - uchar xaddr[4]; - - if (alen > 0) { - xaddr[0] = (addr >> 24) & 0xFF; - xaddr[1] = (addr >> 16) & 0xFF; - xaddr[2] = (addr >> 8) & 0xFF; - xaddr[3] = addr & 0xFF; - - status = I2C_do_buffer (0, I2C_MASTER_XMIT, chip, alen, - &xaddr[4 - alen], I2C_NO_STOP, 1, - I2C_NO_RESTART); - if (status != I2C_SUCCESS) { - PRINT ("i2c_read: can't send data address for read\n"); - return 1; - } - } - - /* The data transfer will be a continuation. */ - status = I2C_do_buffer (0, I2C_MASTER_RCV, chip, len, - buffer, I2C_STOP, 1, (alen > 0 ? I2C_RESTART : - I2C_NO_RESTART)); - - if (status != I2C_SUCCESS) { - PRINT ("i2c_read: can't perform data transfer\n"); - return 1; - } - - return 0; -} - -int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) -{ - I2CStatus status; - uchar dummy_buffer[I2C_RXTX_LEN + 2]; - uchar *p; - int i; - - /* fill in address in big endian order */ - for (i=alen-1; i>=0; --i) { - buffer[i] = addr & 0xFF; - addr >>= 8; - } - /* fill in data */ - p = dummy_buffer + alen; - - for (i=0; i<len; ++i) - *p++ = *buffer++; - - status = I2C_do_buffer (0, I2C_MASTER_XMIT, chip, alen + len, - dummy_buffer, I2C_STOP, 1, I2C_NO_RESTART); - -#ifdef CFG_EEPROM_PAGE_WRITE_DELAY_MS - udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000); -#endif - if (status != I2C_SUCCESS) { - PRINT ("i2c_write: can't perform data transfer\n"); - return 1; - } - - return 0; -} - -uchar i2c_reg_read (uchar i2c_addr, uchar reg) -{ - char buf[1]; - - i2c_init (0, 0); - - i2c_read (i2c_addr, reg, 1, buf, 1); - - return (buf[0]); -} - -void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val) -{ - i2c_init (0, 0); - - i2c_write (i2c_addr, reg, 1, &val, 1); -} - -#endif /* CONFIG_HARD_I2C */ |