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

📄 spi.c

📁 Windows CE 6.0 BSP for the Beagle Board.
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//------------------------------------------------------------------------------
//
//  File: spi.c
//
#include <windows.h>
#include <winuser.h>
#include <winuserm.h>
#include <pm.h>
#include <ceddk.h>
#include <ceddkex.h>
#include <spi.h>
#include <buses.h>
#include <omap2420.h>


//------------------------------------------------------------------------------
//  Local Definitions

#define SPI_DEVICE_COOKIE       'spiD'
#define SPI_INSTANCE_COOKIE     'spiI'

//#undef DEBUGMSG
//#define DEBUGMSG(x, y) RETAILMSG(1,y)

extern DBGPARAM dpCurSettings;
//------------------------------------------------------------------------------
//  Local Structures

typedef struct {
    DWORD cookie;
    DWORD memBase;
    DWORD irq;
    LONG instances;
    HANDLE hParentBus;
    OMAP3_MCSPI_REGS *pSPIRegs;
    CRITICAL_SECTION cs;
    DWORD sysIntr;
    HANDLE hIntrEvent;
    DWORD timeout;
    CEDEVICE_POWER_STATE powerState;
} SPI_DEVICE;

typedef struct {
    DWORD cookie;
    SPI_DEVICE *pDevice;
    DWORD address;
} SPI_INSTANCE;

//------------------------------------------------------------------------------
//  Local Functions

BOOL  SPI_Deinit(DWORD context);
BOOL  SPI_SetSlaveAddress(DWORD context, DWORD address);
BOOL  SPI_SetupMCSPI_Channel(OMAP3_MCSPI_REGS *pSPIRegs, DWORD address);
VOID  SPI_ClockOn(SPI_DEVICE *pDevice);
VOID  SPI_ClockOff(SPI_DEVICE *pDevice);

//------------------------------------------------------------------------------
//  Global variables

const GUID DEVICE_IFC_SPI_GUID;

//------------------------------------------------------------------------------
//  Device registry parameters

static const DEVICE_REGISTRY_PARAM g_deviceRegParams[] = {
    {
        L"MemBase", PARAM_DWORD, TRUE, offset(SPI_DEVICE, memBase),
        fieldsize(SPI_DEVICE, memBase), NULL
    }, { 
        L"Irq", PARAM_DWORD, TRUE, offset(SPI_DEVICE, irq),
        fieldsize(SPI_DEVICE, irq), NULL
    }, { 
        L"Timeout", PARAM_DWORD, FALSE, offset(SPI_DEVICE, timeout),
        fieldsize(SPI_DEVICE, timeout), (VOID*)500
    }        
};

