/* 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 bytes from the I2C device and stores them * in the buffer specified by . 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 . * * 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 bytes from the I2C device read from the * buffer specified by . 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; }