| /** @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; | |
| } | |