//------------------------------------------------------------------------------
//
//  Function:  SPI_Init
//
//  Called by device manager to initialize device.
//
DWORD SPI_Init(LPCTSTR szContext, LPCVOID pBusContext)
{
    DWORD rc = (DWORD)NULL;
    SPI_DEVICE *pDevice = NULL;
    PHYSICAL_ADDRESS pa;
    DWORD dwCount=0;

    DEBUGMSG(ZONE_INIT, (
        L"+SPI_Init(%s, 0x%08x)\r\n", szContext, pBusContext
    ));

    // Create device structure
    pDevice = (SPI_DEVICE *)LocalAlloc(LPTR, sizeof(SPI_DEVICE));
    if (pDevice == NULL) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"Failed allocate SPI controller structure\r\n"
        ));
        goto cleanUp;
    }

    // Set cookie
    pDevice->cookie = SPI_DEVICE_COOKIE;

    // Initalize critical section
    InitializeCriticalSection(&pDevice->cs);

    // Read device parameters
    if (GetDeviceRegistryParams(
        szContext, pDevice, dimof(g_deviceRegParams), g_deviceRegParams
    ) != ERROR_SUCCESS) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"Failed read SPI driver registry parameters\r\n"
        ));
        goto cleanUp;
    }

    // Open parent bus
    pDevice->hParentBus = CreateBusAccessHandle(szContext);
    if (pDevice->hParentBus == NULL) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"Failed open parent bus driver\r\n"
        ));
        goto cleanUp;
    }

    // Set hardware to full power
    pDevice->powerState = D0;
    SPI_ClockOn(pDevice);
    SetDevicePowerState(pDevice->hParentBus, D0, NULL);

    // Map SPI controller
    pa.QuadPart = pDevice->memBase;
    pDevice->pSPIRegs = MmMapIoSpace(pa, sizeof(OMAP3_MCSPI_REGS), FALSE);
    if (pDevice->pSPIRegs == NULL) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"Failed map SPI controller registers\r\n"
        ));
        goto cleanUp;
    }

    // Map SPI interrupt
    if (!KernelIoControl(
        IOCTL_HAL_REQUEST_SYSINTR, &pDevice->irq, sizeof(pDevice->irq), 
        &pDevice->sysIntr, sizeof(pDevice->sysIntr), NULL
    )) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"Failed map SPI controller interrupt\r\n"
        ));
        goto cleanUp;
    }

    // Create interrupt event
    pDevice->hIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (pDevice->hIntrEvent == NULL) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"Failed create interrupt event\r\n"
        ));
        goto cleanUp;
    }

    // Initialize interrupt
    if (!InterruptInitialize(pDevice->sysIntr, pDevice->hIntrEvent, NULL, 0)) {
        DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Init: "
            L"InterruptInitialize failed\r\n"
        ));
        goto cleanUp;
    }

    // Reset the SPI controller
    SETREG32(&pDevice->pSPIRegs->ulMCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SRST);

    // TODO: Get base clock from kernel & read L/H periods from registry

    // Wait until resetting is done
    while ( !(INREG32(&pDevice->pSPIRegs->ulMCSPI_SYSSTATUS) & BIT0)) {
        Sleep (1);

        if (dwCount++>0x100)
        {
            // Break out dead lock, something is wrong.
            ERRORMSG (TRUE, (TEXT("SPI: ERROR holding in reset.\n")));
            goto cleanUp;
        }
    }

    // Disable all interrupts.
    OUTREG32(&pDevice->pSPIRegs->ulMCSPI_IRQENABLE, 0);

    // Clear interrupts.
    OUTREG32(&pDevice->pSPIRegs->ulMCSPI_IRQSTATUS, 0xFFFF);


    // Setup Module Control as master
    OUTREG32(&pDevice->pSPIRegs->ulMCSPI_MODULCTRL, 0);

    // Turn on the clock on default 1M rate.
    // Reset the SPI controller
    SETREG32(&pDevice->pSPIRegs->ulMCSPI_SYSCONFIG, 0x308);
//    g_pSpiRegs->ulSET1 &= ~0x001E;
//    g_pSpiRegs->ulSET1 |= (GetClockParams(INIT_CLOCK_RATE) << 1);
//    g_pSpiRegs->ulSET1 |= BIT0;


    // Enable the SPI
//    SETREG16(&pDevice->pSPIRegs->CON, SPI_CON_EN);

    // Return non-null value
    rc = (DWORD)pDevice;

    // Set this driver to internal suspend mode
    SetDevicePowerState(pDevice->hParentBus, pDevice->powerState = D4, NULL);
    SPI_ClockOff(pDevice);

