]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - bms-linux/bqtool.git/blob - gauge.c
Update typo in usage
[bms-linux/bqtool.git] / gauge.c
1 /*
2  * Copyright (C) 2015 Texas Instruments Inc
3  *
4  * Aneesh V <aneesh@ti.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include "bqt.h"
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <string.h>
22 #include <stdlib.h>
24 #define SEAL_UNSEAL_POLLING_LIMIT_MS    1000
26 int do_read(struct gauge_info_t *gauge, uint8_t *buf, uint8_t len)
27 {
28         int i = 0;
29         uint8_t addr = gauge->slave_addr;
31         while (i++ < 4) {
32                 if (gauge->read(gauge, addr, buf, len))
33                         return 1;
34                 gauge->sleep_ms(10);
35                 pr_err("Retrying read..\n")
36         }
39         return 0;
40 }
42 int do_write(struct gauge_info_t *gauge, uint8_t *buf, uint8_t len)
43 {
44         int i = 0;
45         uint8_t addr = gauge->slave_addr;
47         while (i++ < 4) {
48                 if (gauge->write(gauge, addr, buf, len))
49                         return 1;
50                 gauge->sleep_ms(10);
51                 pr_err("Retrying write..\n")
52         }
54         return 0;
55 }
57 static uint16_t read_word(struct gauge_info_t *gauge, uint8_t reg)
58 {
59         /* Let's not assume Endianness */
60         uint8_t buf[3];
61         uint16_t reg_val = 0;
63         buf[0] = reg;
65         if (do_read(gauge, buf, 2)) {
66                 reg_val = buf[2] << 8;
67                 reg_val |= buf[1];
68         }
70         return reg_val;
71 }
73 static int write_word(struct gauge_info_t *gauge, uint8_t reg, uint16_t reg_val)
74 {
75         /* Let's not assume Endianness */
76         uint8_t buf[3];
78         buf[0] = reg;
79         buf[1] = (uint8_t) (reg_val & 0xFF);
80         buf[2] = (uint8_t) ((reg_val & 0xFF00) >> 8);
83         return do_write(gauge, buf, 2);
84 }
86 static uint8_t read_byte(struct gauge_info_t *gauge, uint8_t reg)
87 {
88         /* Let's not assume Endianness */
89         uint8_t buf[2];
91         buf[0] = reg;
93         if (do_read(gauge, buf, 1))
94                 return buf[1];
96         return 0;
97 }
99 static int write_byte(struct gauge_info_t *gauge, uint8_t reg, uint8_t val)
101         /* Let's not assume Endianness */
102         uint8_t buf[2];
104         buf[0] = reg;
105         buf[1] = val;
107         return do_write(gauge, buf, 1);
110 static void control_write(struct gauge_info_t *gauge, uint16_t val)
112         write_word(gauge, REG_CONTROL, val);
115 static uint16_t control_read(struct gauge_info_t *gauge, uint16_t ctrl_cmd)
117         control_write(gauge, ctrl_cmd);
119         gauge->sleep_ms(5);
121         return read_word(gauge, REG_CONTROL);
124 static uint16_t control_status(struct gauge_info_t *gauge)
126         return control_read(gauge, CTRL_CMD_STATUS);
129 static uint16_t device_type(struct gauge_info_t *gauge)
131         return control_read(gauge, CTRL_CMD_DEVICE_TYPE);
134 static uint16_t fw_version(struct gauge_info_t *gauge)
136         return control_read(gauge, CTRL_CMD_FW_VERSION);
139 static int sealed(struct gauge_info_t *gauge)
141         return control_status(gauge) & CTRL_STATUS_SS;
144 static int fullaccess_sealed(struct gauge_info_t *gauge)
146         if (gauge->family == 0x8101)
147                 return 0;
149         return control_status(gauge) & CTRL_STATUS_FAS;
152 static int seal(struct gauge_info_t *gauge)
154         int i = 0;
155         if (sealed(gauge))
156                 return 1;
158         control_write(gauge, CTRL_CMD_SEAL);
160         while (i < SEAL_UNSEAL_POLLING_LIMIT_MS/10) {
161                 i++;
162                 if (sealed(gauge)) {
163                         pr_info("sealed the device\n");
164                         break;
165                 }
166                 gauge->sleep_ms(10);
167         }
169         if (i == SEAL_UNSEAL_POLLING_LIMIT_MS / 10) {
170                 pr_err("sealing failed\n");
171                 return 0;
172         }
174         return 1;
178 static int do_unseal(struct gauge_info_t *gauge, uint32_t key, int fullaccess)
180         int i = 0;
182         if ((fullaccess && !fullaccess_sealed(gauge)) ||
183                 (!fullaccess && !(sealed(gauge))))
184                 return 1;
187         while (i < SEAL_UNSEAL_POLLING_LIMIT_MS/20) {
188                 control_write(gauge, (uint16_t) (key & 0xFFFF));
189                 gauge->sleep_ms(5);
190                 control_write(gauge, (uint16_t) ((key & 0xFFFF0000) >> 16));
191                 gauge->sleep_ms(5);
192                 if ((fullaccess && !fullaccess_sealed(gauge)) ||
193                         (!fullaccess && !(sealed(gauge)))) {
194                         pr_info("unsealed %s the device..\n",
195                                 fullaccess ? "fullaccess" : "");
196                         break;
197                 }
198                 gauge->sleep_ms(10);
199                 i++;
200         }
202         if (i == SEAL_UNSEAL_POLLING_LIMIT_MS / 20) {
203                 pr_err("unsealing %s failed!\n",
204                         fullaccess ? "fullaccess" : "");
205                 return 0;
206         }
208         return 1;
211 static int unseal(struct gauge_info_t *gauge)
213         return do_unseal(gauge, gauge->unseal_key, 0);
216 static int unseal_fullaccess(struct gauge_info_t *gauge)
218         return do_unseal(gauge, gauge->fullacccess_key, 1);
221 static uint8_t native_endianness() {
222     int i = 1;
223     char *p = (char *)&i;
225     if (p[0] == 1)
226         return BYTEORDER_LE;
227     else
228         return BYTEORDER_BE;
231 static void reverse_byteorder(uint8_t *val, int len)
233         int i;
234         uint8_t tmp;
236         for (i = 0; i < len / 2; i++) {
237                 tmp = val[i];
238                 val[i] = val[len - i - 1];
239                 val[len - i - 1] = tmp;
240         }
243 static void copy_reverse_byteorder(uint8_t *dest, uint8_t *src, int len)
245         int i;
247         for (i = 0; i < len; i++)
248                 dest[i] = src[len - i - 1];
251 /*
252  * Convert from a X single to an IEEE754 floating point
253  * number in Little Endian format
254  */
255 float x_float_to_ieee(uint8_t *data)
257         float res;
258         uint8_t *pK;
260         pK=(unsigned char*)&res;
262         *pK=*(data+3);
263         *(pK+1)=*(data+2);
264         *(pK+2)=*(data+1) & 0x7f;
265         *(pK+3)=((*data) >> 1 )- 1;
267         if(*data & 0x01) *(pK+2) |= 0x80;
269         if(*(data+1) & 0x80) *(pK+3) |= 0x80;
271         return res;
275 /* Convert from IEEE754 single to a x float */
276 static void ieee_float_to_x(uint8_t *dest, float ff)
278         unsigned char *f;
279         f=(unsigned char*)&ff;
281         *dest=((*(f+3))<<1)+2;
282         *(dest+1)=(*(f+2)) & 0x7f;
283         *(dest+2)=*(f+1);
284         *(dest+3)=*f;
286         if(*(f+3) & 0x80)
287         *(dest+1) |= 0x80;
289         if(*(f+2) & 0x80)
290         *dest |=1;
293 static uint8_t checksum(uint8_t *data)
295         uint16_t sum = 0;
296         int i;
298         for (i = 0; i < 32; i++)
299                 sum += data[i];
301         sum &= 0xFF;
303         return 0xFF - sum;
306 /*
307  * !!!!! buf should be 33 bytes long !!!!!
308  * 1 byte for the register address and 32 bytes for data,
309  * write made zero-copy this way
310  */
311 static int do_rw_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
312         uint8_t blk_ind, uint8_t *buf, int write, uint32_t delay)
314         int err = 0;
315         uint16_t cksum, cksum_calc;
317         err |= !write_byte(gauge, REG_BLOCK_DATA_CONTROL, 0);
318         err |= !write_byte(gauge, REG_BLOCK_DATA_CLASS, subclass);
319         err |= !write_byte(gauge, REG_DATA_BLOCK, blk_ind);
320         gauge->sleep_ms(5);
321         if (write) {
322                 buf[0] = REG_BLOCK_DATA;
323                 err |= !do_write(gauge, buf, 32);
325                 /* Write checksum - this is where we need a big delay */
326                 cksum_calc = checksum(&buf[1]);
327                 err |= !write_byte(gauge, REG_BLOCK_DATA_CHECKSUM, cksum_calc);
328                 gauge->sleep_ms(delay);
330                 /* Readback checksum and compare */
331                 err |= !write_byte(gauge, REG_DATA_BLOCK, blk_ind);
332                 gauge->sleep_ms(5);
333                 cksum = read_byte(gauge, REG_BLOCK_DATA_CHECKSUM);
334                 if (cksum != cksum_calc) {
335                         pr_err("checksum failure on write cksum 0x%02x cksum_calc 0x%02x\n",
336                                 cksum, cksum_calc);
337                         err = 1;
338                 }
339         } else {
340                 buf[0] = REG_BLOCK_DATA;
341                 err |= !do_read(gauge, buf, 32);
343                 /* Read checksum and compare */
344                 cksum = read_byte(gauge, REG_BLOCK_DATA_CHECKSUM);
345                 cksum_calc = checksum(&buf[1]);
346                 if (cksum != cksum_calc) {
347                         pr_err("checksum failure on read cksum 0x%02x cksum_calc 0x%02x\n",
348                                 cksum, cksum_calc);
349                         err = 1;
350                 }
351         }
353         if (err) {
354                 pr_err("error accessing subclass 0x%02x blk_ind 0x%02x write %d\n",
355                         subclass, blk_ind, write);
356         }
358         return !err;
361 static int rw_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
362         uint8_t blk_ind, uint8_t *buf, int write)
364         int i = 0;
365         uint32_t delay = 300;
367         while ((i++ < 5)) {
368                 if (do_rw_dm_block(gauge, subclass, blk_ind, buf, write, delay))
369                         return 1;
371                 /* increase the delay by 100ms at every step */
372                 delay += 100;
373                 pr_err("retrying %s block..\n", write == 1 ? "write" : "read");
374         }
376         return 0;
379 static int read_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
380         uint8_t blk_ind, uint8_t *buf)
382         int ret = rw_dm_block(gauge, subclass, blk_ind, buf, 0);
384         return ret;
387 static int write_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
388         uint8_t blk_ind, uint8_t *buf)
390         return rw_dm_block(gauge, subclass, blk_ind, buf, 1);
393 int read_params_block(struct csv_info_t *csv, struct gauge_info_t *gauge)
395         unsigned int i;
396         int err = 0;
397         struct param_t *params = csv->params;
398         uint8_t subclass, blk_ind, offset;
399         uint16_t blk_id, blk_id_prev = 0;
400         uint8_t buf[65], tmp;
401         union val_t tmp_val;
402         uint8_t host_endianness = native_endianness();
403         int read_twoblocks = 0;
405         pr_info("reading params..\n");
407         for (i = 0; !err && i < csv->num_params; i++) {
408                 subclass = (uint8_t) ((params[i].offset & 0xFF000000) >> 24);
409                 offset = (uint8_t) (params[i].offset & 0xFF);
411                 /* block number within subclass */
412                 blk_ind = offset >> 5;
414                 /* offset within the block */
415                 offset = offset & 0x1F;
416                 if (offset + params[i].data_len > 32) {
417                         /*
418                          * Parameter overflowing to the next block.
419                          * Read that block too
420                          */
421                         read_twoblocks = 1;
422                         tmp = buf[32];
423                         err |= !read_dm_block(gauge, subclass, blk_ind + 1, &buf[32]);
424                         buf[32] = tmp;
425                 }
427                 /*
428                  * unique id for the block:
429                  * combination of subclass and blk_ind. Useful to uniquely
430                  * identify the blocks and figure out when it's time to read
431                  * the next block
432                  */
433                 blk_id = (subclass << 8) | blk_ind;
435                 if (i == 0 || blk_id != blk_id_prev) {
436                         err |= !read_dm_block(gauge, subclass, blk_ind, buf);
437                         if (err)
438                                 goto end;
439                 }
441                 /*
442                  * note "offset + 1" below. buf[0] contains the
443                  * reg address: BLOCK_DATA
444                  * x_float_to_ieee returns the output in IEEE little Endian,
445                  * so convert to Big Endian if the host is Big Endian.
446                  */
447                 tmp_val = params[i].val;
449                 /*
450                  * zero it out before reading new value
451                  * Due to the way we are printing them it's important
452                  * not to have any stale bits at the higher nibbles for
453                  * 16-bit and 8-bit values. Stale bits are possible
454                  * because we do not limit check in the input file
455                  * in case of export
456                  */
457                 params[i].val.u = 0;
458                 if (params[i].raw_type == DATATYPE_F) {
459                         params[i].val.f = x_float_to_ieee(&buf[offset + 1]);
460                         if (host_endianness == BYTEORDER_BE)
461                                 reverse_byteorder((uint8_t*) &params[i].val, params[i].data_len);
462                 } else if (params[i].raw_type == DATATYPE_S) {
463                         memcpy(params[i].val_s, &buf[offset + 1], params[i].data_len);
464                 } else if (gauge->endianness != host_endianness) {
465                         /* Fix byte ordering (Endianness) for integral numerical types */
466                         copy_reverse_byteorder((uint8_t*) &params[i].val, &buf[offset + 1], params[i].data_len);
467                 } else {
468                         memcpy(&params[i].val, &buf[offset + 1], params[i].data_len);
469                 }
471                 if (params[i].raw_type == DATATYPE_S) {
472                         /* Null terminate at the end of buffer for safety */
473                         params[i].val_s[params[i].data_len] = '\0';
474                         /* Put length at first byte of the buffer */
475                         params[i].val_s[0] = (uint8_t) strlen(&params[i].val_s[1]);
476                 }
478                 /*
479                  * When we are exporting, we check the limits,
480                  * but do not abort the operation if there is
481                  * an error
482                  */
483                 check_limits(&params[i]);
485                 /* Update the value string if a binary comparison with old value fails */
486                 if (tmp_val.u != params[i].val.u)
487                         err |= !update_value_string(&params[i], csv->value_fld_ind);
489                 blk_id_prev = blk_id;
490                 if (read_twoblocks) {
491                         /* now use the overflow buffer as the regular buffer */
492                         memcpy(&buf[1], &buf[33], 32);
493                         blk_id_prev++;
494                         read_twoblocks = 0;
495                 }
496         }
498 end:
499         if (err)
500                 pr_err("FAILED!!\n");
502         pr_info("reading params successful!\n");
504         return !err;
509 int write_params_block(struct csv_info_t *csv, struct gauge_info_t *gauge)
511         unsigned int i;
512         struct param_t *params = csv->params;
513         uint8_t subclass = 0, blk_ind = 0, offset;
514         uint16_t blk_id, blk_id_prev = 0;
515         uint8_t buf[65], tmp;
516         union val_t tmp_val;
517         uint8_t host_endianness = native_endianness();
518         int read_twoblocks = 0, err = 0;
520         pr_info("writing params..\n");
522         for (i = 0; !err && i < csv->num_params; i++) {
523                 if (!check_limits(&params[i]))
524                         goto end;
526                 subclass = (uint8_t) ((params[i].offset & 0xFF000000) >> 24);
527                 offset = (uint8_t) (params[i].offset & 0xFF);
529                 /* block number within subclass */
530                 blk_ind = offset >> 5;
532                 /* offset within the block */
533                 offset = offset & 0x1F;
534                 if (offset + params[i].data_len > 32) {
535                         /*
536                          * Parameter overflowing to the next block.
537                          * Read that block too
538                          */
539                         read_twoblocks = 1;
540                         tmp = buf[32];
541                         err |= !read_dm_block(gauge, subclass, blk_ind + 1, &buf[32]);
542                         buf[32] = tmp;
543                 }
545                 /*
546                  * unique id for the block:
547                  * combination of subclass and blk_ind. Useful to uniquely
548                  * identify the blocks and figure out when it's time to read
549                  * the next block
550                  */
551                 blk_id = (subclass << 8) | blk_ind;
553                 if (i == 0 || blk_id != blk_id_prev) {
555                         /*
556                          * if this is the first parameter the buf is not valid yet
557                          * in all other cases it's valid
558                          */
559                         if (i != 0) {
560                                 err |= !write_dm_block(gauge, (uint8_t) ((blk_id_prev & 0xFF00) >> 8),
561                                         (uint8_t) (blk_id_prev & 0xFF), buf);
562                         }
564                         if (!err)
565                                 err |= !read_dm_block(gauge, subclass, blk_ind, buf);
566                         if (err)
567                                 goto end;
568                  }
570                 /*
571                  * note "offset + 1" below. buf[0] contains the
572                  * reg address: BLOCK_DATA
573                  * ieee_float_to_x returns the output in x format,
574                  * so no Endian conversion required after that.
575                  */
576                 tmp_val = params[i].val;
578                 if (gauge->ic == GAUGE_IC_X && params[i].raw_type == DATATYPE_F) {
579                         /* ieee_float_to_x assumes the input float to be in Little Endian */
580                         if (host_endianness == BYTEORDER_BE)
581                                 reverse_byteorder((uint8_t*) &tmp_val, params[i].data_len);
582                         ieee_float_to_x(&buf[offset + 1], tmp_val.f);
584                 } else if (params[i].raw_type == DATATYPE_S) {
585                         memcpy(&buf[offset + 1], params[i].val_s, params[i].data_len);
586                 } else if (gauge->endianness != host_endianness) {
587                         copy_reverse_byteorder(&buf[offset + 1], (uint8_t*) &params[i].val, params[i].data_len);
588                 } else {
589                         memcpy(&buf[offset + 1], &params[i].val, params[i].data_len);
590                 }
592                 blk_id_prev = blk_id;
593                 if (read_twoblocks) {
594                         /*
595                          * now write the first block and use the overflow buffer
596                          * as the regular buffer
597                          */
598                         err |= !write_dm_block(gauge, (uint8_t) ((blk_id_prev & 0xFF00) >> 8),
599                                 (uint8_t) (blk_id_prev & 0xFF), buf);
600                         memcpy(&buf[1], &buf[33], 32);
601                         blk_id_prev++;
602                         read_twoblocks = 0;
603                 }
604         }
606         err |= !write_dm_block(gauge, subclass, blk_ind, buf);
608 end:
609         if (err)
610                 pr_err("FAILED!!\n");
612         pr_info("writing params successful!\n");
614         return !err;
617 int read_regs(struct csv_info_t *csv, struct gauge_info_t *gauge)
619         unsigned int i;
620         int err = 0;
621         struct param_t *params = csv->params;
622         uint8_t buf[5];
623         uint8_t host_endianness = native_endianness();
624         union val_t tmp_val;
625         uint8_t ctrl, reg;
626         uint16_t ctrl_reg;
628         pr_info("reading regs..\n");
630         memset(buf, 0, 5);
632         for (i = 0; !err && i < csv->num_params; i++) {
633                 if (params[i].data_len > 4) {
634                         pr_err(" %s: data length %d greater than max allowed 4\n")
635                         return 0;
636                 }
638                 tmp_val = params[i].val;
640                 ctrl = (uint8_t) ((params[i].offset & 0x01000000) >> 24);
641                 if (ctrl) {
642                         if (params->data_len > 2) {
643                                 pr_err("control command read can not be more"
644                                 " than 2 bytes long. Truncating to 2 bytes..\n");
645                                 params->data_len = 2;
646                         }
647                         ctrl_reg = (uint16_t) (params[i].offset & 0xFFFF);
648                         params[i].val.u = control_read(gauge, ctrl_reg);
649                 } else {
650                         reg = (uint8_t) (params[i].offset & 0xFF);
651                         buf[0] = reg;
652                         err |= !do_read(gauge, buf, params[i].data_len);
654                         /* zero it out before reading new value */
655                         params[i].val.u = 0;
656                         if (params[i].raw_type == DATATYPE_F) {
657                                 reverse_byteorder((uint8_t*) &buf[1], params[i].data_len);
658                                 params[i].val.f = x_float_to_ieee(&buf[1]);
659                                 if (host_endianness == BYTEORDER_BE)
660                                         reverse_byteorder((uint8_t*) &params[i].val, params[i].data_len);
661                         } else if (params[i].raw_type == DATATYPE_S) {
662                                 memcpy(params[i].val_s, &buf[1], params[i].data_len);
663                         } else if (host_endianness == BYTEORDER_BE) {
664                                 /* Fix byte ordering (Endianness) for integral numerical types */
665                                 copy_reverse_byteorder((uint8_t*) &params[i].val, &buf[1], params[i].data_len);
666                         } else {
667                                 memcpy(&params[i].val, &buf[1], params[i].data_len);
668                         }
669                 }
671                 /* Update the value string if a binary comparison with old value fails */
672                 if (tmp_val.u != params[i].val.u)
673                         err |= !update_value_string(&params[i], csv->value_fld_ind);
674         }
677         if (err)
678                 pr_err("FAILED!!\n");
680         pr_info("reading regs successful!\n");
682         return !err;
685 static int seal_after_dm_access(struct gauge_info_t *gauge, int argc, char **argv)
687         /* By default return to the previous seal state */
688         int seal_req = gauge->orig_seal_status;
689         int err = 0;
690         const char *exit_seal = get_cmdline_argument(argc, argv, "--exit-seal=", 1);
692         if (exit_seal) {
693                 if (strcmp(exit_seal, "seal") == 0)
694                         seal_req = 1;
695                 else if (strcmp(exit_seal, "unseal") == 0)
696                         seal_req = 0;
697                 else if (strcmp(exit_seal, "original") == 0)
698                         seal_req = gauge->orig_seal_status;
699                 else
700                         pr_err("undetected --exit-seal= request\n");
701         }
703         if (seal_req) {
704                 err |= seal(gauge);
705         } else {
706                 err |= unseal(gauge);
707                 err |= unseal_fullaccess(gauge);
708         }
710         return err;
713 static uint32_t gauge_fmly_from_user(int argc, char **argv)
715         uint32_t ret = 0;
716         char *tmp;
717         const char *family = get_cmdline_argument(argc, argv, "--gauge-family=", 1);
719         if (!family)
720                 return 0;
722         if (strstr(family, "bq") == family )
723                 ret = strtoul(&family[2], &tmp, 16);
725         pr_dbg("family from user %s\n", family);
727         if (!ret)
728                 pr_err("bad input for --gauge-family\n");
730         return ret;
733 static uint32_t autodetect_gauge_family(uint16_t dev)
735         uint32_t family = 0;
737         switch(dev) {
738         case 0x0500:
739         case 0x0501:
740         case 0x0505:
741                 family = 0x8032;
742                 break;
743         case 0x0510:
744         case 0x0541:
745         case 0x0410:
746                 family = 0x8034;
747                 break;
748         case 0x0520:
749         case 0x0545:
750         case 0x0530:
751         case 0x0531:
752         case 0x0532:
753         case 0x0620:
754                 family = 0x8035;
755                 break;
756         case 0x0425:
757                 family = 0x8036;
758                 break;
759         case 0x0546:
760         case 0x0741:
761         case 0x0742:
762                 family = 0x8037;
763                 break;
764         case 0x0421:
765         /*case 0x0411:
766         case 0x0441:*/
767         case 0x0621:
768                 family = 0x8101;
769                 break;
770         default:
771                 pr_err("uable to auto-detect gauge family\n");
772                 break;
773         }
775         pr_dbg("autodetected family bq%04x\n", family);
777         return family;
780 static int get_gauge_family(struct gauge_info_t *gauge, int argc, char **argv)
782         uint32_t usr_fmly, det_fmly;
784         usr_fmly = gauge_fmly_from_user(argc, argv);
785         det_fmly = autodetect_gauge_family(gauge->device_num);
786         if (det_fmly) {
787                 gauge->family = det_fmly;
788                 if (usr_fmly && (usr_fmly != det_fmly)) {
789                         pr_err("User provided gauge-family does not"
790                         "match with autodetected family. Using autodetected"
791                         "family usr 0x%0x auto 0x%0x\n",
792                         usr_fmly, det_fmly);
793                 }
794         } else if (usr_fmly) {
795                 gauge->family = usr_fmly;
796         } else if (gauge->op == OP_BQFS_FLASH){
797                 gauge->family = 0x8035;
798                 pr_err("Unable to get gauge family for bqfs flashing. Assuming 0x8035..\n");
799         } else {
800                 pr_err("unable to detect gauge family. Aborting..\n");
801                 return 0;
802         }
804         return 1;
807 static void reset_gauge(struct gauge_info_t *gauge)
809         pr_info("resetting gauge..\n");
810         control_write(gauge, CTRL_CMD_RESET);
814 static int open_dm_flash(struct gauge_info_t *gauge, int argc, char **argv)
816         long long int res;
817         int err_ss = 0, err_fas = 0, keys_in_gg = 0;
818         int ss, fas;
820         pr_dbg(">>\n");
822         ss = sealed(gauge);
823         fas = fullaccess_sealed(gauge);
824         gauge->orig_seal_status = (uint8_t) (ss || fas);
825         if (!ss && !fas)
826                 return 1;
828         const char *unseal_key_cmdline =
829                 get_cmdline_argument(argc, argv, "--unseal-key=", 1);
830         const char *fullaccess_key_cmdline =
831                 get_cmdline_argument(argc, argv, "--fullaccess-key=", 1);
833         keys_in_gg = gauge->unseal_key_found || gauge->fullaccess_key_found;
835         if (unseal_key_cmdline && extract_int(unseal_key_cmdline, 16, &res)) {
836                 gauge->unseal_key = (uint32_t) res;
837                 gauge->unseal_key_found = 1;
838                 pr_dbg("Unseal key from command line 0x%08x\n",
839                         gauge->unseal_key);
840         }
842         if (fullaccess_key_cmdline &&  extract_int(fullaccess_key_cmdline, 16, &res)) {
843                 gauge->fullacccess_key = (uint32_t) res;
844                 gauge->fullaccess_key_found = 1;
845                 pr_dbg("Full access key from command line 0x%08x\n",
846                         gauge->fullacccess_key);
847         }
849         if (ss && gauge->unseal_key_found) {
850                 err_ss = !unseal(gauge);
851         } else if (ss && !gauge->unseal_key_found && gauge->op != OP_BQFS_FLASH) {
852                 pr_err("unseal key not provided\n");
853                 err_ss = 1;
854         }
856         if (fas && gauge->fullaccess_key_found) {
857                 /* Ignore the error if the keys are not in gg */
858                 err_fas = keys_in_gg && !unseal_fullaccess(gauge);
859         } else if (fas && keys_in_gg && !gauge->fullaccess_key_found) {
860                 pr_err("Full access key not provided even though read/write of keys is requested\n");
861                 err_fas = 1;
862         }
864         pr_dbg("<<\n");
866         return !(err_ss || err_fas);
869 static void close_dm_flash(struct gauge_info_t *gauge, int argc, char **argv)
871         seal_after_dm_access(gauge, argc, argv);
874 #define CFG_UPDATE_POLLING_RETRY_LIMIT_MS       5000
876 static void reset_gauge_rom(struct gauge_info_t *gauge)
878         pr_err("Doing reset of ROM gauge is not a good idea!! Ignoring..\n");
881 static int enter_cfgupdate_mode(struct gauge_info_t *gauge)
883         int i = 0;
884         uint16_t flags;
886         control_write(gauge, CTRL_CMD_ROM_GAUGE_SET_CFGUPDATE);
888         while (i < CFG_UPDATE_POLLING_RETRY_LIMIT_MS / 100) {
889                 i++;
890                 flags = read_word(gauge, ROM_GAUGE_FLAGS);
891                 if (flags & ROM_GAUGE_FLAG_CFGUPDATE_MODE)
892                         break;
893                 gauge->sleep_ms(100);
894         }
896         if (i == CFG_UPDATE_POLLING_RETRY_LIMIT_MS / 100) {
897                 pr_err("failed flags %04x\n", flags);
898                 return 0;
899         }
901         return 1;
904 static int exit_cfgupdate_mode(struct gauge_info_t *gauge)
906         int i = 0;
907         uint16_t flags;
909         control_write(gauge, CTRL_CMD_ROM_GAUGE_EXIT_CFGUPDATE);
911         while (i < CFG_UPDATE_POLLING_RETRY_LIMIT_MS / 100) {
912                 i++;
913                 flags = read_word(gauge, ROM_GAUGE_FLAGS);
914                 if (!(flags & ROM_GAUGE_FLAG_CFGUPDATE_MODE))
915                         break;
916                 gauge->sleep_ms(100);
917         }
919         if (i == CFG_UPDATE_POLLING_RETRY_LIMIT_MS / 100) {
920                 pr_err("failed %04x\n", flags);
921                 return 0;
922         }
924         return 1;
927 static int rom_itpor(struct gauge_info_t *gauge)
929         return read_word(gauge, ROM_GAUGE_FLAGS) & ROM_GAUGE_FLAG_ITPOR;
932 static int open_dm_rom(struct gauge_info_t *gauge, int argc, char **argv)
934         int ret = 1;
936         gauge->unseal_key = ROM_GAUGE_UNSEAL_KEY;
937         gauge->unseal_key_found = 1;
938         gauge->fullaccess_key_found = 1;
939         gauge->orig_seal_status = (uint8_t) sealed(gauge);
941         if (gauge->orig_seal_status)
942                 ret = unseal(gauge);
944         if (ret && gauge->op == OP_DM_WRITE) {
945                 return enter_cfgupdate_mode(gauge);
946         }
948         return ret;
951 static void close_dm_rom(struct gauge_info_t *gauge, int argc, char **argv)
953         if (gauge->op == OP_DM_WRITE)
954                 exit_cfgupdate_mode(gauge);
956         seal_after_dm_access(gauge, argc, argv);
959 static int gauge_family_specific_init(struct gauge_info_t *gauge)
961         switch(gauge->family) {
962 #if (defined(BQ8032) || defined(BQ8034) || defined(BQ8035) || defined(BQ8036) || defined(BQ8037))
963         case 0x8032:
964         case 0x8034:
965         case 0x8035:
966         case 0x8036:
967         case 0x8037:
968                 gauge->ic = GAUGE_IC_X;
969                 gauge->endianness = BYTEORDER_BE;
970                 gauge->open_dm = open_dm_flash;
971                 gauge->close_dm = close_dm_flash;
972                 gauge->write_params = write_params_block;
973                 gauge->read_params = read_params_block;
974                 gauge->reset = reset_gauge;
975                 break;
976 #endif
977 #if defined(BQ8101)
978         case 0x8101:
979                 gauge->ic = GAUGE_IC_X;
980                 gauge->endianness = BYTEORDER_BE;
981                 gauge->open_dm = open_dm_rom;
982                 gauge->close_dm = close_dm_rom;
983                 gauge->write_params = write_params_block;
984                 gauge->read_params = read_params_block;
985                 gauge->reset = reset_gauge_rom;
986                 gauge->itpor = rom_itpor;
987                 gauge->fw_ver_bld = (uint8_t)
988                         control_read(gauge, CTRL_CMD_ROM_GAUGE_DM_CODE);
989                 break;
990 #endif
991         default:
992                 pr_err("unsupported gauge family 0x%0x\n", gauge->family);
993                 return 0;
994         }
996         return 1;
999 #ifndef GAUGE_SIMULATOR
1000 int init_gauge_interface(struct gauge_info_t *gauge, int argc, char **argv)
1002         if (!setup_comm_callbacks(gauge))
1003                 return 0;
1005         if (!gauge->init_comm_interface(gauge, argc, argv))
1006                 return 0;
1008         /* Get device type and FW version */
1009         gauge->device_num = device_type(gauge);
1010         gauge->fw_version = fw_version(gauge);
1012         if (gauge->op == OP_REG_DUMP)
1013                 return 1;
1015         if (!get_gauge_family(gauge, argc, argv))
1016                 return 0;
1018         return gauge_family_specific_init(gauge);
1020 #endif