--- /dev/null
+/** @file\r
+ I2C Bus implementation upon CirrusLogic.\r
+\r
+ Copyright (c) 2008 - 2009, Intel Corporation\r
+ All rights reserved. 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 "CirrusLogic5430.h"\r
+#include "CirrusLogic5430I2c.h"\r
+\r
+#define SEQ_ADDRESS_REGISTER 0x3c4\r
+#define SEQ_DATA_REGISTER 0x3c5\r
+\r
+#define I2C_CONTROL 0x08\r
+#define I2CDAT_IN 7\r
+#define I2CCLK_IN 2\r
+#define I2CDAT_OUT 1\r
+#define I2CCLK_OUT 0\r
+\r
+#define I2C_BUS_SPEED 100 //100kbps\r
+\r
+/**\r
+ PCI I/O byte write function.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param Address The bit map of I2C Data or I2C Clock pins.\r
+ @param Data The date to write.\r
+\r
+**/\r
+VOID\r
+I2cOutb (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINTN Address,\r
+ UINT8 Data\r
+ )\r
+{\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Address,\r
+ 1,\r
+ &Data\r
+ );\r
+}\r
+/**\r
+ PCI I/O byte read function.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param Address The bit map of I2C Data or I2C Clock pins.\r
+\r
+ return byte value read from PCI I/O space.\r
+\r
+**/\r
+UINT8\r
+I2cInb (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINTN Address\r
+ )\r
+{\r
+ UINT8 Data;\r
+\r
+ PciIo->Io.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Address,\r
+ 1,\r
+ &Data\r
+ );\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Read status of I2C Data and I2C Clock Pins.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param Blt The bit map of I2C Data or I2C Clock pins.\r
+\r
+ @retval 0 Low on I2C Data or I2C Clock Pin.\r
+ @retval 1 High on I2C Data or I2C Clock Pin.\r
+\r
+**/\r
+UINT8\r
+I2cPinRead (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINT8 Bit\r
+ )\r
+{\r
+ I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);\r
+ return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe);\r
+}\r
+\r
+\r
+/**\r
+ Set/Clear I2C Data and I2C Clock Pins.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param Blt The bit map to controller I2C Data or I2C Clock pins.\r
+ @param Value 1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins.\r
+\r
+**/\r
+VOID\r
+I2cPinWrite (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINT8 Bit,\r
+ UINT8 Value\r
+ )\r
+{\r
+ UINT8 Byte;\r
+ I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);\r
+ Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ;\r
+ Byte = (UINT8) (Byte | ((Value & 0x01) << Bit));\r
+ I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40));\r
+ return;\r
+}\r
+\r
+/**\r
+ Read/write delay acoording to I2C Bus Speed.\r
+\r
+**/\r
+VOID\r
+I2cDelay (\r
+ VOID\r
+ )\r
+{\r
+ MicroSecondDelay (1000 / I2C_BUS_SPEED);\r
+}\r
+\r
+/**\r
+ Write a 8-bit data onto I2C Data Pin.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param Data The byte data to write.\r
+\r
+**/\r
+VOID\r
+I2cSendByte (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINT8 Data\r
+ )\r
+{\r
+ UINTN Index;\r
+ //\r
+ // Send byte data onto I2C Bus\r
+ //\r
+ for (Index = 0; Index < 8; Index --) {\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index)));\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);\r
+ I2cDelay ();\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);\r
+ }\r
+}\r
+\r
+/**\r
+ Read a 8-bit data from I2C Data Pin.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+\r
+ Return the byte data read from I2C Data Pin.\r
+**/\r
+UINT8\r
+I2cReceiveByte (\r
+ EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ UINT8 Data;\r
+ UINTN Index;\r
+\r
+ Data = 0;\r
+ //\r
+ // Read byte data from I2C Bus\r
+ //\r
+ for (Index = 0; Index < 8; Index --) {\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);\r
+ I2cDelay ();\r
+ Data = (UINT8) (Data << 1);\r
+ Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN));\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);\r
+ }\r
+\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Receive an ACK signal from I2C Bus.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+\r
+**/\r
+BOOLEAN\r
+I2cWaitAck (\r
+ EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);\r
+ I2cDelay ();\r
+ if (I2cPinRead (PciIo, I2CDAT_IN) == 0) {\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Send an ACK signal onto I2C Bus.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+\r
+**/\r
+VOID\r
+I2cSendAck (\r
+ EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);\r
+}\r
+\r
+/**\r
+ Start a I2C transfer on I2C Bus.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+\r
+**/\r
+VOID\r
+I2cStart (\r
+ EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ //\r
+ // Init CLK and DAT pins\r
+ //\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);\r
+ //\r
+ // Start a I2C transfer, set SDA low from high, when SCL is high\r
+ //\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);\r
+}\r
+\r
+/**\r
+ Stop a I2C transfer on I2C Bus.\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+\r
+**/\r
+VOID\r
+I2cStop (\r
+ EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ //\r
+ // Stop a I2C transfer, set SDA high from low, when SCL is high\r
+ //\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);\r
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);\r
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);\r
+}\r
+\r
+/**\r
+ Read one byte data on I2C Bus.\r
+\r
+ Read one byte data from the slave device connectet to I2C Bus.\r
+ If Data is NULL, then ASSERT().\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param DeviceAddress Slave device's address.\r
+ @param RegisterAddress The register address on slave device.\r
+ @param Data The pointer to returned data if EFI_SUCCESS returned.\r
+\r
+ @retval EFI_DEVICE_ERROR\r
+ @retval EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cReadByte (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINT8 DeviceAddress,\r
+ UINT8 RegisterAddress,\r
+ UINT8 *Data\r
+ )\r
+{\r
+ ASSERT (Data != NULL);\r
+\r
+ //\r
+ // Start I2C transfer\r
+ //\r
+ I2cStart (PciIo);\r
+\r
+ //\r
+ // Send slave address with enabling write flag\r
+ //\r
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));\r
+\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ if (I2cWaitAck (PciIo) == FALSE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Send register address\r
+ //\r
+ I2cSendByte (PciIo, RegisterAddress);\r
+\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ if (I2cWaitAck (PciIo) == FALSE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Send slave address with enabling read flag\r
+ //\r
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01));\r
+\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ if (I2cWaitAck (PciIo) == FALSE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Read byte data from I2C Bus\r
+ //\r
+ *Data = I2cReceiveByte (PciIo);\r
+\r
+ //\r
+ // Send ACK signal onto I2C Bus\r
+ //\r
+ I2cSendAck (PciIo);\r
+\r
+ //\r
+ // Stop a I2C transfer\r
+ //\r
+ I2cStop (PciIo);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write one byte data onto I2C Bus.\r
+\r
+ Write one byte data to the slave device connectet to I2C Bus.\r
+ If Data is NULL, then ASSERT().\r
+\r
+ @param PciIo The pointer to PCI_IO_PROTOCOL.\r
+ @param DeviceAddress Slave device's address.\r
+ @param RegisterAddress The register address on slave device.\r
+ @param Data The pointer to write data.\r
+\r
+ @retval EFI_DEVICE_ERROR\r
+ @retval EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cWriteByte (\r
+ EFI_PCI_IO_PROTOCOL *PciIo,\r
+ UINT8 DeviceAddress,\r
+ UINT8 RegisterAddress,\r
+ UINT8 *Data\r
+ )\r
+{\r
+ ASSERT (Data != NULL);\r
+\r
+ I2cStart (PciIo);\r
+ //\r
+ // Send slave address with enabling write flag\r
+ //\r
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));\r
+\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ if (I2cWaitAck (PciIo) == FALSE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Send register address\r
+ //\r
+ I2cSendByte (PciIo, RegisterAddress);\r
+\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ if (I2cWaitAck (PciIo) == FALSE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Send byte data onto I2C Bus\r
+ //\r
+ I2cSendByte (PciIo, *Data);\r
+\r
+ //\r
+ // Wait for ACK signal\r
+ //\r
+ if (I2cWaitAck (PciIo) == FALSE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Stop a I2C transfer\r
+ //\r
+ I2cStop (PciIo);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r