📄 ssp_driver.cpp
字号:
//*********************************************************************
//* Software that is described herein is for illustrative purposes only
//* which provides customers with programming information regarding the
//* products. This software is supplied "AS IS" without any warranties.
//* NXP Semiconductors assumes no responsibility or liability for the
//* use of the software, conveys no license or title under any patent,
//* copyright, or mask work right to the product. NXP Semiconductors
//* reserves the right to make changes in the software without
//* notification. NXP Semiconductors also make no representation or
//* warranty that such application will be suitable for the specified
//* use without further testing or modification.
//*
//* Copyright NXP Semiconductors
//*********************************************************************
//
// ssp_driver.h
//
// SSP driver
//
#include <windows.h>
#include <nkintr.h>
#include <CEDDK.h>
#include "bsp.h"
#include "bsp_ssp.h"
#include "drv_ioctl_funcs.h"
#include "lpc32xx_ssp.h"
#include "lpc32xx_clkpwr.h"
#include "lpc32xx_gpio.h"
// Device context instance
typedef struct
{
SSP_REGS_T *pSSPRegs;
CLKPWR_REGS_T *pClkPwrRegs; // Pointer to CLKPWR regs
GPIO_REGS_T *pGPIORegs; // Pointer to GPIO regs
DWORD SSPsysIntr; // SysIntr value for device
HANDLE sspEvent; // Interrupt event handler
HANDLE sspLock; // Mutex for SSP access lock
int sspNum; // 0 for SSP0, 1 for SSP1
class bspssp *pSSPClass; // Allocated SSP control class
} SSP_DRVCTL_T;
static SSP_DRVCTL_T sspDrv[2] = {
{NULL, NULL, NULL, SYSINTR_UNDEFINED, NULL, NULL, 0, NULL},
{NULL, NULL, NULL, SYSINTR_UNDEFINED, NULL, NULL, 1, NULL}};
// Number of open instances
static int sspInstances[2] = {0, 0};
//------------------------------------------------------------------------------
//
// dump_regs
//
// Dump current SSP registers, debug function
//
void dump_regs(SSP_REGS_T *pRegs)
{
UINT32 *p32 = (UINT32 *) pRegs;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
RETAILMSG(1, (_T("SSP Reg 0x%x = 0x%08x!\r\n"), p32, *p32));
p32++;
}
//------------------------------------------------------------------------------
//
// SSP_Lock
//
// Lock access to SSP registers
//
static void SSP_Lock(HANDLE lckHndl) {
WaitForSingleObject(lckHndl, 150);
}
//------------------------------------------------------------------------------
//
// SSP_Unlock
//
// Unlock access to SSP registers
//
static void SSP_Unlock(HANDLE lckHndl) {
ReleaseMutex(lckHndl);
}
//------------------------------------------------------------------------------
//
// SSPPeriphDown
//
// Disables clocking and power state
//
static void SSPPeriphDown(DWORD hDeviceContext)
{
SSP_DRVCTL_T *pDev = (SSP_DRVCTL_T *) hDeviceContext;
// Disable clock for this device
if (pDev->sspNum == 0)
{
pDev->pClkPwrRegs->clkpwr_ssp_blk_ctrl &= ~CLKPWR_SSPCTRL_SSPCLK0_EN;
}
else
{
pDev->pClkPwrRegs->clkpwr_ssp_blk_ctrl &= ~CLKPWR_SSPCTRL_SSPCLK1_EN;
}
}
//------------------------------------------------------------------------------
//
// SSPPeriphUp
//
// Enables peripheral clocking and power state
//
extern "C" void SSPPeriphUp(DWORD hDeviceContext)
{
SSP_DRVCTL_T *pDev = (SSP_DRVCTL_T *) hDeviceContext;
// Enable clock for this device
if (pDev->sspNum == 0)
{
pDev->pClkPwrRegs->clkpwr_ssp_blk_ctrl |= CLKPWR_SSPCTRL_SSPCLK0_EN;
}
else
{
pDev->pClkPwrRegs->clkpwr_ssp_blk_ctrl |= CLKPWR_SSPCTRL_SSPCLK1_EN;
}
}
//------------------------------------------------------------------------------
//
// SSP_CS_Setup
//
// Sets the control function for the SSP chip select
//
void SSP_CS_Setup(SSP_DRVCTL_T *pDev,
BOOL lockedCS)
{
if (pDev->sspNum == 0)
{
if (lockedCS == TRUE)
{
// GPIO controls SSP0 CS
pDev->pGPIORegs->pio_mux_clr = PIO1_GPIO05_SSEL0;
pDev->pGPIORegs->pio_dir_set = OUTP_STATE_GPIO(5);
}
else
{
// SSP0 controls SSP0 CS
pDev->pGPIORegs->pio_mux_set = PIO1_GPIO05_SSEL0;
pDev->pGPIORegs->pio_dir_clr = OUTP_STATE_GPIO(5);
}
}
else
{
// Not supported on Phytec board
// TBD Customer will need to implement for their own board
}
}
//------------------------------------------------------------------------------
//
// SSP_Transfer
//
// SSP transaction handler, handles both RX and TX for a specific channel
//
static BOOL SSP_Transfer(SSP_DRVCTL_T *pDev,
SSP_SEND_XFER_T *sspout,
SSP_RECV_XFER_T *sspin)
{
SSP_XFER_T sspxfer;
BOOL waitLoop;
DWORD rsts;
DWORD inBuff, outBuff;
int toRecv, toSend;
// Drive the chip select low (if GPIO is used for CS)
if (pDev->sspNum == 0)
{
pDev->pGPIORegs->pio_outp_clr = OUTP_STATE_GPIO(5);
}
else
{
// Not supported on Phytec board
// TBD Customer will need to implement for their own board
}
// Save buffer pointers and transfer sizes
inBuff = (DWORD) sspin->recvBuff;
outBuff = (DWORD) sspout->sendBuff;
toRecv = sspin->recvBuffSize;
toSend = sspout->sendBuffBytes;
// Wait for an interrupt until all data has been transferred
waitLoop = TRUE;
while (waitLoop == TRUE)
{
// Setup the transfer
sspxfer.recvBuff = (void *) inBuff;
sspxfer.recvBuffSize = toRecv;
sspxfer.sendBuff = (void *) outBuff;
sspxfer.sendBuffBytes = toSend;
// Start the transfer
pDev->pSSPClass->bspsspInt(&sspxfer);
// Update counts from actual values
inBuff += (DWORD) sspxfer.recvBuffBytesFilled;
toRecv -= sspxfer.recvBuffBytesFilled;
outBuff += (DWORD) sspxfer.actSendBuffBytes;
toSend -= sspxfer.actSendBuffBytes;
// Transfer complete
if ((toSend == 0) && (toRecv == 0) || (sspxfer.recvDataOflow == TRUE))
{
sspin->recvOflow = sspxfer.recvDataOflow;
waitLoop = FALSE;
}
else
{
// Wait for another interrupt to contimue handling
InterruptDone(pDev->SSPsysIntr);
rsts = WaitForSingleObject(pDev->sspEvent, 1000);
if ((rsts == WAIT_TIMEOUT) || (rsts == WAIT_FAILED))
{
waitLoop = FALSE;
sspin->recvOflow = TRUE;
}
}
}
// Drive the chip select high (if GPIO is used for CS)
if (pDev->sspNum == 0)
{
pDev->pGPIORegs->pio_outp_set = OUTP_STATE_GPIO(5);
}
else
{
// Not supported on Phytec board
// TBD Customer will need to implement for their own board
}
return TRUE;
}
//------------------------------------------------------------------------------
//
// SSP_PowerDown
//
// Powerdown function
//
extern "C" void SSP_PowerDown(DWORD hDeviceContext)
{
SSPPeriphDown(hDeviceContext);
}
//------------------------------------------------------------------------------
//
// SSP_PowerUp
//
// Powerup function
//
extern "C" void SSP_PowerUp(DWORD hDeviceContext)
{
SSPPeriphUp(hDeviceContext);
}
//------------------------------------------------------------------------------
//
// SSP_Deinit
//
// SSP de-init function
//
extern "C" BOOL SSP_Deinit(DWORD hDeviceContext) {
SSP_DRVCTL_T *pDev = (SSP_DRVCTL_T *) hDeviceContext;
// Delete SSP BSP class
if (pDev->pSSPClass != NULL)
{
delete pDev->pSSPClass;
pDev->pSSPClass = NULL;
}
if (pDev->pClkPwrRegs != NULL)
{
// Disable SSP clock
SSPPeriphDown(hDeviceContext);
MmUnmapIoSpace((PVOID) pDev->pClkPwrRegs,
sizeof (CLKPWR_REGS_T));
pDev->pClkPwrRegs = NULL;
}
if (pDev->pSSPRegs != NULL)
{
MmUnmapIoSpace((PVOID) pDev->pSSPRegs,
sizeof (SSP_REGS_T));
pDev->pSSPRegs = NULL;
}
if (pDev->pGPIORegs != NULL)
{
MmUnmapIoSpace((PVOID) pDev->pGPIORegs,
sizeof (GPIO_REGS_T));
pDev->pGPIORegs = NULL;
}
// Release sysIntr value
if (pDev->SSPsysIntr != SYSINTR_UNDEFINED)
{
KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &pDev->SSPsysIntr,
sizeof(pDev->SSPsysIntr), NULL, 0, NULL);
pDev->SSPsysIntr = SYSINTR_UNDEFINED;
}
// Delete event
if (pDev->sspEvent != NULL)
{
CloseHandle(pDev->sspEvent);
pDev->sspEvent = NULL;
}
// Delete access mutex
if (pDev->sspLock != NULL)
{
CloseHandle(pDev->sspLock);
pDev->sspLock = NULL;
}
return TRUE;
}
//------------------------------------------------------------------------------
//
// SSP_Init
//
// SSP Init function
//
extern "C" DWORD SSP_Init(LPCTSTR pContext, LPCVOID lpvBusContext) {
PHYSICAL_ADDRESS pa;
UINT32 bytesret, clk;
int index;
SSP_DRVCTL_T *pDev;
HKEY hkey = NULL;
DWORD dwStatus, dwType, dwSize, indx, irqt, sts = 0;
WCHAR regkeyname[256];
SSP_XFER_SETUP_T sspcfg;
(void) lpvBusContext;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -