17. I2C Protocol Stack

17.1. Design Discussion

The Inter-Integrated Circuit (I2C) protocol stack enables third party silicon vendors to write UEFI drivers for their products by decoupling the I2C chip details from the I2C controller and I2C bus configuration details.

17.1.1. I2C Bus Overview

` <http://www.acpi.info/spec.htm>`__The Inter-Integrated Circuit (|I2C|) bus enables simple low speed communications between chips. The following sections describe the attributes of the |I2C| bus configurations supported by the |I2C| protocol stack and the |I2C|-bus specification and user manual .

17.1.1.1. SingleMaster

_images/V5_I2C_Protocol_Stack-2.png

Fig. 17.1 Simple 12C Bus

Simple 12C Bus shows a simple I2C bus configuration consisting of one host controller and two I2C devices which use the same I2C clock frequency. In this configuration the I2C host controller gets initialized with a single clock frequency and performs transactions to the I2C devices using their slave addresses.

17.1.1.2. Multiple I2C Bus Frequencies

_images/V5_I2C_Protocol_Stack-3.png

Fig. 17.2 Multiple I2C Bus Frequencies

Two I2C bus configurations are shown in Multiple I2C Bus Frequencies, separated by a switch. This allows the I2C bus to operate at two different frequencies depending on the state of the switch. Device requiring higher bus frequencies are placed closer to the I2C host controller and are accessed when the switch is turned off. Devices using lower bus frequencies are placed after the switch and may only be accessed when the switch is on. Note that the I2C bus frequency needs to be set to a frequency supported by all devices currently accessible by the I2C host controller.

17.1.1.3. Limited Address Space

_images/V5_I2C_Protocol_Stack-4.png

Fig. 17.3 Limited Address Space

|I2C| devices have a limited number of address settings, sometimes only one. When the hardware design requires more |I2C| devices than the address space supports a multiplexer may be introduced to create additional bus configurations (address spaces). Note that the host must first select the appropriate bus configuration before communicating with the |I2C| device.

17.1.1.4. I2C Bus Configurations

A bus configuration is a concept introduced by the I2C protocol stack to configure the state of the switches and multiplexers in the I2C bus. The I2C protocol stack calls into the platform code with a value from zero (0) to N-1 to request the platform code enable a specific configuration of the switches and multiplexers. The platform code then sets the requested state for the switches and multiplexers and sets the I2C clock frequency for this I2C bus configuration. Upon return the I2C protocol stack is able to access the I2C devices in this configuration.

17.1.2. 2C Protocol Stack Overview

The following is a representation of the I2C protocol stack and an I2C bus layout.

_images/V5_I2C_Protocol_Stack-12.png

Fig. 17.4 I2C Protocol Stack

I2C Protocol Stack The platform hardware designer chooses the bus layout based upon the platform, I2C chip and software requirements. The design uses switches to truncate the bus to enable higher bus frequencies for a subset of devices which are placed closer to the controller. When the switch is on, the extended bus must operate at a lower bus frequency. The design uses multiplexer to create separate address spaces enabling the use of multiple devices which would otherwise have conflicting addresses. See the |I2C|-bus specification and user manual for more details.

N.B. Some operating systems may prohibit the changing of switches and multiplexers in the I2C bus. In this case the platform hardware and software designers must select a single I2C bus configuration consisting of constant input values for the switches and multiplexers. The I2C subsystem must be placed in the OS compatible I2C bus configuration upon successful completion of ExitBootServices() .

The platform hardware designer needs to provide the platform software designer the following data for each I2C bus:

  1. Which controller controls this bus

  2. A list of logic blocks contained in one or more I2C devices:

    • I2C device which contains this logic block

    • Logic block I2C slave address

    • Logic block description

  3. For each configuration of the switches and multiplexers in the I2C bus

    • What is the maximum frequency of operation for the I2C bus

    • What I2C slave addresses are accessible

  4. The settings for the switches and multiplexers when control is given to the operating system.

17.1.2.1. Handles

The I2C protocol stack uses two groups of handles:

  • I2C controller handles

  • I2C device handles

Some bus driver (PCI, USB, etc.) or the platform specific code may expose a handle for each of the I2C controllers. The platform specific code installs the I2C bus configuration management and I2C enumeration protocols on the controller handle. As the I2C stack is initialized, additional protocols are placed on the I2C controller handle. When the I2C stack initialization is complete, the controller handle contains:

_images/V5_I2C_Protocol_Stack-5.png

Fig. 17.5 Controller Handle After I2C Stack Initialization

The I2C Bus Driver uses the EFI_I2C_ENUMERATE_PROTOCOL to enumerate the set of I2C devices connected to an I2C controller, and creates an I2C device handle for each I2C device installing the following protocols on each:

_images/V5_I2C_Protocol_Stack-6.png

Fig. 17.6 I2C Protocol Stack after EFI_I2C_ENUMERATE_PROTOCOL

It is possible for the SMBus Host Controller Protocol to be implemented using the services on an I2C Controller Handle. The SMBus Host Controller Protocol does not support the concept of multiple bus configurations, so the state of the I2C controller handle required for the SMBus Host Controller Protocol to be produced on an I2C Controller Handle is as follows:

_images/V5_I2C_Protocol_Stack-7.png

Fig. 17.7 State of the Required I2C Controller Handle

17.1.2.2. Driver Loading Order

A race condition potentially exists between the platform specific code and a layered SMBus driver when a driver for a PCI or USB I2C controller installs the EFI_I2C_MASTER_PROTOCOL on its handle. The layered SMBus driver may start on this controller as soon as the EFI_I2C_MASTER_PROTOCOL is installed as long as the EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL is not installed on the controller handle. However if the platform specific code wants to use this controller with the EFI_I2C_HOST_PROTOCOL then the platform specific code needs to prevent the SMBus driver from starting by installing the EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL . Note that the I2C host protocol opens the EFI_I2C_MASTER_PROTOCOL only if the handle contains the EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL .

Chapter 10 of the Universal Extensible Firmware Interface Specification describes several ways for the platform specific code to adjust the driver load order. One possible way to eliminate this race condition is to use the version number for the driver binding protocol. The platform specific code implements the driver binding protocol’s Supported() and Start() routines and sets the version field to a value in the range of 0xfffffff0 - 0xffffffff . The SMBus driver should set the version field of the driver binding protocol to a value in the range of 0x00000010 - 0xffffffef . This selection delays the SMBus driver to execute its Supported() and Start() routines after the platform specific code, enabling the platform specific code to install the EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL and the EFI_I2C_ENUMERATE_PROTOCOL on the controller’s handle.

17.1.2.3. Third Party I2C Drivers

Third party I2C drivers are I2C chip specific but platform and host controller independent.

Third party I2C driver writers, typically silicon vendors, need to provide:

  • The vendor specific GUID that is used to select their driver.

  • I2C slave address array guidance (described below) when the I2C device uses more than one I2C slave address consisting of the order for the blocks of logic that get referenced by the entries in the slave address array.

The hardware version of the I2C device, this value is passed to the third party I2C driver to enable it to perform workarounds for the specific hardware version. It is recommended that value match the value in the ACPI _HRV tag. See the Advanced Configuration and Power Interface Specification, Revision 5.0 for the field format and the Plug and play support for |I2C| web-page for restriction on values.

The third party I2C driver uses relative addressing to abstract the platform specific details of the I2C device. Using an example I2C device containing an accelerometer and a magnetometer which consumes two I2C slave addresses, one for each logic block. The third party I2C driver writer may choose to write two drivers, one for each block of logic, in which case each driver refers to the single I2C slave address using the relative value of zero (0). However if the third party I2C driver writer chooses to write a single driver which consumes multiple I2C slave addresses then the third party I2C driver writer needs to convey the order of the I2C slave address entries in the I2C slave address array to the platform software designer. For the example:

0: Accelerometer
1: Magnetometer

The platform hardware designer picks the actual slave addresses from the I2C device’s data sheet and provides this information to the platform software designer. The platform software designer then places the I2C slave addresses into the I2C slave address array in the EFI_I2C_ENUMERATE_PROTOCL in the order specified by the third party I2C driver writer. The third party I2C driver writer uses the index into the I2C slave address array as the relative I2C slave address. The I2C IO protocol uses the I2C slave address array to translate the relative I2C slave address into the platform specific I2C slave address. The relative value always starts at zero (0) and its maximum value is the number of entries in I2C slave address array minus one.

Each I2C slave address entry is specified as a 32-bit integer to allow room for future I2C slave address expansion. Only the I2C master protocol knows the maximum I2C slave address value. All other drivers and applications must look for the EFI_NOT_FOUND status for the indication that a reserve bit was set in the I2C slave address.

_images/V5_I2C_Protocol_Stack-8.png

Fig. 17.8 v5 i2c protocol stack

_images/V5_I2C_Protocol_Stack-9.png

Fig. 17.9 v5 i2c protocol stack

17.1.2.3.1. Driver Binding Protocol Supported() API

The driver binding protocol’s Supported() routine looks for controllers which declare the EFI_I2C_IO_PROTOCOL and match the device path supplied by the silicon vendor or third party I2C driver writer to the platform integrator.

The third party I2C device driver creates a GUID for a Vendor-Defined Hardware Device Path Node when describing the I2C device. The third party I2C device driver writer provides this GUID to the person writing the platform specific code to identify the type of I2C device.

The third party I2C driver which consumes the EFI_I2C_IO_PROTOCOL compares the known GUID with the GUID pointed to by the DeviceGuid field.

An example algorithm for the driver binding protocol Supported() routine:

  1. Open the EFI_I2C_IO_PROTOCOL using EFI_OPEN_PROTOCOL_BY_DRIVER

  2. If OpenProtocol() fails return the error status

  3. Get the vendor GUID from the EFI_I2C_IO_PROTOCOL

  4. Close the EFI_I2C_IO_PROTOCOL

  5. Compare the expected vendor GUID to the GUID from the EFI_I2C_IO_PROTOCOL structure.

  6. If the GUIDS don’t match then return EFI_NOT_SUPPORTED

  7. Return EFI_SUCCESS

17.1.2.3.2. Supporting Multiple Hardware Versions

Note that package markings are important to allow the platform integrator to verify the hardware revision after the part is integrated! The platform integrator includes the hardware revision information into the EFI_I2C_ENUMERATE_PROTOCOL . The I2C bus driver gets this data during the I2C device enumeration and makes it available to the third party I2C device driver via the EFI_I2C_IO_PROTOCOL . There are a couple of ways in which the silicon vendor or third party I2C driver writer may support multiple hardware versions of the I2C device:

  • Provide a different GUID value to the platform integrator for each hardware revision

  • Provide a different hardware version value to the platform integrator with the devices

Each of the above methods describes an interface to the I2C device. The interface specifies the number of slave addresses as well as the features and software workarounds for the I2C device.

17.1.2.4. I2C IO Protocol

The I2C IO protocol is platform, host controller, and I2C chip independent.

The I2C bus driver creates a handle for each of the I2C devices returned by the I2C enumerate protocol. The I2C controller’s device path is extended with the vendor GUID and unique ID value returned by the I2C enumerate protocol and attached to the handle. The vendor GUID is used to extend the device path with a Vendor-define Hardware Device Path Node and the unique ID is used to further extend the device path with a Controller Device Path Node. If the unique ID is 0, then the Controller Device Path Node is optional. The third party I2C device driver uses the device GUID to determine if it may connect.

When a third party I2C device driver or application calls QueueRequest() , the I2C IO protocol validates the SlaveAddressIndex (relative I2C address) for the I2C device and then converts the SlaveAddressIndex to a I2C slave address. The request is then passed to the I2C host protocol along with the tuple BusConfiguration:I2C slave address.

17.1.2.5. I2C Host Protocol

The I2C host protocol is platform, host controller, and I2C chip independent.

Note

For proper operation of the I2C bus, only the I2C IO protocol and I2C test applications connect to the EFI_I2C_HOST_PROTOCOL .

The I2C host protocol may access any device on the I2C bus. The I2C host protocol has the following responsibilities:

  • Limits the number of requests to the I2C master protocol to one. The I2C host protocol holds on to additional requests until the I2C master protocol is available to process the request. The I2C requests are issued in FIFO order to the I2C master protocol.

  • Enable the proper I2C bus configuration before starting the I2C request using the I2C master protocol

I2C devices are addressed as the tuple: BusConfiguration:SlaveAddress. I2C bus configuration zero (0) is the portion of the I2C bus that connects to the host controller. The bus configuration specifies the control values for the switches and multiplexers in the I2C bus. After the switches and multiplexers are properly configured, the I2C controller uses the slave address to access the requested I2C device.

Since the I2C protocol stack supports asynchronous transactions the I2C host protocol maintains a queue of I2C requests until the I2C controller is available them. When a request reaches the head of the queue the necessary bus configuration is enabled and then the request is sent to the I2C master protocol.

17.1.2.6. I2C Master Protocol

The I2C master protocol is I2C controller specific but platform independent.

This protocol is designed to allow the implementation to be built as a driver which may be delivered in binary form as an EFI image.

The master protocol manipulates the I2C controller to perform a transaction on the I2C bus. The I2C master protocol does not configure the I2C bus so it is up to the caller to ensure that the I2C bus is in the proper configuration before issuing the I2C request.

The I2C master protocol typically needs the following information:

  • Host controller address

  • Controller’s input clock frequency

Depending upon the I2C controller, more data may be necessary. This protocol may use any method to get these values: hard coded values, PCD values, or may choose to communicate with the platform specific code using an undefined mechanism to get these values.

If the I2C master protocol requires data from the platform specific code then the I2C master protocol writer needs to provide the platform interface details to the platform software designer.

17.1.2.7. Platform Specific Code

The platform specific code installs the EFI_I2C_ENUMERATE_PROTOCOL to provide the I2C device descriptions to the I2C bus driver using the EFI_I2C_DEVICE structure. These descriptions include the bus configuration number required for the I2C device, the slave address array, the vendor GUID and a unique ID value.

The EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL enables the I2C host protocol to call into the platform specific code to enable a specific I2C bus configuration and set the I2C bus frequency. This protocol is required to get the I2C host protocol to start for the I2C controller’s handle.

The platform software designer collects the data requirements from third party I2C driver writers, the vendor specific I2C master protocol writer, the EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL and EFI_I2C_ENUMERATE_PROTOCOL . The platform software designer gets the necessary data from the platform hardware designer. The platform software designer then builds the data structures and implements the necessary routines to construct the platform specific code for I2C.

17.1.2.8. Switches and Multiplexers

There are some I2C switches and I2C multiplexers where the control is done via I2C commands. When the control inputs come via the same I2C bus that is being configured then the platform specific code must use the EFI_I2C_MASTER_PROTOCOL . While the I2C host protocol makes the call to EnableI2cBusConfiguration to configure the I2C bus, the I2C host protocol keeps the I2C master protocol idle, enabling the platform specific code to perform the necessary I2C configuration transactions.

If however the configuration control is done via an I2C device connected to a different I2C bus (host controller), then the platform software designer may choose between the following:

  • Call into a third party I2C driver to manipulate the I2C bus control device.

  • Call into the EFI_I2C_IO_PROTOCOL if no third party I2C driver exists for the I2C bus control device

  • Call into the EFI_I2C_HOST_PROTOCOL if the platform does not expose the I2C bus control device.

17.1.3. PCI Comparison

PCI provides several features to describe the device to the operating system as well decoupling the driver from the specific platform.

17.1.3.1. Device Description

PCI uses the Vendor ID and Device ID fields in configuration space to identify the piece of hardware. Where the Vendor ID is assigned by the PCI committee and the Device ID is assigned by the hardware manufacture.

PCI also uses the Base Class , Sub Class and Programming Interface fields to help identify the operating system driver.

The I2C protocol stack uses the vendor GUID associated with the I2C device to identify the UEFI driver. This GUID is supplied by the silicon vendor or third party I2C driver writer to the platform integrator and gets included in the I2C platform driver. The EFI_I2C_ENUMERATE_PROTOCOL provides this GUID to the I2C bus driver during the I2C bus enumeration.

The driver binding protocol’s Supported() routine of the third party I2C device driver looks for controllers which have the EFI_I2C_IO_PROTOCOL and have a match for the vendor GUID.

17.1.3.2. Hardware Features and Workarounds

PCI provides a Revision ID field to allow the driver to determine which version of hardware is present and which features and software workarounds are necessary to support this device.

The I2C protocol stack uses the HardwareRevision field in the EFI_I2C_IO_PROTOCOL for this same purpose. It is recommended that this value match the _HRV value in the DSDT for this I2C device. See the Advanced Configuration and Power Interface Specification, Revision 5.0 for the field format and the Plug and play support for |I2C| web-page for restriction on values.

17.1.3.3. Device Relative Addressing

PCI provides Base Address Registers (BARs) to decouple the device driver software from the details of the platform’s PCI bus configuration. Typically, all device register references are fixed offsets from one of the BAR addresses.

The I2C protocol stack provides a similar mechanism using an index into an array of slave addresses. The silicon vendor or third party driver writer provides the structure of the array listing the major functions to the platform integrator. An example is:

0: Accelerometer
1: Compass

The platform integrator works with the platform’s hardware designer to get the I2C slave addresses of the I2C device and builds the array which is included in the platform specific code. During I2C device enumeration, this array is passed to the I2C bus driver for use by the I2C IO protocol.

The third party I2C driver references the major components within the I2C device using the index values, thus remaining platform independent. The I2C IO protocol performs the array lookup, translating the index into an actual slave address on the I2C bus.

Most I2C devices only have a single I2C slave address and thus the third party I2C device driver will only use index zero (0). Also depending upon the I2C device architecture, the silicon vendor or third party I2C device writer may choose to write multiple drivers, each supporting a single I2C slave address.

17.1.4. Hot Plug Support

I2C protocol stack enables the platform specific code to support hot-plug with the following algorithm:

  1. Describe all possible devices on all possiblebusses, including the hot-plug devices.

  2. The platform specific code detects hot-plug events: Add and Remove

  3. For a removal event:

    • The platform specific code opens the EFI_I2C_IO_PROTOCOL on the hot-plug device’s handle exclusively. This operation tears down any upper layer protocols on this handle. Note that the open request may fail if I/O is pending in the lower protocols.

    • When the step above fails, delay below TPL_NOTIFY to allow the current I

    • 2C transaction complete and then retry until the open is successful

    • After the open is successful, the platform specific code may use the I

    • 2C IO protocol to perform I2C transactions for device probing.

  4. For an add event:

    • The platform specific code waits for completion any outstanding I/O that the platform specific code initiated on the hot-plug I2C device.

    • The platform specific code closes the EFI_I2C_IO_PROTOCOL

    • The platform specific code issues a ConnectController() on the hot-plug device’s handle. This causes the protocol stack which uses the hot-plug device to be reloaded.

17.2. DXE Code definitions

The I2C protocol stack consists of the following protocols:

  • EFI_I2C_IO_PROTOCOL - Third party silicon vendors use this protocol to access their I2C device. This protocol enables a driver or application to perform I/O transactions to a single I2C device independent of the I2C bus configuration.

  • EFI_I2C_HOST_PROTOCOL - The I2C bus driver uses this protocol to produce the EFI_I2C_IO_PROTOCOL that provides access a device on the I2C bus.

  • EFI_I2C_MASTER_PROTOCOL - The I2C host protocol uses this protocol to manipulate the I2C host controller and perform transactions as a master on the I2C bus.

  • EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL - The I2C host protocol uses this protocol to request the proper state for the switches and multiplexers in the I2C bus and set the I2C clock frequency.

  • EFI_I2C_ENUMERATE_PROTOCOL - The I2C bus driver uses this protocol to enumerate the devices on the I2C bus, getting the bus configuration and an array of slave addresses for each of the I2C devices.

The following sections describe these protocols in detail.

17.2.1. I2C Master Protocol

17.2.2. EFI_I2C_MASTER_PROTOCOL

Summary

This protocol manipulates the I2C host controller to perform transactions as a master on the I2C bus using the current state of any switches or multiplexers in the I2C bus.

