i2cloader.c

来自「This driver supports both master mode, s」· C语言 代码 · 共 1,758 行 · 第 1/5 页

C
1,758
字号
******************************************************************************/

ST_ErrorCode_t STI2C_Open(    const ST_DeviceName_t      Name,
                              const STI2C_OpenParams_t   *OpenParams,
                              STI2C_Handle_t             *Handle)
{
    i2c_param_block_s    *ListPtr    = NULL;
    BOOL                 Match       = FALSE;
    i2c_open_block_s     *OpenPtr    = NULL;
    clock_t              Time;

    if (OpenParams->AddressType != STI2C_ADDRESS_7_BITS)
        return ST_ERROR_BAD_PARAMETER;

    /* Check for init()ed devices */
    if ( g_CtrlHead == NULL )
        return ST_ERROR_UNKNOWN_DEVICE;

    /* Walk the list of Ctrl blocks until we find the right name */
    ListPtr = g_CtrlHead;
    do
    {
        if ( strcmp( ListPtr->Name, Name ) == 0 )
            Match = TRUE;
        else
            ListPtr = (i2c_param_block_s*)(ListPtr->Next);
    }
    while ( (ListPtr != NULL) && (Match == FALSE) );

    /* If no match was found, this device name has not been init'ed */
    if ( ListPtr == NULL )
        return ST_ERROR_UNKNOWN_DEVICE;

    /* Check OpenCnt is less than MaxHandles */
    if ( ListPtr->OpenCnt >= ListPtr->MaxHandles )
        return ST_ERROR_NO_FREE_HANDLES;

    /* Generate a new handle and wait 1 tick to ensure handle uniqueness */
    Time = clock();
    task_delay (1);

    /* Assign the open block */
    OpenPtr = AssignI2cOpenBlock();
    if ( OpenPtr == NULL )
        return ST_ERROR_NO_FREE_HANDLES;    /* Should never get this! */

    /* Everything checked & OK - so get exclusive access to driver data,
       then copy in parameters. */
    semaphore_wait ( &ListPtr->BusAccessSemaphore );

    /* Change the open count in the control block */
    ListPtr->OpenCnt++;

    /* Store the open parameters */
    /* Bottom bit is R/W bit - remove for now */
    OpenPtr->I2cAddress        = OpenParams->I2cAddress & 0xFFFE;
    OpenPtr->Handle            = (STI2C_Handle_t)Time;
    OpenPtr->InUse             = TRUE;
    OpenPtr->AddressType       = OpenParams->AddressType;
    OpenPtr->BusAccessTimeOut  = OpenParams->BusAccessTimeOut;
    OpenPtr->CtrlBlkPtr        = (void*)ListPtr;

    /* Set the handle pointer for the calling function */
    *Handle = OpenPtr->Handle;

    /* Release the access semaphore */
    semaphore_signal( &ListPtr->BusAccessSemaphore ); 

    return ST_NO_ERROR;
}



/******************************************************************************
Name        : ResolveHandleToOpenPointer
Description : Walk the linked list until the open block with this handle is 
              found and return a pointer to it, else return a null pointer.
Parameters  : The handle of the open device to be found
******************************************************************************/

static i2c_open_block_s *ResolveHandleToOpenPointer( STI2C_Handle_t Handle )
{
   i2c_open_block_s  *ListPtr    = g_OpenHead;     
   BOOL              Match       = FALSE;

   while ( (ListPtr != NULL) && (Match == FALSE) )
   {
      if ( (Handle == ListPtr->Handle) && (ListPtr->InUse == TRUE) )     
      {
         Match = TRUE;
      }
      else
      {
         ListPtr = (i2c_open_block_s*)(ListPtr->Next);
      }      
   }
   return( ListPtr ); 
}


/******************************************************************************
Name        : ConvertMStoTicks
Description : Converts a timeout in milliseconds to the appropiate number of 
              clock ticks. Returns a pointer to the result. Takes care of
              special case 'infinity'. Also takes care of overflow by treating
              as infinity.

Parameters  : 1) The number of milliseconds to convert to ticks
              2) The number of clock ticks per second
              3) Pointer to result (not used if returns infinity)

Returns     : Pointer to result. This will either be pResult or
              TIMEOUT_INFINITY.
******************************************************************************/

