summaryrefslogtreecommitdiffstats
path: root/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c')
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c1004
1 files changed, 1004 insertions, 0 deletions
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
new file mode 100644
index 0000000000..80f03eaf29
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
@@ -0,0 +1,1004 @@
+/** @file
+I2C Library for Quark I2C Controller.
+Follows I2C Controller setup instructions as detailed in
+Quark DataSheet (doc id: 329676) Section 19.1/19.1.3.
+
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+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 "CommonHeader.h"
+
+/**
+ The Called to Common Service Entry.
+
+ @return None.
+
+**/
+
+VOID
+I2cCommonServiceEntry (
+ OUT UINT16 *SaveCmdPtr,
+ OUT UINT32 *SaveBar0Ptr
+ )
+{
+ *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+ if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+
+ IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =
+ FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;
+
+ //
+ // also Save Cmd Register, Setup by InitializeInternal later during xfers.
+ //
+ *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);
+ }
+}
+
+/**
+ The Called on Common Service Exit.
+
+ @return None.
+
+**/
+VOID
+I2cCommonServiceExit (
+ IN CONST UINT16 SaveCmd,
+ IN CONST UINT32 SaveBar0
+
+ )
+{
+ if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+ IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;
+ IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;
+ }
+}
+
+
+/**
+ The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
+
+ Always reads PCI configuration space to get MMIO base address of I2C Controller.
+
+ @return The IO port base address of I2C controller.
+
+**/
+UINTN
+GetI2CIoPortBaseAddress (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+
+ //
+ // Make sure that the IO port base address has been properly set.
+ //
+ ASSERT (I2CIoPortBaseAddress != 0);
+ ASSERT (I2CIoPortBaseAddress != 0xFF);
+
+ return I2CIoPortBaseAddress;
+}
+
+
+/**
+ The EnableI2CMmioSpace() function enables access to I2C MMIO space.
+
+**/
+VOID
+EnableI2CMmioSpace (
+ VOID
+ )
+{
+ UINT8 PciCmd;
+
+ //
+ // Read PCICMD. Bus=0, Dev=0, Func=0, Reg=0x4
+ //
+ PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);
+
+ //
+ // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)
+ //
+ PciCmd |= 0x7;
+ IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;
+
+}
+
+/**
+ The DisableI2CController() functions disables I2C Controller.
+
+**/
+VOID
+DisableI2CController (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINT32 Addr;
+ UINT32 Data;
+ UINT8 PollCount;
+
+ PollCount = 0;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_ENABLE;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled
+ //
+ Data = 0xFF;
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;
+ Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;
+ while (Data != 0) {
+ //
+ // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).
+ //
+ PollCount++;
+ if (PollCount >= MAX_T_POLL_COUNT) {
+ break;
+ }
+ MicroSecondDelay(TI2C_POLL);
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= I2C_REG_ENABLE_STATUS;
+ }
+
+ //
+ // Asset if controller does not enter Disabled state.
+ //
+ ASSERT (PollCount < MAX_T_POLL_COUNT);
+
+ //
+ // Read IC_CLR_INTR register to automatically clear the combined interrupt,
+ // all individual interrupts and the IC_TX_ABRT_SOURCE register.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+ The EnableI2CController() function enables the I2C Controller.
+
+**/
+VOID
+EnableI2CController (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINT32 Addr;
+ UINT32 Data;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data |= B_I2C_REG_ENABLE;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Clear overflow and abort error status bits before transactions.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+ The WaitForStopDet() function waits until I2C STOP Condition occurs,
+ indicating transfer completion.
+
+ @retval EFI_SUCCESS Stop detected.
+ @retval EFI_TIMEOUT Timeout while waiting for stop condition.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Tx or Rx overflow detected.
+
+**/
+EFI_STATUS
+WaitForStopDet (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINT32 Addr;
+ UINT32 Data;
+ UINT32 PollCount;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ PollCount = 0;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Wait for STOP Detect.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+
+ do {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ MicroSecondDelay(TI2C_POLL);
+ PollCount++;
+ if (PollCount >= MAX_STOP_DET_POLL_COUNT) {
+ Status = EFI_TIMEOUT;
+ break;
+ }
+
+ } while (TRUE);
+
+ return Status;
+}
+
+/**
+
+ The InitializeInternal() function initialises internal I2C Controller
+ register values that are commonly required for I2C Write and Read transfers.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @retval EFI_SUCCESS I2C Operation completed successfully.
+
+**/
+EFI_STATUS
+InitializeInternal (
+ IN EFI_I2C_ADDR_MODE AddrMode
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Enable access to I2C Controller MMIO space.
+ //
+ EnableI2CMmioSpace ();
+
+ //
+ // Disable I2C Controller initially
+ //
+ DisableI2CController ();
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Clear START_DET
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_CLR_START_DET;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Clear STOP_DET
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_CLR_STOP_DET;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Set addressing mode to user defined (7 or 10 bit) and
+ // speed mode to that defined by PCD (standard mode default).
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CON;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ // Set Addressing Mode
+ if (AddrMode == EfiI2CSevenBitAddrMode) {
+ Data &= ~B_I2C_REG_CON_10BITADD_MASTER;
+ } else {
+ Data |= B_I2C_REG_CON_10BITADD_MASTER;
+ }
+ // Set Speed Mode
+ Data &= ~B_I2C_REG_CON_SPEED;
+ if (FeaturePcdGet (PcdI2CFastModeEnabled)) {
+ Data |= BIT2;
+ } else {
+ Data |= BIT1;
+ }
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ return Status;
+
+}
+
+/**
+
+ The WriteByte() function provides a standard way to execute a
+ standard single byte write to an IC2 device (without accessing
+ sub-addresses), as defined in the I2C Specification.
+
+ @param I2CAddress I2C Slave device address
+ @param Value The 8-bit value to write.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteByte (
+ IN UINTN I2CAddress,
+ IN UINT8 Value
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ //
+ // Get I2C Memory Mapped registers base address
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write the data and transfer direction to the IC_DATA_CMD register.
+ // Also specify that transfer should be terminated by STOP condition.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= (UINT8)Value;
+ Data &= ~B_I2C_REG_DATA_CMD_RW;
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Wait for transfer completion.
+ //
+ Status = WaitForStopDet ();
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController();
+
+ return Status;
+}
+
+/**
+
+ The ReadByte() function provides a standard way to execute a
+ standard single byte read to an IC2 device (without accessing
+ sub-addresses), as defined in the I2C Specification.
+
+ @param I2CAddress I2C Slave device address
+ @param ReturnDataPtr Pointer to location to receive read byte.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadByte (
+ IN UINTN I2CAddress,
+ OUT UINT8 *ReturnDataPtr
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write transfer direction to the IC_DATA_CMD register and
+ // specify that transfer should be terminated by STOP condition.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= B_I2C_REG_DATA_CMD_RW;
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Wait for transfer completion
+ //
+ Status = WaitForStopDet ();
+ if (!EFI_ERROR(Status)) {
+
+ //
+ // Clear RX underflow before reading IC_DATA_CMD.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ //
+ // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0x000000FF;
+ *ReturnDataPtr = (UINT8) Data;
+
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+ if (Data != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController ();
+
+ return Status;
+}
+
+/**
+
+ The WriteMultipleByte() function provides a standard way to execute
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+ when writing block of data), as defined in the I2C Specification.
+
+ @param I2CAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param WriteBuffer Contains the value of byte to be written to the
+ I2C slave device.
+
+ @param Length No. of bytes to be written.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteMultipleByte (
+ IN UINTN I2CAddress,
+ IN UINT8 *WriteBuffer,
+ IN UINTN Length
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Index;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ if (Length > I2C_FIFO_SIZE) {
+ return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.
+ }
+
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write the data and transfer direction to the IC_DATA_CMD register.
+ // Also specify that transfer should be terminated by STOP condition.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ for (Index = 0; Index < Length; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= (UINT8)WriteBuffer[Index];
+ Data &= ~B_I2C_REG_DATA_CMD_RW;
+ if (Index == (Length-1)) {
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ }
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+ }
+
+ //
+ // Wait for transfer completion
+ //
+ Status = WaitForStopDet ();
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController ();
+ return Status;
+}
+
+/**
+
+ The ReadMultipleByte() function provides a standard way to execute
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+ when reading block of data), as defined in the I2C Specification (I2C combined
+ write/read protocol).
+
+ @param I2CAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param Buffer Contains the value of byte data written or read from the
+ I2C slave device.
+
+ @param WriteLength No. of bytes to be written. In this case data
+ written typically contains sub-address or sub-addresses
+ in Hi-Lo format, that need to be read (I2C combined
+ write/read protocol).
+
+ @param ReadLength No. of bytes to be read from I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadMultipleByte (
+ IN UINTN I2CAddress,
+ IN OUT UINT8 *Buffer,
+ IN UINTN WriteLength,
+ IN UINTN ReadLength
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Index;
+ UINTN Addr;
+ UINT32 Data;
+ UINT8 PollCount;
+ EFI_STATUS Status;
+
+ if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {
+ return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.
+ }
+
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write the data (sub-addresses) to the IC_DATA_CMD register.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ for (Index = 0; Index < WriteLength; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= (UINT8)Buffer[Index];
+ Data &= ~B_I2C_REG_DATA_CMD_RW;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+ }
+
+ //
+ // Issue Read Transfers for each byte (Restart issued when write/read bit changed).
+ //
+ for (Index = 0; Index < ReadLength; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data |= B_I2C_REG_DATA_CMD_RW;
+ // Issue a STOP for last read transfer.
+ if (Index == (ReadLength-1)) {
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ }
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+ }
+
+ //
+ // Wait for STOP condition.
+ //
+ Status = WaitForStopDet ();
+ if (!EFI_ERROR(Status)) {
+
+ //
+ // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).
+ //
+ Data = 0;
+ PollCount = 0;
+ Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {
+ MicroSecondDelay(TI2C_POLL);
+ PollCount++;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ }
+
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ //
+ // If no timeout or device error then read rx data.
+ //
+ if (PollCount == MAX_T_POLL_COUNT) {
+ Status = EFI_TIMEOUT;
+ } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+
+ //
+ // Clear RX underflow before reading IC_DATA_CMD.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ //
+ // Read data.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ for (Index = 0; Index < ReadLength; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0x000000FF;
+ *(Buffer+Index) = (UINT8)Data;
+ }
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+ if (Data != 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController ();
+
+ return Status;
+}
+
+/**
+
+ The I2cWriteByte() function is a wrapper function for the WriteByte function.
+ Provides a standard way to execute a standard single byte write to an IC2 device
+ (without accessing sub-addresses), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Buffer Contains the value of byte data to execute to the
+ I2C slave device.
+
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 = 0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);
+ }
+
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+/**
+
+ The I2cReadByte() function is a wrapper function for the ReadByte function.
+ Provides a standard way to execute a standard single byte read to an I2C device
+ (without accessing sub-addresses), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Buffer Contains the value of byte data read from the
+ I2C slave device.
+
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 =0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = ReadByte (I2CAddress, (UINT8 *) Buffer);
+ }
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+/**
+
+ The I2cWriteMultipleByte() function is a wrapper function for the
+ WriteMultipleByte() function. Provides a standard way to execute multiple
+ byte writes to an I2C device (e.g. when accessing sub-addresses or writing
+ block of data), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Length No. of bytes to be written.
+
+ @param Buffer Contains the value of byte to be written to the
+ I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteMultipleByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN UINTN *Length,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 =0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));
+ }
+
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+/**
+
+ The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.
+ Provides a standard way to execute multiple byte writes to an I2C device
+ (e.g. when accessing sub-addresses or when reading block of data), as defined
+ in the I2C Specification (I2C combined write/read protocol).
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param WriteLength No. of bytes to be written. In this case data
+ written typically contains sub-address or sub-addresses
+ in Hi-Lo format, that need to be read (I2C combined
+ write/read protocol).
+
+ @param ReadLength No. of bytes to be read from I2C slave device.
+
+ @param Buffer Contains the value of byte data read from the
+ I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer
+ pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadMultipleByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN UINTN *WriteLength,
+ IN UINTN *ReadLength,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 =0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));
+ }
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+