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

📄 i2c.c

📁 三星ARM9系列CPU S3C2440A的WINCE 5.0下的BSP
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

/*++

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:

    I2C.C   I2C H/W Access routines (logical PDD)

Abstract:

    Supports:
    ---------
    o) Master Tx/Rx Modes only.
    o) Multi-byte Tx/Rx (slave must support auto increment for multi-byte)

Functions:

Notes:

--*/

#include <windows.h>
#include <nkintr.h>

#include "drv.h"


//
// I2C Registers
//
#define rIICCON     (pI2C->pI2CReg->IICCON)     // Control Register
#define rIICSTAT    (pI2C->pI2CReg->IICSTAT)    // Status Register
#define rIICADD     (pI2C->pI2CReg->IICADD)     // Address Register
#define rIICDS      (pI2C->pI2CReg->IICDS)      // Data Shift Register


// BUGBUG: need ioctl to set timeout parms based on num chars client is expecting
DWORD gIntrIIC 		= SYSINTR_NOP;
#define RX_TIMEOUT  3000
#define TX_TIMEOUT  3000

#define I2C_POWER_ON    0x10000     // rCLKCON bit 16

static DWORD I2C_IST(LPVOID Context);


VOID
InitRegs(
    PI2C_CONTEXT pI2C
    )
{
    EnterCriticalSection(&pI2C->RegCS);

    //
    // enable the I2C Clock (PCLK)
    //
    pI2C->pCLKPWRReg->CLKCON |= I2C_POWER_ON;

    // setup GPIO for I2C
//    rGPEUP &= ~0xc000;					//Pull-up disable
//    rGPEUP |= 0xc000; 					//pull-ups disable
//    rGPECON &= ~(0xF<<28);
//    rGPECON |= (0xA << 28);   //GPE15:IICSDA, GPE14:IICSCL

    // config controller
    rIICCON  = RESUME_ACK;

    rIICSTAT = M_IDLE;
    
    pI2C->State = IDLE;

    pI2C->DataCount = INVALID_DATA_COUNT;

    LeaveCriticalSection(&pI2C->RegCS);
}


DWORD
HW_Init(
    PI2C_CONTEXT pI2C
    )
{
    DWORD dwErr = ERROR_SUCCESS;
	UINT32 Irq;
    
    RETAILMSG(1,(TEXT("I2C Init\r\n")));
    if ( !pI2C ) {
        return ERROR_INVALID_PARAMETER;
    }
    
    DEBUGMSG(ZONE_TRACE,(TEXT("+I2C_Init: %u, 0x%x, 0x%x \r\n"), 
        pI2C->Mode, pI2C->SlaveAddress));

    InitializeCriticalSection(&pI2C->RegCS);
    
    pI2C->Status    = 0;
    pI2C->Data      = NULL;
    pI2C->DataCount = INVALID_DATA_COUNT;
    pI2C->Flags.DropRxAddr = FALSE;

    pI2C->hProc = (HANDLE)GetCurrentProcessId();

    InitRegs(pI2C);

    // create I/O Done Event
    if ( (pI2C->DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
    {
        dwErr = GetLastError();
        DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to create Done event: %u \r\n"), dwErr));
        goto _init_error;
    }

    // setup Operating Mode
    if ( pI2C->Mode == INTERRUPT ) {
        // create IST event
        if ( (pI2C->ISTEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
        {
            dwErr = GetLastError();
            DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to create IST event: %u \r\n"), dwErr));
            goto _init_error;
        }

	// Obtain sysintr values from the OAL for the camera interrupt.
	//
	Irq = IRQ_IIC;
	if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &gIntrIIC, sizeof(UINT32), NULL))
	{
		DEBUGMSG(ZONE_ERR, (TEXT("ERROR: Failed to request the IIC sysintr.\r\n")));
		gIntrIIC = SYSINTR_UNDEFINED;
		return(FALSE);
	}
	RETAILMSG(1, (TEXT("IIC IRQ mapping: [IRQ:%d->sysIRQ:%d].\r\n"), Irq, gIntrIIC));

        // initialize the interrupt
        if( !InterruptInitialize(gIntrIIC, pI2C->ISTEvent, NULL, 0) ) 
        {
            dwErr = GetLastError();
            DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to initialize interrupt: %u\r\n"), dwErr));
            goto _init_error;
        }

        InterruptDone(gIntrIIC);

        // create the IST
        if ( (pI2C->IST = CreateThread(NULL, 0, I2C_IST, (LPVOID)pI2C, 0, NULL)) == NULL)
        {
            dwErr = GetLastError();
            DEBUGMSG(ZONE_ERR,(TEXT("I2C_Init ERROR: Unable to create IST: %u\r\n"), dwErr));
            goto _init_error;
        }

        // TODO: registry override
        if ( !CeSetThreadPriority(pI2C->IST, I2C_THREAD_PRIORITY)) {
            dwErr = GetLastError();
            DEBUGMSG(ZONE_ERR, (TEXT("I2C_Init ERROR: CeSetThreadPriority ERROR:%d\n"), dwErr));
            goto _init_error;
        }
    }

    DEBUGMSG(ZONE_TRACE,(TEXT("-I2C_Init \r\n")));

    return dwErr;

_init_error:
    HW_Deinit(pI2C);

    return dwErr;
}


DWORD
HW_Deinit(
    PI2C_CONTEXT pI2C
    )
{
    if ( !pI2C )
        return ERROR_INVALID_PARAMETER;
        
    DEBUGMSG(ZONE_TRACE,(TEXT("I2C_Deinit: %u \r\n"), pI2C->State));

    if ( pI2C->State == IDLE ) {

        pI2C->State = OFF; // also signals the IST to terminate
        
        rIICSTAT = M_IDLE;

        if (pI2C->DoneEvent && CloseHandle(pI2C->DoneEvent))
            pI2C->DoneEvent = NULL;

        if (pI2C->Mode == INTERRUPT) {
            
            InterruptDisable(gIntrIIC);
        
            if (pI2C->ISTEvent && CloseHandle(pI2C->ISTEvent))
                pI2C->ISTEvent = NULL;
            
            if (pI2C->IST && CloseHandle(pI2C->IST))
                pI2C->IST = NULL;
        }

        pI2C->Mode = POLLING;
        pI2C->Data  = NULL;
        pI2C->DataCount = INVALID_DATA_COUNT;
        pI2C->Flags.DropRxAddr = FALSE;

        DeleteCriticalSection(&pI2C->RegCS);

        return ERROR_SUCCESS;
        
    } else {
        DEBUGMSG(ZONE_ERR,(TEXT("I2C_Deinit ERROR: %u \r\n"), pI2C->State));
        
        return ERROR_BUSY;
    }
}


DWORD
HW_Open(
    PI2C_CONTEXT pI2C
    )
{
    // BUGBUG: power on device
    return ERROR_SUCCESS;
}


DWORD
HW_Close(
    PI2C_CONTEXT pI2C
    )
{
    // BUGBUG: power off device
    return ERROR_SUCCESS;
}


__inline
DWORD
SyncIst(    
    PI2C_CONTEXT pI2C,
    DWORD dwTimeout
    )
{
    DWORD w;
    if (pI2C->Mode == INTERRUPT) {

        DEBUGMSG(ZONE_READ|ZONE_WRITE,(TEXT("SyncIst...\r\n")));
        RETAILMSG(1,(TEXT("SyncIst...\r\n")));

        w = WaitForSingleObject(pI2C->DoneEvent, dwTimeout);

        if (WAIT_OBJECT_0 != w) {
            pI2C->State = IO_ABANDONED;
            if (pI2C->LastError == ERROR_SUCCESS)
                pI2C->LastError = ERROR_TIMEOUT;
            DEBUGMSG(ZONE_WRN|ZONE_READ|ZONE_WRITE,(TEXT("SyncIst: IO_ABANDONED\r\n")));
            RETAILMSG(1, (TEXT("SyncIst: IO_ABANDONED\r\n")));
        }
        
        DEBUGMSG(ZONE_READ|ZONE_WRITE,(TEXT("...SyncIst: 0x%X\r\n"), pI2C->LastError));
        
        return pI2C->LastError;
        
    } else {
        while(pI2C->DataCount != INVALID_DATA_COUNT) {
            // poll INT pending bit
            if (pI2C->Mode == POLLING && (rIICCON & 0x10))
                I2C_IST(pI2C);
		     RETAILMSG(1, (TEXT("SynIst] I2C_IST : Mode = %d"), pI2C->Mode));
        }
    }
    
    return ERROR_SUCCESS;
}


DWORD 
HW_Read(
    PI2C_CONTEXT pI2C,
    DWORD  SlaveAddr,   // slave address
    UCHAR  WordAddr,    // starting word address
    PUCHAR pData,       // pdata
    DWORD  Count        // bytes to read
    )
{
    DWORD  dwErr;

    if ( !VALID_CONTEXT(pI2C) )
        return ERROR_INVALID_PARAMETER;
        
    DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("+I2C_Read[%u]: 0x%X, 0x%X, 0x%X, %u\r\n"), 
        pI2C->State, SlaveAddr, WordAddr, pData, Count));
    
    if ( !pData || !Count || IsBadWritePtr(pData, Count) ) {
        DEBUGMSG(ZONE_ERR,(TEXT("I2C_Read ERROR: invalid parameter \r\n")));
        return ERROR_INVALID_PARAMETER;
    }

    EnterCriticalSection(&pI2C->RegCS);
    
    if ( pI2C->State != IDLE) {
        DEBUGMSG(ZONE_ERR,(TEXT("I2C_Read ERROR: i2cState: %u \r\n"), pI2C->State));
        LeaveCriticalSection(&pI2C->RegCS);
        return ERROR_BUSY;
    }

    pI2C->LastError = ERROR_SUCCESS;
    
    ResetEvent(pI2C->DoneEvent);

    rIICSTAT = M_ACTIVE;
    
    // pre-setup word address
    pI2C->Data = NULL;
    pI2C->State = SET_READ_ADDR;
    pI2C->WordAddr = WordAddr;
    pI2C->Flags.WordAddr = TRUE;
    pI2C->DataCount = 1;
    
    // enable the slave address drop
    pI2C->Flags.DropRxAddr = TRUE;

    // write slave address
    rIICDS = (UCHAR)SlaveAddr;
    rIICSTAT = MTX_START;

    // Wait for IST to write the word address
    if (WAIT_OBJECT_0 != SyncIst(pI2C, RX_TIMEOUT)) {
        
        DEBUGMSG(ZONE_READ|ZONE_ERR,(TEXT("RX_TIMEOUT.1\r\n")));

        goto _done;
    }

    ResetEvent(pI2C->DoneEvent);

    // get read data
    pI2C->State = READ_DATA;
    pI2C->Data = pData;
    pI2C->DataCount = Count;
    rIICDS = (UCHAR)SlaveAddr;
    rIICSTAT = MRX_START;
    rIICCON  = RESUME_ACK;  // Resume IIC operation (clear bit 4)

    // Wait for IST to get data
    if (WAIT_OBJECT_0 != SyncIst(pI2C, RX_TIMEOUT)) {
        
        DEBUGMSG(ZONE_READ|ZONE_ERR,(TEXT("RX_TIMEOUT.2\r\n")));

        goto _done;
    }



_done:    
    rIICSTAT  = M_IDLE;    // disable Rx/Tx
    pI2C->State = IDLE;
    pI2C->Data  = NULL;
    pI2C->DataCount = INVALID_DATA_COUNT;

    if ( !pI2C->LastError && (SlaveAddr != pI2C->RxRetAddr) ) {

        DEBUGMSG(ZONE_READ|ZONE_ERR,(TEXT("I2C_Read Invalid Return Address: 0x%X != 0x%X \r\n"), 
            pI2C->RxRetAddr, SlaveAddr ));

        pI2C->LastError = ERROR_INCORRECT_ADDRESS;

        TEST_TRAP;
    }
    
    pI2C->RxRetAddr = 0;

    dwErr = pI2C->LastError;
    
    LeaveCriticalSection(&pI2C->RegCS);
    
    DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("-I2C_Read:%u \r\n"), dwErr ));
	//RETAILMSG(1,(_T("data = 0x%X\r\n", *pData)));

    return dwErr;
}


