📄 spi.c
字号:
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 *)®Bit, sizeof(DWORD), NULL, 0, &cbRet);
regBit = PRCM_ICLKEN1_CORE_EN_MCSPI1;
KernelIoControl(IOCTL_ICLK1_ENB, (VOID *)®Bit, 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 *)®Bit, sizeof(DWORD), NULL, 0, &cbRet);
regBit = PRCM_ICLKEN1_CORE_EN_MCSPI2;
KernelIoControl(IOCTL_ICLK1_ENB, (VOID *)®Bit, 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 *)®Bit, sizeof(DWORD), NULL, 0, &cbRet);
regBit = PRCM_ICLKEN1_CORE_EN_MCSPI1;
KernelIoControl(IOCTL_ICLK1_DIS, (VOID *)®Bit, 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 *)®Bit, sizeof(DWORD), NULL, 0, &cbRet);
regBit = PRCM_ICLKEN1_CORE_EN_MCSPI2;
KernelIoControl(IOCTL_ICLK1_DIS, (VOID *)®Bit, sizeof(DWORD), NULL, 0, &cbRet);
}
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -