| /** @file | |
| I2C Bus implementation upon CirrusLogic. | |
| Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "CirrusLogic5430.h" | |
| #include "CirrusLogic5430I2c.h" | |
| #define SEQ_ADDRESS_REGISTER 0x3c4 | |
| #define SEQ_DATA_REGISTER 0x3c5 | |
| #define I2C_CONTROL 0x08 | |
| #define I2CDAT_IN 7 | |
| #define I2CCLK_IN 2 | |
| #define I2CDAT_OUT 1 | |
| #define I2CCLK_OUT 0 | |
| #define I2C_BUS_SPEED 100 //100kbps | |
| /** | |
| PCI I/O byte write function. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param Address The bit map of I2C Data or I2C Clock pins. | |
| @param Data The date to write. | |
| **/ | |
| VOID | |
| I2cOutb ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINTN Address, | |
| UINT8 Data | |
| ) | |
| { | |
| PciIo->Io.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| Address, | |
| 1, | |
| &Data | |
| ); | |
| } | |
| /** | |
| PCI I/O byte read function. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param Address The bit map of I2C Data or I2C Clock pins. | |
| return byte value read from PCI I/O space. | |
| **/ | |
| UINT8 | |
| I2cInb ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINTN Address | |
| ) | |
| { | |
| UINT8 Data; | |
| PciIo->Io.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| Address, | |
| 1, | |
| &Data | |
| ); | |
| return Data; | |
| } | |
| /** | |
| Read status of I2C Data and I2C Clock Pins. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param Blt The bit map of I2C Data or I2C Clock pins. | |
| @retval 0 Low on I2C Data or I2C Clock Pin. | |
| @retval 1 High on I2C Data or I2C Clock Pin. | |
| **/ | |
| UINT8 | |
| I2cPinRead ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINT8 Bit | |
| ) | |
| { | |
| I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL); | |
| return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe); | |
| } | |
| /** | |
| Set/Clear I2C Data and I2C Clock Pins. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param Blt The bit map to controller I2C Data or I2C Clock pins. | |
| @param Value 1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins. | |
| **/ | |
| VOID | |
| I2cPinWrite ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINT8 Bit, | |
| UINT8 Value | |
| ) | |
| { | |
| UINT8 Byte; | |
| I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL); | |
| Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ; | |
| Byte = (UINT8) (Byte | ((Value & 0x01) << Bit)); | |
| I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40)); | |
| return; | |
| } | |
| /** | |
| Read/write delay acoording to I2C Bus Speed. | |
| **/ | |
| VOID | |
| I2cDelay ( | |
| VOID | |
| ) | |
| { | |
| MicroSecondDelay (1000 / I2C_BUS_SPEED); | |
| } | |
| /** | |
| Write a 8-bit data onto I2C Data Pin. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param Data The byte data to write. | |
| **/ | |
| VOID | |
| I2cSendByte ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINT8 Data | |
| ) | |
| { | |
| UINTN Index; | |
| // | |
| // Send byte data onto I2C Bus | |
| // | |
| for (Index = 0; Index < 8; Index --) { | |
| I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index))); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 1); | |
| I2cDelay (); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 0); | |
| } | |
| } | |
| /** | |
| Read a 8-bit data from I2C Data Pin. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| Return the byte data read from I2C Data Pin. | |
| **/ | |
| UINT8 | |
| I2cReceiveByte ( | |
| EFI_PCI_IO_PROTOCOL *PciIo | |
| ) | |
| { | |
| UINT8 Data; | |
| UINTN Index; | |
| Data = 0; | |
| // | |
| // Read byte data from I2C Bus | |
| // | |
| for (Index = 0; Index < 8; Index --) { | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 1); | |
| I2cDelay (); | |
| Data = (UINT8) (Data << 1); | |
| Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN)); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 0); | |
| } | |
| return Data; | |
| } | |
| /** | |
| Receive an ACK signal from I2C Bus. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| **/ | |
| BOOLEAN | |
| I2cWaitAck ( | |
| EFI_PCI_IO_PROTOCOL *PciIo | |
| ) | |
| { | |
| // | |
| // Wait for ACK signal | |
| // | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 1); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 1); | |
| I2cDelay (); | |
| if (I2cPinRead (PciIo, I2CDAT_IN) == 0) { | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 1); | |
| return TRUE; | |
| } else { | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| Send an ACK signal onto I2C Bus. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| **/ | |
| VOID | |
| I2cSendAck ( | |
| EFI_PCI_IO_PROTOCOL *PciIo | |
| ) | |
| { | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 1); | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 1); | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 0); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 0); | |
| } | |
| /** | |
| Start a I2C transfer on I2C Bus. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| **/ | |
| VOID | |
| I2cStart ( | |
| EFI_PCI_IO_PROTOCOL *PciIo | |
| ) | |
| { | |
| // | |
| // Init CLK and DAT pins | |
| // | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 1); | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 1); | |
| // | |
| // Start a I2C transfer, set SDA low from high, when SCL is high | |
| // | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 0); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 0); | |
| } | |
| /** | |
| Stop a I2C transfer on I2C Bus. | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| **/ | |
| VOID | |
| I2cStop ( | |
| EFI_PCI_IO_PROTOCOL *PciIo | |
| ) | |
| { | |
| // | |
| // Stop a I2C transfer, set SDA high from low, when SCL is high | |
| // | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 0); | |
| I2cPinWrite (PciIo, I2CCLK_OUT, 1); | |
| I2cPinWrite (PciIo, I2CDAT_OUT, 1); | |
| } | |
| /** | |
| Read one byte data on I2C Bus. | |
| Read one byte data from the slave device connectet to I2C Bus. | |
| If Data is NULL, then ASSERT(). | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param DeviceAddress Slave device's address. | |
| @param RegisterAddress The register address on slave device. | |
| @param Data The pointer to returned data if EFI_SUCCESS returned. | |
| @retval EFI_DEVICE_ERROR | |
| @retval EFI_SUCCESS | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| I2cReadByte ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINT8 DeviceAddress, | |
| UINT8 RegisterAddress, | |
| UINT8 *Data | |
| ) | |
| { | |
| ASSERT (Data != NULL); | |
| // | |
| // Start I2C transfer | |
| // | |
| I2cStart (PciIo); | |
| // | |
| // Send slave address with enabling write flag | |
| // | |
| I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe)); | |
| // | |
| // Wait for ACK signal | |
| // | |
| if (I2cWaitAck (PciIo) == FALSE) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Send register address | |
| // | |
| I2cSendByte (PciIo, RegisterAddress); | |
| // | |
| // Wait for ACK signal | |
| // | |
| if (I2cWaitAck (PciIo) == FALSE) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Send slave address with enabling read flag | |
| // | |
| I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01)); | |
| // | |
| // Wait for ACK signal | |
| // | |
| if (I2cWaitAck (PciIo) == FALSE) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Read byte data from I2C Bus | |
| // | |
| *Data = I2cReceiveByte (PciIo); | |
| // | |
| // Send ACK signal onto I2C Bus | |
| // | |
| I2cSendAck (PciIo); | |
| // | |
| // Stop a I2C transfer | |
| // | |
| I2cStop (PciIo); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Write one byte data onto I2C Bus. | |
| Write one byte data to the slave device connectet to I2C Bus. | |
| If Data is NULL, then ASSERT(). | |
| @param PciIo The pointer to PCI_IO_PROTOCOL. | |
| @param DeviceAddress Slave device's address. | |
| @param RegisterAddress The register address on slave device. | |
| @param Data The pointer to write data. | |
| @retval EFI_DEVICE_ERROR | |
| @retval EFI_SUCCESS | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| I2cWriteByte ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINT8 DeviceAddress, | |
| UINT8 RegisterAddress, | |
| UINT8 *Data | |
| ) | |
| { | |
| ASSERT (Data != NULL); | |
| I2cStart (PciIo); | |
| // | |
| // Send slave address with enabling write flag | |
| // | |
| I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe)); | |
| // | |
| // Wait for ACK signal | |
| // | |
| if (I2cWaitAck (PciIo) == FALSE) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Send register address | |
| // | |
| I2cSendByte (PciIo, RegisterAddress); | |
| // | |
| // Wait for ACK signal | |
| // | |
| if (I2cWaitAck (PciIo) == FALSE) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Send byte data onto I2C Bus | |
| // | |
| I2cSendByte (PciIo, *Data); | |
| // | |
| // Wait for ACK signal | |
| // | |
| if (I2cWaitAck (PciIo) == FALSE) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Stop a I2C transfer | |
| // | |
| I2cStop (PciIo); | |
| return EFI_SUCCESS; | |
| } | |