You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1637 lines
43 KiB

/* vxbFtI2c.c - I2C Controller hardware driver */
/*
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/* includes */
#include <vxWorks.h>
#include <vxBusLib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <semLib.h>
#include <vxbTimerLib.h>
#include <hwif/util/hwMemLib.h>
#include <hwif/vxbus/vxBus.h>
#include <hwif/vxbus/vxbPlbLib.h>
#include <hwif/vxbus/hwConf.h>
#include <hwif/vxbus/vxbI2cLib.h>
#include <spinLockLib.h>
#include "vxbFtI2c.h"
#include "ft2000-4.h"
/* defines */
#undef I2C_DBG_ON
#ifdef I2C_DBG_ON
#define I2C_DBG_IRQ 0x00000001
#define I2C_DBG_RW 0x00000002
#define I2C_DBG_ERR 0x00000004
#define I2C_DBG_ALL 0xffffffff
#define I2C_DBG_OFF 0x00000000
LOCAL UINT32 i2cDbgMask = I2C_DBG_ALL;
IMPORT FUNCPTR _func_logMsg;
#define I2C_DBG(mask, string, a, b, c, d, e, f) \
if ((i2cDbgMask & mask) || (mask == I2C_DBG_ALL)) \
if (_func_logMsg != NULL) \
(* _func_logMsg)(string, a, b, c, d, e, f)
#else
#define I2C_DBG(mask, string, a, b, c, d, e, f)
#endif /* I2C_DBG_ON */
#undef CSR_READ_4
#define CSR_READ_4(pCtrl, addr) \
vxbRead32 (FT_I2C_HANDLE (pCtrl), \
(UINT32 *) ((char *) FT_I2C_BAR (pCtrl) + addr))
#undef CSR_WRITE_4
#define CSR_WRITE_4(pCtrl, addr, data) \
vxbWrite32 (FT_I2C_HANDLE (pCtrl), \
(UINT32 *) ((char *) FT_I2C_BAR (pCtrl) + addr), data)
/* 8bit data + 1bit ack */
#define I2C_BYTE_LEN 9
#define I2C_BYTE_EXTRA I2C_BYTE_LEN
#ifdef I2C_DBG_ON
/* may print lots of information when I2C_DBG_ON is defined */
#define I2C_TOTAL_EXTRA_TICK(len) (2 * len)
#else
#define I2C_TOTAL_EXTRA_TICK(len) 2
#endif /* I2C_DBG_ON */
/* forward declarations */
void vxbFtI2cRegister (void);
LOCAL void vxbFtI2cInstInit (VXB_DEVICE_ID);
LOCAL void vxbFtI2cInstInit2 (VXB_DEVICE_ID);
LOCAL VXB_I2C_BUS_CTRL * vxbFtI2cCtrlGet (VXB_DEVICE_ID pDev);
LOCAL void vxbFtI2cInstConnect (VXB_DEVICE_ID pDev);
LOCAL STATUS vxbFtI2cInstUnlink (VXB_DEVICE_ID pDev, void * unused);
LOCAL STATUS vxbFtI2cIsr (VXB_DEVICE_ID pDev);
STATUS vxbFtI2cShow (VXB_DEVICE_ID pDevice, int verbose);
LOCAL void vxbFtI2cReadProcess (I2C_DRV_CTRL * pDrvCtrl);
LOCAL void vxbFtI2cWriteProcess (I2C_DRV_CTRL * pDrvCtrl);
LOCAL STATUS vxbFtI2cTransfer (VXB_DEVICE_ID pDev, I2C_MSG * msgs, int num);
LOCAL STATUS vxbFtI2cRead(VXB_DEVICE_ID, UINT8, UINT32, UINT8 *, UINT32);
LOCAL STATUS vxbFtI2cWrite(VXB_DEVICE_ID, UINT8, UINT32, UINT8 *, UINT32);
/* structure to store the driver functions for vxBus */
LOCAL struct drvBusFuncs ftI2cDrvFuncs =
{
vxbFtI2cInstInit, /* devInstanceInit */
vxbFtI2cInstInit2, /* devInstanceInit2 */
vxbFtI2cInstConnect /* devConnect */
};
LOCAL device_method_t ftI2cDrv_methods[] =
{
DEVMETHOD (vxbI2cControlGet, vxbFtI2cCtrlGet),
DEVMETHOD (busDevShow, vxbFtI2cShow),
DEVMETHOD (vxbDrvUnlink, vxbFtI2cInstUnlink),
DEVMETHOD_END
};
/* I2C VxBus registration info */
LOCAL struct vxbDevRegInfo ftI2cDrvRegistration =
{
NULL, /* pNext */
VXB_DEVID_DEVICE, /* devID */
VXB_BUSID_PLB, /* busID = PLB */
VXB_VER_4_0_0, /* busVer */
FT_I2C_DRIVER_NAME, /* drvName */
&ftI2cDrvFuncs, /* pDrvBusFuncs */
&ftI2cDrv_methods[0], /* pMethods */
NULL /* devProbe */
};
LOCAL struct vxbI2cBusCtrl ftI2cCtrl = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
vxbFtI2cRead,
vxbFtI2cWrite,
vxbFtI2cTransfer,
};
/*****************************************************************************
*
* vxbFtI2cInit - initialize the I2C module
*
* This routine initializes the I2C module
*
* RETURNS: OK, or ERROR if fail
*
* ERRNO: N/A
*/
LOCAL STATUS vxbFtI2cInit
(
VXB_DEVICE_ID pDev
)
{
I2C_DRV_CTRL * pDrvCtrl;
UINT16 sclHi = 0;
UINT16 sclLo = 0;
UINT32 val = 0;
UINT32 timeout = 0;
VXB_ASSERT (pDev != NULL, ERROR)
pDrvCtrl = pDev->pDrvCtrl;
CSR_WRITE_4 (pDrvCtrl, I2C_ENABLE, 0x0);
while (timeout++ < I2C_TIMEOUT)
{
if (0 ==
(IC_ENABLE_STATUS_IC_EN & CSR_READ_4 (pDrvCtrl, I2C_ENABLE_STATUS)))
{
break;
}
vxbUsDelay (I2C_DELAY);
if (timeout == I2C_TIMEOUT)
{
I2C_DBG (I2C_DBG_ERR,
"vxbFtI2cInit disable I2C_ENABLE timeout\n",1,2,3,4,5,6);
return ERROR;
}
}
CSR_WRITE_4 (pDrvCtrl, I2C_CON, 0x0);
/* update fifo size information */
val = CSR_READ_4 (pDrvCtrl, I2C_COMP_PARAM_1);
pDrvCtrl->txFifoSize = ((val >> I2C_COMP_PARAM_1_TX_SHIFT) &
I2C_COMP_PARAM_1_TX_MASK) + 1;
pDrvCtrl->rxFifoSize = ((val >> I2C_COMP_PARAM_1_RX_SHIFT) &
I2C_COMP_PARAM_1_RX_MASK) + 1;
/* setting SCL clock */
val = pDrvCtrl->clkFrequency / pDrvCtrl->busSpeed;
sclHi = (UINT16) (val / 2);
/* compensate side effects of integer calculations */
sclLo = (UINT16) (val - sclHi);
if (sclHi < 29)
{
sclLo = sclLo - (29-sclHi);
sclHi = 29;
}
sclLo = sclLo - 8;
sclHi = sclHi - 15;
if (pDrvCtrl->busSpeed > I2C_STANDARD_SPEED)
{
CSR_WRITE_4 (pDrvCtrl, I2C_FS_SCL_LCNT, sclLo);
CSR_WRITE_4 (pDrvCtrl, I2C_FS_SCL_HCNT, sclHi);
CSR_WRITE_4 (pDrvCtrl, I2C_CON, I2C_CTR_DEFAULT | I2C_CON_MS_FS);
}
else
{
CSR_WRITE_4 (pDrvCtrl, I2C_SS_SCL_LCNT, sclLo);
CSR_WRITE_4 (pDrvCtrl, I2C_SS_SCL_HCNT, sclHi);
CSR_WRITE_4 (pDrvCtrl, I2C_CON, I2C_CTR_DEFAULT | I2C_CON_MS_SS);
}
/* clear Interrupt Status Register */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_STAT, CSR_READ_4 (pDrvCtrl, I2C_INTR_STAT));
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_INTR);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_RX_UNDER);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_RX_OVER);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_TX_OVER);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_RD_REQ);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_TX_ABRT);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_RX_DONE);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_ACTIVITY);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_STOP_DET);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_START_DET);
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_GEN_CALL);
/* disable all IRQs */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK, I2C_IRQ_NONE);
return OK;
}
/******************************************************************************
*
* vxbFtI2cDrvRegister - register FT I2c driver
*
* This routine registers the Altera I2c driver with the vxBus subsystem.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void vxbFtI2cRegister (void)
{
/* call the vxBus routine to register the I2c driver */
vxbDevRegister (&ftI2cDrvRegistration);
}
/*******************************************************************************
*
* vxbFtI2cInstInit - first level initialization routine of I2c device
*
* This routine performs the first level initialization of the I2c device.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
LOCAL void vxbFtI2cInstInit
(
VXB_DEVICE_ID pDev
)
{
I2C_DRV_CTRL * pDrvCtrl;
struct hcfDevice * pHcf;
UINT32 muxRegBase, muxRegBaseEx;
UINT32 muxBitValue, muxBitValueEx;
VXB_ASSERT (pDev != NULL, ERROR)
/* create controller driver context structure for core */
pDrvCtrl = (I2C_DRV_CTRL *) hwMemAlloc (sizeof (I2C_DRV_CTRL));
if (pDrvCtrl == NULL)
return;
/* save instance ID */
pDev->pDrvCtrl = pDrvCtrl;
pDrvCtrl->i2cDev = pDev;
/* override intCtlr device reg base from device scratch registers 0 */
vxbRegMap (pDev, 0, &pDrvCtrl->i2cHandle);
pHcf = (struct hcfDevice *) hcfDeviceGet (pDev);
if (pHcf == NULL)
return;
/*
* resourceDesc {
* The clkFreq resource specifies clock frequency of I2C function clock. }
*/
if (devResourceGet (pHcf, "clkFreq", HCF_RES_INT,
(void *) &pDrvCtrl->clkFrequency) != OK)
{
#ifndef _VXBUS_BASIC_HWMEMLIB
hwMemFree ((char *) pDrvCtrl);
#endif /* _VXBUS_BASIC_HWMEMLIB */
pDev->pDrvCtrl = NULL;
return;
}
/*
* resourceDesc {
* The busSpeed resource specifies the BUS Speed. }
*/
if (devResourceGet (pHcf, "busSpeed", HCF_RES_INT,
(void *) &pDrvCtrl->busSpeed) != OK)
{
pDrvCtrl->busSpeed = I2C_FAST_SPEED;
}
pDrvCtrl->defBusSpeed = pDrvCtrl->busSpeed;
/* choose I2C function pin for multi-function pad pin. D2000,FT2000A4... */
/* I2C Controller 1,2,3 */
if(pDev->unitNumber > 0)
{
if (devResourceGet (pHcf, "pinDemuxReg", HCF_RES_INT,
(void *) &muxRegBase) == OK)
{
if (devResourceGet (pHcf, "pinDemuxBit", HCF_RES_INT,
(void *) &muxBitValue) == OK)
{
muxBitValue |= readl(muxRegBase);
writel(muxBitValue, muxRegBase);
}
}
}
/* only I2C Controller 3 */
if(3 == pDev->unitNumber)
{
if (devResourceGet (pHcf, "pinDemuxRegEx", HCF_RES_INT,
(void *) &muxRegBaseEx) == OK)
{
if (devResourceGet (pHcf, "pinDemuxBitEx", HCF_RES_INT,
(void *) &muxBitValueEx) == OK)
{
muxBitValueEx |= readl(muxRegBaseEx);
writel(muxBitValueEx, muxRegBaseEx);
}
}
}
/* reset I2C Controller */
vxbFtI2cInit (pDev);
/* announce that there's an I2C bus */
(void) vxbBusAnnounce (pDev, VXB_BUSID_I2C);
i2cBusAnnounceDevices (pDev);
return;
}
/*******************************************************************************
*
* vxbFtI2cInstInit2 - second level initialization routine of I2c modules
*
* This routine performs the second level initialization of the I2c modules.
*
* This routine is called later during system initialization. OS features
* such as memory allocation are available at this time.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
LOCAL void vxbFtI2cInstInit2
(
VXB_DEVICE_ID pDev /* The device */
)
{
I2C_DRV_CTRL * pDrvCtrl = NULL;
struct hcfDevice * pHcf;
VXB_ASSERT (pDev != NULL, ERROR)
pDrvCtrl = (I2C_DRV_CTRL *) pDev->pDrvCtrl;
pHcf = (struct hcfDevice *) hcfDeviceGet (pDev);
if (pHcf == NULL)
return;
/*
* resourceDesc {
* The polling resource specifies whether
* the driver uses polling mode or not.
* If this property is not explicitly
* specified, the driver uses interrupt
* by default. }
*/
if (devResourceGet (pHcf, "polling", HCF_RES_INT,
(void *) &pDrvCtrl->polling) != OK)
{
pDrvCtrl->polling = TRUE;
}
pDrvCtrl->i2cDevSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE |
SEM_INVERSION_SAFE);
if (pDrvCtrl->i2cDevSem == SEM_ID_NULL)
{
I2C_DBG (I2C_DBG_ERR, "vxbFtI2cInstInit2:i2cDevSem create failed\n",1,2,3,4,5,6);
return;
}
pDrvCtrl->i2cDataSem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
if (pDrvCtrl->i2cDataSem == SEM_ID_NULL)
{
I2C_DBG (I2C_DBG_ERR, "vxbFtI2cInstInit2:i2cDataSem Ceate failed\n",1,2,3,4,5,6);
return;
}
SPIN_LOCK_ISR_INIT (&pDrvCtrl->lock, 0);
return;
}
/*******************************************************************************
*
* vxbFtI2cIsr - interrupt service routine
*
* This routine handles interrupts of I2C.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
LOCAL STATUS vxbFtI2cIsr
(
VXB_DEVICE_ID pDev
)
{
UINT32 status = 0;
UINT32 enabled = 0;
UINT32 giveSem = FALSE;
I2C_DRV_CTRL * pDrvCtrl;
pDrvCtrl = pDev->pDrvCtrl;
I2C_DBG (I2C_DBG_IRQ, "vxbFtI2cIsr enter \n ",1,2,3,4,5,6);
/* check if i2c controller is enabled */
enabled = CSR_READ_4 (pDrvCtrl, I2C_ENABLE);
if (enabled == 0)
{
I2C_DBG (I2C_DBG_IRQ, "Fatal error statue 0x%x \n ",
CSR_READ_4 (pDrvCtrl, I2C_INTR_STAT),2,3,4,5,6);
return ERROR;
}
/* check there is no interrupt */
status = CSR_READ_4 (pDrvCtrl, I2C_RAW_INTR_STAT);
if (0 == (status & ((UINT32) ~I2C_IRQ_ACTIVITY)))
{
I2C_DBG (I2C_DBG_IRQ, "None IRQ\n",1,2,3,4,5,6);
return ERROR;
}
/* read interrupt status */
status = CSR_READ_4 (pDrvCtrl, I2C_INTR_STAT);
if (I2C_IRQ_STOP_DET == (status & I2C_IRQ_STOP_DET))
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_STOP_DET\n",1,2,3,4,5,6);
/* clear interrupt bit */
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_STOP_DET);
giveSem = TRUE;
goto done;
}
if (I2C_INTR_START_DET == (status & I2C_INTR_START_DET))
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_START_DET\n",1,2,3,4,5,6);
/* clear interrupt bit */
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_START_DET);
}
if (I2C_IRQ_RX_UNDER == (status & I2C_IRQ_RX_UNDER))
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_RX_UNDER\n",1,2,3,4,5,6);
/* clear interrupt bit */
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_RX_UNDER);
pDrvCtrl->errorStatus = I2C_ERR_STATUS_RX_UNDER;
giveSem = TRUE;
goto done;
}
if (I2C_IRQ_RX_OVER == (status & I2C_IRQ_RX_OVER))
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_RX_OVER\n",1,2,3,4,5,6);
/* clear interrupt bit */
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_RX_OVER);
pDrvCtrl->errorStatus = I2C_ERR_STATUS_RX_OVER;
giveSem = TRUE;
goto done;
}
if (I2C_IRQ_TX_ABRT == (status & I2C_IRQ_TX_ABRT))
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_TX_ABRT Source 0x%x \n",
CSR_READ_4 (pDrvCtrl, I2C_TX_ABRT_SOURCE),2,3,4,5,6);
/* clear interrupt bit */
(void) CSR_READ_4 (pDrvCtrl, I2C_CLR_TX_ABRT);
pDrvCtrl->errorStatus = I2C_ERR_STATUS_TX_ABRT;
giveSem = TRUE;
goto done;
}
/* Reading Process */
if ((I2C_IRQ_RX_FULL == (status & I2C_IRQ_RX_FULL))
)
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_RX_FULL\n",1,2,3,4,5,6);
/* Mask interrupt */
SPIN_LOCK_ISR_TAKE (&pDrvCtrl->lock);
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) &
(UINT32) ~I2C_IRQ_RX_FULL);
SPIN_LOCK_ISR_GIVE (&pDrvCtrl->lock);
isrDeferJobAdd (pDrvCtrl->trxQueueId, &pDrvCtrl->rxIsrDef);
}
/* Writing Process */
if (I2C_IRQ_TX_EMPTY == (status & I2C_IRQ_TX_EMPTY))
{
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_TX_EMPTY\n",1,2,3,4,5,6);
/* Mask interrupt */
SPIN_LOCK_ISR_TAKE (&pDrvCtrl->lock);
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) &
(UINT32) ~I2C_IRQ_TX_EMPTY);
SPIN_LOCK_ISR_GIVE (&pDrvCtrl->lock);
isrDeferJobAdd (pDrvCtrl->trxQueueId, &pDrvCtrl->txIsrDef);
}
done:
if (giveSem)
{
if (semGive (pDrvCtrl->i2cDataSem) == ERROR)
{
I2C_DBG (I2C_DBG_ERR, "semGive error\n",1,2,3,4,5,6);
}
}
return OK;
}
/*******************************************************************************
*
* vxbFtI2cCtrlGet - get the callback functions
*
* This routine installs the callback functions to I2C libary.
*
* RETURNS: the address of callback functions
*
* ERRNO: N/A
*/
LOCAL VXB_I2C_BUS_CTRL * vxbFtI2cCtrlGet
(
VXB_DEVICE_ID pDev
)
{
VXB_ASSERT (pDev != NULL, ERROR)
return (&ftI2cCtrl);
}
/*******************************************************************************
*
* vxbFtI2cInstConnect - third level initialization
*
* This routine performs the third level initialization of the i2c controller
* driver. Nothing to be done in this routine.
*
* RETURNS: N/A
*
* ERRNO : none
* \NOMANUAL
*/
LOCAL void vxbFtI2cInstConnect
(
VXB_DEVICE_ID pDev
)
{
I2C_DRV_CTRL * pDrvCtrl = NULL;
VXB_ASSERT (pDev != NULL, ERROR)
pDrvCtrl = (I2C_DRV_CTRL *) pDev->pDrvCtrl;
if (pDrvCtrl->polling == FALSE)
{
pDrvCtrl->txIsrDef.func = (void (*)(void *)) vxbFtI2cWriteProcess;
pDrvCtrl->txIsrDef.pData = (void *) pDrvCtrl;
pDrvCtrl->rxIsrDef.func = (void (*)(void *)) vxbFtI2cReadProcess;
pDrvCtrl->rxIsrDef.pData = (void *) pDrvCtrl;
pDrvCtrl->trxQueueId = isrDeferQueueGet (NULL, 0, 0, 0);
if(pDrvCtrl->trxQueueId == NULL)
{
I2C_DBG (I2C_DBG_ERR, "vxbFtI2cInstConnect:DeferQueue Ceate failed\n",1,2,3,4,5,6);
return;
}
/* connect and enable interrupt */
vxbIntConnect (pDev, 0, (VOIDFUNCPTR) vxbFtI2cIsr, pDev);
vxbIntEnable (pDev, 0, (VOIDFUNCPTR) vxbFtI2cIsr, pDev);
}
return;
}
/*******************************************************************************
*
* vxbFtI2cInstUnlink - VxBus unlink handler
*
* This function shuts down a I2C controller instance in response to an
* an unlink event from VxBus. This may occur if our VxBus instance has
* been terminated, or if the FslI2c driver has been unloaded.
*
* RETURNS: OK if device was successfully destroyed, otherwise ERROR
*
* ERRNO: N/A
*/
LOCAL STATUS vxbFtI2cInstUnlink
(
VXB_DEVICE_ID pDev,
void * unused
)
{
I2C_DRV_CTRL * pDrvCtrl = NULL;
VXB_ASSERT (pDev != NULL, ERROR)
pDrvCtrl = (I2C_DRV_CTRL *) pDev->pDrvCtrl;
if (semTake (pDrvCtrl->i2cDevSem, WAIT_FOREVER) == OK)
{
if (semDelete (pDrvCtrl->i2cDevSem) != OK)
{
I2C_DBG (I2C_DBG_ERR,
"vxbFtI2cInstUnlink:i2cDevSem delete failed\n",
0, 0, 0, 0, 0, 0);
return (ERROR);
}
}
if (semTake (pDrvCtrl->i2cDataSem, WAIT_FOREVER) == OK)
{
if (semDelete (pDrvCtrl->i2cDataSem) != OK)
{
I2C_DBG (I2C_DBG_ERR,
"vxbFtI2cInstUnlink:i2cDevSem delete failed\n",
0, 0, 0, 0, 0, 0);
return (ERROR);
}
}
#ifndef _VXBUS_BASIC_HWMEMLIB
hwMemFree ((char *) pDrvCtrl);
#endif /* _VXBUS_BASIC_HWMEMLIB */
pDev->pDrvCtrl = NULL;
return (OK);
}
/*******************************************************************************
*
* vxbFtI2cPoll - poll service function
*
* This function provides poll service of I2C controller.
*
* RETURNS: OK, or ERROR if failed.
*
* ERRNO: N/A
*/
LOCAL STATUS vxbFtI2cPoll
(
I2C_DRV_CTRL * pDrvCtrl
)
{
UINT32 status = 0;
UINT64 timeout = 0;
pDrvCtrl->pollIrqMask = (I2C_IRQ_DEFAULT_MASK & ~I2C_IRQ_STOP_DET);
/* calculate time out to us */
timeout = pDrvCtrl->timeout;
I2C_DBG (I2C_DBG_RW, "vxbFtI2cPoll timeout tick is %llu\n", timeout,2,3,4,5,6);
while (timeout-- > 0)
{
status = CSR_READ_4 (pDrvCtrl, I2C_RAW_INTR_STAT);
status &= pDrvCtrl->pollIrqMask;
if (I2C_IRQ_TX_ABRT == (status & I2C_IRQ_TX_ABRT))
{
pDrvCtrl->errorStatus = I2C_ERR_STATUS_TX_ABRT;
I2C_DBG (I2C_DBG_IRQ, "I2C_IRQ_TX_ABRT Source 0x%x \n",
CSR_READ_4 (pDrvCtrl, I2C_TX_ABRT_SOURCE),2,3,4,5,6);
return ERROR;
}
if (I2C_IRQ_RX_UNDER == (status & I2C_IRQ_RX_UNDER))
{
pDrvCtrl->errorStatus = I2C_ERR_STATUS_RX_UNDER;
return ERROR;
}
if (I2C_IRQ_RX_OVER == (status & I2C_IRQ_RX_OVER))
{
pDrvCtrl->errorStatus = I2C_ERR_STATUS_RX_OVER;
return ERROR;
}
if (I2C_IRQ_STOP_DET == (status & I2C_IRQ_STOP_DET))
{
return OK;
}
/* Reading process */
if (I2C_IRQ_RX_FULL == (status & I2C_IRQ_RX_FULL))
{
vxbFtI2cReadProcess (pDrvCtrl);
}
/* Writing process */
if (I2C_IRQ_TX_EMPTY == (status & I2C_IRQ_TX_EMPTY))
{
vxbFtI2cWriteProcess (pDrvCtrl);
}
vxbUsDelay (1);
}
/* time out */
I2C_DBG (I2C_DBG_RW, "time out\n",1,2,3,4,5,6);
return ERROR;
}
/*******************************************************************************
*
* vxbFtI2cWaitBusFree - wait for I2C bus free
*
* This function waits for I2C bus free
*
* RETURNS: OK, or ERROR if timeout.
*
* ERRNO: N/A
*/
LOCAL STATUS vxbFtI2cWaitBusFree
(
I2C_DRV_CTRL * pDrvCtrl
)
{
#ifdef I2C_DBG_ON
UINT32 status;
#endif /* I2C_DBG_ON */
UINT32 timeout = 0;
/* Wait until Activity Status Bit in I2C_STATUS is IDLE = 0 */
#ifdef I2C_DBG_ON
while (((status =
CSR_READ_4 (pDrvCtrl, I2C_STATUS)) & I2C_STATUS_ACTIVITY) &&
#else
while ((CSR_READ_4 (pDrvCtrl, I2C_STATUS) & I2C_STATUS_ACTIVITY) &&
#endif /* I2C_DBG_ON */
(++timeout < I2C_TIMEOUT))
vxbUsDelay (I2C_DELAY);
if (timeout == I2C_TIMEOUT)
{
I2C_DBG (I2C_DBG_ERR,
"vxbFtI2cWaitBusFree:timeout status 0x%x\n", status,2,3,4,5,6);
return (ERROR);
}
return (OK);
}
/*******************************************************************************
*
* vxbFtI2cReadProcess - read process
*
* This function is the read process of I2C controller.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
LOCAL void vxbFtI2cReadProcess
(
I2C_DRV_CTRL * pDrvCtrl
)
{
I2C_MSG * pMsg;
UINT8 * buf;
UINT32 bufLen = 0;
UINT32 rxfifoAvLen;
for (; pDrvCtrl->msgsRxIdx < pDrvCtrl->num; pDrvCtrl->msgsRxIdx++)
{
pMsg = &pDrvCtrl->msgs[pDrvCtrl->msgsRxIdx];
if (pDrvCtrl->errorStatus != OK)
{
I2C_DBG (I2C_DBG_IRQ, "vxbFtI2cReadProcess errorStatus detected\n",1,2,3,4,5,6);
return;
}
/* if this msg is not I2C_M_RD, continue next msg */
if (0 == (pMsg->flags & I2C_M_RD))
{
continue;
}
if (pDrvCtrl->msgRxLen == 0)
{
bufLen = pMsg->len;
buf = pMsg->buf;
}
else
{
bufLen = pDrvCtrl->msgRxLen;
buf = pDrvCtrl->msgRxBuf;
}
rxfifoAvLen = CSR_READ_4 (pDrvCtrl, I2C_RXFLR);
I2C_DBG (I2C_DBG_IRQ, "vxbFtI2cReadProcess msgs[%d] recv len %d\n",
pDrvCtrl->msgsRxIdx, rxfifoAvLen,3,4,5,6);
for (; ((bufLen > 0) && (rxfifoAvLen > 0)); bufLen--, rxfifoAvLen--)
{
*buf++ = CSR_READ_4 (pDrvCtrl, I2C_DATA_CMD) & 0xff;
if (pDrvCtrl->fifoRdLvl > 0)
{
pDrvCtrl->fifoRdLvl--;
}
}
pDrvCtrl->msgRxLen = bufLen;
pDrvCtrl->msgRxBuf = buf;
I2C_DBG (I2C_DBG_IRQ, "vxbFtI2cReadProcess bufLen %d rxfifoAvLen %d\n",
bufLen,
rxfifoAvLen,3,4,5,6);
if (bufLen > 0)
{
break;
}
}
if (!pDrvCtrl->polling)
{
if ((pDrvCtrl->msgsRxIdx == pDrvCtrl->num) && (bufLen == 0))
{
SPIN_LOCK_ISR_TAKE (&pDrvCtrl->lock);
/* after read all the msgs, disable rx full interrupt */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) &
(UINT32) ~I2C_IRQ_RX_FULL);
if (0 != (pDrvCtrl->msgs[pDrvCtrl->msgsRxIdx-1].flags & I2C_M_RD))
{
/* If the last msg is I2C_M_RD, enable stop interrupt. */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) |
I2C_IRQ_STOP_DET);
}
SPIN_LOCK_ISR_GIVE (&pDrvCtrl->lock);
}
else
{
/* If it is not the last msg, enable rx full interrupt again. */
SPIN_LOCK_ISR_TAKE (&pDrvCtrl->lock);
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) |
I2C_IRQ_RX_FULL);
SPIN_LOCK_ISR_GIVE (&pDrvCtrl->lock);
}
}
else
{
/*
* In polling mode, only need set stop mask if it is the
* last msg and the last msg is I2C_M_RD.
*/
if (((pDrvCtrl->msgsRxIdx == pDrvCtrl->num) && (bufLen == 0)) &&
(0 != (pDrvCtrl->msgs[pDrvCtrl->msgsRxIdx-1].flags & I2C_M_RD)))
{
pDrvCtrl->pollIrqMask = (pDrvCtrl->pollIrqMask &
(UINT32) ~I2C_IRQ_RX_FULL) |
I2C_IRQ_STOP_DET;
}
}
}
/*******************************************************************************
*
* vxbFtI2cWriteProcess - write process
*
* This function is the write process of I2C controller. Both datas which will
* be transmited or received should be processed in this function.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
LOCAL void vxbFtI2cWriteProcess
(
I2C_DRV_CTRL * pDrvCtrl
)
{
UINT8 * buf;
UINT32 bufLen;
UINT32 txFifoAvLen;
UINT32 rxFifoAvLen;
UINT32 cmd = 0;
UINT32 readLen = 0;
I2C_MSG * pMsg;
BOOL isRead;
BOOL restartSign = FALSE;
for (; pDrvCtrl->msgsTxIdx < pDrvCtrl->num; pDrvCtrl->msgsTxIdx++)
{
pMsg = &pDrvCtrl->msgs[pDrvCtrl->msgsTxIdx];
readLen = 0;
if (pDrvCtrl->errorStatus != OK)
{
I2C_DBG (I2C_DBG_IRQ, "vxbFtI2cWriteProcess errorStatus detected\n",1,2,3,4,5,6);
return;
}
if (0 == (pMsg->flags & I2C_M_RD))
{
isRead = FALSE;
}
else
{
isRead = TRUE;
}
if (pDrvCtrl->msgTxLen == 0)
{
bufLen = pMsg->len;
buf = pMsg->buf;
if (pDrvCtrl->msgsTxIdx > 0)
restartSign = TRUE;
}
else
{
bufLen = pDrvCtrl->msgTxLen;
buf = pDrvCtrl->msgTxBuf;
}
txFifoAvLen = pDrvCtrl->txFifoSize - CSR_READ_4 (pDrvCtrl, I2C_TXFLR);
rxFifoAvLen = pDrvCtrl->rxFifoSize - CSR_READ_4 (pDrvCtrl, I2C_RXFLR);
I2C_DBG (I2C_DBG_IRQ,
"vxbFtI2cWriteProcess msgs[%d] send %s len %d txavl %d rxavl %d\n",
pDrvCtrl->msgsTxIdx,
(isRead) ? "read" : "write",
bufLen,
txFifoAvLen,
rxFifoAvLen,6);
for (;
((bufLen > 0) && (txFifoAvLen > 0) &&
((pDrvCtrl->rxFifoSize - CSR_READ_4 (pDrvCtrl, I2C_RXFLR)) > 0));
bufLen--, txFifoAvLen--, rxFifoAvLen--
)
{
cmd = 0;
if (restartSign)
{
/* need set restart at the first data of new msg */
cmd |= I2C_DATA_CMD_RESTART;
restartSign = FALSE;
I2C_DBG (I2C_DBG_IRQ, "restart\n",1,2,3,4,5,6);
}
if ((pDrvCtrl->msgsTxIdx == (pDrvCtrl->num - 1)) &&
(bufLen == 1))
{
/* need set stop at the last data of the last msg */
cmd |= I2C_DATA_CMD_STOP;
I2C_DBG (I2C_DBG_IRQ, "stop\n",1,2,3,4,5,6);
}
if (FALSE == isRead)
{
CSR_WRITE_4 (pDrvCtrl, I2C_DATA_CMD,
*buf | cmd | I2C_DATA_CMD_WR);
buf++;
}
else
{
if (pDrvCtrl->fifoRdLvl >= pDrvCtrl->rxFifoSize)
{
break;
}
pDrvCtrl->fifoRdLvl++;
CSR_WRITE_4 (pDrvCtrl, I2C_DATA_CMD, cmd | I2C_DATA_CMD_RD);
readLen++;
}
}
/*
* If write read decriptor, set RX_TL according to real write number,
* this can reduce rx full interrupt number.
*/
if (isRead)
{
if (readLen > 0)
{
CSR_WRITE_4 (pDrvCtrl, I2C_RX_TL, readLen - 1);
}
else
{
CSR_WRITE_4 (pDrvCtrl, I2C_RX_TL, 0);
}
}
pDrvCtrl->msgTxLen = bufLen;
pDrvCtrl->msgTxBuf = buf;
I2C_DBG (I2C_DBG_IRQ,
"vxbFtI2cWriteProcess bufLen %d txFifoAvLen %d rxFifoAvLen %d\n",
bufLen,
txFifoAvLen,
rxFifoAvLen,4,5,6);
if (bufLen > 0)
{
break;
}
}
if (!pDrvCtrl->polling)
{
if ((pDrvCtrl->msgsTxIdx == pDrvCtrl->num) && (bufLen == 0))
{
/*
* After write all the rx descriptors, set I2C_RX_TL to zero
* to ensure receive all the left rx packets.
*/
CSR_WRITE_4 (pDrvCtrl, I2C_RX_TL, 0);
SPIN_LOCK_ISR_TAKE (&pDrvCtrl->lock);
/* after write all the msgs, disable tx empty interrupt */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) &
(UINT32) ~I2C_IRQ_TX_EMPTY);
if (0 == (pDrvCtrl->msgs[pDrvCtrl->msgsTxIdx - 1].flags & I2C_M_RD))
{
/* If the last msg is I2C_M_WR, enable stop interrupt. */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) |
I2C_IRQ_STOP_DET);
}
SPIN_LOCK_ISR_GIVE (&pDrvCtrl->lock);
}
else
{
/* If it is not the last msg, enable tx empty interrupt again. */
SPIN_LOCK_ISR_TAKE (&pDrvCtrl->lock);
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK,
CSR_READ_4 (pDrvCtrl, I2C_INTR_MASK) |
I2C_IRQ_TX_EMPTY);
SPIN_LOCK_ISR_GIVE (&pDrvCtrl->lock);
}
}
else
{
/*
* In polling mode, only need to set stop mask if it is the
* last msg and the last msg is I2C_M_WR, also set I2C_RX_TL zero
* to ensure receive all the left rx packets.
*/
if ((pDrvCtrl->msgsTxIdx == pDrvCtrl->num) && (bufLen == 0))
{
CSR_WRITE_4 (pDrvCtrl, I2C_RX_TL, 0);
if (0 == (pDrvCtrl->msgs[pDrvCtrl->msgsTxIdx-1].flags & I2C_M_RD))
pDrvCtrl->pollIrqMask = (pDrvCtrl->pollIrqMask &
(UINT32) ~I2C_IRQ_TX_EMPTY) |
I2C_IRQ_STOP_DET;
}
}
}
/*******************************************************************************
*
* vxbFtI2cMasterInit - initialize the I2C master module
*
* This function initializes the I2C master module, control data and sets some
* initial values.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
LOCAL void vxbFtI2cMasterInit
(
I2C_DRV_CTRL * pDrvCtrl,
I2C_MSG * msgs,
int num
)
{
UINT32 i;
UINT32 len = 0;
UINT64 timeout;
/* disable I2C Controller */
CSR_WRITE_4 (pDrvCtrl, I2C_ENABLE, 0x0);
/* set target address */
if (msgs->flags & I2C_M_TEN)
CSR_WRITE_4 (pDrvCtrl, I2C_TAR, msgs->addr | I2C_TAR_ADR_10BIT);
else
CSR_WRITE_4 (pDrvCtrl, I2C_TAR, msgs->addr);
/* it's the combined transfer, set restart enable */
CSR_WRITE_4 (pDrvCtrl, I2C_CON,
CSR_READ_4 (pDrvCtrl, I2C_CON) | I2C_CON_RESTART_EN);
/* disable interrupt */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK, I2C_IRQ_NONE);
/* set interrupt trigger level */
CSR_WRITE_4 (pDrvCtrl, I2C_TX_TL, pDrvCtrl->txFifoSize/2);
CSR_WRITE_4 (pDrvCtrl, I2C_RX_TL, 0);
/* enable I2C Controller */
CSR_WRITE_4 (pDrvCtrl, I2C_ENABLE, 0x1);
/* init tranfer control data */
pDrvCtrl->msgs = msgs;
pDrvCtrl->num = (UINT32) num;
pDrvCtrl->msgsRxIdx = 0;
pDrvCtrl->msgRxLen = 0;
pDrvCtrl->msgRxBuf = NULL;
pDrvCtrl->fifoRdLvl = 0;
pDrvCtrl->msgsTxIdx = 0;
pDrvCtrl->msgTxLen = 0;
pDrvCtrl->msgTxBuf = NULL;
pDrvCtrl->errorStatus = OK;
/* calculate total wait time */
for (i = 0; i < (UINT32) num; i++)
{
len += msgs[i].len;
I2C_DBG (I2C_DBG_RW, "msg [%d]\n", i,2,3,4,5,6);
}
pDrvCtrl->totalLen = len;
timeout = (UINT64) I2C_S_TO_US * (I2C_BYTE_LEN + I2C_BYTE_EXTRA) * len;
timeout /= pDrvCtrl->busSpeed;
pDrvCtrl->timeout = timeout;
I2C_DBG (I2C_DBG_RW,
"vxbFtI2cMasterInit: byte lenght %d, timeout is %llu (us)\n",
len, timeout,3,4,5,6);
}
/*******************************************************************************
*
* vxbFtI2cTransfer - VxBus I2C device generic write support function
*
* This function receive msg from upper layer and perform I2C transfer.
*
* RETURNS: OK, or ERROR if failed.
*
* ERRNO: N/A
*/
LOCAL STATUS vxbFtI2cTransfer
(
VXB_DEVICE_ID pDev,
I2C_MSG * msgs,
int num
)
{
int clkRate;
_Vx_ticks_t timeout;
I2C_DRV_CTRL * pDrvCtrl;
VXB_ASSERT (pDevice != NULL, ERROR)
pDrvCtrl = pDev->pDrvCtrl;
if (pDev == NULL || msgs == NULL || num == 0)
return ERROR;
if (pDrvCtrl == NULL)
{
return ERROR;
}
if (msgs->scl == 0)
{
msgs->scl = pDrvCtrl->defBusSpeed;
}
if (msgs->scl != pDrvCtrl->busSpeed)
{
pDrvCtrl->busSpeed = msgs->scl;
vxbFtI2cInit (pDev);
}
(void) semTake (pDrvCtrl->i2cDevSem, WAIT_FOREVER);
/* lock the I2C controller */
if (vxbFtI2cWaitBusFree (pDrvCtrl) == ERROR)
{
I2C_DBG (I2C_DBG_ERR, "vxbFtI2cTransfer: WaitBusFree error\n",1,2,3,4,5,6);
goto xfailed;
}
vxbFtI2cMasterInit (pDrvCtrl, msgs, num);
if (!pDrvCtrl->polling)
{
clkRate = vxbSysClkRateGet ();
timeout = (_Vx_ticks_t) (pDrvCtrl->timeout * (UINT64) clkRate) /
I2C_S_TO_US;
timeout += I2C_TOTAL_EXTRA_TICK (pDrvCtrl->totalLen);
/* I2C_IRQ_STOP_DET will be enabled after last byte */
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK, (I2C_IRQ_DEFAULT_MASK &
~I2C_IRQ_STOP_DET));
if (semTake (pDrvCtrl->i2cDataSem, timeout) == ERROR)
{
I2C_DBG (I2C_DBG_ERR, "vxbFtI2cTransfer: semTake error\n",1,2,3,4,5,6);
goto xfailed;
}
}
else
{
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK, I2C_IRQ_NONE);
if (OK != vxbFtI2cPoll (pDrvCtrl))
goto xfailed;
}
if (vxbFtI2cWaitBusFree (pDrvCtrl) == ERROR)
{
I2C_DBG (I2C_DBG_ERR, "vxbFtI2cTransfer: WaitBusFree error\n",1,2,3,4,5,6);
goto xfailed;
}
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK, I2C_IRQ_NONE);
if (pDrvCtrl->errorStatus != OK)
{
I2C_DBG (I2C_DBG_ERR, "errorStatus == %d\n", pDrvCtrl->errorStatus,2,3,4,5,6);
goto xfailed;
}
(void) semGive (pDrvCtrl->i2cDevSem);
return OK;
xfailed:
I2C_DBG (I2C_DBG_ERR, "transfer failed \n",1,2,3,4,5,6);
CSR_WRITE_4 (pDrvCtrl, I2C_INTR_MASK, I2C_IRQ_NONE);
vxbFtI2cInit (pDev);
(void) semGive (pDrvCtrl->i2cDevSem);
return ERROR;
}
/*******************************************************************************
*
* vxbFtI2cRead - issue the command to read bytes from a device
*
* This function reads <length> bytes from the I2C device and stores them
* in the buffer specified by <pDataBuf>. The read starts at an offset
* specified previously in the transaction. If too many bytes are requested,
* the read will return ERROR, though any successfully read bytes will be
* returned in <pDataBuf>.
*
* RETURNS: OK if read completed successfully, otherwise ERROR.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
STATUS vxbFtI2cRead
(
VXB_DEVICE_ID pDevice,
UINT8 devAddr,
UINT32 startAddr,
UINT8 * pDataBuf,
UINT32 length
)
{
I2C_HARDWARE * pI2cDev;
VXB_DEVICE_ID pDev;
I2C_DRV_CTRL * pDrvCtrl;
I2C_MSG msg[2];
UINT8 msgbuf[2];
int i;
I2C_DBG (I2C_DBG_RW, "vxbFtI2cRead\n", 1, 2, 3, 4, 5, 6);
if ((pDevice == NULL) || (length == 0) || (pDataBuf == NULL))
{
return ERROR;
}
pI2cDev = (I2C_HARDWARE *) pDevice->pBusSpecificDevInfo;
if ((pI2cDev == NULL) || (pI2cDev->pCtlr == NULL) ||
(pI2cDev->pCtlr->pDrvCtrl == NULL))
{
return ERROR;
}
pDev = pI2cDev->pCtlr;
pDrvCtrl = (I2C_DRV_CTRL *)pDev->pDrvCtrl;
memset (msg, 0, sizeof(I2C_MSG) * 2);
memset (msgbuf, 0, sizeof(msgbuf));
i = 0;
if ((pI2cDev->flag & I2C_WORDADDR) != 0)
{
msgbuf[i++] = (UINT8)(startAddr >> 8);
}
msgbuf[i++] = (UINT8)startAddr;
/* write start address */
msg[0].addr = devAddr;
msg[0].scl = pDrvCtrl->busSpeed;
msg[0].buf = msgbuf;
msg[0].len = i;
/* read data */
msg[1].addr = devAddr;
msg[1].scl = pDrvCtrl->busSpeed;
msg[1].flags = I2C_M_RD;
msg[1].buf = pDataBuf;
msg[1].len = length;
return vxbFtI2cTransfer (pDev, msg, 2);
}
/*******************************************************************************
*
* vxbFtI2cWrite - write a sequence of bytes to a device
*
* This function writes <length> bytes from the I2C device read from the
* buffer specified by <pDataBuf>. The write starts at an offset specified
* previously in the transaction. If too many bytes are requested, the write
* will return ERROR.
*
* RETURNS: OK if write completed successfully, otherwise ERROR.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
STATUS vxbFtI2cWrite
(
VXB_DEVICE_ID pDevice,
UINT8 devAddr,
UINT32 startAddr,
UINT8 * pDataBuf,
UINT32 length
)
{
I2C_HARDWARE * pI2cDev;
VXB_DEVICE_ID pDev;
I2C_DRV_CTRL * pDrvCtrl;
I2C_MSG msg;
UINT8 * msgbuf;
int i;
STATUS stat;
I2C_DBG (I2C_DBG_RW, "vxbFtI2cWrite\n", 1, 2, 3, 4, 5, 6);
/* length == 0 is OK for I2C switch which only writes info in startAddr */
if (pDevice == NULL)
{
return ERROR;
}
pI2cDev = (I2C_HARDWARE *) pDevice->pBusSpecificDevInfo;
if ((pI2cDev == NULL) || (pI2cDev->pCtlr == NULL) ||
(pI2cDev->pCtlr->pDrvCtrl == NULL) ||
((pI2cDev->flag & I2C_RDONLY) != 0))
{
return ERROR;
}
msgbuf = malloc (length + 2);
if (msgbuf == NULL)
{
return ERROR;
}
pDev = pI2cDev->pCtlr;
pDrvCtrl = (I2C_DRV_CTRL *)pDev->pDrvCtrl;
memset (&msg, 0, sizeof(I2C_MSG));
i = 0;
if ((pI2cDev->flag & I2C_WORDADDR) != 0)
{
msgbuf[i++] = (UINT8)(startAddr >> 8);
}
msgbuf[i++] = (UINT8)startAddr;
msg.addr = devAddr;
msg.scl = pDrvCtrl->busSpeed;
msg.buf = msgbuf;
msg.len = i + length;
if ((length != 0) && (pDataBuf != NULL))
{
memcpy (&msgbuf[i], pDataBuf, length);
}
stat = vxbFtI2cTransfer (pDev, &msg, 1);
free (msgbuf);
return stat;
}
#define I2C_DBG_ON
#ifdef I2C_DBG_ON
/*******************************************************************************
*
* vxbFtI2cDbgShow - show I2C transfer control data
*
* This function shows I2C transfer control data.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* \NOMANUAL
*/
void vxbFtI2cDbgShow
(
VXB_DEVICE_ID pDev
)
{
I2C_DRV_CTRL * pDrvCtrl = pDev->pDrvCtrl;
if (pDrvCtrl == NULL)
{
return;
}
printf ("pDrvCtrl->msgs 0x%x\n", pDrvCtrl->msgs );
printf ("pDrvCtrl->num %d\n", pDrvCtrl->num );
printf ("pDrvCtrl->msgsRxIdx %d\n", pDrvCtrl->msgsRxIdx );
printf ("pDrvCtrl->msgRxLen %d\n", pDrvCtrl->msgRxLen );
printf ("pDrvCtrl->msgRxBuf 0x%x\n", pDrvCtrl->msgRxBuf );
printf ("pDrvCtrl->fifoRdLvl %d\n", pDrvCtrl->fifoRdLvl );
printf ("pDrvCtrl->msgsTxIdx %d\n", pDrvCtrl->msgsTxIdx );
printf ("pDrvCtrl->msgTxLen %d\n", pDrvCtrl->msgTxLen );
printf ("pDrvCtrl->msgTxBuf 0x%x\n", pDrvCtrl->msgTxBuf );
printf ("pDrvCtrl->errorStatus %d\n", pDrvCtrl->errorStatus );
}
#endif /* I2C_DBG_ON */
/*****************************************************************************
*
* vxbFtI2cShow - show the valid device address on the bus
*
* This function scans the device address from 0 to 0x7f
* (only 7 bit address supported) on each I2C bus,
* if we can receipt the ACK signal from the device, means this address is valid
* and have the device connect to the BUS. If no ACK received, go on to the next
* address.
*
* RETURNS: OK if write completed successfully, otherwise ERROR
*
* ERRNO: N/A
*
* \NOMANUAL
*
*/
STATUS vxbFtI2cShow
(
VXB_DEVICE_ID pDev,
int verbose
)
{
I2C_DRV_CTRL * pDrvCtrl;
VXB_ASSERT (pDev != NULL, ERROR)
pDrvCtrl = pDev->pDrvCtrl;
printf (" %s unit %d on %s @ 0x%08x",
pDev->pName,
pDev->unitNumber,
vxbBusTypeString (pDev->busID),
pDev);
printf (" with busInfo %p\n", pDev->u.pSubordinateBus);
if (verbose >= 1)
{
printf (" BAR0 @ 0x%08x (memory mapped)\n",
pDev->pRegBase[0]);
printf (" pDrvCtrl @ 0x%08x\n", pDev->pDrvCtrl);
}
if (verbose > 1000)
{
printf(" clkFrequency: %dMhz\n", pDrvCtrl->clkFrequency/1000000);
printf(" busSpeed : %dKbps\n",pDrvCtrl->busSpeed/1000);
printf(" interrupt : %s\n",pDrvCtrl->polling?"FALSE":"TRUE");
printf("\n");
}
return OK;
}