# Configure I2C Buses

## Config options

The I2C options are prefixed with `CONFIG_I2C*`. Evaluate whether each option is
appropriate to add to your board.

A typical EC and board should at a minimum set `CONFIG_I2C` and
`CONFIG_I2C_CONTROLLER`.

## Feature Parameters

The following parameters control the behavior of the I2C library. [config.h]
defines a reasonable default value, but you may need to change the default value
for your board.

-   `CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE <bytes>`
-   `CONFIG_I2C_NACK_RETRY_COUNT <count>`
-   `CONFIG_I2C_EXTRA_PACKET_SIZE <bytes>` - Only used on STM32 EC's if
    `CONFIG_HOSTCMD_I2C_ADDR_FLAGS` is defined.

## GPIOs and Alternate Pins

In the gpio.inc file, you need to define a GPIO for the clock (SCL) and data
(SDA) pin used on each active I2C bus. The corresponding GPIOs are then included
in the `i2c_ports[]` array. This permits the I2C library to perform common bus
recovery actions using bit-banging without involvement by the EC-specific I2C
device driver.

You also need to define the alternate function assignment for all I2C pins using
the `ALTERNATE()` macro. This step can be skipped for any pins that default to
I2C functionality.

Note that many I2C buses only support 1.8V operation. This is determined by I2C
devices connected to the bus. In this case you need to include `GPIO_SEL_1P8V`
as part of the `flags` field in both the `GPIO()` and `ALTERNATE()` macros. I2C
bus 0 in the example below demonstrates configuring the SCL and SDA pins for
1.8V operation.

See the [GPIO](./gpio.md) documentation for additional details on the GPIO
macros.

## Data Structures

-   `const struct i2c_port_t i2c_ports[]` - This array should be defined in your
    baseboard.c or board.c file. This array defines the mapping of internal I2C
    port numbers used by the I2C library to the physical I2C ports connected to
    the EC.
-   `const unsigned int i2c_port_used = ARRAY_SIZE(i2c_ports)` - Defines the
    number of internal I2C ports accessible by the I2C library.

## Tasks

None required by this feature.

## Testing and Debugging

### Console Commands

-   `i2cscan` - Provides a quick look of all I2C devices found on all configured
    buses.
-   `i2cxfer` - Allows you to read and write individual registers on an I2C
    device.

For runtime troubleshooting of an I2C device, enable and the
[I2C tracing](../i2c-debugging.md) module to log all I2C transactions initiated
by the EC code.

## Example

The image below shows the I2C bus assignment for the Volteer reference board.

![I2C Example]

The `gpio.inc` file for Volteer defines both `GPIO()` and `ALTERNATE()` entries
for all I2C buses used in the design.

```c
/* I2C pins - Alternate function below configures I2C module on these pins */
GPIO(EC_I2C0_SENSOR_SCL,       PIN(B, 5), GPIO_INPUT | GPIO_SEL_1P8V)
GPIO(EC_I2C0_SENSOR_SDA,       PIN(B, 4), GPIO_INPUT | GPIO_SEL_1P8V)
GPIO(EC_I2C1_USB_C0_SCL,       PIN(9, 0), GPIO_INPUT)
GPIO(EC_I2C1_USB_C0_SDA,       PIN(8, 7), GPIO_INPUT)
GPIO(EC_I2C2_USB_C1_SCL,       PIN(9, 2), GPIO_INPUT)
GPIO(EC_I2C2_USB_C1_SDA,       PIN(9, 1), GPIO_INPUT)
GPIO(EC_I2C3_USB_1_MIX_SCL,    PIN(D, 1), GPIO_INPUT)
GPIO(EC_I2C3_USB_1_MIX_SDA,    PIN(D, 0), GPIO_INPUT)
GPIO(EC_I2C5_POWER_SCL,        PIN(3, 3), GPIO_INPUT)
GPIO(EC_I2C5_POWER_SDA,        PIN(3, 6), GPIO_INPUT)
GPIO(EC_I2C7_EEPROM_SCL,       PIN(B, 3), GPIO_INPUT)
GPIO(EC_I2C7_EEPROM_SDA,       PIN(B, 2), GPIO_INPUT)

/* Alternate functions GPIO definitions */
ALTERNATE(PIN_MASK(B, BIT(5) | BIT(4)), 0, MODULE_I2C, (GPIO_INPUT | GPIO_SEL_1P8V)) /* I2C0 */
ALTERNATE(PIN_MASK(9, BIT(0) | BIT(2) | BIT(1)), 0, MODULE_I2C, 0)                   /* I2C1 SCL / I2C2 */
ALTERNATE(PIN_MASK(8, BIT(7)), 0, MODULE_I2C, 0)                                     /* I2C1 SDA */
ALTERNATE(PIN_MASK(D, BIT(1) | BIT(0)), 0, MODULE_I2C, 0)                            /* I2C3 */
ALTERNATE(PIN_MASK(3, BIT(3) | BIT(6)), 0, MODULE_I2C, 0)                            /* I2C5 */
ALTERNATE(PIN_MASK(B, BIT(3) | BIT(2)), 0, MODULE_I2C, 0)                            /* I2C7 */
```

