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