/** @file | |
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include <Uefi.h> | |
#include <Omap3530/Omap3530.h> | |
#include <Library/DebugLib.h> | |
#include <Library/IoLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Protocol/SmbusHc.h> | |
#define MAX_RETRY 1000 | |
// | |
// Internal Functions | |
// | |
STATIC | |
EFI_STATUS | |
WaitForBusBusy ( | |
VOID | |
) | |
{ | |
UINTN Retry = 0; | |
while (++Retry < MAX_RETRY && (MmioRead16(I2C_STAT) & BB) == 0x1); | |
if (Retry == MAX_RETRY) { | |
return EFI_TIMEOUT; | |
} | |
return EFI_SUCCESS; | |
} | |
STATIC | |
EFI_STATUS | |
PollForStatus( | |
UINT16 StatusBit | |
) | |
{ | |
UINTN Retry = 0; | |
while(Retry < MAX_RETRY) { | |
if (MmioRead16(I2C_STAT) & StatusBit) { | |
//Clear particular status bit from Status register. | |
MmioOr16(I2C_STAT, StatusBit); | |
break; | |
} | |
Retry++; | |
} | |
if (Retry == MAX_RETRY) { | |
return EFI_TIMEOUT; | |
} | |
return EFI_SUCCESS; | |
} | |
STATIC | |
EFI_STATUS | |
ConfigureI2c ( | |
VOID | |
) | |
{ | |
//Program prescaler to obtain 12-MHz clock | |
MmioWrite16(I2C_PSC, 0x0000); | |
//Program SCLL and SCLH | |
//NOTE: Following values are the register dump after U-Boot code executed. | |
//We need to figure out how its calculated based on the I2C functional clock and I2C_PSC. | |
MmioWrite16(I2C_SCLL, 0x0035); | |
MmioWrite16(I2C_SCLH, 0x0035); | |
//Take the I2C controller out of reset. | |
MmioOr16(I2C_CON, I2C_EN); | |
//Initialize the I2C controller. | |
//Set I2C controller in Master mode. | |
MmioOr16(I2C_CON, MST); | |
//Enable interrupts for receive/transmit mode. | |
MmioOr16(I2C_IE, (XRDY_IE | RRDY_IE | ARDY_IE | NACK_IE)); | |
return EFI_SUCCESS; | |
} | |
STATIC | |
EFI_STATUS | |
I2CReadOneByte ( | |
UINT8 *Data | |
) | |
{ | |
EFI_STATUS Status; | |
//I2C bus status checking | |
Status = WaitForBusBusy(); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
//Poll till Receive ready bit is set. | |
Status = PollForStatus(RRDY); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
*Data = MmioRead8(I2C_DATA); | |
return EFI_SUCCESS; | |
} | |
STATIC | |
EFI_STATUS | |
I2CWriteOneByte ( | |
UINT8 Data | |
) | |
{ | |
EFI_STATUS Status; | |
//I2C bus status checking | |
Status = WaitForBusBusy(); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
//Data transfer | |
//Poll till Transmit ready bit is set | |
Status = PollForStatus(XRDY); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
MmioWrite8(I2C_DATA, Data); | |
//Wait and check if the NACK is not set. | |
gBS->Stall(1000); | |
if (MmioRead16(I2C_STAT) & NACK) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
STATIC | |
EFI_STATUS | |
SmbusBlockRead ( | |
OUT UINT8 *Buffer, | |
IN UINTN Length | |
) | |
{ | |
UINTN Index = 0; | |
EFI_STATUS Status = EFI_SUCCESS; | |
//Transfer configuration for receiving data. | |
MmioWrite16(I2C_CNT, Length); | |
//Need stop bit before sending data. | |
MmioWrite16(I2C_CON, (I2C_EN | MST | STP | STT)); | |
while (Index < Length) { | |
//Read a byte | |
Status = I2CReadOneByte(&Buffer[Index++]); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
} | |
//Transfer completion | |
Status = PollForStatus(ARDY); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
return Status; | |
} | |
STATIC | |
EFI_STATUS | |
SmbusBlockWrite ( | |
IN UINT8 *Buffer, | |
IN UINTN Length | |
) | |
{ | |
UINTN Index = 0; | |
EFI_STATUS Status = EFI_SUCCESS; | |
//Transfer configuration for transmitting data | |
MmioWrite16(I2C_CNT, Length); | |
MmioWrite16(I2C_CON, (I2C_EN | TRX | MST | STT | STP)); | |
while (Index < Length) { | |
//Send a byte | |
Status = I2CWriteOneByte(Buffer[Index++]); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
} | |
//Transfer completion | |
Status = PollForStatus(ARDY); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
return Status; | |
} | |
// | |
// Public Functions. | |
// | |
EFI_STATUS | |
EFIAPI | |
SmbusExecute ( | |
IN CONST EFI_SMBUS_HC_PROTOCOL *This, | |
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, | |
IN CONST EFI_SMBUS_DEVICE_COMMAND Command, | |
IN CONST EFI_SMBUS_OPERATION Operation, | |
IN CONST BOOLEAN PecCheck, | |
IN OUT UINTN *Length, | |
IN OUT VOID *Buffer | |
) | |
{ | |
UINT8 *ByteBuffer = Buffer; | |
EFI_STATUS Status = EFI_SUCCESS; | |
UINT8 SlaveAddr = (UINT8)(SlaveAddress.SmbusDeviceAddress); | |
if (PecCheck) { | |
return EFI_UNSUPPORTED; | |
} | |
if ((Operation != EfiSmbusWriteBlock) && (Operation != EfiSmbusReadBlock)) { | |
return EFI_UNSUPPORTED; | |
} | |
//Set the Slave address. | |
MmioWrite16(I2C_SA, SlaveAddr); | |
if (Operation == EfiSmbusReadBlock) { | |
Status = SmbusBlockRead(ByteBuffer, *Length); | |
} else if (Operation == EfiSmbusWriteBlock) { | |
Status = SmbusBlockWrite(ByteBuffer, *Length); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
SmbusArpDevice ( | |
IN CONST EFI_SMBUS_HC_PROTOCOL *This, | |
IN BOOLEAN ArpAll, | |
IN EFI_SMBUS_UDID *SmbusUdid OPTIONAL, | |
IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL | |
) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
EFI_STATUS | |
EFIAPI | |
SmbusGetArpMap ( | |
IN CONST EFI_SMBUS_HC_PROTOCOL *This, | |
IN OUT UINTN *Length, | |
IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap | |
) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
EFI_STATUS | |
EFIAPI | |
SmbusNotify ( | |
IN CONST EFI_SMBUS_HC_PROTOCOL *This, | |
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, | |
IN CONST UINTN Data, | |
IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction | |
) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
EFI_SMBUS_HC_PROTOCOL SmbusProtocol = | |
{ | |
SmbusExecute, | |
SmbusArpDevice, | |
SmbusGetArpMap, | |
SmbusNotify | |
}; | |
EFI_STATUS | |
InitializeSmbus ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_HANDLE Handle = NULL; | |
EFI_STATUS Status; | |
//Configure I2C controller. | |
Status = ConfigureI2c(); | |
if (EFI_ERROR(Status)) { | |
DEBUG ((EFI_D_ERROR, "InitializeI2c fails.\n")); | |
return Status; | |
} | |
// Install the SMBUS interface | |
Status = gBS->InstallMultipleProtocolInterfaces(&Handle, &gEfiSmbusHcProtocolGuid, &SmbusProtocol, NULL); | |
ASSERT_EFI_ERROR(Status); | |
return Status; | |
} | |