static clock_t * ConvertMStoTicks (U32 TimeOutMS, U32 TicksPerSec,
                                   clock_t *pResult)
{
    int      Div = 0;
    clock_t  Timeout;

    /* Deal with Infinity as special case */
    if (TimeOutMS == STI2C_TIMEOUT_INFINITY)
        return (clock_t *)(TIMEOUT_INFINITY);

    /* Make sure the conversion will not overflow */
    while (TimeOutMS > INT_MAX/TicksPerSec)
    {
        Div++;
        TimeOutMS /= 10;
    }

    /* Convert from ms to clock ticks, with rounding */
    Timeout = (TimeOutMS * TicksPerSec + 500) / 1000;

    /* Now multiply up again, but if overflow giving infinity */
    while (Div > 0)
    {
        if (Timeout > INT_MAX/10)
            return (clock_t *)(TIMEOUT_INFINITY);
        Div--;
        Timeout *= 10;
    }

    *pResult = Timeout;
    return pResult;
}


/******************************************************************************
Name        : TakeBus
Description : Take control of the I2C bus. Only the 
              handle with control of the bus may call BusAccess
Parameters  : 1) Handle - open connection to STI2C
              2) *AlreadyLocked - Returns TRUE if this handle already
                 has control of the bus.
Returns     : ST_NO_ERROR - This handle now has control of the bus
              ST_ERROR_INVALID_HANDLE - Self explanatory
              ST_ERROR_DEVICE_BUSY - BusAccessTimeout expired
******************************************************************************/

static ST_ErrorCode_t TakeBus( STI2C_Handle_t Handle, BOOL *AlreadyLocked )
{
    const U32           TicksPerSec = ST_GetClocksPerSecond();
    U32                 SemReturn;
    clock_t             BusTimeOut;
    clock_t             *pBusTimeOut;
    i2c_param_block_s   *CtrlBlkPtr;
    i2c_open_block_s    *OpenBlkPtr;
    BOOL                LocalAlreadyLocked;
    ST_ErrorCode_t      ErrorCode = ST_NO_ERROR;

    /* Default return value for already locked flag */
    LocalAlreadyLocked = FALSE;

    /* Set up the pointers to the control block and the open block */
    OpenBlkPtr = ResolveHandleToOpenPointer (Handle);
    if ( OpenBlkPtr == NULL )
    {
        *AlreadyLocked = LocalAlreadyLocked;
        return ST_ERROR_INVALID_HANDLE;
    }

    CtrlBlkPtr = OpenBlkPtr->CtrlBlkPtr;

    /* Set bus access timeout */
    pBusTimeOut = ConvertMStoTicks( OpenBlkPtr->BusAccessTimeOut, 
                                        TicksPerSec, &BusTimeOut );
    if (pBusTimeOut != TIMEOUT_INFINITY)
        *pBusTimeOut = time_plus (*pBusTimeOut, time_now());


    /* Test if I2C bus has already been locked */
    SemReturn = semaphore_wait_timeout( &(CtrlBlkPtr->HandleAccessSemaphore), 
                                        TIMEOUT_IMMEDIATE );
    if( SemReturn == 0 )
    {
        /* SUCCESS: I2C bus is now locked to this handle */

        CtrlBlkPtr->LockedHandle = Handle;

	/* Check bus access has not been claimed already */
        SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->BusAccessSemaphore),
                                             pBusTimeOut );
        if( SemReturn != 0 )
	{
	    /* Failed to claim bus access */
            ErrorCode = ST_ERROR_DEVICE_BUSY;
	}
    }
    else
    {
        /* FAILURE: Bus is already locked  */

        /* Test if this handle has the bus locked */
        if( CtrlBlkPtr->LockedHandle == Handle )
	{ 
	    /* SUCCESS: This handle already has the bus locked */

	    /* Check bus access has not been claimed already */
            SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->BusAccessSemaphore),
                                                 pBusTimeOut );
            if (SemReturn != 0)
	    {
                /* Failed to claim bus access */
                ErrorCode =  ST_ERROR_DEVICE_BUSY;
	    }
            else
	    {
                LocalAlreadyLocked = TRUE;
	    }
	}
        else
	{
	    /* FAILURE: The bus is currently locked by another handle */

	    /* Wait for the bus to become unlocked */
            SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->HandleAccessSemaphore),
                                                 pBusTimeOut );
            if (SemReturn != 0)
	    {
                /* Failed to claim bus lock */
                ErrorCode = ST_ERROR_DEVICE_BUSY; 
	    }
            else
	    {
	        /* SUCCESS: Bus is now locked to this handle */

                CtrlBlkPtr->LockedHandle = Handle;

                /* Check bus access has not been claimed already */
                SemReturn = semaphore_wait_timeout ( &(CtrlBlkPtr->BusAccessSemaphore),
                                                     pBusTimeOut );
                if (SemReturn != 0)
		{
                    /* Failed to claim bus access */
                    ErrorCode = ST_ERROR_DEVICE_BUSY; 
                }
	    }
	}
    }

    *AlreadyLocked = LocalAlreadyLocked;
    return( ErrorCode );
}


