📄 cpvi2c.c
字号:
/* cpvI2c.c - I2C bus interface for PPC 8xx *//* Copyright 1998-2001 Wind River Systems, Inc. *//* Copyright 1997-2000 Motorola, Inc., All Rights Reserved *//*modification history--------------------01j,16sep01,dat Use of WRS_ASM macro01i,05dec00,rhk cleanup to comply with WRS code standards.01h,27jul99,rhk final cleanup of SDRAM sizing, added more comments.01g,26jul99,rhk more cleanup of SDRAM size calculation.01f,16jul99,rhk modified code to to determine size of SDRAM.01e,09jun99,srr changed to support cpv3060.01d,25mar98,map code cleanup01c,21nov97,rhk cleanup to comply with WRS code review01b,27sep97,scb Modified for crystal or 1:1 oscillator input clock.01a,17jun97,scb written by rb, integrated by scb.*//*DESCRIPTIONThis module implements the I2c bus access functions for PPC 8xx, and includes initilization of DPRAM from values in SROM.This module is linked in with others to create the compressed bootrom image,and also separately included in sysLib.c to make routines available tosysHwInit(). It is thus necessary for this module to beself-contained. Therefore there are no external references in this module.The cpvI2cdMain() or cpvI2cdInit() should be called when CPU interrupts arenot enabled, so they should not typically be called after sysHwInit2().*//* includes */#include "vxWorks.h" /* types */#include "intLib.h"#include "drv/multi/ppc860Siu.h"#include "drv/sio/ppc860Sio.h"#include "drv/multi/ppc860Cpm.h"#include "config.h" /* cpv3060 BSP definitions */#include "vxLib.h"#include "cpvI2c.h" /* I2C I/O definitions */#include "sdramSpd.h"/* externals *//* defines */#define IO_SYNC WRS_ASM(" sync") /* Macro for all i/o operations to use *//* I2C IOCTL data macros */#define I2C_WRITE(registername, data) \ cpvI2cdIoctl(I2C_IOCTL_W, ®istername, sizeof (registername), data)#define I2C_READ(registername) \ cpvI2cdIoctl(I2C_IOCTL_R, ®istername, sizeof (registername))#define I2C_OR(registername, data) \ cpvI2cdIoctl(I2C_IOCTL_O, ®istername, sizeof (registername), data)#define I2C_AND(registername, data) \ cpvI2cdIoctl(I2C_IOCTL_A, ®istername,sizeof (registername), data)#define I2C_ANDOR(registername, data1, data2) \ cpvI2cdIoctl(I2C_IOCTL_AO, ®istername, sizeof (registername), \ data1, data2)/* typedefs *//* globals */UINT cpvI2cEepromRead(); /* read EEPROM for DRAM information */UINT cpvI2cSromRead(); /* read SROM for DRAM information *//* locals */LOCAL STATUS cpvI2cdMain(); /* i2c driver main */LOCAL void cpvI2cdAlarm(); /* enable alarm */LOCAL void cpvI2cdCcr(); /* execute i2c command */LOCAL I2C_DRV_BD *cpvI2cdInit(); /* initialize i2c bus controller */LOCAL UINT cpvI2cdIoctl(); /* i2c I/O control */LOCAL void localIntLock(); /* Disable interrupts */LOCAL void localIntUnlock(); /* Reestablish interrupt state *//* forward declarations *//******************************************************************************** cpvI2cdMain - i2c driver main* * This function is the main entry point into the driver,* the driver is responsible for handling the specified* command request, the specified command requests are* local to the module.** Possible command requests (entry points):* transmit (put/write) data packet* receive (get/read) data packet* notes:* 1. error codes are passed back via the control/status word* field of the command packet** RETURNS: OK, and ERROR on failure*/LOCAL STATUS cpvI2cdMain ( FAST I2C_CMD_PKT *pPckt /* command packet pointer */ ) { FAST I2C_DRV_BD *pI2cdrvBd; /* buffer descriptor pointer */ FAST SCC_BUF *pRxbd; /* RXBD pointer */ FAST SCC_BUF *pTxbd; /* TXBD pointer */ FAST UINT counter; /* general purpose counter variable */ FAST UCHAR *pS; /* general purpose buffer pointer */ FAST UCHAR *pD; /* general purpose buffer pointer */ int dontCare; UINT immrVal = INTERNAL_MEM_MAP_ADDR; /* Base address of Internal Memory */ /* check transfer size */ if (pPckt->csword & I2C_IO_C_RDATA) { if ((pPckt->dataSize + 1) > I2C_RXBL_MAX) { pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_X_BUF); return (ERROR); } } if (pPckt->csword & I2C_IO_C_WDATA) { if ((pPckt->dataSize + 1) > I2C_TXBL_MAX) { pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_X_BUF); return (ERROR); } } /* initialize I2C bus controller */ pI2cdrvBd = cpvI2cdInit(pPckt, immrVal); /* setup pointers to transmit/receive buffer descriptors */ pRxbd = (SCC_BUF *)&pI2cdrvBd->rxbd[0]; pTxbd = (SCC_BUF *)&pI2cdrvBd->txbd[0]; /* * perform transmit operation, any operation requires it * * retrieve character(s) from user's buffer and move to * the transmit buffer */ pS = (UCHAR *)pPckt->dataAdrs; pD = pTxbd->dataPointer; *pD = (UCHAR)(pPckt->devAdrs & 0xFE); if (pPckt->csword & I2C_IO_C_RDATA) *pD |= 0x01; for (++pD, counter = pPckt->dataSize; counter; counter--) *pD++ = *pS++; IO_SYNC; /* mask processor interrupts */ localIntLock(&dontCare); /* * give transmit buffer descriptor to I2C (i.e., transmit * the buffer) */ I2C_WRITE(pTxbd->dataLength,pPckt->dataSize + 1); I2C_OR(pTxbd->statusMode,CPM_I2C_T_CS_R); /* * clear the slave address register, we do this due to the fact * that the I2C bus controller (i.e., the MPC8xx) will answer to * the transmitted buffer if the contents of the slave address * register equals the device address that we're communicating * with (only on I2C bus write operations) */ *I2ADD(immrVal) = 0x00; if (pPckt->csword & I2C_IO_C_RDATA) *I2ADD(immrVal) = (UCHAR)((pPckt->devAdrs & 0xFE) | 0x01); IO_SYNC; /* issue the start command (i.e., transmit the buffer) */ *I2COM(immrVal) |= CPM_I2C_COMMAND_STR; IO_SYNC; /* * poll for completion * enable RTC alarm for 10 seconds and poll for transmit-buffer * or transmit-error interrupt */ *RTCSC(immrVal) &= ~RTCSC_ALE; /* disable alarm interrupt */ for (cpvI2cdAlarm(immrVal, 10);;) { /* check for some type of transmit interrupt condition */ if (*I2CER(immrVal) & (CPM_I2C_ER_TXE|CPM_I2C_ER_TXB)) { if (*I2CER(immrVal) & (CPM_I2C_ER_TXE)) { pPckt->csword |= (I2C_IO_S_ERROR); if (pTxbd->statusMode & CPM_I2C_T_CS_NAK) pPckt->csword |= (I2C_IO_S_T_NAK); if (pTxbd->statusMode & CPM_I2C_T_CS_UN) pPckt->csword |= (I2C_IO_S_T_UN); if (pTxbd->statusMode & CPM_I2C_T_CS_CL) pPckt->csword |= (I2C_IO_S_T_CL); } break; } /* poll for alarm condition */ if (*RTCSC(immrVal) & RTCSC_ALR) { pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_T_TO); break; } } /* unmask processor interrupts */ localIntUnlock(dontCare); /* check for data transfer count mismatch */ if (!(pPckt->csword & (I2C_IO_S_ERROR))) { if (pTxbd->dataLength != (pPckt->dataSize + 1)) { pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_X_CNT); pPckt->dataSizeActual = pTxbd->dataLength; } } /* exit on error */ if (pPckt->csword & (I2C_IO_S_ERROR)) { /* disable i2c operation and exit with error status */ *I2MOD(immrVal) &= ~CPM_I2C_MODE_EN; IO_SYNC; return (ERROR); } /* exit if no receive data is expected */ if (!(pPckt->csword & I2C_IO_C_RDATA)) { /* disable i2c operation and exit with okay status */ *I2MOD(immrVal) &= ~CPM_I2C_MODE_EN; IO_SYNC; return (OK); } /* poll for completion of receive data */ localIntLock(&dontCare); /* * enable RTC alarm for 10 seconds and poll for transmit-buffer * or transmit-error interrupt */ *RTCSC(immrVal) &= ~RTCSC_ALE; /* Disable alarm interrupt */ for (cpvI2cdAlarm(immrVal, 10);;) { /* check for some type of transmit interrupt condition */ if (*I2CER(immrVal) & (CPM_I2C_ER_BSY|CPM_I2C_ER_RXB)) { if (*I2CER(immrVal) & (CPM_I2C_ER_BSY)) pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_R_BSY); if (pRxbd->statusMode & CPM_I2C_R_CS_OV) pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_R_OV); break; } /* poll for alarm condition */ if (*RTCSC(immrVal) & RTCSC_ALR) { pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_R_TO); break; } } /* disable i2c operation */ *I2MOD(immrVal) &= ~CPM_I2C_MODE_EN; IO_SYNC; /* unmask processor interrupts */ localIntUnlock(dontCare); /* * check for data transfer count mismatch, on match copy receive * buffer to caller's */ if (!(pPckt->csword & (I2C_IO_S_ERROR))) { if (pRxbd->dataLength != (pPckt->dataSize + 1)) { pPckt->csword |= (I2C_IO_S_ERROR|I2C_IO_S_X_CNT); pPckt->dataSizeActual = pRxbd->dataLength; return (ERROR); } else { /* * retrieve character(s) from driver's buffer and move to * user's buffer */ pS = (pRxbd->dataPointer + 1); pD = (UCHAR *)pPckt->dataAdrs; for (counter = pRxbd->dataLength - 1; counter; counter--) *pD++ = *pS++; IO_SYNC; } } else return (ERROR); return (OK); }/******************************************************************************** cpvI2cdInit - initialize I2C bus controller* * This component's purpose is to initialize the I2C bus* controller.** RETURNS: I2C buffer descriptor pointer*/LOCAL I2C_DRV_BD * cpvI2cdInit ( FAST I2C_CMD_PKT *pPckt, /* command packet pointer */ FAST UINT immrVal /* Base address of Internal Memory Regs */ ) { FAST I2C_DRV_BD *pI2cdrvBd; /* buffer descriptor pointer */ FAST SCC_BUF *pBd; /* TXBD/RXBD pointer */ FAST I2C_PARAM *pI2cPram; /* parameter RAM pointer */ FAST USHORT varWork; /* the old general purpose variable */ FAST UINT varDiv; /* clock divide variable */ FAST UINT varBdi; /* buffer descriptor index variable */ FAST UINT varBa; /* buffer allocation variable */ UINT dprbase = (UINT)DPRAM(immrVal); /* Dual-Ported RAM base address */ int dontCare; /* * setup local pointers and variables * initialize the base address to all buffers */ pI2cdrvBd = (I2C_DRV_BD *)DPRAM_I2C_BD; varBa = (UINT)((UCHAR *)DPRAM_I2C_BUFFER); /* mask processor interrupts */ localIntLock(&dontCare); /* disable i2c operation */ *I2MOD(immrVal) &= ~CPM_I2C_MODE_EN; IO_SYNC; /* * initialize I2C specifics: * first, initialize the I2C clock (keep below 100khz) * * MAX_MPU_SPEED is the likely maximum MPU speed for an MPC * for the near future. We could call mpc8xx_clk_value() * here to determine the actual speed but to do so causes * very slow accesses to SROM contents. Using MAX_MPU_SPEED * instead here is less accurate but since the I2C clock frequency * is legitimately variable, it works for all the supported * speeds and is much faster than calculating the clock speed * for every SROM access. */ varDiv = (MAX_MPU_SPEED) / 4; varDiv /= I2C_CLK_SPD; /* divide by I2C bus clock - 90khz */ varDiv /= 2; varDiv -= 3; *I2BRG(immrVal) = (UCHAR)varDiv; *I2MOD(immrVal) = (CPM_I2C_MODE_PDIV_BRGCLK4); IO_SYNC; /* enable the I2CSDA/I2CSCL pins */ *PBPAR(immrVal) |= PORT_B_PINS_I2C; IO_SYNC; *PBDIR(immrVal) |= PORT_B_PINS_I2C; IO_SYNC; *PBODR(immrVal) |= PORT_B_PINS_I2C; IO_SYNC; /* initialize receive buffers */ pBd = (SCC_BUF *)&pI2cdrvBd->rxbd[0]; for (varBdi = 0; varBdi < I2C_DRV_NBDS; varBdi++, pBd++) { I2C_WRITE(pBd->dataLength,0x0000); I2C_WRITE(pBd->dataPointer,varBa); varWork = (CPM_I2C_R_CS_E|CPM_I2C_R_CS_I); if (varBdi == (I2C_DRV_NBDS - 1)) varWork |= CPM_I2C_R_CS_W; I2C_WRITE(pBd->statusMode,varWork); varBa += I2C_RXBL_MAX; /* update buffer allocation variable */ } /* initialize transmit buffers */ pBd = (SCC_BUF *)&pI2cdrvBd->txbd[0]; for (varBdi = 0; varBdi < I2C_DRV_NBDS; varBdi++, pBd++) { I2C_WRITE(pBd->dataLength,0x0000); I2C_WRITE(pBd->dataPointer,varBa); varWork = (CPM_I2C_T_CS_I|CPM_I2C_T_CS_L|CPM_I2C_T_CS_S); if (varBdi == (I2C_DRV_NBDS - 1)) varWork |= CPM_I2C_T_CS_W; I2C_WRITE(pBd->statusMode,varWork); varBa += I2C_TXBL_MAX; /* update buffer allocation variable */ } /* initialize parameter RAM specifics */ pI2cPram = (I2C_PARAM *)PPC860_DPR_I2C(dprbase);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -