blob: da26f5e191aacd99aa588365dd7d197b44255c44 [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 Vlasenkob097a842018-12-28 03:20:17 +010012//config: bool "i2cget (5.5 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010013//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010014//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020015//config: Read from I2C/SMBus chip registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010016//config:
17//config:config I2CSET
Denys Vlasenkob097a842018-12-28 03:20:17 +010018//config: bool "i2cset (6.7 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010019//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010020//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020021//config: Set I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010022//config:
23//config:config I2CDUMP
Denys Vlasenkob097a842018-12-28 03:20:17 +010024//config: bool "i2cdump (7.1 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010025//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010026//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020027//config: Examine I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010028//config:
29//config:config I2CDETECT
Denys Vlasenkob097a842018-12-28 03:20:17 +010030//config: bool "i2cdetect (7.1 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010031//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010032//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020033//config: Detect I2C chips.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010034//config:
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010035//config:config I2CTRANSFER
36//config: bool "i2ctransfer (4.0 kb)"
37//config: default y
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010038//config: help
39//config: Send user-defined I2C messages in one transfer.
40//config:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010041
42//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
43//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
44//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
45//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010046//applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP))
Denys Vlasenko1a1203f2017-08-07 16:47:34 +020047/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010048
49//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
50//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
51//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
52//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010053//kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010054
55/*
56 * Unsupported stuff:
57 *
58 * - upstream i2c-tools can also look-up i2c busses by name, we only accept
59 * numbers,
60 * - bank and bankreg parameters for i2cdump are not supported because of
61 * their limited usefulness (see i2cdump manual entry for more info),
62 * - i2cdetect doesn't look for bus info in /proc as it does in upstream, but
63 * it shouldn't be a problem in modern kernels.
64 */
65
66#include "libbb.h"
67
Bartosz Golaszewskid9892fa2015-09-04 10:35:22 +020068#include <linux/i2c.h>
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010069
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020070#define I2CDUMP_NUM_REGS 256
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010071
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020072#define I2CDETECT_MODE_AUTO 0
73#define I2CDETECT_MODE_QUICK 1
74#define I2CDETECT_MODE_READ 2
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010075
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020076/* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi
77 * and defines symbols already defined by linux/i2c.h.
78 * Also, it defines a bunch of static inlines which we would rather NOT
79 * inline. What a mess.
80 * We need only these definitions from linux/i2c-dev.h:
81 */
82#define I2C_SLAVE 0x0703
83#define I2C_SLAVE_FORCE 0x0706
84#define I2C_FUNCS 0x0705
85#define I2C_PEC 0x0708
86#define I2C_SMBUS 0x0720
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010087#define I2C_RDWR 0x0707
88#define I2C_RDWR_IOCTL_MAX_MSGS 42
89#define I2C_RDWR_IOCTL_MAX_MSGS_STR "42"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020090struct i2c_smbus_ioctl_data {
91 __u8 read_write;
92 __u8 command;
93 __u32 size;
94 union i2c_smbus_data *data;
95};
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010096struct i2c_rdwr_ioctl_data {
97 struct i2c_msg *msgs; /* pointers to i2c_msgs */
98 __u32 nmsgs; /* number of i2c_msgs */
99};
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +0200100/* end linux/i2c-dev.h */
101
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100102/*
103 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
104 */
105static ALWAYS_INLINE void *itoptr(int i)
106{
107 return (void*)(intptr_t)i;
108}
109
110static int32_t i2c_smbus_access(int fd, char read_write, uint8_t cmd,
111 int size, union i2c_smbus_data *data)
112{
113 struct i2c_smbus_ioctl_data args;
114
115 args.read_write = read_write;
116 args.command = cmd;
117 args.size = size;
118 args.data = data;
119
120 return ioctl(fd, I2C_SMBUS, &args);
121}
122
Denys Vlasenko8ad2acf2022-01-17 23:59:46 +0100123#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CDETECT
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100124static int32_t i2c_smbus_read_byte(int fd)
125{
126 union i2c_smbus_data data;
127 int err;
128
129 err = i2c_smbus_access(fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
130 if (err < 0)
131 return err;
132
133 return data.byte;
134}
Denys Vlasenko8ad2acf2022-01-17 23:59:46 +0100135#endif
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100136
137#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
138static int32_t i2c_smbus_write_byte(int fd, uint8_t val)
139{
140 return i2c_smbus_access(fd, I2C_SMBUS_WRITE,
141 val, I2C_SMBUS_BYTE, NULL);
142}
143
144static int32_t i2c_smbus_read_byte_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_BYTE_DATA, &data);
151 if (err < 0)
152 return err;
153
154 return data.byte;
155}
156
157static int32_t i2c_smbus_read_word_data(int fd, uint8_t cmd)
158{
159 union i2c_smbus_data data;
160 int err;
161
162 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
163 I2C_SMBUS_WORD_DATA, &data);
164 if (err < 0)
165 return err;
166
167 return data.word;
168}
169#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
170
171#if ENABLE_I2CSET
172static int32_t i2c_smbus_write_byte_data(int file,
173 uint8_t cmd, uint8_t value)
174{
175 union i2c_smbus_data data;
176
177 data.byte = value;
178
179 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
180 I2C_SMBUS_BYTE_DATA, &data);
181}
182
183static int32_t i2c_smbus_write_word_data(int file, uint8_t cmd, uint16_t value)
184{
185 union i2c_smbus_data data;
186
187 data.word = value;
188
189 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
190 I2C_SMBUS_WORD_DATA, &data);
191}
192
193static int32_t i2c_smbus_write_block_data(int file, uint8_t cmd,
194 uint8_t length, const uint8_t *values)
195{
196 union i2c_smbus_data data;
197
198 if (length > I2C_SMBUS_BLOCK_MAX)
199 length = I2C_SMBUS_BLOCK_MAX;
200
201 memcpy(data.block+1, values, length);
202 data.block[0] = length;
203
204 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
205 I2C_SMBUS_BLOCK_DATA, &data);
206}
207
208static int32_t i2c_smbus_write_i2c_block_data(int file, uint8_t cmd,
209 uint8_t length, const uint8_t *values)
210{
211 union i2c_smbus_data data;
212
213 if (length > I2C_SMBUS_BLOCK_MAX)
214 length = I2C_SMBUS_BLOCK_MAX;
215
216 memcpy(data.block+1, values, length);
217 data.block[0] = length;
218
219 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
220 I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
221}
222#endif /* ENABLE_I2CSET */
223
224#if ENABLE_I2CDUMP
225/*
226 * Returns the number of bytes read, vals must hold at
227 * least I2C_SMBUS_BLOCK_MAX bytes.
228 */
229static int32_t i2c_smbus_read_block_data(int fd, uint8_t cmd, uint8_t *vals)
230{
231 union i2c_smbus_data data;
232 int i, err;
233
234 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
235 I2C_SMBUS_BLOCK_DATA, &data);
236 if (err < 0)
237 return err;
238
239 for (i = 1; i <= data.block[0]; i++)
240 *vals++ = data.block[i];
241 return data.block[0];
242}
243
244static int32_t i2c_smbus_read_i2c_block_data(int fd, uint8_t cmd,
245 uint8_t len, uint8_t *vals)
246{
247 union i2c_smbus_data data;
248 int i, err;
249
250 if (len > I2C_SMBUS_BLOCK_MAX)
251 len = I2C_SMBUS_BLOCK_MAX;
252 data.block[0] = len;
253
254 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
255 len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
256 I2C_SMBUS_I2C_BLOCK_DATA, &data);
257 if (err < 0)
258 return err;
259
260 for (i = 1; i <= data.block[0]; i++)
261 *vals++ = data.block[i];
262 return data.block[0];
263}
264#endif /* ENABLE_I2CDUMP */
265
266#if ENABLE_I2CDETECT
267static int32_t i2c_smbus_write_quick(int fd, uint8_t val)
268{
269 return i2c_smbus_access(fd, val, 0, I2C_SMBUS_QUICK, NULL);
270}
271#endif /* ENABLE_I2CDETECT */
272
273static int i2c_bus_lookup(const char *bus_str)
274{
275 return xstrtou_range(bus_str, 10, 0, 0xfffff);
276}
277
Denys Vlasenko77a51a22020-12-29 16:53:11 +0100278#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100279static int i2c_parse_bus_addr(const char *addr_str)
280{
281 /* Slave address must be in range 0x03 - 0x77. */
282 return xstrtou_range(addr_str, 16, 0x03, 0x77);
283}
284
285static void i2c_set_pec(int fd, int pec)
286{
287 ioctl_or_perror_and_die(fd, I2C_PEC,
288 itoptr(pec ? 1 : 0),
289 "can't set PEC");
290}
Denys Vlasenko77a51a22020-12-29 16:53:11 +0100291#endif
Bartosz Golaszewski31474272015-06-05 10:27:28 +0200292
Denys Vlasenko77a51a22020-12-29 16:53:11 +0100293#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER
Bartosz Golaszewski31474272015-06-05 10:27:28 +0200294static void i2c_set_slave_addr(int fd, int addr, int force)
295{
296 ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
297 itoptr(addr),
298 "can't set address to 0x%02x", addr);
299}
Denys Vlasenko77a51a22020-12-29 16:53:11 +0100300#endif
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100301
302#if ENABLE_I2CGET || ENABLE_I2CSET
303static int i2c_parse_data_addr(const char *data_addr)
304{
305 /* Data address must be an 8 bit integer. */
306 return xstrtou_range(data_addr, 16, 0, 0xff);
307}
308#endif /* ENABLE_I2CGET || ENABLE_I2CSET */
309
310/*
311 * Opens the device file associated with given i2c bus.
312 *
313 * Upstream i2c-tools also support opening devices by i2c bus name
314 * but we drop it here for size reduction.
315 */
316static int i2c_dev_open(int i2cbus)
317{
318 char filename[sizeof("/dev/i2c-%d") + sizeof(int)*3];
319 int fd;
320
321 sprintf(filename, "/dev/i2c-%d", i2cbus);
322 fd = open(filename, O_RDWR);
323 if (fd < 0) {
Bartosz Golaszewski7ca5c512015-05-11 17:26:27 +0200324 if (errno == ENOENT) {
325 filename[8] = '/'; /* change to "/dev/i2c/%d" */
326 fd = xopen(filename, O_RDWR);
327 } else {
328 bb_perror_msg_and_die("can't open '%s'", filename);
329 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100330 }
331
332 return fd;
333}
334
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100335/* Size reducing helpers for xxx_check_funcs(). */
336static void get_funcs_matrix(int fd, unsigned long *funcs)
337{
338 ioctl_or_perror_and_die(fd, I2C_FUNCS, funcs,
339 "can't get adapter functionality matrix");
340}
341
342#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
343static void check_funcs_test_end(int funcs, int pec, const char *err)
344{
345 if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C)))
James Byrne69374872019-07-02 11:35:03 +0200346 bb_simple_error_msg("warning: adapter does not support PEC");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100347
348 if (err)
349 bb_error_msg_and_die(
350 "adapter has no %s capability", err);
351}
352#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
353
354/*
355 * The below functions emit an error message and exit if the adapter doesn't
356 * support desired functionalities.
357 */
358#if ENABLE_I2CGET || ENABLE_I2CDUMP
359static void check_read_funcs(int fd, int mode, int data_addr, int pec)
360{
361 unsigned long funcs;
362 const char *err = NULL;
363
364 get_funcs_matrix(fd, &funcs);
365 switch (mode) {
366 case I2C_SMBUS_BYTE:
367 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
368 err = "SMBus receive byte";
369 break;
370 }
371 if (data_addr >= 0 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
372 err = "SMBus send byte";
373 break;
374 case I2C_SMBUS_BYTE_DATA:
375 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
376 err = "SMBus read byte";
377 break;
378 case I2C_SMBUS_WORD_DATA:
379 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
380 err = "SMBus read word";
381 break;
382#if ENABLE_I2CDUMP
383 case I2C_SMBUS_BLOCK_DATA:
384 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
385 err = "SMBus block read";
386 break;
387
388 case I2C_SMBUS_I2C_BLOCK_DATA:
389 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
390 err = "I2C block read";
391 break;
392#endif /* ENABLE_I2CDUMP */
393 default:
James Byrne69374872019-07-02 11:35:03 +0200394 bb_simple_error_msg_and_die("internal error");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100395 }
396 check_funcs_test_end(funcs, pec, err);
397}
398#endif /* ENABLE_I2CGET || ENABLE_I2CDUMP */
399
400#if ENABLE_I2CSET
401static void check_write_funcs(int fd, int mode, int pec)
402{
403 unsigned long funcs;
404 const char *err = NULL;
405
406 get_funcs_matrix(fd, &funcs);
407 switch (mode) {
408 case I2C_SMBUS_BYTE:
409 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
410 err = "SMBus send byte";
411 break;
412
413 case I2C_SMBUS_BYTE_DATA:
414 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
415 err = "SMBus write byte";
416 break;
417
418 case I2C_SMBUS_WORD_DATA:
419 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
420 err = "SMBus write word";
421 break;
422
423 case I2C_SMBUS_BLOCK_DATA:
424 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
425 err = "SMBus block write";
426 break;
427 case I2C_SMBUS_I2C_BLOCK_DATA:
428 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
429 err = "I2C block write";
430 break;
431 }
432 check_funcs_test_end(funcs, pec, err);
433}
434#endif /* ENABLE_I2CSET */
435
436static void confirm_or_abort(void)
437{
438 fprintf(stderr, "Continue? [y/N] ");
Denys Vlasenko77cb6b92018-04-07 15:08:12 +0200439 if (!bb_ask_y_confirmation())
James Byrne69374872019-07-02 11:35:03 +0200440 bb_simple_error_msg_and_die("aborting");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100441}
442
443/*
444 * Return only if user confirms the action, abort otherwise.
445 *
446 * The messages displayed here are much less elaborate than their i2c-tools
447 * counterparts - this is done for size reduction.
448 */
449static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
450{
James Byrne69374872019-07-02 11:35:03 +0200451 bb_simple_error_msg("WARNING! This program can confuse your I2C bus");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100452
453 /* Don't let the user break his/her EEPROMs */
454 if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
James Byrne69374872019-07-02 11:35:03 +0200455 bb_simple_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100456 "devices may result in data loss, aborting");
457 }
458
459 if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
James Byrne69374872019-07-02 11:35:03 +0200460 bb_simple_error_msg("WARNING! May interpret a write byte command "
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100461 "with PEC as a write byte data command");
462
463 if (pec)
James Byrne69374872019-07-02 11:35:03 +0200464 bb_simple_error_msg("PEC checking enabled");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100465
466 confirm_or_abort();
467}
468
469#if ENABLE_I2CGET
470//usage:#define i2cget_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200471//usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100472//usage:#define i2cget_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200473//usage: "Read from I2C/SMBus chip registers"
474//usage: "\n"
475//usage: "\n I2CBUS I2C bus number"
476//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100477//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200478//usage: "\n b Read byte data (default)"
479//usage: "\n w Read word data"
480//usage: "\n c Write byte/read byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100481//usage: "\n Append p for SMBus PEC"
482//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200483//usage: "\n -f Force access"
484//usage: "\n -y Disable interactive mode"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100485int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
486int i2cget_main(int argc UNUSED_PARAM, char **argv)
487{
488 const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100489
490 int bus_num, bus_addr, data_addr = -1, status;
491 int mode = I2C_SMBUS_BYTE, pec = 0, fd;
492 unsigned opts;
493
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200494 opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100495 argv += optind;
496
497 bus_num = i2c_bus_lookup(argv[0]);
498 bus_addr = i2c_parse_bus_addr(argv[1]);
499
500 if (argv[2]) {
501 data_addr = i2c_parse_data_addr(argv[2]);
502 mode = I2C_SMBUS_BYTE_DATA;
503 if (argv[3]) {
504 switch (argv[3][0]) {
505 case 'b': /* Already set */ break;
506 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
507 case 'c': mode = I2C_SMBUS_BYTE; break;
508 default:
James Byrne69374872019-07-02 11:35:03 +0200509 bb_simple_error_msg("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100510 bb_show_usage();
511 }
512 pec = argv[3][1] == 'p';
513 }
514 }
515
516 fd = i2c_dev_open(bus_num);
517 check_read_funcs(fd, mode, data_addr, pec);
518 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
519
520 if (!(opts & opt_y))
521 confirm_action(bus_addr, mode, data_addr, pec);
522
523 if (pec)
524 i2c_set_pec(fd, 1);
525
526 switch (mode) {
527 case I2C_SMBUS_BYTE:
528 if (data_addr >= 0) {
529 status = i2c_smbus_write_byte(fd, data_addr);
530 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200531 bb_simple_error_msg("warning - write failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100532 }
533 status = i2c_smbus_read_byte(fd);
534 break;
535 case I2C_SMBUS_WORD_DATA:
536 status = i2c_smbus_read_word_data(fd, data_addr);
537 break;
538 default: /* I2C_SMBUS_BYTE_DATA */
539 status = i2c_smbus_read_byte_data(fd, data_addr);
540 }
541 close(fd);
542
543 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200544 bb_simple_perror_msg_and_die("read failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100545
546 printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
547
548 return 0;
549}
550#endif /* ENABLE_I2CGET */
551
552#if ENABLE_I2CSET
553//usage:#define i2cset_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200554//usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100555//usage:#define i2cset_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200556//usage: "Set I2C registers"
557//usage: "\n"
558//usage: "\n I2CBUS I2C bus number"
559//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100560//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200561//usage: "\n c Byte, no value"
562//usage: "\n b Byte data (default)"
563//usage: "\n w Word data"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100564//usage: "\n i I2C block data"
565//usage: "\n s SMBus block data"
566//usage: "\n Append p for SMBus PEC"
567//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200568//usage: "\n -f Force access"
569//usage: "\n -y Disable interactive mode"
570//usage: "\n -r Read back and compare the result"
571//usage: "\n -m MASK Mask specifying which bits to write"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100572int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
573int i2cset_main(int argc, char **argv)
574{
575 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
576 opt_m = (1 << 2), opt_r = (1 << 3);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100577
578 int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200579 int val, blen, mask, fd, status;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100580 unsigned char block[I2C_SMBUS_BLOCK_MAX];
581 char *opt_m_arg = NULL;
582 unsigned opts;
583
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200584 opts = getopt32(argv, "^"
585 "fym:r"
586 "\0" "-3", /* minimum 3 args */
587 &opt_m_arg
588 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100589 argv += optind;
590 argc -= optind;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200591 argc--; /* now argv[argc] is last arg */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100592
593 bus_num = i2c_bus_lookup(argv[0]);
594 bus_addr = i2c_parse_bus_addr(argv[1]);
595 data_addr = i2c_parse_data_addr(argv[2]);
596
597 if (argv[3]) {
598 if (!argv[4] && argv[3][0] != 'c') {
599 mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
600 } else {
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200601 switch (argv[argc][0]) {
602 case 'c': /* Already set */
603 break;
604 case 'b': mode = I2C_SMBUS_BYTE_DATA;
605 break;
606 case 'w': mode = I2C_SMBUS_WORD_DATA;
607 break;
608 case 's': mode = I2C_SMBUS_BLOCK_DATA;
609 break;
610 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
611 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100612 default:
James Byrne69374872019-07-02 11:35:03 +0200613 bb_simple_error_msg("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100614 bb_show_usage();
615 }
616
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200617 pec = (argv[argc][1] == 'p');
618 if (mode == I2C_SMBUS_BLOCK_DATA
619 || mode == I2C_SMBUS_I2C_BLOCK_DATA
620 ) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100621 if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
James Byrne69374872019-07-02 11:35:03 +0200622 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100623 "PEC not supported for I2C "
624 "block writes");
625 if (opts & opt_m)
James Byrne69374872019-07-02 11:35:03 +0200626 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100627 "mask not supported for block "
628 "writes");
629 }
630 }
631 }
632
633 /* Prepare the value(s) to be written according to current mode. */
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200634 mask = 0;
635 blen = 0;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100636 switch (mode) {
637 case I2C_SMBUS_BYTE_DATA:
638 val = xstrtou_range(argv[3], 0, 0, 0xff);
639 break;
640 case I2C_SMBUS_WORD_DATA:
641 val = xstrtou_range(argv[3], 0, 0, 0xffff);
642 break;
643 case I2C_SMBUS_BLOCK_DATA:
644 case I2C_SMBUS_I2C_BLOCK_DATA:
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200645 for (blen = 3; blen < argc; blen++)
646 block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
647 blen -= 3;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100648 val = -1;
649 break;
650 default:
651 val = -1;
652 break;
653 }
654
655 if (opts & opt_m) {
656 mask = xstrtou_range(opt_m_arg, 0, 0,
657 (mode == I2C_SMBUS_BYTE ||
658 mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
659 }
660
661 fd = i2c_dev_open(bus_num);
662 check_write_funcs(fd, mode, pec);
663 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
664
665 if (!(opts & opt_y))
666 confirm_action(bus_addr, mode, data_addr, pec);
667
668 /*
669 * If we're using mask - read the current value here and adjust the
670 * value to be written.
671 */
672 if (opts & opt_m) {
673 int tmpval;
674
675 switch (mode) {
676 case I2C_SMBUS_BYTE:
677 tmpval = i2c_smbus_read_byte(fd);
678 break;
679 case I2C_SMBUS_WORD_DATA:
680 tmpval = i2c_smbus_read_word_data(fd, data_addr);
681 break;
682 default:
683 tmpval = i2c_smbus_read_byte_data(fd, data_addr);
684 }
685
686 if (tmpval < 0)
James Byrne69374872019-07-02 11:35:03 +0200687 bb_simple_perror_msg_and_die("can't read old value");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100688
689 val = (val & mask) | (tmpval & ~mask);
690
691 if (!(opts & opt_y)) {
692 bb_error_msg("old value 0x%0*x, write mask "
693 "0x%0*x, will write 0x%0*x to register "
694 "0x%02x",
695 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
696 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
697 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
698 data_addr);
699 confirm_or_abort();
700 }
701 }
702
703 if (pec)
704 i2c_set_pec(fd, 1);
705
706 switch (mode) {
707 case I2C_SMBUS_BYTE:
708 status = i2c_smbus_write_byte(fd, data_addr);
709 break;
710 case I2C_SMBUS_WORD_DATA:
711 status = i2c_smbus_write_word_data(fd, data_addr, val);
712 break;
713 case I2C_SMBUS_BLOCK_DATA:
714 status = i2c_smbus_write_block_data(fd, data_addr,
715 blen, block);
716 break;
717 case I2C_SMBUS_I2C_BLOCK_DATA:
718 status = i2c_smbus_write_i2c_block_data(fd, data_addr,
719 blen, block);
720 break;
721 default: /* I2C_SMBUS_BYTE_DATA */
722 status = i2c_smbus_write_byte_data(fd, data_addr, val);
723 break;
724 }
725 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200726 bb_simple_perror_msg_and_die("write failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100727
728 if (pec)
729 i2c_set_pec(fd, 0); /* Clear PEC. */
730
731 /* No readback required - we're done. */
732 if (!(opts & opt_r))
733 return 0;
734
735 switch (mode) {
736 case I2C_SMBUS_BYTE:
737 status = i2c_smbus_read_byte(fd);
738 val = data_addr;
739 break;
740 case I2C_SMBUS_WORD_DATA:
741 status = i2c_smbus_read_word_data(fd, data_addr);
742 break;
743 default: /* I2C_SMBUS_BYTE_DATA */
744 status = i2c_smbus_read_byte_data(fd, data_addr);
745 }
746
747 if (status < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200748 puts("Warning - readback failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100749 } else
750 if (status != val) {
751 printf("Warning - data mismatch - wrote "
752 "0x%0*x, read back 0x%0*x\n",
753 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
754 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
755 } else {
756 printf("Value 0x%0*x written, readback matched\n",
757 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
758 }
759
760 return 0;
761}
762#endif /* ENABLE_I2CSET */
763
764#if ENABLE_I2CDUMP
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200765static int read_block_data(int buf_fd, int mode, int *block)
766{
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200767 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200768 int res, blen = 0, tmp, i;
769
Bartosz Golaszewski1fe75b82015-10-27 17:15:03 +0100770 if (mode == I2C_SMBUS_BLOCK_DATA) {
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100771 blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
772 if (blen <= 0)
773 goto fail;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200774 } else {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200775 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200776 tmp = i2c_smbus_read_i2c_block_data(
777 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
778 cblock + res);
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100779 if (tmp <= 0) {
780 blen = tmp;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100781 goto fail;
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100782 }
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200783 }
784
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200785 if (res >= I2CDUMP_NUM_REGS)
786 res = I2CDUMP_NUM_REGS;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200787
788 for (i = 0; i < res; i++)
789 block[i] = cblock[i];
790
791 if (mode != I2C_SMBUS_BLOCK_DATA)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200792 for (i = res; i < I2CDUMP_NUM_REGS; i++)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200793 block[i] = -1;
794 }
795
796 return blen;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100797
798 fail:
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100799 bb_error_msg_and_die("block read failed: %d", blen);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200800}
801
802/* Dump all but word data. */
803static void dump_data(int bus_fd, int mode, unsigned first,
804 unsigned last, int *block, int blen)
805{
806 int i, j, res;
807
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200808 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
809 " 0123456789abcdef");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200810
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200811 for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200812 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
813 break;
814 if (i/16 < first/16)
815 continue;
816 if (i/16 > last/16)
817 break;
818
819 printf("%02x: ", i);
820 for (j = 0; j < 16; j++) {
821 fflush_all();
822 /* Skip unwanted registers */
823 if (i+j < first || i+j > last) {
824 printf(" ");
825 if (mode == I2C_SMBUS_WORD_DATA) {
826 printf(" ");
827 j++;
828 }
829 continue;
830 }
831
832 switch (mode) {
833 case I2C_SMBUS_BYTE_DATA:
834 res = i2c_smbus_read_byte_data(bus_fd, i+j);
835 block[i+j] = res;
836 break;
837 case I2C_SMBUS_WORD_DATA:
838 res = i2c_smbus_read_word_data(bus_fd, i+j);
839 if (res < 0) {
840 block[i+j] = res;
841 block[i+j+1] = res;
842 } else {
843 block[i+j] = res & 0xff;
844 block[i+j+1] = res >> 8;
845 }
846 break;
847 case I2C_SMBUS_BYTE:
848 res = i2c_smbus_read_byte(bus_fd);
849 block[i+j] = res;
850 break;
851 default:
852 res = block[i+j];
853 }
854
855 if (mode == I2C_SMBUS_BLOCK_DATA &&
856 i+j >= blen) {
857 printf(" ");
858 } else if (res < 0) {
859 printf("XX ");
860 if (mode == I2C_SMBUS_WORD_DATA)
861 printf("XX ");
862 } else {
863 printf("%02x ", block[i+j]);
864 if (mode == I2C_SMBUS_WORD_DATA)
865 printf("%02x ", block[i+j+1]);
866 }
867
868 if (mode == I2C_SMBUS_WORD_DATA)
869 j++;
870 }
871 printf(" ");
872
873 for (j = 0; j < 16; j++) {
874 if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
875 break;
876 /* Skip unwanted registers */
877 if (i+j < first || i+j > last) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200878 bb_putchar(' ');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200879 continue;
880 }
881
882 res = block[i+j];
883 if (res < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200884 bb_putchar('X');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200885 } else if (res == 0x00 || res == 0xff) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200886 bb_putchar('.');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200887 } else if (res < 32 || res >= 127) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200888 bb_putchar('?');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200889 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200890 bb_putchar(res);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200891 }
892 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200893 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200894 }
895}
896
897static void dump_word_data(int bus_fd, unsigned first, unsigned last)
898{
899 int i, j, rv;
900
901 /* Word data. */
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200902 puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200903 for (i = 0; i < 256; i += 8) {
904 if (i/8 < first/8)
905 continue;
906 if (i/8 > last/8)
907 break;
908
909 printf("%02x: ", i);
910 for (j = 0; j < 8; j++) {
911 /* Skip unwanted registers. */
912 if (i+j < first || i+j > last) {
913 printf(" ");
914 continue;
915 }
916
917 rv = i2c_smbus_read_word_data(bus_fd, i+j);
918 if (rv < 0)
919 printf("XXXX ");
920 else
921 printf("%04x ", rv & 0xffff);
922 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200923 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200924 }
925}
926
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100927//usage:#define i2cdump_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200928//usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100929//usage:#define i2cdump_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200930//usage: "Examine I2C registers"
931//usage: "\n"
932//usage: "\n I2CBUS I2C bus number"
933//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100934//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200935//usage: "\n b Byte (default)"
936//usage: "\n w Word"
937//usage: "\n W Word on even register addresses"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100938//usage: "\n i I2C block"
939//usage: "\n s SMBus block"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200940//usage: "\n c Consecutive byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100941//usage: "\n Append p for SMBus PEC"
942//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200943//usage: "\n -f Force access"
944//usage: "\n -y Disable interactive mode"
945//usage: "\n -r Limit the number of registers being accessed"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100946int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
947int i2cdump_main(int argc UNUSED_PARAM, char **argv)
948{
949 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
950 opt_r = (1 << 2);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100951
952 int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200953 unsigned first = 0x00, last = 0xff, opts;
Bartosz Golaszewski59f81972016-06-23 17:19:50 +0200954 int block[I2CDUMP_NUM_REGS];
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100955 char *opt_r_str, *dash;
Denys Vlasenko2cf45912015-11-01 20:57:34 +0100956 int fd, res;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100957
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200958 opts = getopt32(argv, "^"
959 "fyr:"
960 "\0" "-2:?3" /* from 2 to 3 args */,
961 &opt_r_str
962 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100963 argv += optind;
964
965 bus_num = i2c_bus_lookup(argv[0]);
966 bus_addr = i2c_parse_bus_addr(argv[1]);
967
968 if (argv[2]) {
969 switch (argv[2][0]) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200970 case 'b': /* Already set. */ break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100971 case 'c': mode = I2C_SMBUS_BYTE; break;
972 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
973 case 'W':
974 mode = I2C_SMBUS_WORD_DATA;
975 even = 1;
976 break;
977 case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
978 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
979 default:
James Byrne69374872019-07-02 11:35:03 +0200980 bb_simple_error_msg_and_die("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100981 }
982
983 if (argv[2][1] == 'p') {
984 if (argv[2][0] == 'W' || argv[2][0] == 'i') {
James Byrne69374872019-07-02 11:35:03 +0200985 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100986 "pec not supported for -W and -i");
987 } else {
988 pec = 1;
989 }
990 }
991 }
992
993 if (opts & opt_r) {
994 first = strtol(opt_r_str, &dash, 0);
995 if (dash == opt_r_str || *dash != '-' || first > 0xff)
James Byrne69374872019-07-02 11:35:03 +0200996 bb_simple_error_msg_and_die("invalid range");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100997 last = xstrtou_range(++dash, 0, first, 0xff);
998
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200999 /* Range is not available for every mode. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001000 switch (mode) {
1001 case I2C_SMBUS_BYTE:
1002 case I2C_SMBUS_BYTE_DATA:
1003 break;
1004 case I2C_SMBUS_WORD_DATA:
1005 if (!even || (!(first % 2) && last % 2))
1006 break;
1007 /* Fall through */
1008 default:
James Byrne69374872019-07-02 11:35:03 +02001009 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001010 "range not compatible with selected mode");
1011 }
1012 }
1013
1014 fd = i2c_dev_open(bus_num);
1015 check_read_funcs(fd, mode, -1 /* data_addr */, pec);
1016 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
1017
1018 if (pec)
1019 i2c_set_pec(fd, 1);
1020
1021 if (!(opts & opt_y))
1022 confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
1023
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001024 /* All but word data. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001025 if (mode != I2C_SMBUS_WORD_DATA || even) {
Denys Vlasenko2cf45912015-11-01 20:57:34 +01001026 int blen = 0;
1027
Bartosz Golaszewski1cde5f72015-10-27 17:15:02 +01001028 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
1029 blen = read_block_data(fd, mode, block);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001030
1031 if (mode == I2C_SMBUS_BYTE) {
1032 res = i2c_smbus_write_byte(fd, first);
1033 if (res < 0)
James Byrne69374872019-07-02 11:35:03 +02001034 bb_simple_perror_msg_and_die("write start address");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001035 }
1036
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001037 dump_data(fd, mode, first, last, block, blen);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001038 } else {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001039 dump_word_data(fd, first, last);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001040 }
1041
1042 return 0;
1043}
1044#endif /* ENABLE_I2CDUMP */
1045
1046#if ENABLE_I2CDETECT
1047enum adapter_type {
1048 ADT_DUMMY = 0,
1049 ADT_ISA,
1050 ADT_I2C,
1051 ADT_SMBUS,
1052};
1053
1054struct adap_desc {
1055 const char *funcs;
1056 const char *algo;
1057};
1058
Denys Vlasenko6cc49622020-11-30 14:58:02 +01001059static const struct adap_desc adap_descs[] ALIGN_PTR = {
Denys Vlasenko965b7952020-11-30 13:03:03 +01001060 { .funcs = "dummy", .algo = "Dummy bus", },
1061 { .funcs = "isa", .algo = "ISA bus", },
1062 { .funcs = "i2c", .algo = "I2C adapter", },
1063 { .funcs = "smbus", .algo = "SMBus adapter", },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001064};
1065
Denys Vlasenko965b7952020-11-30 13:03:03 +01001066struct i2c_func {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001067 long value;
1068 const char* name;
1069};
1070
Denys Vlasenko6cc49622020-11-30 14:58:02 +01001071static const struct i2c_func i2c_funcs_tab[] ALIGN_PTR = {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001072 { .value = I2C_FUNC_I2C,
1073 .name = "I2C" },
1074 { .value = I2C_FUNC_SMBUS_QUICK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001075 .name = "SMBus quick command" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001076 { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001077 .name = "SMBus send byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001078 { .value = I2C_FUNC_SMBUS_READ_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001079 .name = "SMBus receive byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001080 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001081 .name = "SMBus write byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001082 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001083 .name = "SMBus read byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001084 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001085 .name = "SMBus write word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001086 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001087 .name = "SMBus read word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001088 { .value = I2C_FUNC_SMBUS_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001089 .name = "SMBus process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001090 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001091 .name = "SMBus block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001092 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001093 .name = "SMBus block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001094 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001095 .name = "SMBus block process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001096 { .value = I2C_FUNC_SMBUS_PEC,
1097 .name = "SMBus PEC" },
1098 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001099 .name = "I2C block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001100 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001101 .name = "I2C block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001102 { .value = 0, .name = NULL }
1103};
1104
1105static enum adapter_type i2cdetect_get_funcs(int bus)
1106{
1107 enum adapter_type ret;
1108 unsigned long funcs;
1109 int fd;
1110
1111 fd = i2c_dev_open(bus);
1112
1113 get_funcs_matrix(fd, &funcs);
1114 if (funcs & I2C_FUNC_I2C)
1115 ret = ADT_I2C;
1116 else if (funcs & (I2C_FUNC_SMBUS_BYTE |
1117 I2C_FUNC_SMBUS_BYTE_DATA |
1118 I2C_FUNC_SMBUS_WORD_DATA))
1119 ret = ADT_SMBUS;
1120 else
1121 ret = ADT_DUMMY;
1122
1123 close(fd);
1124
1125 return ret;
1126}
1127
1128static void NORETURN list_i2c_busses_and_exit(void)
1129{
1130 const char *const i2cdev_path = "/sys/class/i2c-dev";
1131
1132 char path[NAME_MAX], name[128];
1133 struct dirent *de, *subde;
1134 enum adapter_type adt;
1135 DIR *dir, *subdir;
1136 int rv, bus;
1137 char *pos;
1138 FILE *fp;
1139
1140 /*
1141 * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
1142 * but we won't bother since it's only useful on older kernels (before
1143 * 2.6.5). We expect sysfs to be present and mounted at /sys/.
1144 */
1145
1146 dir = xopendir(i2cdev_path);
1147 while ((de = readdir(dir))) {
1148 if (de->d_name[0] == '.')
1149 continue;
1150
1151 /* Simple version for ISA chips. */
1152 snprintf(path, NAME_MAX, "%s/%s/name",
1153 i2cdev_path, de->d_name);
Denys Vlasenkob230ff92020-12-30 00:16:27 +01001154 fp = fopen_for_read(path);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001155 if (fp == NULL) {
1156 snprintf(path, NAME_MAX,
1157 "%s/%s/device/name",
1158 i2cdev_path, de->d_name);
Denys Vlasenkob230ff92020-12-30 00:16:27 +01001159 fp = fopen_for_read(path);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001160 }
1161
1162 /* Non-ISA chips require the hard-way. */
1163 if (fp == NULL) {
1164 snprintf(path, NAME_MAX,
1165 "%s/%s/device/name",
1166 i2cdev_path, de->d_name);
1167 subdir = opendir(path);
1168 if (subdir == NULL)
1169 continue;
1170
1171 while ((subde = readdir(subdir))) {
1172 if (subde->d_name[0] == '.')
1173 continue;
1174
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001175 if (is_prefixed_with(subde->d_name, "i2c-")) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001176 snprintf(path, NAME_MAX,
1177 "%s/%s/device/%s/name",
1178 i2cdev_path, de->d_name,
1179 subde->d_name);
Denys Vlasenkob230ff92020-12-30 00:16:27 +01001180 fp = fopen_for_read(path);
Bartosz Golaszewskid9089922015-06-05 10:27:32 +02001181 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001182 }
1183 }
1184 }
1185
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001186 if (fp != NULL) {
1187 /*
1188 * Get the rest of the info and display a line
1189 * for a single bus.
1190 */
1191 memset(name, 0, sizeof(name));
1192 pos = fgets(name, sizeof(name), fp);
1193 fclose(fp);
1194 if (pos == NULL)
1195 continue;
1196
1197 pos = strchr(name, '\n');
1198 if (pos != NULL)
1199 *pos = '\0';
1200
1201 rv = sscanf(de->d_name, "i2c-%d", &bus);
1202 if (rv != 1)
1203 continue;
1204
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001205 if (is_prefixed_with(name, "ISA"))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001206 adt = ADT_ISA;
1207 else
1208 adt = i2cdetect_get_funcs(bus);
1209
1210 printf(
1211 "i2c-%d\t%-10s\t%-32s\t%s\n",
1212 bus, adap_descs[adt].funcs,
1213 name, adap_descs[adt].algo);
1214 }
1215 }
1216
Denys Vlasenkodb5546c2022-01-05 22:16:06 +01001217 exit_SUCCESS();
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001218}
1219
1220static void NORETURN no_support(const char *cmd)
1221{
1222 bb_error_msg_and_die("bus doesn't support %s", cmd);
1223}
1224
1225static void will_skip(const char *cmd)
1226{
1227 bb_error_msg(
1228 "warning: can't use %s command, "
1229 "will skip some addresses", cmd);
1230}
1231
1232//usage:#define i2cdetect_trivial_usage
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001233//usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001234//usage:#define i2cdetect_full_usage "\n\n"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001235//usage: "Detect I2C chips"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001236//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +02001237//usage: "\n -l List installed buses"
1238//usage: "\n -F BUS# List functionalities on this bus"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001239//usage: "\n -y Disable interactive mode"
1240//usage: "\n -a Force scanning of non-regular addresses"
1241//usage: "\n -q Use smbus quick write commands for probing (default)"
1242//usage: "\n -r Use smbus read byte commands for probing"
1243//usage: "\n FIRST and LAST limit probing range"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001244int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1245int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1246{
1247 const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
1248 opt_q = (1 << 2), opt_r = (1 << 3),
1249 opt_F = (1 << 4), opt_l = (1 << 5);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001250
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001251 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001252 unsigned first = 0x03, last = 0x77, opts;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001253 unsigned long funcs;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001254
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001255 opts = getopt32(argv, "^"
1256 "yaqrFl"
1257 "\0"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001258 "q--r:r--q:"/*mutually exclusive*/
1259 "?3"/*up to 3 args*/
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001260 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001261 argv += optind;
1262
1263 if (opts & opt_l)
1264 list_i2c_busses_and_exit();
1265
Bartosz Golaszewskib2cca322015-05-11 17:22:10 +02001266 if (!argv[0])
1267 bb_show_usage();
1268
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001269 bus_num = i2c_bus_lookup(argv[0]);
1270 fd = i2c_dev_open(bus_num);
1271 get_funcs_matrix(fd, &funcs);
1272
1273 if (opts & opt_F) {
1274 /* Only list the functionalities. */
1275 printf("Functionalities implemented by bus #%d\n", bus_num);
1276 for (i = 0; i2c_funcs_tab[i].value; i++) {
1277 printf("%-32s %s\n", i2c_funcs_tab[i].name,
1278 funcs & i2c_funcs_tab[i].value ? "yes" : "no");
1279 }
1280
1281 return EXIT_SUCCESS;
1282 }
1283
1284 if (opts & opt_r)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001285 mode = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001286 else if (opts & opt_q)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001287 mode = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001288
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001289 if (opts & opt_a) {
1290 first = 0x00;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001291 last = 0x7f;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001292 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001293
1294 /* Read address range. */
1295 if (argv[1]) {
1296 first = xstrtou_range(argv[1], 16, first, last);
1297 if (argv[2])
1298 last = xstrtou_range(argv[2], 16, first, last);
1299 }
1300
1301 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1302 no_support("detection commands");
1303 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001304 if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001305 no_support("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001306 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001307 if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001308 no_support("SMBus receive byte");
Bartosz Golaszewski22044722015-06-05 10:27:30 +02001309 }
1310
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001311 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001312 if (!(funcs & I2C_FUNC_SMBUS_QUICK))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001313 will_skip("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001314 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001315 will_skip("SMBus receive byte");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001316 }
1317
1318 if (!(opts & opt_y))
1319 confirm_action(-1, -1, -1, 0);
1320
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001321 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001322 for (i = 0; i < 128; i += 16) {
1323 printf("%02x: ", i);
Bartosz Golaszewskifc8eb052015-10-27 17:15:01 +01001324 for (j = 0; j < 16; j++) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001325 fflush_all();
1326
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001327 cmd = mode;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001328 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001329 if ((i+j >= 0x30 && i+j <= 0x37) ||
1330 (i+j >= 0x50 && i+j <= 0x5F))
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001331 cmd = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001332 else
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001333 cmd = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001334 }
1335
1336 /* Skip unwanted addresses. */
1337 if (i+j < first
1338 || i+j > last
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001339 || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1340 || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001341 {
1342 printf(" ");
1343 continue;
1344 }
1345
Bartosz Golaszewski31474272015-06-05 10:27:28 +02001346 status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
1347 if (status < 0) {
1348 if (errno == EBUSY) {
1349 printf("UU ");
1350 continue;
1351 }
1352
1353 bb_perror_msg_and_die(
1354 "can't set address to 0x%02x", i + j);
1355 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001356
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001357 switch (cmd) {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001358 case I2CDETECT_MODE_READ:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001359 /*
1360 * This is known to lock SMBus on various
1361 * write-only chips (mainly clock chips).
1362 */
1363 status = i2c_smbus_read_byte(fd);
1364 break;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001365 default: /* I2CDETECT_MODE_QUICK: */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001366 /*
1367 * This is known to corrupt the Atmel
1368 * AT24RF08 EEPROM.
1369 */
1370 status = i2c_smbus_write_quick(fd,
1371 I2C_SMBUS_WRITE);
1372 break;
1373 }
1374
1375 if (status < 0)
1376 printf("-- ");
1377 else
1378 printf("%02x ", i+j);
1379 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001380 bb_putchar('\n');
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001381 }
1382
1383 return 0;
1384}
1385#endif /* ENABLE_I2CDETECT */
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001386
1387#if ENABLE_I2CTRANSFER
1388static void check_i2c_func(int fd)
1389{
1390 unsigned long funcs;
1391
1392 get_funcs_matrix(fd, &funcs);
1393
1394 if (!(funcs & I2C_FUNC_I2C))
James Byrne69374872019-07-02 11:35:03 +02001395 bb_simple_error_msg_and_die("adapter does not support I2C transfers");
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001396}
1397
1398//usage:#define i2ctransfer_trivial_usage
Denys Vlasenko6f7b10c2021-06-13 03:51:55 +02001399//usage: "[-fay] I2CBUS { rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..."
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001400//usage:#define i2ctransfer_full_usage "\n\n"
1401//usage: "Read/write I2C data in one transfer"
1402//usage: "\n"
Nikolaus Vossf81e0122019-02-11 11:30:52 +01001403//usage: "\n -f Force access to busy addresses"
1404//usage: "\n -a Force access to non-regular addresses"
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001405//usage: "\n -y Disable interactive mode"
1406int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1407int i2ctransfer_main(int argc UNUSED_PARAM, char **argv)
1408{
1409 enum {
1410 opt_f = (1 << 0),
1411 opt_y = (1 << 1),
1412 opt_a = (1 << 2),
1413 };
1414 int bus_num, bus_addr;
1415 int fd;
1416 unsigned opts, first, last;
1417 int nmsgs, nmsgs_sent, i;
1418 struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS];
1419 struct i2c_rdwr_ioctl_data rdwr;
1420
1421 memset(msgs, 0, sizeof(msgs));
1422
1423 opts = getopt32(argv, "^"
1424 "fya"
1425 "\0" "-2" /* minimum 2 args */
1426 );
1427 first = 0x03;
1428 last = 0x77;
1429 if (opts & opt_a) {
1430 first = 0x00;
1431 last = 0x7f;
1432 }
1433
1434 argv += optind;
1435 bus_num = i2c_bus_lookup(argv[0]);
1436 fd = i2c_dev_open(bus_num);
1437 check_i2c_func(fd);
1438
1439 bus_addr = -1;
1440 nmsgs = 0;
1441 while (*++argv) {
1442 char *arg_ptr;
1443 unsigned len;
1444 uint16_t flags;
1445 char *end;
1446
1447 if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS)
James Byrne69374872019-07-02 11:35:03 +02001448 bb_simple_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR);
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001449
1450 flags = 0;
1451 arg_ptr = *argv;
1452 switch (*arg_ptr++) {
1453 case 'r': flags |= I2C_M_RD; break;
1454 case 'w': break;
1455 default:
1456 bb_show_usage();
1457 }
1458
1459 end = strchr(arg_ptr, '@');
1460 if (end) *end = '\0';
1461 len = xstrtou_range(arg_ptr, 0, 0, 0xffff);
1462 if (end) {
1463 bus_addr = xstrtou_range(end + 1, 0, first, last);
Nikolaus Vossf81e0122019-02-11 11:30:52 +01001464 i2c_set_slave_addr(fd, bus_addr, (opts & opt_f));
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001465 } else {
1466 /* Reuse last address if possible */
1467 if (bus_addr < 0)
1468 bb_error_msg_and_die("no address given in '%s'", *argv);
1469 }
1470
1471 msgs[nmsgs].addr = bus_addr;
1472 msgs[nmsgs].flags = flags;
1473 msgs[nmsgs].len = len;
1474 if (len)
1475 msgs[nmsgs].buf = xzalloc(len);
1476
1477 if (!(flags & I2C_M_RD)) {
1478 /* Consume DATA arg(s) */
1479 unsigned buf_idx = 0;
1480
1481 while (buf_idx < len) {
1482 uint8_t data8;
1483 unsigned long data;
1484
1485 arg_ptr = *++argv;
1486 if (!arg_ptr)
1487 bb_show_usage();
1488 data = strtoul(arg_ptr, &end, 0);
1489 if (data > 0xff || arg_ptr == end)
1490 bb_error_msg_and_die("invalid data byte '%s'", *argv);
1491
1492 data8 = data;
1493 while (buf_idx < len) {
1494 msgs[nmsgs].buf[buf_idx++] = data8;
1495 if (!*end)
1496 break;
1497 switch (*end) {
1498 /* Pseudo randomness (8 bit AXR with a=13 and b=27) */
1499 case 'p':
1500 data8 = (data8 ^ 27) + 13;
1501 data8 = (data8 << 1) | (data8 >> 7);
1502 break;
1503 case '+': data8++; break;
1504 case '-': data8--; break;
1505 case '=': break;
1506 default:
1507 bb_error_msg_and_die("invalid data byte suffix: '%s'",
1508 *argv);
1509 }
1510 }
1511 }
1512 }
1513 nmsgs++;
1514 }
1515
1516 if (!(opts & opt_y))
1517 confirm_action(bus_addr, 0, 0, 0);
1518
1519 rdwr.msgs = msgs;
1520 rdwr.nmsgs = nmsgs;
1521 nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR");
1522 if (nmsgs_sent < nmsgs)
1523 bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs);
1524
1525 for (i = 0; i < nmsgs_sent; i++) {
1526 if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) {
1527 int j;
1528 for (j = 0; j < msgs[i].len - 1; j++)
1529 printf("0x%02x ", msgs[i].buf[j]);
1530 /* Print final byte with newline */
1531 printf("0x%02x\n", msgs[i].buf[j]);
1532 }
1533 }
1534
1535# if ENABLE_FEATURE_CLEAN_UP
1536 close(fd);
1537 for (i = 0; i < nmsgs; i++)
1538 free(msgs[i].buf);
1539# endif
1540
1541 return 0;
1542}
1543#endif /* ENABLE_I2CTRANSFER */