--- /dev/null
+/** @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