DWORD
HW_Write(
    PI2C_CONTEXT pI2C,
    DWORD  SlaveAddr,   // slave address
    UCHAR  WordAddr,    // starting slave word address
    PUCHAR pData,       // pdata
    DWORD  Count        // bytes to write
    )    
{
    DWORD dwErr;

    if ( !VALID_CONTEXT(pI2C) )
        return ERROR_INVALID_PARAMETER;
        
    DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("+I2C_Write[%u]: 0x%X, 0x%X, 0x%X, %u \r\n"), 
    //RETAILMSG(1,(TEXT("+I2C_Write[%u]: 0x%X, 0x%X, 0x%X, %u \r\n"), 
        pI2C->State, SlaveAddr, WordAddr, *pData, Count));
    
    if ( !pData || !Count || IsBadReadPtr(pData, Count) ) {
        DEBUGMSG(ZONE_ERR,(TEXT("I2C_Write ERROR: invalid parameter \r\n")));
        return ERROR_INVALID_PARAMETER;
    }

    EnterCriticalSection(&pI2C->RegCS);
    
    if ( pI2C->State != IDLE) {
        DEBUGMSG(ZONE_ERR,(TEXT("I2C_Write ERROR: i2cState: %u \r\n"), pI2C->State));
        LeaveCriticalSection(&pI2C->RegCS);
        return ERROR_BUSY;
    }

    pI2C->LastError = ERROR_SUCCESS;
        
    ResetEvent(pI2C->DoneEvent);

    rIICSTAT = M_ACTIVE;

    // pre-setup write data
    pI2C->State     = WRITE_DATA;
    pI2C->DataCount = 1 + Count; // slave word address + data 
    pI2C->WordAddr  = WordAddr;
    pI2C->Flags.WordAddr = TRUE;    
    pI2C->Data      = pData;

⌨️ 快捷键说明

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