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 
20 #include <zephyr/ztest.h>
21 
22 #define NODE_EP0 DT_NODELABEL(eeprom0)
23 #define NODE_EP1 DT_NODELABEL(eeprom1)
24 
25 #define TEST_DATA_SIZE	20
26 static const uint8_t eeprom_0_data[TEST_DATA_SIZE] = "0123456789abcdefghij";
27 static const uint8_t eeprom_1_data[TEST_DATA_SIZE] = "jihgfedcba9876543210";
28 static uint8_t i2c_buffer[TEST_DATA_SIZE];
29 
30 /*
31  * We need 5x(buffer size) + 1 to print a comma-separated list of each
32  * byte in hex, plus a null.
33  */
34 uint8_t buffer_print_eeprom[TEST_DATA_SIZE * 5 + 1];
35 uint8_t buffer_print_i2c[TEST_DATA_SIZE * 5 + 1];
36 
to_display_format(const uint8_t * src,size_t size,char * dst)37 static void to_display_format(const uint8_t *src, size_t size, char *dst)
38 {
39 	size_t i;
40 
41 	for (i = 0; i < size; i++) {
42 		sprintf(dst + 5 * i, "0x%02x,", src[i]);
43 	}
44 }
45 
run_full_read(const struct device * i2c,uint8_t addr,uint8_t addr_width,const uint8_t * comp_buffer)46 static int run_full_read(const struct device *i2c, uint8_t addr,
47 			 uint8_t addr_width, const uint8_t *comp_buffer)
48 {
49 	int ret;
50 	uint8_t start_addr[2];
51 
52 	TC_PRINT("Testing full read: Master: %s, address: 0x%x\n",
53 		 i2c->name, addr);
54 
55 	/* Read EEPROM from I2C Master requests, then compare */
56 	memset(start_addr, 0, sizeof(start_addr));
57 	ret = i2c_write_read(i2c, addr, start_addr, (addr_width >> 3), i2c_buffer, TEST_DATA_SIZE);
58 	zassert_equal(ret, 0, "Failed to read EEPROM");
59 
60 	if (memcmp(i2c_buffer, comp_buffer, TEST_DATA_SIZE)) {
61 		to_display_format(i2c_buffer, TEST_DATA_SIZE,
62 				  buffer_print_i2c);
63 		to_display_format(comp_buffer, TEST_DATA_SIZE,
64 				  buffer_print_eeprom);
65 		TC_PRINT("Error: Buffer contents are different: %s\n",
66 			 buffer_print_i2c);
67 		TC_PRINT("                         vs expected: %s\n",
68 			 buffer_print_eeprom);
69 		return -EIO;
70 	}
71 
72 	return 0;
73 }
74 
run_partial_read(const struct device * i2c,uint8_t addr,uint8_t addr_width,const uint8_t * comp_buffer,unsigned int offset)75 static int run_partial_read(const struct device *i2c, uint8_t addr,
76 			    uint8_t addr_width, const uint8_t *comp_buffer, unsigned int offset)
77 {
78 	int ret;
79 	uint8_t start_addr[2];
80 
81 	TC_PRINT("Testing partial read. Master: %s, address: 0x%x, off=%d\n",
82 		 i2c->name, addr, offset);
83 
84 	switch (addr_width) {
85 	case 8:
86 		start_addr[0] = (uint8_t) (offset & 0xFF);
87 	break;
88 	case 16:
89 		sys_put_be16((uint16_t)(offset & 0xFFFF), start_addr);
90 	break;
91 	default:
92 		return -EINVAL;
93 	}
94 
95 	ret = i2c_write_read(i2c, addr,
96 			     start_addr, (addr_width >> 3), i2c_buffer, TEST_DATA_SIZE-offset);
97 	zassert_equal(ret, 0, "Failed to read EEPROM");
98 
99 	if (memcmp(i2c_buffer, &comp_buffer[offset], TEST_DATA_SIZE-offset)) {
100 		to_display_format(i2c_buffer, TEST_DATA_SIZE-offset,
101 				  buffer_print_i2c);
102 		to_display_format(&comp_buffer[offset], TEST_DATA_SIZE-offset,
103 				  buffer_print_eeprom);
104 		TC_PRINT("Error: Buffer contents are different: %s\n",
105 			 buffer_print_i2c);
106 		TC_PRINT("                         vs expected: %s\n",
107 			 buffer_print_eeprom);
108 		return -EIO;
109 	}
110 
111 	return 0;
112 }
113 
run_program_read(const struct device * i2c,uint8_t addr,uint8_t addr_width,unsigned int offset)114 static int run_program_read(const struct device *i2c, uint8_t addr,
115 			    uint8_t addr_width, unsigned int offset)
116 {
117 	int ret, i;
118 	uint8_t start_addr[2];
119 	struct i2c_msg msg[2];
120 
121 	TC_PRINT("Testing program. Master: %s, address: 0x%x, off=%d\n",
122 		i2c->name, addr, offset);
123 
124 	for (i = 0 ; i < TEST_DATA_SIZE-offset ; ++i) {
125 		i2c_buffer[i] = i;
126 	}
127 
128 	switch (addr_width) {
129 	case 8:
130 		start_addr[0] = (uint8_t) (offset & 0xFF);
131 	break;
132 	case 16:
133 		sys_put_be16((uint16_t)(offset & 0xFFFF), start_addr);
134 	break;
135 	default:
136 		return -EINVAL;
137 	}
138 
139 	msg[0].buf = start_addr;
140 	msg[0].len = (addr_width >> 3);
141 	msg[0].flags = I2C_MSG_WRITE;
142 	msg[1].buf = &i2c_buffer[0];
143 	msg[1].len = TEST_DATA_SIZE;
144 	msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
145 
146 	ret = i2c_transfer(i2c, &msg[0], 2, addr);
147 	zassert_equal(ret, 0, "Failed to write EEPROM");
148 
149 	(void)memset(i2c_buffer, 0xFF, TEST_DATA_SIZE);
150 
151 	/* Read back EEPROM from I2C Master requests, then compare */
152 	ret = i2c_write_read(i2c, addr,
153 			     start_addr, (addr_width >> 3), i2c_buffer, TEST_DATA_SIZE-offset);
154 	zassert_equal(ret, 0, "Failed to read EEPROM");
155 
156 	for (i = 0 ; i < TEST_DATA_SIZE-offset ; ++i) {
157 		if (i2c_buffer[i] != i) {
158 			to_display_format(i2c_buffer, TEST_DATA_SIZE-offset,
159 					  buffer_print_i2c);
160 			TC_PRINT("Error: Unexpected buffer content: %s\n",
161 				 buffer_print_i2c);
162 			return -EIO;
163 		}
164 	}
165 
166 	return 0;
167 }
168 
ZTEST(i2c_eeprom_target,test_eeprom_target)169 ZTEST(i2c_eeprom_target, test_eeprom_target)
170 {
171 	const struct device *const eeprom_0 = DEVICE_DT_GET(NODE_EP0);
172 	const struct device *const i2c_0 = DEVICE_DT_GET(DT_BUS(NODE_EP0));
173 	int addr_0 = DT_REG_ADDR(NODE_EP0);
174 	uint8_t addr_0_width = DT_PROP_OR(NODE_EP0, address_width, 8);
175 	const struct device *const eeprom_1 = DEVICE_DT_GET(NODE_EP1);
176 	const struct device *const i2c_1 = DEVICE_DT_GET(DT_BUS(NODE_EP1));
177 	int addr_1 = DT_REG_ADDR(NODE_EP1);
178 	uint8_t addr_1_width = DT_PROP_OR(NODE_EP1, address_width, 8);
179 	int ret, offset;
180 
181 	zassert_not_null(i2c_0, "EEPROM 0 - I2C bus not found");
182 	zassert_not_null(eeprom_0, "EEPROM 0 device not found");
183 
184 	zassert_true(device_is_ready(i2c_0), "EEPROM 0 - I2C bus not ready");
185 
186 	TC_PRINT("Found EEPROM 0 on I2C bus device %s at addr %02x\n",
187 		 i2c_0->name, addr_0);
188 
189 	zassert_not_null(i2c_1, "EEPROM 1 - I2C device not found");
190 	zassert_not_null(eeprom_1, "EEPROM 1 device not found");
191 
192 	zassert_true(device_is_ready(i2c_1), "EEPROM 1 - I2C bus not ready");
193 
194 	TC_PRINT("Found EEPROM 1 on I2C bus device %s at addr %02x\n",
195 		 i2c_1->name, addr_1);
196 
197 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
198 		TC_PRINT("Testing dual-role\n");
199 	} else {
200 		TC_PRINT("Testing single-role\n");
201 	}
202 
203 	/* Program differentiable data into the two devices through a back door
204 	 * that doesn't use I2C.
205 	 */
206 	ret = eeprom_target_program(eeprom_0, eeprom_0_data, TEST_DATA_SIZE);
207 	zassert_equal(ret, 0, "Failed to program EEPROM 0");
208 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
209 		ret = eeprom_target_program(eeprom_1, eeprom_1_data,
210 					   TEST_DATA_SIZE);
211 		zassert_equal(ret, 0, "Failed to program EEPROM 1");
212 	}
213 
214 	/* Attach each EEPROM to its owning bus as a target device. */
215 	ret = i2c_target_driver_register(eeprom_0);
216 	zassert_equal(ret, 0, "Failed to register EEPROM 0");
217 
218 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
219 		ret = i2c_target_driver_register(eeprom_1);
220 		zassert_equal(ret, 0, "Failed to register EEPROM 1");
221 	}
222 
223 	/* The simulated EP0 is configured to be accessed as a target device
224 	 * at addr_0 on i2c_0 and should expose eeprom_0_data.  The validation
225 	 * uses i2c_1 as a bus master to access this device, which works because
226 	 * i2c_0 and i2_c have their SDA (SCL) pins shorted (they are on the
227 	 * same physical bus).  Thus in these calls i2c_1 is a master device
228 	 * operating on the target address addr_0.
229 	 *
230 	 * Similarly validation of EP1 uses i2c_0 as a master with addr_1 and
231 	 * eeprom_1_data for validation.
232 	 */
233 	ret = run_full_read(i2c_1, addr_0, addr_0_width, eeprom_0_data);
234 	zassert_equal(ret, 0,
235 		     "Full I2C read from EP0 failed");
236 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
237 		ret = run_full_read(i2c_0, addr_1, addr_1_width, eeprom_1_data);
238 		zassert_equal(ret, 0,
239 			      "Full I2C read from EP1 failed");
240 	}
241 
242 	for (offset = 0 ; offset < TEST_DATA_SIZE-1 ; ++offset) {
243 		zassert_equal(0, run_partial_read(i2c_1, addr_0,
244 			      addr_0_width, eeprom_0_data, offset),
245 			      "Partial I2C read EP0 failed");
246 		if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
247 			zassert_equal(0, run_partial_read(i2c_0, addr_1,
248 							  addr_1_width,
249 							  eeprom_1_data,
250 							  offset),
251 				      "Partial I2C read EP1 failed");
252 		}
253 	}
254 
255 	for (offset = 0 ; offset < TEST_DATA_SIZE-1 ; ++offset) {
256 		zassert_equal(0, run_program_read(i2c_1, addr_0,
257 							  addr_0_width, offset),
258 			      "Program I2C read EP0 failed");
259 		if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
260 			zassert_equal(0, run_program_read(i2c_0, addr_1,
261 							  addr_1_width, offset),
262 				      "Program I2C read EP1 failed");
263 		}
264 	}
265 
266 	/* Detach EEPROM */
267 	ret = i2c_target_driver_unregister(eeprom_0);
268 	zassert_equal(ret, 0, "Failed to unregister EEPROM 0");
269 
270 	if (IS_ENABLED(CONFIG_APP_DUAL_ROLE_I2C)) {
271 		ret = i2c_target_driver_unregister(eeprom_1);
272 		zassert_equal(ret, 0, "Failed to unregister EEPROM 1");
273 	}
274 }
275 
276 ZTEST_SUITE(i2c_eeprom_target, NULL, NULL, NULL, NULL, NULL);
277