The `i2c_ports[]` array requires the `.port` field to be assigned to an EC
chipset specific enumeration. For the NPCx7 I2C bus names are defined in
[./chip/npcx/registers.h]. The Volteer `baseboard.h` file creates a mapping from
the schematic net name to the NPCx7 I2C bus enumeration.

```c
#define CONFIG_I2C
#define I2C_PORT_SENSOR     NPCX_I2C_PORT0_0
#define I2C_PORT_USB_C0     NPCX_I2C_PORT1_0
#define I2C_PORT_USB_C1     NPCX_I2C_PORT2_0
#define I2C_PORT_USB_1_MIX  NPCX_I2C_PORT3_0
#define I2C_PORT_POWER      NPCX_I2C_PORT5_0
#define I2C_PORT_EEPROM     NPCX_I2C_PORT7_0
```

The last piece for I2C configuration is to create the `i2c_ports[]` array using
the macros and enumerations added to `baseboard.h` and `gpio.inc`.

```c
/* I2C port map configuration */
const struct i2c_port_t i2c_ports[] = {
    {
        .name = "sensor",
        .port = I2C_PORT_SENSOR,
        .kbps = 400,
        .scl = GPIO_EC_I2C0_SENSOR_SCL,
        .sda = GPIO_EC_I2C0_SENSOR_SDA,
        .flags = 0,
    },
    {
        .name = "usb_c0",
        .port = I2C_PORT_USB_C0,
        /*
         * I2C buses used for PD communication must be set for 400 kbps
         * or greater. Set to the maximum speed supported by all devices.
         */
        .kbps = 1000,
        .scl = GPIO_EC_I2C1_USB_C0_SCL,
        .sda = GPIO_EC_I2C1_USB_C0_SDA,
    },
    {
        .name = "usb_c1",
        .port = I2C_PORT_USB_C1,
        /*
         * I2C buses used for PD communication must be set for 400 kbps
         * or greater. Set to the maximum speed supported by all devices.
         */
        .scl = GPIO_EC_I2C2_USB_C1_SCL,
        .sda = GPIO_EC_I2C2_USB_C1_SDA,
    },
    {
        .name = "usb_1_mix",
        .port = I2C_PORT_USB_1_MIX,
        .kbps = 100,
        .scl = GPIO_EC_I2C3_USB_1_MIX_SCL,
        .sda = GPIO_EC_I2C3_USB_1_MIX_SDA,
    },
    {
        .name = "power",
        .port = I2C_PORT_POWER,
        .kbps = 100,
        .scl = GPIO_EC_I2C5_POWER_SCL,
        .sda = GPIO_EC_I2C5_POWER_SDA,
    },
    {
        .name = "eeprom",
        .port = I2C_PORT_EEPROM,
        .kbps = 400,
        .scl = GPIO_EC_I2C7_EEPROM_SCL,
        .sda = GPIO_EC_I2C7_EEPROM_SDA,
    },
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
```

The `.flags` field is optional when using the default I2C bus setup. See
[./include/i2c.h] for the full list of supported flags.

The flag `I2C_PORT_FLAG_DYNAMIC_SPEED` allows the I2C bus frequency to be
changed at runtime. The typical use case is to set the I2C bus frequency to
different speeds based on the BOARD_VERSION in [CBI]. For example board version
1 supports 100 kbps operation but board version 2 and greater supports 400 kbps
operation. `I2C_PORT_FLAG_DYNAMIC_SPEED` is not used to change the I2C bus
frequency on the fly depending on the addressed slave device.

An example of changing the I2C bus frequency from the
[Kodama board](../../board/kodama/board.c) is shown below.

```c
static void board_i2c_init(void)
{
    if (board_get_version() < 2)
        i2c_set_freq(1,  I2C_FREQ_100KHZ);
}
DECLARE_HOOK(HOOK_INIT, board_i2c_init, HOOK_PRIO_INIT_I2C);
```

[config.h]: ../new_board_checklist.md#config_h
[./chip/npcx/registers.h]: ../../chip/npcx/registers.h
[./include/i2c.h]: ../../include/i2c.h
[I2C Example]: ../images/i2c_example.png
[CBI]: https://chromium.googlesource.com/chromiumos/docs/+/HEAD/design_docs/cros_board_info.md
