Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 656 lines (525 sloc) 15.085 kb
5ab8537 working version of bqupdate.c
daveriess authored
1 /*
2 bqupdate.c - a user-space utility for updating bq27x00 fuel gauges.
3
4 Please have a look at the README
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include "i2c-dev.h"
27 #include <unistd.h>
28
29 //global vars
30 int i2c_dev_handle;
31
32 static void help(void)
33 {
34 fprintf(stderr,
35 "\nUsage: bqupdate I2CBUS GOLDEN_DFI\n"
36 " I2CBUS is an integer - look in /sys/class/i2c-dev\n"
37 " FILE is a 'Golden Image' dfi generated by b-queasy\n");
38 }
39
40 //use to write single bytes
41 int bq_write(char reg, char data)
42 {
43 int err = 0;
44 char i2c_buf[2];
45
46 i2c_buf[0] = reg;
47 i2c_buf[1] = data;
48 err = write(i2c_dev_handle, i2c_buf, 2);
49
50 if (err != 2) {
51 fprintf(stderr, "\nError: 0x%x - i2c transaction failure! a \n", err);
52 return -1;
53 }
54
55 return 0;
56 }
57
58 int bq_read(char reg, int bytes, char *i2c_buf)
59 {
60 int err = 0;
61
62 i2c_buf[0] = reg;
63 err = write(i2c_dev_handle, i2c_buf, 1);
64 if (err != 1) {
65 fprintf(stderr, "\nError: 0x%x - i2c transaction failure! b \n", err);
66 }
67
68 err = read(i2c_dev_handle, i2c_buf, bytes);
69 if (err != bytes) {
70 fprintf(stderr, "\nError: 0x%x - i2c transaction failure! bb \n", err);
71 return -1;
72 }
73
74 return 0;
75 }
76
77 int error_check(void)
78 {
79 int err;
80 char i2c_buf[2];
81
82 i2c_buf[0] = 0x66;
83 err = write(i2c_dev_handle, i2c_buf, 1);
84 if (err != 1) {
85 fprintf(stderr, "Error reading 0x66: %x\n", err);
86 }
87
88 err = read(i2c_dev_handle, i2c_buf, 1);
89 if (err != 1) {
90 fprintf(stderr, "Error reading 0x66 %x\n", err);
91 }
92
93 if (i2c_buf[0] != 0x00) {
94 printf("ErrorCheck: Error - 0x66: %x\n", i2c_buf[0]);
95 return -1;
96 }
97 //else {
98 // printf("ErrorCheck: Clean - 0x66: %x\n", i2c_buf[0]);
99 //}
100
101 return 0;
102 }
103
104 int main(int argc, char *argv[])
105 {
106 //i2c vars
107 char i2c_dev_name[20];
108 long i2c_bus;
109 char i2c_buf[100];
110 int i2c_address;
111 int error_reg;
112
113 //gimage vars
114 char gimage_name[50];
115 FILE *gimage_file;
116 long gimage_length;
117 char *gimage_data;
118
119 //some flash related vars
120 char yIFRowData_0[97];
121 char yIFRowData_1[97];
122 char yRowData[33];
123 int iRow;
124 long int checksum;
125 long int checksum0;
126 long int checksum1;
127 long int dfi_checksum;
128 int dfi_checksum_rd;
129 FILE *ifrow_file;
130
131 //other vars
132 int i;
133 int err;
134 int loops;
135 int write_loops;
136 int version;
137
138 //Grab the bus ID
139 if (argc < 2) {
140 fprintf(stderr, "\nError: Please specify i2c bus ID\n");
141 help();
142 exit(1);
143 }
144
145 i2c_bus = strtol(argv[1], NULL, 0);
146 if (i2c_bus < 0 || i2c_bus > 0xff) {
147 fprintf(stderr, "\nInvalid bus ID\n");
148 exit(1);
149 }
150
151 //Grab the golden image file name
152 if (argc < 3) {
153 fprintf(stderr, "\nError: Please specify a golden image dfi\n");
154 help();
155 exit(1);
156 }
157
158 strcpy(gimage_name, argv[2]);
159 if (gimage_name == NULL) {
160 fprintf(stderr, "\nInvalid golden image\n");
161 exit(1);
162 }
163
164 //Throw error for too many args
165 if (argc > 3) {
166 fprintf(stderr, "\nError: Too many arguments!\n");
167 help();
168 exit(1);
169 }
170
171 /* Read the golden image */
172 printf("\nReading %s...\n", gimage_name);
173 gimage_file = fopen(gimage_name, "r");
174
175 // check length
176 fseek(gimage_file, 0 , SEEK_END);
177 gimage_length = ftell(gimage_file);
178 fseek(gimage_file, 0, SEEK_SET);
179
180 if (gimage_length != 0x401) {
181 printf("DFI might be wrong size, could cause problems...\n");
182 }
183
184 // read file
185 gimage_data = (char*)malloc(0x3ff);
186 fread(gimage_data, 1, 0x3ff, gimage_file);
187 fclose(gimage_file);
188
189 /* i2c setup */
190 i2c_address = 0x55;
191
192 sprintf(i2c_dev_name, "/dev/i2c-%d", i2c_bus);
193 i2c_dev_handle = open(i2c_dev_name, O_RDWR);
194
195 if (i2c_dev_handle < 0) {
196 fprintf(stderr, "\nError: Failed to open %s!\n", i2c_dev_name);
197 goto ESCAPE;
198 }
199
200 err = ioctl(i2c_dev_handle, I2C_SLAVE, i2c_address);
201 if (err < 0) {
202 fprintf(stderr, "\nError: Some kind of ioctl error!\n");
203 goto ESCAPE;
204 }
205
206 /* check firmware version */
207 version = 0;
208
209 err = bq_write(0x00, 0x02);
210 err = bq_write(0x01, 0x00);
211 err |= bq_read(0x00, 2, i2c_buf);
212
213 if (!err)
214 version = (i2c_buf[0] + (i2c_buf[1] << 8));
215 else
216 printf("Unable to get version.");
217
218 printf("\nCurrent firmware version: %x \n", version);
219 if (version != 0x120) {
220 printf("Firmware version mismatch! Exiting\n");
221 exit(1);
222 }
223
224 /* begin IF copy */
225
226 printf("Enter ROM mode...\n");
227 err = bq_write(0x00, 0x00);
228 err |= bq_write(0x01, 0x0F);
229
230 if (err != 0) {
231 fprintf(stderr, "\nError: Might still be in ROM mode!\n");
232 goto ESCAPE_ROM;
233 }
234
235 //error_check();
236
237 printf("Begin IF copy...\n");
238 iRow = 0;
239
240 while (iRow < 2) {
241 // setup i2c to use address 0x0b
242 i2c_address = 0x0b;
243 err = ioctl(i2c_dev_handle, I2C_SLAVE, i2c_address);
244 if (err < 0) { fprintf(stderr, "\nError: Some kind of super tragic ioctl error!\n"); goto ESCAPE_ROM; }
245 usleep(20);
246
247 // => write 0x00/0x00
248 err = bq_write(0x00, 0x00);
249 // => write 0x00/0x00+iRow
250 err |= bq_write(0x01, 0x00+iRow);
251 // => write 0x02/0x00
252 err |= bq_write(0x02, 0x00);
253 // => write 0x64/0x00+iRow
254 err |= bq_write(0x64, 0x00+iRow);
255 // => write 0x65/0x00
256 err |= bq_write(0x65, 0x00);
257
258 // => read 96 bytes from 0x04 to 0x63 into yIFRowData_iRow
259 if (iRow == 0)
260 err |= bq_read(0x04, 96, yIFRowData_0);
261 else if (iRow == 1)
262 err |= bq_read(0x04, 96, yIFRowData_1);
263
264 if (err != 0x00) {
265 printf("Error reading from IF row %d...\n", iRow);
266 goto ESCAPE_ROM;
267 }
268
269 //sleep 20ms
270 usleep(20000);
271
272 iRow++;
273 }
274
275 printf("IF copy successful.\n");
276
277 /* save IF rows to a file */
278
279 ifrow_file = fopen("ifrows.bin", "wb");
280 fwrite(yIFRowData_0, sizeof(yIFRowData_0[0]), sizeof(yIFRowData_0)/sizeof(yIFRowData_0[0]), ifrow_file);
281 fwrite(yIFRowData_1, sizeof(yIFRowData_1[0]), sizeof(yIFRowData_1)/sizeof(yIFRowData_1[0]), ifrow_file);
282 fclose(ifrow_file);
283
284
285 IF_ERASE:
286
287 /* Begin erase */
288 printf("Begin IF erase...\n");
289
290 error_reg = -1;
291 loops = 0;
292 while (error_reg != 0) {
293 // => write 0x00/0x03
294 err = bq_write(0x00, 0x03);
295 // => write 0x01/0x00
296 err = bq_write(0x01, 0x00);
297 // => write 0x64/0x03
298 err |= bq_write(0x64, 0x03);
299 // => write 0x65/0x00
300 err |= bq_write(0x65, 0x00);
301 //sleep 20ms
302 usleep(20000);
303
304 if (!err) {
305 printf("Row %d successfully erased\n", iRow);
306 }
307 else {
308 printf("Encountered an error erasing row %d\n", iRow);
309 goto ESCAPE;
310 }
311
312 //check 0x66
313 error_reg = error_check();
314 if (!error_reg) {
315 printf("Error check verifies first two lines are clear.\n");
316 }
317 else {
318 loops ++;
319 printf("Attempt %d: Invalid value in reg 0x66...\n", loops);
320 }
321
322 if (loops > 5) {
323 printf("Flash erase failed, check setup...\n");
324 goto ESCAPE;
325 }
326
327 }
328
329 //sleep 20ms
330 usleep(20000);
331
332 /* Mass erase data flash */
333 write_loops = 0;
334
335 WRITE_IMG:
336
337 printf("Begin mass erase...\n");
338 checksum = 0;
339 dfi_checksum = 0;
340 error_reg = -1;
341 loops = 0;
342
343 while (error_reg != 0) {
344 // => write 0x00/0x0C
345 err = bq_write(0x00, 0x0C);
346 // => write 0x01/0x00
347 err = bq_write(0x01, 0x00);
348 // => write 0x04/0x83
349 err |= bq_write(0x04, 0x83);
350 // => write 0x05/0xde
351 err |= bq_write(0x05, 0xde);
352 // => write 0x64/0x6D
353 err |= bq_write(0x64, 0x6D);
354 // => write 0x65/0x01
355 err |= bq_write(0x65, 0x01);
356
357 //sleep 200ms
358 usleep(200000);
359
360 //read back 0x66
361 error_reg = error_check();
362 if (!error_reg) {
363 printf("Mass erase successful.\n");
364 }
365 else {
366 loops ++;
367 printf("Attempt %d: Invalid value in reg 0x66...\n", loops);
368 }
369
370 if (loops > 5) {
371 printf("Mass erase failed, check setup...\n");
372 goto WRITEBACK_ROWS;
373 }
374
375 }
376
377 /* Begin writing image */
378 printf("\nBegin writing image:\n");
379
380 iRow = 0;
381 error_reg = -1;
382
383 while (iRow < 32) {
384 // copy 32 bytes of data from gimage_data into yRowData
385 checksum = 0;
386 yRowData[0] = 0x04; //write row command
387 //printf("Row %2d: ", iRow);
388 for (i = 0; i < 32; i++) {
389 yRowData[i+1] = gimage_data[32*iRow+i];
390 checksum += gimage_data[32*iRow+i];
391 //printf("%2x ", yRowData[i]);
392 }
393 //printf("%2x", yRowData[32]);
394
395 // => write 0x00/0x0A (program row command)
396 err = bq_write(0x00, 0x0A);
397 // => write 0x01/iRow (designate row to write)
398 err |= bq_write(0x01, iRow);
399
400 // => write row command followed by 32 bytes of data
401 err = write(i2c_dev_handle, yRowData, 33);
402 if (err != 33) { fprintf(stderr, "\nError: i2c transaction failure! 3 \n"); goto WRITEBACK_ROWS; }
403
404 // generate checksums
405 dfi_checksum = (dfi_checksum + checksum) % 0x10000;
406 checksum += 0x0A + iRow;
407 checksum = checksum % 0x10000;
408
409 // => write checksum (LSB)
410 err = bq_write(0x64, (checksum & ~(0xFF00)));
411 // => write checksum (MSB)
412 err |= bq_write(0x65, (checksum >> 8));
413
414 //sleep 2ms
415 usleep(2000);
416
417 //read back 0x66
418 error_reg = error_check();
419 if (!error_reg) {
420 printf("x"); //row successfully written
421 }
422 else {
423 write_loops ++;
424 printf("Write attempt %d failed at Row %d...\n", write_loops, iRow);
425
426 if (write_loops > 5) {
427 printf("Data Flash write failed: check setup...\n");
428 goto WRITEBACK_ROWS;
429 }
430 else {
431 printf("Retrying DF Write...\n\n\n");
432 goto WRITE_IMG;
433 }
434 }
435
436 iRow ++;
437 }
438
439 printf("\n\nImage write completed, verifying checksum...\n");
440
441 /* verify checksum */
442
443 // => write 0x00/0x08
444 err = bq_write(0x00, 0x08);
445 // => write 0x64/0x08
446 err |= bq_write(0x64, 0x08);
447 // => write 0x65/0x00
448 err |= bq_write(0x65, 0x00);
449
450 //sleep 20ms
451 usleep(20000);
452
453 //read back checksum
454 err = bq_read(0x04, 2, i2c_buf);
455 dfi_checksum_rd = ((i2c_buf[1] << 8) | i2c_buf[0]);
456
457 //printf("calculated checksum: 0x%x\n", dfi_checksum);
458 //printf(" read checksum: 0x%x\n", dfi_checksum_rd);
459
460 if (dfi_checksum == dfi_checksum_rd){
461 printf("Checksum verified - Image write successful.\n");
462 }
463 else {
464 printf("Checksum invalid - write error...\n");
465 }
466
467 loops = 0;
468
469 WRITEBACK_ROWS:
470
471 /* Begin writing back IF flash */
472 printf("Begin writing back IF rows...\n");
473
474 iRow = 1;
475 checksum1 = 0;
476 checksum0 = 0;
477
478 //prep yIFRowData_0 and 1
479 for (i = 96; i > 0; i--) {
480 checksum0 += yIFRowData_0[i-1];
481 yIFRowData_0[i] = yIFRowData_0[i-1];
482 }
483 yIFRowData_0[0] = 0x04;
484 checksum0 = (0x02 + 0 + checksum0) % 0x10000;
485
486 for (i = 96; i > 0; i--) {
487 checksum1 += yIFRowData_1[i-1];
488 yIFRowData_1[i] = yIFRowData_1[i-1];
489 }
490 yIFRowData_1[0] = 0x04;
491 checksum1 = (0x02 + 1 + checksum1) % 0x10000;
492
493 while (iRow > -1) {
494 // => write 0x00/0x02
495 err = bq_write(0x00, 0x02);
496 // => write 0x01/0x00+iRow
497 err |= bq_write(0x01, 0x00+iRow);
498 // => write 0x02/0x00
499 err |= bq_write(0x02, 0x00);
500
501 // => write 0x04/iRow_data
502 if (iRow == 1) {
503 err = write(i2c_dev_handle, yIFRowData_1, 97);
504 checksum = checksum1;
505 }
506 else if (iRow == 0) {
507 err = write(i2c_dev_handle, yIFRowData_0, 97);
508 checksum = checksum0;
509 }
510 if (err != 97) { fprintf(stderr, "\nError: i2c transaction failure! 4 \n"); goto ESCAPE; }
511
512 // => write checksum (LSB)
513 err = bq_write(0x64, (checksum & ~(0xFF00)));
514 // => write checksum (MSB)
515 err |= bq_write(0x65, (checksum >> 8));
516
517 //sleep 20ms
518 usleep(20000);
519
520 //read back 0x66
521 error_reg = error_check();
522 if (!error_reg) {
523 printf("IF Row %d written back successfully\n", iRow); //row successfully written
524 iRow --;
525 }
526 else {
527 loops ++;
528 printf("Write attempt %d for IF row %d failed: 0x%x...\n", loops, iRow, error_reg);
529
530 if (loops > 2) {
531 printf("IF row write back failed: check setup...\n");
532 goto ESCAPE;
533 }
534 else {
535 printf("Retrying IF row write back...\n\n");
536 }
537 }
538 }
539
540 printf("Finished updating.\n\n");
541 usleep(20);
542
543 /* exit ROM mode */
544 printf("Exiting ROM mode...\n");
545
546 err = bq_write(0x00, 0x0F);
547 err |= bq_write(0x01, 0x00);
548 err |= bq_write(0x64, 0x0F);
549 err |= bq_write(0x65, 0x00);
550
551 /* Issue RESET IT ENABLE and SEALED commands */
552 printf("Issuing RESET, IT_ENABLE and SEALED commands...\n\n");
553
554 // Change address back to 0x55
555 usleep(20000);
556 i2c_address = 0x55;
557 err = ioctl(i2c_dev_handle, I2C_SLAVE, i2c_address);
558 if (err < 0) { fprintf(stderr, "\nError: Some kind of super tragic ioctl error!\n"); goto ESCAPE; }
559 usleep(20000);
560
561 // RESET
562 err = bq_write(0x00, 0x41);
563 err |= bq_write(0x01, 0x00);
564
565 if (!err)
566 printf("Successfully issued RESET on address 0x55\n");
567 else
568 printf("Unable to issue RESET on address 0x55\n");
569
570 usleep(20000);
571
572 /*
573 // IT ENABLE
574 err = bq_write(0x00, 0x21);
575 err |= bq_write(0x01, 0x00);
576
577 if (!err)
578 printf("Successfully issued IT ENABLE on address 0x55\n");
579 else
580 printf("Unable to issue IT_ENABLE on address 0x55\n");
581
582
583 // SEALED
584 err = bq_write(0x00, 0x20);
585 err |= bq_write(0x01, 0x00);
586
587
588 if (!err)
589 printf("Successfully issued SEALED on address 0x55\n");
590 else
591 printf("Unable to issue SEALED on address 0x55\n");
592 */
593
594
595 close(i2c_dev_handle);
596 printf("bqupdate completed.\n");
597 exit(0);
598
599 ESCAPE:
600 printf("Encountered escape condition: Exiting...\n");
601
602 close(i2c_dev_handle);
603 exit(1);
604
605 ESCAPE_ROM:
606 printf("Encountered escape condition: Attempting to exit ROM mode...\n");
607
608 i2c_address = 0x0b;
609 err = ioctl(i2c_dev_handle, I2C_SLAVE, i2c_address);
610 if (err < 0) {
611 fprintf(stderr, "\nError: Some kind of super tragic ioctl error!\n");
612 goto ESCAPE;
613 }
614
615 err = bq_write(0x00, 0x0F);
616 err |= bq_write(0x01, 0x00);
617 err |= bq_write(0x64, 0x0F);
618 err |= bq_write(0x65, 0x00);
619
620 if (!err)
621 printf("Successfully exitied ROM mode\n");
622 else
623 printf("Unable to cleanly exit ROM mode\n");
624
625 //error_check();
626
627 close(i2c_dev_handle);
628 exit(1);
629
630 READ_IFBACKUP:
631 /* read the row backup */
632 printf("\nReading %s...\n", "ifrows.bin");
633 ifrow_file = fopen("ifrows.bin", "r");
634 err = fread(yIFRowData_0, 1, 96, ifrow_file);
635 printf("\n read %d bytes...", err);
636 fread(yIFRowData_1, 1, 1, ifrow_file);
637 err = fread(yIFRowData_1, 1, 96, ifrow_file);
638 printf("\n read %d bytes...\n", err);
639 fclose(ifrow_file);
640
641 printf("Read Row 0: ");
642 for (i = 0; i < 97; i++) {
643 printf("%2x ", yIFRowData_0[i]);
644 }
645 printf("\n");
646
647 printf("Read Row 1: ");
648 for (i = 0; i < 97; i++) {
649 printf("%2x ", yIFRowData_1[i]);
650 }
651 printf("\n");
652
653 loops = 0;
654 goto IF_ERASE;
655 }
Something went wrong with that request. Please try again.