GUID

#define EFI_I2C_MASTER_PROTOCOL_GUID \
{ 0xcd72881f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, \
0xa8, 0x11, 0x74, 0x62 }}

Protocol Interface Structure

typedef struct _EFI_I2C_MASTER_PROTOCOL {
  EFI_I2C_MASTER_PROTOCOL_SET_BUS_FREQUENCY  SetBusFrequency;
  EFI_I2C_MASTER_PROTOCOL_RESET              Reset;
  EFI_I2C_MASTER_PROTOCOL_START_REQUEST      StartRequest;
  CONST EFI_I2C_CONTROLLER_CAPABILITIES *I2cControllerCapabilities;
} EFI_I2C_MASTER_PROTOCOL;

Parameters

SetBusFrequency

Set the clock frequency for the I2C bus.

Reset

Reset the I2C host controller.

StartRequest

Start an I2C transaction in master mode on the host controller.

I2cControllerCapabilities

Pointer to an EFI_I2C_CONTROLLER_CAPABILITIES data structure containing the capabilities of the I2C host controller.

Description

The EFI_I2C_MASTER_PROTOCOL is typically used by the I2C host protocol to perform transactions on the I2C bus. This protocol may also be used to configure the I2C clock frequency and use I2C transactions to set the state of switches and multiplexers in the I2C bus.

A 10-bit slave address is or’ed with the following value enabling the I2C protocol stack to address the duplicated address space between 0 and 127 in 10-bit mode.

#define I2C_ADDRESSING_10_BIT 0x80000000

The I2C protocol stack uses the EFI_I2C_REQUEST_PACKET structure to describe I2C transactions on the I2C bus. The EFI_I2C_OPERATION describes a portion of the I2C transaction. The transaction starts with a start bit followed by the first operation in the operation array. Subsequent operations are separated with repeated start bits and the last operation is followed by a stop bit which concludes the transaction.

typedef struct {
  UINTN                   OperationCount;
  EFI_I2C_OPERATION       Operation[];
} EFI_I2C_REQUEST_PACKET;

Parameters

OperationCount

Number of elements in the operation array.

Operation

Description of the I2C operation

Description

The EFI_I2C_REQUEST_PACKET describes a single I2C transaction. The transaction starts with a start bit followed by the first operation in the operation array. Subsequent operations are separated with repeated start bits and the last operation is followed by a stop bit which concludes the transaction. Each operation is described by one of the elements in the Operation array.

typedef struct {
  UINT32             Flags;
  UINT32             LengthInBytes;
  UINT8              *Buffer;
} EFI_I2C_OPERATION;

Parameters

Flags

Flag bits qualify the I2C operation.

Flag Bits:

///
/// Define the I2C flags
///
/// I2C read operation when set
#define I2C_FLAG_READ               0x00000001

///
/// Define the flags for SMBus operation
///
/// The following flags are also present in only the first I2C operation
/// and are ignored when present in other operations. These flags
/// describe a particular SMB transaction as shown in the following table.
///

/// SMBus operation
#define I2C_FLAG_SMBUS_OPERATION 0x00010000

/// SMBus block operation
/// The flag I2C_FLAG_SMBUS_BLOCK causes the I2C master protocol to update
/// the LengthInBytes field of the operation in the request packet with
/// the actual number of bytes read or written. These values are only
/// valid when the entire I2C transaction is successful.
/// This flag also changes the LengthInBytes meaning to be: A maximum
/// of LengthInBytes is to be read from the device. The first byte
/// read contains the number of bytes remaining to be read, plus an
/// optional PEC value.
#define I2C_FLAG_SMBUS_BLOCK 0x00020000

/// SMBus process call operation
#define I2C_FLAG_SMBUS_PROCESS_CALL 0x00040000

/// SMBus use packet error code (PEC)
///   Note that the I2C master protocol may clear the I2C_FLAG_SMBUS_PEC bit
/// to indicate that the PEC value was checked by the hardware and is
/// not appended to the returned read data.
///
#define I2C_FLAG_SMBUS_PEC 0x00080000

//----------------------------------------------------------------------
///
/// QuickRead:          OperationCount=1,
///                     LengthInBytes=0,   Flags=I2C_FLAG_READ
/// QuickWrite:         OperationCount=1,
///                     LengthInBytes=0,   Flags=0
///
///
/// ReceiveByte:        OperationCount=1,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                                              | I2C_FLAG_READ
/// ReceiveByte+PEC:    OperationCount=1,
///                     LengthInBytes=2, Flags=I2C_FLAG_SMBUS_OPERATION
///                                              | I2C_FLAG_READ
///                                           | I2C_FLAG_SMBUS_PEC
///
///
/// SendByte:           OperationCount=1,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
/// SendByte+PEC:       OperationCount=1,
///                     LengthInBytes=2, Flags=I2C_FLAG_SMBUS_OPERATION
///                                           | I2C_FLAG_SMBUS_PEC
///
///
/// ReadDataByte:       OperationCount=2,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                     LengthInBytes=1, Flags=I2C_FLAG_READ
/// ReadDataByte+PEC:   OperationCount=2,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                                           | I2C_FLAG_SMBUS_PEC
///                     LengthInBytes=2, Flags=I2C_FLAG_READ
///
///
/// WriteDataByte:      OperationCount=1,
///                     LengthInBytes=2, Flags=I2C_FLAG_SMBUS_OPERATION
/// WriteDataByte+PEC: OperationCount=1,
///                     LengthInBytes=3, Flags=I2C_FLAG_SMBUS_OPERATION
///                                           | I2C_FLAG_SMBUS_PEC
///
///
/// ReadDataWord:       OperationCount=2,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                     LengthInBytes=2, Flags=I2C_FLAG_READ
/// ReadDataWord+PEC:   OperationCount=2,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_PEC
///                     LengthInBytes=3, Flags=I2C_FLAG_READ
///
///
/// WriteDataWord:      OperationCount=1,
///                     LengthInBytes=3, Flags=I2C_FLAG_SMBUS_OPERATION
/// WriteDataWord+PEC:  OperationCount=1,
///                     LengthInBytes=4, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_PEC
///
///
/// ReadBlock:          OperationCount=2,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_BLOCK
///                     LengthInBytes=33, Flags=I2C_FLAG_READ
/// ReadBlock+PEC:      OperationCount=2,
///                     LengthInBytes=1, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_BLOCK
///                                          | I2C_FLAG_SMBUS_PEC
///                     LengthInBytes=34, Flags=I2C_FLAG_READ
///
///
/// WriteBlock:         OperationCount=1,
///                     LengthInBytes=N+2, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_BLOCK
/// WriteBlock+PEC:     OperationCount=1,
///                     LengthInBytes=N+3, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_BLOCK
///                                          | I2C_FLAG_SMBUS_PEC
///
///
/// ProcessCall:        OperationCount=2,
///                     LengthInBytes=3, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_PROCESS_CALL
///                     LengthInBytes=2, Flags=I2C_FLAG_READ
/// ProcessCall+PEC:    OperationCount=2,
///                     LengthInBytes=3, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_PROCESS_CALL
///                                          | I2C_FLAG_SMBUS_PEC
///                     LengthInBytes=3, Flags=I2C_FLAG_READ
///
///
/// BlkProcessCall:     OperationCount=2,
///                     LengthInBytes=N+2, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_PROCESS_CALL
///                                          | I2C_FLAG_SMBUS_BLOCK
///                     LengthInBytes=33, Flags=I2C_FLAG_READ
/// BlkProcessCall+PEC: OperationCount=2,
///                     LengthInBytes=N+2, Flags=I2C_FLAG_SMBUS_OPERATION
///                                          | I2C_FLAG_SMBUS_PROCESS_CALL
///                                          | I2C_FLAG_SMBUS_BLOCK
///                                          | I2C_FLAG_SMBUS_PEC
///                     LengthInBytes=34, Flags=I2C_FLAG_READ
///
//----------------------------------------------------------------------
LengthInBytes

Number of bytes to send to or receive from the I2C device. A ping (address only byte/bytes) is indicated by setting the LengthInBytes to zero.

Buffer

Pointer to a buffer containing the data to send or to receive from the I2C device. The Buffer must be at least LengthInBytes in size.

Description

The EFI_I2C_OPERATION describes a subset of an I2C transaction in which the I2C controller is either sending or receiving bytes from the bus. Some transactions will consist of a single operation while others will be two or more.

Note

Some I2C controllers do not support read or write ping (address only) operation and will return EFI_UNSUPPORTED status when these operations are requested.

Note

I2C controllers which do not support complex transactions requiring multiple repeated start bits return EFI_UNSUPPORTED without processing any of the transaction.

typedef struct {
  UINT32   StructureSizeInBytes;
  UINT32   MaximumReceiveBytes;
  UINT32   MaximumTransmitBytes;
  UINT32   MaximumTotalBytes;
} EFI_I2C_CONTROLLER_CAPABILITIES;

Parameters

StructureSizeInBytes

Length of this data structure in bytes

MaximumReceiveBytes;

The maximum number of bytes the I2C host controller is able to receive from the I2C bus.

MaximumTransmitBytes

The maximum number of bytes the I2C host controller is able to send on the I2C bus.

MaximumTotalBytes

The maximum number of bytes in the I2C bus transaction.

Description

The EFI_I2C_CONTROLLER_CAPABILITIES specifies the capabilities of the I2C host controller. The StructureSizeInBytes enables variations of this structure to be identified if there is need to extend this structure in the future.

17.2.3. EFI_I2C_MASTER_PROTOCOL.SetBusFrequency()

Summary

Set the frequency for the I2C clock line.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_I2C_MASTER_PROTOCOL_SET_BUS_FREQUENCY) (
  IN CONST EFI_I2C_MASTER_PROTOCOL    *This,
  IN OUT UINTN                        *BusClockHertz
  );

Parameters

This

Pointer to an EFI_I2C_MASTER_PROTOCOL structure.

BusClockHertz

Pointer to the requested I2C bus clock frequency in Hertz. Upon return this value contains the actual frequency in use by the I2C controller.

