Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
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.