mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 03:57:26 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10425 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			434 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			434 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  I2C Bus implementation upon CirrusLogic.
 | 
						|
 | 
						|
  Copyright (c) 2008 - 2009, Intel Corporation. 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 "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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 |