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

📄 i2c.cpp

📁 SM501基于ARMV4/ARMV4I平台
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// -----------------------------------------------------------------------------
//
//  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 + -