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