summaryrefslogtreecommitdiff
path: root/zephyr/shim/include/i2c/i2c.h
blob: 3e95fbc9d360d1ba012e8ed22c4ad481b013d3b7 (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
205
206
207
/* Copyright 2020 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef ZEPHYR_CHROME_I2C_I2C_H
#define ZEPHYR_CHROME_I2C_I2C_H

#include <zephyr/device.h>
#include <zephyr/devicetree.h>

#ifdef CONFIG_PLATFORM_EC_I2C
#if DT_NODE_EXISTS(DT_PATH(named_i2c_ports))

#define NPCX_PORT_COMPAT nuvoton_npcx_i2c_port
#define ITE_IT8XXX2_PORT_COMPAT ite_it8xxx2_i2c
#define ITE_ENHANCE_PORT_COMPAT ite_enhance_i2c
#define MICROCHIP_XEC_COMPAT microchip_xec_i2c_v2
#define I2C_EMUL_COMPAT zephyr_i2c_emul_controller
#define I2C_FOREACH_PORT(fn)                                \
	DT_FOREACH_STATUS_OKAY(NPCX_PORT_COMPAT, fn)        \
	DT_FOREACH_STATUS_OKAY(ITE_IT8XXX2_PORT_COMPAT, fn) \
	DT_FOREACH_STATUS_OKAY(ITE_ENHANCE_PORT_COMPAT, fn) \
	DT_FOREACH_STATUS_OKAY(MICROCHIP_XEC_COMPAT, fn)    \
	DT_FOREACH_STATUS_OKAY(I2C_EMUL_COMPAT, fn)

/*
 * Get the legacy I2C port enum value from the I2C bus node identifier.
 * The value returned by this macro is passed as the 'int port' parameter to all
 * the legacy APIs provided by i2c_controller.h
 *
 * Example devicetree fragment:
 *
 *     / {
 *         soc-if {
 *             i2c2_0: io_i2c_ctrl2_port0 {
 *                 compatible = "nuvoton,npcx-i2c-port";
 *                 #address-cells = <1>;
 *                 #size-cells = <0>;
 *                 port = <0x20>;
 *                 controller = <&i2c_ctrl2>;
 *                 label = "I2C_2_PORT_0";
 *                 status = "disabled";
 *             };
 *         }.
 *     };
 *
 * Example usage to get the I2C port enum value for i2c2_0:
 *
 *     I2C_PORT_BUS(DT_NODELABEL(i2c2_0))
 *     // I2C_BUS_DT_N_S_soc_if_S_io_i2c_ctrl2_port0
 *
 * @param i2c_port_id: node id of a I2C port device
 */
#define I2C_PORT_BUS(i2c_port_id) DT_CAT(I2C_BUS_, i2c_port_id)
#define I2C_PORT_BUS_WITH_COMMA(i2c_port_id) I2C_PORT_BUS(i2c_port_id),

/*
 * Get the legacy I2C port enum value from a named-i2c-ports child node.
 *
 * Example devicetree fragment:
 *
 *     i2c0_0: io_i2c_ctrl0_port0 {
 *         compatible = "nuvoton,npcx-i2c-port";
 *         #address-cells = <1>;
 *         #size-cells = <0>;
 *         port = <0x00>;
 *         controller = <&i2c_ctrl0>;
 *         label = "I2C_0_PORT_0";
 *         status = "disabled";
 *     };
 *
 *     named-i2c-ports {
 *         compatible = "named-i2c-ports";
 *         i2c_sensor: sensor {
 *             i2c-port = <&i2c0_0>;
 *             enum-names = "I2C_PORT_SENSOR";
 *         };
 *     };
 *
 * Example usage to get the I2C port enum value for i2c_sensor:
 *
 *     I2C_PORT(DT_NODELABEL(i2c_sensor))
 *
 * which equals:
 *
 *     I2C_PORT_BUS(DT_NODELABEL(i2c0_0))
 *
 * @param i2c_named_id: node id of a child of the named-i2c-ports node
 */
#define I2C_PORT(i2c_named_id) I2C_PORT_BUS(DT_PHANDLE(i2c_named_id, i2c_port))

/*
 * Get the legacy I2C port enum from the I2C bus nodelabel. This macro should be
 * used with the I2C port device node, not the named-i2c-port child node.
 *
 *     / {
 *         soc-if {
 *             i2c2_0: io_i2c_ctrl2_port0 {
 *                 compatible = "nuvoton,npcx-i2c-port";
 *                 #address-cells = <1>;
 *                 #size-cells = <0>;
 *                 port = <0x20>;
 *                 controller = <&i2c_ctrl2>;
 *                 label = "I2C_2_PORT_0";
 *                 status = "disabled";
 *             };
 *         }.
 *     };
 *
 * Example usage to get the I2C port enum value for i2c2_0:
 *
 *     I2C_PORT_NODELABEL(i2c2_0)
 *     // I2C_BUS_DT_N_S_soc_if_S_io_i2c_ctrl2_port0
 *
 * @param label: nodelabel of a I2C port device
 */
#define I2C_PORT_NODELABEL(label) I2C_PORT_BUS(DT_NODELABEL(label))

/*
 * Get the legacy I2C port enum for a child device on an I2C bus.
 *
 * Example devicetree fragment:
 *
 *     i2c2_0: io_i2c_ctrl2_port0 {
 *         compatible = "nuvoton,npcx-i2c-port";
 *         #address-cells = <1>;
 *         #size-cells = <0>;
 *         port = <0x20>;
 *         controller = <&i2c_ctrl2>;
 *         label = "I2C_2_PORT_0";
 *         status = "disabled";
 *     };
 *
 *     &i2c2_0 {
 *         bc12_port0: pi3usb9201@5f {
 *             compatible = "pericom,pi3usb9201";
 *             status = "okay";
 *             reg = <0x5f>;
 *             irq = <&int_usb_c0_bc12>;
 *         };
 *     };
 *
 * Example usage to get the I2C port enum value for bc12_port0:
 *
 *     I2C_PORT_BY_DEV(DT_NODELABEL(bc12_port0))
 *
 *  * which equals:
 *
 *     I2C_PORT_BUS(DT_NODELABEL(i2c2_0))
 *
 * @param dev_id: node id of a device on the I2C bus
 */
#define I2C_PORT_BY_DEV(dev_id) I2C_PORT_BUS(DT_BUS(dev_id))

enum i2c_ports_chip {
	I2C_FOREACH_PORT(I2C_PORT_BUS_WITH_COMMA) I2C_PORT_COUNT
};

BUILD_ASSERT(I2C_PORT_COUNT != 0, "No I2C devices defined");

#define I2C_PORT_ENUM_IDX_COMMA(i2c_named_id, prop, idx)        \
	DT_STRING_UPPER_TOKEN_BY_IDX(i2c_named_id, prop, idx) = \
		I2C_PORT(i2c_named_id),
#define NAMED_I2C_PORT_COMMA(i2c_named_id) \
	DT_FOREACH_PROP_ELEM(i2c_named_id, enum_names, I2C_PORT_ENUM_IDX_COMMA)

/*
 * The enum i2c_ports maps the hard-coded I2C port names (such as
 * I2C_PORT_BATTERY or I2C_PORT_SENSOR) to the unique port numbers created by
 * enum i2c_ports_chip above for every I2C port devicetree node.
 */
enum i2c_ports {
	DT_FOREACH_CHILD(DT_PATH(named_i2c_ports), NAMED_I2C_PORT_COMMA)
};
#endif /* named_i2c_ports */
#endif /* CONFIG_PLATFORM_EC_I2C */

/**
 * @brief Adaptation of platform/ec's port IDs which map a port/bus to a device.
 *
 * This function should be implemented per chip and should map the enum value
 * defined for the chip for encoding each valid port/bus combination. For
 * example, the npcx chip defines the port/bus combinations NPCX_I2C_PORT* under
 * chip/npcx/registers-npcx7.h.
 *
 * Thus, the npcx shim should implement this function to map the enum values
 * to the correct devicetree device.
 *
 * @param port The port to get the device for.
 * @return Pointer to the device struct or {@code NULL} if none are available.
 */
const struct device *i2c_get_device_for_port(const int port);

/**
 * @brief Get a port number for a received remote port number.
 *
 * This function translate a received port number via the I2C_PASSTHRU host
 * command to a port number used in ZephyrEC based on remote_port property in
 * dts. The first port which matches the remote port number is returned.
 *
 * @param port The received remote port.
 * @return Port number used in EC. -1 if the remote port is not defined
 */
int i2c_get_port_from_remote_port(int remote_port);

#endif /* ZEPHYR_CHROME_I2C_I2C_H */