📄 i2c.cpp
字号:
// -----------------------------------------------------------------------------
//
// 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.
// Copyright (c) 2002 Silicon Motion, Inc.
//
// Module Name: i2c.cpp
//
// Abstract: I2C API
//
// -----------------------------------------------------------------------------
#include "precomp.h"
#include "smi.h"
///////////////////////////////////////////////////////////////////////////////
// Global definitions
#define DELAY_TIME 3 // Number of milliseconds
#define BUFFER_LENGTH 16 // Maximum length in bytes
#define TRANSACTION_TIMEOUT 1000 // Number of milliseconds
///////////////////////////////////////////////////////////////////////////////
// Macro for printing debug messages
#if 1
// Print messages only in DEBUG mode
#define MESSAGE DEBUGMSG
#define MESSAGE_ZONE GPE_ZONE_WARNING
#else
// Force messages even in RELEASE mode
#define MESSAGE RETAILMSG
#define MESSAGE_ZONE 0
#endif
///////////////////////////////////////////////////////////////////////////////
// Interrupt event name
static TCHAR* lpszIntEventName =
TEXT("VGX-I2C-INT-70D34510-CEEE-42a2-BA7E-66045FEA170C");
///////////////////////////////////////////////////////////////////////////////
// I2C API Command Handler.
ULONG SMI::HandleSMII2CAPI(ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::HandleSMII2CAPI\r\n")));
ULONG ulRetVal = VGXI2C_INVALID_PARAMETER;
if ((cjIn >= sizeof(VGXI2C_STRUCT)) && (pvIn != NULL))
{
PVGXI2C_STRUCT pIn = (PVGXI2C_STRUCT)pvIn;
switch (pIn->Command)
{
case VGXI2CCMD_OPEN:
if ((cjIn == sizeof(VGXI2C_OPEN_STRUCT)) &&
(cjOut == 0) && (pvOut == NULL))
{
PVGXI2C_OPEN_STRUCT pInit = (PVGXI2C_OPEN_STRUCT)pvIn;
ulRetVal = i2cOpen(pInit->bFastMode, pInit->bRepStart);
}
break;
case VGXI2CCMD_CLOSE:
if ((cjIn == sizeof(VGXI2C_STRUCT)) &&
(cjOut == 0) && (pvOut == NULL))
{
i2cClose();
ulRetVal = VGXI2C_SUCCESS;
}
break;
case VGXI2CCMD_READ:
if (cjIn == sizeof(VGXI2C_TRANSFER_STRUCT))
{
PVGXI2C_TRANSFER_STRUCT pRead = (PVGXI2C_TRANSFER_STRUCT)pvIn;
if ((pRead->dwCount != 0) &&
(cjOut == pRead->dwCount) && (pvOut != NULL))
{
ulRetVal = i2cRead(pRead->byAddress, pRead->dwCount,
(PBYTE)pvOut);
}
}
break;
case VGXI2CCMD_WRITE:
if (cjIn > sizeof(VGXI2C_TRANSFER_STRUCT))
{
PVGXI2C_TRANSFER_STRUCT pWrite = (PVGXI2C_TRANSFER_STRUCT)pvIn;
if ((pWrite->dwCount != 0) &&
(cjIn == sizeof(VGXI2C_TRANSFER_STRUCT) + pWrite->dwCount) &&
(cjOut == 0) && (pvOut == NULL))
{
ulRetVal = i2cWrite(pWrite->byAddress, pWrite->dwCount,
(PBYTE)pvIn + sizeof(VGXI2C_TRANSFER_STRUCT));
}
}
break;
default:
MESSAGE(MESSAGE_ZONE, (TEXT("SMI::HandleSMII2CAPI: invalid command has been specified\r\n")));
}
}
else
{
MESSAGE(MESSAGE_ZONE,
(TEXT("SMI::HandleSMII2CAPI: invalid input structure\r\n")));
}
if (ulRetVal == VGXI2C_INVALID_PARAMETER)
SetLastError(ERROR_INVALID_PARAMETER);
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::HandleSMII2CAPI\r\n")));
return ulRetVal;
}
///////////////////////////////////////////////////////////////////////////////
// I2C Interrupt Handler.
VOID SMI::i2cIntHandler()
{
#ifndef DISABLE_INTERRUPT_MANAGEMENT
// Stop the transaction
BYTE I2CControl = peekRegisterByte(I2C_CONTROL);
I2CControl = (BYTE)FIELD_SET(I2CControl, I2C_CONTROL, STATUS, STOP);
pokeRegisterByte(I2C_CONTROL, I2CControl);
// Read status
BYTE Status = peekRegisterByte(I2C_STATUS);
MESSAGE(MESSAGE_ZONE, (TEXT("i2cIntHandler: I2C_STATUS = 0x%04X\r\n"), Status));
// Check for the acknowledge
if (FIELD_GET(Status, I2C_STATUS, ACK)
== I2C_STATUS_ACK_NOT_RECEIVED)
{
// Reset the bit
pokeRegisterByte(I2C_STATUS,
(BYTE)FIELD_SET(Status, I2C_STATUS, ACK, CLEAR));
// Acknowledge has not been received
m_I2CStatus = VGXI2C_NO_ACKNOWLEDGE;
}
// Check if there's been an error
else if (FIELD_GET(Status, I2C_STATUS, ERROR)
== I2C_STATUS_ERROR_BUS_ERROR)
{
// Acknowledge the error
I2CControl = peekRegisterByte(I2C_CONTROL);
I2CControl = (BYTE)FIELD_SET(I2CControl, I2C_CONTROL, ERROR, ACKNOWLEDGE);
pokeRegisterByte(I2C_CONTROL, I2CControl);
// Reset the bit
pokeRegisterByte(I2C_STATUS,
(BYTE)FIELD_SET(Status, I2C_STATUS, ERROR, CLEAR));
// Bus error has happend
m_I2CStatus = VGXI2C_BUS_ERROR;
}
// Check for the transfer status
else if (FIELD_GET(Status, I2C_STATUS, TRANSFER)
== I2C_STATUS_TRANSFER_COMPLETE)
{
// Reset the bit
pokeRegisterByte(I2C_STATUS,
(BYTE)FIELD_SET(Status, I2C_STATUS, TRANSFER, CLEAR));
// Transfer is complete
m_I2CStatus = VGXI2C_SUCCESS;
}
// Check whether the bus is busy
else if (FIELD_GET(Status, I2C_STATUS, BUS)
== I2C_STATUS_BUS_BUSY)
{
// The bus is busy
m_I2CStatus = VGXI2C_BUS_BUSY;
}
// Unknown state
else
{
m_I2CStatus = VGXI2C_UNKNOWN_STATE;
}
// Set the interrupt event
SetEvent(m_I2CIntEvent);
#endif
}
///////////////////////////////////////////////////////////////////////////////
// I2C Interrupt Handler Entry.
#ifndef DISABLE_INTERRUPT_MANAGEMENT
VOID i2cIntHandlerEntry(SMI* pSMI)
{
pSMI->i2cIntHandler();
}
#endif
///////////////////////////////////////////////////////////////////////////////
// Initializes I2C transfer.
ULONG SMI::i2cOpen(
BOOL bFastMode, // Fast mode enable
BOOL bRepStart) // Repeated start enable
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::i2cOpen\r\n")));
ULONG nResult;
#ifdef DISABLE_INTERRUPT_MANAGEMENT
nResult = VGXI2C_INT_NOT_SUPPORTED;
#else
nResult = VGXI2C_SUCCESS;
// Create an event
m_I2CIntEvent = CreateEvent(NULL, FALSE, FALSE, lpszIntEventName);
// Configure GPIO pins 46 and 47
DWORD MuxHigh = peekRegisterDWord(GPIO_MUX_HIGH);
MuxHigh = FIELD_SET(MuxHigh, GPIO_MUX_HIGH, 46, I2C);
MuxHigh = FIELD_SET(MuxHigh, GPIO_MUX_HIGH, 47, I2C);
pokeRegisterDWord(GPIO_MUX_HIGH, MuxHigh);
// Register I2C interrupt handler
if (RegisterHandler(i2cIntHandlerEntry, _F_MASK(INT_MASK_I2C)))
{
// Set the I2C flag
m_bI2CEnabled = TRUE;
// Enable I2C gate register
setGate(
_F_MASK(CURRENT_POWER_GATE_GPIO_PWM_I2C),
FIELD_SET(0, CURRENT_POWER_GATE, GPIO_PWM_I2C, ENABLE));
// Configure the control register
BYTE I2CControl = peekRegisterByte(I2C_CONTROL);
I2CControl = FIELD_VALUE(I2CControl, I2C_CONTROL, REPEAT_START, bRepStart?
I2C_CONTROL_REPEAT_START_ENABLE : I2C_CONTROL_REPEAT_START_DISABLE);
I2CControl = FIELD_VALUE(I2CControl, I2C_CONTROL, MODE, bFastMode?
I2C_CONTROL_MODE_FAST : I2C_CONTROL_MODE_STANDARD);
pokeRegisterByte(I2C_CONTROL, I2CControl);
}
else
{
nResult = VGXI2C_INTERRUPT_FAILED;
}
#endif
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::i2cOpen\r\n")));
return nResult;
}
///////////////////////////////////////////////////////////////////////////////
// Shuts I2C down.
VOID SMI::i2cClose()
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::i2cClose\r\n")));
#ifndef DISABLE_INTERRUPT_MANAGEMENT
if (m_bI2CEnabled)
{
// Reset the I2C flag
m_bI2CEnabled = FALSE;
// Turn the controller off and disable interrupts
BYTE I2CControl = peekRegisterByte(I2C_CONTROL);
I2CControl = (BYTE)FIELD_SET(I2CControl, I2C_CONTROL, INTERRUPT, DISABLE);
I2CControl = (BYTE)FIELD_SET(I2CControl, I2C_CONTROL, I2C, DISABLE);
pokeRegisterByte(I2C_CONTROL, I2CControl);
// Register I2C interrupt handler
DisableHandler(_F_MASK(INT_MASK_I2C));
// Disable I2C gate register
setGate(
_F_MASK(CURRENT_POWER_GATE_GPIO_PWM_I2C),
FIELD_SET(0, CURRENT_POWER_GATE, GPIO_PWM_I2C, DISABLE));
}
#endif
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::i2cClose\r\n")));
}
///////////////////////////////////////////////////////////////////////////////
// Stops all activities in the I2C controller if any.
ULONG SMI::i2cReset()
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::i2cReset\r\n")));
ULONG nResult;
#ifdef DISABLE_INTERRUPT_MANAGEMENT
nResult = VGXI2C_INT_NOT_SUPPORTED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -