summaryrefslogtreecommitdiff
path: root/docs/configuration/i2c.md
blob: 7a6241e349582d71eb8475f883f7645baa552b24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# 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/+/master/design_docs/cros_board_info.md