audk/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c

428 lines
8.6 KiB
C

/** @file
I2C Bus implementation upon CirrusLogic.
Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "CirrusLogic5430.h"
#include "CirrusLogic5430I2c.h"
#define SEQ_ADDRESS_REGISTER 0x3c4
#define SEQ_DATA_REGISTER 0x3c5
#define I2C_CONTROL 0x08
#define I2CDAT_IN 7
#define I2CCLK_IN 2
#define I2CDAT_OUT 1
#define I2CCLK_OUT 0
#define I2C_BUS_SPEED 100 //100kbps
/**
PCI I/O byte write function.
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param Address The bit map of I2C Data or I2C Clock pins.
@param Data The date to write.
**/
VOID
I2cOutb (
EFI_PCI_IO_PROTOCOL *PciIo,
UINTN Address,
UINT8 Data
)
{
PciIo->Io.Write (
PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
Address,
1,
&Data
);
}
/**
PCI I/O byte read function.
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param Address The bit map of I2C Data or I2C Clock pins.
return byte value read from PCI I/O space.
**/
UINT8
I2cInb (
EFI_PCI_IO_PROTOCOL *PciIo,
UINTN Address
)
{
UINT8 Data;
PciIo->Io.Read (
PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
Address,
1,
&Data
);
return Data;
}
/**
Read status of I2C Data and I2C Clock Pins.
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param Blt The bit map of I2C Data or I2C Clock pins.
@retval 0 Low on I2C Data or I2C Clock Pin.
@retval 1 High on I2C Data or I2C Clock Pin.
**/
UINT8
I2cPinRead (
EFI_PCI_IO_PROTOCOL *PciIo,
UINT8 Bit
)
{
I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe);
}
/**
Set/Clear I2C Data and I2C Clock Pins.
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param Blt The bit map to controller I2C Data or I2C Clock pins.
@param Value 1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins.
**/
VOID
I2cPinWrite (
EFI_PCI_IO_PROTOCOL *PciIo,
UINT8 Bit,
UINT8 Value
)
{
UINT8 Byte;
I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ;
Byte = (UINT8) (Byte | ((Value & 0x01) << Bit));
I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40));
return;
}
/**
Read/write delay acoording to I2C Bus Speed.
**/
VOID
I2cDelay (
VOID
)
{
MicroSecondDelay (1000 / I2C_BUS_SPEED);
}
/**
Write a 8-bit data onto I2C Data Pin.
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param Data The byte data to write.
**/
VOID
I2cSendByte (
EFI_PCI_IO_PROTOCOL *PciIo,
UINT8 Data
)
{
UINTN Index;
//
// Send byte data onto I2C Bus
//
for (Index = 0; Index < 8; Index --) {
I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index)));
I2cPinWrite (PciIo, I2CCLK_OUT, 1);
I2cDelay ();
I2cPinWrite (PciIo, I2CCLK_OUT, 0);
}
}
/**
Read a 8-bit data from I2C Data Pin.
@param PciIo The pointer to PCI_IO_PROTOCOL.
Return the byte data read from I2C Data Pin.
**/
UINT8
I2cReceiveByte (
EFI_PCI_IO_PROTOCOL *PciIo
)
{
UINT8 Data;
UINTN Index;
Data = 0;
//
// Read byte data from I2C Bus
//
for (Index = 0; Index < 8; Index --) {
I2cPinWrite (PciIo, I2CCLK_OUT, 1);
I2cDelay ();
Data = (UINT8) (Data << 1);
Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN));
I2cPinWrite (PciIo, I2CCLK_OUT, 0);
}
return Data;
}
/**
Receive an ACK signal from I2C Bus.
@param PciIo The pointer to PCI_IO_PROTOCOL.
**/
BOOLEAN
I2cWaitAck (
EFI_PCI_IO_PROTOCOL *PciIo
)
{
//
// Wait for ACK signal
//
I2cPinWrite (PciIo, I2CDAT_OUT, 1);
I2cPinWrite (PciIo, I2CCLK_OUT, 1);
I2cDelay ();
if (I2cPinRead (PciIo, I2CDAT_IN) == 0) {
I2cPinWrite (PciIo, I2CDAT_OUT, 1);
return TRUE;
} else {
return FALSE;
}
}
/**
Send an ACK signal onto I2C Bus.
@param PciIo The pointer to PCI_IO_PROTOCOL.
**/
VOID
I2cSendAck (
EFI_PCI_IO_PROTOCOL *PciIo
)
{
I2cPinWrite (PciIo, I2CCLK_OUT, 1);
I2cPinWrite (PciIo, I2CDAT_OUT, 1);
I2cPinWrite (PciIo, I2CDAT_OUT, 0);
I2cPinWrite (PciIo, I2CCLK_OUT, 0);
}
/**
Start a I2C transfer on I2C Bus.
@param PciIo The pointer to PCI_IO_PROTOCOL.
**/
VOID
I2cStart (
EFI_PCI_IO_PROTOCOL *PciIo
)
{
//
// Init CLK and DAT pins
//
I2cPinWrite (PciIo, I2CCLK_OUT, 1);
I2cPinWrite (PciIo, I2CDAT_OUT, 1);
//
// Start a I2C transfer, set SDA low from high, when SCL is high
//
I2cPinWrite (PciIo, I2CDAT_OUT, 0);
I2cPinWrite (PciIo, I2CCLK_OUT, 0);
}
/**
Stop a I2C transfer on I2C Bus.
@param PciIo The pointer to PCI_IO_PROTOCOL.
**/
VOID
I2cStop (
EFI_PCI_IO_PROTOCOL *PciIo
)
{
//
// Stop a I2C transfer, set SDA high from low, when SCL is high
//
I2cPinWrite (PciIo, I2CDAT_OUT, 0);
I2cPinWrite (PciIo, I2CCLK_OUT, 1);
I2cPinWrite (PciIo, I2CDAT_OUT, 1);
}
/**
Read one byte data on I2C Bus.
Read one byte data from the slave device connectet to I2C Bus.
If Data is NULL, then ASSERT().
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param DeviceAddress Slave device's address.
@param RegisterAddress The register address on slave device.
@param Data The pointer to returned data if EFI_SUCCESS returned.
@retval EFI_DEVICE_ERROR
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
I2cReadByte (
EFI_PCI_IO_PROTOCOL *PciIo,
UINT8 DeviceAddress,
UINT8 RegisterAddress,
UINT8 *Data
)
{
ASSERT (Data != NULL);
//
// Start I2C transfer
//
I2cStart (PciIo);
//
// Send slave address with enabling write flag
//
I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
//
// Wait for ACK signal
//
if (I2cWaitAck (PciIo) == FALSE) {
return EFI_DEVICE_ERROR;
}
//
// Send register address
//
I2cSendByte (PciIo, RegisterAddress);
//
// Wait for ACK signal
//
if (I2cWaitAck (PciIo) == FALSE) {
return EFI_DEVICE_ERROR;
}
//
// Send slave address with enabling read flag
//
I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01));
//
// Wait for ACK signal
//
if (I2cWaitAck (PciIo) == FALSE) {
return EFI_DEVICE_ERROR;
}
//
// Read byte data from I2C Bus
//
*Data = I2cReceiveByte (PciIo);
//
// Send ACK signal onto I2C Bus
//
I2cSendAck (PciIo);
//
// Stop a I2C transfer
//
I2cStop (PciIo);
return EFI_SUCCESS;
}
/**
Write one byte data onto I2C Bus.
Write one byte data to the slave device connectet to I2C Bus.
If Data is NULL, then ASSERT().
@param PciIo The pointer to PCI_IO_PROTOCOL.
@param DeviceAddress Slave device's address.
@param RegisterAddress The register address on slave device.
@param Data The pointer to write data.
@retval EFI_DEVICE_ERROR
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
I2cWriteByte (
EFI_PCI_IO_PROTOCOL *PciIo,
UINT8 DeviceAddress,
UINT8 RegisterAddress,
UINT8 *Data
)
{
ASSERT (Data != NULL);
I2cStart (PciIo);
//
// Send slave address with enabling write flag
//
I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
//
// Wait for ACK signal
//
if (I2cWaitAck (PciIo) == FALSE) {
return EFI_DEVICE_ERROR;
}
//
// Send register address
//
I2cSendByte (PciIo, RegisterAddress);
//
// Wait for ACK signal
//
if (I2cWaitAck (PciIo) == FALSE) {
return EFI_DEVICE_ERROR;
}
//
// Send byte data onto I2C Bus
//
I2cSendByte (PciIo, *Data);
//
// Wait for ACK signal
//
if (I2cWaitAck (PciIo) == FALSE) {
return EFI_DEVICE_ERROR;
}
//
// Stop a I2C transfer
//
I2cStop (PciIo);
return EFI_SUCCESS;
}