Description

This routine must be called at or below TPL_NOTIFY .

The software and controller do a best case effort of using the specified frequency for the I2C bus. If the frequency does not match exactly then the I2C master protocol selects the next lower frequency to avoid exceeding the operating conditions for any of the I2C devices on the bus. For example if 400 KHz was specified and the controller’s divide network only supports 402 KHz or 398 KHz then the I2C master protocol selects 398 KHz. If there are not lower frequencies available, then return EFI_UNSUPPORTED .

Status Codes Returned

EFI_SUCCESS

The bus frequency was set successfully.

EFI_ALREADY_STARTED

The controller is busy with another transaction.

EFI_UNSUPPORTED

The controller does not support this frequency.

17.2.4. EFI_I2C_MASTER_PROTOCOL.Reset()

Summary

Reset the I2C controller and configure it for use.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_I2C_MASTER_PROTOCOL_RESET) (
  IN CONST EFI_I2C_MASTER_PROTOCOL  *This
  );

Parameters

This

Pointer to an EFI_I2C_MASTER_PROTOCOL structure.

Description

This routine must be called at or below TPL_NOTIFY .

The I2C controller is reset. The caller must call SetBusFrequency() after calling Reset() .

Status Codes Returned

EFI_SUCCESS

The rest completed successfully.

EFI_ALREADY_STARTED

The controller is busy with another transaction.

EFI_DEVICE_ERROR

The reset operation failed.

17.2.5. EFI_I2C_MASTER_PROTOCOL.StartRequest()

Summary

Start an I2C transaction on the host controller.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_I2C_MASTER_PROTOCOL_START_REQUEST) (
  IN CONST EFI_I2C_MASTER_PROTOCOL   *This,
  IN UINTN                           SlaveAddress,
  IN EFI_I2C_REQUEST_PACKET          *RequestPacket,
  IN EFI_EVENT                       Event          OPTIONAL,
  OUT EFI_STATUS                     *I2cStatus     OPTIONAL
  );

Parameters

This

Pointer to an EFI_I2C_MASTER_PROTOCOL structure.

SlaveAddress

Address of the device on the I2C BUS. Set the I2C_ADDRESSING_10_BIT when using 10-bit addresses, clear this bit for 7-bit addressing. Bits 0-6 are used for 7-bit I2C slave addresses and bits 0-9 are used for 10-bit I2C slave addresses.

RequestPacket

Pointer to an EFI_I2C_REQUEST_PACKET structure describing the I2C transaction.

Event

Event to signal for asynchronous transactions, NULL for synchronous transactions

I2cStatus

Optional buffer to receive the I2C transaction completion status

Description

This routine must be called at or below TPL_NOTIFY . For synchronous requests this routine must be called at or below TPL_CALLBACK .

This function initiates an I2C transaction on the controller. To enable proper error handling by the I2C protocol stack, the I2C master protocol does not support queuing but instead only manages one I2C transaction at a time. This API requires that the I2C bus is in the correct configuration for the I2C transaction.

The transaction is performed by sending a start-bit and selecting the I2C device with the specified I2C slave address and then performing the specified I2C operations. When multiple operations are requested they are separated with a repeated start bit and the slave address. The transaction is terminated with a stop bit.

When Event is NULL, StartRequest operates synchronously and returns the I2C completion status as its return value.

When Event is not NULL, StartRequest synchronously returns EFI_SUCCESS indicating that the I2C transaction was started asynchronously. The transaction status value is returned in the buffer pointed to by I2cStatus upon the completion of the I2C transaction when I2cStatus is not NULL. After the transaction status is returned the Event is signaled.

Note

The typical consumer of this API is the I2C host protocol. Extreme care must be taken by other consumers of this API to prevent confusing the third party I2C drivers due to a state change at the I2C device which the third party I2C drivers did not initiate. I2C platform specific code may use this API within these guidelines.

Status Codes Returned

EFI_SUCCESS

The asynchronous transaction was successfully started when Event is not NULL

EFI_SUCCESS

The transaction completed successfully when Event is NULL

EFI_ALREADY_STARTED

The controller is busy with another transaction

EFI_BAD_BUFFER_SIZE

The RequestPacket LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NOT_FOUND

Reserved bit set in the SlaveAddress parameter

EFI_NO_RESPONSE

The I2C device is not responding to the slave address EFI_DEVICE_ERROR will be returned if the controller cannot distinguish when the NACK occurred

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.2.6. I2C Host Protocol

17.2.7. EFI_I2C_HOST_PROTOCOL

Summary

This protocol provides callers with the ability to do I/O transactions to all of the devices on the I2C bus.

GUID

#define EFI_I2C_HOST_PROTOCOL_GUID \
{ 0xa5aab9e3, 0xc727, 0x48cd, { 0x8b, 0xbf, 0x42, 0x72, \
0x33, 0x85, 0x49, 0x48 }}

Protocol Interface Structure

typedef struct _EFI_I2C_HOST_PROTOCOL {
  EFI_I2C_HOST_PROTOCOL_QUEUE_REQUEST    QueueRequest;
  CONST EFI_I2C_CONTROLLER_CAPABILITIES  *I2cControllerCapabilities;
} EFI_I2C_HOST_PROTOCOL;

Parameters

QueueRequest

Queue an transaction for execution on the I2C bus

I2cControllerCapabilities

Pointer to an EFI_I2C_CONTROLLER_CAPABILITIES data structure containing the capabilities of the I2C host controller.

Description

The I2C bus driver uses the services of the EFI_I2C_HOST_PROTOCOL to produce an instance of the EFI_I2C_IO_PROTOCOL for each I2C device on an I2C bus.

The EFI_I2C_HOST_PROTOCOL exposes an asynchronous interface to callers to perform transactions to any device on the I2C bus. Internally, the I2C host protocol manages the flow of the I2C transactions to the host controller, keeping them in FIFO order. Prior to each transaction, the I2C host protocol ensures that the switches and multiplexers are properly configured. The I2C host protocol then starts the transaction on the host controller using the EFI_I2C_MASTER_PROTOCOL .

17.2.8. EFI_I2C_HOST_PROTOCOL.QueueRequest()

Summary

Queue an I2C transaction for execution on the I2C controller.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_I2C_HOST_PROTOCOL_QUEUE_REQUEST) (
  IN CONST EFI_I2C_HOST_PROTOCOL    *This,
  IN UINTN                          I2cBusConfiguration,
  IN UINTN                          SlaveAddress,
  IN EFI_EVENT                      Event             OPTIONAL,
  IN EFI_I2C_REQUEST_PACKET         *RequestPacket,
  OUT EFI_STATUS                    *I2cStatus        OPTIONAL
  );

Parameters

This

Pointer to an EFI_I2C_HOST_PROTOCOL structure.

I2cBusConfiguration

I2C bus configuration to access the I2C device

SlaveAddress

Address of the device on the I2C bus. Set the I2C_ADDRESSING_10_BIT when using 10-bit addresses, clear this bit for 7-bit addressing. Bits 0-6 are used for 7-bit I2C slave addresses and bits 0-9 are used for 10-bit I2C slave addresses.

Event

Event to signal for asynchronous transactions, NULL for synchronous transactions

RequestPacket

Pointer to an EFI_I2C_REQUEST_PACKET structure describing the I2C transaction

I2cStatus

Optional buffer to receive the I2C transaction completion status

Description

Queue an I2C transaction for execution on the I2C controller.

This routine must be called at or below TPL_NOTIFY . For synchronous requests this routine must be called at or below TPL_CALLBACK . The I2C host protocol uses the concept of I2C bus configurations to describe the I2C bus. An I2C bus configuration is defined as a unique setting of the multiplexers and switches in the I2C bus which enable access to one or more I2C devices. When using a switch to divide a bus, due to bus frequency differences, the I2C bus configuration management protocol defines an I2C bus configuration for the I2C devices on each side of the switch. When using a multiplexer, the I2C bus configuration management defines an I2C bus configuration for each of the selector values required to control the multiplexer. See Figure 1 in the |I2C| -bus specification and user manual for a complex I2C bus configuration.

The I2C host protocol processes all transactions in FIFO order. Prior to performing the transaction, the I2C host protocol calls EnableI2cBusConfiguration to reconfigure the switches and multiplexers in the I2C bus enabling access to the specified I2C device. The EnableI2cBusConfiguration also selects the I2C bus frequency for the I2C device. After the I2C bus is configured, the I2C host protocol calls the I2C master protocol to start the I2C transaction. When Event is NULL, QueueRequest() operates synchronously and returns the I2C completion status as its return value.

When Event is not NULL, QueueRequest() synchronously returns EFI_SUCCESS indicating that the asynchronously I2C transaction was queued. The values above are returned in the buffer pointed to by I2cStatus upon the completion of the I2C transaction when I2cStatus is not NULL.

Status Codes Returned

EFI_SUCCESS

The asynchronous transaction was successfully queued when Event is not NULL

EFI_SUCCESS

The transaction completed successfully when Event is NULL

EFI_BAD_BUFFER_SIZE

The RequestPacket LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NOT_FOUND

Reserved bit set in the SlaveAddress parameter

EFI_NO_MAPPING

Invalid I2cBusConfiguration value

EFI_NO_RESPONSE

The I2C device is not responding to the slave address EFI_DEVICE_ERROR will be returned if the controller cannot distinguish when the NACK occurred

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.2.9. I2C I/O Protocol

17.2.10. EFI_I2C_IO_PROTOCOL

Summary

The EFI I2C I/O protocol enables the user to manipulate a single I2C device independent of the host controller and I2C design.

GUID

#define EFI_I2C_IO_PROTOCOL_GUID \
{ 0xb60a3e6b, 0x18c4, 0x46e5, { 0xa2, 0x9a, 0xc9, 0xa1, \
0x06, 0x65, 0xa2, 0x8e }}

Protocol Interface Structure

typedef struct _EFI_I2C_IO_PROTOCOL {
  EFI_I2C_IO_PROTOCOL_QUEUE_REQUEST      QueueRequest;
  CONST EFI_GUID                         *DeviceGuid;
  UINT32                                 DeviceIndex;
  UINT32                                 HardwareRevision;
  CONST EFI_I2C_CONTROLLER_CAPABILITIES  *I2cControllerCapabilities;
} EFI_I2C_IO_PROTOCOL;

