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