i2ctools.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. USE_I2CDETECT(NEWTOY(i2cdetect, ">3aFlqry[!qr]", TOYFLAG_USR|TOYFLAG_BIN))
  14. USE_I2CDUMP(NEWTOY(i2cdump, "<2>2fy", TOYFLAG_USR|TOYFLAG_BIN))
  15. USE_I2CGET(NEWTOY(i2cget, "<3>3fy", TOYFLAG_USR|TOYFLAG_BIN))
  16. USE_I2CSET(NEWTOY(i2cset, "<4fy", TOYFLAG_USR|TOYFLAG_BIN))
  17. config I2CDETECT
  18. bool "i2cdetect"
  19. default y
  20. help
  21. usage: i2cdetect [-aqry] BUS [FIRST LAST]
  22. usage: i2cdetect -F BUS
  23. usage: i2cdetect -l
  24. Detect i2c devices.
  25. -a All addresses (0x00-0x7f rather than 0x03-0x77 or FIRST-LAST)
  26. -F Show functionality
  27. -l List available buses
  28. -q Probe with SMBus Quick Write (default)
  29. -r Probe with SMBus Read Byte
  30. -y Answer "yes" to confirmation prompts (for script use)
  31. config I2CDUMP
  32. bool "i2cdump"
  33. default y
  34. help
  35. usage: i2cdump [-fy] BUS CHIP
  36. Dump i2c registers.
  37. -f Force access to busy devices
  38. -y Answer "yes" to confirmation prompts (for script use)
  39. config I2CGET
  40. bool "i2cget"
  41. default y
  42. help
  43. usage: i2cget [-fy] BUS CHIP ADDR
  44. Read an i2c register.
  45. -f Force access to busy devices
  46. -y Answer "yes" to confirmation prompts (for script use)
  47. config I2CSET
  48. bool "i2cset"
  49. default y
  50. help
  51. usage: i2cset [-fy] BUS CHIP ADDR VALUE... MODE
  52. Write an i2c register. MODE is b for byte, w for 16-bit word, i for I2C block.
  53. -f Force access to busy devices
  54. -y Answer "yes" to confirmation prompts (for script use)
  55. */
  56. #define FOR_i2cdetect
  57. #define TT this.i2ctools
  58. #include "toys.h"
  59. #include <linux/i2c.h>
  60. #include <linux/i2c-dev.h>
  61. printf_format static void confirm(const char *fmt, ...)
  62. {
  63. va_list va;
  64. if (FLAG(y)) return;
  65. va_start(va, fmt);
  66. vfprintf(stderr, fmt, va);
  67. va_end(va);
  68. if (!yesno(1)) error_exit("Exiting");
  69. }
  70. static int i2c_open(int bus, int slave, int chip)
  71. {
  72. int fd;
  73. snprintf(toybuf, sizeof(toybuf), "/dev/i2c-%d", bus);
  74. fd = xopen(toybuf, O_RDONLY);
  75. if (slave) xioctl(fd, slave, (void *)(long)chip);
  76. return fd;
  77. }
  78. static unsigned long i2c_get_funcs(int bus)
  79. {
  80. int fd = i2c_open(bus, 0, 0);
  81. unsigned long result;
  82. xioctl(fd, I2C_FUNCS, &result);
  83. close(fd);
  84. return result;
  85. }
  86. static int i2c_read_byte(int fd, int addr, int *byte)
  87. {
  88. union i2c_smbus_data data;
  89. struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_READ,
  90. .size = I2C_SMBUS_BYTE_DATA, .command = addr, .data = &data };
  91. memset(&data, 0, sizeof(data));
  92. if (ioctl(fd, I2C_SMBUS, &ioctl_data)==-1) return -1;
  93. *byte = data.byte;
  94. return 0;
  95. }
  96. static int i2c_quick_write(int fd, int addr)
  97. {
  98. struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_QUICK,
  99. .size = 0, .command = addr };
  100. return ioctl(fd, I2C_SMBUS, &ioctl_data);
  101. }
  102. static void i2cdetect_dash_F(int bus)
  103. {
  104. struct { int mask; const char *name; } funcs[] = {
  105. {I2C_FUNC_I2C, "I2C"},
  106. {I2C_FUNC_SMBUS_QUICK, "SMBus Quick Command"},
  107. {I2C_FUNC_SMBUS_WRITE_BYTE, "SMBus Send Byte"},
  108. {I2C_FUNC_SMBUS_READ_BYTE, "SMBus Receive Byte"},
  109. {I2C_FUNC_SMBUS_WRITE_BYTE_DATA, "SMBus Write Byte"},
  110. {I2C_FUNC_SMBUS_READ_BYTE_DATA, "SMBus Read Byte"},
  111. {I2C_FUNC_SMBUS_WRITE_WORD_DATA, "SMBus Write Word"},
  112. {I2C_FUNC_SMBUS_READ_WORD_DATA, "SMBus Read Word"},
  113. {I2C_FUNC_SMBUS_PROC_CALL, "SMBus Process Call"},
  114. {I2C_FUNC_SMBUS_WRITE_BLOCK_DATA, "SMBus Write Block"},
  115. {I2C_FUNC_SMBUS_READ_BLOCK_DATA, "SMBus Read Block"},
  116. {I2C_FUNC_SMBUS_BLOCK_PROC_CALL, "SMBus Block Process Call"},
  117. {I2C_FUNC_SMBUS_PEC, "SMBus PEC"},
  118. {I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, "I2C Write Block"},
  119. {I2C_FUNC_SMBUS_READ_I2C_BLOCK, "I2C Read Block"},
  120. };
  121. unsigned long sup = i2c_get_funcs(bus);
  122. int i;
  123. printf("Functionalities implemented by %s:\n", toybuf);
  124. for (i = 0; i < ARRAY_LEN(funcs); ++i)
  125. printf("%-32s %s\n", funcs[i].name, (sup & funcs[i].mask) ? "yes" : "no");
  126. }
  127. static int i2cdetect_dash_l(struct dirtree *node)
  128. {
  129. int suffix_len = strlen("/name");
  130. int bus;
  131. char *fname, *p;
  132. unsigned long funcs;
  133. if (!node->parent) return DIRTREE_RECURSE; // Skip the directory itself.
  134. if (sscanf(node->name, "i2c-%d", &bus)!=1) return 0;
  135. funcs = i2c_get_funcs(bus);
  136. fname = dirtree_path(node, &suffix_len);
  137. strcat(fname, "/name");
  138. xreadfile(fname, toybuf, sizeof(toybuf));
  139. free(fname);
  140. if ((p = strchr(toybuf, '\n'))) *p = 0;
  141. // "i2c-1 i2c Synopsys DesignWare I2C adapter I2C adapter"
  142. printf("%s\t%-10s\t%-32s\t%s\n", node->name,
  143. (funcs & I2C_FUNC_I2C) ? "i2c" : "?", toybuf,
  144. (funcs & I2C_FUNC_I2C) ? "I2C Adapter" : "?");
  145. return 0;
  146. }
  147. void i2cdetect_main(void)
  148. {
  149. if (FLAG(l)) {
  150. if (toys.optc) error_exit("-l doesn't take arguments");
  151. dirtree_flagread("/sys/class/i2c-dev", DIRTREE_SHUTUP, i2cdetect_dash_l);
  152. } else if (FLAG(F)) {
  153. if (toys.optc != 1) error_exit("-F BUS");
  154. i2cdetect_dash_F(atolx_range(*toys.optargs, 0, INT_MAX));
  155. } else {
  156. int bus, first = 0x03, last = 0x77, fd, row, addr, byte;
  157. if (FLAG(a)) {
  158. first = 0x00;
  159. last = 0x7f;
  160. }
  161. if (toys.optc!=1 && toys.optc!=3) help_exit("Needs 1 or 3 arguments");
  162. bus = atolx_range(*toys.optargs, 0, INT_MAX);
  163. if (toys.optc==3) {
  164. first = atolx_range(toys.optargs[1], 0, 0x7f);
  165. last = atolx_range(toys.optargs[2], 0, 0x7f);
  166. if (first > last) error_exit("first > last");
  167. }
  168. confirm("Probe chips 0x%02x-0x%02x on bus %d?", first, last, bus);
  169. fd = i2c_open(bus, 0, 0);
  170. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
  171. for (row = 0; row <= 0x70; row += 16) {
  172. xprintf("%02x:", row & 0xf0);
  173. for (addr = row; addr<row+16; ++addr) {
  174. if (addr<first || addr>last) printf(" ");
  175. else {
  176. if (ioctl(fd, I2C_SLAVE, addr) == -1) {
  177. if (errno == EBUSY) {
  178. xprintf(" UU");
  179. continue;
  180. }
  181. perror_exit("ioctl(I2C_SLAVE)");
  182. }
  183. if ((FLAG(r) ? i2c_read_byte(fd, addr, &byte)
  184. : i2c_quick_write(fd, addr)) == -1) xprintf(" --");
  185. else xprintf(" %02x", addr);
  186. }
  187. }
  188. putchar('\n');
  189. }
  190. close(fd);
  191. }
  192. }
  193. #define FOR_i2cdump
  194. #include "generated/flags.h"
  195. void i2cdump_main(void)
  196. {
  197. int bus = atolx_range(toys.optargs[0], 0, INT_MAX);
  198. int chip = atolx_range(toys.optargs[1], 0, 0x7f);
  199. int fd, row, addr, byte;
  200. confirm("Dump chip 0x%02x on bus %d?", chip, bus);
  201. fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
  202. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef\n");
  203. for (row = 0; row<=0xf0; row += 16) {
  204. xprintf("%02x:", row & 0xf0);
  205. for (addr = row; addr<row+16; ++addr) {
  206. if (!i2c_read_byte(fd, addr, &byte)) printf(" %02x", byte);
  207. else {
  208. printf(" XX");
  209. byte = 'X';
  210. }
  211. toybuf[addr-row] = isprint(byte) ? byte : (byte ? '?' : '.');
  212. }
  213. printf(" %16.16s\n", toybuf);
  214. }
  215. close(fd);
  216. }
  217. #define FOR_i2cget
  218. #include "generated/flags.h"
  219. void i2cget_main(void)
  220. {
  221. int bus = atolx_range(toys.optargs[0], 0, INT_MAX);
  222. int chip = atolx_range(toys.optargs[1], 0, 0x7f);
  223. int addr = atolx_range(toys.optargs[2], 0, 0xff);
  224. int fd, byte;
  225. confirm("Read register 0x%02x from chip 0x%02x on bus %d?", addr, chip, bus);
  226. fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
  227. if (i2c_read_byte(fd, addr, &byte)==-1) perror_exit("i2c_read_byte");
  228. printf("0x%02x\n", byte);
  229. close(fd);
  230. }
  231. #define FOR_i2cset
  232. #include "generated/flags.h"
  233. void i2cset_main(void)
  234. {
  235. int bus = atolx_range(toys.optargs[0], 0, INT_MAX);
  236. int chip = atolx_range(toys.optargs[1], 0, 0x7f);
  237. int addr = atolx_range(toys.optargs[2], 0, 0xff);
  238. char *mode = toys.optargs[toys.optc-1];
  239. int fd, i;
  240. struct i2c_smbus_ioctl_data ioctl_data;
  241. union i2c_smbus_data data;
  242. memset(&data, 0, sizeof(data));
  243. if (strlen(mode)!=1) help_exit("mode too long");
  244. if (*mode=='b' && toys.optc==5) {
  245. ioctl_data.size = I2C_SMBUS_BYTE_DATA;
  246. data.byte = atolx_range(toys.optargs[3], 0, 0xff);
  247. } else if (*mode=='w' && toys.optc==5) {
  248. ioctl_data.size = I2C_SMBUS_WORD_DATA;
  249. data.word = atolx_range(toys.optargs[3], 0, 0xffff);
  250. } else if (*mode=='i' && toys.optc>=5) {
  251. if (toys.optc-4>I2C_SMBUS_BLOCK_MAX) error_exit("too much data");
  252. ioctl_data.size = I2C_SMBUS_I2C_BLOCK_DATA;
  253. for (i = 0; i<toys.optc-4; ++i)
  254. data.block[i+1] = atolx_range(toys.optargs[3+i], 0, 0xff);
  255. data.block[0] = toys.optc-4;
  256. } else help_exit("syntax error");
  257. confirm("Write register 0x%02x from chip 0x%02x on bus %d?", addr, chip, bus);
  258. fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
  259. ioctl_data.read_write = I2C_SMBUS_WRITE;
  260. ioctl_data.command = addr;
  261. ioctl_data.data = &data;
  262. xioctl(fd, I2C_SMBUS, &ioctl_data);
  263. close(fd);
  264. }