blob: 82f9842bd1beb83c9ca29a8367696aad72abafc8 [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] ");
424 fflush_all();
425 if (!bb_ask_confirmation())
426 bb_error_msg_and_die("aborting");
427}
428
429/*
430 * Return only if user confirms the action, abort otherwise.
431 *
432 * The messages displayed here are much less elaborate than their i2c-tools
433 * counterparts - this is done for size reduction.
434 */
435static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
436{
437 bb_error_msg("WARNING! This program can confuse your I2C bus");
438
439 /* Don't let the user break his/her EEPROMs */
440 if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
441 bb_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
442 "devices may result in data loss, aborting");
443 }
444
445 if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
446 bb_error_msg("WARNING! May interpret a write byte command "
447 "with PEC as a write byte data command");
448
449 if (pec)
450 bb_error_msg("PEC checking enabled");
451
452 confirm_or_abort();
453}
454
455#if ENABLE_I2CGET
456//usage:#define i2cget_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200457//usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100458//usage:#define i2cget_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200459//usage: "Read from I2C/SMBus chip registers"
460//usage: "\n"
461//usage: "\n I2CBUS I2C bus number"
462//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100463//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200464//usage: "\n b Read byte data (default)"
465//usage: "\n w Read word data"
466//usage: "\n c Write byte/read byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100467//usage: "\n Append p for SMBus PEC"
468//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200469//usage: "\n -f Force access"
470//usage: "\n -y Disable interactive mode"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100471int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
472int i2cget_main(int argc UNUSED_PARAM, char **argv)
473{
474 const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100475
476 int bus_num, bus_addr, data_addr = -1, status;
477 int mode = I2C_SMBUS_BYTE, pec = 0, fd;
478 unsigned opts;
479
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200480 opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100481 argv += optind;
482
483 bus_num = i2c_bus_lookup(argv[0]);
484 bus_addr = i2c_parse_bus_addr(argv[1]);
485
486 if (argv[2]) {
487 data_addr = i2c_parse_data_addr(argv[2]);
488 mode = I2C_SMBUS_BYTE_DATA;
489 if (argv[3]) {
490 switch (argv[3][0]) {
491 case 'b': /* Already set */ break;
492 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
493 case 'c': mode = I2C_SMBUS_BYTE; break;
494 default:
495 bb_error_msg("invalid mode");
496 bb_show_usage();
497 }
498 pec = argv[3][1] == 'p';
499 }
500 }
501
502 fd = i2c_dev_open(bus_num);
503 check_read_funcs(fd, mode, data_addr, pec);
504 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
505
506 if (!(opts & opt_y))
507 confirm_action(bus_addr, mode, data_addr, pec);
508
509 if (pec)
510 i2c_set_pec(fd, 1);
511
512 switch (mode) {
513 case I2C_SMBUS_BYTE:
514 if (data_addr >= 0) {
515 status = i2c_smbus_write_byte(fd, data_addr);
516 if (status < 0)
517 bb_error_msg("warning - write failed");
518 }
519 status = i2c_smbus_read_byte(fd);
520 break;
521 case I2C_SMBUS_WORD_DATA:
522 status = i2c_smbus_read_word_data(fd, data_addr);
523 break;
524 default: /* I2C_SMBUS_BYTE_DATA */
525 status = i2c_smbus_read_byte_data(fd, data_addr);
526 }
527 close(fd);
528
529 if (status < 0)
530 bb_perror_msg_and_die("read failed");
531
532 printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
533
534 return 0;
535}
536#endif /* ENABLE_I2CGET */
537
538#if ENABLE_I2CSET
539//usage:#define i2cset_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200540//usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100541//usage:#define i2cset_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200542//usage: "Set I2C registers"
543//usage: "\n"
544//usage: "\n I2CBUS I2C bus number"
545//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100546//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200547//usage: "\n c Byte, no value"
548//usage: "\n b Byte data (default)"
549//usage: "\n w Word data"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100550//usage: "\n i I2C block data"
551//usage: "\n s SMBus block data"
552//usage: "\n Append p for SMBus PEC"
553//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200554//usage: "\n -f Force access"
555//usage: "\n -y Disable interactive mode"
556//usage: "\n -r Read back and compare the result"
557//usage: "\n -m MASK Mask specifying which bits to write"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100558int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
559int i2cset_main(int argc, char **argv)
560{
561 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
562 opt_m = (1 << 2), opt_r = (1 << 3);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100563
564 int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200565 int val, blen, mask, fd, status;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100566 unsigned char block[I2C_SMBUS_BLOCK_MAX];
567 char *opt_m_arg = NULL;
568 unsigned opts;
569
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200570 opts = getopt32(argv, "^"
571 "fym:r"
572 "\0" "-3", /* minimum 3 args */
573 &opt_m_arg
574 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100575 argv += optind;
576 argc -= optind;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200577 argc--; /* now argv[argc] is last arg */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100578
579 bus_num = i2c_bus_lookup(argv[0]);
580 bus_addr = i2c_parse_bus_addr(argv[1]);
581 data_addr = i2c_parse_data_addr(argv[2]);
582
583 if (argv[3]) {
584 if (!argv[4] && argv[3][0] != 'c') {
585 mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
586 } else {
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200587 switch (argv[argc][0]) {
588 case 'c': /* Already set */
589 break;
590 case 'b': mode = I2C_SMBUS_BYTE_DATA;
591 break;
592 case 'w': mode = I2C_SMBUS_WORD_DATA;
593 break;
594 case 's': mode = I2C_SMBUS_BLOCK_DATA;
595 break;
596 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
597 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100598 default:
599 bb_error_msg("invalid mode");
600 bb_show_usage();
601 }
602
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200603 pec = (argv[argc][1] == 'p');
604 if (mode == I2C_SMBUS_BLOCK_DATA
605 || mode == I2C_SMBUS_I2C_BLOCK_DATA
606 ) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100607 if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
608 bb_error_msg_and_die(
609 "PEC not supported for I2C "
610 "block writes");
611 if (opts & opt_m)
612 bb_error_msg_and_die(
613 "mask not supported for block "
614 "writes");
615 }
616 }
617 }
618
619 /* Prepare the value(s) to be written according to current mode. */
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200620 mask = 0;
621 blen = 0;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100622 switch (mode) {
623 case I2C_SMBUS_BYTE_DATA:
624 val = xstrtou_range(argv[3], 0, 0, 0xff);
625 break;
626 case I2C_SMBUS_WORD_DATA:
627 val = xstrtou_range(argv[3], 0, 0, 0xffff);
628 break;
629 case I2C_SMBUS_BLOCK_DATA:
630 case I2C_SMBUS_I2C_BLOCK_DATA:
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200631 for (blen = 3; blen < argc; blen++)
632 block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
633 blen -= 3;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100634 val = -1;
635 break;
636 default:
637 val = -1;
638 break;
639 }
640
641 if (opts & opt_m) {
642 mask = xstrtou_range(opt_m_arg, 0, 0,
643 (mode == I2C_SMBUS_BYTE ||
644 mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
645 }
646
647 fd = i2c_dev_open(bus_num);
648 check_write_funcs(fd, mode, pec);
649 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
650
651 if (!(opts & opt_y))
652 confirm_action(bus_addr, mode, data_addr, pec);
653
654 /*
655 * If we're using mask - read the current value here and adjust the
656 * value to be written.
657 */
658 if (opts & opt_m) {
659 int tmpval;
660
661 switch (mode) {
662 case I2C_SMBUS_BYTE:
663 tmpval = i2c_smbus_read_byte(fd);
664 break;
665 case I2C_SMBUS_WORD_DATA:
666 tmpval = i2c_smbus_read_word_data(fd, data_addr);
667 break;
668 default:
669 tmpval = i2c_smbus_read_byte_data(fd, data_addr);
670 }
671
672 if (tmpval < 0)
673 bb_perror_msg_and_die("can't read old value");
674
675 val = (val & mask) | (tmpval & ~mask);
676
677 if (!(opts & opt_y)) {
678 bb_error_msg("old value 0x%0*x, write mask "
679 "0x%0*x, will write 0x%0*x to register "
680 "0x%02x",
681 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
682 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
683 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
684 data_addr);
685 confirm_or_abort();
686 }
687 }
688
689 if (pec)
690 i2c_set_pec(fd, 1);
691
692 switch (mode) {
693 case I2C_SMBUS_BYTE:
694 status = i2c_smbus_write_byte(fd, data_addr);
695 break;
696 case I2C_SMBUS_WORD_DATA:
697 status = i2c_smbus_write_word_data(fd, data_addr, val);
698 break;
699 case I2C_SMBUS_BLOCK_DATA:
700 status = i2c_smbus_write_block_data(fd, data_addr,
701 blen, block);
702 break;
703 case I2C_SMBUS_I2C_BLOCK_DATA:
704 status = i2c_smbus_write_i2c_block_data(fd, data_addr,
705 blen, block);
706 break;
707 default: /* I2C_SMBUS_BYTE_DATA */
708 status = i2c_smbus_write_byte_data(fd, data_addr, val);
709 break;
710 }
711 if (status < 0)
712 bb_perror_msg_and_die("write failed");
713
714 if (pec)
715 i2c_set_pec(fd, 0); /* Clear PEC. */
716
717 /* No readback required - we're done. */
718 if (!(opts & opt_r))
719 return 0;
720
721 switch (mode) {
722 case I2C_SMBUS_BYTE:
723 status = i2c_smbus_read_byte(fd);
724 val = data_addr;
725 break;
726 case I2C_SMBUS_WORD_DATA:
727 status = i2c_smbus_read_word_data(fd, data_addr);
728 break;
729 default: /* I2C_SMBUS_BYTE_DATA */
730 status = i2c_smbus_read_byte_data(fd, data_addr);
731 }
732
733 if (status < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200734 puts("Warning - readback failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100735 } else
736 if (status != val) {
737 printf("Warning - data mismatch - wrote "
738 "0x%0*x, read back 0x%0*x\n",
739 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
740 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
741 } else {
742 printf("Value 0x%0*x written, readback matched\n",
743 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
744 }
745
746 return 0;
747}
748#endif /* ENABLE_I2CSET */
749
750#if ENABLE_I2CDUMP
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200751static int read_block_data(int buf_fd, int mode, int *block)
752{
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200753 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200754 int res, blen = 0, tmp, i;
755
Bartosz Golaszewski1fe75b82015-10-27 17:15:03 +0100756 if (mode == I2C_SMBUS_BLOCK_DATA) {
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100757 blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
758 if (blen <= 0)
759 goto fail;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200760 } else {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200761 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200762 tmp = i2c_smbus_read_i2c_block_data(
763 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
764 cblock + res);
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100765 if (tmp <= 0) {
766 blen = tmp;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100767 goto fail;
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100768 }
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200769 }
770
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200771 if (res >= I2CDUMP_NUM_REGS)
772 res = I2CDUMP_NUM_REGS;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200773
774 for (i = 0; i < res; i++)
775 block[i] = cblock[i];
776
777 if (mode != I2C_SMBUS_BLOCK_DATA)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200778 for (i = res; i < I2CDUMP_NUM_REGS; i++)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200779 block[i] = -1;
780 }
781
782 return blen;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100783
784 fail:
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100785 bb_error_msg_and_die("block read failed: %d", blen);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200786}
787
788/* Dump all but word data. */
789static void dump_data(int bus_fd, int mode, unsigned first,
790 unsigned last, int *block, int blen)
791{
792 int i, j, res;
793
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200794 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
795 " 0123456789abcdef");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200796
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200797 for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200798 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
799 break;
800 if (i/16 < first/16)
801 continue;
802 if (i/16 > last/16)
803 break;
804
805 printf("%02x: ", i);
806 for (j = 0; j < 16; j++) {
807 fflush_all();
808 /* Skip unwanted registers */
809 if (i+j < first || i+j > last) {
810 printf(" ");
811 if (mode == I2C_SMBUS_WORD_DATA) {
812 printf(" ");
813 j++;
814 }
815 continue;
816 }
817
818 switch (mode) {
819 case I2C_SMBUS_BYTE_DATA:
820 res = i2c_smbus_read_byte_data(bus_fd, i+j);
821 block[i+j] = res;
822 break;
823 case I2C_SMBUS_WORD_DATA:
824 res = i2c_smbus_read_word_data(bus_fd, i+j);
825 if (res < 0) {
826 block[i+j] = res;
827 block[i+j+1] = res;
828 } else {
829 block[i+j] = res & 0xff;
830 block[i+j+1] = res >> 8;
831 }
832 break;
833 case I2C_SMBUS_BYTE:
834 res = i2c_smbus_read_byte(bus_fd);
835 block[i+j] = res;
836 break;
837 default:
838 res = block[i+j];
839 }
840
841 if (mode == I2C_SMBUS_BLOCK_DATA &&
842 i+j >= blen) {
843 printf(" ");
844 } else if (res < 0) {
845 printf("XX ");
846 if (mode == I2C_SMBUS_WORD_DATA)
847 printf("XX ");
848 } else {
849 printf("%02x ", block[i+j]);
850 if (mode == I2C_SMBUS_WORD_DATA)
851 printf("%02x ", block[i+j+1]);
852 }
853
854 if (mode == I2C_SMBUS_WORD_DATA)
855 j++;
856 }
857 printf(" ");
858
859 for (j = 0; j < 16; j++) {
860 if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
861 break;
862 /* Skip unwanted registers */
863 if (i+j < first || i+j > last) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200864 bb_putchar(' ');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200865 continue;
866 }
867
868 res = block[i+j];
869 if (res < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200870 bb_putchar('X');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200871 } else if (res == 0x00 || res == 0xff) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200872 bb_putchar('.');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200873 } else if (res < 32 || res >= 127) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200874 bb_putchar('?');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200875 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200876 bb_putchar(res);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200877 }
878 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200879 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200880 }
881}
882
883static void dump_word_data(int bus_fd, unsigned first, unsigned last)
884{
885 int i, j, rv;
886
887 /* Word data. */
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200888 puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200889 for (i = 0; i < 256; i += 8) {
890 if (i/8 < first/8)
891 continue;
892 if (i/8 > last/8)
893 break;
894
895 printf("%02x: ", i);
896 for (j = 0; j < 8; j++) {
897 /* Skip unwanted registers. */
898 if (i+j < first || i+j > last) {
899 printf(" ");
900 continue;
901 }
902
903 rv = i2c_smbus_read_word_data(bus_fd, i+j);
904 if (rv < 0)
905 printf("XXXX ");
906 else
907 printf("%04x ", rv & 0xffff);
908 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200909 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200910 }
911}
912
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100913//usage:#define i2cdump_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200914//usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100915//usage:#define i2cdump_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200916//usage: "Examine I2C registers"
917//usage: "\n"
918//usage: "\n I2CBUS I2C bus number"
919//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100920//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200921//usage: "\n b Byte (default)"
922//usage: "\n w Word"
923//usage: "\n W Word on even register addresses"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100924//usage: "\n i I2C block"
925//usage: "\n s SMBus block"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200926//usage: "\n c Consecutive byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100927//usage: "\n Append p for SMBus PEC"
928//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200929//usage: "\n -f Force access"
930//usage: "\n -y Disable interactive mode"
931//usage: "\n -r Limit the number of registers being accessed"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100932int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
933int i2cdump_main(int argc UNUSED_PARAM, char **argv)
934{
935 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
936 opt_r = (1 << 2);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100937
938 int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200939 unsigned first = 0x00, last = 0xff, opts;
Bartosz Golaszewski59f81972016-06-23 17:19:50 +0200940 int block[I2CDUMP_NUM_REGS];
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100941 char *opt_r_str, *dash;
Denys Vlasenko2cf45912015-11-01 20:57:34 +0100942 int fd, res;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100943
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200944 opts = getopt32(argv, "^"
945 "fyr:"
946 "\0" "-2:?3" /* from 2 to 3 args */,
947 &opt_r_str
948 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100949 argv += optind;
950
951 bus_num = i2c_bus_lookup(argv[0]);
952 bus_addr = i2c_parse_bus_addr(argv[1]);
953
954 if (argv[2]) {
955 switch (argv[2][0]) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200956 case 'b': /* Already set. */ break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100957 case 'c': mode = I2C_SMBUS_BYTE; break;
958 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
959 case 'W':
960 mode = I2C_SMBUS_WORD_DATA;
961 even = 1;
962 break;
963 case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
964 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
965 default:
966 bb_error_msg_and_die("invalid mode");
967 }
968
969 if (argv[2][1] == 'p') {
970 if (argv[2][0] == 'W' || argv[2][0] == 'i') {
971 bb_error_msg_and_die(
972 "pec not supported for -W and -i");
973 } else {
974 pec = 1;
975 }
976 }
977 }
978
979 if (opts & opt_r) {
980 first = strtol(opt_r_str, &dash, 0);
981 if (dash == opt_r_str || *dash != '-' || first > 0xff)
982 bb_error_msg_and_die("invalid range");
983 last = xstrtou_range(++dash, 0, first, 0xff);
984
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200985 /* Range is not available for every mode. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100986 switch (mode) {
987 case I2C_SMBUS_BYTE:
988 case I2C_SMBUS_BYTE_DATA:
989 break;
990 case I2C_SMBUS_WORD_DATA:
991 if (!even || (!(first % 2) && last % 2))
992 break;
993 /* Fall through */
994 default:
995 bb_error_msg_and_die(
996 "range not compatible with selected mode");
997 }
998 }
999
1000 fd = i2c_dev_open(bus_num);
1001 check_read_funcs(fd, mode, -1 /* data_addr */, pec);
1002 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
1003
1004 if (pec)
1005 i2c_set_pec(fd, 1);
1006
1007 if (!(opts & opt_y))
1008 confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
1009
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001010 /* All but word data. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001011 if (mode != I2C_SMBUS_WORD_DATA || even) {
Denys Vlasenko2cf45912015-11-01 20:57:34 +01001012 int blen = 0;
1013
Bartosz Golaszewski1cde5f72015-10-27 17:15:02 +01001014 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
1015 blen = read_block_data(fd, mode, block);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001016
1017 if (mode == I2C_SMBUS_BYTE) {
1018 res = i2c_smbus_write_byte(fd, first);
1019 if (res < 0)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001020 bb_perror_msg_and_die("write start address");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001021 }
1022
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001023 dump_data(fd, mode, first, last, block, blen);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001024 } else {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001025 dump_word_data(fd, first, last);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001026 }
1027
1028 return 0;
1029}
1030#endif /* ENABLE_I2CDUMP */
1031
1032#if ENABLE_I2CDETECT
1033enum adapter_type {
1034 ADT_DUMMY = 0,
1035 ADT_ISA,
1036 ADT_I2C,
1037 ADT_SMBUS,
1038};
1039
1040struct adap_desc {
1041 const char *funcs;
1042 const char *algo;
1043};
1044
1045static const struct adap_desc adap_descs[] = {
1046 { .funcs = "dummy",
1047 .algo = "Dummy bus", },
1048 { .funcs = "isa",
1049 .algo = "ISA bus", },
1050 { .funcs = "i2c",
1051 .algo = "I2C adapter", },
1052 { .funcs = "smbus",
1053 .algo = "SMBus adapter", },
1054};
1055
1056struct i2c_func
1057{
1058 long value;
1059 const char* name;
1060};
1061
1062static const struct i2c_func i2c_funcs_tab[] = {
1063 { .value = I2C_FUNC_I2C,
1064 .name = "I2C" },
1065 { .value = I2C_FUNC_SMBUS_QUICK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001066 .name = "SMBus quick command" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001067 { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001068 .name = "SMBus send byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001069 { .value = I2C_FUNC_SMBUS_READ_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001070 .name = "SMBus receive byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001071 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001072 .name = "SMBus write byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001073 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001074 .name = "SMBus read byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001075 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001076 .name = "SMBus write word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001077 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001078 .name = "SMBus read word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001079 { .value = I2C_FUNC_SMBUS_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001080 .name = "SMBus process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001081 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001082 .name = "SMBus block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001083 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001084 .name = "SMBus block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001085 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001086 .name = "SMBus block process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001087 { .value = I2C_FUNC_SMBUS_PEC,
1088 .name = "SMBus PEC" },
1089 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001090 .name = "I2C block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001091 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001092 .name = "I2C block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001093 { .value = 0, .name = NULL }
1094};
1095
1096static enum adapter_type i2cdetect_get_funcs(int bus)
1097{
1098 enum adapter_type ret;
1099 unsigned long funcs;
1100 int fd;
1101
1102 fd = i2c_dev_open(bus);
1103
1104 get_funcs_matrix(fd, &funcs);
1105 if (funcs & I2C_FUNC_I2C)
1106 ret = ADT_I2C;
1107 else if (funcs & (I2C_FUNC_SMBUS_BYTE |
1108 I2C_FUNC_SMBUS_BYTE_DATA |
1109 I2C_FUNC_SMBUS_WORD_DATA))
1110 ret = ADT_SMBUS;
1111 else
1112 ret = ADT_DUMMY;
1113
1114 close(fd);
1115
1116 return ret;
1117}
1118
1119static void NORETURN list_i2c_busses_and_exit(void)
1120{
1121 const char *const i2cdev_path = "/sys/class/i2c-dev";
1122
1123 char path[NAME_MAX], name[128];
1124 struct dirent *de, *subde;
1125 enum adapter_type adt;
1126 DIR *dir, *subdir;
1127 int rv, bus;
1128 char *pos;
1129 FILE *fp;
1130
1131 /*
1132 * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
1133 * but we won't bother since it's only useful on older kernels (before
1134 * 2.6.5). We expect sysfs to be present and mounted at /sys/.
1135 */
1136
1137 dir = xopendir(i2cdev_path);
1138 while ((de = readdir(dir))) {
1139 if (de->d_name[0] == '.')
1140 continue;
1141
1142 /* Simple version for ISA chips. */
1143 snprintf(path, NAME_MAX, "%s/%s/name",
1144 i2cdev_path, de->d_name);
1145 fp = fopen(path, "r");
1146 if (fp == NULL) {
1147 snprintf(path, NAME_MAX,
1148 "%s/%s/device/name",
1149 i2cdev_path, de->d_name);
1150 fp = fopen(path, "r");
1151 }
1152
1153 /* Non-ISA chips require the hard-way. */
1154 if (fp == NULL) {
1155 snprintf(path, NAME_MAX,
1156 "%s/%s/device/name",
1157 i2cdev_path, de->d_name);
1158 subdir = opendir(path);
1159 if (subdir == NULL)
1160 continue;
1161
1162 while ((subde = readdir(subdir))) {
1163 if (subde->d_name[0] == '.')
1164 continue;
1165
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001166 if (is_prefixed_with(subde->d_name, "i2c-")) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001167 snprintf(path, NAME_MAX,
1168 "%s/%s/device/%s/name",
1169 i2cdev_path, de->d_name,
1170 subde->d_name);
1171 fp = fopen(path, "r");
Bartosz Golaszewskid9089922015-06-05 10:27:32 +02001172 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001173 }
1174 }
1175 }
1176
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001177 if (fp != NULL) {
1178 /*
1179 * Get the rest of the info and display a line
1180 * for a single bus.
1181 */
1182 memset(name, 0, sizeof(name));
1183 pos = fgets(name, sizeof(name), fp);
1184 fclose(fp);
1185 if (pos == NULL)
1186 continue;
1187
1188 pos = strchr(name, '\n');
1189 if (pos != NULL)
1190 *pos = '\0';
1191
1192 rv = sscanf(de->d_name, "i2c-%d", &bus);
1193 if (rv != 1)
1194 continue;
1195
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001196 if (is_prefixed_with(name, "ISA"))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001197 adt = ADT_ISA;
1198 else
1199 adt = i2cdetect_get_funcs(bus);
1200
1201 printf(
1202 "i2c-%d\t%-10s\t%-32s\t%s\n",
1203 bus, adap_descs[adt].funcs,
1204 name, adap_descs[adt].algo);
1205 }
1206 }
1207
1208 exit(EXIT_SUCCESS);
1209}
1210
1211static void NORETURN no_support(const char *cmd)
1212{
1213 bb_error_msg_and_die("bus doesn't support %s", cmd);
1214}
1215
1216static void will_skip(const char *cmd)
1217{
1218 bb_error_msg(
1219 "warning: can't use %s command, "
1220 "will skip some addresses", cmd);
1221}
1222
1223//usage:#define i2cdetect_trivial_usage
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001224//usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001225//usage:#define i2cdetect_full_usage "\n\n"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001226//usage: "Detect I2C chips"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001227//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +02001228//usage: "\n -l List installed buses"
1229//usage: "\n -F BUS# List functionalities on this bus"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001230//usage: "\n -y Disable interactive mode"
1231//usage: "\n -a Force scanning of non-regular addresses"
1232//usage: "\n -q Use smbus quick write commands for probing (default)"
1233//usage: "\n -r Use smbus read byte commands for probing"
1234//usage: "\n FIRST and LAST limit probing range"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001235int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1236int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1237{
1238 const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
1239 opt_q = (1 << 2), opt_r = (1 << 3),
1240 opt_F = (1 << 4), opt_l = (1 << 5);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001241
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001242 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001243 unsigned first = 0x03, last = 0x77, opts;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001244 unsigned long funcs;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001245
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001246 opts = getopt32(argv, "^"
1247 "yaqrFl"
1248 "\0"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001249 "q--r:r--q:"/*mutually exclusive*/
1250 "?3"/*up to 3 args*/
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001251 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001252 argv += optind;
1253
1254 if (opts & opt_l)
1255 list_i2c_busses_and_exit();
1256
Bartosz Golaszewskib2cca322015-05-11 17:22:10 +02001257 if (!argv[0])
1258 bb_show_usage();
1259
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001260 bus_num = i2c_bus_lookup(argv[0]);
1261 fd = i2c_dev_open(bus_num);
1262 get_funcs_matrix(fd, &funcs);
1263
1264 if (opts & opt_F) {
1265 /* Only list the functionalities. */
1266 printf("Functionalities implemented by bus #%d\n", bus_num);
1267 for (i = 0; i2c_funcs_tab[i].value; i++) {
1268 printf("%-32s %s\n", i2c_funcs_tab[i].name,
1269 funcs & i2c_funcs_tab[i].value ? "yes" : "no");
1270 }
1271
1272 return EXIT_SUCCESS;
1273 }
1274
1275 if (opts & opt_r)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001276 mode = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001277 else if (opts & opt_q)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001278 mode = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001279
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001280 if (opts & opt_a) {
1281 first = 0x00;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001282 last = 0x7f;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001283 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001284
1285 /* Read address range. */
1286 if (argv[1]) {
1287 first = xstrtou_range(argv[1], 16, first, last);
1288 if (argv[2])
1289 last = xstrtou_range(argv[2], 16, first, last);
1290 }
1291
1292 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1293 no_support("detection commands");
1294 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001295 if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001296 no_support("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001297 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001298 if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001299 no_support("SMBus receive byte");
Bartosz Golaszewski22044722015-06-05 10:27:30 +02001300 }
1301
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001302 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001303 if (!(funcs & I2C_FUNC_SMBUS_QUICK))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001304 will_skip("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001305 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001306 will_skip("SMBus receive byte");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001307 }
1308
1309 if (!(opts & opt_y))
1310 confirm_action(-1, -1, -1, 0);
1311
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001312 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001313 for (i = 0; i < 128; i += 16) {
1314 printf("%02x: ", i);
Bartosz Golaszewskifc8eb052015-10-27 17:15:01 +01001315 for (j = 0; j < 16; j++) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001316 fflush_all();
1317
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001318 cmd = mode;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001319 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001320 if ((i+j >= 0x30 && i+j <= 0x37) ||
1321 (i+j >= 0x50 && i+j <= 0x5F))
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001322 cmd = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001323 else
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001324 cmd = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001325 }
1326
1327 /* Skip unwanted addresses. */
1328 if (i+j < first
1329 || i+j > last
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001330 || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1331 || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001332 {
1333 printf(" ");
1334 continue;
1335 }
1336
Bartosz Golaszewski31474272015-06-05 10:27:28 +02001337 status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
1338 if (status < 0) {
1339 if (errno == EBUSY) {
1340 printf("UU ");
1341 continue;
1342 }
1343
1344 bb_perror_msg_and_die(
1345 "can't set address to 0x%02x", i + j);
1346 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001347
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001348 switch (cmd) {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001349 case I2CDETECT_MODE_READ:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001350 /*
1351 * This is known to lock SMBus on various
1352 * write-only chips (mainly clock chips).
1353 */
1354 status = i2c_smbus_read_byte(fd);
1355 break;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001356 default: /* I2CDETECT_MODE_QUICK: */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001357 /*
1358 * This is known to corrupt the Atmel
1359 * AT24RF08 EEPROM.
1360 */
1361 status = i2c_smbus_write_quick(fd,
1362 I2C_SMBUS_WRITE);
1363 break;
1364 }
1365
1366 if (status < 0)
1367 printf("-- ");
1368 else
1369 printf("%02x ", i+j);
1370 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001371 bb_putchar('\n');
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001372 }
1373
1374 return 0;
1375}
1376#endif /* ENABLE_I2CDETECT */