cleanUp:
    if (rc == 0) SPI_Deinit((DWORD)pDevice);
    DEBUGMSG(ZONE_INIT, (L"-SPI_Init(rc = %d)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_Deinit
//
//  Called by device manager to uninitialize device.
//
BOOL SPI_Deinit(DWORD context)
{
    BOOL rc = FALSE;
    SPI_DEVICE *pDevice = (SPI_DEVICE*)context;

    DEBUGMSG(ZONE_INIT, (L"+SPI_Deinit(0x%08x)\r\n", context));

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

    // Check for open instances
    if (pDevice->instances > 0) {
        DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Deinit: "
            L"Deinit with active instance (%d instances active)\r\n",
            pDevice->instances
        ));
        goto cleanUp;
    }

    // Set hardware to D4 and close parent bus driver
    if (pDevice->hParentBus!= NULL) 
    {
        SetDevicePowerState(pDevice->hParentBus, D4,NULL);
        CloseBusAccessHandle(pDevice->hParentBus);
    }

    // Delete critical section
    DeleteCriticalSection(&pDevice->cs);

    // Unmap SPI controller registers
    if (pDevice->pSPIRegs != NULL)
    {
        MmUnmapIoSpace((VOID*)pDevice->pSPIRegs, sizeof(OMAP3_MCSPI_REGS));
    }

    //Turn clocks off
    SPI_ClockOff(pDevice);

    // Release SPI controller interrupt
    if (pDevice->sysIntr != 0) 
    {
        InterruptDisable(pDevice->sysIntr);
        KernelIoControl(
            IOCTL_HAL_RELEASE_SYSINTR, &pDevice->sysIntr,
            sizeof(pDevice->sysIntr), NULL, 0, NULL
        );
    }

    // Close interrupt handler
    if (pDevice->hIntrEvent != NULL) CloseHandle(pDevice->hIntrEvent);

    // Free device structure
    LocalFree(pDevice);

    // Done
    rc = TRUE;

cleanUp:
    DEBUGMSG(ZONE_INIT, (L"-SPI_Deinit(rc = %d)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_Open
//
//  Called by device manager to open a device for reading and/or writing.
//
DWORD SPI_Open(DWORD context, DWORD accessCode, DWORD shareMode)
{
    DWORD rc = (DWORD)NULL;
    SPI_DEVICE *pDevice = (SPI_DEVICE*)context;
    SPI_INSTANCE *pInstance = NULL;

    DEBUGMSG(ZONE_FUNCTION, (
        L"+SPI_Open(0x%08x, 0x%08x, 0x%08x\r\n", context, accessCode, shareMode
    ));

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

    // Create device structure
    pInstance = (SPI_INSTANCE*)LocalAlloc(LPTR, sizeof(SPI_INSTANCE));
    if (pInstance == NULL) {
        DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Open: "
            L"Failed allocate SPI instance structure\r\n"
        ));
        goto cleanUp;
    }

    // Set cookie
    pInstance->cookie = SPI_INSTANCE_COOKIE;

    // Save device reference
    pInstance->pDevice = pDevice;

    // Increment number of open instances
    InterlockedIncrement(&pDevice->instances);

    // sanity check number of instances
    ASSERT(pDevice->instances > 0);

    // Done...
    rc = (DWORD)pInstance;

cleanUp:
    DEBUGMSG(ZONE_FUNCTION, (L"-SPI_Open(rc = 0x%08x)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_Close
//
//  This function closes the device context.
//
BOOL SPI_Close(DWORD context)
{
    BOOL rc = FALSE;
    SPI_DEVICE *pDevice;
    SPI_INSTANCE *pInstance = (SPI_INSTANCE*)context;

    DEBUGMSG(ZONE_FUNCTION, (L"+SPI_Close(0x%08x)\r\n", context));

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

    // Get device context
    pDevice = pInstance->pDevice;

    // sanity check number of instances
    ASSERT(pDevice->instances > 0);

    // Decrement number of open instances
    InterlockedDecrement(&pDevice->instances);

    // Free instance structure
    LocalFree(pInstance);

    // Done...
    rc = TRUE;

cleanUp:
    DEBUGMSG(ZONE_FUNCTION, (L"-SPI_Close(rc = %d)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  SPI_Transfer
//
//  This function reads data from the device identified by the open context.
//
DWORD SPI_Transfer(DWORD context, PVOID pBuffer)
{

    DWORD rc = 0;
    SPI_DEVICE *pDevice;
    SPI_INSTANCE *pInstance = (SPI_INSTANCE*)context;
    OMAP3_MCSPI_REGS *pSPIRegs;
    UINT32* pData = (UINT32*)pBuffer;
    DWORD dwCount;

//    DEBUGMSG(ZONE_FUNCTION, ( L"+SPI_Transfer(0x%08x, 0x%08x\r\n", context, *pData));

    // Check if we get correct context

⌨️ 快捷键说明

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