⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c1.c

📁 ppcboot2.0 华恒光盘里带的BOOTLOADER
💻 C
📖 第 1 页 / 共 3 页
字号:
/************************************************************* * * 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_printstatic 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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -