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

📄 spi.c

📁 Windows CE 6.0 BSP for the Beagle Board.
💻 C
📖 第 1 页 / 共 2 页
字号:
    if (pInstance == NULL || pInstance->cookie != SPI_INSTANCE_COOKIE) {
        DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Transfer: "
            L"Incorrect context paramer\r\n"
        ));
        goto clean;
    }
    pDevice = pInstance->pDevice;
    pSPIRegs = pDevice->pSPIRegs;
    // Get hardware
    EnterCriticalSection(&pDevice->cs);
    
    // Set this driver to Active Mode
    SPI_ClockOn(pDevice);
    SetDevicePowerState(pDevice->hParentBus, pDevice->powerState = D0, NULL);
    switch (pInstance->address) {
    case 0:
        // Enable the channel
        SETREG32(&pSPIRegs->ulMCSPI_CH0CTRL, BIT0);

        OUTREG32(&pSPIRegs->ulMCSPI_TX0, *pData);
        // Wait for transfer to finish.
        dwCount = 0;
        while(!(INREG32(&pSPIRegs->ulMCSPI_CH0STATUS) & BIT2))
        {
            if (dwCount++>0x1ffff)
            {
                // Break out dead lock, something is wrong.
                ERRORMSG (1, (L"SPI_Transfer: SPI is not responding CHSTATUS = 0x%x\r\n",INREG32(&pSPIRegs->ulMCSPI_CH0STATUS)));
                goto clean;
            }
        }
        *pData = 0xFFFF & INREG32(&pSPIRegs->ulMCSPI_RX0);
        break;

    default:
        DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Transfer: Incorrect channel address\r\n"));
        goto clean;
    }
    rc = 1;

clean:
    // Disable the channel.
    CLRREG32(&pSPIRegs->ulMCSPI_CH0CTRL, BIT0);

    // Set this driver to Suspend Mode
    SPI_ClockOff(pDevice);
    SetDevicePowerState(pDevice->hParentBus, pDevice->powerState = D4, NULL);
    
    // Release hardware
    LeaveCriticalSection(&pDevice->cs);
//    DEBUGMSG(ZONE_FUNCTION, (L"-SPI_Transfer(rc = %d)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_IOControl
//
//  This function sends a command to a device.
//
BOOL SPI_IOControl(
    DWORD context, DWORD dwCode, BYTE *pInBuffer, DWORD inSize, BYTE *pOutBuffer,
    DWORD outSize, DWORD *pOutSize
) {
    BOOL bRetVal = FALSE;
    SPI_DEVICE *pDevice = NULL;
    SPI_INSTANCE *pInstance = (SPI_INSTANCE*)context;
    DEVICE_IFC_SPI ifc;

    DEBUGMSG(ZONE_FUNCTION, (
        L"+SPI_IOControl(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x)\r\n",
        context, dwCode, pInBuffer, inSize, pOutBuffer, outSize, pOutSize
    ));

    // Check if we get correct context
    if (pInstance == NULL || pInstance->cookie != SPI_INSTANCE_COOKIE) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_IOControl: "
            L"Incorrect context paramer\r\n"
        ));
        goto clean;
    }

    //Get Device
    pDevice = pInstance->pDevice;

    switch (dwCode) {
    case IOCTL_DDK_GET_DRIVER_IFC:
        // We can give interface only to our peer in device process
        if (GetCurrentProcessId() != (DWORD)GetCallerProcess()) {
            DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_IOControl: "
                L"IOCTL_DDK_GET_DRIVER_IFC can be called only from "
                L"device process (caller process id 0x%08x)\r\n",
                GetCallerProcess()
            ));
            SetLastError(ERROR_ACCESS_DENIED);
            goto clean;
        }
        // Check input parameters
        if (pInBuffer == NULL || inSize < sizeof(GUID)) {
            SetLastError(ERROR_INVALID_PARAMETER);
            break;
        }
        if (IsEqualGUID(pInBuffer, &DEVICE_IFC_SPI_GUID)) {
            if (pOutSize != NULL) *pOutSize = sizeof(DEVICE_IFC_SPI);
            if (pOutBuffer == NULL || outSize < sizeof(DEVICE_IFC_SPI)) {
                SetLastError(ERROR_INVALID_PARAMETER);
                break;
            }
            ifc.context = context;
            ifc.pfnSetSlaveAddress = SPI_SetSlaveAddress;
            ifc.pfnTransfer = SPI_Transfer;
            if (!CeSafeCopyMemory(pOutBuffer, &ifc, sizeof(DEVICE_IFC_SPI))) {
                SetLastError(ERROR_INVALID_PARAMETER);
                break;
            }
            bRetVal = TRUE;
            break;
        }
        SetLastError(ERROR_INVALID_PARAMETER);
        break;
    case IOCTL_SPI_SET_SLAVE_ADDRESS:
        if (pOutSize != NULL) *pOutSize = sizeof(DWORD);
        if (pInBuffer == NULL || inSize < sizeof(DWORD)) {
            SetLastError(ERROR_INVALID_PARAMETER);
            break;
        }
        bRetVal = SPI_SetSlaveAddress(context, (DWORD)*pInBuffer);
        break;


    // Power management functions.
    // Return device specific power capabilities.
    case IOCTL_POWER_CAPABILITIES:
    {
        POWER_CAPABILITIES pc;

        // Check arguments.
        if ( pOutBuffer == NULL || outSize < sizeof(POWER_CAPABILITIES))
        {
            ERRORMSG( TRUE, ( TEXT( "SPI: IOCTL_POWER_CAPABILITIES "
                L"Invalid parameter.\r\n" ) ) );
            break;
        }

        // Clear capabilities structure.
        memset(&pc, 0, sizeof(POWER_CAPABILITIES));

        // Set power capabilities. Supports D0 and D4.
        pc.DeviceDx = DX_MASK(D0)|DX_MASK(D4);

        DEBUGMSG(ZONE_POWER, (TEXT("SPI: IOCTL_POWER_CAPABILITIES = 0x%x\r\n"), pc.DeviceDx));

        if (CeSafeCopyMemory(pOutBuffer, &pc, sizeof(pc)) == 0)
        {
            ERRORMSG( TRUE, ( TEXT( "SPI: CeSafeCopyMemory Failed\r\n" ) ) );
            break;
        }

        // Update returned data size.
        if (pOutSize)
        {
            *pOutSize = sizeof(pc);
        }
        bRetVal = TRUE;
        break;
    }

    // Indicate if the device is ready to enter a new device power state.
    case IOCTL_POWER_QUERY:
    {
        DEBUGMSG(ZONE_POWER, (TEXT("SPI: IOCTL_POWER_QUERY"
            L"Deprecated Function Called\r\n")));
        bRetVal = FALSE;
        break;
    }

    // Request a change from one device power state to another
    // This driver self-manages it's internal power state by controlling
    // functional and interface clocks as needed in the Read and Write
    // functions rather than waiting for PM to tell it to save power
    // So the set calls below just update the power state variable
    case IOCTL_POWER_SET:
    {
        CEDEVICE_POWER_STATE dxState;

        // Check arguments.
        if (pOutBuffer == NULL || outSize < sizeof(CEDEVICE_POWER_STATE))
        {
            ERRORMSG( TRUE, ( TEXT( "SPI: IOCTL_POWER_SET"
                L"Invalid parameter.\r\n" ) ) );
            break;
        }

        if (CeSafeCopyMemory(&dxState, pOutBuffer, sizeof(dxState)) == 0) break;

        DEBUGMSG(ZONE_POWER, ( TEXT( "SPI: IOCTL_POWER_SET = %d.\r\n"), dxState));

        // Check for any valid power state.
        if (VALID_DX(dxState))
        {
            // Power off
            if ( dxState == D4 )
            {
                // Set this driver to low power mode external state
                pDevice->powerState = dxState;
            }
            // Power on.
            else
            {
                //Set to high power external state
                pDevice->powerState = dxState;
            }
            bRetVal = TRUE;
        }
        else
        {
            ERRORMSG( TRUE, ( TEXT( "SPI: IOCTL_POWER_SET "
                L"Invalid power state.\r\n" ) ) );
        }
        break;
    }

    // Return the current device power state.
    case IOCTL_POWER_GET:
    {
        // Check arguments.
        if (pOutBuffer == NULL || outSize < sizeof(CEDEVICE_POWER_STATE))
        {
            ERRORMSG( TRUE, ( TEXT( "SPI: IOCTL_POWER_GET "
                L"Invalid parameter.\r\n" ) ) );
            break;
        }

        //Copy current state
        if (CeSafeCopyMemory(pOutBuffer, &pDevice->powerState, sizeof(pDevice->powerState)) == 0)
        {
            ERRORMSG( TRUE, ( TEXT( "SPI: CeSafeCopyMemory Failed\r\n" ) ) );
            break;
        }

        // Update returned data size.
        if (pOutSize)
        {
            *pOutSize = sizeof(pDevice->powerState);
        }

        DEBUGMSG(ZONE_POWER, (TEXT("SPI: IOCTL_POWER_GET: %d\r\n"), pDevice->powerState));
        bRetVal = TRUE;
        break;
    }


    default:
        ERRORMSG(1, (TEXT("SPI: Unknown IOCTL_xxx(0x%0.8X) \r\n"), dwCode));
        break;
    }

