1 /*
2  * Copyright (c) 2017 BayLibre, SAS
3  * Copyright (c) 2020 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <errno.h>
9 #include <string.h>
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <stdio.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/util.h>
16 
17 #include <zephyr/drivers/i2c.h>
18 #include <zephyr/drivers/i2c/target/eeprom.h>
19 #include <zephyr/drivers/gpio.h>
20 
21 #include <zephyr/ztest.h>
22 
23 #define NODE_EP0 DT_NODELABEL(eeprom0)
24 #define NODE_EP1 DT_NODELABEL(eeprom1)
25 
26 #define TEST_DATA_SIZE	20
27 static const uint8_t eeprom_0_data[TEST_DATA_SIZE] = "0123456789abcdefghij";
28 static const uint8_t eeprom_1_data[TEST_DATA_SIZE] = "jihgfedcba9876543210";
29 static uint8_t i2c_buffer[TEST_DATA_SIZE];
30 
31 /*
32  * We need 5x(buffer size) + 1 to print a comma-separated list of each
33  * byte in hex, plus a null.
34  */
35 uint8_t buffer_print_eeprom[TEST_DATA_SIZE * 5 + 1];
36 uint8_t buffer_print_i2c[TEST_DATA_SIZE * 5 + 1];
37 
to_display_format(const uint8_t * src,size_t size,char * dst)38 static void to_display_format(const uint8_t *src, size_t size, char *dst)
39 {
40 	size_t i;
41 
42 	for (i = 0; i < size; i++) {
43 		sprintf(dst + 5 * i, "0x%02x,", src[i]);
44 	}
45 }
46 
run_full_read(const struct device * i2c,uint8_t addr,uint8_t addr_width,const uint8_t * comp_buffer)47 static int run_full_read(const struct device *i2c, uint8_t addr,
48 			 uint8_t addr_width, const uint8_t *comp_buffer)
49 {
50 	int ret;
51 	uint8_t start_addr[2];
52 
53 	TC_PRINT("Testing full read: Master: %s, address: 0x%x\n",
54 		 i2c->name, addr);
55 
56 	/* Read EEPROM from I2C Master requests, then compare */
57 	memset(start_addr, 0, sizeof(start_addr));
58 	ret = i2c_write_read(i2c, addr, start_addr, (addr_width >> 3), i2c_buffer, TEST_DATA_SIZE);
59 	zassert_equal(ret, 0, "Failed to read EEPROM");
60 
61 	if (memcmp(i2c_buffer, comp_buffer, TEST_DATA_SIZE)) {
62 		to_display_format(i2c_buffer, TEST_DATA_SIZE,
63 				  buffer_print_i2c);
64 		to_display_format(comp_buffer, TEST_DATA_SIZE,
65 				  buffer_print_eeprom);
66 		TC_PRINT("Error: Buffer contents are different: %s\n",
67 			 buffer_print_i2c);
68 		TC_PRINT("                         vs expected: %s\n",
69 			 buffer_print_eeprom);
70 		return -EIO;
71 	}
72 
73 	return 0;
74 }
75 
run_partial_read(const struct device * i2c,uint8_t addr,uint8_t addr_width,const uint8_t * comp_buffer,unsigned int offset)76 static int run_partial_read(const struct device *i2c, uint8_t addr,
77 			    uint8_t addr_width, const uint8_t *comp_buffer, unsigned int offset)
78 {
79 	int ret;
80 	uint8_t start_addr[2];
81 
82 	TC_PRINT("Testing partial read. Master: %s, address: 0x%x, off=%d\n",
83 		 i2c->name, addr, offset);
84 
85 	switch (addr_width) {
86 	case 8:
87 		start_addr[0] = (uint8_t) (offset & 0xFF);
88 	break;
89 	case 16:
90 		sys_put_be16((uint16_t)(offset & 0xFFFF), start_addr);
91 	break;
92 	default:
93 		return -EINVAL;
94 	}
95 
96 	ret = i2c_write_read(i2c, addr,
97 			     start_addr, (addr_width >> 3), i2c_buffer, TEST_DATA_SIZE-offset);
98 	zassert_equal(ret, 0, "Failed to read EEPROM");
99 
100 	if (memcmp(i2c_buffer, &comp_buffer[offset], TEST_DATA_SIZE-offset)) {
101 		to_display_format(i2c_buffer, TEST_DATA_SIZE-offset,
102 				  buffer_print_i2c);
103 		to_display_format(&comp_buffer[offset], TEST_DATA_SIZE-offset,
104 				  buffer_print_eeprom);
105 		TC_PRINT("Error: Buffer contents are different: %s\n",
106 			 buffer_print_i2c);
107 		TC_PRINT("                         vs expected: %s\n",
108 			 buffer_print_eeprom);
109 		return -EIO;
110 	}
111 
112 	return 0;
113 }
114 
run_program_read(const struct device * i2c,uint8_t addr,uint8_t addr_width,unsigned int offset)115 static int run_program_read(const struct device *i2c, uint8_t addr,
116 			    uint8_t addr_width, unsigned int offset)
117 {
118 	int ret, i;
119 	uint8_t start_addr[2];
120 	struct i2c_msg msg[2];
121 
122 	TC_PRINT("Testing program. Master: %s, address: 0x%x, off=%d\n",
123 		i2c->name, addr, offset);
124 
125 	for (i = 0 ; i < TEST_DATA_SIZE-offset ; ++i) {
126 		i2c_buffer[i] = i;
127 	}
128 
129 	switch (addr_width) {
130 	case 8:
131 		start_addr[0] = (uint8_t) (offset & 0xFF);
132 	break;
133 	case 16:
134 		sys_put_be16((uint16_t)(offset & 0xFFFF), start_addr);
135 	break;
136 	default:
137 		return -EINVAL;
138 	}
139 
140 	msg[0].buf = start_addr;
141 	msg[0].len = (addr_width >> 3);
142 	msg[0].flags = I2C_MSG_WRITE;
143 	msg[1].buf = &i2c_buffer[0];
144 	msg[1].len = TEST_DATA_SIZE;
145 	msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
146 
147 	ret = i2c_transfer(i2c, &msg[0], 2, addr);
148 	zassert_equal(ret, 0, "Failed to write EEPROM");
149 
150 	(void)memset(i2c_buffer, 0xFF, TEST_DATA_SIZE);
151 
152 	/* Read back EEPROM from I2C Master requests, then compare */
153 	ret = i2c_write_read(i2c, addr,
154 			     start_addr, (addr_width >> 3), i2c_buffer, TEST_DATA_SIZE-offset);
155 	zassert_equal(ret, 0, "Failed to read EEPROM");
156 
157 	for (i = 0 ; i < TEST_DATA_SIZE-offset ; ++i) {
158 		if (i2c_buffer[i] != i) {
159 			to_display_format(i2c_buffer, TEST_DATA_SIZE-offset,
160 					  buffer_print_i2c);
161 			TC_PRINT("Error: Unexpected buffer content: %s\n",
162 				 buffer_print_i2c);
163 			return -EIO;
164 		}
165 	}
166 
167 	return 0;
168 }
169 
ZTEST(i2c_eeprom_target,test_deinit)170 ZTEST(i2c_eeprom_target, test_deinit)
171 {
172 	const struct device *const i2c_0 = DEVICE_DT_GET(DT_BUS(NODE_EP0));
173 	const struct device *const i2c_1 = DEVICE_DT_GET(DT_BUS(NODE_EP1));
174 	const struct gpio_dt_spec sda_pin_0 =
175 		GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), sda0_gpios, {});
176 	const struct gpio_dt_spec scl_pin_0 =
177 		GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), scl0_gpios, {});
178 	const struct gpio_dt_spec sda_pin_1 =
179 		GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), sda1_gpios, {});
180 	const struct gpio_dt_spec scl_pin_1 =
181 		GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), scl1_gpios, {});
182 	int ret;
183 
184 	if (i2c_0 == i2c_1) {
185 		TC_PRINT("  gpio loopback required for test\n");
186 		ztest_test_skip();
187 	}
188 
189 	if (scl_pin_0.port == NULL || sda_pin_0.port == NULL ||
190 	    scl_pin_1.port == NULL || sda_pin_1.port == NULL) {
191 		TC_PRINT("  bus gpios not specified in zephyr,path\n");
192 		ztest_test_skip();
193 	}
194 
195 	ret = device_deinit(i2c_0);
196 	if (ret == -ENOTSUP) {
197 		TC_PRINT("  device deinit not supported\n");
198 		ztest_test_skip();
199 	}
200 
201 	zassert_ok(ret);
202 
203 	ret = device_deinit(i2c_1);
204 	if (ret == -ENOTSUP) {
205 		TC_PRINT("  device deinit not supported\n");
206 		zassert_ok(device_init(i2c_0));
207 		ztest_test_skip();
208 	}
209 
210 	zassert_ok(gpio_pin_configure_dt(&sda_pin_0, GPIO_INPUT));
211 	zassert_ok(gpio_pin_configure_dt(&sda_pin_1, GPIO_OUTPUT_INACTIVE));
212 	zassert_ok(gpio_pin_configure_dt(&scl_pin_0, GPIO_INPUT));
213 	zassert_ok(gpio_pin_configure_dt(&scl_pin_1, GPIO_OUTPUT_INACTIVE));
214 	zassert_equal(gpio_pin_get_dt(&sda_pin_0), 0);
215 	zassert_equal(gpio_pin_get_dt(&scl_pin_0), 0);
216 	zassert_ok(gpio_pin_set_dt(&sda_pin_1, 1));
217 	zassert_ok(gpio_pin_set_dt(&scl_pin_1, 1));
218 	zassert_equal(gpio_pin_get_dt(&sda_pin_0), 1);
219 	zassert_equal(gpio_pin_get_dt(&scl_pin_0), 1);
220 	zassert_ok(gpio_pin_configure_dt(&sda_pin_1, GPIO_INPUT));
221 	zassert_ok(gpio_pin_configure_dt(&scl_pin_1, GPIO_INPUT));
222 	zassert_ok(device_init(i2c_0));
223 	zassert_ok(device_init(i2c_1));
224 }
225 
ZTEST(i2c_eeprom_target,test_eeprom_target)226 ZTEST(i2c_eeprom_target, test_eeprom_target)
227 {
228 	const struct device *const eeprom_0 = DEVICE_DT_GET(NODE_EP0);
229 	const struct device *const i2c_0 = DEVICE_DT_GET(DT_BUS(NODE_EP0));
230 	int addr_0 = DT_REG_ADDR(NODE_EP0);
231 	uint8_t addr_0_width = DT_PROP_OR(NODE_EP0, address_width, 8);
232 	const struct device *const eeprom_1 = DEVICE_DT_GET(NODE_EP1);
233 	const struct device *const i2c_1 = DEVICE_DT_GET(DT_BUS(NODE_EP1));
234 	int addr_1 = DT_REG_ADDR(NODE_EP1);
235 	uint8_t addr_1_width = DT_PROP_OR(NODE_EP1, address_width, 8);
236 	int ret, offset;
237 
238 	zassert_not_null(i2c_0, "EEPROM 0 - I2C bus not found");
239 	zassert_not_null(eeprom_0, "EEPROM 0 device not found");
240 
241 	zassert_true(device_is_ready(i2c_0), "EEPROM 0 - I2C bus not ready");
242 
243 	TC_PRINT("Found EEPROM 0 on I2C bus device %s at addr %02x\n",
244 		 i2c_0->name, addr_0);
245 
246 	zassert_not_null(i2c_1, "EEPROM 1 - I2C device not found");
247 	zassert_not_null(eeprom_1, "EEPROM 1 device not found");
248 
249 	zassert_true(device_is_ready(i2c_1), "EEPROM 1 - I2C bus not ready");
250 
251 	TC_PRINT("Found EEPROM 1 on I2C bus device %s at addr %02x\n",
252 		 i2c_1->name, addr_1);
253 
254 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
255 		TC_PRINT("Testing dual-role\n");
256 	} else {
257 		TC_PRINT("Testing single-role\n");
258 	}
259 
260 	/* Program differentiable data into the two devices through a back door
261 	 * that doesn't use I2C.
262 	 */
263 	ret = eeprom_target_program(eeprom_0, eeprom_0_data, TEST_DATA_SIZE);
264 	zassert_equal(ret, 0, "Failed to program EEPROM 0");
265 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
266 		ret = eeprom_target_program(eeprom_1, eeprom_1_data,
267 					   TEST_DATA_SIZE);
268 		zassert_equal(ret, 0, "Failed to program EEPROM 1");
269 	}
270 
271 	/* Attach each EEPROM to its owning bus as a target device. */
272 	ret = i2c_target_driver_register(eeprom_0);
273 	zassert_equal(ret, 0, "Failed to register EEPROM 0");
274 
275 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
276 		ret = i2c_target_driver_register(eeprom_1);
277 		zassert_equal(ret, 0, "Failed to register EEPROM 1");
278 	}
279 
280 	/* The simulated EP0 is configured to be accessed as a target device
281 	 * at addr_0 on i2c_0 and should expose eeprom_0_data.  The validation
282 	 * uses i2c_1 as a bus master to access this device, which works because
283 	 * i2c_0 and i2_c have their SDA (SCL) pins shorted (they are on the
284 	 * same physical bus).  Thus in these calls i2c_1 is a master device
285 	 * operating on the target address addr_0.
286 	 *
287 	 * Similarly validation of EP1 uses i2c_0 as a master with addr_1 and
288 	 * eeprom_1_data for validation.
289 	 */
290 	ret = run_full_read(i2c_1, addr_0, addr_0_width, eeprom_0_data);
291 	zassert_equal(ret, 0,
292 		     "Full I2C read from EP0 failed");
293 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
294 		ret = run_full_read(i2c_0, addr_1, addr_1_width, eeprom_1_data);
295 		zassert_equal(ret, 0,
296 			      "Full I2C read from EP1 failed");
297 	}
298 
299 	for (offset = 0 ; offset < TEST_DATA_SIZE-1 ; ++offset) {
300 		zassert_equal(0, run_partial_read(i2c_1, addr_0,
301 			      addr_0_width, eeprom_0_data, offset),
302 			      "Partial I2C read EP0 failed");
303 		if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
304 			zassert_equal(0, run_partial_read(i2c_0, addr_1,
305 							  addr_1_width,
306 							  eeprom_1_data,
307 							  offset),
308 				      "Partial I2C read EP1 failed");
309 		}
310 	}
311 
312 	for (offset = 0 ; offset < TEST_DATA_SIZE-1 ; ++offset) {
313 		zassert_equal(0, run_program_read(i2c_1, addr_0,
314 							  addr_0_width, offset),
315 			      "Program I2C read EP0 failed");
316 		if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
317 			zassert_equal(0, run_program_read(i2c_0, addr_1,
318 							  addr_1_width, offset),
319 				      "Program I2C read EP1 failed");
320 		}
321 	}
322 
323 	/* Detach EEPROM */
324 	ret = i2c_target_driver_unregister(eeprom_0);
325 	zassert_equal(ret, 0, "Failed to unregister EEPROM 0");
326 
327 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
328 		ret = i2c_target_driver_unregister(eeprom_1);
329 		zassert_equal(ret, 0, "Failed to unregister EEPROM 1");
330 	}
331 }
332 
333 ZTEST_SUITE(i2c_eeprom_target, NULL, NULL, NULL, NULL, NULL);
334