blob: 6a213406317ad5478b4b86049ae69f209203246b [file] [log] [blame]
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001/* vi: set sw=4 ts=4: */
2/*
3 * Minimal i2c-tools implementation for busybox.
4 * Parts of code ported from i2c-tools:
5 * http://www.lm-sensors.org/wiki/I2CTools.
6 *
7 * Copyright (C) 2014 by Bartosz Golaszewski <bartekgola@gmail.com>
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010011//config:config I2CGET
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020012//config: bool "i2cget (5.6 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010013//config: default y
14//config: select PLATFORM_LINUX
15//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020016//config: Read from I2C/SMBus chip registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010017//config:
18//config:config I2CSET
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020019//config: bool "i2cset (6.9 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010020//config: default y
21//config: select PLATFORM_LINUX
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: Set I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010024//config:
25//config:config I2CDUMP
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020026//config: bool "i2cdump (7.2 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010027//config: default y
28//config: select PLATFORM_LINUX
29//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020030//config: Examine I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010031//config:
32//config:config I2CDETECT
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020033//config: bool "i2cdetect (7.2 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010034//config: default y
35//config: select PLATFORM_LINUX
36//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020037//config: Detect I2C chips.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010038//config:
39
40//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
41//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
42//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
43//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
Denys Vlasenko1a1203f2017-08-07 16:47:34 +020044/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010045
46//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
47//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
48//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
49//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
50
51/*
52 * Unsupported stuff:
53 *
54 * - upstream i2c-tools can also look-up i2c busses by name, we only accept
55 * numbers,
56 * - bank and bankreg parameters for i2cdump are not supported because of
57 * their limited usefulness (see i2cdump manual entry for more info),
58 * - i2cdetect doesn't look for bus info in /proc as it does in upstream, but
59 * it shouldn't be a problem in modern kernels.
60 */
61
62#include "libbb.h"
63
Bartosz Golaszewskid9892fa2015-09-04 10:35:22 +020064#include <linux/i2c.h>
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010065
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020066#define I2CDUMP_NUM_REGS 256
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010067
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020068#define I2CDETECT_MODE_AUTO 0
69#define I2CDETECT_MODE_QUICK 1
70#define I2CDETECT_MODE_READ 2
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010071
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020072/* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi
73 * and defines symbols already defined by linux/i2c.h.
74 * Also, it defines a bunch of static inlines which we would rather NOT
75 * inline. What a mess.
76 * We need only these definitions from linux/i2c-dev.h:
77 */
78#define I2C_SLAVE 0x0703
79#define I2C_SLAVE_FORCE 0x0706
80#define I2C_FUNCS 0x0705
81#define I2C_PEC 0x0708
82#define I2C_SMBUS 0x0720
83struct i2c_smbus_ioctl_data {
84 __u8 read_write;
85 __u8 command;
86 __u32 size;
87 union i2c_smbus_data *data;
88};
89/* end linux/i2c-dev.h */
90
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010091/*
92 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
93 */
94static ALWAYS_INLINE void *itoptr(int i)
95{
96 return (void*)(intptr_t)i;
97}
98
99static int32_t i2c_smbus_access(int fd, char read_write, uint8_t cmd,
100 int size, union i2c_smbus_data *data)
101{
102 struct i2c_smbus_ioctl_data args;
103
104 args.read_write = read_write;
105 args.command = cmd;
106 args.size = size;
107 args.data = data;
108
109 return ioctl(fd, I2C_SMBUS, &args);
110}
111
112static int32_t i2c_smbus_read_byte(int fd)
113{
114 union i2c_smbus_data data;
115 int err;
116
117 err = i2c_smbus_access(fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
118 if (err < 0)
119 return err;
120
121 return data.byte;
122}
123
124#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
125static int32_t i2c_smbus_write_byte(int fd, uint8_t val)
126{
127 return i2c_smbus_access(fd, I2C_SMBUS_WRITE,
128 val, I2C_SMBUS_BYTE, NULL);
129}
130
131static int32_t i2c_smbus_read_byte_data(int fd, uint8_t cmd)
132{
133 union i2c_smbus_data data;
134 int err;
135
136 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
137 I2C_SMBUS_BYTE_DATA, &data);
138 if (err < 0)
139 return err;
140
141 return data.byte;
142}
143
144static int32_t i2c_smbus_read_word_data(int fd, uint8_t cmd)
145{
146 union i2c_smbus_data data;
147 int err;
148
149 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
150 I2C_SMBUS_WORD_DATA, &data);
151 if (err < 0)
152 return err;
153
154 return data.word;
155}
156#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
157
158#if ENABLE_I2CSET
159static int32_t i2c_smbus_write_byte_data(int file,
160 uint8_t cmd, uint8_t value)
161{
162 union i2c_smbus_data data;
163
164 data.byte = value;
165
166 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
167 I2C_SMBUS_BYTE_DATA, &data);
168}
169
170static int32_t i2c_smbus_write_word_data(int file, uint8_t cmd, uint16_t value)
171{
172 union i2c_smbus_data data;
173
174 data.word = value;
175
176 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
177 I2C_SMBUS_WORD_DATA, &data);
178}
179
180static int32_t i2c_smbus_write_block_data(int file, uint8_t cmd,
181 uint8_t length, const uint8_t *values)
182{
183 union i2c_smbus_data data;
184
185 if (length > I2C_SMBUS_BLOCK_MAX)
186 length = I2C_SMBUS_BLOCK_MAX;
187
188 memcpy(data.block+1, values, length);
189 data.block[0] = length;
190
191 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
192 I2C_SMBUS_BLOCK_DATA, &data);
193}
194
195static int32_t i2c_smbus_write_i2c_block_data(int file, uint8_t cmd,
196 uint8_t length, const uint8_t *values)
197{
198 union i2c_smbus_data data;
199
200 if (length > I2C_SMBUS_BLOCK_MAX)
201 length = I2C_SMBUS_BLOCK_MAX;
202
203 memcpy(data.block+1, values, length);
204 data.block[0] = length;
205
206 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
207 I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
208}
209#endif /* ENABLE_I2CSET */
210
211#if ENABLE_I2CDUMP
212/*
213 * Returns the number of bytes read, vals must hold at
214 * least I2C_SMBUS_BLOCK_MAX bytes.
215 */
216static int32_t i2c_smbus_read_block_data(int fd, uint8_t cmd, uint8_t *vals)
217{
218 union i2c_smbus_data data;
219 int i, err;
220
221 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
222 I2C_SMBUS_BLOCK_DATA, &data);
223 if (err < 0)
224 return err;
225
226 for (i = 1; i <= data.block[0]; i++)
227 *vals++ = data.block[i];
228 return data.block[0];
229}
230
231static int32_t i2c_smbus_read_i2c_block_data(int fd, uint8_t cmd,
232 uint8_t len, uint8_t *vals)
233{
234 union i2c_smbus_data data;
235 int i, err;
236
237 if (len > I2C_SMBUS_BLOCK_MAX)
238 len = I2C_SMBUS_BLOCK_MAX;
239 data.block[0] = len;
240
241 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
242 len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
243 I2C_SMBUS_I2C_BLOCK_DATA, &data);
244 if (err < 0)
245 return err;
246
247 for (i = 1; i <= data.block[0]; i++)
248 *vals++ = data.block[i];
249 return data.block[0];
250}
251#endif /* ENABLE_I2CDUMP */
252
253#if ENABLE_I2CDETECT
254static int32_t i2c_smbus_write_quick(int fd, uint8_t val)
255{
256 return i2c_smbus_access(fd, val, 0, I2C_SMBUS_QUICK, NULL);
257}
258#endif /* ENABLE_I2CDETECT */
259
260static int i2c_bus_lookup(const char *bus_str)
261{
262 return xstrtou_range(bus_str, 10, 0, 0xfffff);
263}
264
265#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
266static int i2c_parse_bus_addr(const char *addr_str)
267{
268 /* Slave address must be in range 0x03 - 0x77. */
269 return xstrtou_range(addr_str, 16, 0x03, 0x77);
270}
271
272static void i2c_set_pec(int fd, int pec)
273{
274 ioctl_or_perror_and_die(fd, I2C_PEC,
275 itoptr(pec ? 1 : 0),
276 "can't set PEC");
277}
Bartosz Golaszewski31474272015-06-05 10:27:28 +0200278
279static void i2c_set_slave_addr(int fd, int addr, int force)
280{
281 ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
282 itoptr(addr),
283 "can't set address to 0x%02x", addr);
284}
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100285#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
286
287#if ENABLE_I2CGET || ENABLE_I2CSET
288static int i2c_parse_data_addr(const char *data_addr)
289{
290 /* Data address must be an 8 bit integer. */
291 return xstrtou_range(data_addr, 16, 0, 0xff);
292}
293#endif /* ENABLE_I2CGET || ENABLE_I2CSET */
294
295/*
296 * Opens the device file associated with given i2c bus.
297 *
298 * Upstream i2c-tools also support opening devices by i2c bus name
299 * but we drop it here for size reduction.
300 */
301static int i2c_dev_open(int i2cbus)
302{
303 char filename[sizeof("/dev/i2c-%d") + sizeof(int)*3];
304 int fd;
305
306 sprintf(filename, "/dev/i2c-%d", i2cbus);
307 fd = open(filename, O_RDWR);
308 if (fd < 0) {
Bartosz Golaszewski7ca5c512015-05-11 17:26:27 +0200309 if (errno == ENOENT) {
310 filename[8] = '/'; /* change to "/dev/i2c/%d" */
311 fd = xopen(filename, O_RDWR);
312 } else {
313 bb_perror_msg_and_die("can't open '%s'", filename);
314 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100315 }
316
317 return fd;
318}
319
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100320/* Size reducing helpers for xxx_check_funcs(). */
321static void get_funcs_matrix(int fd, unsigned long *funcs)
322{
323 ioctl_or_perror_and_die(fd, I2C_FUNCS, funcs,
324 "can't get adapter functionality matrix");
325}
326
327#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
328static void check_funcs_test_end(int funcs, int pec, const char *err)
329{
330 if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C)))
331 bb_error_msg("warning: adapter does not support PEC");
332
333 if (err)
334 bb_error_msg_and_die(
335 "adapter has no %s capability", err);
336}
337#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
338
339/*
340 * The below functions emit an error message and exit if the adapter doesn't
341 * support desired functionalities.
342 */
343#if ENABLE_I2CGET || ENABLE_I2CDUMP
344static void check_read_funcs(int fd, int mode, int data_addr, int pec)
345{
346 unsigned long funcs;
347 const char *err = NULL;
348
349 get_funcs_matrix(fd, &funcs);
350 switch (mode) {
351 case I2C_SMBUS_BYTE:
352 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
353 err = "SMBus receive byte";
354 break;
355 }
356 if (data_addr >= 0 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
357 err = "SMBus send byte";
358 break;
359 case I2C_SMBUS_BYTE_DATA:
360 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
361 err = "SMBus read byte";
362 break;
363 case I2C_SMBUS_WORD_DATA:
364 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
365 err = "SMBus read word";
366 break;
367#if ENABLE_I2CDUMP
368 case I2C_SMBUS_BLOCK_DATA:
369 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
370 err = "SMBus block read";
371 break;
372
373 case I2C_SMBUS_I2C_BLOCK_DATA:
374 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
375 err = "I2C block read";
376 break;
377#endif /* ENABLE_I2CDUMP */
378 default:
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +0200379 bb_error_msg_and_die("internal error");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100380 }
381 check_funcs_test_end(funcs, pec, err);
382}
383#endif /* ENABLE_I2CGET || ENABLE_I2CDUMP */
384
385#if ENABLE_I2CSET
386static void check_write_funcs(int fd, int mode, int pec)
387{
388 unsigned long funcs;
389 const char *err = NULL;
390
391 get_funcs_matrix(fd, &funcs);
392 switch (mode) {
393 case I2C_SMBUS_BYTE:
394 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
395 err = "SMBus send byte";
396 break;
397
398 case I2C_SMBUS_BYTE_DATA:
399 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
400 err = "SMBus write byte";
401 break;
402
403 case I2C_SMBUS_WORD_DATA:
404 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
405 err = "SMBus write word";
406 break;
407
408 case I2C_SMBUS_BLOCK_DATA:
409 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
410 err = "SMBus block write";
411 break;
412 case I2C_SMBUS_I2C_BLOCK_DATA:
413 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
414 err = "I2C block write";
415 break;
416 }
417 check_funcs_test_end(funcs, pec, err);
418}
419#endif /* ENABLE_I2CSET */
420
421static void confirm_or_abort(void)
422{
423 fprintf(stderr, "Continue? [y/N] ");
Denys Vlasenko77cb6b92018-04-07 15:08:12 +0200424 if (!bb_ask_y_confirmation())
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100425 bb_error_msg_and_die("aborting");
426}
427
428/*
429 * Return only if user confirms the action, abort otherwise.
430 *
431 * The messages displayed here are much less elaborate than their i2c-tools
432 * counterparts - this is done for size reduction.
433 */
434static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
435{
436 bb_error_msg("WARNING! This program can confuse your I2C bus");
437
438 /* Don't let the user break his/her EEPROMs */
439 if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
440 bb_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
441 "devices may result in data loss, aborting");
442 }
443
444 if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
445 bb_error_msg("WARNING! May interpret a write byte command "
446 "with PEC as a write byte data command");
447
448 if (pec)
449 bb_error_msg("PEC checking enabled");
450
451 confirm_or_abort();
452}
453
454#if ENABLE_I2CGET
455//usage:#define i2cget_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200456//usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100457//usage:#define i2cget_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200458//usage: "Read from I2C/SMBus chip registers"
459//usage: "\n"
460//usage: "\n I2CBUS I2C bus number"
461//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100462//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200463//usage: "\n b Read byte data (default)"
464//usage: "\n w Read word data"
465//usage: "\n c Write byte/read byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100466//usage: "\n Append p for SMBus PEC"
467//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200468//usage: "\n -f Force access"
469//usage: "\n -y Disable interactive mode"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100470int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
471int i2cget_main(int argc UNUSED_PARAM, char **argv)
472{
473 const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100474
475 int bus_num, bus_addr, data_addr = -1, status;
476 int mode = I2C_SMBUS_BYTE, pec = 0, fd;
477 unsigned opts;
478
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200479 opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100480 argv += optind;
481
482 bus_num = i2c_bus_lookup(argv[0]);
483 bus_addr = i2c_parse_bus_addr(argv[1]);
484
485 if (argv[2]) {
486 data_addr = i2c_parse_data_addr(argv[2]);
487 mode = I2C_SMBUS_BYTE_DATA;
488 if (argv[3]) {
489 switch (argv[3][0]) {
490 case 'b': /* Already set */ break;
491 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
492 case 'c': mode = I2C_SMBUS_BYTE; break;
493 default:
494 bb_error_msg("invalid mode");
495 bb_show_usage();
496 }
497 pec = argv[3][1] == 'p';
498 }
499 }
500
501 fd = i2c_dev_open(bus_num);
502 check_read_funcs(fd, mode, data_addr, pec);
503 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
504
505 if (!(opts & opt_y))
506 confirm_action(bus_addr, mode, data_addr, pec);
507
508 if (pec)
509 i2c_set_pec(fd, 1);
510
511 switch (mode) {
512 case I2C_SMBUS_BYTE:
513 if (data_addr >= 0) {
514 status = i2c_smbus_write_byte(fd, data_addr);
515 if (status < 0)
516 bb_error_msg("warning - write failed");
517 }
518 status = i2c_smbus_read_byte(fd);
519 break;
520 case I2C_SMBUS_WORD_DATA:
521 status = i2c_smbus_read_word_data(fd, data_addr);
522 break;
523 default: /* I2C_SMBUS_BYTE_DATA */
524 status = i2c_smbus_read_byte_data(fd, data_addr);
525 }
526 close(fd);
527
528 if (status < 0)
529 bb_perror_msg_and_die("read failed");
530
531 printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
532
533 return 0;
534}
535#endif /* ENABLE_I2CGET */
536
537#if ENABLE_I2CSET
538//usage:#define i2cset_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200539//usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100540//usage:#define i2cset_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200541//usage: "Set I2C registers"
542//usage: "\n"
543//usage: "\n I2CBUS I2C bus number"
544//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100545//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200546//usage: "\n c Byte, no value"
547//usage: "\n b Byte data (default)"
548//usage: "\n w Word data"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100549//usage: "\n i I2C block data"
550//usage: "\n s SMBus block data"
551//usage: "\n Append p for SMBus PEC"
552//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200553//usage: "\n -f Force access"
554//usage: "\n -y Disable interactive mode"
555//usage: "\n -r Read back and compare the result"
556//usage: "\n -m MASK Mask specifying which bits to write"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100557int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
558int i2cset_main(int argc, char **argv)
559{
560 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
561 opt_m = (1 << 2), opt_r = (1 << 3);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100562
563 int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200564 int val, blen, mask, fd, status;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100565 unsigned char block[I2C_SMBUS_BLOCK_MAX];
566 char *opt_m_arg = NULL;
567 unsigned opts;
568
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200569 opts = getopt32(argv, "^"
570 "fym:r"
571 "\0" "-3", /* minimum 3 args */
572 &opt_m_arg
573 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100574 argv += optind;
575 argc -= optind;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200576 argc--; /* now argv[argc] is last arg */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100577
578 bus_num = i2c_bus_lookup(argv[0]);
579 bus_addr = i2c_parse_bus_addr(argv[1]);
580 data_addr = i2c_parse_data_addr(argv[2]);
581
582 if (argv[3]) {
583 if (!argv[4] && argv[3][0] != 'c') {
584 mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
585 } else {
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200586 switch (argv[argc][0]) {
587 case 'c': /* Already set */
588 break;
589 case 'b': mode = I2C_SMBUS_BYTE_DATA;
590 break;
591 case 'w': mode = I2C_SMBUS_WORD_DATA;
592 break;
593 case 's': mode = I2C_SMBUS_BLOCK_DATA;
594 break;
595 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
596 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100597 default:
598 bb_error_msg("invalid mode");
599 bb_show_usage();
600 }
601
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200602 pec = (argv[argc][1] == 'p');
603 if (mode == I2C_SMBUS_BLOCK_DATA
604 || mode == I2C_SMBUS_I2C_BLOCK_DATA
605 ) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100606 if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
607 bb_error_msg_and_die(
608 "PEC not supported for I2C "
609 "block writes");
610 if (opts & opt_m)
611 bb_error_msg_and_die(
612 "mask not supported for block "
613 "writes");
614 }
615 }
616 }
617
618 /* Prepare the value(s) to be written according to current mode. */
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200619 mask = 0;
620 blen = 0;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100621 switch (mode) {
622 case I2C_SMBUS_BYTE_DATA:
623 val = xstrtou_range(argv[3], 0, 0, 0xff);
624 break;
625 case I2C_SMBUS_WORD_DATA:
626 val = xstrtou_range(argv[3], 0, 0, 0xffff);
627 break;
628 case I2C_SMBUS_BLOCK_DATA:
629 case I2C_SMBUS_I2C_BLOCK_DATA:
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200630 for (blen = 3; blen < argc; blen++)
631 block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
632 blen -= 3;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100633 val = -1;
634 break;
635 default:
636 val = -1;
637 break;
638 }
639
640 if (opts & opt_m) {
641 mask = xstrtou_range(opt_m_arg, 0, 0,
642 (mode == I2C_SMBUS_BYTE ||
643 mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
644 }
645
646 fd = i2c_dev_open(bus_num);
647 check_write_funcs(fd, mode, pec);
648 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
649
650 if (!(opts & opt_y))
651 confirm_action(bus_addr, mode, data_addr, pec);
652
653 /*
654 * If we're using mask - read the current value here and adjust the
655 * value to be written.
656 */
657 if (opts & opt_m) {
658 int tmpval;
659
660 switch (mode) {
661 case I2C_SMBUS_BYTE:
662 tmpval = i2c_smbus_read_byte(fd);
663 break;
664 case I2C_SMBUS_WORD_DATA:
665 tmpval = i2c_smbus_read_word_data(fd, data_addr);
666 break;
667 default:
668 tmpval = i2c_smbus_read_byte_data(fd, data_addr);
669 }
670
671 if (tmpval < 0)
672 bb_perror_msg_and_die("can't read old value");
673
674 val = (val & mask) | (tmpval & ~mask);
675
676 if (!(opts & opt_y)) {
677 bb_error_msg("old value 0x%0*x, write mask "
678 "0x%0*x, will write 0x%0*x to register "
679 "0x%02x",
680 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
681 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
682 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
683 data_addr);
684 confirm_or_abort();
685 }
686 }
687
688 if (pec)
689 i2c_set_pec(fd, 1);
690
691 switch (mode) {
692 case I2C_SMBUS_BYTE:
693 status = i2c_smbus_write_byte(fd, data_addr);
694 break;
695 case I2C_SMBUS_WORD_DATA:
696 status = i2c_smbus_write_word_data(fd, data_addr, val);
697 break;
698 case I2C_SMBUS_BLOCK_DATA:
699 status = i2c_smbus_write_block_data(fd, data_addr,
700 blen, block);
701 break;
702 case I2C_SMBUS_I2C_BLOCK_DATA:
703 status = i2c_smbus_write_i2c_block_data(fd, data_addr,
704 blen, block);
705 break;
706 default: /* I2C_SMBUS_BYTE_DATA */
707 status = i2c_smbus_write_byte_data(fd, data_addr, val);
708 break;
709 }
710 if (status < 0)
711 bb_perror_msg_and_die("write failed");
712
713 if (pec)
714 i2c_set_pec(fd, 0); /* Clear PEC. */
715
716 /* No readback required - we're done. */
717 if (!(opts & opt_r))
718 return 0;
719
720 switch (mode) {
721 case I2C_SMBUS_BYTE:
722 status = i2c_smbus_read_byte(fd);
723 val = data_addr;
724 break;
725 case I2C_SMBUS_WORD_DATA:
726 status = i2c_smbus_read_word_data(fd, data_addr);
727 break;
728 default: /* I2C_SMBUS_BYTE_DATA */
729 status = i2c_smbus_read_byte_data(fd, data_addr);
730 }
731
732 if (status < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200733 puts("Warning - readback failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100734 } else
735 if (status != val) {
736 printf("Warning - data mismatch - wrote "
737 "0x%0*x, read back 0x%0*x\n",
738 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
739 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
740 } else {
741 printf("Value 0x%0*x written, readback matched\n",
742 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
743 }
744
745 return 0;
746}
747#endif /* ENABLE_I2CSET */
748
749#if ENABLE_I2CDUMP
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200750static int read_block_data(int buf_fd, int mode, int *block)
751{
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200752 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200753 int res, blen = 0, tmp, i;
754
Bartosz Golaszewski1fe75b82015-10-27 17:15:03 +0100755 if (mode == I2C_SMBUS_BLOCK_DATA) {
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100756 blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
757 if (blen <= 0)
758 goto fail;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200759 } else {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200760 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200761 tmp = i2c_smbus_read_i2c_block_data(
762 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
763 cblock + res);
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100764 if (tmp <= 0) {
765 blen = tmp;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100766 goto fail;
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100767 }
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200768 }
769
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200770 if (res >= I2CDUMP_NUM_REGS)
771 res = I2CDUMP_NUM_REGS;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200772
773 for (i = 0; i < res; i++)
774 block[i] = cblock[i];
775
776 if (mode != I2C_SMBUS_BLOCK_DATA)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200777 for (i = res; i < I2CDUMP_NUM_REGS; i++)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200778 block[i] = -1;
779 }
780
781 return blen;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100782
783 fail:
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100784 bb_error_msg_and_die("block read failed: %d", blen);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200785}
786
787/* Dump all but word data. */
788static void dump_data(int bus_fd, int mode, unsigned first,
789 unsigned last, int *block, int blen)
790{
791 int i, j, res;
792
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200793 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
794 " 0123456789abcdef");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200795
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200796 for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200797 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
798 break;
799 if (i/16 < first/16)
800 continue;
801 if (i/16 > last/16)
802 break;
803
804 printf("%02x: ", i);
805 for (j = 0; j < 16; j++) {
806 fflush_all();
807 /* Skip unwanted registers */
808 if (i+j < first || i+j > last) {
809 printf(" ");
810 if (mode == I2C_SMBUS_WORD_DATA) {
811 printf(" ");
812 j++;
813 }
814 continue;
815 }
816
817 switch (mode) {
818 case I2C_SMBUS_BYTE_DATA:
819 res = i2c_smbus_read_byte_data(bus_fd, i+j);
820 block[i+j] = res;
821 break;
822 case I2C_SMBUS_WORD_DATA:
823 res = i2c_smbus_read_word_data(bus_fd, i+j);
824 if (res < 0) {
825 block[i+j] = res;
826 block[i+j+1] = res;
827 } else {
828 block[i+j] = res & 0xff;
829 block[i+j+1] = res >> 8;
830 }
831 break;
832 case I2C_SMBUS_BYTE:
833 res = i2c_smbus_read_byte(bus_fd);
834 block[i+j] = res;
835 break;
836 default:
837 res = block[i+j];
838 }
839
840 if (mode == I2C_SMBUS_BLOCK_DATA &&
841 i+j >= blen) {
842 printf(" ");
843 } else if (res < 0) {
844 printf("XX ");
845 if (mode == I2C_SMBUS_WORD_DATA)
846 printf("XX ");
847 } else {
848 printf("%02x ", block[i+j]);
849 if (mode == I2C_SMBUS_WORD_DATA)
850 printf("%02x ", block[i+j+1]);
851 }
852
853 if (mode == I2C_SMBUS_WORD_DATA)
854 j++;
855 }
856 printf(" ");
857
858 for (j = 0; j < 16; j++) {
859 if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
860 break;
861 /* Skip unwanted registers */
862 if (i+j < first || i+j > last) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200863 bb_putchar(' ');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200864 continue;
865 }
866
867 res = block[i+j];
868 if (res < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200869 bb_putchar('X');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200870 } else if (res == 0x00 || res == 0xff) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200871 bb_putchar('.');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200872 } else if (res < 32 || res >= 127) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200873 bb_putchar('?');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200874 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200875 bb_putchar(res);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200876 }
877 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200878 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200879 }
880}
881
882static void dump_word_data(int bus_fd, unsigned first, unsigned last)
883{
884 int i, j, rv;
885
886 /* Word data. */
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200887 puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200888 for (i = 0; i < 256; i += 8) {
889 if (i/8 < first/8)
890 continue;
891 if (i/8 > last/8)
892 break;
893
894 printf("%02x: ", i);
895 for (j = 0; j < 8; j++) {
896 /* Skip unwanted registers. */
897 if (i+j < first || i+j > last) {
898 printf(" ");
899 continue;
900 }
901
902 rv = i2c_smbus_read_word_data(bus_fd, i+j);
903 if (rv < 0)
904 printf("XXXX ");
905 else
906 printf("%04x ", rv & 0xffff);
907 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200908 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200909 }
910}
911
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100912//usage:#define i2cdump_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200913//usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100914//usage:#define i2cdump_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200915//usage: "Examine I2C registers"
916//usage: "\n"
917//usage: "\n I2CBUS I2C bus number"
918//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100919//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200920//usage: "\n b Byte (default)"
921//usage: "\n w Word"
922//usage: "\n W Word on even register addresses"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100923//usage: "\n i I2C block"
924//usage: "\n s SMBus block"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200925//usage: "\n c Consecutive byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100926//usage: "\n Append p for SMBus PEC"
927//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200928//usage: "\n -f Force access"
929//usage: "\n -y Disable interactive mode"
930//usage: "\n -r Limit the number of registers being accessed"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100931int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
932int i2cdump_main(int argc UNUSED_PARAM, char **argv)
933{
934 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
935 opt_r = (1 << 2);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100936
937 int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200938 unsigned first = 0x00, last = 0xff, opts;
Bartosz Golaszewski59f81972016-06-23 17:19:50 +0200939 int block[I2CDUMP_NUM_REGS];
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100940 char *opt_r_str, *dash;
Denys Vlasenko2cf45912015-11-01 20:57:34 +0100941 int fd, res;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100942
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200943 opts = getopt32(argv, "^"
944 "fyr:"
945 "\0" "-2:?3" /* from 2 to 3 args */,
946 &opt_r_str
947 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100948 argv += optind;
949
950 bus_num = i2c_bus_lookup(argv[0]);
951 bus_addr = i2c_parse_bus_addr(argv[1]);
952
953 if (argv[2]) {
954 switch (argv[2][0]) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200955 case 'b': /* Already set. */ break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100956 case 'c': mode = I2C_SMBUS_BYTE; break;
957 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
958 case 'W':
959 mode = I2C_SMBUS_WORD_DATA;
960 even = 1;
961 break;
962 case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
963 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
964 default:
965 bb_error_msg_and_die("invalid mode");
966 }
967
968 if (argv[2][1] == 'p') {
969 if (argv[2][0] == 'W' || argv[2][0] == 'i') {
970 bb_error_msg_and_die(
971 "pec not supported for -W and -i");
972 } else {
973 pec = 1;
974 }
975 }
976 }
977
978 if (opts & opt_r) {
979 first = strtol(opt_r_str, &dash, 0);
980 if (dash == opt_r_str || *dash != '-' || first > 0xff)
981 bb_error_msg_and_die("invalid range");
982 last = xstrtou_range(++dash, 0, first, 0xff);
983
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200984 /* Range is not available for every mode. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100985 switch (mode) {
986 case I2C_SMBUS_BYTE:
987 case I2C_SMBUS_BYTE_DATA:
988 break;
989 case I2C_SMBUS_WORD_DATA:
990 if (!even || (!(first % 2) && last % 2))
991 break;
992 /* Fall through */
993 default:
994 bb_error_msg_and_die(
995 "range not compatible with selected mode");
996 }
997 }
998
999 fd = i2c_dev_open(bus_num);
1000 check_read_funcs(fd, mode, -1 /* data_addr */, pec);
1001 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
1002
1003 if (pec)
1004 i2c_set_pec(fd, 1);
1005
1006 if (!(opts & opt_y))
1007 confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
1008
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001009 /* All but word data. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001010 if (mode != I2C_SMBUS_WORD_DATA || even) {
Denys Vlasenko2cf45912015-11-01 20:57:34 +01001011 int blen = 0;
1012
Bartosz Golaszewski1cde5f72015-10-27 17:15:02 +01001013 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
1014 blen = read_block_data(fd, mode, block);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001015
1016 if (mode == I2C_SMBUS_BYTE) {
1017 res = i2c_smbus_write_byte(fd, first);
1018 if (res < 0)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001019 bb_perror_msg_and_die("write start address");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001020 }
1021
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001022 dump_data(fd, mode, first, last, block, blen);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001023 } else {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001024 dump_word_data(fd, first, last);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001025 }
1026
1027 return 0;
1028}
1029#endif /* ENABLE_I2CDUMP */
1030
1031#if ENABLE_I2CDETECT
1032enum adapter_type {
1033 ADT_DUMMY = 0,
1034 ADT_ISA,
1035 ADT_I2C,
1036 ADT_SMBUS,
1037};
1038
1039struct adap_desc {
1040 const char *funcs;
1041 const char *algo;
1042};
1043
1044static const struct adap_desc adap_descs[] = {
1045 { .funcs = "dummy",
1046 .algo = "Dummy bus", },
1047 { .funcs = "isa",
1048 .algo = "ISA bus", },
1049 { .funcs = "i2c",
1050 .algo = "I2C adapter", },
1051 { .funcs = "smbus",
1052 .algo = "SMBus adapter", },
1053};
1054
1055struct i2c_func
1056{
1057 long value;
1058 const char* name;
1059};
1060
1061static const struct i2c_func i2c_funcs_tab[] = {
1062 { .value = I2C_FUNC_I2C,
1063 .name = "I2C" },
1064 { .value = I2C_FUNC_SMBUS_QUICK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001065 .name = "SMBus quick command" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001066 { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001067 .name = "SMBus send byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001068 { .value = I2C_FUNC_SMBUS_READ_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001069 .name = "SMBus receive byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001070 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001071 .name = "SMBus write byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001072 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001073 .name = "SMBus read byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001074 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001075 .name = "SMBus write word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001076 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001077 .name = "SMBus read word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001078 { .value = I2C_FUNC_SMBUS_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001079 .name = "SMBus process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001080 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001081 .name = "SMBus block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001082 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001083 .name = "SMBus block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001084 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001085 .name = "SMBus block process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001086 { .value = I2C_FUNC_SMBUS_PEC,
1087 .name = "SMBus PEC" },
1088 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001089 .name = "I2C block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001090 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001091 .name = "I2C block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001092 { .value = 0, .name = NULL }
1093};
1094
1095static enum adapter_type i2cdetect_get_funcs(int bus)
1096{
1097 enum adapter_type ret;
1098 unsigned long funcs;
1099 int fd;
1100
1101 fd = i2c_dev_open(bus);
1102
1103 get_funcs_matrix(fd, &funcs);
1104 if (funcs & I2C_FUNC_I2C)
1105 ret = ADT_I2C;
1106 else if (funcs & (I2C_FUNC_SMBUS_BYTE |
1107 I2C_FUNC_SMBUS_BYTE_DATA |
1108 I2C_FUNC_SMBUS_WORD_DATA))
1109 ret = ADT_SMBUS;
1110 else
1111 ret = ADT_DUMMY;
1112
1113 close(fd);
1114
1115 return ret;
1116}
1117
1118static void NORETURN list_i2c_busses_and_exit(void)
1119{
1120 const char *const i2cdev_path = "/sys/class/i2c-dev";
1121
1122 char path[NAME_MAX], name[128];
1123 struct dirent *de, *subde;
1124 enum adapter_type adt;
1125 DIR *dir, *subdir;
1126 int rv, bus;
1127 char *pos;
1128 FILE *fp;
1129
1130 /*
1131 * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
1132 * but we won't bother since it's only useful on older kernels (before
1133 * 2.6.5). We expect sysfs to be present and mounted at /sys/.
1134 */
1135
1136 dir = xopendir(i2cdev_path);
1137 while ((de = readdir(dir))) {
1138 if (de->d_name[0] == '.')
1139 continue;
1140
1141 /* Simple version for ISA chips. */
1142 snprintf(path, NAME_MAX, "%s/%s/name",
1143 i2cdev_path, de->d_name);
1144 fp = fopen(path, "r");
1145 if (fp == NULL) {
1146 snprintf(path, NAME_MAX,
1147 "%s/%s/device/name",
1148 i2cdev_path, de->d_name);
1149 fp = fopen(path, "r");
1150 }
1151
1152 /* Non-ISA chips require the hard-way. */
1153 if (fp == NULL) {
1154 snprintf(path, NAME_MAX,
1155 "%s/%s/device/name",
1156 i2cdev_path, de->d_name);
1157 subdir = opendir(path);
1158 if (subdir == NULL)
1159 continue;
1160
1161 while ((subde = readdir(subdir))) {
1162 if (subde->d_name[0] == '.')
1163 continue;
1164
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001165 if (is_prefixed_with(subde->d_name, "i2c-")) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001166 snprintf(path, NAME_MAX,
1167 "%s/%s/device/%s/name",
1168 i2cdev_path, de->d_name,
1169 subde->d_name);
1170 fp = fopen(path, "r");
Bartosz Golaszewskid9089922015-06-05 10:27:32 +02001171 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001172 }
1173 }
1174 }
1175
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001176 if (fp != NULL) {
1177 /*
1178 * Get the rest of the info and display a line
1179 * for a single bus.
1180 */
1181 memset(name, 0, sizeof(name));
1182 pos = fgets(name, sizeof(name), fp);
1183 fclose(fp);
1184 if (pos == NULL)
1185 continue;
1186
1187 pos = strchr(name, '\n');
1188 if (pos != NULL)
1189 *pos = '\0';
1190
1191 rv = sscanf(de->d_name, "i2c-%d", &bus);
1192 if (rv != 1)
1193 continue;
1194
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001195 if (is_prefixed_with(name, "ISA"))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001196 adt = ADT_ISA;
1197 else
1198 adt = i2cdetect_get_funcs(bus);
1199
1200 printf(
1201 "i2c-%d\t%-10s\t%-32s\t%s\n",
1202 bus, adap_descs[adt].funcs,
1203 name, adap_descs[adt].algo);
1204 }
1205 }
1206
1207 exit(EXIT_SUCCESS);
1208}
1209
1210static void NORETURN no_support(const char *cmd)
1211{
1212 bb_error_msg_and_die("bus doesn't support %s", cmd);
1213}
1214
1215static void will_skip(const char *cmd)
1216{
1217 bb_error_msg(
1218 "warning: can't use %s command, "
1219 "will skip some addresses", cmd);
1220}
1221
1222//usage:#define i2cdetect_trivial_usage
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001223//usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001224//usage:#define i2cdetect_full_usage "\n\n"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001225//usage: "Detect I2C chips"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001226//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +02001227//usage: "\n -l List installed buses"
1228//usage: "\n -F BUS# List functionalities on this bus"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001229//usage: "\n -y Disable interactive mode"
1230//usage: "\n -a Force scanning of non-regular addresses"
1231//usage: "\n -q Use smbus quick write commands for probing (default)"
1232//usage: "\n -r Use smbus read byte commands for probing"
1233//usage: "\n FIRST and LAST limit probing range"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001234int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1235int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1236{
1237 const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
1238 opt_q = (1 << 2), opt_r = (1 << 3),
1239 opt_F = (1 << 4), opt_l = (1 << 5);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001240
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001241 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001242 unsigned first = 0x03, last = 0x77, opts;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001243 unsigned long funcs;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001244
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001245 opts = getopt32(argv, "^"
1246 "yaqrFl"
1247 "\0"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001248 "q--r:r--q:"/*mutually exclusive*/
1249 "?3"/*up to 3 args*/
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001250 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001251 argv += optind;
1252
1253 if (opts & opt_l)
1254 list_i2c_busses_and_exit();
1255
Bartosz Golaszewskib2cca322015-05-11 17:22:10 +02001256 if (!argv[0])
1257 bb_show_usage();
1258
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001259 bus_num = i2c_bus_lookup(argv[0]);
1260 fd = i2c_dev_open(bus_num);
1261 get_funcs_matrix(fd, &funcs);
1262
1263 if (opts & opt_F) {
1264 /* Only list the functionalities. */
1265 printf("Functionalities implemented by bus #%d\n", bus_num);
1266 for (i = 0; i2c_funcs_tab[i].value; i++) {
1267 printf("%-32s %s\n", i2c_funcs_tab[i].name,
1268 funcs & i2c_funcs_tab[i].value ? "yes" : "no");
1269 }
1270
1271 return EXIT_SUCCESS;
1272 }
1273
1274 if (opts & opt_r)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001275 mode = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001276 else if (opts & opt_q)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001277 mode = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001278
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001279 if (opts & opt_a) {
1280 first = 0x00;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001281 last = 0x7f;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001282 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001283
1284 /* Read address range. */
1285 if (argv[1]) {
1286 first = xstrtou_range(argv[1], 16, first, last);
1287 if (argv[2])
1288 last = xstrtou_range(argv[2], 16, first, last);
1289 }
1290
1291 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1292 no_support("detection commands");
1293 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001294 if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001295 no_support("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001296 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001297 if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001298 no_support("SMBus receive byte");
Bartosz Golaszewski22044722015-06-05 10:27:30 +02001299 }
1300
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001301 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001302 if (!(funcs & I2C_FUNC_SMBUS_QUICK))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001303 will_skip("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001304 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001305 will_skip("SMBus receive byte");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001306 }
1307
1308 if (!(opts & opt_y))
1309 confirm_action(-1, -1, -1, 0);
1310
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001311 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001312 for (i = 0; i < 128; i += 16) {
1313 printf("%02x: ", i);
Bartosz Golaszewskifc8eb052015-10-27 17:15:01 +01001314 for (j = 0; j < 16; j++) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001315 fflush_all();
1316
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001317 cmd = mode;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001318 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001319 if ((i+j >= 0x30 && i+j <= 0x37) ||
1320 (i+j >= 0x50 && i+j <= 0x5F))
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001321 cmd = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001322 else
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001323 cmd = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001324 }
1325
1326 /* Skip unwanted addresses. */
1327 if (i+j < first
1328 || i+j > last
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001329 || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1330 || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001331 {
1332 printf(" ");
1333 continue;
1334 }
1335
Bartosz Golaszewski31474272015-06-05 10:27:28 +02001336 status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
1337 if (status < 0) {
1338 if (errno == EBUSY) {
1339 printf("UU ");
1340 continue;
1341 }
1342
1343 bb_perror_msg_and_die(
1344 "can't set address to 0x%02x", i + j);
1345 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001346
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001347 switch (cmd) {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001348 case I2CDETECT_MODE_READ:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001349 /*
1350 * This is known to lock SMBus on various
1351 * write-only chips (mainly clock chips).
1352 */
1353 status = i2c_smbus_read_byte(fd);
1354 break;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001355 default: /* I2CDETECT_MODE_QUICK: */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001356 /*
1357 * This is known to corrupt the Atmel
1358 * AT24RF08 EEPROM.
1359 */
1360 status = i2c_smbus_write_quick(fd,
1361 I2C_SMBUS_WRITE);
1362 break;
1363 }
1364
1365 if (status < 0)
1366 printf("-- ");
1367 else
1368 printf("%02x ", i+j);
1369 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001370 bb_putchar('\n');
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001371 }
1372
1373 return 0;
1374}
1375#endif /* ENABLE_I2CDETECT */