1 /* i2ctools.c - i2c tools
2 *
3 * Copyright 2018 The Android Open Source Project
4 *
5 * https://www.kernel.org/doc/Documentation/i2c/
6 *
7 * Note: -y must have the same value in each toy for `confirm`.
8 *
9 * TODO: i2cdetect -q/-r and the "auto" mode?
10 * TODO: i2cdump non-byte modes, -r FIRST-LAST?
11 * TODO: i2cget non-byte modes? default to current read address?
12 * TODO: i2cset -r? -m MASK? c/s modes, p mode modifier?
13 * TODO: I2C_M_TEN bit addressing (-t, larger range in probe...)
14
15 // note: confirm() needs "y" to be in same place for all commands
16 USE_I2CDETECT(NEWTOY(i2cdetect, ">3aF#<0>63lqry[!qr][!Fl]", TOYFLAG_USR|TOYFLAG_SBIN))
17 USE_I2CDUMP(NEWTOY(i2cdump, "<2>2fy", TOYFLAG_USR|TOYFLAG_SBIN))
18 USE_I2CGET(NEWTOY(i2cget, "<2>3fy", TOYFLAG_USR|TOYFLAG_SBIN))
19 USE_I2CSET(NEWTOY(i2cset, "<4fy", TOYFLAG_USR|TOYFLAG_SBIN))
20 USE_I2CTRANSFER(NEWTOY(i2ctransfer, "<2vfy", TOYFLAG_USR|TOYFLAG_SBIN))
21
22 config I2CDETECT
23 bool "i2cdetect"
24 default y
25 help
26 usage: i2cdetect [-aqry] BUS [FIRST LAST]
27 usage: i2cdetect -F BUS
28 usage: i2cdetect -l
29
30 Detect i2c devices.
31
32 -a All addresses (0x00-0x7f rather than 0x03-0x77 or FIRST-LAST)
33 -F Show functionality
34 -l List available buses
35 -q Probe with SMBus Quick Write (default)
36 -r Probe with SMBus Read Byte
37 -y Skip confirmation prompts (yes to all)
38
39 config I2CDUMP
40 bool "i2cdump"
41 default y
42 help
43 usage: i2cdump [-fy] BUS CHIP
44
45 Dump i2c registers.
46
47 -f Force access to busy devices
48 -y Skip confirmation prompts (yes to all)
49
50 config I2CGET
51 bool "i2cget"
52 default y
53 help
54 usage: i2cget [-fy] BUS CHIP [ADDR]
55
56 Read an i2c register.
57
58 -f Force access to busy devices
59 -y Skip confirmation prompts (yes to all)
60
61 config I2CSET
62 bool "i2cset"
63 default y
64 help
65 usage: i2cset [-fy] BUS CHIP ADDR VALUE... MODE
66
67 Write an i2c register. MODE is b for byte, w for 16-bit word, i for I2C block.
68
69 -f Force access to busy devices
70 -y Skip confirmation prompts (yes to all)
71
72 config I2CTRANSFER
73 bool "i2ctransfer"
74 default y
75 help
76 usage: i2ctransfer [-fy] BUS DESC [DATA...]...
77
78 Make i2c transfers. DESC is 'r' for read or 'w' for write, followed by
79 the number of bytes to read or write, followed by '@' and a 7-bit address.
80 For any message after the first, the '@' and address can be omitted to
81 reuse the previous address. A 'w' DESC must be followed by the number of
82 DATA bytes that was specified in the DESC.
83
84 -f Force access to busy devices
85 -v Verbose (show messages sent, not just received)
86 -y Skip confirmation prompts (yes to all)
87 */
88
89 #define FOR_i2cdetect
90 #define FORCE_FLAGS
91 #include "toys.h"
92
GLOBALS(long F;)93 GLOBALS(
94 long F;
95 )
96
97 #include <linux/i2c.h>
98 #include <linux/i2c-dev.h>
99
100 printf_format static void confirm(const char *fmt, ...)
101 {
102 va_list va;
103
104 if (FLAG(y)) return;
105
106 va_start(va, fmt);
107 vfprintf(stderr, fmt, va);
108 va_end(va);
109 if (!yesno(1)) error_exit("Exiting");
110 }
111
i2c_open(int bus,int slave,long chip)112 static int i2c_open(int bus, int slave, long chip)
113 {
114 int fd;
115
116 sprintf(toybuf, "/dev/i2c-%d", bus);
117 fd = xopen(toybuf, O_RDONLY);
118 if (slave) xioctl(fd, slave, (void *)chip);
119
120 return fd;
121 }
122
i2c_get_funcs(int bus)123 static unsigned long i2c_get_funcs(int bus)
124 {
125 int fd = i2c_open(bus, 0, 0);
126 unsigned long result;
127
128 xioctl(fd, I2C_FUNCS, &result);
129 close(fd);
130
131 return result;
132 }
133
i2c_read_byte(int fd,int addr,char * byte)134 static int i2c_read_byte(int fd, int addr, char *byte)
135 {
136 union i2c_smbus_data data;
137 struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_READ,
138 .size = I2C_SMBUS_BYTE_DATA, .command = addr, .data = &data };
139
140 memset(&data, 0, sizeof(data));
141 if (ioctl(fd, I2C_SMBUS, &ioctl_data)==-1) return -1;
142 *byte = data.byte;
143
144 return 0;
145 }
146
i2c_quick_write(int fd,int addr)147 static int i2c_quick_write(int fd, int addr)
148 {
149 struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_QUICK,
150 .command = addr };
151
152 return ioctl(fd, I2C_SMBUS, &ioctl_data);
153 }
154
i2cdetect_dash_l(struct dirtree * node)155 static int i2cdetect_dash_l(struct dirtree *node)
156 {
157 char *suffix = "/name", *fname, *p;
158 int suffix_len = strlen(suffix), bus;
159 unsigned long funcs;
160
161 if (!node->parent) return DIRTREE_RECURSE; // Skip the directory itself.
162
163 if (sscanf(node->name, "i2c-%d", &bus)!=1) return 0;
164 funcs = i2c_get_funcs(bus) & I2C_FUNC_I2C;
165
166 fname = dirtree_path(node, &suffix_len);
167 strcat(fname, suffix);
168 xreadfile(fname, toybuf, sizeof(toybuf));
169 free(fname);
170 if ((p = strchr(toybuf, '\n'))) *p = 0;
171
172 // "i2c-1 i2c Synopsys DesignWare I2C adapter I2C adapter"
173 printf("%s\t%-10s\t%-32s\t%s\n", node->name, funcs ? "i2c" : "?", toybuf,
174 funcs ? "I2C Adapter" : "?");
175
176 return 0;
177 }
178
i2cdetect_main(void)179 void i2cdetect_main(void)
180 {
181 int bus, first, last, fd, addr = 0;
182 char byte;
183
184 if (FLAG(l)|FLAG(F)) {
185 if (toys.optc) error_exit("bad '%s'", *toys.optargs);
186 if (FLAG(l))
187 dirtree_flagread("/sys/class/i2c-dev", DIRTREE_SHUTUP, i2cdetect_dash_l);
188 else {
189 unsigned sup = i2c_get_funcs(TT.F), i;
190 char *funcs[] = {
191 "I2C", "10 bit", 0, "SMBus PEC", 0, 0, "SMBus Block Process Call",
192 "SMBus Quick Command", "SMBus Receive Byte", "SMBus Send Byte",
193 "SMBus Read Byte", "SMBus Write Byte", "SMBus Read Word",
194 "SMBus Write Word", "SMBus Process Call", "SMBus Read Block",
195 "SMBus Write Block", "I2C Read Block", "I2C Write Block" };
196
197 printf("Functionalities implemented by %s:\n", toybuf);
198 for (i = 0; i<ARRAY_LEN(funcs); i++)
199 if (funcs[i])
200 printf("%-32s %s\n", funcs[i], (sup&(1<<i)) ? "yes" : "no");
201 }
202
203 return;
204 }
205
206 if (!(toys.optc&1)) help_exit("Needs 1 or 3 arguments");
207 bus = atolx_range(*toys.optargs, 0, 0x3f);
208 if (toys.optc==3) {
209 first = atolx_range(toys.optargs[1], 0, 0x7f);
210 last = atolx_range(toys.optargs[2], 0, 0x7f);
211 if (first > last) error_exit("first > last");
212 } else {
213 first = FLAG(a) ? 0 : 3;
214 last = FLAG(a) ? 0x7f : 0x77;
215 }
216
217 confirm("Probe chips 0x%02x-0x%02x on bus %d?", first, last, bus);
218
219 fd = i2c_open(bus, 0, 0);
220 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
221 while (addr < 0x80) {
222 if (!(addr&0xf)) xprintf("%02x:", addr);
223 if (addr<first || addr>last) printf(" ");
224 else if (ioctl(fd, I2C_SLAVE, addr) == -1) {
225 if (errno == EBUSY) xprintf(" UU");
226 else perror_exit("ioctl(I2C_SLAVE)");
227 } else if ((FLAG(r) ? i2c_read_byte(fd, addr, &byte)
228 : i2c_quick_write(fd, addr)) == -1) xprintf(" --");
229 else xprintf(" %02x", addr);
230 if (!(++addr&0xf)) putchar('\n');
231 }
232 close(fd);
233 }
234
235 #define FOR_i2cdump
236 #include "generated/flags.h"
237
i2cdump_main(void)238 void i2cdump_main(void)
239 {
240 int fd, row, addr, bus = atolx_range(toys.optargs[0], 0, 0x3f),
241 chip = atolx_range(toys.optargs[1], 0, 0x7f);
242 char byte;
243
244 confirm("Dump chip 0x%02x on bus %d?", chip, bus);
245
246 fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
247 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef\n");
248 for (row = 0; row<0x100; row += 16) {
249 xprintf("%02x:", row & 0xf0);
250 for (addr = row; addr<row+16; ++addr) {
251 if (!i2c_read_byte(fd, addr, &byte)) printf(" %02x", byte);
252 else {
253 printf(" XX");
254 byte = 'X';
255 }
256 toybuf[addr-row] = isprint(byte) ? byte : byte ? '?' : '.';
257 }
258 printf(" %16.16s\n", toybuf);
259 }
260 close(fd);
261 }
262
263 #define FOR_i2cget
264 #include "generated/flags.h"
265
i2cget_main(void)266 void i2cget_main(void)
267 {
268 int fd, bus = atolx_range(toys.optargs[0], 0, 0x3f),
269 chip = atolx_range(toys.optargs[1], 0, 0x7f),
270 addr = (toys.optc == 3) ? atolx_range(toys.optargs[2], 0, 0xff) : -1;
271 char byte;
272
273 confirm("Read register 0x%02x from chip 0x%02x on bus %d?", addr, chip, bus);
274
275 fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
276 if (toys.optc == 3) {
277 if (i2c_read_byte(fd, addr, &byte)==-1) perror_exit("i2c_read_byte");
278 } else if (read(fd, &byte, 1) != 1) perror_exit("i2c_read");
279
280 printf("0x%02x\n", byte);
281 close(fd);
282 }
283
284 #define FOR_i2cset
285 #include "generated/flags.h"
286
i2cset_main(void)287 void i2cset_main(void)
288 {
289 int fd, i, bus = atolx_range(toys.optargs[0], 0, 0x3f),
290 chip = atolx_range(toys.optargs[1], 0, 0x7f),
291 addr = atolx_range(toys.optargs[2], 0, 0xff);
292 char *mode = toys.optargs[toys.optc-1];
293 struct i2c_smbus_ioctl_data ioctl_data;
294 union i2c_smbus_data data;
295
296 memset(&data, 0, sizeof(data));
297 if (strlen(mode)!=1) help_exit("mode too long");
298 if (*mode=='b' && toys.optc==5) {
299 ioctl_data.size = I2C_SMBUS_BYTE_DATA;
300 data.byte = atolx_range(toys.optargs[3], 0, 0xff);
301 } else if (*mode=='w' && toys.optc==5) {
302 ioctl_data.size = I2C_SMBUS_WORD_DATA;
303 data.word = atolx_range(toys.optargs[3], 0, 0xffff);
304 } else if (*mode=='i' && toys.optc>=5) {
305 if (toys.optc-4>I2C_SMBUS_BLOCK_MAX) error_exit("too much data");
306 ioctl_data.size = I2C_SMBUS_I2C_BLOCK_DATA;
307 data.block[0] = toys.optc-4;
308 for (i = 0; i<toys.optc-4; i++)
309 data.block[i+1] = atolx_range(toys.optargs[3+i], 0, 0xff);
310 } else help_exit("syntax error");
311
312 confirm("Write register 0x%02x from chip 0x%02x on bus %d?", addr, chip, bus);
313
314 // We open the device read-only and the write command works?
315 fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
316 ioctl_data.read_write = I2C_SMBUS_WRITE;
317 ioctl_data.command = addr;
318 ioctl_data.data = &data;
319 xioctl(fd, I2C_SMBUS, &ioctl_data);
320 close(fd);
321 }
322
323 #define FOR_i2ctransfer
324 #include "generated/flags.h"
325
show_msgs(FILE * fp,struct i2c_rdwr_ioctl_data * data,int before)326 static void show_msgs(FILE *fp, struct i2c_rdwr_ioctl_data *data, int before)
327 {
328 int i;
329
330 for (i = 0; i < data->nmsgs; i++) {
331 struct i2c_msg *msg = &data->msgs[i];
332 int j, write = !msg->flags, hexdump;
333
334 // Even with -v we can't show read data before it's read!
335 hexdump = (before && write) || (!before && !write) || (!before && FLAG(v));
336 if (!before && !FLAG(v) && !hexdump) continue;
337
338 if (before || FLAG(v)) {
339 fprintf(fp, "msg %d: addr 0x%02x, %s, length %u%s", i, msg->addr,
340 write ? "write" : "read", msg->len, hexdump ? ", data " : "");
341 }
342 if (hexdump) {
343 for (j = 0; j < msg->len; j++) fprintf(fp, "0x%02x ", msg->buf[j]);
344 }
345 fprintf(fp, "\n");
346 }
347 }
348
i2ctransfer_main(void)349 void i2ctransfer_main(void)
350 {
351 int fd, bus = atolx_range(toys.optargs[0], 0, 0x3f), i = 1, j;
352 char *arg, *addr_str;
353 struct i2c_rdwr_ioctl_data ioctl_data;
354 struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS], *msg;
355
356 ioctl_data.msgs = msgs;
357 ioctl_data.nmsgs = 0;
358
359 while ((arg = toys.optargs[i++])) {
360 if (ioctl_data.nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS) error_exit("too much!");
361
362 msg = &msgs[ioctl_data.nmsgs];
363 if (*arg == 'r') {
364 msg->flags = I2C_M_RD;
365 } else if (*arg == 'w') {
366 msg->flags = 0;
367 } else error_exit("expected read or write: %s", arg);
368
369 addr_str = strchr(arg, '@');
370 if (addr_str) {
371 msg->addr = atolx_range(addr_str + 1, 0, 0x7f);
372 *addr_str = '\0';
373 } else {
374 if (ioctl_data.nmsgs == 0) error_exit("missing address: %s", arg);
375 msg->addr = msgs[ioctl_data.nmsgs - 1].addr;
376 }
377
378 // The struct field is 16 bits, but the kernel (as of 6.4) limits each
379 // message to 8KiB. Either is far larger than you're likely to see in
380 // practice.
381 msg->len = atolx_range(arg + 1, 0, 0xffff);
382 msg->buf = xzalloc(msg->len);
383 if (*arg == 'w') {
384 for (j = 0; j < msg->len; j++) {
385 arg = toys.optargs[i++];
386 if (!arg) error_exit("expected %d data bytes", msg->len);
387 msg->buf[j] = atolx_range(arg, 0, 0xff);
388 }
389 }
390
391 ioctl_data.nmsgs++;
392 }
393
394 fprintf(stderr, "Will send following messages on bus %d...\n", bus);
395 show_msgs(stderr, &ioctl_data, 1);
396 confirm("Send transfers on bus %d?", bus);
397
398 fd = i2c_open(bus, 0, 0);
399 xioctl(fd, I2C_RDWR, &ioctl_data);
400 close(fd);
401
402 show_msgs(stdout, &ioctl_data, 0);
403
404 for (i = 0; i < ioctl_data.nmsgs; i++) free(msgs[i].buf);
405 }
406