1 /*
2  * Copyright (c) 2018 Prevas A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/i2c.h>
8 #include <zephyr/drivers/i3c.h>
9 #include <zephyr/shell/shell.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/util.h>
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(i2c_shell, CONFIG_LOG_DEFAULT_LEVEL);
17 
18 #define MAX_BYTES_FOR_REGISTER_INDEX	4
19 #define ARGV_DEV	1
20 #define ARGV_ADDR	2
21 #define ARGV_REG	3
22 
23 /* Maximum bytes we can write or read at once */
24 #define MAX_I2C_BYTES	16
25 
get_bytes_count_for_hex(char * arg)26 static int get_bytes_count_for_hex(char *arg)
27 {
28 	int length = (strlen(arg) + 1) / 2;
29 
30 	if (length > 1 && arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) {
31 		length -= 1;
32 	}
33 
34 	return MIN(MAX_BYTES_FOR_REGISTER_INDEX, length);
35 }
36 
37 /*
38  * This sends I2C messages without any data (i.e. stop condition after
39  * sending just the address). If there is an ACK for the address, it
40  * is assumed there is a device present.
41  *
42  * WARNING: As there is no standard I2C detection command, this code
43  * uses arbitrary SMBus commands (namely SMBus quick write and SMBus
44  * receive byte) to probe for devices.  This operation can confuse
45  * your I2C bus, cause data loss, and is known to corrupt the Atmel
46  * AT24RF08 EEPROM found on many IBM Thinkpad laptops.
47  *
48  * https://manpages.debian.org/buster/i2c-tools/i2cdetect.8.en.html
49  */
50 /* i2c scan <device> */
cmd_i2c_scan(const struct shell * sh,size_t argc,char ** argv)51 static int cmd_i2c_scan(const struct shell *sh, size_t argc, char **argv)
52 {
53 	const struct device *dev;
54 	uint8_t cnt = 0, first = 0x04, last = 0x77;
55 
56 	dev = shell_device_get_binding(argv[ARGV_DEV]);
57 
58 	if (!dev) {
59 		shell_error(sh, "I2C: Device driver %s not found.", argv[ARGV_DEV]);
60 		return -ENODEV;
61 	}
62 
63 	shell_print(sh, "     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
64 	for (uint8_t i = 0; i <= last; i += 16) {
65 		shell_fprintf_normal(sh, "%02x: ", i);
66 		for (uint8_t j = 0; j < 16; j++) {
67 			if (i + j < first || i + j > last) {
68 				shell_fprintf_normal(sh, "   ");
69 				continue;
70 			}
71 
72 			struct i2c_msg msgs[1];
73 			uint8_t dst;
74 
75 			/* Send the address to read from */
76 			msgs[0].buf = &dst;
77 			msgs[0].len = 0U;
78 			msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
79 			if (i2c_transfer(dev, &msgs[0], 1, i + j) == 0) {
80 				shell_fprintf_normal(sh, "%02x ", i + j);
81 				++cnt;
82 			} else {
83 				shell_fprintf_normal(sh, "-- ");
84 			}
85 		}
86 		shell_print(sh, "");
87 	}
88 
89 	shell_print(sh, "%u devices found on %s", cnt, argv[ARGV_DEV]);
90 
91 	return 0;
92 }
93 
94 /* i2c recover <device> */
cmd_i2c_recover(const struct shell * sh,size_t argc,char ** argv)95 static int cmd_i2c_recover(const struct shell *sh, size_t argc, char **argv)
96 {
97 	const struct device *dev;
98 	int err;
99 
100 	dev = shell_device_get_binding(argv[ARGV_DEV]);
101 	if (!dev) {
102 		shell_error(sh, "I2C: Device driver %s not found.", argv[1]);
103 		return -ENODEV;
104 	}
105 
106 	err = i2c_recover_bus(dev);
107 	if (err) {
108 		shell_error(sh, "I2C: Bus recovery failed (err %d)", err);
109 		return err;
110 	}
111 
112 	return 0;
113 }
114 
i2c_write_from_buffer(const struct shell * sh,char * s_dev_name,char * s_dev_addr,char * s_reg_addr,char ** data,uint8_t data_length)115 static int i2c_write_from_buffer(const struct shell *sh,
116 		char *s_dev_name, char *s_dev_addr, char *s_reg_addr,
117 		char **data, uint8_t data_length)
118 {
119 	/* This buffer must preserve 4 bytes for register address, as it is
120 	 * filled using put_be32 function and we don't want to lower available
121 	 * space when using 1 byte address.
122 	 */
123 	uint8_t buf[MAX_I2C_BYTES + MAX_BYTES_FOR_REGISTER_INDEX - 1];
124 	const struct device *dev;
125 	int reg_addr_bytes;
126 	int reg_addr;
127 	int dev_addr;
128 	int ret;
129 	int i;
130 
131 	dev = shell_device_get_binding(s_dev_name);
132 	if (!dev) {
133 		shell_error(sh, "I2C: Device driver %s not found.", s_dev_name);
134 		return -ENODEV;
135 	}
136 
137 	dev_addr = strtol(s_dev_addr, NULL, 16);
138 	reg_addr = strtol(s_reg_addr, NULL, 16);
139 
140 	reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr);
141 	sys_put_be32(reg_addr, buf);
142 
143 	if (data_length + reg_addr_bytes > MAX_I2C_BYTES) {
144 		data_length = MAX_I2C_BYTES - reg_addr_bytes;
145 		shell_info(sh, "Too many bytes provided, limit is %d",
146 			   MAX_I2C_BYTES - reg_addr_bytes);
147 	}
148 
149 	for (i = 0; i < data_length; i++) {
150 		buf[MAX_BYTES_FOR_REGISTER_INDEX + i] =
151 			(uint8_t)strtol(data[i], NULL, 16);
152 	}
153 
154 	ret = i2c_write(dev,
155 			buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes,
156 			reg_addr_bytes + data_length, dev_addr);
157 	if (ret < 0) {
158 		shell_error(sh, "Failed to write to device: %s", s_dev_addr);
159 		return -EIO;
160 	}
161 
162 	return 0;
163 }
164 
165 /* i2c write <device> <dev_addr> <reg_addr> [<byte1>, ...] */
cmd_i2c_write(const struct shell * sh,size_t argc,char ** argv)166 static int cmd_i2c_write(const struct shell *sh, size_t argc, char **argv)
167 {
168 	return i2c_write_from_buffer(sh, argv[ARGV_DEV],
169 				     argv[ARGV_ADDR], argv[ARGV_REG],
170 				     &argv[4], argc - 4);
171 }
172 
173 /* i2c write_byte <device> <dev_addr> <reg_addr> <value> */
cmd_i2c_write_byte(const struct shell * sh,size_t argc,char ** argv)174 static int cmd_i2c_write_byte(const struct shell *sh, size_t argc, char **argv)
175 {
176 	return i2c_write_from_buffer(sh, argv[ARGV_DEV],
177 				     argv[ARGV_ADDR], argv[ARGV_REG],
178 				     &argv[4], 1);
179 }
180 
i2c_read_to_buffer(const struct shell * sh,char * s_dev_name,char * s_dev_addr,char * s_reg_addr,uint8_t * buf,uint8_t buf_length)181 static int i2c_read_to_buffer(const struct shell *sh,
182 			      char *s_dev_name,
183 			      char *s_dev_addr, char *s_reg_addr,
184 			      uint8_t *buf, uint8_t buf_length)
185 {
186 	const struct device *dev;
187 	int dev_addr;
188 	int ret;
189 
190 	dev = shell_device_get_binding(s_dev_name);
191 	if (!dev) {
192 		shell_error(sh, "I2C: Device driver %s not found.", s_dev_name);
193 		return -ENODEV;
194 	}
195 
196 	dev_addr = strtol(s_dev_addr, NULL, 16);
197 
198 	if (s_reg_addr != NULL) {
199 		uint8_t reg_addr_buf[MAX_BYTES_FOR_REGISTER_INDEX];
200 		int reg_addr_bytes;
201 		int reg_addr;
202 
203 		reg_addr = strtol(s_reg_addr, NULL, 16);
204 		reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr);
205 		sys_put_be32(reg_addr, reg_addr_buf);
206 
207 		ret = i2c_write_read(dev, dev_addr,
208 				     reg_addr_buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes,
209 				     reg_addr_bytes, buf, buf_length);
210 	} else {
211 		ret = i2c_read(dev, buf, buf_length, dev_addr);
212 	}
213 
214 	if (ret < 0) {
215 		shell_error(sh, "Failed to read from device: %s", s_dev_addr);
216 		return -EIO;
217 	}
218 
219 	return 0;
220 }
221 
222 /* i2c read_byte <device> <dev_addr> <reg_addr> */
cmd_i2c_read_byte(const struct shell * sh,size_t argc,char ** argv)223 static int cmd_i2c_read_byte(const struct shell *sh, size_t argc, char **argv)
224 {
225 	uint8_t out;
226 	int ret;
227 
228 	ret = i2c_read_to_buffer(sh, argv[ARGV_DEV],
229 				 argv[ARGV_ADDR], argv[ARGV_REG], &out, 1);
230 	if (ret == 0) {
231 		shell_print(sh, "Output: 0x%x", out);
232 	}
233 
234 	return ret;
235 }
236 
237 /* i2c read <device> <dev_addr> <reg_addr> [<numbytes>] */
cmd_i2c_read(const struct shell * sh,size_t argc,char ** argv)238 static int cmd_i2c_read(const struct shell *sh, size_t argc, char **argv)
239 {
240 	uint8_t buf[MAX_I2C_BYTES];
241 	int num_bytes;
242 	int ret;
243 
244 	if (argc > 4) {
245 		num_bytes = strtol(argv[4], NULL, 16);
246 		if (num_bytes > MAX_I2C_BYTES) {
247 			num_bytes = MAX_I2C_BYTES;
248 		}
249 	} else {
250 		num_bytes = MAX_I2C_BYTES;
251 	}
252 
253 	ret = i2c_read_to_buffer(sh, argv[ARGV_DEV],
254 				 argv[ARGV_ADDR], argv[ARGV_REG],
255 				 buf, num_bytes);
256 	if (ret == 0) {
257 		shell_hexdump(sh, buf, num_bytes);
258 	}
259 
260 	return ret;
261 }
262 
263 /* i2c direct_read <device> <dev_addr> [<numbytes>] */
cmd_i2c_direct_read(const struct shell * sh,size_t argc,char ** argv)264 static int cmd_i2c_direct_read(const struct shell *sh, size_t argc, char **argv)
265 {
266 	uint8_t buf[MAX_I2C_BYTES];
267 	int num_bytes;
268 	int ret;
269 
270 	if (argc > 3) {
271 		num_bytes = strtol(argv[3], NULL, 16);
272 		if (num_bytes > MAX_I2C_BYTES) {
273 			num_bytes = MAX_I2C_BYTES;
274 		}
275 	} else {
276 		num_bytes = MAX_I2C_BYTES;
277 	}
278 
279 	ret = i2c_read_to_buffer(sh, argv[ARGV_DEV], argv[ARGV_ADDR], NULL, buf, num_bytes);
280 	if (ret == 0) {
281 		shell_hexdump(sh, buf, num_bytes);
282 	}
283 
284 	return ret;
285 }
286 
287 /* i2c speed <device> <speed>
288  * For: speed see constants like I2C_SPEED_STANDARD
289  */
cmd_i2c_speed(const struct shell * sh,size_t argc,char ** argv)290 static int cmd_i2c_speed(const struct shell *sh, size_t argc, char **argv)
291 {
292 	char *s_dev_name = argv[ARGV_DEV];
293 	const struct device *dev;
294 	uint32_t dev_config = 0;
295 	uint32_t speed;
296 	int ret;
297 
298 	dev = shell_device_get_binding(s_dev_name);
299 	if (!dev) {
300 		shell_error(sh, "I2C: Device driver %s not found.", s_dev_name);
301 		return -ENODEV;
302 	}
303 
304 	speed = strtol(argv[ARGV_DEV + 1], NULL, 10);
305 	ret = i2c_get_config(dev, &dev_config);
306 	if (ret == 0) {
307 		dev_config &= ~I2C_SPEED_MASK;
308 		dev_config |= I2C_SPEED_SET(speed);
309 	} else {
310 		/* Can't get current config. Fallback to something reasonable */
311 		dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(speed);
312 	}
313 
314 	ret = i2c_configure(dev, dev_config);
315 	if (ret < 0) {
316 		shell_error(sh, "I2C: Failed to configure device: %s", s_dev_name);
317 		return -EIO;
318 	}
319 	return 0;
320 }
321 
322 /* i2c target register <device> */
cmd_i2c_target_register(const struct shell * sh,size_t argc,char ** argv)323 __maybe_unused static int cmd_i2c_target_register(const struct shell *sh, size_t argc, char **argv)
324 {
325 	char *s_dev_name = argv[ARGV_DEV];
326 	const struct device *dev;
327 	int ret;
328 
329 	dev = shell_device_get_binding(s_dev_name);
330 	if (!dev) {
331 		shell_error(sh, "I2C: Device driver %s not found.", s_dev_name);
332 		return -ENODEV;
333 	}
334 
335 	ret = i2c_target_driver_register(dev);
336 	if (ret < 0) {
337 		shell_error(sh, "I2C: Failed to register %s with err=%d", s_dev_name, ret);
338 		return ret;
339 	}
340 
341 	shell_print(sh, "I2C: Successfully registered %s", s_dev_name);
342 
343 	return 0;
344 }
345 
346 /* i2c target unregister <device> */
cmd_i2c_target_unregister(const struct shell * sh,size_t argc,char ** argv)347 __maybe_unused static int cmd_i2c_target_unregister(const struct shell *sh, size_t argc,
348 						    char **argv)
349 {
350 	char *s_dev_name = argv[ARGV_DEV];
351 	const struct device *dev;
352 	int ret;
353 
354 	dev = shell_device_get_binding(s_dev_name);
355 	if (!dev) {
356 		shell_error(sh, "I2C: Device driver %s not found.", s_dev_name);
357 		return -ENODEV;
358 	}
359 
360 	ret = i2c_target_driver_unregister(dev);
361 	if (ret < 0) {
362 		shell_error(sh, "I2C: Failed to unregister %s with err=%d", s_dev_name, ret);
363 		return ret;
364 	}
365 
366 	shell_print(sh, "I2C: Successfully unregistered %s", s_dev_name);
367 
368 	return 0;
369 }
370 
device_is_i2c(const struct device * dev)371 static bool device_is_i2c(const struct device *dev)
372 {
373 #ifdef CONFIG_I3C
374 	return DEVICE_API_IS(i2c, dev) || DEVICE_API_IS(i3c, dev);
375 #else
376 	return DEVICE_API_IS(i2c, dev);
377 #endif
378 }
379 
device_name_get(size_t idx,struct shell_static_entry * entry)380 static void device_name_get(size_t idx, struct shell_static_entry *entry)
381 {
382 	const struct device *dev = shell_device_filter(idx, device_is_i2c);
383 
384 	entry->syntax = (dev != NULL) ? dev->name : NULL;
385 	entry->handler = NULL;
386 	entry->help = NULL;
387 	entry->subcmd = NULL;
388 }
389 
390 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
391 
392 #ifdef CONFIG_I2C_TARGET
393 SHELL_STATIC_SUBCMD_SET_CREATE(
394 	sub_i2c_target,
395 	SHELL_CMD_ARG(register, &dsub_device_name,
396 		      "Register an i2c-target on its respective bus.\n"
397 		      "Usage: target register <device>",
398 		      cmd_i2c_target_register, 2, 0),
399 	SHELL_CMD_ARG(unregister, &dsub_device_name,
400 		      "Unegister an i2c-target from its respective bus.\n"
401 		      "Usage: target unregister <device>",
402 		      cmd_i2c_target_unregister, 2, 0),
403 	SHELL_SUBCMD_SET_END     /* Array terminated. */
404 );
405 #endif /* CONFIG_I2C_TARGET */
406 
407 SHELL_STATIC_SUBCMD_SET_CREATE(sub_i2c_cmds,
408 	SHELL_CMD_ARG(scan, &dsub_device_name,
409 		      "Scan I2C devices\n"
410 		      "Usage: scan <device>",
411 		      cmd_i2c_scan, 2, 0),
412 	SHELL_CMD_ARG(recover, &dsub_device_name,
413 		      "Recover I2C bus\n"
414 		      "Usage: recover <device>",
415 		      cmd_i2c_recover, 2, 0),
416 	SHELL_CMD_ARG(read, &dsub_device_name,
417 		      "Read bytes from an I2C device\n"
418 		      "Usage: read <device> <addr> <reg> [<bytes>]",
419 		      cmd_i2c_read, 4, 1),
420 	SHELL_CMD_ARG(read_byte, &dsub_device_name,
421 		      "Read a byte from an I2C device\n"
422 		      "Usage: read_byte <device> <addr> <reg>",
423 		      cmd_i2c_read_byte, 4, 0),
424 	SHELL_CMD_ARG(direct_read, &dsub_device_name,
425 		      "Read byte stream directly from an I2C device without "
426 		      "writing a register address first\n"
427 		      "Usage: direct_read <device> <addr> [<bytes>]",
428 		      cmd_i2c_direct_read, 3, 1),
429 	SHELL_CMD_ARG(write, &dsub_device_name,
430 		      "Write bytes to an I2C device\n"
431 		      "Usage: write <device> <addr> <reg> [<byte1>, ...]",
432 		      cmd_i2c_write, 4, MAX_I2C_BYTES),
433 	SHELL_CMD_ARG(write_byte, &dsub_device_name,
434 		      "Write a byte to an I2C device\n"
435 		      "Usage: write_byte <device> <addr> <reg> <value>",
436 		      cmd_i2c_write_byte, 5, 0),
437 	SHELL_CMD_ARG(speed, &dsub_device_name,
438 		      "Configure I2C bus speed\n"
439 		      "Usage: speed <device> <speed>",
440 		      cmd_i2c_speed, 3, 0),
441 #ifdef CONFIG_I2C_TARGET
442 	SHELL_CMD_ARG(target, &sub_i2c_target,
443 		      "Subcommands operating on i2c targets.",
444 		      NULL, 3, 0),
445 #endif /* CONFIG_I2C_TARGET */
446 	SHELL_SUBCMD_SET_END     /* Array terminated. */
447 );
448 
449 SHELL_CMD_REGISTER(i2c, &sub_i2c_cmds, "I2C commands", NULL);
450