1 /*
2  * Copyright (c) 2018 Prevas A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <shell/shell.h>
8 #include <stdlib.h>
9 #include <drivers/i2c.h>
10 #include <string.h>
11 #include <sys/util.h>
12 #include <stdlib.h>
13 
14 #include <logging/log.h>
15 LOG_MODULE_REGISTER(i2c_shell, CONFIG_LOG_DEFAULT_LEVEL);
16 
17 #define I2C_DEVICE_PREFIX "I2C_"
18 
19 /* Maximum bytes we can write or read at once */
20 #define MAX_I2C_BYTES	16
21 
22 /*
23  * This sends I2C messages without any data (i.e. stop condition after
24  * sending just the address). If there is an ACK for the address, it
25  * is assumed there is a device present.
26  *
27  * WARNING: As there is no standard I2C detection command, this code
28  * uses arbitrary SMBus commands (namely SMBus quick write and SMBus
29  * receive byte) to probe for devices.  This operation can confuse
30  * your I2C bus, cause data loss, and is known to corrupt the Atmel
31  * AT24RF08 EEPROM found on many IBM Thinkpad laptops.
32  *
33  * https://manpages.debian.org/buster/i2c-tools/i2cdetect.8.en.html
34  */
cmd_i2c_scan(const struct shell * shell,size_t argc,char ** argv)35 static int cmd_i2c_scan(const struct shell *shell,
36 			size_t argc, char **argv)
37 {
38 	const struct device *dev;
39 	uint8_t cnt = 0, first = 0x04, last = 0x77;
40 
41 	dev = device_get_binding(argv[1]);
42 
43 	if (!dev) {
44 		shell_error(shell, "I2C: Device driver %s not found.",
45 			    argv[1]);
46 		return -ENODEV;
47 	}
48 
49 	shell_print(shell,
50 		    "     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
51 	for (uint8_t i = 0; i <= last; i += 16) {
52 		shell_fprintf(shell, SHELL_NORMAL, "%02x: ", i);
53 		for (uint8_t j = 0; j < 16; j++) {
54 			if (i + j < first || i + j > last) {
55 				shell_fprintf(shell, SHELL_NORMAL, "   ");
56 				continue;
57 			}
58 
59 			struct i2c_msg msgs[1];
60 			uint8_t dst;
61 
62 			/* Send the address to read from */
63 			msgs[0].buf = &dst;
64 			msgs[0].len = 0U;
65 			msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
66 			if (i2c_transfer(dev, &msgs[0], 1, i + j) == 0) {
67 				shell_fprintf(shell, SHELL_NORMAL,
68 					      "%02x ", i + j);
69 				++cnt;
70 			} else {
71 				shell_fprintf(shell, SHELL_NORMAL, "-- ");
72 			}
73 		}
74 		shell_print(shell, "");
75 	}
76 
77 	shell_print(shell, "%u devices found on %s",
78 		    cnt, argv[1]);
79 
80 	return 0;
81 }
82 
cmd_i2c_recover(const struct shell * shell,size_t argc,char ** argv)83 static int cmd_i2c_recover(const struct shell *shell,
84 			   size_t argc, char **argv)
85 {
86 	const struct device *dev;
87 	int err;
88 
89 	dev = device_get_binding(argv[1]);
90 	if (!dev) {
91 		shell_error(shell, "I2C: Device driver %s not found.", argv[1]);
92 		return -ENODEV;
93 	}
94 
95 	err = i2c_recover_bus(dev);
96 	if (err) {
97 		shell_error(shell, "I2C: Bus recovery failed (err %d)", err);
98 		return err;
99 	}
100 
101 	return 0;
102 }
103 
104 /* i2c write <device> <dev_addr> [<byte1>, ...] */
cmd_i2c_write(const struct shell * shell,size_t argc,char ** argv)105 static int cmd_i2c_write(const struct shell *shell, size_t argc, char **argv)
106 {
107 	uint8_t buf[MAX_I2C_BYTES];
108 	const struct device *dev;
109 	int num_bytes;
110 	int reg_addr;
111 	int dev_addr;
112 	int i;
113 
114 	dev = device_get_binding(argv[1]);
115 	if (!dev) {
116 		shell_error(shell, "I2C: Device driver %s not found.", argv[1]);
117 		return -ENODEV;
118 	}
119 
120 	dev_addr = strtol(argv[2], NULL, 16);
121 	reg_addr = strtol(argv[3], NULL, 16);
122 	num_bytes = argc - 4;
123 	if (num_bytes < 0) {
124 		return 0;
125 	}
126 	if (num_bytes > MAX_I2C_BYTES) {
127 		num_bytes = MAX_I2C_BYTES;
128 	}
129 	for (i = 0; i < num_bytes; i++) {
130 		buf[i] = (uint8_t)strtol(argv[4 + i], NULL, 16);
131 	}
132 
133 	if (i2c_burst_write(dev, dev_addr, reg_addr, buf, num_bytes) < 0) {
134 		shell_error(shell, "Failed to write to device: %s", argv[1]);
135 		return -EIO;
136 	}
137 
138 	return 0;
139 }
140 
cmd_i2c_write_byte(const struct shell * shell,size_t argc,char ** argv)141 static int cmd_i2c_write_byte(const struct shell *shell,
142 			      size_t argc, char **argv)
143 {
144 	const struct device *dev;
145 	int reg_addr;
146 	int dev_addr;
147 	int out_byte;
148 
149 	dev = device_get_binding(argv[1]);
150 	if (!dev) {
151 		shell_error(shell, "I2C: Device driver %s not found.",
152 			    argv[1]);
153 		return -ENODEV;
154 	}
155 
156 	dev_addr = strtol(argv[2], NULL, 16);
157 	reg_addr = strtol(argv[3], NULL, 16);
158 	out_byte = strtol(argv[4], NULL, 16);
159 
160 	if (i2c_reg_write_byte(dev, dev_addr, reg_addr, out_byte) < 0) {
161 		shell_error(shell, "Failed to write to device: %s", argv[1]);
162 		return -EIO;
163 	}
164 
165 	return 0;
166 }
167 
cmd_i2c_read_byte(const struct shell * shell,size_t argc,char ** argv)168 static int cmd_i2c_read_byte(const struct shell *shell,
169 			     size_t argc, char **argv)
170 {
171 	const struct device *dev;
172 	int reg_addr;
173 	int dev_addr;
174 	uint8_t out;
175 
176 	dev = device_get_binding(argv[1]);
177 	if (!dev) {
178 		shell_error(shell, "I2C: Device driver %s not found.",
179 			    argv[1]);
180 		return -ENODEV;
181 	}
182 
183 	dev_addr = strtol(argv[2], NULL, 16);
184 	reg_addr = strtol(argv[3], NULL, 16);
185 
186 	if (i2c_reg_read_byte(dev, dev_addr, reg_addr, &out) < 0) {
187 		shell_error(shell, "Failed to read from device: %s", argv[1]);
188 		return -EIO;
189 	}
190 
191 	shell_print(shell, "Output: 0x%x", out);
192 
193 	return 0;
194 }
195 
196 /* i2c read <device> <dev_addr> [<numbytes>] */
cmd_i2c_read(const struct shell * shell,size_t argc,char ** argv)197 static int cmd_i2c_read(const struct shell *shell, size_t argc, char **argv)
198 {
199 	uint8_t buf[MAX_I2C_BYTES];
200 	const struct device *dev;
201 	int num_bytes;
202 	int reg_addr;
203 	int dev_addr;
204 
205 	dev = device_get_binding(argv[1]);
206 	if (!dev) {
207 		shell_error(shell, "I2C: Device driver %s not found.", argv[1]);
208 		return -ENODEV;
209 	}
210 
211 	dev_addr = strtol(argv[2], NULL, 16);
212 	reg_addr = strtol(argv[3], NULL, 16);
213 	if (argc > 4) {
214 		num_bytes = strtol(argv[4], NULL, 16);
215 		if (num_bytes > MAX_I2C_BYTES)
216 			num_bytes = MAX_I2C_BYTES;
217 	} else {
218 		num_bytes = MAX_I2C_BYTES;
219 	}
220 
221 	if (i2c_burst_read(dev, dev_addr, reg_addr, buf, num_bytes) < 0) {
222 		shell_error(shell, "Failed to read from device: %s", argv[1]);
223 		return -EIO;
224 	}
225 
226 	shell_hexdump(shell, buf, num_bytes);
227 
228 	return 0;
229 }
230 
231 static void device_name_get(size_t idx, struct shell_static_entry *entry);
232 
233 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
234 
device_name_get(size_t idx,struct shell_static_entry * entry)235 static void device_name_get(size_t idx, struct shell_static_entry *entry)
236 {
237 	const struct device *dev = shell_device_lookup(idx, I2C_DEVICE_PREFIX);
238 
239 	entry->syntax = (dev != NULL) ? dev->name : NULL;
240 	entry->handler = NULL;
241 	entry->help = NULL;
242 	entry->subcmd = NULL;
243 }
244 
245 SHELL_STATIC_SUBCMD_SET_CREATE(sub_i2c_cmds,
246 			       SHELL_CMD(scan, &dsub_device_name,
247 					 "Scan I2C devices", cmd_i2c_scan),
248 			       SHELL_CMD(recover, &dsub_device_name,
249 					 "Recover I2C bus", cmd_i2c_recover),
250 			       SHELL_CMD_ARG(read, &dsub_device_name,
251 					     "Read bytes from an I2C device",
252 					     cmd_i2c_read, 3, MAX_I2C_BYTES),
253 			       SHELL_CMD_ARG(read_byte, &dsub_device_name,
254 					     "Read a byte from an I2C device",
255 					     cmd_i2c_read_byte, 3, 1),
256 			       SHELL_CMD_ARG(write, &dsub_device_name,
257 					     "Write bytes to an I2C device",
258 					     cmd_i2c_write, 3, MAX_I2C_BYTES),
259 			       SHELL_CMD_ARG(write_byte, &dsub_device_name,
260 					     "Write a byte to an I2C device",
261 					     cmd_i2c_write_byte, 4, 1),
262 			       SHELL_SUBCMD_SET_END     /* Array terminated. */
263 			       );
264 
265 SHELL_CMD_REGISTER(i2c, &sub_i2c_cmds, "I2C commands", NULL);
266