Parameters

QueueRequest

Queue an I2C transaction for execution on the I2C device.

DeviceGuid

Unique value assigned by the silicon manufacture or the third party I2C driver writer for the I2C part. This value logically combines both the manufacture name and the I2C part number into a single value specified as a GUID.

DeviceIndex

Unique ID of the I2C part within the system

HardwareRevision

Hardware revision - ACPI _HRV value. See the Advanced Configuration and Power Interface Specification, Revision 5.0 for the field format and the Plug and play support for |I2C| web-page for restriction on values.

I2cControllerCapabilities

Pointer to an EFI_I2C_CONTROLLER_CAPABILITIES data structure containing the capabilities of the I2C host controller.

Description

  • The I2C IO protocol enables access to a specific device on the I2C bus.

  • Each I2C device is identified uniquely in the system by the tuple DeviceGuid : DeviceIndex. The DeviceGuid represents the manufacture and part number and is provided by the silicon vendor or the third party I2C device driver writer. The DeviceIndex identifies the part within the system by using a unique number and is created by the board designer or the writer of the EFI_I2C_ENUMERATE_PROTOCOL . I2C slave addressing is abstracted to validate addresses and limit operation to the specified I2C device. The third party providing the I2C device support provides an ordered list of slave addresses for the I2C device required to implement the EFI_I2C_ENUMERATE_PROTOCOL . The order of the list must be preserved.

17.2.11. EFI_I2C_IO_PROTOCOL.QueueRequest()

Summary

Queue an I2C transaction for execution on the I2C device.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_I2C_IO_PROTOCOL_QUEUE_REQUEST) (
  IN CONST EFI_I2C_IO_PROTOCOL   *This,
  IN UINTN                       SlaveAddressIndex,
  IN EFI_EVENT                   Event              OPTIONAL,
  IN EFI_I2C_REQUEST_PACKET      *RequestPacket,
  OUT EFI_STATUS                 *I2cStatus         OPTIONAL
  );

Parameters

This

Pointer to an EFI_I2C_IO_PROTOCOL structure.

SlaveAddressIndex

Index value into an array of slave addresses for the I2C device. The values in the array are specified by the board designer, with the third party I2C device driver writer providing the slave address order.

For devices that have a single slave address, this value must be zero. If the I2C device uses more than one slave address then the third party (upper level) I2C driver writer needs to specify the order of entries in the slave address array.

Event

Event to signal for asynchronous transactions, NULL for synchronous transactions

RequestPacket

Pointer to an EFI_I2C_REQUEST_PACKET structure describing the I2C transaction

I2cStatus

Optional buffer to receive the I2C transaction completion status

Description

This routine must be called at or below TPL_NOTIFY . For synchronous requests this routine must be called at or below TPL_CALLBACK .

This routine queues an I2C transaction to the I2C controller for execution on the I2C bus. When Event is NULL, QueueRequest() operates synchronously and returns the I2C completion status as its return value.

When Event is not NULL, QueueRequest() synchronously returns EFI_SUCCESS indicating that the asynchronous I2C transaction was queued. The values above are returned in the buffer pointed to by I2cStatus upon the completion of the I2C transaction when I2cStatus is not NULL.

Status Codes Returned

EFI_SUCCESS

The asynchronous transaction was successfully queued when Event is not NULL

EFI_SUCCESS

The transaction completed successfully when Event is NULL

EFI_BAD_BUFFER_SIZE

The RequestPacket LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NO_MAPPING

The EFI_I2C_HOST_PROTOCOL could not set the bus configuration required to access this I2C device

EFI_NO_RESPONSE

The I2C device is not responding to the slave address selected by SlaveAddressIndex EFI_DEVICE_ERROR will be returned if the controller cannot distinguish when the NACK occurred

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.2.12. I2C Bus Configuration Management Protocol

17.2.13. EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL

Summary

The EFI I2C bus configuration management protocol provides platform specific services that allow the I2C host protocol to reconfigure the switches and multiplexers and set the clock frequency for the I2C bus. This protocol also enables the I2C host protocol to reset an I2C device which may be locking up the I2C bus by holding the clock or data line low.

GUID

#define EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL_GUID \
{ 0x55b71fb5, 0x17c6, 0x410e, { 0xb5, 0xbd, 0x5f, 0xa2, \
0xe3, 0xd4, 0x46, 0x6b }}

Protocol Interface Structure

typedef struct _EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL {

EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL_ENABLE_I2C_BUS_CONFIGURATION   EnableI2cBusConfiguration;
} EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL;

Parameters

EnableI2cBusConfiguration

Enable an I2C bus configuration for use.

Description

The I2C protocol stack uses the concept of an I2C bus configuration as a way to describe a particular state of the switches and multiplexers in the I2C bus.

A simple I2C bus does not have any multiplexers or switches is described to the I2C protocol stack with a single I2C bus configuration which specifies the I2C bus frequency. An I2C bus with switches and multiplexers use an I2C bus configuration to describe each of the unique settings for the switches and multiplexers and the I2C bus frequency. However the I2C bus configuration management protocol only needs to define the I2C bus configurations that the software uses, which may be a subset of the total.

The I2C bus configuration description includes a list of I2C devices which may be accessed when this I2C bus configuration is enabled. I2C devices before a switch or multiplexer must be included in one I2C bus configuration while I2C devices after a switch or multiplexer are on another I2C bus configuration.

The I2C bus configuration management protocol is an optional protocol. When the I2C bus configuration protocol is not defined the I2C host protocol does not start and the I2C master protocol may be used for other purposes such as SMBus traffic. When the I2C bus configuration protocol is available, the I2C host protocol uses the I2C bus configuration protocol to call into the platform specific code to set the switches and multiplexers and set the maximum I2C bus frequency.

The platform designers determine the maximum I2C bus frequency by selecting a frequency which supports all of the I2C devices on the I2C bus for the setting of switches and multiplexers. The platform designers must validate this against the I2C device data sheets and any limits of the I2C controller or bus length.

During I2C device enumeration, the I2C bus driver retrieves the I2C bus configuration that must be used to perform I2C transactions to each I2C device. This I2C bus configuration value is passed into the I2C host protocol to identify the I2C bus configuration required to access a specific I2C device. The I2C host protocol calls EnableBusConfiguration() to set the switches and multiplexers in the I2C bus and the I2C clock frequency. The I2C host protocol may optimize calls to EnableBusConfiguration() by only making the call when the I2C bus configuration value changes between I2C requests.

When I2C transactions are required on the same I2C bus to change the state of multiplexers or switches, the I2C master protocol must be used to perform the necessary I2C transactions.

It is up to the platform specific code to choose the proper I2C bus configuration when ExitBootServices() is called. Some operating systems are not able to manage the I2C bus configurations and must use the I2C bus configuration that is established by the platform firmware before ExitBootServices() returns.

17.2.14. EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL.EnableI2cBusConfiguration()

Summary

Enable access to an I2C bus configuration.

Prototype

typedef
EFI_STATUS
(EFIAPI
*EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL_ENABLE_I2C_BUS_CONFIGURATION)  (
  IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL  *This,
IN UINTN                                     I2cBusConfiguration,
IN EFI_EVENT                                 Event        OPTIONAL,
IN EFI_STATUS                                *I2cStatus   OPTIONAL
);

Parameters

This

Pointer to an EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL structure.

I2cBusConfiguration

Index of an I2C bus configuration. All values in the range of zero to N-1 are valid where N is the total number of I2C bus configurations for an I2C bus.

Event

Event to signal when the transaction is complete

I2cStatus

Buffer to receive the transaction status.

Description

This routine must be called at or below TPL_NOTIFY . For synchronous requests this routine must be called at or below TPL_CALLBACK .

Reconfigure the switches and multiplexers in the I2C bus to enable access to a specific I2C bus configuration. Also select the maximum clock frequency for this I2C bus configuration. This routine uses the I2C Master protocol to perform I2C transactions on the local bus. This eliminates any recursion in the I2C stack for configuration transactions on the same I2C bus. This works because the local I2C bus is idle while the I2C bus configuration is being enabled.

If I2C transactions must be performed on other I2C busses, then the EFI_I2C_HOST_PROTOCOL , the EFI_I2C_IO_PROTCOL , or a third party I2C driver interface for a specific device must be used. This requirement is because the I2C host protocol controls the flow of requests to the I2C controller. Use the EFI_I2C_HOST_PROTOCOL when the I2C device is not enumerated by the EFI_I2C_ENUMERATE_PROTOCOL . Use a protocol produced by a third party driver when it is available or the EFI_I2C_IO_PROTOCOL when the third party driver is not available but the device is enumerated with the EFI_I2C_ENUMERATE_PROTOCOL .

When Event is NULL, EnableI2cBusConfiguration operates synchronously and returns the I2C completion status as its return value. The values returned from EnableI2cBusConfiguration are:

Status Codes Returned

EFI_SUCCESS

The asynchronous bus configuration request was successfully started when Event is not NULL

EFI_SUCCESS

The bus configuration request completed successfully when Event is NULL

EFI_DEVICE_ERROR

The bus configuration failed

EFI_NO_MAPPING

Invalid I2cBusConfiguration value

17.2.15. I2C Enumerate Protocol

17.2.16. EFI_I2C_ENUMERATE_PROTOCOL

Summary

Support the enumeration of the I2C devices.

GUID

#define EFI_I2C_ENUMERATE_PROTOCOL_GUID \
{ 0xda8cd7c4, 0x1c00, 0x49e2, { 0x80, 0x3e, 0x52, 0x14, \
0xe7, 0x01, 0x89, 0x4c }}

Protocol Interface Structure

typedef struct _EFI_I2C_ENUMERATE_PROTOCOL {
  EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE          Enumerate;
  EFI_I2C_ENUMERATE_PROTOCOL_GET_BUS_FREQUENCY  GetBusFrequency;
} EFI_I2C_ENUMERATE_PROTOCOL;

Parameters

