Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 503 lines (439 sloc) 12.004 kb
4bc042b initial public release v1.50
Patrick Titiano authored
1 /* ======================================================================= *//**
2 * @Component OMAPCONF
3 * @Filename i2cset.c
4 * @Description A user-space program to write an I2C register.
5 * @Copyright GPL
6 *//*======================================================================== */
7 /*
8 i2cset.c - A user-space program to write an I2C register.
9 Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
10 Mark D. Studebaker <mdsxyz123@yahoo.com>
11 Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 MA 02110-1301 USA.
27 */
28
29 #include <errno.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <i2c-dev.h>
35 #include <i2cbusses.h>
36 #include <util.h>
37 #include <version.h>
38
39 static void help(void) __attribute__ ((noreturn));
40
41 static void help(void)
42 {
43 fprintf(stderr,
44 "Usage: i2cset [-f] [-y] [-m MASK] "\
45 "I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE [MODE]]\n"
46 " I2CBUS is an integer or an I2C bus name\n"
47 " ADDRESS is an integer (0x03 - 0x77)\n"
48 " MODE is one of:\n"
49 " b (byte, default)\n"
50 " w (word)\n"
51 " Append p for SMBus PEC\n");
52 exit(1);
53 }
54
55 static int check_funcs(int file, int size, int pec)
56 {
57 unsigned long funcs;
58
59 /* check adapter functionality */
60 if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
61 fprintf(stderr, "Error: Could not get the adapter "
62 "functionality matrix: %s\n", strerror(errno));
63 return -1;
64 }
65
66 switch (size) {
67 case I2C_SMBUS_BYTE:
68 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
69 fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
70 return -1;
71 }
72 break;
73
74 case I2C_SMBUS_BYTE_DATA:
75 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
76 fprintf(stderr, MISSING_FUNC_FMT, "SMBus write byte");
77 return -1;
78 }
79 break;
80
81 case I2C_SMBUS_WORD_DATA:
82 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
83 fprintf(stderr, MISSING_FUNC_FMT, "SMBus write word");
84 return -1;
85 }
86 break;
87 }
88
89 if (pec
90 && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
91 fprintf(stderr, "Warning: Adapter does "
92 "not seem to support PEC\n");
93 }
94
95 return 0;
96 }
97
98 static int confirm(const char *filename, int address, int size, int daddress,
99 int value, int vmask, int pec)
100 {
101 int dont = 0;
102
103 fprintf(stderr, "WARNING! This program can confuse your I2C "
104 "bus, cause data loss and worse!\n");
105
106 if (address >= 0x50 && address <= 0x57) {
107 fprintf(stderr, "DANGEROUS! Writing to a serial "
108 "EEPROM on a memory DIMM\nmay render your "
109 "memory USELESS and make your system "
110 "UNBOOTABLE!\n");
111 dont++;
112 }
113
114 fprintf(stderr, "I will write to device file %s, chip address "
115 "0x%02x, data address\n0x%02x, ", filename, address, daddress);
116 if (size == I2C_SMBUS_BYTE)
117 fprintf(stderr, "no data.\n");
118 else
119 fprintf(stderr, "data 0x%02x%s, mode %s.\n", value,
120 vmask ? " (masked)" : "",
121 size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
122 if (pec)
123 fprintf(stderr, "PEC checking enabled.\n");
124
125 fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
126 fflush(stderr);
127 if (!user_ack(!dont)) {
128 fprintf(stderr, "Aborting on user request.\n");
129 return 0;
130 }
131
132 return 1;
133 }
134
135 int main_i2cset(int argc, char *argv[])
136 {
137 char *end;
138 const char *maskp = NULL;
139 int res, i2cbus, address, size, file;
140 int value, daddress, vmask = 0;
141 char filename[20];
142 int pec = 0;
143 int flags = 0;
144 int force = 0, yes = 0, version = 0, readback = 0;
145 int index, loopcount = 1;
146
147 /* handle (optional) flags first */
148 while (1+flags < argc && argv[1+flags][0] == '-') {
149 switch (argv[1+flags][1]) {
150 case 'V': version = 1; break;
151 case 'f': force = 1; break;
152 case 'y': yes = 1; break;
153 case 'm':
154 if (2+flags < argc)
155 maskp = argv[2+flags];
156 flags++;
157 break;
158 case 'r': readback = 1; break;
159 default:
160 fprintf(stderr, "Error: Unsupported option "
161 "\"%s\"!\n", argv[1+flags]);
162 help();
163 exit(1);
164 }
165 flags++;
166 }
167
168 if (version) {
169 fprintf(stderr, "i2cset version %s\n", VERSION);
170 exit(0);
171 }
172
173 if (argc < flags + 4)
174 help();
175
176 i2cbus = lookup_i2c_bus(argv[flags+1]);
177 if (i2cbus < 0)
178 help();
179
180 address = parse_i2c_address(argv[flags+2]);
181 if (address < 0)
182 help();
183
184 daddress = strtol(argv[flags+3], &end, 0);
185 if (*end || daddress < 0 || daddress > 0xff) {
186 fprintf(stderr, "Error: Data address invalid!\n");
187 help();
188 }
189
190 if (argc > flags + 4) {
191 size = I2C_SMBUS_BYTE_DATA;
192 value = strtol(argv[flags+4], &end, 0);
193 if (*end || value < 0) {
194 fprintf(stderr, "Error: Data value invalid!\n");
195 help();
196 }
197 } else {
198 size = I2C_SMBUS_BYTE;
199 value = -1;
200 }
201
202 if (argc > flags + 5) {
203 switch (argv[flags+5][0]) {
204 case 'b': size = I2C_SMBUS_BYTE_DATA; break;
205 case 'w': size = I2C_SMBUS_WORD_DATA; break;
206 default:
207 fprintf(stderr, "Error: Invalid mode!\n");
208 help();
209 }
210 pec = argv[flags+5][1] == 'p';
211 }
212
213 /* Old method to provide the value mask, deprecated and no longer
214 documented but still supported for compatibility */
215 if (argc > flags + 6) {
216 if (maskp) {
217 fprintf(stderr, "Error: Data value mask provided twice!\n");
218 help();
219 }
220 fprintf(stderr, "Warning: Using deprecated way to set the data value mask!\n");
221 fprintf(stderr, " Please switch to using -m.\n");
222 maskp = argv[flags+6];
223 }
224 if (argc > flags + 7)
225 loopcount = strtol(argv[flags+7], &end, 0);
226 if (*end || loopcount < 1) {
227 fprintf(stderr, "Error: Loop Count invalid!\n");
228 help();
229 }
230
231 if (maskp) {
232 vmask = strtol(maskp, &end, 0);
233 if (*end || vmask == 0) {
234 fprintf(stderr, "Error: Data value mask invalid!\n");
235 help();
236 }
237 }
238
239 if ((size == I2C_SMBUS_BYTE_DATA && value > 0xff)
240 || (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) {
241 fprintf(stderr, "Error: Data value out of range!\n");
242 help();
243 }
244
245 file = open_i2c_dev(i2cbus, filename, 0);
246 if (file < 0
247 || check_funcs(file, size, pec)
248 || set_slave_addr(file, address, force))
249 exit(1);
250
251 if (!yes && !confirm(filename, address, size, daddress,
252 value, vmask, pec))
253 exit(0);
254
255 if (vmask) {
256 int oldvalue;
257
258 switch (size) {
259 case I2C_SMBUS_BYTE:
260 oldvalue = i2c_smbus_read_byte(file);
261 break;
262 case I2C_SMBUS_WORD_DATA:
263 oldvalue = i2c_smbus_read_word_data(file, daddress);
264 break;
265 default:
266 oldvalue = i2c_smbus_read_byte_data(file, daddress);
267 }
268
269 if (oldvalue < 0) {
270 fprintf(stderr, "Error: Failed to read old value\n");
271 exit(1);
272 }
273
274 value = (value & vmask) | (oldvalue & ~vmask);
275
276 if (!yes) {
277 fprintf(stderr, "Old value 0x%0*x, write mask "
278 "0x%0*x: Will write 0x%0*x to register "
279 "0x%02x\n",
280 size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue,
281 size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask,
282 size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
283 daddress);
284
285 fprintf(stderr, "Continue? [Y/n] ");
286 fflush(stderr);
287 if (!user_ack(1)) {
288 fprintf(stderr, "Aborting on user request.\n");
289 exit(0);
290 }
291 }
292 }
293
294 if (pec && ioctl(file, I2C_PEC, 1) < 0) {
295 fprintf(stderr, "Error: Could not set PEC: %s\n",
296 strerror(errno));
297 close(file);
298 exit(1);
299 }
300 for (index = 0; index < loopcount; index++) {
301 switch (size) {
302 case I2C_SMBUS_BYTE:
303 res = i2c_smbus_write_byte(file, daddress);
304 break;
305 case I2C_SMBUS_WORD_DATA:
306 res = i2c_smbus_write_word_data(file, daddress, value);
307 break;
308 default: /* I2C_SMBUS_BYTE_DATA */
309 res = i2c_smbus_write_byte_data(file, daddress, value);
310 }
311 if (res < 0) {
312 fprintf(stderr, "Error: Write failed\n");
313 close(file);
314 exit(1);
315 }
316
317 if (pec) {
318 if (ioctl(file, I2C_PEC, 0) < 0) {
319 fprintf(stderr, "Error: Could not clear PEC: %s\n",
320 strerror(errno));
321 close(file);
322 exit(1);
323 }
324 }
325
326 if (!readback) {
327 /* We're done */
328 close(file);
329 exit(0);
330 }
331
332 switch (size) {
333 case I2C_SMBUS_BYTE:
334 res = i2c_smbus_read_byte(file);
335 value = daddress;
336 break;
337 case I2C_SMBUS_WORD_DATA:
338 res = i2c_smbus_read_word_data(file, daddress);
339 break;
340 default: /* I2C_SMBUS_BYTE_DATA */
341 res = i2c_smbus_read_byte_data(file, daddress);
342 }
343
344 if (res < 0)
345 printf("Warning - readback failed\n");
346 else
347 if (res != value) {
348 printf("Warning - data mismatch - wrote "
349 "0x%0*x, read back 0x%0*x\n",
350 size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
351 size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
352 } else {
353 printf("Value 0x%0*x written, readback matched\n",
354 size == I2C_SMBUS_WORD_DATA ? 4 : 2, value);
355 }
356
357 }
358 close(file);
359 exit(0);
360 }
361
362
363 /**
364 * Function: i2cset
365 * Role: write given data at given address of given device of given I2C bus
366 * Parameters:
367 * i2cbus: I2C bus number
368 * address: I2C device address
369 * daddress: I2C device register address
370 * data: data to be written
371 * Return:
372 * 0 in case of success
373 * -1 in case of incorrect argument
374 * -8 in case of i2c dev cannot be opened
375 * -4 in case of I2C read error
376 */
377 int i2cset(
378 unsigned int i2cbus, unsigned int address, unsigned int daddress,
379 unsigned int data)
380 {
381 int res, file;
382 char filename[20];
383
384 if (i2cbus > 0xFF) {
385 printf("Error: I2C bus out of range (0-255)!\n");
386 return -1;
387 }
388
389 if (address > 0xFF) {
390 printf("Error: Chip address invalid!\n");
391 return -1;
392 }
393
394 if (daddress > 0xFF) {
395 printf("Error: Data address invalid!\n");
396 return -1;
397 }
398
399 if (data > 0xFF) {
400 printf("Error: Data invalid!\n");
401 return -1;
402 }
403
404 file = open_i2c_dev(i2cbus, filename, 1);
405 if (file < 0
406 || check_funcs(file, I2C_SMBUS_BYTE_DATA, 0)
407 || set_slave_addr(file, address, 1))
408 return -8;
409
410 res = i2c_smbus_write_byte_data(file, daddress, data);
411 if (res < 0) {
412 fprintf(stderr, "Error: Write failed!\n");
413 close(file);
414 return -4;
415 }
416
417 res = i2c_smbus_read_byte_data(file, daddress);
418 close(file);
419 if (res < 0) {
420 printf("Warning - readback failed\n");
421 return -4;
422 } else {
423 if (res != (int) data) {
424 printf("Warning - data mismatch - wrote "
425 "0x%02x, read back 0x%02x\n", data, res);
426 return -4;
427 } else {
428 return 0;
429 }
430 }
431 }
432
433
434 /**
435 * Function: i2cset_word
436 * Role: write given data at given address of given device of given I2C bus
437 * Parameters:
438 * i2cbus: I2C bus number
439 * address: I2C device address
440 * daddress: I2C device register address
441 * data: data to be written
442 * Return:
443 * 0 in case of success
444 * -1 in case of incorrect argument
445 * -8 in case of i2c dev cannot be opened
446 * -4 in case of I2C read error
447 */
448 int i2cset_word(
449 unsigned int i2cbus, unsigned int address, unsigned int daddress,
450 unsigned int data)
451 {
452 int res, file;
453 char filename[20];
454
455 if (i2cbus > 0xFF) {
456 printf("Error: I2C bus out of range (0-255)!\n");
457 return -1;
458 }
459
460 if (address > 0xFF) {
461 printf("Error: Chip address invalid!\n");
462 return -1;
463 }
464
465 if (daddress > 0xFF) {
466 printf("Error: Data address invalid!\n");
467 return -1;
468 }
469
470 if (data > 0xFFFF) {
471 printf("Error: Data invalid!\n");
472 return -1;
473 }
474
475 file = open_i2c_dev(i2cbus, filename, 1);
476 if (file < 0
477 || check_funcs(file, I2C_SMBUS_WORD_DATA, 0)
478 || set_slave_addr(file, address, 1))
479 return -8;
480
481 res = i2c_smbus_write_word_data(file, daddress, data);
482 if (res < 0) {
483 fprintf(stderr, "Error: Write failed!\n");
484 close(file);
485 return -4;
486 }
487
488 res = i2c_smbus_read_word_data(file, daddress);
489 close(file);
490 if (res < 0) {
491 printf("Warning - readback failed\n");
492 return -4;
493 } else {
494 if (res != (int) data) {
495 printf("Warning - data mismatch - wrote "
496 "0x%02x, read back 0x%02x\n", data, res);
497 return -4;
498 } else {
499 return 0;
500 }
501 }
502 }
Something went wrong with that request. Please try again.