clean:
    DEBUGMSG(ZONE_FUNCTION, (L"-SPI_IOControl(rc = %d)\r\n", bRetVal));
    return bRetVal;
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_PowerUp
//
//  This function restores power to a device.
//
VOID SPI_PowerUp(DWORD context)
{
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_PowerDown
//
//  This function suspends power to the device.
//
void SPI_PowerDown(DWORD context)
{
}

//------------------------------------------------------------------------------

BOOL SPI_SetSlaveAddress(DWORD context, DWORD address)
{
    BOOL rc = FALSE;
    SPI_INSTANCE *pInstance = (SPI_INSTANCE*)context;
    SPI_DEVICE *pDevice;

    DEBUGMSG(ZONE_FUNCTION, (L"SPI_SetSlaveAddress 0x%x\r\n", address));

    // Check if we get correct context
    if (pInstance == NULL || pInstance->cookie != SPI_INSTANCE_COOKIE) {
        DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_SetSlaveAddress: "
            L"Incorrect context paramer\r\n"
        ));
        goto cleanUp;
    }

    //Get Device
    pDevice = pInstance->pDevice;

    //Set Address
    pInstance->address = address;

    // Get hardware
    EnterCriticalSection(&pDevice->cs);
    
    // Set this driver to Active Mode
    SPI_ClockOn(pDevice);
    SetDevicePowerState(pDevice->hParentBus, pDevice->powerState = D0, NULL);

    //Set channel address
    SPI_SetupMCSPI_Channel(pInstance->pDevice->pSPIRegs, pInstance->address);

    // Set this driver to Suspend Mode
    SPI_ClockOff(pDevice);
    SetDevicePowerState(pDevice->hParentBus, pDevice->powerState = D4, NULL);
    
    // Release hardware
    LeaveCriticalSection(&pDevice->cs);    
    
    rc = TRUE;

cleanUp:
    return rc;
}



//SPI_SetupMCSPI_Channel ***Assumes we already hold the hardware critical section and clocks are enabled***
BOOL SPI_SetupMCSPI_Channel(OMAP3_MCSPI_REGS *pSPIRegs, DWORD address)
{
    BOOL rc = FALSE;
    //DEBUGMSG(ZONE_FUNCTION, (L"SPI_SetupMCSPI_Channel 0x%x\r\n", address));
    // Config the channel:
    if (address == 0)
    {
        //BIT0 = 0 Data are latched on odd numbered edges 
        //BIT1 = 1 Active Low Clock 
        //BIT5-2 = 6 Clock Divider =64 divide from 48MHz
        //BIT6 = 1 EPOL Active Low CS
        //BIT11-7 = F, SPI Word = 16 bit
        //BIT11-7 = 1F, SPI Word = 16 bit
        //BIT13-12 = 0, Transmit AND Receive mode
        //BIT14 = 0, DMA Write req disabled
        //BIT15 = 0, DMA Read req disabled
        //BIT16 = 1, transmission on SOMI disabled
        //BIT17 = 0, transmission on SIMO enabled
        //BIT18 = 0, reception on SOMI enabled
        //BIT19 = 0, TURBO deactivated
        //BIT20 = 0, FORCE HIGH between words
        //BIT21-31 = 0 reserved
        OUTREG32(&pSPIRegs->ulMCSPI_CH0CONF, 0x00010FDA);
    }
    else
    {
        goto cleanUp;
    }
    rc = TRUE;

cleanUp:
    return rc;
}



//  Turn on the clocks
VOID SPI_ClockOn(SPI_DEVICE *pDevice)
{
    DWORD regBit,cbRet;

    //Check if it's SPI1 or SPI2
    if(OMAP3_MCSPI1_REGS_PA == pDevice->memBase)
    {
        DEBUGMSG(ZONE_POWER, (TEXT("SPI1: SPI_ClockOn\r\n") ));
        regBit = PRCM_FCLKEN1_CORE_EN_MCSPI1;
        KernelIoControl(IOCTL_FCLK1_ENB, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
        regBit = PRCM_ICLKEN1_CORE_EN_MCSPI1;
        KernelIoControl(IOCTL_ICLK1_ENB, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
    }
    else
    {
        //Assume SPI2
        DEBUGMSG(ZONE_POWER, (TEXT("SPI2: SPI_ClockOn\r\n") ));
        regBit = PRCM_FCLKEN1_CORE_EN_MCSPI2;
        KernelIoControl(IOCTL_FCLK1_ENB, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
        regBit = PRCM_ICLKEN1_CORE_EN_MCSPI2;
        KernelIoControl(IOCTL_ICLK1_ENB, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
    }
}

// Turn the clocks off
VOID SPI_ClockOff(SPI_DEVICE *pDevice)
{
    DWORD regBit,cbRet;

    //Check if it's SPI1 or SPI2
    if(OMAP3_MCSPI1_REGS_PA== pDevice->memBase)
    {
        DEBUGMSG(ZONE_POWER, (TEXT("SPI1: SPI_ClockOff\r\n") ));
        regBit = PRCM_FCLKEN1_CORE_EN_MCSPI1;
        KernelIoControl(IOCTL_FCLK1_DIS, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
        regBit = PRCM_ICLKEN1_CORE_EN_MCSPI1;
        KernelIoControl(IOCTL_ICLK1_DIS, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
    }
    else
    {
        //Assume SPI2
        DEBUGMSG(ZONE_POWER, (TEXT("SPI2: SPI_ClockOff\r\n") ));
        regBit = PRCM_FCLKEN1_CORE_EN_MCSPI2;
        KernelIoControl(IOCTL_FCLK1_DIS, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
        regBit = PRCM_ICLKEN1_CORE_EN_MCSPI2;
        KernelIoControl(IOCTL_ICLK1_DIS, (VOID *)&regBit, sizeof(DWORD), NULL, 0, &cbRet);
    }
}

//------------------------------------------------------------------------------

⌨️ 快捷键说明

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