1 /*
2 * Copyright (c) 2018 Prevas A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <shell/shell.h>
8 #include <stdlib.h>
9 #include <drivers/i2c.h>
10 #include <string.h>
11 #include <sys/util.h>
12 #include <stdlib.h>
13
14 #include <logging/log.h>
15 LOG_MODULE_REGISTER(i2c_shell, CONFIG_LOG_DEFAULT_LEVEL);
16
17 #define I2C_DEVICE_PREFIX "I2C_"
18
19 /* Maximum bytes we can write or read at once */
20 #define MAX_I2C_BYTES 16
21
22 /*
23 * This sends I2C messages without any data (i.e. stop condition after
24 * sending just the address). If there is an ACK for the address, it
25 * is assumed there is a device present.
26 *
27 * WARNING: As there is no standard I2C detection command, this code
28 * uses arbitrary SMBus commands (namely SMBus quick write and SMBus
29 * receive byte) to probe for devices. This operation can confuse
30 * your I2C bus, cause data loss, and is known to corrupt the Atmel
31 * AT24RF08 EEPROM found on many IBM Thinkpad laptops.
32 *
33 * https://manpages.debian.org/buster/i2c-tools/i2cdetect.8.en.html
34 */
cmd_i2c_scan(const struct shell * shell,size_t argc,char ** argv)35 static int cmd_i2c_scan(const struct shell *shell,
36 size_t argc, char **argv)
37 {
38 const struct device *dev;
39 uint8_t cnt = 0, first = 0x04, last = 0x77;
40
41 dev = device_get_binding(argv[1]);
42
43 if (!dev) {
44 shell_error(shell, "I2C: Device driver %s not found.",
45 argv[1]);
46 return -ENODEV;
47 }
48
49 shell_print(shell,
50 " 0 1 2 3 4 5 6 7 8 9 a b c d e f");
51 for (uint8_t i = 0; i <= last; i += 16) {
52 shell_fprintf(shell, SHELL_NORMAL, "%02x: ", i);
53 for (uint8_t j = 0; j < 16; j++) {
54 if (i + j < first || i + j > last) {
55 shell_fprintf(shell, SHELL_NORMAL, " ");
56 continue;
57 }
58
59 struct i2c_msg msgs[1];
60 uint8_t dst;
61
62 /* Send the address to read from */
63 msgs[0].buf = &dst;
64 msgs[0].len = 0U;
65 msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
66 if (i2c_transfer(dev, &msgs[0], 1, i + j) == 0) {
67 shell_fprintf(shell, SHELL_NORMAL,
68 "%02x ", i + j);
69 ++cnt;
70 } else {
71 shell_fprintf(shell, SHELL_NORMAL, "-- ");
72 }
73 }
74 shell_print(shell, "");
75 }
76
77 shell_print(shell, "%u devices found on %s",
78 cnt, argv[1]);
79
80 return 0;
81 }
82
cmd_i2c_recover(const struct shell * shell,size_t argc,char ** argv)83 static int cmd_i2c_recover(const struct shell *shell,
84 size_t argc, char **argv)
85 {
86 const struct device *dev;
87 int err;
88
89 dev = device_get_binding(argv[1]);
90 if (!dev) {
91 shell_error(shell, "I2C: Device driver %s not found.", argv[1]);
92 return -ENODEV;
93 }
94
95 err = i2c_recover_bus(dev);
96 if (err) {
97 shell_error(shell, "I2C: Bus recovery failed (err %d)", err);
98 return err;
99 }
100
101 return 0;
102 }
103
104 /* i2c write <device> <dev_addr> [<byte1>, ...] */
cmd_i2c_write(const struct shell * shell,size_t argc,char ** argv)105 static int cmd_i2c_write(const struct shell *shell, size_t argc, char **argv)
106 {
107 uint8_t buf[MAX_I2C_BYTES];
108 const struct device *dev;
109 int num_bytes;
110 int reg_addr;
111 int dev_addr;
112 int i;
113
114 dev = device_get_binding(argv[1]);
115 if (!dev) {
116 shell_error(shell, "I2C: Device driver %s not found.", argv[1]);
117 return -ENODEV;
118 }
119
120 dev_addr = strtol(argv[2], NULL, 16);
121 reg_addr = strtol(argv[3], NULL, 16);
122 num_bytes = argc - 4;
123 if (num_bytes < 0) {
124 return 0;
125 }
126 if (num_bytes > MAX_I2C_BYTES) {
127 num_bytes = MAX_I2C_BYTES;
128 }
129 for (i = 0; i < num_bytes; i++) {
130 buf[i] = (uint8_t)strtol(argv[4 + i], NULL, 16);
131 }
132
133 if (i2c_burst_write(dev, dev_addr, reg_addr, buf, num_bytes) < 0) {
134 shell_error(shell, "Failed to write to device: %s", argv[1]);
135 return -EIO;
136 }
137
138 return 0;
139 }
140
cmd_i2c_write_byte(const struct shell * shell,size_t argc,char ** argv)141 static int cmd_i2c_write_byte(const struct shell *shell,
142 size_t argc, char **argv)
143 {
144 const struct device *dev;
145 int reg_addr;
146 int dev_addr;
147 int out_byte;
148
149 dev = device_get_binding(argv[1]);
150 if (!dev) {
151 shell_error(shell, "I2C: Device driver %s not found.",
152 argv[1]);
153 return -ENODEV;
154 }
155
156 dev_addr = strtol(argv[2], NULL, 16);
157 reg_addr = strtol(argv[3], NULL, 16);
158 out_byte = strtol(argv[4], NULL, 16);
159
160 if (i2c_reg_write_byte(dev, dev_addr, reg_addr, out_byte) < 0) {
161 shell_error(shell, "Failed to write to device: %s", argv[1]);
162 return -EIO;
163 }
164
165 return 0;
166 }
167
cmd_i2c_read_byte(const struct shell * shell,size_t argc,char ** argv)168 static int cmd_i2c_read_byte(const struct shell *shell,
169 size_t argc, char **argv)
170 {
171 const struct device *dev;
172 int reg_addr;
173 int dev_addr;
174 uint8_t out;
175
176 dev = device_get_binding(argv[1]);
177 if (!dev) {
178 shell_error(shell, "I2C: Device driver %s not found.",
179 argv[1]);
180 return -ENODEV;
181 }
182
183 dev_addr = strtol(argv[2], NULL, 16);
184 reg_addr = strtol(argv[3], NULL, 16);
185
186 if (i2c_reg_read_byte(dev, dev_addr, reg_addr, &out) < 0) {
187 shell_error(shell, "Failed to read from device: %s", argv[1]);
188 return -EIO;
189 }
190
191 shell_print(shell, "Output: 0x%x", out);
192
193 return 0;
194 }
195
196 /* i2c read <device> <dev_addr> [<numbytes>] */
cmd_i2c_read(const struct shell * shell,size_t argc,char ** argv)197 static int cmd_i2c_read(const struct shell *shell, size_t argc, char **argv)
198 {
199 uint8_t buf[MAX_I2C_BYTES];
200 const struct device *dev;
201 int num_bytes;
202 int reg_addr;
203 int dev_addr;
204
205 dev = device_get_binding(argv[1]);
206 if (!dev) {
207 shell_error(shell, "I2C: Device driver %s not found.", argv[1]);
208 return -ENODEV;
209 }
210
211 dev_addr = strtol(argv[2], NULL, 16);
212 reg_addr = strtol(argv[3], NULL, 16);
213 if (argc > 4) {
214 num_bytes = strtol(argv[4], NULL, 16);
215 if (num_bytes > MAX_I2C_BYTES)
216 num_bytes = MAX_I2C_BYTES;
217 } else {
218 num_bytes = MAX_I2C_BYTES;
219 }
220
221 if (i2c_burst_read(dev, dev_addr, reg_addr, buf, num_bytes) < 0) {
222 shell_error(shell, "Failed to read from device: %s", argv[1]);
223 return -EIO;
224 }
225
226 shell_hexdump(shell, buf, num_bytes);
227
228 return 0;
229 }
230
231 static void device_name_get(size_t idx, struct shell_static_entry *entry);
232
233 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
234
device_name_get(size_t idx,struct shell_static_entry * entry)235 static void device_name_get(size_t idx, struct shell_static_entry *entry)
236 {
237 const struct device *dev = shell_device_lookup(idx, I2C_DEVICE_PREFIX);
238
239 entry->syntax = (dev != NULL) ? dev->name : NULL;
240 entry->handler = NULL;
241 entry->help = NULL;
242 entry->subcmd = NULL;
243 }
244
245 SHELL_STATIC_SUBCMD_SET_CREATE(sub_i2c_cmds,
246 SHELL_CMD(scan, &dsub_device_name,
247 "Scan I2C devices", cmd_i2c_scan),
248 SHELL_CMD(recover, &dsub_device_name,
249 "Recover I2C bus", cmd_i2c_recover),
250 SHELL_CMD_ARG(read, &dsub_device_name,
251 "Read bytes from an I2C device",
252 cmd_i2c_read, 3, MAX_I2C_BYTES),
253 SHELL_CMD_ARG(read_byte, &dsub_device_name,
254 "Read a byte from an I2C device",
255 cmd_i2c_read_byte, 3, 1),
256 SHELL_CMD_ARG(write, &dsub_device_name,
257 "Write bytes to an I2C device",
258 cmd_i2c_write, 3, MAX_I2C_BYTES),
259 SHELL_CMD_ARG(write_byte, &dsub_device_name,
260 "Write a byte to an I2C device",
261 cmd_i2c_write_byte, 4, 1),
262 SHELL_SUBCMD_SET_END /* Array terminated. */
263 );
264
265 SHELL_CMD_REGISTER(i2c, &sub_i2c_cmds, "I2C commands", NULL);
266