1 /*
2  * This driver creates fake I2C buses which can contain emulated devices,
3  * implemented by a separate emulation driver. The API between this driver and
4  * its emulators is defined by struct i2c_emul_driver_api.
5  *
6  * Copyright 2020 Google LLC
7  * Copyright (c) 2020 Nordic Semiconductor ASA
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #define DT_DRV_COMPAT zephyr_i2c_emul_controller
13 
14 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(i2c_emul_ctlr);
17 
18 #include <zephyr/device.h>
19 #include <zephyr/drivers/emul.h>
20 #include <zephyr/drivers/i2c.h>
21 #include <zephyr/drivers/i2c_emul.h>
22 
23 #include "i2c-priv.h"
24 
25 /** Working data for the device */
26 struct i2c_emul_data {
27 	/* List of struct i2c_emul associated with the device */
28 	sys_slist_t emuls;
29 	/* I2C host configuration */
30 	uint32_t config;
31 	uint32_t bitrate;
32 #ifdef CONFIG_I2C_TARGET
33 	struct i2c_target_config *target_cfg;
34 #endif
35 };
36 
37 struct i2c_emul_config {
38 	struct emul_list_for_bus emul_list;
39 	bool target_buffered_mode;
40 	const struct i2c_dt_spec *forward_list;
41 	uint16_t forward_list_size;
42 };
43 
44 /**
45  * Find an emulator by its I2C address
46  *
47  * @param dev I2C emulation controller device
48  * @param addr I2C address of that device
49  * @return emulator ro use
50  * @return NULL if not found
51  */
i2c_emul_find(const struct device * dev,int addr)52 static struct i2c_emul *i2c_emul_find(const struct device *dev, int addr)
53 {
54 	struct i2c_emul_data *data = dev->data;
55 	sys_snode_t *node;
56 
57 	SYS_SLIST_FOR_EACH_NODE(&data->emuls, node) {
58 		struct i2c_emul *emul = NULL;
59 
60 		emul = CONTAINER_OF(node, struct i2c_emul, node);
61 		if (emul->addr == addr) {
62 			return emul;
63 		}
64 	}
65 
66 	return NULL;
67 }
68 
i2c_emul_configure(const struct device * dev,uint32_t dev_config)69 static int i2c_emul_configure(const struct device *dev, uint32_t dev_config)
70 {
71 	struct i2c_emul_data *data = dev->data;
72 
73 	data->config = dev_config;
74 
75 	return 0;
76 }
77 
i2c_emul_get_config(const struct device * dev,uint32_t * dev_config)78 static int i2c_emul_get_config(const struct device *dev, uint32_t *dev_config)
79 {
80 	struct i2c_emul_data *data = dev->data;
81 
82 	*dev_config = data->config;
83 
84 	return 0;
85 }
86 
87 #ifdef CONFIG_I2C_TARGET
i2c_emul_send_to_target(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs)88 static int i2c_emul_send_to_target(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs)
89 {
90 	struct i2c_emul_data *data = dev->data;
91 	const struct i2c_target_callbacks *callbacks = data->target_cfg->callbacks;
92 
93 #ifdef CONFIG_I2C_TARGET_BUFFER_MODE
94 	const struct i2c_emul_config *config = dev->config;
95 
96 	if (config->target_buffered_mode) {
97 		for (uint8_t i = 0; i < num_msgs; ++i) {
98 			if (i2c_is_read_op(&msgs[i])) {
99 				uint8_t *ptr = NULL;
100 				uint32_t len;
101 				int rc =
102 					callbacks->buf_read_requested(data->target_cfg, &ptr, &len);
103 
104 				if (rc != 0) {
105 					return rc;
106 				}
107 				if (len > msgs[i].len) {
108 					LOG_ERR("buf_read_requested returned too many bytes");
109 					return -ENOMEM;
110 				}
111 				memcpy(msgs[i].buf, ptr, len);
112 			} else {
113 				callbacks->buf_write_received(data->target_cfg, msgs[i].buf,
114 							      msgs[i].len);
115 			}
116 			if (i2c_is_stop_op(&msgs[i])) {
117 				int rc = callbacks->stop(data->target_cfg);
118 
119 				if (rc != 0) {
120 					return rc;
121 				}
122 			}
123 		}
124 		return 0;
125 	}
126 #endif /* CONFIG_I2C_TARGET_BUFFER_MODE */
127 
128 	for (uint8_t i = 0; i < num_msgs; ++i) {
129 		LOG_DBG("    msgs[%u].flags? 0x%02x", i, msgs[i].flags);
130 		if (i2c_is_read_op(&msgs[i])) {
131 			for (uint32_t j = 0; j < msgs[i].len; ++j) {
132 				int rc = 0;
133 
134 				if (j == 0) {
135 					LOG_DBG("    Calling read_requested with data %p",
136 						(void *)&msgs[i].buf[j]);
137 					rc = callbacks->read_requested(data->target_cfg,
138 								       &msgs[i].buf[j]);
139 				} else {
140 					LOG_DBG("    Calling read_processed with data %p",
141 						(void *)&msgs[i].buf[j]);
142 					rc = callbacks->read_processed(data->target_cfg,
143 								       &msgs[i].buf[j]);
144 				}
145 				if (rc != 0) {
146 					return rc;
147 				}
148 			}
149 		} else {
150 			for (uint32_t j = 0; j < msgs[i].len; ++j) {
151 				int rc = 0;
152 
153 				if (j == 0) {
154 					LOG_DBG("    Calling write_requested");
155 					rc = callbacks->write_requested(data->target_cfg);
156 				}
157 				if (rc != 0) {
158 					return rc;
159 				}
160 				LOG_DBG("    Calling write_received with data 0x%02x",
161 					msgs[i].buf[j]);
162 				rc = callbacks->write_received(data->target_cfg, msgs[i].buf[j]);
163 				if (rc != 0) {
164 					return rc;
165 				}
166 			}
167 		}
168 		if (i2c_is_stop_op(&msgs[i])) {
169 			int rc = callbacks->stop(data->target_cfg);
170 
171 			if (rc != 0) {
172 				return rc;
173 			}
174 		}
175 	}
176 	return 0;
177 }
178 #endif /* CONFIG_I2C_TARGET*/
179 
i2c_emul_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)180 static int i2c_emul_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
181 			     uint16_t addr)
182 {
183 	const struct i2c_emul_config *conf = dev->config;
184 	struct i2c_emul *emul;
185 	const struct i2c_emul_api *api;
186 	int ret;
187 
188 	LOG_DBG("%s(dev=%p, addr=0x%02x)", __func__, (void *)dev, addr);
189 #ifdef CONFIG_I2C_TARGET
190 	struct i2c_emul_data *data = dev->data;
191 
192 	/*
193 	 * First check if the bus is configured as a target, targets either listen to the address or
194 	 * ignore the messages. So if the address doesn't match, we're just going to bail.
195 	 */
196 	LOG_DBG("    has_target_cfg? %d", data->target_cfg != NULL);
197 	if (data->target_cfg != NULL) {
198 		LOG_DBG("    target_cfg->address? 0x%02x", data->target_cfg->address);
199 		if (data->target_cfg->address != addr) {
200 			return -EINVAL;
201 		}
202 		LOG_DBG("    forwarding to target");
203 		return i2c_emul_send_to_target(dev, msgs, num_msgs);
204 	}
205 #endif /* CONFIG_I2C_TARGET */
206 
207 	/*
208 	 * We're not a target, but lets check if we need to forward this request before we start
209 	 * looking for a peripheral.
210 	 */
211 	for (uint16_t i = 0; i < conf->forward_list_size; ++i) {
212 		LOG_DBG("    Checking forward list [%u].addr? 0x%02x", i,
213 			conf->forward_list[i].addr);
214 		if (conf->forward_list[i].addr == addr) {
215 			/* We need to forward this request */
216 			return i2c_transfer(conf->forward_list[i].bus, msgs, num_msgs, addr);
217 		}
218 	}
219 
220 	emul = i2c_emul_find(dev, addr);
221 	if (!emul) {
222 		return -EIO;
223 	}
224 
225 	api = emul->api;
226 	__ASSERT_NO_MSG(emul->api);
227 	__ASSERT_NO_MSG(emul->api->transfer);
228 
229 	if (emul->mock_api != NULL && emul->mock_api->transfer != NULL) {
230 		ret = emul->mock_api->transfer(emul->target, msgs, num_msgs, addr);
231 		if (ret != -ENOSYS) {
232 			return ret;
233 		}
234 	}
235 
236 	return api->transfer(emul->target, msgs, num_msgs, addr);
237 }
238 
239 /**
240  * Set up a new emulator and add it to the list
241  *
242  * @param dev I2C emulation controller device
243  */
i2c_emul_init(const struct device * dev)244 static int i2c_emul_init(const struct device *dev)
245 {
246 	struct i2c_emul_data *data = dev->data;
247 	int rc;
248 
249 	sys_slist_init(&data->emuls);
250 
251 	rc = emul_init_for_bus(dev);
252 
253 	/* Set config to an uninitialized state */
254 	data->config = (I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(data->bitrate));
255 
256 	return rc;
257 }
258 
i2c_emul_register(const struct device * dev,struct i2c_emul * emul)259 int i2c_emul_register(const struct device *dev, struct i2c_emul *emul)
260 {
261 	struct i2c_emul_data *data = dev->data;
262 	const char *name = emul->target->dev->name;
263 
264 	sys_slist_append(&data->emuls, &emul->node);
265 
266 	LOG_INF("Register emulator '%s' at I2C addr %02x", name, emul->addr);
267 
268 	return 0;
269 }
270 
271 #ifdef CONFIG_I2C_TARGET
i2c_emul_target_register(const struct device * dev,struct i2c_target_config * cfg)272 static int i2c_emul_target_register(const struct device *dev, struct i2c_target_config *cfg)
273 {
274 	struct i2c_emul_data *data = dev->data;
275 
276 	data->target_cfg = cfg;
277 	return 0;
278 }
279 
i2c_emul_target_unregister(const struct device * dev,struct i2c_target_config * cfg)280 static int i2c_emul_target_unregister(const struct device *dev, struct i2c_target_config *cfg)
281 {
282 	struct i2c_emul_data *data = dev->data;
283 
284 	if (data->target_cfg != cfg) {
285 		return -EINVAL;
286 	}
287 
288 	data->target_cfg = NULL;
289 	return 0;
290 }
291 #endif /* CONFIG_I2C_TARGET */
292 
293 /* Device instantiation */
294 
295 static DEVICE_API(i2c, i2c_emul_api) = {
296 	.configure = i2c_emul_configure,
297 	.get_config = i2c_emul_get_config,
298 	.transfer = i2c_emul_transfer,
299 #ifdef CONFIG_I2C_TARGET
300 	.target_register = i2c_emul_target_register,
301 	.target_unregister = i2c_emul_target_unregister,
302 #endif
303 #ifdef CONFIG_I2C_RTIO
304 	.iodev_submit = i2c_iodev_submit_fallback,
305 #endif
306 };
307 
308 #define EMUL_LINK_AND_COMMA(node_id)                                                               \
309 	{                                                                                          \
310 		.dev = DEVICE_DT_GET(node_id),                                                     \
311 	},
312 
313 #define EMUL_FORWARD_ITEM(node_id, prop, idx)                                                      \
314 	{                                                                                          \
315 		.bus = DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)),                       \
316 		.addr = DT_PHA_BY_IDX(node_id, prop, idx, addr),                                   \
317 	},
318 
319 #define I2C_EMUL_INIT(n)                                                                           \
320 	static const struct emul_link_for_bus emuls_##n[] = {                                      \
321 		DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(n), EMUL_LINK_AND_COMMA)};                \
322 	static const struct i2c_dt_spec emul_forward_list_##n[] = {                                \
323 		COND_CODE_1(DT_INST_NODE_HAS_PROP(n, forwards),                                    \
324 			    (DT_INST_FOREACH_PROP_ELEM(n, forwards, EMUL_FORWARD_ITEM)), ())};     \
325 	static struct i2c_emul_config i2c_emul_cfg_##n = {                                         \
326 		.emul_list =                                                                       \
327 			{                                                                          \
328 				.children = emuls_##n,                                             \
329 				.num_children = ARRAY_SIZE(emuls_##n),                             \
330 			},                                                                         \
331 		.target_buffered_mode = DT_INST_PROP(n, target_buffered_mode),                     \
332 		.forward_list = emul_forward_list_##n,                                             \
333 		.forward_list_size = ARRAY_SIZE(emul_forward_list_##n),                            \
334 	};                                                                                         \
335 	static struct i2c_emul_data i2c_emul_data_##n = {                                          \
336 		.bitrate = DT_INST_PROP(n, clock_frequency),                                       \
337 	};                                                                                         \
338 	I2C_DEVICE_DT_INST_DEFINE(n, i2c_emul_init, NULL, &i2c_emul_data_##n, &i2c_emul_cfg_##n,   \
339 				  POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, &i2c_emul_api);
340 
341 DT_INST_FOREACH_STATUS_OKAY(I2C_EMUL_INIT)
342