Enumerate

Traverse the set of I2C devices on an I2C bus. This routine returns the next I2C device on an I2C bus.

GetBusFrequency

Get the requested I2C bus frequency for a specified bus configuration.

Description

The I2C bus driver uses this protocol to enumerate the devices on the I2C bus.

typedef struct {
  CONST EFI_GUID           *DeviceGuid;
  UINT32                   DeviceIndex;
  UINT32                   HardwareRevision;
  UINT32                   I2cBusConfiguration;
  UINT32                   SlaveAddressCount;
  CONST UINT32             *SlaveAddressArray;
} EFI_I2C_DEVICE;

Parameters

DeviceGuid

Unique value assigned by the silicon manufacture or the third party I2C driver writer for the I2C part. This value logically combines both the manufacture name and the I2C part number into a single value specified as a GUID.

DeviceIndex

Unique ID of the I2C part within the system

HardwareRevision

Hardware revision - ACPI _HRV value. See the Advanced Configuration and Power Interface Specification, Revision 5.0 for the field format and the Plug and play support for |I2C| web-page for restriction on values.

I2cBusConfiguration

I2C bus configuration for the I2C device

SlaveAddressCount

Number of slave addresses for the I2C device.

SlaveAddressArray

Pointer to the array of slave addresses for the I2C device.

Description

The EFI_I2C_ENUMERATE_PROTOCOL uses the EFI_I2C_DEVICE to describe the platform specific details associated with an I2C device. This description is passed to the I2C bus driver during enumeration where it is made available to the third party I2C device driver via the EFI_I2C_IO_PROTOCOL .

17.2.17. EFI_I2C_ENUMERATE_PROTOCOL.Enumerate()

Summary

Enumerate the I2C devices

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE) (
  IN CONST EFI_I2C_ENUMERATE_PROTOCOL   *This,
  IN OUT CONST EFI_I2C_DEVICE           **Device
);

Parameters

This

Pointer to an EFI_I2C_ENUMERATE_PROTOCOL structure.

Device

Pointer to a buffer containing an EFI_I2C_DEVICE structure. Enumeration is started by setting the initial EFI_I2C_DEVICE structure pointer to NULL. The buffer receives an EFI_I2C_DEVICE structure pointer to the next I2C device.

Description

This function enables the caller to traverse the set of I2C devices on an I2C bus.

Status Codes Returned

EFI_SUCCESS

The platform data for the next device on the I2C bus was returned successfully

EFI_INVALID_PARAMETER

Device is NULL

EFI_NO_MAPPING

Device does not point to a valid EFI_I2C_DEVICE structure returned in a previous call Enumerate

17.2.18. EFI_I2C_ENUMERATE_PROTOCOL.GetBusFrequency()

Summary

Get the requested I2C bus frequency for a specified bus configuration.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_I2C_ENUMERATE_PROTOCOL_GET_BUS_FREQUENCY) (
  IN CONST EFI_I2C_ENUMERATE_PROTOCOL  *This,
  IN UINTN                             I2cBusConfiguration,
  OUT UINTN                            *BusClockHertz
);

Parameters

This

Pointer to an EFI_I2C_ENUMERATE_PROTOCOL structure.

I2cBusConfiguration

I2C bus configuration to access the I2C device

BusClockHertz

Pointer to a buffer to receive the I2C bus clock frequency in Hertz

Description

This function returns the requested I2C bus clock frequency for the I2cBusConfiguration . This routine is provided for diagnostic purposes and is meant to be called after calling Enumerate to get the I2cBusConfiguration value.

Status Codes Returned

EFI_SUCCESS

The I2C bus frequency was returned successfully.

EFI_INVALID_PARAMETER

BusClockHertz was NULL

EFI_NO_MAPPING

Invalid I2cBusConfiguration value

17.3. PEI Code definitions

For the Pre-EFI Initialization environment a subset of the I2C stack is defined to support basic hardware initialization in the PEI phase. The EFI_PEI_I2C_MASTER PPI is defined to standardize access to the I2C controller.

17.3.1. I2C Master PPI

17.3.2. EFI_PEI_I2C_MASTER

Summary

This PPI manipulates the I2C host controller to perform transactions as a master on the I2C bus using the current state of any switches or multiplexers in the I2C bus.

GUID

#define EFI_PEI_I2C_MASTER_PPI_GUID \
{ 0xb3bfab9b, 0x9f9c, 0x4e8b, { 0xad, 0x37, 0x7f, 0x8c, \
0x51, 0xfc, 0x62, 0x80 }}

PEIM-to-PEIM Interface Structure

typedef struct _EFI_PEI_I2C_MASTER_PPI {
  EFI_PEI_I2C_MASTER_PPI_SET_BUS_FREQUENCY   SetBusFrequency;
  EFI_PEI_I2C_MASTER_PPI_RESET               Reset;
  EFI_PEI_I2C_MASTER_PPI_START_REQUEST       StartRequest;
  CONST EFI_PEI_I2C_CONTROLLER_CAPABILITIES  *I2cControllerCapabilities;
  EFI_GUID                                   Identifier;
} EFI_PEI_I2C_MASTER_PPI;

Parameters

SetBusFrequency

Set the clock frequency in Hertz for the I2C bus.

Reset

Reset the I2C host controller.

StartRequest

Start an I2C transaction in master mode on the host controller.

I2cControllerCapabilities

Pointer to an EFI_I2C_CONTROLLER_CAPABILITIES data structure containing the capabilities of the I2C host controller.

Identifier

Identifier which uniquely identifies thisI2C controller in the system.

Description

The EFI_PEI_I2C_MASTER PPI enables the platform code to perform transactions on the I2C bus.

17.3.3. EFI_PEI_I2C_MASTER_PPI.SetBusFrequency()

Summary

Set the frequency for the I2C clock line.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_PEI_I2C_MASTER_PPI_SET_BUS_FREQUENCY) (
  IN EFI_PEI_I2C_MASTER    *This,
  IN UINTN                 *BusClockHertz
  );

Parameters

This

Pointer to an EFI_PEI_I2C_MASTER_PPI structure.

BusClockHertz

Pointer to the requested I2C bus clock frequency in Hertz. Upon return this value contains the actual frequency in use by the I2C controller.

Description

The software and controller do a best case effort of using the specified frequency for the I2C bus. If the frequency does not match exactly then the I2C master protocol selects the next lower frequency to avoid exceeding the operating conditions for any of the I2C devices on the bus. For example if 400 KHz was specified and the controller’s divide network only supports 402 KHz or 398 KHz then the controller would be set to 398 KHz. If there are no lower frequencies available, then return EFI_UNSUPPORTED .

Status Codes Returned

EFI_SUCCESS

The bus frequency was set successfully.

EFI_INVALID_PARAMETER

BusClockHertz is NULL

EFI_UNSUPPORTED

The controller does not support this frequency.

17.3.4. EFI_PEI_I2C_MASTER_PPI.Reset()

Summary

Reset the I2C controller and configure it for use.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_PEI_I2C_MASTER_PPI_RESET) (
  IN CONST EFI_PEI_I2C_MASTER            *This
  );

Parameters

This

Pointer to an EFI_PEI_I2C_MASTER_PPI structure.

Description

The I2C controller is reset. The caller must call SetBusFrequency() after calling Reset() .

Status Codes Returned

EFI_SUCCESS

The reset completed successfully.

EFI_DEVICE_ERROR

The reset operation failed.

17.3.5. EFI_PEI_I2C_MASTER_PPI.StartRequest()

Summary

Start an I2C transaction on the host controller.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_PEI_I2C_MASTER_PPI_START_REQUEST) (
  IN CONST EFI_PEI_I2C_MASTER    *This,
  IN UINTN                       SlaveAddress,
  IN EFI_I2C_REQUEST_PACKET      *RequestPacket
  );

Parameters

This

Pointer to an EFI_PEI_I2C_MASTER_PPI structure.

SlaveAddress

Address of the device on the I2C bus. Set the I2C_ADDRESSING_10_BIT when using 10-bit addresses, clear this bit for 7-bit addressing. Bits 0-6 are used for 7-bit I2C slave addresses and bits 0-9 are used for 10-bit I2C slave addresses.

RequestPacket

Pointer to an EFI_I2C_REQUEST_PACKET structure describing the I2C transaction.

Description

This function initiates an I2C transaction on the controller.

The transaction is performed by sending a start-bit and selecting the I2C device with the specified I2C slave address and then performing the specified I2C operations. When multiple operations are requested they are separated with a repeated start bit and the slave address. The transaction is terminated with a stop bit. When the transaction completes, the status value is returned.

Status Codes Returned

EFI_SUCCESS

The transaction completed successfully

EFI_BAD_BUFFER_SIZE

The RequestPacket LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NO_RESPONSE

The I2C device is not responding to the slave address EFI_DEVICE_ERROR will be returned if the controller cannot distinguish when the NACK occurred

EFI_NOT_FOUND

Reserved bit set in the SlaveAddress parameter

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.3.6. I2C Host PPI

17.3.7. EFI_PEI_I2C_HOST

Summary

This PPI provides callers with the ability to do I/O transactions to all of the devices on the I2C bus.

GUID

#define EFI_PEI_I2C_HOST_GUID \
{ 0x3a12e52d, 0x3bd2, 0x482c, 0xa6, 0x80, 0x0f, 0xeb, \
0x61, 0x9a, 0xeb, 0xef }

PEIM-to-PEIM Interface Structure

typedef struct _EFI_I2C_HOST_PPI {
  EFI_I2C_HOST_START_REQUEST            StartRequest;
  CONST EFI_I2C_CONTROLLER_CAPABILITIES *I2cControllerCapabilities;
  UINTN                                 ControllerNumber;
};

Parameters

QueueRequest

Queue a transaction for execution on the I2C bus

I2cControllerCapabilities

The address of an EFI_I2C_CONTROLLER_CAPABILITIES data structure containing the capabilities of the I2C host controller.

ControllerNumber

Unique number identifying the I2C controller in the system

Description

