Repository navigation
Expand file tree
/
Copy pathrk817_battery.c
More file actions
3337 lines (2818 loc) · 92.7 KB
/
Copy pathrk817_battery.c
File metadata and controls
3337 lines (2818 loc) · 92.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* rk817 battery driver
*
* Copyright (C) 2018 Rockchip Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "rk817-bat: " fmt
#include <linux/delay.h>
#include <linux/extcon.h>
#include <linux/fb.h>
#include <linux/gpio.h>
#include <linux/iio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/power/rk_usbbc.h>
#include <linux/regmap.h>
#include <linux/rk_keys.h>
#include <linux/rtc.h>
#include <linux/timer.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
static int dbg_enable;
module_param_named(dbg_level, dbg_enable, int, 0644);
#define DBG(args...) \
do { \
if (dbg_enable) { \
pr_info(args); \
} \
} while (0)
#define BAT_INFO(fmt, args...) pr_info(fmt, ##args)
#define DRIVER_VERSION "1.00"
#define SFT_SET_KB 1
#define DIV(x) ((x) ? (x) : 1)
#define ENABLE 0x01
#define DISABLE 0x00
#define MAX_INTERPOLATE 1000
#define MAX_PERCENTAGE 100
#define MAX_INT 0x7FFF
/* RK818_GGCON */
#define OCV_SAMP_MIN_MSK 0x0c
#define OCV_SAMP_8MIN (0x00 << 2)
#define ADC_CAL_8MIN 0x00
#define RELAX_VOL12_UPD_MSK (RELAX_VOL1_UPD | RELAX_VOL2_UPD)
#define MINUTE(x) \
((x) * 60)
#define ADC_TO_CURRENT(adc_value, samp_res) \
(adc_value * 172 / 1000 / samp_res)
#define CURRENT_TO_ADC(current, samp_res) \
(current * 1000 * samp_res / 172)
#define ADC_TO_CAPACITY(adc_value, samp_res) \
(adc_value / 1000 * 172 / 3600 / samp_res)
#define CAPACITY_TO_ADC(capacity, samp_res) \
(capacity * samp_res * 3600 / 172 * 1000)
#define ADC_TO_CAPACITY_UAH(adc_value, samp_res) \
(adc_value / 3600 * 172 / samp_res)
#define ADC_TO_CAPACITY_MAH(adc_value, samp_res) \
(adc_value / 1000 * 172 / 3600 / samp_res)
/* THREAML_REG */
#define TEMP_85C (0x00 << 2)
#define TEMP_95C (0x01 << 2)
#define TEMP_105C (0x02 << 2)
#define TEMP_115C (0x03 << 2)
#define ZERO_LOAD_LVL1 1400
#define ZERO_LOAD_LVL2 600
/* zero algorithm */
#define PWROFF_THRESD 3400
#define MIN_ZERO_DSOC_ACCURACY 10 /*0.01%*/
#define MIN_ZERO_OVERCNT 100
#define MIN_ACCURACY 1
#define DEF_PWRPATH_RES 50
#define WAIT_DSOC_DROP_SEC 15
#define WAIT_SHTD_DROP_SEC 30
#define MIN_ZERO_GAP_XSOC1 10
#define MIN_ZERO_GAP_XSOC2 5
#define MIN_ZERO_GAP_XSOC3 3
#define MIN_ZERO_GAP_CALIB 5
#define ADC_CALIB_THRESHOLD 4
#define ADC_CALIB_LMT_MIN 3
#define ADC_CALIB_CNT 5
/* default param */
#define DEFAULT_BAT_RES 135
#define DEFAULT_SLP_ENTER_CUR 300
#define DEFAULT_SLP_EXIT_CUR 300
#define DEFAULT_SLP_FILTER_CUR 100
#define DEFAULT_PWROFF_VOL_THRESD 3400
#define DEFAULT_MONITOR_SEC 5
#define DEFAULT_ALGR_VOL_THRESD1 3850
#define DEFAULT_ALGR_VOL_THRESD2 3950
#define DEFAULT_CHRG_VOL_SEL CHRG_VOL4200MV
#define DEFAULT_CHRG_CUR_SEL CHRG_CUR1400MA
#define DEFAULT_CHRG_CUR_INPUT INPUT_CUR2000MA
#define DEFAULT_POFFSET 42
#define DEFAULT_MAX_SOC_OFFSET 60
#define DEFAULT_FB_TEMP TEMP_115C
#define DEFAULT_ENERGY_MODE 0
#define DEFAULT_ZERO_RESERVE_DSOC 10
#define DEFAULT_SAMPLE_RES 20
/* sample resistor and division */
#define SAMPLE_RES_10MR 10
#define SAMPLE_RES_20MR 20
#define SAMPLE_RES_DIV1 1
#define SAMPLE_RES_DIV2 2
/* sleep */
#define SLP_CURR_MAX 40
#define SLP_CURR_MIN 6
#define DISCHRG_TIME_STEP1 MINUTE(10)
#define DISCHRG_TIME_STEP2 MINUTE(60)
#define SLP_DSOC_VOL_THRESD 3600
#define REBOOT_PERIOD_SEC 180
#define REBOOT_MAX_CNT 80
#define TIMER_MS_COUNTS 1000
/* fcc */
#define MIN_FCC 500
#define CAP_INVALID 0x80
/* virtual params */
#define VIRTUAL_CURRENT 1000
#define VIRTUAL_VOLTAGE 3888
#define VIRTUAL_SOC 66
#define VIRTUAL_PRESET 1
#define VIRTUAL_TEMPERATURE 188
#define VIRTUAL_STATUS POWER_SUPPLY_STATUS_CHARGING
#define FINISH_CHRG_CUR1 1000
#define FINISH_CHRG_CUR2 1500
#define FINISH_MAX_SOC_DELAY 20
#define TERM_CHRG_DSOC 88
#define TERM_CHRG_CURR 600
#define TERM_CHRG_K 650
#define SIMULATE_CHRG_INTV 8
#define SIMULATE_CHRG_CURR 400
#define SIMULATE_CHRG_K 1500
#define FULL_CHRG_K 400
enum work_mode {
MODE_ZERO = 0,
MODE_FINISH,
MODE_SMOOTH_CHRG,
MODE_SMOOTH_DISCHRG,
MODE_SMOOTH,
};
enum charge_status {
CHRG_OFF,
DEAD_CHRG,
TRICKLE_CHRG,
CC_OR_CV_CHRG,
CHARGE_FINISH,
USB_OVER_VOL,
BAT_TMP_ERR,
BAT_TIM_ERR,
};
enum bat_mode {
MODE_BATTARY = 0,
MODE_VIRTUAL,
};
enum rk817_sample_time {
S_8_MIN,
S_16_MIN,
S_32_MIN,
S_48_MIN,
};
enum rk817_output_mode {
AVERAGE_MODE,
INSTANT_MODE,
};
enum rk817_battery_fields {
ADC_SLP_RATE, BAT_CUR_ADC_EN, BAT_VOL_ADC_EN,
USB_VOL_ADC_EN, TS_ADC_EN, SYS_VOL_ADC_EN, GG_EN, /*ADC_CONFIG0*/
CUR_ADC_DITH_SEL, CUR_ADC_DIH_EN, CUR_ADC_CHOP_EN,
CUR_ADC_CHOP_SEL, CUR_ADC_CHOP_VREF_EN, /*CUR_ADC_CFG0*/
CUR_ADC_VCOM_SEL, CUR_ADC_VCOM_BUF_INC, CUR_ADC_VREF_BUF_INC,
CUR_ADC_BIAS_DEC, CUR_ADC_IBIAS_SEL,/*CUR_ADC_CFG1*/
VOL_ADC_EXT_VREF_EN, VOL_ADC_DITH_SEL, VOL_ADC_DITH_EN,
VOL_ADC_CHOP_EN, VOL_ADC_CHOP_SEL, VOL_ADC_CHOP_VREF_EN,
VOL_ADC_VCOM_SEL, VOL_ADC_VCOM_BUF_INC, VOL_ADC_VREF_BUF_INC,
VOL_ADC_IBIAS_SEL, /*VOL_ADC_CFG1*/
RLX_CUR_FILTER, TS_FUN, VOL_ADC_TSCUR_SEL,
VOL_CALIB_UPD, CUR_CALIB_UPD, /*ADC_CONFIG1*/
CUR_OUT_MOD, VOL_OUT_MOD, FRAME_SMP_INTERV,
ADC_OFF_CAL_INTERV, RLX_SPT, /*GG_CON*/
OCV_UPD, RELAX_STS, RELAX_VOL2_UPD, RELAX_VOL1_UPD, BAT_CON,
QMAX_UPD_SOFT, TERM_UPD, OCV_STS, /*GG_STS*/
RELAX_THRE_H, RELAX_THRE_L, /*RELAX_THRE*/
RELAX_VOL1_H, RELAX_VOL1_L,
RELAX_VOL2_H, RELAX_VOL2_L,
RELAX_CUR1_H, RELAX_CUR1_L,
RELAX_CUR2_H, RELAX_CUR2_L,
OCV_THRE_VOL,
OCV_VOL_H, OCV_VOL_L,
OCV_VOL0_H, OCV_VOL0_L,
OCV_CUR_H, OCV_CUR_L,
OCV_CUR0_H, OCV_CUR0_L,
PWRON_VOL_H, PWRON_VOL_L,
PWRON_CUR_H, PWRON_CUR_L,
OFF_CNT,
Q_INIT_H3, Q_INIT_H2, Q_INIT_L1, Q_INIT_L0,
Q_PRESS_H3, Q_PRESS_H2, Q_PRESS_L1, Q_PRESS_L0,
BAT_VOL_H, BAT_VOL_L,
BAT_CUR_H, BAT_CUR_L,
BAT_TS_H, BAT_TS_L,
USB_VOL_H, USB_VOL_L,
SYS_VOL_H, SYS_VOL_L,
Q_MAX_H3, Q_MAX_H2, Q_MAX_L1, Q_MAX_L0,
Q_TERM_H3, Q_TERM_H2, Q_TERM_L1, Q_TERM_L0,
Q_OCV_H3, Q_OCV_H2, Q_OCV_L1, Q_OCV_L0,
OCV_CNT,
SLEEP_CON_SAMP_CUR_H, SLEEP_CON_SAMP_CUR_L,
CAL_OFFSET_H, CAL_OFFSET_L,
VCALIB0_H, VCALIB0_L,
VCALIB1_H, VCALIB1_L,
IOFFSET_H, IOFFSET_L,
BAT_R0, SOC_REG0, SOC_REG1, SOC_REG2,
REMAIN_CAP_REG2, REMAIN_CAP_REG1, REMAIN_CAP_REG0,
NEW_FCC_REG2, NEW_FCC_REG1, NEW_FCC_REG0,
RESET_MODE,
FG_INIT, HALT_CNT_REG, CALC_REST_REGL, CALC_REST_REGH,
VOL_ADC_B3, VOL_ADC_B2, VOL_ADC_B1, VOL_ADC_B0,
VOL_ADC_K3, VOL_ADC_K2, VOL_ADC_K1, VOL_ADC_K0,
BAT_EXS, CHG_STS, BAT_OVP_STS, CHRG_IN_CLAMP,
CHIP_NAME_H, CHIP_NAME_L,
PLUG_IN_STS,
F_MAX_FIELDS
};
static const struct reg_field rk817_battery_reg_fields[] = {
[ADC_SLP_RATE] = REG_FIELD(0x50, 0, 0),
[BAT_CUR_ADC_EN] = REG_FIELD(0x50, 2, 2),
[BAT_VOL_ADC_EN] = REG_FIELD(0x50, 3, 3),
[USB_VOL_ADC_EN] = REG_FIELD(0x50, 4, 4),
[TS_ADC_EN] = REG_FIELD(0x50, 5, 5),
[SYS_VOL_ADC_EN] = REG_FIELD(0x50, 6, 6),
[GG_EN] = REG_FIELD(0x50, 7, 7),/*ADC_CONFIG0*/
[CUR_ADC_DITH_SEL] = REG_FIELD(0x51, 1, 3),
[CUR_ADC_DIH_EN] = REG_FIELD(0x51, 4, 4),
[CUR_ADC_CHOP_EN] = REG_FIELD(0x51, 5, 5),
[CUR_ADC_CHOP_SEL] = REG_FIELD(0x51, 6, 6),
[CUR_ADC_CHOP_VREF_EN] = REG_FIELD(0x51, 7, 7), /*CUR_ADC_COFG0*/
[CUR_ADC_VCOM_SEL] = REG_FIELD(0x52, 0, 1),
[CUR_ADC_VCOM_BUF_INC] = REG_FIELD(0x52, 2, 2),
[CUR_ADC_VREF_BUF_INC] = REG_FIELD(0x52, 3, 3),
[CUR_ADC_BIAS_DEC] = REG_FIELD(0x52, 4, 4),
[CUR_ADC_IBIAS_SEL] = REG_FIELD(0x52, 5, 6), /*CUR_ADC_COFG1*/
[VOL_ADC_EXT_VREF_EN] = REG_FIELD(0x53, 0, 0),
[VOL_ADC_DITH_SEL] = REG_FIELD(0x53, 1, 3),
[VOL_ADC_DITH_EN] = REG_FIELD(0x53, 4, 4),
[VOL_ADC_CHOP_EN] = REG_FIELD(0x53, 5, 5),
[VOL_ADC_CHOP_SEL] = REG_FIELD(0x53, 6, 6),
[VOL_ADC_CHOP_VREF_EN] = REG_FIELD(0x53, 7, 7),/*VOL_ADC_COFG0*/
[VOL_ADC_VCOM_SEL] = REG_FIELD(0x54, 0, 1),
[VOL_ADC_VCOM_BUF_INC] = REG_FIELD(0x54, 2, 2),
[VOL_ADC_VREF_BUF_INC] = REG_FIELD(0x54, 3, 3),
[VOL_ADC_IBIAS_SEL] = REG_FIELD(0x54, 5, 6), /*VOL_ADC_COFG1*/
[RLX_CUR_FILTER] = REG_FIELD(0x55, 0, 1),
[TS_FUN] = REG_FIELD(0x55, 3, 3),
[VOL_ADC_TSCUR_SEL] = REG_FIELD(0x55, 4, 5),
[VOL_CALIB_UPD] = REG_FIELD(0x55, 6, 6),
[CUR_CALIB_UPD] = REG_FIELD(0x55, 7, 7), /*ADC_CONFIG1*/
[CUR_OUT_MOD] = REG_FIELD(0x56, 0, 0),
[VOL_OUT_MOD] = REG_FIELD(0x56, 1, 1),
[FRAME_SMP_INTERV] = REG_FIELD(0x56, 2, 3),
[ADC_OFF_CAL_INTERV] = REG_FIELD(0x56, 4, 5),
[RLX_SPT] = REG_FIELD(0x56, 6, 7), /*GG_CON*/
[OCV_UPD] = REG_FIELD(0x57, 0, 0),
[RELAX_STS] = REG_FIELD(0x57, 1, 1),
[RELAX_VOL2_UPD] = REG_FIELD(0x57, 2, 2),
[RELAX_VOL1_UPD] = REG_FIELD(0x57, 3, 3),
[BAT_CON] = REG_FIELD(0x57, 4, 4),
[QMAX_UPD_SOFT] = REG_FIELD(0x57, 5, 5),
[TERM_UPD] = REG_FIELD(0x57, 6, 6),
[OCV_STS] = REG_FIELD(0x57, 7, 7), /*GG_STS*/
[RELAX_THRE_H] = REG_FIELD(0x58, 0, 7),
[RELAX_THRE_L] = REG_FIELD(0x59, 0, 7),
[RELAX_VOL1_H] = REG_FIELD(0x5A, 0, 7),
[RELAX_VOL1_L] = REG_FIELD(0x5B, 0, 7),
[RELAX_VOL2_H] = REG_FIELD(0x5C, 0, 7),
[RELAX_VOL2_L] = REG_FIELD(0x5D, 0, 7),
[RELAX_CUR1_H] = REG_FIELD(0x5E, 0, 7),
[RELAX_CUR1_L] = REG_FIELD(0x5F, 0, 7),
[RELAX_CUR2_H] = REG_FIELD(0x60, 0, 7),
[RELAX_CUR2_L] = REG_FIELD(0x61, 0, 7),
[OCV_THRE_VOL] = REG_FIELD(0x62, 0, 7),
[OCV_VOL_H] = REG_FIELD(0x63, 0, 7),
[OCV_VOL_L] = REG_FIELD(0x64, 0, 7),
[OCV_VOL0_H] = REG_FIELD(0x65, 0, 7),
[OCV_VOL0_L] = REG_FIELD(0x66, 0, 7),
[OCV_CUR_H] = REG_FIELD(0x67, 0, 7),
[OCV_CUR_L] = REG_FIELD(0x68, 0, 7),
[OCV_CUR0_H] = REG_FIELD(0x69, 0, 7),
[OCV_CUR0_L] = REG_FIELD(0x6A, 0, 7),
[PWRON_VOL_H] = REG_FIELD(0x6B, 0, 7),
[PWRON_VOL_L] = REG_FIELD(0x6C, 0, 7),
[PWRON_CUR_H] = REG_FIELD(0x6D, 0, 7),
[PWRON_CUR_L] = REG_FIELD(0x6E, 0, 7),
[OFF_CNT] = REG_FIELD(0x6F, 0, 7),
[Q_INIT_H3] = REG_FIELD(0x70, 0, 7),
[Q_INIT_H2] = REG_FIELD(0x71, 0, 7),
[Q_INIT_L1] = REG_FIELD(0x72, 0, 7),
[Q_INIT_L0] = REG_FIELD(0x73, 0, 7),
[Q_PRESS_H3] = REG_FIELD(0x74, 0, 7),
[Q_PRESS_H2] = REG_FIELD(0x75, 0, 7),
[Q_PRESS_L1] = REG_FIELD(0x76, 0, 7),
[Q_PRESS_L0] = REG_FIELD(0x77, 0, 7),
[BAT_VOL_H] = REG_FIELD(0x78, 0, 7),
[BAT_VOL_L] = REG_FIELD(0x79, 0, 7),
[BAT_CUR_H] = REG_FIELD(0x7A, 0, 7),
[BAT_CUR_L] = REG_FIELD(0x7B, 0, 7),
[BAT_TS_H] = REG_FIELD(0x7C, 0, 7),
[BAT_TS_L] = REG_FIELD(0x7D, 0, 7),
[USB_VOL_H] = REG_FIELD(0x7E, 0, 7),
[USB_VOL_L] = REG_FIELD(0x7F, 0, 7),
[SYS_VOL_H] = REG_FIELD(0x80, 0, 7),
[SYS_VOL_L] = REG_FIELD(0x81, 0, 7),
[Q_MAX_H3] = REG_FIELD(0x82, 0, 7),
[Q_MAX_H2] = REG_FIELD(0x83, 0, 7),
[Q_MAX_L1] = REG_FIELD(0x84, 0, 7),
[Q_MAX_L0] = REG_FIELD(0x85, 0, 7),
[Q_TERM_H3] = REG_FIELD(0x86, 0, 7),
[Q_TERM_H2] = REG_FIELD(0x87, 0, 7),
[Q_TERM_L1] = REG_FIELD(0x88, 0, 7),
[Q_TERM_L0] = REG_FIELD(0x89, 0, 7),
[Q_OCV_H3] = REG_FIELD(0x8A, 0, 7),
[Q_OCV_H2] = REG_FIELD(0x8B, 0, 7),
[Q_OCV_L1] = REG_FIELD(0x8C, 0, 7),
[Q_OCV_L0] = REG_FIELD(0x8D, 0, 7),
[OCV_CNT] = REG_FIELD(0x8E, 0, 7),
[SLEEP_CON_SAMP_CUR_H] = REG_FIELD(0x8F, 0, 7),
[SLEEP_CON_SAMP_CUR_L] = REG_FIELD(0x90, 0, 7),
[CAL_OFFSET_H] = REG_FIELD(0x91, 0, 7),
[CAL_OFFSET_L] = REG_FIELD(0x92, 0, 7),
[VCALIB0_H] = REG_FIELD(0x93, 0, 7),
[VCALIB0_L] = REG_FIELD(0x94, 0, 7),
[VCALIB1_H] = REG_FIELD(0x95, 0, 7),
[VCALIB1_L] = REG_FIELD(0x96, 0, 7),
[IOFFSET_H] = REG_FIELD(0x97, 0, 7),
[IOFFSET_L] = REG_FIELD(0x98, 0, 7),
[BAT_R0] = REG_FIELD(0x99, 0, 7),
[SOC_REG0] = REG_FIELD(0x9A, 0, 7),
[SOC_REG1] = REG_FIELD(0x9B, 0, 7),
[SOC_REG2] = REG_FIELD(0x9C, 0, 7),
[REMAIN_CAP_REG0] = REG_FIELD(0x9D, 0, 7),
[REMAIN_CAP_REG1] = REG_FIELD(0x9E, 0, 7),
[REMAIN_CAP_REG2] = REG_FIELD(0x9F, 0, 7),
[NEW_FCC_REG0] = REG_FIELD(0xA0, 0, 7),
[NEW_FCC_REG1] = REG_FIELD(0xA1, 0, 7),
[NEW_FCC_REG2] = REG_FIELD(0xA2, 0, 7),
[RESET_MODE] = REG_FIELD(0xA3, 0, 3),
[FG_INIT] = REG_FIELD(0xA5, 7, 7),
[HALT_CNT_REG] = REG_FIELD(0xA6, 0, 7),
[CALC_REST_REGL] = REG_FIELD(0xA7, 0, 7),
[CALC_REST_REGH] = REG_FIELD(0xA8, 0, 7),
[VOL_ADC_B3] = REG_FIELD(0xA9, 0, 7),
[VOL_ADC_B2] = REG_FIELD(0xAA, 0, 7),
[VOL_ADC_B1] = REG_FIELD(0xAB, 0, 7),
[VOL_ADC_B0] = REG_FIELD(0xAC, 0, 7),
[VOL_ADC_K3] = REG_FIELD(0xAD, 0, 7),
[VOL_ADC_K2] = REG_FIELD(0xAE, 0, 7),
[VOL_ADC_K1] = REG_FIELD(0xAF, 0, 7),
[VOL_ADC_K0] = REG_FIELD(0xB0, 0, 7),
[BAT_EXS] = REG_FIELD(0xEB, 7, 7),
[CHG_STS] = REG_FIELD(0xEB, 4, 6),
[BAT_OVP_STS] = REG_FIELD(0xEB, 3, 3),
[CHRG_IN_CLAMP] = REG_FIELD(0xEB, 2, 2),
[CHIP_NAME_H] = REG_FIELD(0xED, 0, 7),
[CHIP_NAME_L] = REG_FIELD(0xEE, 0, 7),
[PLUG_IN_STS] = REG_FIELD(0xF0, 6, 6),
};
struct battery_platform_data {
u32 *ocv_table;
u32 *zero_table;
u32 table_t[4][21];
int temp_t[4];
u32 temp_t_num;
u32 *ntc_table;
u32 ocv_size;
u32 ntc_size;
int ntc_degree_from;
u32 ntc_factor;
u32 max_input_current;
u32 max_chrg_current;
u32 max_chrg_voltage;
u32 lp_input_current;
u32 lp_soc_min;
u32 lp_soc_max;
u32 pwroff_vol;
u32 monitor_sec;
u32 zero_algorithm_vol;
u32 zero_reserve_dsoc;
u32 bat_res;
u32 design_capacity;
u32 design_qmax;
u32 sleep_enter_current;
u32 sleep_exit_current;
u32 sleep_filter_current;
u32 power_dc2otg;
u32 max_soc_offset;
u32 bat_mode;
u32 fb_temp;
u32 energy_mode;
u32 cccv_hour;
u32 dc_det_adc;
int dc_det_pin;
u8 dc_det_level;
u32 sample_res;
u32 bat_res_up;
u32 bat_res_down;
u32 design_max_voltage;
bool extcon;
};
struct rk817_battery_device {
struct platform_device *pdev;
struct device *dev;
struct i2c_client *client;
struct rk808 *rk817;
struct power_supply *bat;
struct power_supply *chg_psy;
struct power_supply *usb_psy;
struct power_supply *ac_psy;
struct regmap *regmap;
struct regmap_field *rmap_fields[F_MAX_FIELDS];
struct battery_platform_data *pdata;
struct workqueue_struct *bat_monitor_wq;
struct delayed_work bat_delay_work;
struct delayed_work calib_delay_work;
struct wake_lock wake_lock;
struct timer_list caltimer;
int res_div;
int bat_res;
bool is_first_power_on;
int chrg_status;
int res_fac;
int over_20mR;
bool is_initialized;
bool bat_first_power_on;
u8 ac_in;
u8 usb_in;
u8 otg_in;
u8 dc_in;
u8 prop_status;
int cvtlmt_irq;
int current_avg;
int current_relax;
int voltage_usb;
int voltage_sys;
int voltage_avg;
int voltage_ocv;
int voltage_relax;
int voltage_k;/* VCALIB0 VCALIB1 */
int voltage_b;
u32 remain_cap;
int design_cap;
int nac;
int fcc;
int lock_fcc;
int qmax;
int dsoc;
int rsoc;
int poffset;
int fake_offline;
int age_ocv_soc;
bool age_allow_update;
int age_level;
int age_ocv_cap;
int pwron_voltage;
int age_voltage;
int age_adjust_cap;
unsigned long age_keep_sec;
int zero_timeout_cnt;
int zero_remain_cap;
int zero_dsoc;
int zero_linek;
u64 zero_drop_sec;
u64 shtd_drop_sec;
int powerpatch_res;
int zero_voltage_avg;
int zero_current_avg;
int zero_vsys;
int zero_dead_voltage;
int zero_dead_soc;
int zero_dead_cap;
int zero_batvol_to_ocv;
int zero_batocv_to_soc;
int zero_batocv_to_cap;
int zero_xsoc;
unsigned long finish_base;
time_t rtc_base;
int sm_remain_cap;
int sm_linek;
int sm_chrg_dsoc;
int sm_dischrg_dsoc;
int smooth_soc;
int algo_rest_val;
int algo_rest_mode;
int sleep_sum_cap;
int sleep_remain_cap;
unsigned long sleep_dischrg_sec;
unsigned long sleep_sum_sec;
bool sleep_chrg_online;
u8 sleep_chrg_status;
bool adc_allow_update;
int fb_blank;
bool s2r; /*suspend to resume*/
u32 work_mode;
int temperature;
int chrg_cur_lp_input;
int chrg_vol_sel;
int chrg_cur_input;
int chrg_cur_sel;
u32 monitor_ms;
u32 pwroff_min;
u32 adc_calib_cnt;
unsigned long chrg_finish_base;
unsigned long boot_base;
unsigned long flat_match_sec;
unsigned long plug_in_base;
unsigned long plug_out_base;
u8 halt_cnt;
bool is_halt;
bool is_max_soc_offset;
bool is_sw_reset;
bool is_ocv_calib;
bool is_first_on;
bool is_force_calib;
int last_dsoc;
u8 cvtlmt_int_event;
u8 slp_dcdc_en_reg;
int ocv_pre_dsoc;
int ocv_new_dsoc;
int max_pre_dsoc;
int max_new_dsoc;
int force_pre_dsoc;
int force_new_dsoc;
int dbg_cap_low0;
int dbg_pwr_dsoc;
int dbg_pwr_rsoc;
int dbg_pwr_vol;
int dbg_chrg_min[10];
int dbg_meet_soc;
int dbg_calc_dsoc;
int dbg_calc_rsoc;
int is_charging;
unsigned long charge_count;
u8 plugin_trigger;
u8 plugout_trigger;
int plugin_irq;
int plugout_irq;
int chip_id;
int is_register_chg_psy;
};
static u64 get_boot_sec(void)
{
struct timespec ts;
get_monotonic_boottime(&ts);
return ts.tv_sec;
}
static unsigned long base2sec(unsigned long x)
{
if (x)
return (get_boot_sec() > x) ? (get_boot_sec() - x) : 0;
else
return 0;
}
static u32 interpolate(int value, u32 *table, int size)
{
u8 i;
u16 d;
for (i = 0; i < size; i++) {
if (value < table[i])
break;
}
if ((i > 0) && (i < size)) {
d = (value - table[i - 1]) * (MAX_INTERPOLATE / (size - 1));
d /= table[i] - table[i - 1];
d = d + (i - 1) * (MAX_INTERPOLATE / (size - 1));
} else {
d = i * ((MAX_INTERPOLATE + size / 2) / size);
}
if (d > 1000)
d = 1000;
return d;
}
/* (a * b) / c */
static int32_t ab_div_c(u32 a, u32 b, u32 c)
{
bool sign;
u32 ans = MAX_INT;
int tmp;
sign = ((((a ^ b) ^ c) & 0x80000000) != 0);
if (c != 0) {
if (sign)
c = -c;
tmp = (a * b + (c >> 1)) / c;
if (tmp < MAX_INT)
ans = tmp;
}
if (sign)
ans = -ans;
return ans;
}
static int rk817_bat_field_read(struct rk817_battery_device *battery,
enum rk817_battery_fields field_id)
{
int val;
int ret;
ret = regmap_field_read(battery->rmap_fields[field_id], &val);
if (ret < 0)
return ret;
return val;
}
static int rk817_bat_field_write(struct rk817_battery_device *battery,
enum rk817_battery_fields field_id,
unsigned int val)
{
return regmap_field_write(battery->rmap_fields[field_id], val);
}
/*cal_offset: current offset value*/
static int rk817_bat_get_coffset(struct rk817_battery_device *battery)
{
int coffset_value = 0;
coffset_value |= rk817_bat_field_read(battery, CAL_OFFSET_H) << 8;
coffset_value |= rk817_bat_field_read(battery, CAL_OFFSET_L);
return coffset_value;
}
static void rk817_bat_set_coffset(struct rk817_battery_device *battery, int val)
{
u8 buf = 0;
buf = (val >> 8) & 0xff;
rk817_bat_field_write(battery, CAL_OFFSET_H, buf);
buf = (val >> 0) & 0xff;
rk817_bat_field_write(battery, CAL_OFFSET_L, buf);
}
/* current offset value calculated */
static int rk817_bat_get_ioffset(struct rk817_battery_device *battery)
{
int ioffset_value = 0;
ioffset_value |= rk817_bat_field_read(battery, IOFFSET_H) << 8;
ioffset_value |= rk817_bat_field_read(battery, IOFFSET_L);
return ioffset_value;
}
static void rk817_bat_current_calibration(struct rk817_battery_device *battery)
{
int pwron_value, ioffset, cal_offset;
pwron_value = rk817_bat_field_read(battery, PWRON_CUR_H) << 8;
pwron_value |= rk817_bat_field_read(battery, PWRON_CUR_L);
ioffset = rk817_bat_get_ioffset(battery);
DBG("Caloffset: 0x%x\n", rk817_bat_get_coffset(battery));
DBG("IOFFSET: 0x%x\n", ioffset);
if (0)
cal_offset = pwron_value + ioffset;
else
cal_offset = ioffset;
rk817_bat_set_coffset(battery, cal_offset);
DBG("Caloffset: 0x%x\n", rk817_bat_get_coffset(battery));
}
static int rk817_bat_get_vaclib0(struct rk817_battery_device *battery)
{
int vcalib_value = 0;
vcalib_value |= rk817_bat_field_read(battery, VCALIB0_H) << 8;
vcalib_value |= rk817_bat_field_read(battery, VCALIB0_L);
return vcalib_value;
}
static int rk817_bat_get_vaclib1(struct rk817_battery_device *battery)
{
int vcalib_value = 0;
vcalib_value |= rk817_bat_field_read(battery, VCALIB1_H) << 8;
vcalib_value |= rk817_bat_field_read(battery, VCALIB1_L);
return vcalib_value;
}
static void rk817_bat_init_voltage_kb(struct rk817_battery_device *battery)
{
int vcalib0, vcalib1;
vcalib0 = rk817_bat_get_vaclib0(battery);
vcalib1 = rk817_bat_get_vaclib1(battery);
if (battery->chip_id == RK809_ID) {
battery->voltage_k = (1050 - 600) * 1000 / DIV(vcalib1 - vcalib0);
battery->voltage_b = 1050 - (battery->voltage_k * vcalib1) / 1000;
} else {
battery->voltage_k = (4025 - 2300) * 1000 / DIV(vcalib1 - vcalib0);
battery->voltage_b = 4025 - (battery->voltage_k * vcalib1) / 1000;
}
}
static void rk817_bat_restart_relax(struct rk817_battery_device *battery)
{
rk817_bat_field_write(battery, RELAX_VOL1_UPD, 0x00);
rk817_bat_field_write(battery, RELAX_VOL2_UPD, 0x00);
}
static bool is_rk817_bat_relax_mode(struct rk817_battery_device *battery)
{
u8 relax_sts, relax_vol1_upd, relax_vol2_upd;
relax_sts = rk817_bat_field_read(battery, RELAX_STS);
relax_vol1_upd = rk817_bat_field_read(battery, RELAX_VOL1_UPD);
relax_vol2_upd = rk817_bat_field_read(battery, RELAX_VOL2_UPD);
DBG("RELAX_STS: %d\n", relax_sts);
DBG("RELAX_VOL1_UPD: %d\n", relax_vol1_upd);
DBG("RELAX_VOL2_UPD: %d\n", relax_vol2_upd);
if (relax_sts && relax_vol1_upd && relax_vol2_upd)
return true;
else
return false;
}
static u16 rk817_bat_get_relax_vol1(struct rk817_battery_device *battery)
{
u16 vol, val = 0;
val = rk817_bat_field_read(battery, RELAX_VOL1_H) << 8;
val |= rk817_bat_field_read(battery, RELAX_VOL1_L);
vol = battery->voltage_k * val / 1000 + battery->voltage_b;
return vol;
}
static u16 rk817_bat_get_relax_vol2(struct rk817_battery_device *battery)
{
u16 vol, val = 0;
val = rk817_bat_field_read(battery, RELAX_VOL2_H) << 8;
val |= rk817_bat_field_read(battery, RELAX_VOL2_L);
vol = battery->voltage_k * val / 1000 + battery->voltage_b;
return vol;
}
static u16 rk817_bat_get_relax_voltage(struct rk817_battery_device *battery)
{
u16 relax_vol1, relax_vol2;
if (!is_rk817_bat_relax_mode(battery))
return 0;
relax_vol1 = rk817_bat_get_relax_vol1(battery);
relax_vol2 = rk817_bat_get_relax_vol2(battery);
return relax_vol1 > relax_vol2 ? relax_vol1 : relax_vol2;
}
static void rk817_bat_set_relax_sample(struct rk817_battery_device *battery)
{
u8 buf;
int enter_thres, filter_thres;
struct battery_platform_data *pdata = battery->pdata;
filter_thres = pdata->sleep_filter_current * 1000 / 1506;
enter_thres = CURRENT_TO_ADC(pdata->sleep_enter_current,
battery->res_div);
filter_thres = CURRENT_TO_ADC(pdata->sleep_filter_current,
battery->res_div);
/* set relax enter and exit threshold */
buf = (enter_thres >> 8) & 0xff;
rk817_bat_field_write(battery, RELAX_THRE_H, buf);
buf = enter_thres & 0xff;
rk817_bat_field_write(battery, RELAX_THRE_L, buf);
/* set sample current threshold */
buf = (filter_thres >> 8) & 0xff;
rk817_bat_field_write(battery, SLEEP_CON_SAMP_CUR_H, buf);
buf = filter_thres & 0xff;
rk817_bat_field_write(battery, SLEEP_CON_SAMP_CUR_L, buf);
/* reset relax update state */
rk817_bat_restart_relax(battery);
DBG("<%s>. sleep_enter_current = %d, sleep_exit_current = %d\n",
__func__, pdata->sleep_enter_current, pdata->sleep_exit_current);
}
/* runtime OCV voltage, |RLX_VOL2 - RLX_VOL1| < OCV_THRE,
* the OCV reg update every 120s
*/
static void rk817_bat_ocv_thre(struct rk817_battery_device *battery, int value)
{
rk817_bat_field_write(battery, OCV_THRE_VOL, value);
}
static int rk817_bat_get_ocv_voltage(struct rk817_battery_device *battery)
{
int vol, val = 0, vol_temp;
val = rk817_bat_field_read(battery, OCV_VOL_H) << 8;
val |= rk817_bat_field_read(battery, OCV_VOL_L);
vol = battery->voltage_k * val / 1000 + battery->voltage_b;
if (battery->chip_id == RK809_ID) {
vol_temp = vol * battery->pdata->bat_res_up /
battery->pdata->bat_res_down + vol;
vol = vol_temp;
}
return vol;
}
static int rk817_bat_get_ocv0_voltage0(struct rk817_battery_device *battery)
{
int vol, val = 0, vol_temp;
val = rk817_bat_field_read(battery, OCV_VOL0_H) << 8;
val |= rk817_bat_field_read(battery, OCV_VOL0_L);
vol = battery->voltage_k * val / 1000 + battery->voltage_b;
if (battery->chip_id == RK809_ID) {
vol_temp = vol * battery->pdata->bat_res_up /
battery->pdata->bat_res_down + vol;
vol = vol_temp;
}
return vol;
}
/* power on battery voltage */
static int rk817_bat_get_pwron_voltage(struct rk817_battery_device *battery)
{
int vol, val = 0, vol_temp;
val = rk817_bat_field_read(battery, PWRON_VOL_H) << 8;
val |= rk817_bat_field_read(battery, PWRON_VOL_L);
vol = battery->voltage_k * val / 1000 + battery->voltage_b;
if (battery->chip_id == RK809_ID) {
vol_temp = vol * battery->pdata->bat_res_up /
battery->pdata->bat_res_down + vol;
vol = vol_temp;
}
return vol;
}
static int rk817_bat_get_battery_voltage(struct rk817_battery_device *battery)
{
int vol, val = 0, vol_temp;
int vcalib0, vcalib1;
vcalib0 = rk817_bat_get_vaclib0(battery);
vcalib1 = rk817_bat_get_vaclib1(battery);
val = rk817_bat_field_read(battery, BAT_VOL_H) << 8;
val |= rk817_bat_field_read(battery, BAT_VOL_L) << 0;
vol = battery->voltage_k * val / 1000 + battery->voltage_b;
if (battery->chip_id == RK809_ID) {
vol_temp = vol * battery->pdata->bat_res_up /
battery->pdata->bat_res_down + vol;
vol = vol_temp;
}
return vol;
}
static int rk817_bat_get_USB_voltage(struct rk817_battery_device *battery)
{
int vol, val = 0, vol_temp;
rk817_bat_field_write(battery, USB_VOL_ADC_EN, 0x01);
val = rk817_bat_field_read(battery, USB_VOL_H) << 8;
val |= rk817_bat_field_read(battery, USB_VOL_L) << 0;
vol = (battery->voltage_k * val / 1000 + battery->voltage_b) * 60 / 46;
if (battery->chip_id == RK809_ID) {
vol_temp = vol * battery->pdata->bat_res_up /
battery->pdata->bat_res_down + vol;
vol = vol_temp;
}
return vol;
}
static int rk817_bat_get_sys_voltage(struct rk817_battery_device *battery)
{
int vol, val = 0, vol_temp;
val = rk817_bat_field_read(battery, SYS_VOL_H) << 8;
val |= rk817_bat_field_read(battery, SYS_VOL_L) << 0;
vol = (battery->voltage_k * val / 1000 + battery->voltage_b) * 60 / 46;
if (battery->chip_id == RK809_ID) {
vol_temp = vol * battery->pdata->bat_res_up /
battery->pdata->bat_res_down + vol;
vol = vol_temp;
}
return vol;