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 * shell_ctx,size_t argc,char ** argv)51 static int cmd_i2c_scan(const struct shell *shell_ctx,
52 size_t argc, char **argv)
53 {
54 const struct device *dev;
55 uint8_t cnt = 0, first = 0x04, last = 0x77;
56
57 dev = shell_device_get_binding(argv[ARGV_DEV]);
58
59 if (!dev) {
60 shell_error(shell_ctx, "I2C: Device driver %s not found.",
61 argv[ARGV_DEV]);
62 return -ENODEV;
63 }
64
65 shell_print(shell_ctx,
66 " 0 1 2 3 4 5 6 7 8 9 a b c d e f");
67 for (uint8_t i = 0; i <= last; i += 16) {
68 shell_fprintf(shell_ctx, SHELL_NORMAL, "%02x: ", i);
69 for (uint8_t j = 0; j < 16; j++) {
70 if (i + j < first || i + j > last) {
71 shell_fprintf(shell_ctx, SHELL_NORMAL, " ");
72 continue;
73 }
74
75 struct i2c_msg msgs[1];
76 uint8_t dst;
77
78 /* Send the address to read from */
79 msgs[0].buf = &dst;
80 msgs[0].len = 0U;
81 msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
82 if (i2c_transfer(dev, &msgs[0], 1, i + j) == 0) {
83 shell_fprintf(shell_ctx, SHELL_NORMAL,
84 "%02x ", i + j);
85 ++cnt;
86 } else {
87 shell_fprintf(shell_ctx, SHELL_NORMAL, "-- ");
88 }
89 }
90 shell_print(shell_ctx, "");
91 }
92
93 shell_print(shell_ctx, "%u devices found on %s",
94 cnt, argv[ARGV_DEV]);
95
96 return 0;
97 }
98
99 /* i2c recover <device> */
cmd_i2c_recover(const struct shell * shell_ctx,size_t argc,char ** argv)100 static int cmd_i2c_recover(const struct shell *shell_ctx,
101 size_t argc, char **argv)
102 {
103 const struct device *dev;
104 int err;
105
106 dev = shell_device_get_binding(argv[ARGV_DEV]);
107 if (!dev) {
108 shell_error(shell_ctx, "I2C: Device driver %s not found.",
109 argv[1]);
110 return -ENODEV;
111 }
112
113 err = i2c_recover_bus(dev);
114 if (err) {
115 shell_error(shell_ctx, "I2C: Bus recovery failed (err %d)",
116 err);
117 return err;
118 }
119
120 return 0;
121 }
122
i2c_write_from_buffer(const struct shell * shell_ctx,char * s_dev_name,char * s_dev_addr,char * s_reg_addr,char ** data,uint8_t data_length)123 static int i2c_write_from_buffer(const struct shell *shell_ctx,
124 char *s_dev_name, char *s_dev_addr, char *s_reg_addr,
125 char **data, uint8_t data_length)
126 {
127 /* This buffer must preserve 4 bytes for register address, as it is
128 * filled using put_be32 function and we don't want to lower available
129 * space when using 1 byte address.
130 */
131 uint8_t buf[MAX_I2C_BYTES + MAX_BYTES_FOR_REGISTER_INDEX - 1];
132 const struct device *dev;
133 int reg_addr_bytes;
134 int reg_addr;
135 int dev_addr;
136 int ret;
137 int i;
138
139 dev = shell_device_get_binding(s_dev_name);
140 if (!dev) {
141 shell_error(shell_ctx, "I2C: Device driver %s not found.",
142 s_dev_name);
143 return -ENODEV;
144 }
145
146 dev_addr = strtol(s_dev_addr, NULL, 16);
147 reg_addr = strtol(s_reg_addr, NULL, 16);
148
149 reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr);
150 sys_put_be32(reg_addr, buf);
151
152 if (data_length + reg_addr_bytes > MAX_I2C_BYTES) {
153 data_length = MAX_I2C_BYTES - reg_addr_bytes;
154 shell_info(shell_ctx, "Too many bytes provided, limit is %d",
155 MAX_I2C_BYTES - reg_addr_bytes);
156 }
157
158 for (i = 0; i < data_length; i++) {
159 buf[MAX_BYTES_FOR_REGISTER_INDEX + i] =
160 (uint8_t)strtol(data[i], NULL, 16);
161 }
162
163 ret = i2c_write(dev,
164 buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes,
165 reg_addr_bytes + data_length, dev_addr);
166 if (ret < 0) {
167 shell_error(shell_ctx, "Failed to write to device: %s",
168 s_dev_addr);
169 return -EIO;
170 }
171
172 return 0;
173 }
174
175 /* i2c write <device> <dev_addr> <reg_addr> [<byte1>, ...] */
cmd_i2c_write(const struct shell * shell_ctx,size_t argc,char ** argv)176 static int cmd_i2c_write(const struct shell *shell_ctx,
177 size_t argc, char **argv)
178 {
179 return i2c_write_from_buffer(shell_ctx, argv[ARGV_DEV],
180 argv[ARGV_ADDR], argv[ARGV_REG],
181 &argv[4], argc - 4);
182 }
183
184 /* i2c write_byte <device> <dev_addr> <reg_addr> <value> */
cmd_i2c_write_byte(const struct shell * shell_ctx,size_t argc,char ** argv)185 static int cmd_i2c_write_byte(const struct shell *shell_ctx,
186 size_t argc, char **argv)
187 {
188 return i2c_write_from_buffer(shell_ctx, argv[ARGV_DEV],
189 argv[ARGV_ADDR], argv[ARGV_REG],
190 &argv[4], 1);
191 }
192
i2c_read_to_buffer(const struct shell * shell_ctx,char * s_dev_name,char * s_dev_addr,char * s_reg_addr,uint8_t * buf,uint8_t buf_length)193 static int i2c_read_to_buffer(const struct shell *shell_ctx,
194 char *s_dev_name,
195 char *s_dev_addr, char *s_reg_addr,
196 uint8_t *buf, uint8_t buf_length)
197 {
198 const struct device *dev;
199 int dev_addr;
200 int ret;
201
202 dev = shell_device_get_binding(s_dev_name);
203 if (!dev) {
204 shell_error(shell_ctx, "I2C: Device driver %s not found.",
205 s_dev_name);
206 return -ENODEV;
207 }
208
209 dev_addr = strtol(s_dev_addr, NULL, 16);
210
211 if (s_reg_addr != NULL) {
212 uint8_t reg_addr_buf[MAX_BYTES_FOR_REGISTER_INDEX];
213 int reg_addr_bytes;
214 int reg_addr;
215
216 reg_addr = strtol(s_reg_addr, NULL, 16);
217 reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr);
218 sys_put_be32(reg_addr, reg_addr_buf);
219
220 ret = i2c_write_read(dev, dev_addr,
221 reg_addr_buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes,
222 reg_addr_bytes, buf, buf_length);
223 } else {
224 ret = i2c_read(dev, buf, buf_length, dev_addr);
225 }
226
227 if (ret < 0) {
228 shell_error(shell_ctx, "Failed to read from device: %s",
229 s_dev_addr);
230 return -EIO;
231 }
232
233 return 0;
234 }
235
236 /* i2c read_byte <device> <dev_addr> <reg_addr> */
cmd_i2c_read_byte(const struct shell * shell_ctx,size_t argc,char ** argv)237 static int cmd_i2c_read_byte(const struct shell *shell_ctx,
238 size_t argc, char **argv)
239 {
240 uint8_t out;
241 int ret;
242
243
244 ret = i2c_read_to_buffer(shell_ctx, argv[ARGV_DEV],
245 argv[ARGV_ADDR], argv[ARGV_REG], &out, 1);
246 if (ret == 0) {
247 shell_print(shell_ctx, "Output: 0x%x", out);
248 }
249
250 return ret;
251 }
252
253 /* i2c read <device> <dev_addr> <reg_addr> [<numbytes>] */
cmd_i2c_read(const struct shell * shell_ctx,size_t argc,char ** argv)254 static int cmd_i2c_read(const struct shell *shell_ctx, size_t argc, char **argv)
255 {
256 uint8_t buf[MAX_I2C_BYTES];
257 int num_bytes;
258 int ret;
259
260 if (argc > 4) {
261 num_bytes = strtol(argv[4], NULL, 16);
262 if (num_bytes > MAX_I2C_BYTES) {
263 num_bytes = MAX_I2C_BYTES;
264 }
265 } else {
266 num_bytes = MAX_I2C_BYTES;
267 }
268
269 ret = i2c_read_to_buffer(shell_ctx, argv[ARGV_DEV],
270 argv[ARGV_ADDR], argv[ARGV_REG],
271 buf, num_bytes);
272 if (ret == 0) {
273 shell_hexdump(shell_ctx, buf, num_bytes);
274 }
275
276 return ret;
277 }
278
279 /* i2c direct_read <device> <dev_addr> [<numbytes>] */
cmd_i2c_direct_read(const struct shell * shell_ctx,size_t argc,char ** argv)280 static int cmd_i2c_direct_read(const struct shell *shell_ctx, size_t argc, char **argv)
281 {
282 uint8_t buf[MAX_I2C_BYTES];
283 int num_bytes;
284 int ret;
285
286 if (argc > 3) {
287 num_bytes = strtol(argv[3], NULL, 16);
288 if (num_bytes > MAX_I2C_BYTES) {
289 num_bytes = MAX_I2C_BYTES;
290 }
291 } else {
292 num_bytes = MAX_I2C_BYTES;
293 }
294
295 ret = i2c_read_to_buffer(shell_ctx, argv[ARGV_DEV], argv[ARGV_ADDR], NULL, buf, num_bytes);
296 if (ret == 0) {
297 shell_hexdump(shell_ctx, buf, num_bytes);
298 }
299
300 return ret;
301 }
302
303 /* i2c speed <device> <speed>
304 * For: speed see constants like I2C_SPEED_STANDARD
305 */
cmd_i2c_speed(const struct shell * shell_ctx,size_t argc,char ** argv)306 static int cmd_i2c_speed(const struct shell *shell_ctx, size_t argc, char **argv)
307 {
308 char *s_dev_name = argv[ARGV_DEV];
309 const struct device *dev;
310 uint32_t dev_config = 0;
311 uint32_t speed;
312 int ret;
313
314 dev = shell_device_get_binding(s_dev_name);
315 if (!dev) {
316 shell_error(shell_ctx, "I2C: Device driver %s not found.",
317 s_dev_name);
318 return -ENODEV;
319 }
320
321 speed = strtol(argv[ARGV_DEV + 1], NULL, 10);
322 ret = i2c_get_config(dev, &dev_config);
323 if (ret == 0) {
324 dev_config &= ~I2C_SPEED_MASK;
325 dev_config |= I2C_SPEED_SET(speed);
326 } else {
327 /* Can't get current config. Fallback to something reasonable */
328 dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(speed);
329 }
330
331 ret = i2c_configure(dev, dev_config);
332 if (ret < 0) {
333 shell_error(shell_ctx, "I2C: Failed to configure device: %s",
334 s_dev_name);
335 return -EIO;
336 }
337 return 0;
338 }
339
device_is_i2c(const struct device * dev)340 static bool device_is_i2c(const struct device *dev)
341 {
342 #ifdef CONFIG_I3C
343 return DEVICE_API_IS(i2c, dev) || DEVICE_API_IS(i3c, dev);
344 #else
345 return DEVICE_API_IS(i2c, dev);
346 #endif
347 }
348
device_name_get(size_t idx,struct shell_static_entry * entry)349 static void device_name_get(size_t idx, struct shell_static_entry *entry)
350 {
351 const struct device *dev = shell_device_filter(idx, device_is_i2c);
352
353 entry->syntax = (dev != NULL) ? dev->name : NULL;
354 entry->handler = NULL;
355 entry->help = NULL;
356 entry->subcmd = NULL;
357 }
358
359 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
360
361 SHELL_STATIC_SUBCMD_SET_CREATE(sub_i2c_cmds,
362 SHELL_CMD_ARG(scan, &dsub_device_name,
363 "Scan I2C devices\n"
364 "Usage: scan <device>",
365 cmd_i2c_scan, 2, 0),
366 SHELL_CMD_ARG(recover, &dsub_device_name,
367 "Recover I2C bus\n"
368 "Usage: recover <device>",
369 cmd_i2c_recover, 2, 0),
370 SHELL_CMD_ARG(read, &dsub_device_name,
371 "Read bytes from an I2C device\n"
372 "Usage: read <device> <addr> <reg> [<bytes>]",
373 cmd_i2c_read, 4, 1),
374 SHELL_CMD_ARG(read_byte, &dsub_device_name,
375 "Read a byte from an I2C device\n"
376 "Usage: read_byte <device> <addr> <reg>",
377 cmd_i2c_read_byte, 4, 0),
378 SHELL_CMD_ARG(direct_read, &dsub_device_name,
379 "Read byte stream directly from an I2C device without "
380 "writing a register address first\n"
381 "Usage: direct_read <device> <addr> [<bytes>]",
382 cmd_i2c_direct_read, 3, 1),
383 SHELL_CMD_ARG(write, &dsub_device_name,
384 "Write bytes to an I2C device\n"
385 "Usage: write <device> <addr> <reg> [<byte1>, ...]",
386 cmd_i2c_write, 4, MAX_I2C_BYTES),
387 SHELL_CMD_ARG(write_byte, &dsub_device_name,
388 "Write a byte to an I2C device\n"
389 "Usage: write_byte <device> <addr> <reg> <value>",
390 cmd_i2c_write_byte, 5, 0),
391 SHELL_CMD_ARG(speed, &dsub_device_name,
392 "Configure I2C bus speed\n"
393 "Usage: speed <device> <speed>",
394 cmd_i2c_speed, 3, 0),
395 SHELL_SUBCMD_SET_END /* Array terminated. */
396 );
397
398 SHELL_CMD_REGISTER(i2c, &sub_i2c_cmds, "I2C commands", NULL);
399