Please use EFI_PEI_I2C_IO as EFI_PEI_I2C_HOST is only intended to be used by the I2C bus driver. The EFI_PEI_I2C_HOST requires the tuple ControllerNumber:BusConfiguration:SlaveAddress which is platform specific data to identify the I2C device. EFI_PEI_I2C_IO eliminates the platform specific details. The upper layer driver locates the correct EFI_PEI_I2C_HOST interface (I2cHost) by comparing the following field:

  • I2cHost->ControllerNumber with the system unique value for the I2C Controller Number

Prior to each transaction, the I2C host driver ensures that the switches and multiplexers are properly configured. The I2C host driver then starts the transaction on the I2C controller calling the I2C port driver interface ( EFI_PEI_I2C_MASTER ).

The I2C platform driver installs the following GUID after installing EFI_PEI_I2C_ENUMERATE and*EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT* PPIs for the necessary I2C controllers. The following GUID resolves the dependency expressions for the I2C port and host drivers enabling them to load and start their configuration.

Lack of EFI_PEI_I2C_BUS_CONFIGURATION prevents the I2C host driver from loading, reserving the I2C port driver for SMBus transactions.

GUID

#define EFI_PEI_I2C_BUS_CONFIGURED_GUID \
{ 0x9eade134, 0x6bb1, 0x421d, 0xac, 0xaf, 0x59, 0x0a, \
0x5d, 0x2e, 0xa6, 0x3a }

17.3.8. EFI_PEI_I2C_HOST.StartRequest()

Summary

Start a transaction on the I2C controller.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_PEI_I2C_HOST_START_REQUEST) (
  IN EFI_PEI_I2C_HOST        *This,
  IN UINTN                   I2cBusConfiguration,
  IN UINTN                   SlaveAddress,
  IN EFI_I2C_REQUEST_PACKET  *RequestPacket
);

Parameters

This

Address of an EFI_PEI_I2C_HOST structure.

I2cBusConfiguration

I2C bus configuration to access the I2C device

SlaveAddress

Address of the device on the |I2C| bus. Or in the value I2C_ADDRESSING_10_BIT when using 10-bit addresses.

RequestPacket

Address of an EFI_I2C_REQUEST_PACKET structure describing the I2C transaction

Description

Start an I2C transaction on the I2C controller.

N.B. The typical consumers of this API are the I2C bus driver and on rare occasions I2C test applications. Extreme care must be taken by other consumers of this API to prevent confusing the third party I2C drivers due to a state change at the I2C device which the third party I2C drivers did not initiate. I2C platform drivers may use this API within these guidelines.

This layer uses the concept of I2C bus configurations to describe the I2C bus. An I2C bus configuration is defined as a unique setting of the multiplexers and switches in the I2C bus which enable access to one or more I2C devices. When using a switch to divide a bus, due to speed differences, the I2C platform layer would define an I2C bus configuration for the I2C devices on each side of the switch. When using a multiplexer, the I2C platform layer defines an I2C bus configuration for each of the selector values required to control the multiplexer. See Figure 1 in the |I2C| -bus specification and user manual for a complex I2C bus configuration.

The I2C host driver calls the I2C platform driver to reconfigure the switches and multiplexers in the I2C bus enabling access to the specified I2C device. The I2C platform driver also selects the maximum bus speed for the device. After the I2C bus is configured, the I2C host driver calls the I2C port driver to initialize the I2C controller and start the I2C transaction.

In event of timeout, the I2C host driver calls the I2C platform driver in an attempt to reset the host controller and the I2C device.

Status Codes Returned

The values returned from StartRequest are:

EFI_SUCCESS

The transaction completed successfully

EFI_BAD_BUFFER_SIZE

The LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction One possible cause is that the slave device is not present

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NOT_FOUND

I2C slave address exceeds maximum address

EFI_NO_MAPPING

Invalid I2cBusConfiguration value

EFI_NO_MEDIA

State was lost because more than one device was reset

EFI_NO_RESPONSE

The I2C device is not responding to the slave address EFI_DEVICE_ERROR may also be returned if the controller cannot distinguish when the NACK occurred

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_TIMEOUT

The transaction did not complete within the specified timeout period

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.3.9. I2C I/O PPI

17.3.10. EFI_PEI_I2C_IO

Summary

The EFI I2C I/O PPI enables the user to manipulate a single I2C device independent of the host controller and I2C bus design.

GUID

#define EFI_PEI_I2C_IO_GUID \
{ 0x42179ed0, 0x2fa2, 0x47c0, 0x85, 0x7e, 0x8b, 0xc0, \
0x18, 0x81, 0xea, 0x97 }

PEIM-to-PEIM Interface Structure

typedef struct {
  EFI_PEI_I2C_IO_GET_DEVICE_INFO          GetDeviceInfo;
  EFI_PEI_I2C_IO_GET_DEVICE_INFO_ID_LIST  GetDeviceInfoIdList;
  EFI_PEI_I2C_IO_START_REQUEST            StartRequest;
  EFI_I2C_DEVICE                          *I2cDevice;
  CONST EFI_I2C_CONTROLLER_CAPABILITIES   *I2cControllerCapabilities;
} EFI_PEI_I2C_IO;

Parameters

GetDeviceInfo

Get a blob of data identified by a GUID.

GetDeviceInfoIdList

Get a list of the GUIDs associated with this I2C device.

StartRequest

Start a transaction on the I2C device.

I2cDevice

A pointer to the EFI_I2C_DEVICE structure contained within the I2C platform driver.

I2cControllerCapabilities

The address of an EFI_I2C_CONTROLLER_CAPABILITIES data structure containing the capabilities of the I2C host controller.

Description

The I2C I/O PPI enables access to a specific device on the I2C bus.

Each I2C device is identified uniquely in the system by the tuple DeviceGuid:DeviceIndex . The DeviceGuid combines the manufacture and part number and is provided by the silicon vendor or the third party I2C device driver writer. The DeviceIndex identifies the part within the system by using a unique number and is created by the board designer or the I2C platform driver writer. The upper layer I2C driver writer provides the following to the platform vendor:

  • Vendor specific GUID for the I2C part that is used to connect the upper layer driver to the device.

  • Slave address array guidance when the I2C device uses more than one slave address. This is used to access the blocks of hardware within the I2C device.

The upper layer driver locates the correct EFI_PEI_I2C_IO interface (I2cIo) by comparing the following fields:

  • I2cIo->Device.DeviceGuid with the vendor supplied GUID

  • I2cIo->DeviceIndex with the system wide unique number assigned to the specific I2C part.

I2C slave addressing is abstracted to validate addresses and limit operation to the specified I2C device. The third party providing the I2C device support provides an ordered list of slave addresses for the I2C device to the team building the platform layer. The platform team must preserve the order of the supplied list. SlaveAddressCount is the number of entries in this list or array within the platform layer. The third party device support references a slave address using an index into the list or array in the range of zero to SlaveAddressCount - 1.

17.3.11. EFI_I2C_IO_PROTOCOL.GetDeviceInfo()

Summary

Get a data blob associated with the I2C device.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_I2C_IO_GET_DEVICE_INFO) (
  IN EFI_PEI_I2C_IO      *This,
  IN EFI_GUID            *DataGuid,
  IN OUT UINT32          *LengthInBytes,
  OUT VOID               *Buffer
  );

Parameters

This

Address of an EFI_PEI_I2C_IO structure.

DataGuid

Address of the GUID associated with the data

LengthInBytes

Address of a value containing the length of the buffer in bytes on input and receiving the length of the data on output. If the input length was too small, the output length specifies the data length.

Buffer

Buffer address to receive the data

Description

This routine locates the specified data blob associated with the I2C device.

Status Codes Returned

The values returned from GetDeviceInfo are:

EFI_SUCCESS

The data was returned successfully

EFI_BUFFER_TOO_SMALL

The specified buffer length is too small

EFI_INVALID_PARAMETER

Buffer is NULL

EFI_INVALID_PARAMETER

DataGuid is NULL

EFI_INVALID_PARAMETER

LengthInBytes is NULL

EFI_NOT_FOUND

Data blob was not found

17.3.12. EFI_I2C_IO_PROTOCOL.GetDeviceInfoIdList()

Summary

Get the list of data associated with the I2C device.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_I2C_IO_GET_DEVICE_INFO_ID_LIST) (
  IN EFI_PEI_I2C_IO     *This,
  IN CONST EFI_GUID     ***GuidArray,
  IN UINTN              *GuidEntries
);

Parameters

This

Address of an EFI_PEI_I2C_IO structure.

GuidArray

Address to receive the list of GUIDs

GuidEntries

Address to receive the number of entries in the GUID array

Description

This routine must be called at or below TPL_NOTIFY .

This routine returns an array of GUIDs identifying data associated with the I2C device. When the caller is done with the GUID array, the caller must call FreePool to return the GUID array to the heap.

Status Codes Returned

The values returned from GetDeviceInfoIdList are:

EFI_SUCCESS

The GUID array was returned successfully

EFI_INVALID_PARAMETER

GuidArray is NULL

EFI_INVALID_PARAMETER

GuidEntries is NULL

EFI_OUT_OF_RESOURCES

Memory allocation failure

17.3.13. EFI_PEI_I2C_IO.StartRequest()

Summary

Start an I2C transaction on the I2C device.

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_PEI_I2C_BUS_START_REQUEST) (
  IN EFI_PEI_I2C_IO             *This,
  IN UINTN                      SlaveAddressIndex,
  IN EFI_I2C_REQUEST_PACKET     *RequestPacket
  );

Parameters

This

Address of an EFI_PEI_I2C_IO structure.

SlaveAddressIndex

Index value into an array of slave addresses for the I2C device. The values in the array are specified by the board designer, with the I2C device driver writer providing the slave address order.

For devices that have a single slave address, this value must be zero. If the I2C device uses more than one slave address then the third party (upper level) I2C driver writer needs to specify the order of entries in the slave address array.

RequestPacket

Address of an EFI_I2C_REQUEST_PACKET structure describing the I2C transaction

Description

N.B. The typical consumers of this API are the third party I2C drivers. Extreme care must be taken by other consumers of this API to prevent confusing the third party I2C drivers due to a state change at the I2C device which the third party I2C drivers did not initiate. I2C platform drivers may use this API within these guidelines.