/******************************************************************************
Name        : ReleaseBus
Description : Releases control of the I2C bus.
Parameters  : 1) Handle - open connection to STI2C
Returns     : ST_NO_ERROR - This handle now has control of the bus
              ST_ERROR_INVALID_HANDLE - Self explanatory
******************************************************************************/

static ST_ErrorCode_t ReleaseBus( STI2C_Handle_t Handle )
{
    ST_ErrorCode_t      ErrorCode = ST_NO_ERROR;
    i2c_param_block_s   *CtrlBlkPtr;
    i2c_open_block_s    *OpenBlkPtr;

    /* Set up the pointers to the control block and the open block */
    OpenBlkPtr = ResolveHandleToOpenPointer (Handle);
    if ( OpenBlkPtr == NULL )
    {
        ErrorCode = ST_ERROR_INVALID_HANDLE;
    }
    else
    {
        CtrlBlkPtr = OpenBlkPtr->CtrlBlkPtr;

        /* Release the access semaphore */
        semaphore_signal( &CtrlBlkPtr->HandleAccessSemaphore );
    }

    return( ErrorCode );
}


/******************************************************************************
Name        : STI2C_Reset
Description : Resets the I2C h/w device associated with the given handle.
              Also sets the s/w state back to Idle. Does not reset the I2C bus.
              This is designed as a recovery aid when things go badly wrong.
              Note this function does not get exclusive access by claiming the
              bus access semaphore.

              Currently, this is a hidden function not visible in the API.

Parameters  : 1) The handle to a device being used
******************************************************************************/

ST_ErrorCode_t STI2C_Reset (STI2C_Handle_t Handle)
{
    DU16                *I2cRegPtr;
    i2c_param_block_s   *CtrlBlkPtr;
    i2c_open_block_s    *OpenBlkPtr =  ResolveHandleToOpenPointer (Handle);

    if ( OpenBlkPtr == NULL )
        return ST_ERROR_INVALID_HANDLE;

    CtrlBlkPtr = OpenBlkPtr->CtrlBlkPtr;
    I2cRegPtr  = (DU16*) CtrlBlkPtr->I2cBase;
    I2C_TRACE_LOCK(CtrlBlkPtr,0xD000,(U32)I2cRegPtr);
    CtrlBlkPtr->State = STI2C_IDLE;
    I2cRegPtr [SSC_INT_ENABLE] = 0;
    I2cRegPtr [SSC_CONTROL] = DEFAULT_CONTROL | SSC_CON_RESET;
    I2cRegPtr [SSC_CONTROL] = DEFAULT_CONTROL;

    /* Set Tx data high to avoid bus corruption */
    I2cRegPtr [SSC_TX_BUFFER]  = 0x1FF;
    I2cRegPtr [SSC_INT_ENABLE] = CtrlBlkPtr->InterruptMask = DEFAULT_ENABLES;
    return ST_NO_ERROR;
}


/******************************************************************************
Name        : BusAccess
Description : Initiates all master mode bus activity by reading or writing the
              first byte in a bus transfer. The ISR does the rest, signalling
              via a semaphore when the operation is complete or aborted.

              Caters for the possibility of the bus being in use by another
              master device (but see comments on h/w bugs in module header).
              If a transfer fails due to 'Bus In Use', the function will keep
              retrying until the bus access timeout expires. As a partial
              workaround the h/w bugs, the function will also retry after
              other errors up to a maximum of STI2C_MAX_RETRIES times.

Parameters  : 1) The handle

⌨️ 快捷键说明

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