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)
100 {
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);
108 }
110 static void control_write(struct gauge_info_t *gauge, uint16_t val)
111 {
112 write_word(gauge, REG_CONTROL, val);
113 }
115 static uint16_t control_read(struct gauge_info_t *gauge, uint16_t ctrl_cmd)
116 {
117 control_write(gauge, ctrl_cmd);
119 gauge->sleep_ms(5);
121 return read_word(gauge, REG_CONTROL);
122 }
124 static uint16_t control_status(struct gauge_info_t *gauge)
125 {
126 return control_read(gauge, CTRL_CMD_STATUS);
127 }
129 static uint16_t device_type(struct gauge_info_t *gauge)
130 {
131 return control_read(gauge, CTRL_CMD_DEVICE_TYPE);
132 }
134 static uint16_t fw_version(struct gauge_info_t *gauge)
135 {
136 return control_read(gauge, CTRL_CMD_FW_VERSION);
137 }
139 static int sealed(struct gauge_info_t *gauge)
140 {
141 return control_status(gauge) & CTRL_STATUS_SS;
142 }
144 static int fullaccess_sealed(struct gauge_info_t *gauge)
145 {
146 if (gauge->family == 0x8101)
147 return 0;
149 return control_status(gauge) & CTRL_STATUS_FAS;
150 }
152 static int seal(struct gauge_info_t *gauge)
153 {
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;
175 }
178 static int do_unseal(struct gauge_info_t *gauge, uint32_t key, int fullaccess)
179 {
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;
209 }
211 static int unseal(struct gauge_info_t *gauge)
212 {
213 return do_unseal(gauge, gauge->unseal_key, 0);
214 }
216 static int unseal_fullaccess(struct gauge_info_t *gauge)
217 {
218 return do_unseal(gauge, gauge->fullacccess_key, 1);
219 }
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;
229 }
231 static void reverse_byteorder(uint8_t *val, int len)
232 {
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 }
241 }
243 static void copy_reverse_byteorder(uint8_t *dest, uint8_t *src, int len)
244 {
245 int i;
247 for (i = 0; i < len; i++)
248 dest[i] = src[len - i - 1];
249 }
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)
256 {
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;
272 }
275 /* Convert from IEEE754 single to a x float */
276 static void ieee_float_to_x(uint8_t *dest, float ff)
277 {
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;
291 }
293 static uint8_t checksum(uint8_t *data)
294 {
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;
304 }
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)
313 {
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;
359 }
361 static int rw_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
362 uint8_t blk_ind, uint8_t *buf, int write)
363 {
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;
377 }
379 static int read_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
380 uint8_t blk_ind, uint8_t *buf)
381 {
382 int ret = rw_dm_block(gauge, subclass, blk_ind, buf, 0);
384 return ret;
385 }
387 static int write_dm_block(struct gauge_info_t *gauge, uint8_t subclass,
388 uint8_t blk_ind, uint8_t *buf)
389 {
390 return rw_dm_block(gauge, subclass, blk_ind, buf, 1);
391 }
393 int read_params_block(struct csv_info_t *csv, struct gauge_info_t *gauge)
394 {
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*) ¶ms[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*) ¶ms[i].val, &buf[offset + 1], params[i].data_len);
467 } else {
468 memcpy(¶ms[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(¶ms[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(¶ms[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(¶ms[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;
505 }
509 int write_params_block(struct csv_info_t *csv, struct gauge_info_t *gauge)
510 {
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(¶ms[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*) ¶ms[i].val, params[i].data_len);
588 } else {
589 memcpy(&buf[offset + 1], ¶ms[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;
615 }
617 int read_regs(struct csv_info_t *csv, struct gauge_info_t *gauge)
618 {
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*) ¶ms[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*) ¶ms[i].val, &buf[1], params[i].data_len);
666 } else {
667 memcpy(¶ms[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(¶ms[i], csv->value_fld_ind);
674 }
677 if (err)
678 pr_err("FAILED!!\n");
680 pr_info("reading regs successful!\n");
682 return !err;
683 }
685 static int seal_after_dm_access(struct gauge_info_t *gauge, int argc, char **argv)
686 {
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;
711 }
713 static uint32_t gauge_fmly_from_user(int argc, char **argv)
714 {
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;
731 }
733 static uint32_t autodetect_gauge_family(uint16_t dev)
734 {
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;
778 }
780 static int get_gauge_family(struct gauge_info_t *gauge, int argc, char **argv)
781 {
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;
805 }
807 static void reset_gauge(struct gauge_info_t *gauge)
808 {
809 pr_info("resetting gauge..\n");
810 control_write(gauge, CTRL_CMD_RESET);
811 }
814 static int open_dm_flash(struct gauge_info_t *gauge, int argc, char **argv)
815 {
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);
867 }
869 static void close_dm_flash(struct gauge_info_t *gauge, int argc, char **argv)
870 {
871 seal_after_dm_access(gauge, argc, argv);
872 }
874 #define CFG_UPDATE_POLLING_RETRY_LIMIT_MS 5000
876 static void reset_gauge_rom(struct gauge_info_t *gauge)
877 {
878 pr_err("Doing reset of ROM gauge is not a good idea!! Ignoring..\n");
879 }
881 static int enter_cfgupdate_mode(struct gauge_info_t *gauge)
882 {
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;
902 }
904 static int exit_cfgupdate_mode(struct gauge_info_t *gauge)
905 {
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;
925 }
927 static int rom_itpor(struct gauge_info_t *gauge)
928 {
929 return read_word(gauge, ROM_GAUGE_FLAGS) & ROM_GAUGE_FLAG_ITPOR;
930 }
932 static int open_dm_rom(struct gauge_info_t *gauge, int argc, char **argv)
933 {
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;
949 }
951 static void close_dm_rom(struct gauge_info_t *gauge, int argc, char **argv)
952 {
953 if (gauge->op == OP_DM_WRITE)
954 exit_cfgupdate_mode(gauge);
956 seal_after_dm_access(gauge, argc, argv);
957 }
959 static int gauge_family_specific_init(struct gauge_info_t *gauge)
960 {
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;
997 }
999 #ifndef GAUGE_SIMULATOR
1000 int init_gauge_interface(struct gauge_info_t *gauge, int argc, char **argv)
1001 {
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);
1019 }
1020 #endif