This routine starts a transaction on the I2C device.

Status Codes Returned

The values returned from StartRequest are:

EFI_SUCCESS

The transaction completed successfully

EFI_BAD_BUFFER_SIZE

The LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction One possible cause is that the slave device is not present

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NOT_FOUND

I2C slave address exceeds maximum address

EFI_NO_MAPPING

Invalid I2cBusConfiguration value due to invalid platform data

EFI_NO_MEDIA

State was lost because more than one device was reset

EFI_NO_RESPONSE

The I2C device is not responding to the slave address EFI_DEVICE_ERROR may also be returned if the controller cannot distinguish when the NACK occurred

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_TIMEOUT

The transaction did not complete within the specified timeout period

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.3.14. I2C Bus Configuration Management PPI

17.3.15. EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT

Summary

The EFI I2C bus configuration management PPI enables the host driver to interact with the platform layer to reconfigure the switches and multiplexers and set the clock speed for the I2C bus. This PPI also enables the I2C host driver to reset an I2C device which may be locking up the I2C bus by holding the clock or data line low.

GUID

#define EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT_GUID \
{ 0xe721de6f, 0x145b, 0x4532, 0xbd, 0x78, 0x9b, 0x40, \
0x95, 0xc7, 0x46, 0x97 }

PEIM-to-PEIM Interface Structure

typedef struct {

  EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT_ENABLE_I2C_BUS_CONFIGURATION EnableI2cBusConfiguration;
  EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT_I2C_DEVICE_RESET I2cDeviceReset;
} EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT;

Parameters

EnableI2cBusConfiguration

Enable an I2C bus configuration for use.

I2cDeviceReset

Perform a platform specific reset for the specified I2C part and the I2C controller.

ControllerNumber

Unique number identifying the I2C controller in the system.

Description

The I2C driver stack uses the concept of an I2C bus configuration as a way to describe a particular state of the switches and multiplexers in the I2C bus.

A simple I2C bus does not have any multiplexers or switches is described to the I2C driver stack with a single I2C bus configuration.

An I2C bus with switches and multiplexers use an I2C bus configuration to describe each of the unique settings for the switches and multiplexers. However the I2C platform driver only needs to define the I2C bus configurations that the software uses, which is a subset of the total.

The upper layer driver locates the correct EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT interface (I2cBusConfig) by comparing the following field:

  • I2cBusConfigControllerNumber with the system unique value for the I2C ControllerNumber

The I2C bus configuration description includes a list of I2C devices which may be accessed when this I2C bus configuration is enabled. I2C devices before a switch or multiplexer must be included in one I2C bus configuration while I2C devices after a switch or multiplexer are on another I2C bus configuration.

The I2C bus configuration management PPI is an optional PPI provided by the I2C platform driver. The I2C host driver only starts for this I2C controller if the I2C bus configuration management PPI is present. The I2C host driver uses the I2C bus configuration management PPI to call into the I2C platform driver to set the switches and multiplexers and set the maximum I2C bus frequency.

The platform designers determine the maximum I2C bus frequency by selecting a frequency which supports all of the I2C devices on the I2C bus for the setting of switches and multiplexers. The platform designers must validate this against the I2C device data sheets and any limits of the I2C controller or bus length.

17.3.16. EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT.EnableI2cBusConfiguration()

Summary

Enable access to an I2C bus configuration.

Prototype

typedef
EFI_STATUS
(EFIAPI
*EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT_ENABLE_I2C_BUS_CONFIGURATION)  (
  IN EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT  *This,
  IN UINTN                                     I2cBusConfiguration
);

Parameters

This

Address of an EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT structure.

I2cBusConfiguration

Index into a list or array of I2C bus configurations

Description

Reconfigure the switches and multiplexers in the I2C bus to enable access to a specific I2C bus configuration. Also select the maximum clock frequency for this I2C bus configuration.

This routine uses the I2C Master PPI when the platform routine needs to perform I2C transactions on the local bus. This eliminates any recursion in the I2C stack for configuration transactions on the local bus.

The platform layer must perform I2C transactions on other I2C busses by using the EFI_PEI_I2C_HOST PPI or third party driver interface for the specific device. Use the EFI_PEI_I2C_HOST PPI when the device is not defined by the I2C platform driver. Use the third party driver when it is available or EFI_PEI_I2C_IO when the third party driver is not available but the device is defined in the I2C platform driver.

Status Codes Returned

The values returned from EnableI2cBusConfiguration are:

EFI_SUCCESS

The transaction completed successfully

EFI_BAD_BUFFER_SIZE

The LengthInBytes value is too large

EFI_DEVICE_ERROR

There was an I2C error NACK during the transaction One possible cause is that the slave device is not present

EFI_INVALID_PARAMETER

RequestPacket is NULL

EFI_NOT_FOUND

I2C slave address exceeds maximum address

EFI_NO_MAPPING

Invalid I2cBusConfiguration value due to invalid platform data

EFI_NO_MEDIA

State was lost because more than one device was reset

EFI_NO_RESPONSE

The I2C device is not responding to the slave address EFI_DEVICE_ERROR may also be returned if the controller cannot distinguish when the NACK occurred

EFI_OUT_OF_RESOURCES

Insufficient memory for I2C transaction

EFI_TIMEOUT

The transaction did not complete within the specified timeout period

EFI_UNSUPPORTED

The controller does not support the requested transaction

17.3.17. EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT.I2cDeviceReset()

Summary

Perform a platform specific reset for the specified I2C part and the I2C controller.

Prototype

typedef
EFI_STATUS
(EFIAPI
*EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT_I2C_DEVICE_RESET)  (
  IN CONST EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT  *This,
  IN UINTN                                  I2cBusConfiguration,
  IN UINTN                                  SlaveAddress
);

Parameters

This

Address of an EFI_PEI_I2C_BUS_CONFIGURATION_MANAGEMENT structure.

I2cBusConfiguration

Index into a list or array of I2C bus configurations

SlaveAddress

Address of the device on the I2C bus.

Description

This error handling routine is called by the I2C host driver when EFI_TIMEOUT status is returned by the I2C port driver for an EFI_I2C_REQUEST_PACKET . This routine attempts to reset the failing I2C device and the I2C controller.

Status Codes Returned

The values returned from I2cDeviceReset are:

EFI_SUCCESS

The transaction completed successfully Only the requested I2C device and the I2C controller were reset

EFI_NO_MAPPING

Invalid I2cBusConfiguration value due to invalid platform data

EFI_NO_MEDIA

State was lost because more than one device was reset The host driver needs to return errors for the queue of pending EFI_I2C_REQUEST_PACKETs

17.3.18. I2C Enumerate PPI

17.3.19. EFI_PEI_I2C_ENUMERATE

Summary

Support the enumeration of the I2C devices listed in the I2C platform driver.

GUID

#define EFI_PEI_I2C_ENUMERATE_GUID \
{ 0xbe83f6f4, 0xe286, 0x4e70, 0xb4, 0x51, 0x1a, 0x2e, \
0x42, 0xdf, 0x31, 0x03 }

Protocol Interface Structure

typedef struct {
  EFI_PEI_I2C_ENUMERATE_ENUMERATE          Enumerate;
  EFI_PEI_I2C_ENUMERATE_GET_BUS_FREQUENCY  GetBusFrequency;
} EFI_PEI_I2C_ENUMERATE;

Parameters

Enumerate

Walk the platform’s list of I2C devices on the bus. This routine returns the next I2C device in the platform’s list for this I2C bus.

GetBusFrequency

Get the I2C bus frequency for the bus configuration.

Description

The I2C bus driver uses this PPI to enumerate the devices on the I2C bus listed in the platform layer.

The upper layer driver locates the correct EFI_PEI_I2C_ENUMERATE interface (I2cEnumerate) by comparing the following field:

  • I2cEnumerateControllerNumber with the system unique value for the I2C ControllerNumber .

17.3.20. EFI_PEI_I2C_ENUMERATE_PROTOCOL.Enumerate()

Summary

Enumerate the I2C devices

Prototype

typedef
EFI_STATUS
(EFIAPI \*EFI_PEI_I2C_ENUMERATE_ENUMERATE) (
  IN EFI_PEI_I2C_ENUMERATE      *This,
  IN OUT CONST EFI_I2C_DEVICE   **Device
);

Parameters

This

Address of an EFI_PEI_I2C_ENUMERATE structure.

Device

Address of a buffer containing an EFI_I2C_DEVICE structure. Enumeration is started by setting the initial EFI_I2C_DEVICE structure address to NULL . The buffer receives an EFI_I2C_DEVICE structure address for the next I2C device.

Description

This function walks the platform specific data to enumerate the I2C devices on an I2C bus.

Status Codes Returned

The values returned from Enumerate are:

EFI_SUCCESS

The platform data for the next device on the I2C bus was returned successfully

EFI_INVALID_PARAMETER

Device was NULL

EFI_NO_MAPPING

Device does not point to a valid EFI_I2C_DEVICE structure

17.3.21. EFI_PEI_I2C_ENUMERATE_PROTOCOL.GetBusFrequency()

Summary

Get the I2C bus frequency for the bus configuration.

Prototype

typedef
EFI_STATUS
(EFIAPI *EFI_PEI_I2C_ENUMERATE_GET_BUS_FREQUENCY) (
  IN EFI_PEI_I2C_ENUMERATE  *This,
  IN UNITN                  I2cBusConfiguration,
  IN OUT UINTN              *BusClockHertz
  );

Parameters

This

Address of an EFI_PEI_I2C_ENUMERATE structure.

I2cBusConfiguration

I2C bus configuration to access the I2C device

BusClockHertz

Address to receive the I2C bus clock frequency in Hertz

Description

This function returns the I2C bus clock frequency for the specified I2C bus configuration.

Status Codes Returned

The values returned from GetBusFrequency are:

Table 17.1 Status Codes Returned

EFI_SUCCESS

The I2C bus frequency was returned

EFI_INVALID_PARAMETER

BusClockHertz was NULL

EFI_NO_MAPPING

Invalid I2cBusConfiguration value