blob: 2a47442ead6565c5549407ce60b0bc4078eada14 [file] [log] [blame]
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "FG: %s: " fmt, __func__
14
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -080015#include <linux/ktime.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070016#include <linux/of.h>
17#include <linux/of_irq.h>
18#include <linux/of_platform.h>
19#include <linux/of_batterydata.h>
20#include <linux/platform_device.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070021#include <linux/iio/consumer.h>
22#include <linux/qpnp/qpnp-revid.h>
23#include "fg-core.h"
24#include "fg-reg.h"
25
26#define FG_GEN3_DEV_NAME "qcom,fg-gen3"
27
28#define PERPH_SUBTYPE_REG 0x05
Harry Yang2452b272017-03-06 13:56:14 -080029#define FG_BATT_SOC_PMI8998 0x10
30#define FG_BATT_INFO_PMI8998 0x11
31#define FG_MEM_INFO_PMI8998 0x0D
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070032
33/* SRAM address and offset in ascending order */
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -070034#define ESR_PULSE_THRESH_WORD 2
35#define ESR_PULSE_THRESH_OFFSET 3
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -080036#define SLOPE_LIMIT_WORD 3
37#define SLOPE_LIMIT_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070038#define CUTOFF_VOLT_WORD 5
39#define CUTOFF_VOLT_OFFSET 0
40#define SYS_TERM_CURR_WORD 6
41#define SYS_TERM_CURR_OFFSET 0
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -070042#define VBATT_FULL_WORD 7
43#define VBATT_FULL_OFFSET 0
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -080044#define ESR_FILTER_WORD 8
45#define ESR_UPD_TIGHT_OFFSET 0
46#define ESR_UPD_BROAD_OFFSET 1
47#define ESR_UPD_TIGHT_LOW_TEMP_OFFSET 2
48#define ESR_UPD_BROAD_LOW_TEMP_OFFSET 3
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -070049#define KI_COEFF_MED_DISCHG_WORD 9
Anirudh Ghayalddabeee2017-04-04 06:13:48 +053050#define TIMEBASE_OFFSET 1
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -070051#define KI_COEFF_MED_DISCHG_OFFSET 3
52#define KI_COEFF_HI_DISCHG_WORD 10
53#define KI_COEFF_HI_DISCHG_OFFSET 0
54#define KI_COEFF_LOW_DISCHG_WORD 10
55#define KI_COEFF_LOW_DISCHG_OFFSET 2
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -070056#define KI_COEFF_FULL_SOC_WORD 12
57#define KI_COEFF_FULL_SOC_OFFSET 2
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -080058#define DELTA_MSOC_THR_WORD 12
59#define DELTA_MSOC_THR_OFFSET 3
60#define DELTA_BSOC_THR_WORD 13
61#define DELTA_BSOC_THR_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070062#define RECHARGE_SOC_THR_WORD 14
63#define RECHARGE_SOC_THR_OFFSET 0
64#define CHG_TERM_CURR_WORD 14
65#define CHG_TERM_CURR_OFFSET 1
66#define EMPTY_VOLT_WORD 15
67#define EMPTY_VOLT_OFFSET 0
68#define VBATT_LOW_WORD 15
69#define VBATT_LOW_OFFSET 1
Nicholas Troastdcf8fe62016-08-04 14:30:02 -070070#define ESR_TIMER_DISCHG_MAX_WORD 17
71#define ESR_TIMER_DISCHG_MAX_OFFSET 0
72#define ESR_TIMER_DISCHG_INIT_WORD 17
73#define ESR_TIMER_DISCHG_INIT_OFFSET 2
74#define ESR_TIMER_CHG_MAX_WORD 18
75#define ESR_TIMER_CHG_MAX_OFFSET 0
76#define ESR_TIMER_CHG_INIT_WORD 18
77#define ESR_TIMER_CHG_INIT_OFFSET 2
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -070078#define ESR_EXTRACTION_ENABLE_WORD 19
79#define ESR_EXTRACTION_ENABLE_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070080#define PROFILE_LOAD_WORD 24
81#define PROFILE_LOAD_OFFSET 0
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -080082#define ESR_RSLOW_DISCHG_WORD 34
83#define ESR_RSLOW_DISCHG_OFFSET 0
84#define ESR_RSLOW_CHG_WORD 51
85#define ESR_RSLOW_CHG_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070086#define NOM_CAP_WORD 58
87#define NOM_CAP_OFFSET 0
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -070088#define ACT_BATT_CAP_BKUP_WORD 74
89#define ACT_BATT_CAP_BKUP_OFFSET 0
Nicholas Troaste29dec92016-08-24 09:35:11 -070090#define CYCLE_COUNT_WORD 75
91#define CYCLE_COUNT_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070092#define PROFILE_INTEGRITY_WORD 79
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -080093#define SW_CONFIG_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070094#define PROFILE_INTEGRITY_OFFSET 3
95#define BATT_SOC_WORD 91
96#define BATT_SOC_OFFSET 0
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -070097#define FULL_SOC_WORD 93
98#define FULL_SOC_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070099#define MONOTONIC_SOC_WORD 94
100#define MONOTONIC_SOC_OFFSET 2
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700101#define CC_SOC_WORD 95
102#define CC_SOC_OFFSET 0
103#define CC_SOC_SW_WORD 96
104#define CC_SOC_SW_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700105#define VOLTAGE_PRED_WORD 97
106#define VOLTAGE_PRED_OFFSET 0
107#define OCV_WORD 97
108#define OCV_OFFSET 2
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800109#define ESR_WORD 99
110#define ESR_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700111#define RSLOW_WORD 101
112#define RSLOW_OFFSET 0
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700113#define ACT_BATT_CAP_WORD 117
114#define ACT_BATT_CAP_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700115#define LAST_BATT_SOC_WORD 119
116#define LAST_BATT_SOC_OFFSET 0
117#define LAST_MONOTONIC_SOC_WORD 119
118#define LAST_MONOTONIC_SOC_OFFSET 2
Nicholas Troast69da2252016-09-07 16:17:47 -0700119#define ALG_FLAGS_WORD 120
120#define ALG_FLAGS_OFFSET 1
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700121
Nicholas Troasta2b40372016-08-15 10:45:39 -0700122/* v2 SRAM address and offset in ascending order */
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700123#define KI_COEFF_LOW_DISCHG_v2_WORD 9
124#define KI_COEFF_LOW_DISCHG_v2_OFFSET 3
125#define KI_COEFF_MED_DISCHG_v2_WORD 10
126#define KI_COEFF_MED_DISCHG_v2_OFFSET 0
127#define KI_COEFF_HI_DISCHG_v2_WORD 10
128#define KI_COEFF_HI_DISCHG_v2_OFFSET 1
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800129#define DELTA_BSOC_THR_v2_WORD 12
130#define DELTA_BSOC_THR_v2_OFFSET 3
131#define DELTA_MSOC_THR_v2_WORD 13
132#define DELTA_MSOC_THR_v2_OFFSET 0
Nicholas Troasta2b40372016-08-15 10:45:39 -0700133#define RECHARGE_SOC_THR_v2_WORD 14
134#define RECHARGE_SOC_THR_v2_OFFSET 1
135#define CHG_TERM_CURR_v2_WORD 15
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -0700136#define CHG_TERM_BASE_CURR_v2_OFFSET 0
Nicholas Troasta2b40372016-08-15 10:45:39 -0700137#define CHG_TERM_CURR_v2_OFFSET 1
138#define EMPTY_VOLT_v2_WORD 15
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -0700139#define EMPTY_VOLT_v2_OFFSET 3
Nicholas Troasta2b40372016-08-15 10:45:39 -0700140#define VBATT_LOW_v2_WORD 16
141#define VBATT_LOW_v2_OFFSET 0
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -0800142#define RECHARGE_VBATT_THR_v2_WORD 16
143#define RECHARGE_VBATT_THR_v2_OFFSET 1
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700144#define FLOAT_VOLT_v2_WORD 16
145#define FLOAT_VOLT_v2_OFFSET 2
Nicholas Troasta2b40372016-08-15 10:45:39 -0700146
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700147static int fg_decode_voltage_15b(struct fg_sram_param *sp,
148 enum fg_sram_param_id id, int val);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700149static int fg_decode_value_16b(struct fg_sram_param *sp,
150 enum fg_sram_param_id id, int val);
151static int fg_decode_default(struct fg_sram_param *sp,
152 enum fg_sram_param_id id, int val);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700153static int fg_decode_cc_soc(struct fg_sram_param *sp,
154 enum fg_sram_param_id id, int value);
Nicholas Troasta2b40372016-08-15 10:45:39 -0700155static void fg_encode_voltage(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700156 enum fg_sram_param_id id, int val_mv, u8 *buf);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700157static void fg_encode_current(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700158 enum fg_sram_param_id id, int val_ma, u8 *buf);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700159static void fg_encode_default(struct fg_sram_param *sp,
160 enum fg_sram_param_id id, int val, u8 *buf);
161
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800162static struct fg_irq_info fg_irqs[FG_IRQ_MAX];
163
Nicholas Troasta2b40372016-08-15 10:45:39 -0700164#define PARAM(_id, _addr_word, _addr_byte, _len, _num, _den, _offset, \
165 _enc, _dec) \
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700166 [FG_SRAM_##_id] = { \
Nicholas Troasta2b40372016-08-15 10:45:39 -0700167 .addr_word = _addr_word, \
168 .addr_byte = _addr_byte, \
169 .len = _len, \
170 .numrtr = _num, \
171 .denmtr = _den, \
172 .offset = _offset, \
173 .encode = _enc, \
174 .decode = _dec, \
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700175 } \
176
Harry Yang2452b272017-03-06 13:56:14 -0800177static struct fg_sram_param pmi8998_v1_sram_params[] = {
Nicholas Troasta2b40372016-08-15 10:45:39 -0700178 PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700179 fg_decode_default),
Nicholas Troast1769fd32016-09-07 09:20:58 -0700180 PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
181 fg_decode_default),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800182 PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
183 244141, 0, NULL, fg_decode_voltage_15b),
184 PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700185 fg_decode_voltage_15b),
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800186 PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default,
187 fg_decode_value_16b),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800188 PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700189 fg_decode_value_16b),
Nicholas Troast69da2252016-09-07 16:17:47 -0700190 PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
191 fg_decode_default),
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700192 PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL,
193 fg_decode_cc_soc),
194 PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL,
195 fg_decode_cc_soc),
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -0700196 PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
197 1, 1, 0, NULL, fg_decode_default),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700198 /* Entries below here are configurable during initialization */
199 PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700200 244141, 0, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700201 PARAM(EMPTY_VOLT, EMPTY_VOLT_WORD, EMPTY_VOLT_OFFSET, 1, 100000, 390625,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700202 -2500, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700203 PARAM(VBATT_LOW, VBATT_LOW_WORD, VBATT_LOW_OFFSET, 1, 100000, 390625,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700204 -2500, fg_encode_voltage, NULL),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800205 PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
206 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700207 PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700208 1000000, 122070, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700209 PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700210 100000, 390625, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800211 PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1,
212 2048, 100, 0, fg_encode_default, NULL),
213 PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1,
214 2048, 100, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700215 PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700216 1, 256, 100, 0, fg_encode_default, NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700217 PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700218 ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
219 NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700220 PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700221 ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700222 NULL),
223 PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700224 ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700225 PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700226 ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -0700227 PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
228 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700229 PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_WORD,
230 KI_COEFF_MED_DISCHG_OFFSET, 1, 1000, 244141, 0,
231 fg_encode_default, NULL),
232 PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_WORD,
233 KI_COEFF_HI_DISCHG_OFFSET, 1, 1000, 244141, 0,
234 fg_encode_default, NULL),
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -0700235 PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
236 KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
237 fg_encode_default, NULL),
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -0800238 PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
239 1, 512, 1000000, 0, fg_encode_default, NULL),
240 PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
241 1, 512, 1000000, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -0800242 PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
243 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700244};
245
Harry Yang2452b272017-03-06 13:56:14 -0800246static struct fg_sram_param pmi8998_v2_sram_params[] = {
Nicholas Troasta2b40372016-08-15 10:45:39 -0700247 PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700248 fg_decode_default),
Nicholas Troast1769fd32016-09-07 09:20:58 -0700249 PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
250 fg_decode_default),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800251 PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
252 244141, 0, NULL, fg_decode_voltage_15b),
253 PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700254 fg_decode_voltage_15b),
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800255 PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default,
256 fg_decode_value_16b),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800257 PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700258 fg_decode_value_16b),
Nicholas Troast69da2252016-09-07 16:17:47 -0700259 PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
260 fg_decode_default),
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700261 PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL,
262 fg_decode_cc_soc),
263 PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL,
264 fg_decode_cc_soc),
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -0700265 PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
266 1, 1, 0, NULL, fg_decode_default),
Anirudh Ghayalddabeee2017-04-04 06:13:48 +0530267 PARAM(TIMEBASE, KI_COEFF_MED_DISCHG_WORD, TIMEBASE_OFFSET, 2, 1000,
268 61000, 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700269 /* Entries below here are configurable during initialization */
270 PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
271 244141, 0, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -0700272 PARAM(EMPTY_VOLT, EMPTY_VOLT_v2_WORD, EMPTY_VOLT_v2_OFFSET, 1, 1000,
273 15625, -2000, fg_encode_voltage, NULL),
274 PARAM(VBATT_LOW, VBATT_LOW_v2_WORD, VBATT_LOW_v2_OFFSET, 1, 1000,
275 15625, -2000, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700276 PARAM(FLOAT_VOLT, FLOAT_VOLT_v2_WORD, FLOAT_VOLT_v2_OFFSET, 1, 1000,
277 15625, -2000, fg_encode_voltage, NULL),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800278 PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
279 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700280 PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
281 1000000, 122070, 0, fg_encode_current, NULL),
282 PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1,
283 100000, 390625, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -0700284 PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD,
285 CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0,
286 fg_encode_current, NULL),
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800287 PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
288 1, 2048, 100, 0, fg_encode_default, NULL),
289 PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
290 1, 2048, 100, 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700291 PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD,
292 RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default,
293 NULL),
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -0800294 PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD,
295 RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000,
296 fg_encode_voltage, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700297 PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
298 ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
299 NULL),
300 PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
301 ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default,
302 NULL),
303 PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
304 ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
305 PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
306 ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -0700307 PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
308 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700309 PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_v2_WORD,
310 KI_COEFF_MED_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
311 fg_encode_default, NULL),
312 PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_v2_WORD,
313 KI_COEFF_HI_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
314 fg_encode_default, NULL),
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -0700315 PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
316 KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
317 fg_encode_default, NULL),
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -0800318 PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
319 1, 512, 1000000, 0, fg_encode_default, NULL),
320 PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
321 1, 512, 1000000, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -0800322 PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
323 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700324};
325
Harry Yang2452b272017-03-06 13:56:14 -0800326static struct fg_alg_flag pmi8998_v1_alg_flags[] = {
Nicholas Troast69da2252016-09-07 16:17:47 -0700327 [ALG_FLAG_SOC_LT_OTG_MIN] = {
328 .name = "SOC_LT_OTG_MIN",
329 .bit = BIT(0),
330 },
331 [ALG_FLAG_SOC_LT_RECHARGE] = {
332 .name = "SOC_LT_RECHARGE",
333 .bit = BIT(1),
334 },
335 [ALG_FLAG_IBATT_LT_ITERM] = {
336 .name = "IBATT_LT_ITERM",
337 .bit = BIT(2),
338 },
339 [ALG_FLAG_IBATT_GT_HPM] = {
340 .name = "IBATT_GT_HPM",
341 .bit = BIT(3),
342 },
343 [ALG_FLAG_IBATT_GT_UPM] = {
344 .name = "IBATT_GT_UPM",
345 .bit = BIT(4),
346 },
347 [ALG_FLAG_VBATT_LT_RECHARGE] = {
348 .name = "VBATT_LT_RECHARGE",
349 .bit = BIT(5),
350 },
351 [ALG_FLAG_VBATT_GT_VFLOAT] = {
352 .invalid = true,
353 },
354};
355
Harry Yang2452b272017-03-06 13:56:14 -0800356static struct fg_alg_flag pmi8998_v2_alg_flags[] = {
Nicholas Troast69da2252016-09-07 16:17:47 -0700357 [ALG_FLAG_SOC_LT_OTG_MIN] = {
358 .name = "SOC_LT_OTG_MIN",
359 .bit = BIT(0),
360 },
361 [ALG_FLAG_SOC_LT_RECHARGE] = {
362 .name = "SOC_LT_RECHARGE",
363 .bit = BIT(1),
364 },
365 [ALG_FLAG_IBATT_LT_ITERM] = {
366 .name = "IBATT_LT_ITERM",
367 .bit = BIT(2),
368 },
369 [ALG_FLAG_IBATT_GT_HPM] = {
370 .name = "IBATT_GT_HPM",
371 .bit = BIT(4),
372 },
373 [ALG_FLAG_IBATT_GT_UPM] = {
374 .name = "IBATT_GT_UPM",
375 .bit = BIT(5),
376 },
377 [ALG_FLAG_VBATT_LT_RECHARGE] = {
378 .name = "VBATT_LT_RECHARGE",
379 .bit = BIT(6),
380 },
381 [ALG_FLAG_VBATT_GT_VFLOAT] = {
382 .name = "VBATT_GT_VFLOAT",
383 .bit = BIT(7),
384 },
385};
386
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700387static int fg_gen3_debug_mask;
388module_param_named(
389 debug_mask, fg_gen3_debug_mask, int, 0600
390);
391
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800392static bool fg_profile_dump;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700393module_param_named(
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800394 profile_dump, fg_profile_dump, bool, 0600
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700395);
396
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800397static int fg_sram_dump_period_ms = 20000;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700398module_param_named(
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800399 sram_dump_period_ms, fg_sram_dump_period_ms, int, 0600
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700400);
401
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -0700402static int fg_restart;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800403static bool fg_sram_dump;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700404
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700405/* All getters HERE */
406
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700407#define VOLTAGE_15BIT_MASK GENMASK(14, 0)
408static int fg_decode_voltage_15b(struct fg_sram_param *sp,
409 enum fg_sram_param_id id, int value)
410{
411 value &= VOLTAGE_15BIT_MASK;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800412 sp[id].value = div_u64((u64)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700413 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
414 sp[id].value);
415 return sp[id].value;
416}
417
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700418static int fg_decode_cc_soc(struct fg_sram_param *sp,
419 enum fg_sram_param_id id, int value)
420{
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800421 sp[id].value = div_s64((s64)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700422 sp[id].value = sign_extend32(sp[id].value, 31);
423 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
424 sp[id].value);
425 return sp[id].value;
426}
427
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700428static int fg_decode_value_16b(struct fg_sram_param *sp,
429 enum fg_sram_param_id id, int value)
430{
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800431 sp[id].value = div_u64((u64)(u16)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700432 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
433 sp[id].value);
434 return sp[id].value;
435}
436
Nicholas Troaste29dec92016-08-24 09:35:11 -0700437static int fg_decode_default(struct fg_sram_param *sp, enum fg_sram_param_id id,
438 int value)
439{
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700440 sp[id].value = value;
441 return sp[id].value;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700442}
443
444static int fg_decode(struct fg_sram_param *sp, enum fg_sram_param_id id,
445 int value)
446{
447 if (!sp[id].decode) {
448 pr_err("No decoding function for parameter %d\n", id);
449 return -EINVAL;
450 }
451
452 return sp[id].decode(sp, id, value);
453}
454
Nicholas Troasta2b40372016-08-15 10:45:39 -0700455static void fg_encode_voltage(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700456 enum fg_sram_param_id id, int val_mv, u8 *buf)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700457{
458 int i, mask = 0xff;
459 int64_t temp;
460
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700461 val_mv += sp[id].offset;
462 temp = (int64_t)div_u64((u64)val_mv * sp[id].numrtr, sp[id].denmtr);
463 pr_debug("temp: %llx id: %d, val_mv: %d, buf: [ ", temp, id, val_mv);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700464 for (i = 0; i < sp[id].len; i++) {
465 buf[i] = temp & mask;
466 temp >>= 8;
467 pr_debug("%x ", buf[i]);
468 }
469 pr_debug("]\n");
470}
471
472static void fg_encode_current(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700473 enum fg_sram_param_id id, int val_ma, u8 *buf)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700474{
475 int i, mask = 0xff;
476 int64_t temp;
477 s64 current_ma;
478
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700479 current_ma = val_ma;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700480 temp = (int64_t)div_s64(current_ma * sp[id].numrtr, sp[id].denmtr);
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700481 pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val_ma);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700482 for (i = 0; i < sp[id].len; i++) {
483 buf[i] = temp & mask;
484 temp >>= 8;
485 pr_debug("%x ", buf[i]);
486 }
487 pr_debug("]\n");
488}
489
490static void fg_encode_default(struct fg_sram_param *sp,
491 enum fg_sram_param_id id, int val, u8 *buf)
492{
493 int i, mask = 0xff;
494 int64_t temp;
495
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -0700496 temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700497 pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
498 for (i = 0; i < sp[id].len; i++) {
499 buf[i] = temp & mask;
500 temp >>= 8;
501 pr_debug("%x ", buf[i]);
502 }
503 pr_debug("]\n");
504}
505
506static void fg_encode(struct fg_sram_param *sp, enum fg_sram_param_id id,
507 int val, u8 *buf)
508{
509 if (!sp[id].encode) {
510 pr_err("No encoding function for parameter %d\n", id);
511 return;
512 }
513
514 sp[id].encode(sp, id, val, buf);
515}
516
517/*
518 * Please make sure *_sram_params table has the entry for the parameter
519 * obtained through this function. In addition to address, offset,
520 * length from where this SRAM parameter is read, a decode function
521 * need to be specified.
522 */
523static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id,
524 int *val)
525{
526 int temp, rc, i;
527 u8 buf[4];
528
529 if (id < 0 || id > FG_SRAM_MAX || chip->sp[id].len > sizeof(buf))
530 return -EINVAL;
531
Subbaraman Narayanamurthy0a749db2016-10-03 18:33:19 -0700532 if (chip->battery_missing)
533 return -ENODATA;
534
Nicholas Troasta2b40372016-08-15 10:45:39 -0700535 rc = fg_sram_read(chip, chip->sp[id].addr_word, chip->sp[id].addr_byte,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700536 buf, chip->sp[id].len, FG_IMA_DEFAULT);
537 if (rc < 0) {
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -0700538 pr_err("Error reading address %d[%d] rc=%d\n",
Nicholas Troasta2b40372016-08-15 10:45:39 -0700539 chip->sp[id].addr_word, chip->sp[id].addr_byte, rc);
Nicholas Troastb2d71742016-08-04 14:31:41 -0700540 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700541 }
542
543 for (i = 0, temp = 0; i < chip->sp[id].len; i++)
544 temp |= buf[i] << (8 * i);
545
546 *val = fg_decode(chip->sp, id, temp);
547 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700548}
549
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700550#define CC_SOC_30BIT GENMASK(29, 0)
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -0700551static int fg_get_charge_raw(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700552{
553 int rc, cc_soc;
554
555 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC, &cc_soc);
556 if (rc < 0) {
557 pr_err("Error in getting CC_SOC, rc=%d\n", rc);
558 return rc;
559 }
560
561 *val = div_s64(cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT);
562 return 0;
563}
564
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -0700565#define BATT_SOC_32BIT GENMASK(31, 0)
566static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val)
567{
568 int rc, batt_soc;
569
570 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
571 if (rc < 0) {
572 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
573 return rc;
574 }
575
576 *val = div_u64((u32)batt_soc * chip->cl.learned_cc_uah, BATT_SOC_32BIT);
577 return 0;
578}
579
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -0700580static int fg_get_charge_counter(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700581{
582 int rc, cc_soc;
583
584 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc);
585 if (rc < 0) {
586 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
587 return rc;
588 }
589
590 *val = div_s64(cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT);
591 return 0;
592}
593
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -0700594static int fg_get_jeita_threshold(struct fg_chip *chip,
595 enum jeita_levels level, int *temp_decidegC)
596{
597 int rc;
598 u8 val;
599 u16 reg;
600
601 switch (level) {
602 case JEITA_COLD:
603 reg = BATT_INFO_JEITA_TOO_COLD(chip);
604 break;
605 case JEITA_COOL:
606 reg = BATT_INFO_JEITA_COLD(chip);
607 break;
608 case JEITA_WARM:
609 reg = BATT_INFO_JEITA_HOT(chip);
610 break;
611 case JEITA_HOT:
612 reg = BATT_INFO_JEITA_TOO_HOT(chip);
613 break;
614 default:
615 return -EINVAL;
616 }
617
618 rc = fg_read(chip, reg, &val, 1);
619 if (rc < 0) {
620 pr_err("Error in reading jeita level %d, rc=%d\n", level, rc);
621 return rc;
622 }
623
624 /* Resolution is 0.5C. Base is -30C. */
625 *temp_decidegC = (((5 * val) / 10) - 30) * 10;
626 return 0;
627}
628
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700629#define BATT_TEMP_NUMR 1
630#define BATT_TEMP_DENR 1
631static int fg_get_battery_temp(struct fg_chip *chip, int *val)
632{
Subbaraman Narayanamurthyfabbb8e2016-10-21 16:55:09 -0700633 int rc = 0, temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700634 u8 buf[2];
635
636 rc = fg_read(chip, BATT_INFO_BATT_TEMP_LSB(chip), buf, 2);
637 if (rc < 0) {
638 pr_err("failed to read addr=0x%04x, rc=%d\n",
639 BATT_INFO_BATT_TEMP_LSB(chip), rc);
640 return rc;
641 }
642
643 temp = ((buf[1] & BATT_TEMP_MSB_MASK) << 8) |
644 (buf[0] & BATT_TEMP_LSB_MASK);
645 temp = DIV_ROUND_CLOSEST(temp, 4);
646
647 /* Value is in Kelvin; Convert it to deciDegC */
648 temp = (temp - 273) * 10;
649 *val = temp;
650 return 0;
651}
652
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700653static int fg_get_battery_resistance(struct fg_chip *chip, int *val)
654{
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800655 int rc, esr_uohms, rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700656
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800657 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700658 if (rc < 0) {
659 pr_err("failed to get ESR, rc=%d\n", rc);
660 return rc;
661 }
662
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800663 rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &rslow_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700664 if (rc < 0) {
665 pr_err("failed to get Rslow, rc=%d\n", rc);
666 return rc;
667 }
668
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800669 *val = esr_uohms + rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700670 return 0;
671}
672
673#define BATT_CURRENT_NUMR 488281
674#define BATT_CURRENT_DENR 1000
675static int fg_get_battery_current(struct fg_chip *chip, int *val)
676{
677 int rc = 0;
678 int64_t temp = 0;
679 u8 buf[2];
680
681 rc = fg_read(chip, BATT_INFO_IBATT_LSB(chip), buf, 2);
682 if (rc < 0) {
683 pr_err("failed to read addr=0x%04x, rc=%d\n",
684 BATT_INFO_IBATT_LSB(chip), rc);
685 return rc;
686 }
687
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530688 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700689 temp = buf[0] << 8 | buf[1];
690 else
691 temp = buf[1] << 8 | buf[0];
692
693 pr_debug("buf: %x %x temp: %llx\n", buf[0], buf[1], temp);
694 /* Sign bit is bit 15 */
695 temp = twos_compliment_extend(temp, 15);
696 *val = div_s64((s64)temp * BATT_CURRENT_NUMR, BATT_CURRENT_DENR);
697 return 0;
698}
699
700#define BATT_VOLTAGE_NUMR 122070
701#define BATT_VOLTAGE_DENR 1000
702static int fg_get_battery_voltage(struct fg_chip *chip, int *val)
703{
704 int rc = 0;
705 u16 temp = 0;
706 u8 buf[2];
707
708 rc = fg_read(chip, BATT_INFO_VBATT_LSB(chip), buf, 2);
709 if (rc < 0) {
710 pr_err("failed to read addr=0x%04x, rc=%d\n",
711 BATT_INFO_VBATT_LSB(chip), rc);
712 return rc;
713 }
714
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530715 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700716 temp = buf[0] << 8 | buf[1];
717 else
718 temp = buf[1] << 8 | buf[0];
719
720 pr_debug("buf: %x %x temp: %x\n", buf[0], buf[1], temp);
721 *val = div_u64((u64)temp * BATT_VOLTAGE_NUMR, BATT_VOLTAGE_DENR);
722 return 0;
723}
724
725#define MAX_TRIES_SOC 5
726static int fg_get_msoc_raw(struct fg_chip *chip, int *val)
727{
728 u8 cap[2];
729 int rc, tries = 0;
730
731 while (tries < MAX_TRIES_SOC) {
732 rc = fg_read(chip, BATT_SOC_FG_MONOTONIC_SOC(chip), cap, 2);
733 if (rc < 0) {
734 pr_err("failed to read addr=0x%04x, rc=%d\n",
735 BATT_SOC_FG_MONOTONIC_SOC(chip), rc);
736 return rc;
737 }
738
739 if (cap[0] == cap[1])
740 break;
741
742 tries++;
743 }
744
745 if (tries == MAX_TRIES_SOC) {
746 pr_err("shadow registers do not match\n");
747 return -EINVAL;
748 }
749
750 fg_dbg(chip, FG_POWER_SUPPLY, "raw: 0x%02x\n", cap[0]);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700751 *val = cap[0];
752 return 0;
753}
754
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800755#define FULL_CAPACITY 100
756#define FULL_SOC_RAW 255
757static int fg_get_msoc(struct fg_chip *chip, int *msoc)
758{
759 int rc;
760
761 rc = fg_get_msoc_raw(chip, msoc);
762 if (rc < 0)
763 return rc;
764
765 *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW);
766 return 0;
767}
768
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800769static bool is_batt_empty(struct fg_chip *chip)
770{
771 u8 status;
772 int rc, vbatt_uv, msoc;
773
774 rc = fg_read(chip, BATT_SOC_INT_RT_STS(chip), &status, 1);
775 if (rc < 0) {
776 pr_err("failed to read addr=0x%04x, rc=%d\n",
777 BATT_SOC_INT_RT_STS(chip), rc);
778 return false;
779 }
780
781 if (!(status & MSOC_EMPTY_BIT))
782 return false;
783
784 rc = fg_get_battery_voltage(chip, &vbatt_uv);
785 if (rc < 0) {
786 pr_err("failed to get battery voltage, rc=%d\n", rc);
787 return false;
788 }
789
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800790 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800791 if (!rc)
792 pr_warn("batt_soc_rt_sts: %x vbatt: %d uV msoc:%d\n", status,
793 vbatt_uv, msoc);
794
795 return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false);
796}
797
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800798static int fg_get_debug_batt_id(struct fg_chip *chip, int *batt_id)
799{
800 int rc;
801 u64 temp;
802 u8 buf[2];
803
804 rc = fg_read(chip, ADC_RR_FAKE_BATT_LOW_LSB(chip), buf, 2);
805 if (rc < 0) {
806 pr_err("failed to read addr=0x%04x, rc=%d\n",
807 ADC_RR_FAKE_BATT_LOW_LSB(chip), rc);
808 return rc;
809 }
810
811 /*
812 * Fake battery threshold is encoded in the following format.
813 * Threshold (code) = (battery_id in Ohms) * 0.00015 * 2^10 / 2.5
814 */
815 temp = (buf[1] << 8 | buf[0]) * 2500000;
816 do_div(temp, 150 * 1024);
817 batt_id[0] = temp;
818 rc = fg_read(chip, ADC_RR_FAKE_BATT_HIGH_LSB(chip), buf, 2);
819 if (rc < 0) {
820 pr_err("failed to read addr=0x%04x, rc=%d\n",
821 ADC_RR_FAKE_BATT_HIGH_LSB(chip), rc);
822 return rc;
823 }
824
825 temp = (buf[1] << 8 | buf[0]) * 2500000;
826 do_div(temp, 150 * 1024);
827 batt_id[1] = temp;
828 pr_debug("debug batt_id range: [%d %d]\n", batt_id[0], batt_id[1]);
829 return 0;
830}
831
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700832static bool is_debug_batt_id(struct fg_chip *chip)
833{
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800834 int debug_batt_id[2], rc;
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700835
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800836 if (!chip->batt_id_ohms)
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700837 return false;
838
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800839 rc = fg_get_debug_batt_id(chip, debug_batt_id);
840 if (rc < 0) {
841 pr_err("Failed to get debug batt_id, rc=%d\n", rc);
842 return false;
843 }
844
845 if (is_between(debug_batt_id[0], debug_batt_id[1],
846 chip->batt_id_ohms)) {
847 fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dohms\n",
848 chip->batt_id_ohms);
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700849 return true;
850 }
851
852 return false;
853}
854
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700855#define DEBUG_BATT_SOC 67
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800856#define BATT_MISS_SOC 50
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700857#define EMPTY_SOC 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700858static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
859{
860 int rc, msoc;
861
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700862 if (is_debug_batt_id(chip)) {
863 *val = DEBUG_BATT_SOC;
864 return 0;
865 }
866
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800867 if (chip->fg_restarting) {
868 *val = chip->last_soc;
869 return 0;
870 }
871
872 if (chip->battery_missing) {
873 *val = BATT_MISS_SOC;
874 return 0;
875 }
876
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800877 if (is_batt_empty(chip)) {
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700878 *val = EMPTY_SOC;
879 return 0;
880 }
881
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700882 if (chip->charge_full) {
883 *val = FULL_CAPACITY;
884 return 0;
885 }
886
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800887 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700888 if (rc < 0)
889 return rc;
890
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -0700891 if (chip->dt.linearize_soc && chip->delta_soc > 0)
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800892 *val = chip->maint_soc;
893 else
894 *val = msoc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700895 return 0;
896}
897
898#define DEFAULT_BATT_TYPE "Unknown Battery"
899#define MISSING_BATT_TYPE "Missing Battery"
900#define LOADING_BATT_TYPE "Loading Battery"
901static const char *fg_get_battery_type(struct fg_chip *chip)
902{
903 if (chip->battery_missing)
904 return MISSING_BATT_TYPE;
905
906 if (chip->bp.batt_type_str) {
907 if (chip->profile_loaded)
908 return chip->bp.batt_type_str;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -0800909 else if (chip->profile_available)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700910 return LOADING_BATT_TYPE;
911 }
912
913 return DEFAULT_BATT_TYPE;
914}
915
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800916static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700917{
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800918 int rc;
919
920 rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
921 BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
922 if (rc < 0)
923 pr_err("Error in writing to %04x, rc=%d\n",
924 BATT_INFO_BATT_MISS_CFG(chip), rc);
925 return rc;
926}
927
928static int fg_get_batt_id(struct fg_chip *chip)
929{
930 int rc, ret, batt_id = 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700931
932 if (!chip->batt_id_chan)
933 return -EINVAL;
934
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800935 rc = fg_batt_missing_config(chip, false);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700936 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800937 pr_err("Error in disabling BMD, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700938 return rc;
939 }
940
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800941 rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
942 if (rc < 0) {
943 pr_err("Error in reading batt_id channel, rc:%d\n", rc);
944 goto out;
945 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700946
Fenglin Wud10ccf12017-08-10 15:43:41 +0800947 /* Wait for BATT_ID to settle down before enabling BMD again */
948 msleep(chip->dt.bmd_en_delay_ms);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800949
950 fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
951 chip->batt_id_ohms = batt_id;
952out:
953 ret = fg_batt_missing_config(chip, true);
954 if (ret < 0) {
955 pr_err("Error in enabling BMD, ret=%d\n", ret);
956 return ret;
957 }
958
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -0700959 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, true, 0);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800960 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700961}
962
963static int fg_get_batt_profile(struct fg_chip *chip)
964{
965 struct device_node *node = chip->dev->of_node;
966 struct device_node *batt_node, *profile_node;
967 const char *data;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800968 int rc, len;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700969
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700970 batt_node = of_find_node_by_name(node, "qcom,battery-data");
971 if (!batt_node) {
972 pr_err("Batterydata not available\n");
973 return -ENXIO;
974 }
975
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800976 profile_node = of_batterydata_get_best_profile(batt_node,
977 chip->batt_id_ohms / 1000, NULL);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700978 if (IS_ERR(profile_node))
979 return PTR_ERR(profile_node);
980
981 if (!profile_node) {
982 pr_err("couldn't find profile handle\n");
983 return -ENODATA;
984 }
985
986 rc = of_property_read_string(profile_node, "qcom,battery-type",
987 &chip->bp.batt_type_str);
988 if (rc < 0) {
989 pr_err("battery type unavailable, rc:%d\n", rc);
990 return rc;
991 }
992
993 rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
994 &chip->bp.float_volt_uv);
995 if (rc < 0) {
996 pr_err("battery float voltage unavailable, rc:%d\n", rc);
997 chip->bp.float_volt_uv = -EINVAL;
998 }
999
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -08001000 rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001001 &chip->bp.fastchg_curr_ma);
1002 if (rc < 0) {
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -08001003 pr_err("battery fastchg current unavailable, rc:%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001004 chip->bp.fastchg_curr_ma = -EINVAL;
1005 }
1006
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07001007 rc = of_property_read_u32(profile_node, "qcom,fg-cc-cv-threshold-mv",
1008 &chip->bp.vbatt_full_mv);
1009 if (rc < 0) {
1010 pr_err("battery cc_cv threshold unavailable, rc:%d\n", rc);
1011 chip->bp.vbatt_full_mv = -EINVAL;
1012 }
1013
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001014 data = of_get_property(profile_node, "qcom,fg-profile-data", &len);
1015 if (!data) {
1016 pr_err("No profile data available\n");
1017 return -ENODATA;
1018 }
1019
1020 if (len != PROFILE_LEN) {
1021 pr_err("battery profile incorrect size: %d\n", len);
1022 return -EINVAL;
1023 }
1024
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07001025 chip->profile_available = true;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001026 memcpy(chip->batt_profile, data, len);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001027
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001028 return 0;
1029}
1030
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07001031static inline void get_batt_temp_delta(int delta, u8 *val)
1032{
1033 switch (delta) {
1034 case 2:
1035 *val = BTEMP_DELTA_2K;
1036 break;
1037 case 4:
1038 *val = BTEMP_DELTA_4K;
1039 break;
1040 case 6:
1041 *val = BTEMP_DELTA_6K;
1042 break;
1043 case 10:
1044 *val = BTEMP_DELTA_10K;
1045 break;
1046 default:
1047 *val = BTEMP_DELTA_2K;
1048 break;
1049 };
1050}
1051
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07001052static inline void get_esr_meas_current(int curr_ma, u8 *val)
1053{
1054 switch (curr_ma) {
1055 case 60:
1056 *val = ESR_MEAS_CUR_60MA;
1057 break;
1058 case 120:
1059 *val = ESR_MEAS_CUR_120MA;
1060 break;
1061 case 180:
1062 *val = ESR_MEAS_CUR_180MA;
1063 break;
1064 case 240:
1065 *val = ESR_MEAS_CUR_240MA;
1066 break;
1067 default:
1068 *val = ESR_MEAS_CUR_120MA;
1069 break;
1070 };
1071
1072 *val <<= ESR_PULL_DOWN_IVAL_SHIFT;
1073}
1074
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001075static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
1076 int cycles_max, bool charging, int flags)
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001077{
1078 u8 buf[2];
1079 int rc, timer_max, timer_init;
1080
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001081 if (cycles_init < 0 || cycles_max < 0)
1082 return 0;
1083
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001084 if (charging) {
1085 timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
1086 timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
1087 } else {
1088 timer_max = FG_SRAM_ESR_TIMER_DISCHG_MAX;
1089 timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
1090 }
1091
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001092 fg_encode(chip->sp, timer_max, cycles_max, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001093 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001094 chip->sp[timer_max].addr_word,
1095 chip->sp[timer_max].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001096 chip->sp[timer_max].len, flags);
1097 if (rc < 0) {
1098 pr_err("Error in writing esr_timer_dischg_max, rc=%d\n",
1099 rc);
1100 return rc;
1101 }
1102
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001103 fg_encode(chip->sp, timer_init, cycles_init, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001104 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001105 chip->sp[timer_init].addr_word,
1106 chip->sp[timer_init].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001107 chip->sp[timer_init].len, flags);
1108 if (rc < 0) {
1109 pr_err("Error in writing esr_timer_dischg_init, rc=%d\n",
1110 rc);
1111 return rc;
1112 }
1113
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001114 fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
1115 charging ? "charging" : "discharging", cycles_init, cycles_max);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001116 return 0;
1117}
1118
Nicholas Troaste29dec92016-08-24 09:35:11 -07001119/* Other functions HERE */
1120
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001121static void fg_notify_charger(struct fg_chip *chip)
1122{
1123 union power_supply_propval prop = {0, };
1124 int rc;
1125
1126 if (!chip->batt_psy)
1127 return;
1128
1129 if (!chip->profile_available)
1130 return;
1131
1132 prop.intval = chip->bp.float_volt_uv;
1133 rc = power_supply_set_property(chip->batt_psy,
1134 POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
1135 if (rc < 0) {
1136 pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
1137 rc);
1138 return;
1139 }
1140
1141 prop.intval = chip->bp.fastchg_curr_ma * 1000;
1142 rc = power_supply_set_property(chip->batt_psy,
1143 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
1144 if (rc < 0) {
1145 pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
1146 rc);
1147 return;
1148 }
1149
1150 fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
1151}
1152
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001153static int fg_batt_miss_irq_en_cb(struct votable *votable, void *data,
1154 int enable, const char *client)
1155{
1156 struct fg_chip *chip = data;
1157
1158 if (!chip->irqs[BATT_MISSING_IRQ].irq)
1159 return 0;
1160
1161 if (enable) {
1162 enable_irq(chip->irqs[BATT_MISSING_IRQ].irq);
1163 enable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
1164 } else {
1165 disable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
Subbaraman Narayanamurthyd1b4c842017-09-29 16:07:28 -07001166 disable_irq_nosync(chip->irqs[BATT_MISSING_IRQ].irq);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001167 }
1168
1169 return 0;
1170}
1171
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001172static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data,
1173 int enable, const char *client)
1174{
1175 struct fg_chip *chip = data;
1176
1177 if (!chip->irqs[BSOC_DELTA_IRQ].irq)
1178 return 0;
1179
1180 if (enable) {
1181 enable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1182 enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1183 } else {
1184 disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
Subbaraman Narayanamurthyd1b4c842017-09-29 16:07:28 -07001185 disable_irq_nosync(chip->irqs[BSOC_DELTA_IRQ].irq);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001186 }
1187
1188 return 0;
1189}
1190
Nicholas Troaste29dec92016-08-24 09:35:11 -07001191static int fg_awake_cb(struct votable *votable, void *data, int awake,
1192 const char *client)
1193{
1194 struct fg_chip *chip = data;
1195
1196 if (awake)
1197 pm_stay_awake(chip->dev);
1198 else
1199 pm_relax(chip->dev);
1200
1201 pr_debug("client: %s awake: %d\n", client, awake);
1202 return 0;
1203}
1204
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001205static bool batt_psy_initialized(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07001206{
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001207 if (chip->batt_psy)
1208 return true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07001209
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001210 chip->batt_psy = power_supply_get_by_name("battery");
Nicholas Troaste29dec92016-08-24 09:35:11 -07001211 if (!chip->batt_psy)
1212 return false;
1213
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001214 /* batt_psy is initialized, set the fcc and fv */
1215 fg_notify_charger(chip);
1216
Nicholas Troaste29dec92016-08-24 09:35:11 -07001217 return true;
1218}
1219
Nicholas Troast805c2422017-07-06 14:53:46 -07001220static bool usb_psy_initialized(struct fg_chip *chip)
1221{
1222 if (chip->usb_psy)
1223 return true;
1224
1225 chip->usb_psy = power_supply_get_by_name("usb");
1226 if (!chip->usb_psy)
1227 return false;
1228
1229 return true;
1230}
1231
1232static bool pc_port_psy_initialized(struct fg_chip *chip)
1233{
1234 if (chip->pc_port_psy)
1235 return true;
1236
1237 chip->pc_port_psy = power_supply_get_by_name("pc_port");
1238 if (!chip->pc_port_psy)
1239 return false;
1240
1241 return true;
1242}
1243
1244static bool dc_psy_initialized(struct fg_chip *chip)
1245{
1246 if (chip->dc_psy)
1247 return true;
1248
1249 chip->dc_psy = power_supply_get_by_name("dc");
1250 if (!chip->dc_psy)
1251 return false;
1252
1253 return true;
1254}
1255
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001256static bool is_parallel_charger_available(struct fg_chip *chip)
1257{
1258 if (!chip->parallel_psy)
1259 chip->parallel_psy = power_supply_get_by_name("parallel");
1260
1261 if (!chip->parallel_psy)
1262 return false;
1263
1264 return true;
1265}
1266
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001267static int fg_prime_cc_soc_sw(struct fg_chip *chip, int cc_soc_sw)
1268{
1269 int rc;
1270
1271 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1272 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
1273 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
1274 if (rc < 0)
1275 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1276 else
1277 fg_dbg(chip, FG_STATUS, "cc_soc_sw: %x\n", cc_soc_sw);
1278
1279 return rc;
1280}
1281
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001282static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
1283{
1284 int16_t cc_mah;
1285 int rc;
1286
1287 if (chip->battery_missing || !chip->cl.learned_cc_uah)
1288 return -EPERM;
1289
1290 cc_mah = div64_s64(chip->cl.learned_cc_uah, 1000);
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001291 /* Write to a backup register to use across reboot */
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001292 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word,
1293 chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah,
1294 chip->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT);
1295 if (rc < 0) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001296 pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc);
1297 return rc;
1298 }
1299
1300 /* Write to actual capacity register for coulomb counter operation */
1301 rc = fg_sram_write(chip, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET,
1302 (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len,
1303 FG_IMA_DEFAULT);
1304 if (rc < 0) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001305 pr_err("Error in writing act_batt_cap, rc=%d\n", rc);
1306 return rc;
1307 }
1308
1309 fg_dbg(chip, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n",
1310 chip->cl.learned_cc_uah, cc_mah);
1311 return 0;
1312}
1313
1314#define CAPACITY_DELTA_DECIPCT 500
1315static int fg_load_learned_cap_from_sram(struct fg_chip *chip)
1316{
1317 int rc, act_cap_mah;
1318 int64_t delta_cc_uah, pct_nom_cap_uah;
1319
1320 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
1321 if (rc < 0) {
1322 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1323 return rc;
1324 }
1325
1326 chip->cl.learned_cc_uah = act_cap_mah * 1000;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001327
1328 if (chip->cl.learned_cc_uah != chip->cl.nom_cap_uah) {
Subbaraman Narayanamurthy51d3c902016-10-24 14:05:44 -07001329 if (chip->cl.learned_cc_uah == 0)
1330 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
1331
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001332 delta_cc_uah = abs(chip->cl.learned_cc_uah -
1333 chip->cl.nom_cap_uah);
1334 pct_nom_cap_uah = div64_s64((int64_t)chip->cl.nom_cap_uah *
1335 CAPACITY_DELTA_DECIPCT, 1000);
1336 /*
1337 * If the learned capacity is out of range by 50% from the
1338 * nominal capacity, then overwrite the learned capacity with
1339 * the nominal capacity.
1340 */
1341 if (chip->cl.nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001342 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected, capping it to nominal: %lld\n",
1343 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001344 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001345 }
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001346
1347 rc = fg_save_learned_cap_to_sram(chip);
1348 if (rc < 0)
1349 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001350 }
1351
1352 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah:%lld nom_cap_uah: %lld\n",
1353 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
1354 return 0;
1355}
1356
1357static bool is_temp_valid_cap_learning(struct fg_chip *chip)
1358{
1359 int rc, batt_temp;
1360
1361 rc = fg_get_battery_temp(chip, &batt_temp);
1362 if (rc < 0) {
1363 pr_err("Error in getting batt_temp\n");
1364 return false;
1365 }
1366
1367 if (batt_temp > chip->dt.cl_max_temp ||
1368 batt_temp < chip->dt.cl_min_temp) {
1369 fg_dbg(chip, FG_CAP_LEARN, "batt temp %d out of range [%d %d]\n",
1370 batt_temp, chip->dt.cl_min_temp, chip->dt.cl_max_temp);
1371 return false;
1372 }
1373
1374 return true;
1375}
1376
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001377#define QNOVO_CL_SKEW_DECIPCT -30
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001378static void fg_cap_learning_post_process(struct fg_chip *chip)
1379{
1380 int64_t max_inc_val, min_dec_val, old_cap;
1381 int rc;
1382
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001383 if (is_qnovo_en(chip)) {
1384 fg_dbg(chip, FG_CAP_LEARN, "applying skew %d on current learnt capacity %lld\n",
1385 QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
1386 chip->cl.final_cc_uah = chip->cl.final_cc_uah *
1387 (1000 + QNOVO_CL_SKEW_DECIPCT);
1388 do_div(chip->cl.final_cc_uah, 1000);
1389 }
1390
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001391 max_inc_val = chip->cl.learned_cc_uah
1392 * (1000 + chip->dt.cl_max_cap_inc);
1393 do_div(max_inc_val, 1000);
1394
1395 min_dec_val = chip->cl.learned_cc_uah
1396 * (1000 - chip->dt.cl_max_cap_dec);
1397 do_div(min_dec_val, 1000);
1398
1399 old_cap = chip->cl.learned_cc_uah;
1400 if (chip->cl.final_cc_uah > max_inc_val)
1401 chip->cl.learned_cc_uah = max_inc_val;
1402 else if (chip->cl.final_cc_uah < min_dec_val)
1403 chip->cl.learned_cc_uah = min_dec_val;
1404 else
1405 chip->cl.learned_cc_uah =
1406 chip->cl.final_cc_uah;
1407
1408 if (chip->dt.cl_max_cap_limit) {
1409 max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
1410 chip->dt.cl_max_cap_limit);
1411 do_div(max_inc_val, 1000);
1412 if (chip->cl.final_cc_uah > max_inc_val) {
1413 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
1414 chip->cl.final_cc_uah, max_inc_val);
1415 chip->cl.learned_cc_uah = max_inc_val;
1416 }
1417 }
1418
1419 if (chip->dt.cl_min_cap_limit) {
1420 min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
1421 chip->dt.cl_min_cap_limit);
1422 do_div(min_dec_val, 1000);
1423 if (chip->cl.final_cc_uah < min_dec_val) {
1424 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
1425 chip->cl.final_cc_uah, min_dec_val);
1426 chip->cl.learned_cc_uah = min_dec_val;
1427 }
1428 }
1429
1430 rc = fg_save_learned_cap_to_sram(chip);
1431 if (rc < 0)
1432 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
1433
1434 fg_dbg(chip, FG_CAP_LEARN, "final cc_uah = %lld, learned capacity %lld -> %lld uah\n",
1435 chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah);
1436}
1437
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001438static int fg_cap_learning_process_full_data(struct fg_chip *chip)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001439{
1440 int rc, cc_soc_sw, cc_soc_delta_pct;
1441 int64_t delta_cc_uah;
1442
1443 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
1444 if (rc < 0) {
1445 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
1446 return rc;
1447 }
1448
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -07001449 cc_soc_delta_pct =
1450 div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
1451 CC_SOC_30BIT);
1452
1453 /* If the delta is < 50%, then skip processing full data */
1454 if (cc_soc_delta_pct < 50) {
1455 pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
1456 return -ERANGE;
1457 }
1458
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001459 delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
1460 100);
1461 chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
1462 fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n",
1463 cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
1464 return 0;
1465}
1466
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001467static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001468{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001469 int rc, cc_soc_sw, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001470
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001471 batt_soc_msb = batt_soc >> 24;
1472 if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001473 chip->dt.cl_start_soc) {
1474 fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001475 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001476 return -EINVAL;
1477 }
1478
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001479 chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001480 FULL_SOC_RAW);
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001481
1482 /* Prime cc_soc_sw with battery SOC when capacity learning begins */
1483 cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
1484 BATT_SOC_32BIT);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001485 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001486 if (rc < 0) {
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001487 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1488 goto out;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001489 }
1490
1491 chip->cl.init_cc_soc_sw = cc_soc_sw;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001492 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001493 batt_soc_msb, chip->cl.init_cc_soc_sw);
1494out:
1495 return rc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001496}
1497
1498static int fg_cap_learning_done(struct fg_chip *chip)
1499{
1500 int rc, cc_soc_sw;
1501
1502 rc = fg_cap_learning_process_full_data(chip);
1503 if (rc < 0) {
1504 pr_err("Error in processing cap learning full data, rc=%d\n",
1505 rc);
1506 goto out;
1507 }
1508
1509 /* Write a FULL value to cc_soc_sw */
1510 cc_soc_sw = CC_SOC_30BIT;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001511 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001512 if (rc < 0) {
1513 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1514 goto out;
1515 }
1516
1517 fg_cap_learning_post_process(chip);
1518out:
1519 return rc;
1520}
1521
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001522static void fg_cap_learning_update(struct fg_chip *chip)
1523{
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001524 int rc, batt_soc, batt_soc_msb, cc_soc_sw;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001525 bool input_present = is_input_present(chip);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001526 bool prime_cc = false;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001527
1528 mutex_lock(&chip->cl.lock);
1529
1530 if (!is_temp_valid_cap_learning(chip) || !chip->cl.learned_cc_uah ||
1531 chip->battery_missing) {
1532 fg_dbg(chip, FG_CAP_LEARN, "Aborting cap_learning %lld\n",
1533 chip->cl.learned_cc_uah);
1534 chip->cl.active = false;
1535 chip->cl.init_cc_uah = 0;
1536 goto out;
1537 }
1538
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001539 if (chip->charge_status == chip->prev_charge_status)
1540 goto out;
1541
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001542 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
1543 if (rc < 0) {
1544 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1545 goto out;
1546 }
1547
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001548 batt_soc_msb = (u32)batt_soc >> 24;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001549 fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001550 chip->charge_status, chip->cl.active, batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001551
1552 /* Initialize the starting point of learning capacity */
1553 if (!chip->cl.active) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07001554 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001555 rc = fg_cap_learning_begin(chip, batt_soc);
1556 chip->cl.active = (rc == 0);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001557 } else {
1558 if ((chip->charge_status ==
1559 POWER_SUPPLY_STATUS_DISCHARGING) ||
1560 chip->charge_done)
1561 prime_cc = true;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001562 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001563 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001564 if (chip->charge_done) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001565 rc = fg_cap_learning_done(chip);
1566 if (rc < 0)
1567 pr_err("Error in completing capacity learning, rc=%d\n",
1568 rc);
1569
1570 chip->cl.active = false;
1571 chip->cl.init_cc_uah = 0;
1572 }
1573
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001574 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
1575 if (!input_present) {
1576 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1577 batt_soc_msb);
1578 chip->cl.active = false;
1579 chip->cl.init_cc_uah = 0;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001580 prime_cc = true;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001581 }
1582 }
1583
Nicholas Troast1769fd32016-09-07 09:20:58 -07001584 if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001585 if (is_qnovo_en(chip) && input_present) {
1586 /*
1587 * Don't abort the capacity learning when qnovo
1588 * is enabled and input is present where the
1589 * charging status can go to "not charging"
1590 * intermittently.
1591 */
1592 } else {
1593 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1594 batt_soc_msb);
1595 chip->cl.active = false;
1596 chip->cl.init_cc_uah = 0;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001597 prime_cc = true;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001598 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001599 }
1600 }
1601
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001602 /*
1603 * Prime CC_SOC_SW when the device is not charging or during charge
1604 * termination when the capacity learning is not active.
1605 */
1606
1607 if (prime_cc) {
1608 if (chip->charge_done)
1609 cc_soc_sw = CC_SOC_30BIT;
1610 else
1611 cc_soc_sw = div_u64((u32)batt_soc *
1612 CC_SOC_30BIT, BATT_SOC_32BIT);
1613
1614 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
1615 if (rc < 0)
1616 pr_err("Error in writing cc_soc_sw, rc=%d\n",
1617 rc);
1618 }
1619
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001620out:
1621 mutex_unlock(&chip->cl.lock);
1622}
1623
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001624#define KI_COEFF_MED_DISCHG_DEFAULT 1500
1625#define KI_COEFF_HI_DISCHG_DEFAULT 2200
1626static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
1627{
1628 int rc, i, msoc;
1629 int ki_coeff_med = KI_COEFF_MED_DISCHG_DEFAULT;
1630 int ki_coeff_hi = KI_COEFF_HI_DISCHG_DEFAULT;
1631 u8 val;
1632
1633 if (!chip->ki_coeff_dischg_en)
1634 return 0;
1635
1636 rc = fg_get_prop_capacity(chip, &msoc);
1637 if (rc < 0) {
1638 pr_err("Error in getting capacity, rc=%d\n", rc);
1639 return rc;
1640 }
1641
Nicholas Troast1769fd32016-09-07 09:20:58 -07001642 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001643 for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) {
1644 if (msoc < chip->dt.ki_coeff_soc[i]) {
1645 ki_coeff_med = chip->dt.ki_coeff_med_dischg[i];
1646 ki_coeff_hi = chip->dt.ki_coeff_hi_dischg[i];
1647 }
1648 }
1649 }
1650
1651 fg_encode(chip->sp, FG_SRAM_KI_COEFF_MED_DISCHG, ki_coeff_med, &val);
1652 rc = fg_sram_write(chip,
1653 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_word,
1654 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_byte, &val,
1655 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].len,
1656 FG_IMA_DEFAULT);
1657 if (rc < 0) {
1658 pr_err("Error in writing ki_coeff_med, rc=%d\n", rc);
1659 return rc;
1660 }
1661
1662 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_DISCHG, ki_coeff_hi, &val);
1663 rc = fg_sram_write(chip,
1664 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_word,
1665 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_byte, &val,
1666 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].len,
1667 FG_IMA_DEFAULT);
1668 if (rc < 0) {
1669 pr_err("Error in writing ki_coeff_hi, rc=%d\n", rc);
1670 return rc;
1671 }
1672
1673 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_med %d ki_coeff_hi %d\n",
1674 ki_coeff_med, ki_coeff_hi);
1675 return 0;
1676}
1677
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001678#define KI_COEFF_FULL_SOC_DEFAULT 733
1679static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
1680{
1681 int rc, ki_coeff_full_soc;
1682 u8 val;
1683
1684 if (batt_temp < 0)
1685 ki_coeff_full_soc = 0;
Subbaraman Narayanamurthye17be582017-08-08 19:28:37 -07001686 else if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
1687 ki_coeff_full_soc = chip->dt.ki_coeff_full_soc_dischg;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001688 else
1689 ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
1690
1691 if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
1692 return 0;
1693
1694 fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
1695 rc = fg_sram_write(chip,
1696 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
1697 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
1698 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
1699 FG_IMA_DEFAULT);
1700 if (rc < 0) {
1701 pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
1702 return rc;
1703 }
1704
1705 chip->ki_coeff_full_soc = ki_coeff_full_soc;
1706 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
1707 ki_coeff_full_soc);
1708 return 0;
1709}
1710
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001711static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
1712{
1713 u8 buf;
1714 int rc;
1715
1716 if (chip->dt.auto_recharge_soc)
1717 return 0;
1718
1719 /* This configuration is available only for pmicobalt v2.0 and above */
1720 if (chip->wa_flags & PMI8998_V1_REV_WA)
1721 return 0;
1722
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07001723 if (voltage_mv == chip->last_recharge_volt_mv)
1724 return 0;
1725
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001726 fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
1727 voltage_mv);
1728 fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
1729 rc = fg_sram_write(chip,
1730 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
1731 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
1732 &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
1733 FG_IMA_DEFAULT);
1734 if (rc < 0) {
1735 pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
1736 rc);
1737 return rc;
1738 }
1739
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07001740 chip->last_recharge_volt_mv = voltage_mv;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001741 return 0;
1742}
1743
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07001744static int fg_configure_full_soc(struct fg_chip *chip, int bsoc)
1745{
1746 int rc;
1747 u8 full_soc[2] = {0xFF, 0xFF};
1748
1749 /*
1750 * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC
1751 * needs to be updated to reflect the same. Write battery SOC to
1752 * FULL_SOC and write a full value to MONOTONIC_SOC.
1753 */
1754 rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET,
1755 (u8 *)&bsoc, 2, FG_IMA_ATOMIC);
1756 if (rc < 0) {
1757 pr_err("failed to write full_soc rc=%d\n", rc);
1758 return rc;
1759 }
1760
1761 rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
1762 full_soc, 2, FG_IMA_ATOMIC);
1763 if (rc < 0) {
1764 pr_err("failed to write monotonic_soc rc=%d\n", rc);
1765 return rc;
1766 }
1767
1768 return 0;
1769}
1770
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001771#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001772static int fg_charge_full_update(struct fg_chip *chip)
1773{
1774 union power_supply_propval prop = {0, };
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301775 int rc, msoc, bsoc, recharge_soc, msoc_raw;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001776
1777 if (!chip->dt.hold_soc_while_full)
1778 return 0;
1779
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001780 if (!batt_psy_initialized(chip))
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001781 return 0;
1782
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001783 mutex_lock(&chip->charge_full_lock);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001784 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
1785 chip->charge_done, 0);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001786 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
1787 &prop);
1788 if (rc < 0) {
1789 pr_err("Error in getting battery health, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001790 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001791 }
1792
1793 chip->health = prop.intval;
1794 recharge_soc = chip->dt.recharge_soc_thr;
1795 recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
1796 FULL_CAPACITY);
1797 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
1798 if (rc < 0) {
1799 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001800 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001801 }
1802
1803 /* We need 2 most significant bytes here */
1804 bsoc = (u32)bsoc >> 16;
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301805 rc = fg_get_msoc_raw(chip, &msoc_raw);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001806 if (rc < 0) {
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301807 pr_err("Error in getting msoc_raw, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001808 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001809 }
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301810 msoc = DIV_ROUND_CLOSEST(msoc_raw * FULL_CAPACITY, FULL_SOC_RAW);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001811
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001812 fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
1813 msoc, bsoc, chip->health, chip->charge_status,
1814 chip->charge_full);
1815 if (chip->charge_done && !chip->charge_full) {
1816 if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) {
1817 fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n");
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001818 chip->charge_full = true;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001819 /*
1820 * Lower the recharge voltage so that VBAT_LT_RECHG
1821 * signal will not be asserted soon.
1822 */
1823 rc = fg_set_recharge_voltage(chip,
1824 AUTO_RECHG_VOLT_LOW_LIMIT_MV);
1825 if (rc < 0) {
1826 pr_err("Error in reducing recharge voltage, rc=%d\n",
1827 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001828 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001829 }
1830 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001831 fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
1832 msoc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001833 }
Subbaraman Narayanamurthy9e024112017-10-05 16:05:16 -07001834 } else if ((msoc_raw <= recharge_soc || !chip->charge_done)
1835 && chip->charge_full) {
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07001836 if (chip->dt.linearize_soc) {
1837 chip->delta_soc = FULL_CAPACITY - msoc;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001838
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07001839 /*
1840 * We're spreading out the delta SOC over every 10%
1841 * change in monotonic SOC. We cannot spread more than
1842 * 9% in the range of 0-100 skipping the first 10%.
1843 */
1844 if (chip->delta_soc > 9) {
1845 chip->delta_soc = 0;
1846 chip->maint_soc = 0;
1847 } else {
1848 chip->maint_soc = FULL_CAPACITY;
1849 chip->last_msoc = msoc;
1850 }
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001851 }
1852
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001853 /*
1854 * Raise the recharge voltage so that VBAT_LT_RECHG signal
1855 * will be asserted soon as battery SOC had dropped below
1856 * the recharge SOC threshold.
1857 */
1858 rc = fg_set_recharge_voltage(chip,
1859 chip->dt.recharge_volt_thr_mv);
1860 if (rc < 0) {
1861 pr_err("Error in setting recharge voltage, rc=%d\n",
1862 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001863 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001864 }
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07001865
1866 /*
1867 * If charge_done is still set, wait for recharging or
1868 * discharging to happen.
1869 */
1870 if (chip->charge_done)
1871 goto out;
1872
1873 rc = fg_configure_full_soc(chip, bsoc);
1874 if (rc < 0)
1875 goto out;
1876
1877 chip->charge_full = false;
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301878 fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
1879 msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001880 }
1881
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001882out:
1883 mutex_unlock(&chip->charge_full_lock);
1884 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001885}
1886
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001887#define RCONN_CONFIG_BIT BIT(0)
1888static int fg_rconn_config(struct fg_chip *chip)
1889{
1890 int rc, esr_uohms;
1891 u64 scaling_factor;
1892 u32 val = 0;
1893
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07001894 if (!chip->dt.rconn_mohms)
1895 return 0;
1896
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001897 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
1898 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1899 if (rc < 0) {
1900 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
1901 return rc;
1902 }
1903
1904 if (val & RCONN_CONFIG_BIT) {
1905 fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
1906 return 0;
1907 }
1908
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08001909 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001910 if (rc < 0) {
1911 pr_err("failed to get ESR, rc=%d\n", rc);
1912 return rc;
1913 }
1914
1915 scaling_factor = div64_u64((u64)esr_uohms * 1000,
1916 esr_uohms + (chip->dt.rconn_mohms * 1000));
1917
1918 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
1919 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1920 if (rc < 0) {
1921 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1922 return rc;
1923 }
1924
1925 val *= scaling_factor;
1926 do_div(val, 1000);
1927 rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
1928 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1929 if (rc < 0) {
1930 pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1931 return rc;
1932 }
1933 fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
1934
1935 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
1936 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1937 if (rc < 0) {
1938 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1939 return rc;
1940 }
1941
1942 val *= scaling_factor;
1943 do_div(val, 1000);
1944 rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
1945 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1946 if (rc < 0) {
1947 pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1948 return rc;
1949 }
1950 fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
1951 val & 0xFF);
1952
1953 val = RCONN_CONFIG_BIT;
1954 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
1955 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1956 if (rc < 0) {
1957 pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
1958 return rc;
1959 }
1960
1961 return 0;
1962}
1963
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07001964static int fg_set_jeita_threshold(struct fg_chip *chip,
1965 enum jeita_levels level, int temp_decidegC)
1966{
1967 int rc;
1968 u8 val;
1969 u16 reg;
1970
1971 if (temp_decidegC < -300 || temp_decidegC > 970)
1972 return -EINVAL;
1973
1974 /* Resolution is 0.5C. Base is -30C. */
1975 val = DIV_ROUND_CLOSEST(((temp_decidegC / 10) + 30) * 10, 5);
1976 switch (level) {
1977 case JEITA_COLD:
1978 reg = BATT_INFO_JEITA_TOO_COLD(chip);
1979 break;
1980 case JEITA_COOL:
1981 reg = BATT_INFO_JEITA_COLD(chip);
1982 break;
1983 case JEITA_WARM:
1984 reg = BATT_INFO_JEITA_HOT(chip);
1985 break;
1986 case JEITA_HOT:
1987 reg = BATT_INFO_JEITA_TOO_HOT(chip);
1988 break;
1989 default:
1990 return -EINVAL;
1991 }
1992
1993 rc = fg_write(chip, reg, &val, 1);
1994 if (rc < 0) {
1995 pr_err("Error in setting jeita level %d, rc=%d\n", level, rc);
1996 return rc;
1997 }
1998
1999 return 0;
2000}
2001
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08002002static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
2003{
2004 u8 buf[2];
2005 int rc;
2006
2007 if (volt_uv <= 0 || volt_uv > 15590000) {
2008 pr_err("Invalid voltage %d\n", volt_uv);
2009 return -EINVAL;
2010 }
2011
2012 fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
2013
2014 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
2015 chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
2016 chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
2017 if (rc < 0) {
2018 pr_err("Error in writing vbatt_full, rc=%d\n", rc);
2019 return rc;
2020 }
2021
2022 return 0;
2023}
2024
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002025static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
2026{
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002027 u8 buf;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002028 int rc;
2029
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002030 if (!chip->dt.auto_recharge_soc)
2031 return 0;
2032
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002033 if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY)
2034 return 0;
2035
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002036 fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002037 rc = fg_sram_write(chip,
2038 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002039 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002040 chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
2041 if (rc < 0) {
2042 pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
2043 return rc;
2044 }
2045
2046 return 0;
2047}
2048
2049static int fg_adjust_recharge_soc(struct fg_chip *chip)
2050{
2051 int rc, msoc, recharge_soc, new_recharge_soc = 0;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002052 bool recharge_soc_status;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002053
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002054 if (!chip->dt.auto_recharge_soc)
2055 return 0;
2056
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002057 recharge_soc = chip->dt.recharge_soc_thr;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002058 recharge_soc_status = chip->recharge_soc_adjusted;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002059 /*
2060 * If the input is present and charging had been terminated, adjust
2061 * the recharge SOC threshold based on the monotonic SOC at which
2062 * the charge termination had happened.
2063 */
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002064 if (is_input_present(chip)) {
2065 if (chip->charge_done) {
2066 if (!chip->recharge_soc_adjusted) {
2067 /* Get raw monotonic SOC for calculation */
2068 rc = fg_get_msoc(chip, &msoc);
2069 if (rc < 0) {
2070 pr_err("Error in getting msoc, rc=%d\n",
2071 rc);
2072 return rc;
2073 }
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002074
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002075 /* Adjust the recharge_soc threshold */
2076 new_recharge_soc = msoc - (FULL_CAPACITY -
2077 recharge_soc);
2078 chip->recharge_soc_adjusted = true;
2079 } else {
2080 /* adjusted already, do nothing */
2081 return 0;
2082 }
2083 } else {
2084 /* Charging, do nothing */
2085 return 0;
2086 }
2087 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002088 /* Restore the default value */
2089 new_recharge_soc = recharge_soc;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002090 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002091 }
2092
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002093 rc = fg_set_recharge_soc(chip, new_recharge_soc);
2094 if (rc < 0) {
2095 chip->recharge_soc_adjusted = recharge_soc_status;
2096 pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
2097 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002098 }
2099
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002100 fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002101 return 0;
2102}
2103
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07002104static int fg_adjust_recharge_voltage(struct fg_chip *chip)
2105{
2106 int rc, recharge_volt_mv;
2107
2108 if (chip->dt.auto_recharge_soc)
2109 return 0;
2110
2111 fg_dbg(chip, FG_STATUS, "health: %d chg_status: %d chg_done: %d\n",
2112 chip->health, chip->charge_status, chip->charge_done);
2113
2114 recharge_volt_mv = chip->dt.recharge_volt_thr_mv;
2115
2116 /* Lower the recharge voltage in soft JEITA */
2117 if (chip->health == POWER_SUPPLY_HEALTH_WARM ||
2118 chip->health == POWER_SUPPLY_HEALTH_COOL)
2119 recharge_volt_mv -= 200;
2120
2121 rc = fg_set_recharge_voltage(chip, recharge_volt_mv);
2122 if (rc < 0) {
2123 pr_err("Error in setting recharge_voltage, rc=%d\n",
2124 rc);
2125 return rc;
2126 }
2127
2128 return 0;
2129}
2130
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002131static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
2132{
2133 enum slope_limit_status status;
2134 int rc;
2135 u8 buf;
2136
2137 if (!chip->slope_limit_en)
2138 return 0;
2139
2140 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
2141 chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
2142 if (batt_temp < chip->dt.slope_limit_temp)
2143 status = LOW_TEMP_CHARGE;
2144 else
2145 status = HIGH_TEMP_CHARGE;
2146 } else {
2147 if (batt_temp < chip->dt.slope_limit_temp)
2148 status = LOW_TEMP_DISCHARGE;
2149 else
2150 status = HIGH_TEMP_DISCHARGE;
2151 }
2152
2153 if (chip->slope_limit_sts == status)
2154 return 0;
2155
2156 fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
2157 chip->dt.slope_limit_coeffs[status], &buf);
2158 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
2159 chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
2160 chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
2161 if (rc < 0) {
2162 pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
2163 rc);
2164 return rc;
2165 }
2166
2167 chip->slope_limit_sts = status;
2168 fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
2169 buf);
2170 return 0;
2171}
2172
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002173static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
2174{
2175 u8 esr_tight_lt_flt, esr_broad_lt_flt;
2176 bool cold_temp = false;
2177 int rc;
2178
2179 /*
2180 * If the battery temperature is lower than -20 C, then skip modifying
2181 * ESR filter.
2182 */
2183 if (batt_temp < -210)
2184 return 0;
2185
2186 /*
2187 * If battery temperature is lesser than 10 C (default), then apply the
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002188 * ESR low temperature tight and broad filter values to ESR room
2189 * temperature tight and broad filters. If battery temperature is higher
2190 * than 10 C, then apply back the room temperature ESR filter
2191 * coefficients to ESR room temperature tight and broad filters.
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002192 */
2193 if (batt_temp > chip->dt.esr_flt_switch_temp
2194 && chip->esr_flt_cold_temp_en) {
2195 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002196 chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
2197 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
2198 chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002199 } else if (batt_temp <= chip->dt.esr_flt_switch_temp
2200 && !chip->esr_flt_cold_temp_en) {
2201 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
2202 chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
2203 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
2204 chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002205 cold_temp = true;
2206 } else {
2207 return 0;
2208 }
2209
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002210 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
2211 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
2212 &esr_tight_lt_flt,
2213 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002214 if (rc < 0) {
2215 pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
2216 return rc;
2217 }
2218
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002219 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
2220 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
2221 &esr_broad_lt_flt,
2222 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002223 if (rc < 0) {
2224 pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
2225 return rc;
2226 }
2227
2228 chip->esr_flt_cold_temp_en = cold_temp;
2229 fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n",
2230 cold_temp ? "cold" : "normal");
2231 return 0;
2232}
2233
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002234static int fg_esr_fcc_config(struct fg_chip *chip)
2235{
2236 union power_supply_propval prop = {0, };
2237 int rc;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002238 bool parallel_en = false, qnovo_en;
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002239
2240 if (is_parallel_charger_available(chip)) {
2241 rc = power_supply_get_property(chip->parallel_psy,
2242 POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop);
2243 if (rc < 0) {
2244 pr_err("Error in reading charging_enabled from parallel_psy, rc=%d\n",
2245 rc);
2246 return rc;
2247 }
2248 parallel_en = prop.intval;
2249 }
2250
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002251 qnovo_en = is_qnovo_en(chip);
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002252
2253 fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
2254 chip->charge_status, parallel_en, qnovo_en,
2255 chip->esr_fcc_ctrl_en);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002256
Nicholas Troast1769fd32016-09-07 09:20:58 -07002257 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002258 (parallel_en || qnovo_en)) {
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002259 if (chip->esr_fcc_ctrl_en)
2260 return 0;
2261
2262 /*
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002263 * When parallel charging or Qnovo is enabled, configure ESR
2264 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
2265 * request the main charger to increase FCC when it is supposed
2266 * to decrease it.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002267 */
2268 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2269 ESR_FAST_CRG_IVAL_MASK |
2270 ESR_FAST_CRG_CTL_EN_BIT,
2271 ESR_FCC_300MA | ESR_FAST_CRG_CTL_EN_BIT);
2272 if (rc < 0) {
2273 pr_err("Error in writing to %04x, rc=%d\n",
2274 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2275 return rc;
2276 }
2277
2278 chip->esr_fcc_ctrl_en = true;
2279 } else {
2280 if (!chip->esr_fcc_ctrl_en)
2281 return 0;
2282
2283 /*
2284 * If we're here, then it means either the device is not in
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002285 * charging state or parallel charging / Qnovo is disabled.
2286 * Disable ESR fast charge current control in SW.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002287 */
2288 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2289 ESR_FAST_CRG_CTL_EN_BIT, 0);
2290 if (rc < 0) {
2291 pr_err("Error in writing to %04x, rc=%d\n",
2292 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2293 return rc;
2294 }
2295
2296 chip->esr_fcc_ctrl_en = false;
2297 }
2298
2299 fg_dbg(chip, FG_STATUS, "esr_fcc_ctrl_en set to %d\n",
2300 chip->esr_fcc_ctrl_en);
2301 return 0;
2302}
2303
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002304static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
2305{
2306 int rc, cycles_init, cycles_max;
2307 bool end_of_charge = false;
2308
2309 end_of_charge = is_input_present(chip) && chip->charge_done;
2310 fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
2311
2312 /* ESR discharging timer configuration */
2313 cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
2314 chip->dt.esr_timer_awake[TIMER_RETRY];
2315 if (end_of_charge)
2316 cycles_init = 0;
2317
2318 cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
2319 chip->dt.esr_timer_awake[TIMER_MAX];
2320
2321 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
2322 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2323 if (rc < 0) {
2324 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2325 return rc;
2326 }
2327
2328 /* ESR charging timer configuration */
2329 cycles_init = cycles_max = -EINVAL;
2330 if (end_of_charge || sleep) {
2331 cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
2332 cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
2333 } else if (is_input_present(chip)) {
2334 cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
2335 cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
2336 }
2337
2338 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
2339 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2340 if (rc < 0) {
2341 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2342 return rc;
2343 }
2344
2345 return 0;
2346}
2347
Nicholas Troast805c2422017-07-06 14:53:46 -07002348static void fg_ttf_update(struct fg_chip *chip)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002349{
Nicholas Troast805c2422017-07-06 14:53:46 -07002350 int rc;
2351 int delay_ms;
2352 union power_supply_propval prop = {0, };
2353 int online = 0;
2354
2355 if (usb_psy_initialized(chip)) {
2356 rc = power_supply_get_property(chip->usb_psy,
2357 POWER_SUPPLY_PROP_ONLINE, &prop);
2358 if (rc < 0) {
2359 pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
2360 return;
2361 }
2362
2363 online = online || prop.intval;
2364 }
2365
2366 if (pc_port_psy_initialized(chip)) {
2367 rc = power_supply_get_property(chip->pc_port_psy,
2368 POWER_SUPPLY_PROP_ONLINE, &prop);
2369 if (rc < 0) {
2370 pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
2371 return;
2372 }
2373
2374 online = online || prop.intval;
2375 }
2376
2377 if (dc_psy_initialized(chip)) {
2378 rc = power_supply_get_property(chip->dc_psy,
2379 POWER_SUPPLY_PROP_ONLINE, &prop);
2380 if (rc < 0) {
2381 pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
2382 return;
2383 }
2384
2385 online = online || prop.intval;
2386 }
2387
2388
2389 if (chip->online_status == online)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002390 return;
2391
Nicholas Troast805c2422017-07-06 14:53:46 -07002392 chip->online_status = online;
2393 if (online)
2394 /* wait 35 seconds for the input to settle */
2395 delay_ms = 35000;
2396 else
2397 /* wait 5 seconds for current to settle during discharge */
2398 delay_ms = 5000;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002399
Nicholas Troast805c2422017-07-06 14:53:46 -07002400 vote(chip->awake_votable, TTF_PRIMING, true, 0);
2401 cancel_delayed_work_sync(&chip->ttf_work);
2402 mutex_lock(&chip->ttf.lock);
2403 fg_circ_buf_clr(&chip->ttf.ibatt);
2404 fg_circ_buf_clr(&chip->ttf.vbatt);
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07002405 chip->ttf.last_ttf = 0;
2406 chip->ttf.last_ms = 0;
Nicholas Troast805c2422017-07-06 14:53:46 -07002407 mutex_unlock(&chip->ttf.lock);
2408 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
Nicholas Troast1769fd32016-09-07 09:20:58 -07002409}
2410
Nicholas Troaste29dec92016-08-24 09:35:11 -07002411static void restore_cycle_counter(struct fg_chip *chip)
2412{
2413 int rc = 0, i;
2414 u8 data[2];
2415
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002416 if (!chip->cyc_ctr.en)
2417 return;
2418
Nicholas Troaste29dec92016-08-24 09:35:11 -07002419 mutex_lock(&chip->cyc_ctr.lock);
2420 for (i = 0; i < BUCKET_COUNT; i++) {
2421 rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
2422 CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
2423 FG_IMA_DEFAULT);
2424 if (rc < 0)
2425 pr_err("failed to read bucket %d rc=%d\n", i, rc);
2426 else
2427 chip->cyc_ctr.count[i] = data[0] | data[1] << 8;
2428 }
2429 mutex_unlock(&chip->cyc_ctr.lock);
2430}
2431
2432static void clear_cycle_counter(struct fg_chip *chip)
2433{
2434 int rc = 0, i;
2435
2436 if (!chip->cyc_ctr.en)
2437 return;
2438
2439 mutex_lock(&chip->cyc_ctr.lock);
2440 memset(chip->cyc_ctr.count, 0, sizeof(chip->cyc_ctr.count));
2441 for (i = 0; i < BUCKET_COUNT; i++) {
2442 chip->cyc_ctr.started[i] = false;
2443 chip->cyc_ctr.last_soc[i] = 0;
2444 }
2445 rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET,
2446 (u8 *)&chip->cyc_ctr.count,
2447 sizeof(chip->cyc_ctr.count) / sizeof(u8 *),
2448 FG_IMA_DEFAULT);
2449 if (rc < 0)
2450 pr_err("failed to clear cycle counter rc=%d\n", rc);
2451
2452 mutex_unlock(&chip->cyc_ctr.lock);
2453}
2454
2455static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
2456{
2457 int rc = 0;
2458 u16 cyc_count;
2459 u8 data[2];
2460
2461 if (bucket < 0 || (bucket > BUCKET_COUNT - 1))
2462 return 0;
2463
2464 cyc_count = chip->cyc_ctr.count[bucket];
2465 cyc_count++;
2466 data[0] = cyc_count & 0xFF;
2467 data[1] = cyc_count >> 8;
2468
2469 rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
2470 CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
2471 FG_IMA_DEFAULT);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002472 if (rc < 0) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002473 pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
2474 bucket, rc);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002475 return rc;
2476 }
2477
2478 chip->cyc_ctr.count[bucket] = cyc_count;
2479 fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
2480 bucket);
2481
Nicholas Troaste29dec92016-08-24 09:35:11 -07002482 return rc;
2483}
2484
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002485static void fg_cycle_counter_update(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07002486{
2487 int rc = 0, bucket, i, batt_soc;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002488
2489 if (!chip->cyc_ctr.en)
2490 return;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002491
2492 mutex_lock(&chip->cyc_ctr.lock);
2493 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
2494 if (rc < 0) {
2495 pr_err("Failed to read battery soc rc: %d\n", rc);
2496 goto out;
2497 }
2498
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002499 /* We need only the most significant byte here */
2500 batt_soc = (u32)batt_soc >> 24;
2501
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002502 /* Find out which bucket the SOC falls in */
2503 bucket = batt_soc / BUCKET_SOC_PCT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002504
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002505 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002506 if (!chip->cyc_ctr.started[bucket]) {
2507 chip->cyc_ctr.started[bucket] = true;
2508 chip->cyc_ctr.last_soc[bucket] = batt_soc;
2509 }
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002510 } else if (chip->charge_done || !is_input_present(chip)) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002511 for (i = 0; i < BUCKET_COUNT; i++) {
2512 if (chip->cyc_ctr.started[i] &&
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002513 batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002514 rc = fg_inc_store_cycle_ctr(chip, i);
2515 if (rc < 0)
2516 pr_err("Error in storing cycle_ctr rc: %d\n",
2517 rc);
2518 chip->cyc_ctr.last_soc[i] = 0;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002519 chip->cyc_ctr.started[i] = false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002520 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002521 }
2522 }
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002523
2524 fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
2525 batt_soc, bucket, chip->charge_status);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002526out:
2527 mutex_unlock(&chip->cyc_ctr.lock);
2528}
2529
2530static int fg_get_cycle_count(struct fg_chip *chip)
2531{
2532 int count;
2533
2534 if (!chip->cyc_ctr.en)
2535 return 0;
2536
2537 if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT))
2538 return -EINVAL;
2539
2540 mutex_lock(&chip->cyc_ctr.lock);
2541 count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1];
2542 mutex_unlock(&chip->cyc_ctr.lock);
2543 return count;
2544}
2545
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002546static void status_change_work(struct work_struct *work)
2547{
2548 struct fg_chip *chip = container_of(work,
2549 struct fg_chip, status_change_work);
2550 union power_supply_propval prop = {0, };
2551 int rc, batt_temp;
2552
2553 if (!batt_psy_initialized(chip)) {
2554 fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
2555 goto out;
2556 }
2557
2558 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
2559 &prop);
2560 if (rc < 0) {
2561 pr_err("Error in getting charging status, rc=%d\n", rc);
2562 goto out;
2563 }
2564
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002565 chip->charge_status = prop.intval;
2566 rc = power_supply_get_property(chip->batt_psy,
2567 POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
2568 if (rc < 0) {
2569 pr_err("Error in getting charge type, rc=%d\n", rc);
2570 goto out;
2571 }
2572
2573 chip->charge_type = prop.intval;
2574 rc = power_supply_get_property(chip->batt_psy,
2575 POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
2576 if (rc < 0) {
2577 pr_err("Error in getting charge_done, rc=%d\n", rc);
2578 goto out;
2579 }
2580
2581 chip->charge_done = prop.intval;
2582 fg_cycle_counter_update(chip);
2583 fg_cap_learning_update(chip);
2584
2585 rc = fg_charge_full_update(chip);
2586 if (rc < 0)
2587 pr_err("Error in charge_full_update, rc=%d\n", rc);
2588
2589 rc = fg_adjust_recharge_soc(chip);
2590 if (rc < 0)
2591 pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
2592
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07002593 rc = fg_adjust_recharge_voltage(chip);
2594 if (rc < 0)
2595 pr_err("Error in adjusting recharge_voltage, rc=%d\n", rc);
2596
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002597 rc = fg_adjust_ki_coeff_dischg(chip);
2598 if (rc < 0)
2599 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
2600
2601 rc = fg_esr_fcc_config(chip);
2602 if (rc < 0)
2603 pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
2604
2605 rc = fg_get_battery_temp(chip, &batt_temp);
2606 if (!rc) {
2607 rc = fg_slope_limit_config(chip, batt_temp);
2608 if (rc < 0)
2609 pr_err("Error in configuring slope limiter rc:%d\n",
2610 rc);
2611
2612 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
2613 if (rc < 0)
2614 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
2615 rc);
2616 }
2617
2618 fg_ttf_update(chip);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07002619 chip->prev_charge_status = chip->charge_status;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002620out:
2621 fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
2622 chip->charge_status, chip->charge_type, chip->charge_done);
2623 pm_relax(chip->dev);
2624}
2625
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002626static int fg_bp_params_config(struct fg_chip *chip)
2627{
2628 int rc = 0;
2629 u8 buf;
2630
2631 /* This SRAM register is only present in v2.0 and above */
2632 if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
2633 chip->bp.float_volt_uv > 0) {
2634 fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
2635 chip->bp.float_volt_uv / 1000, &buf);
2636 rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
2637 chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
2638 chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
2639 if (rc < 0) {
2640 pr_err("Error in writing float_volt, rc=%d\n", rc);
2641 return rc;
2642 }
2643 }
2644
2645 if (chip->bp.vbatt_full_mv > 0) {
2646 rc = fg_set_constant_chg_voltage(chip,
2647 chip->bp.vbatt_full_mv * 1000);
2648 if (rc < 0)
2649 return rc;
2650 }
2651
2652 return rc;
2653}
2654
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002655#define PROFILE_LOAD_BIT BIT(0)
2656#define BOOTLOADER_LOAD_BIT BIT(1)
2657#define BOOTLOADER_RESTART_BIT BIT(2)
2658#define HLOS_RESTART_BIT BIT(3)
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002659static bool is_profile_load_required(struct fg_chip *chip)
2660{
Nicholas Troaste29dec92016-08-24 09:35:11 -07002661 u8 buf[PROFILE_COMP_LEN], val;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002662 bool profiles_same = false;
2663 int rc;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002664
Nicholas Troaste29dec92016-08-24 09:35:11 -07002665 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
2666 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2667 if (rc < 0) {
2668 pr_err("failed to read profile integrity rc=%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002669 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002670 }
2671
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002672 /* Check if integrity bit is set */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002673 if (val & PROFILE_LOAD_BIT) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002674 fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
Subbaraman Narayanamurthy73616e12017-03-20 14:37:54 -07002675
2676 /* Whitelist the values */
2677 val &= ~PROFILE_LOAD_BIT;
2678 if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
2679 val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
2680 val |= PROFILE_LOAD_BIT;
2681 pr_warn("Garbage value in profile integrity word: 0x%x\n",
2682 val);
2683 return true;
2684 }
2685
Nicholas Troaste29dec92016-08-24 09:35:11 -07002686 rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2687 buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
2688 if (rc < 0) {
2689 pr_err("Error in reading battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002690 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002691 }
2692 profiles_same = memcmp(chip->batt_profile, buf,
2693 PROFILE_COMP_LEN) == 0;
2694 if (profiles_same) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002695 fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
2696 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002697 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002698
2699 if (!chip->dt.force_load_profile) {
2700 pr_warn("Profiles doesn't match, skipping loading it since force_load_profile is disabled\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002701 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002702 pr_info("FG: loaded profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002703 dump_sram(buf, PROFILE_LOAD_WORD,
2704 PROFILE_COMP_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002705 pr_info("FG: available profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002706 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2707 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002708 }
2709 return false;
2710 }
2711
2712 fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n");
2713 } else {
2714 fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002715 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002716 pr_info("FG: profile to be loaded:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002717 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2718 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002719 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002720 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002721 return true;
2722}
2723
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08002724static void clear_battery_profile(struct fg_chip *chip)
2725{
2726 u8 val = 0;
2727 int rc;
2728
2729 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2730 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2731 if (rc < 0)
2732 pr_err("failed to write profile integrity rc=%d\n", rc);
2733}
2734
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002735#define SOC_READY_WAIT_MS 2000
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002736static int __fg_restart(struct fg_chip *chip)
2737{
2738 int rc, msoc;
2739 bool tried_again = false;
2740
2741 rc = fg_get_prop_capacity(chip, &msoc);
2742 if (rc < 0) {
2743 pr_err("Error in getting capacity, rc=%d\n", rc);
2744 return rc;
2745 }
2746
2747 chip->last_soc = msoc;
2748 chip->fg_restarting = true;
2749 reinit_completion(&chip->soc_ready);
2750 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT,
2751 RESTART_GO_BIT);
2752 if (rc < 0) {
2753 pr_err("Error in writing to %04x, rc=%d\n",
2754 BATT_SOC_RESTART(chip), rc);
2755 goto out;
2756 }
2757
2758wait:
2759 rc = wait_for_completion_interruptible_timeout(&chip->soc_ready,
2760 msecs_to_jiffies(SOC_READY_WAIT_MS));
2761
2762 /* If we were interrupted wait again one more time. */
2763 if (rc == -ERESTARTSYS && !tried_again) {
2764 tried_again = true;
2765 goto wait;
2766 } else if (rc <= 0) {
2767 pr_err("wait for soc_ready timed out rc=%d\n", rc);
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002768 }
2769
2770 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2771 if (rc < 0) {
2772 pr_err("Error in writing to %04x, rc=%d\n",
2773 BATT_SOC_RESTART(chip), rc);
2774 goto out;
2775 }
2776out:
2777 chip->fg_restarting = false;
2778 return rc;
2779}
2780
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002781static void profile_load_work(struct work_struct *work)
2782{
2783 struct fg_chip *chip = container_of(work,
2784 struct fg_chip,
2785 profile_load_work.work);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002786 u8 buf[2], val;
2787 int rc;
2788
2789 vote(chip->awake_votable, PROFILE_LOAD, true, 0);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07002790
2791 rc = fg_get_batt_id(chip);
2792 if (rc < 0) {
2793 pr_err("Error in getting battery id, rc:%d\n", rc);
2794 goto out;
2795 }
2796
2797 rc = fg_get_batt_profile(chip);
2798 if (rc < 0) {
2799 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
2800 chip->batt_id_ohms / 1000, rc);
2801 goto out;
2802 }
2803
2804 if (!chip->profile_available)
2805 goto out;
2806
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002807 if (!is_profile_load_required(chip))
2808 goto done;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002809
2810 clear_cycle_counter(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002811 mutex_lock(&chip->cl.lock);
2812 chip->cl.learned_cc_uah = 0;
2813 chip->cl.active = false;
2814 mutex_unlock(&chip->cl.lock);
2815
Nicholas Troaste29dec92016-08-24 09:35:11 -07002816 fg_dbg(chip, FG_STATUS, "profile loading started\n");
2817 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2818 if (rc < 0) {
2819 pr_err("Error in writing to %04x, rc=%d\n",
2820 BATT_SOC_RESTART(chip), rc);
2821 goto out;
2822 }
2823
2824 /* load battery profile */
2825 rc = fg_sram_write(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2826 chip->batt_profile, PROFILE_LEN, FG_IMA_ATOMIC);
2827 if (rc < 0) {
2828 pr_err("Error in writing battery profile, rc:%d\n", rc);
2829 goto out;
2830 }
2831
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002832 rc = __fg_restart(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002833 if (rc < 0) {
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002834 pr_err("Error in restarting FG, rc=%d\n", rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002835 goto out;
2836 }
2837
2838 fg_dbg(chip, FG_STATUS, "SOC is ready\n");
2839
2840 /* Set the profile integrity bit */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002841 val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002842 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2843 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2844 if (rc < 0) {
2845 pr_err("failed to write profile integrity rc=%d\n", rc);
2846 goto out;
2847 }
2848
Nicholas Troaste29dec92016-08-24 09:35:11 -07002849done:
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002850 rc = fg_bp_params_config(chip);
2851 if (rc < 0)
2852 pr_err("Error in configuring battery profile params, rc:%d\n",
2853 rc);
2854
Nicholas Troaste29dec92016-08-24 09:35:11 -07002855 rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
2856 FG_IMA_DEFAULT);
2857 if (rc < 0) {
2858 pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD,
2859 NOM_CAP_OFFSET, rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002860 } else {
2861 chip->cl.nom_cap_uah = (int)(buf[0] | buf[1] << 8) * 1000;
2862 rc = fg_load_learned_cap_from_sram(chip);
2863 if (rc < 0)
2864 pr_err("Error in loading capacity learning data, rc:%d\n",
2865 rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002866 }
2867
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002868 batt_psy_initialized(chip);
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07002869 fg_notify_charger(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002870 chip->profile_loaded = true;
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002871 fg_dbg(chip, FG_STATUS, "profile loaded successfully");
Nicholas Troaste29dec92016-08-24 09:35:11 -07002872out:
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07002873 chip->soc_reporting_ready = true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002874 vote(chip->awake_votable, PROFILE_LOAD, false, 0);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002875}
2876
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002877static void sram_dump_work(struct work_struct *work)
2878{
2879 struct fg_chip *chip = container_of(work, struct fg_chip,
2880 sram_dump_work.work);
2881 u8 buf[FG_SRAM_LEN];
2882 int rc;
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302883 s64 timestamp_ms, quotient;
2884 s32 remainder;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002885
2886 rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
2887 if (rc < 0) {
2888 pr_err("Error in reading FG SRAM, rc:%d\n", rc);
2889 goto resched;
2890 }
2891
2892 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302893 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2894 fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
2895 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002896 dump_sram(buf, 0, FG_SRAM_LEN);
2897 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302898 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2899 fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
2900 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002901resched:
2902 schedule_delayed_work(&chip->sram_dump_work,
2903 msecs_to_jiffies(fg_sram_dump_period_ms));
2904}
2905
2906static int fg_sram_dump_sysfs(const char *val, const struct kernel_param *kp)
2907{
2908 int rc;
2909 struct power_supply *bms_psy;
2910 struct fg_chip *chip;
2911 bool old_val = fg_sram_dump;
2912
2913 rc = param_set_bool(val, kp);
2914 if (rc) {
2915 pr_err("Unable to set fg_sram_dump: %d\n", rc);
2916 return rc;
2917 }
2918
2919 if (fg_sram_dump == old_val)
2920 return 0;
2921
2922 bms_psy = power_supply_get_by_name("bms");
2923 if (!bms_psy) {
2924 pr_err("bms psy not found\n");
2925 return -ENODEV;
2926 }
2927
2928 chip = power_supply_get_drvdata(bms_psy);
2929 if (fg_sram_dump)
2930 schedule_delayed_work(&chip->sram_dump_work,
2931 msecs_to_jiffies(fg_sram_dump_period_ms));
2932 else
2933 cancel_delayed_work_sync(&chip->sram_dump_work);
2934
2935 return 0;
2936}
2937
2938static struct kernel_param_ops fg_sram_dump_ops = {
2939 .set = fg_sram_dump_sysfs,
2940 .get = param_get_bool,
2941};
2942
2943module_param_cb(sram_dump_en, &fg_sram_dump_ops, &fg_sram_dump, 0644);
2944
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002945static int fg_restart_sysfs(const char *val, const struct kernel_param *kp)
2946{
2947 int rc;
2948 struct power_supply *bms_psy;
2949 struct fg_chip *chip;
2950
2951 rc = param_set_int(val, kp);
2952 if (rc) {
2953 pr_err("Unable to set fg_restart: %d\n", rc);
2954 return rc;
2955 }
2956
2957 if (fg_restart != 1) {
2958 pr_err("Bad value %d\n", fg_restart);
2959 return -EINVAL;
2960 }
2961
2962 bms_psy = power_supply_get_by_name("bms");
2963 if (!bms_psy) {
2964 pr_err("bms psy not found\n");
2965 return 0;
2966 }
2967
2968 chip = power_supply_get_drvdata(bms_psy);
2969 rc = __fg_restart(chip);
2970 if (rc < 0) {
2971 pr_err("Error in restarting FG, rc=%d\n", rc);
2972 return rc;
2973 }
2974
2975 pr_info("FG restart done\n");
2976 return rc;
2977}
2978
2979static struct kernel_param_ops fg_restart_ops = {
2980 .set = fg_restart_sysfs,
2981 .get = param_get_int,
2982};
2983
2984module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
2985
Nicholas Troast1769fd32016-09-07 09:20:58 -07002986#define HOURS_TO_SECONDS 3600
2987#define OCV_SLOPE_UV 10869
2988#define MILLI_UNIT 1000
2989#define MICRO_UNIT 1000000
Nicholas Troast805c2422017-07-06 14:53:46 -07002990#define NANO_UNIT 1000000000
2991static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002992{
Nicholas Troast805c2422017-07-06 14:53:46 -07002993 int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07002994 i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
2995 i, soc_per_step, msoc_this_step, msoc_next_step,
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07002996 ibatt_this_step, t_predicted_this_step, ttf_slope,
Nicholas Troast805c2422017-07-06 14:53:46 -07002997 t_predicted_cv, t_predicted = 0;
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07002998 s64 delta_ms;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002999
Subbaraman Narayanamurthy476e8372017-08-25 13:38:36 -07003000 if (!chip->soc_reporting_ready)
3001 return -ENODATA;
3002
Nicholas Troast1769fd32016-09-07 09:20:58 -07003003 if (chip->bp.float_volt_uv <= 0) {
3004 pr_err("battery profile is not loaded\n");
3005 return -ENODATA;
3006 }
3007
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003008 if (!batt_psy_initialized(chip)) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07003009 fg_dbg(chip, FG_TTF, "charger is not available\n");
3010 return -ENODATA;
3011 }
3012
Nicholas Troast32a22d32016-12-14 16:12:04 -08003013 rc = fg_get_prop_capacity(chip, &msoc);
3014 if (rc < 0) {
3015 pr_err("failed to get msoc rc=%d\n", rc);
3016 return rc;
3017 }
3018 fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
3019
Nicholas Troast805c2422017-07-06 14:53:46 -07003020 /* the battery is considered full if the SOC is 100% */
Nicholas Troast32a22d32016-12-14 16:12:04 -08003021 if (msoc >= 100) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07003022 *val = 0;
3023 return 0;
3024 }
3025
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003026 if (is_qnovo_en(chip))
3027 ttf_mode = TTF_MODE_QNOVO;
3028 else
3029 ttf_mode = TTF_MODE_NORMAL;
3030
3031 /* when switching TTF algorithms the TTF needs to be reset */
3032 if (chip->ttf.mode != ttf_mode) {
3033 fg_circ_buf_clr(&chip->ttf.ibatt);
3034 fg_circ_buf_clr(&chip->ttf.vbatt);
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003035 chip->ttf.last_ttf = 0;
3036 chip->ttf.last_ms = 0;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003037 chip->ttf.mode = ttf_mode;
3038 }
3039
Nicholas Troast805c2422017-07-06 14:53:46 -07003040 /* at least 10 samples are required to produce a stable IBATT */
3041 if (chip->ttf.ibatt.size < 10) {
3042 *val = -1;
3043 return 0;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003044 }
3045
Nicholas Troast805c2422017-07-06 14:53:46 -07003046 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003047 if (rc < 0) {
Nicholas Troast805c2422017-07-06 14:53:46 -07003048 pr_err("failed to get IBATT AVG rc=%d\n", rc);
3049 return rc;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003050 }
3051
Nicholas Troast805c2422017-07-06 14:53:46 -07003052 rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
3053 if (rc < 0) {
3054 pr_err("failed to get VBATT AVG rc=%d\n", rc);
3055 return rc;
3056 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003057
Nicholas Troast805c2422017-07-06 14:53:46 -07003058 ibatt_avg = -ibatt_avg / MILLI_UNIT;
3059 vbatt_avg /= MILLI_UNIT;
3060
3061 /* clamp ibatt_avg to iterm */
3062 if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
3063 ibatt_avg = abs(chip->dt.sys_term_curr_ma);
3064
Nicholas Troast1769fd32016-09-07 09:20:58 -07003065 fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
Nicholas Troast805c2422017-07-06 14:53:46 -07003066 fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003067
3068 rc = fg_get_battery_resistance(chip, &rbatt);
3069 if (rc < 0) {
3070 pr_err("failed to get battery resistance rc=%d\n", rc);
3071 return rc;
3072 }
3073
Nicholas Troast805c2422017-07-06 14:53:46 -07003074 rbatt /= MILLI_UNIT;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003075 fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
3076
Nicholas Troast805c2422017-07-06 14:53:46 -07003077 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003078 if (rc < 0) {
3079 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
3080 return rc;
3081 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003082
Nicholas Troast1769fd32016-09-07 09:20:58 -07003083 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3084 if (rc < 0) {
3085 pr_err("failed to get full soc rc=%d\n", rc);
3086 return rc;
3087 }
3088 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3089 FULL_SOC_RAW);
Nicholas Troast805c2422017-07-06 14:53:46 -07003090 act_cap_mah = full_soc * act_cap_mah / 100;
3091 fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
3092
3093 /* estimated battery current at the CC to CV transition */
3094 switch (chip->ttf.mode) {
3095 case TTF_MODE_NORMAL:
3096 i_cc2cv = ibatt_avg * vbatt_avg /
3097 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
3098 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003099 case TTF_MODE_QNOVO:
3100 i_cc2cv = min(
3101 chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
3102 ibatt_avg * vbatt_avg /
3103 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
3104 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07003105 default:
3106 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
3107 break;
3108 }
3109 fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003110
3111 /* if we are already in CV state then we can skip estimating CC */
3112 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
Nicholas Troast805c2422017-07-06 14:53:46 -07003113 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003114
Nicholas Troast1769fd32016-09-07 09:20:58 -07003115 /* estimated SOC at the CC to CV transition */
Nicholas Troast805c2422017-07-06 14:53:46 -07003116 soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003117 soc_cc2cv = 100 - soc_cc2cv;
3118 fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
3119
Nicholas Troast805c2422017-07-06 14:53:46 -07003120 switch (chip->ttf.mode) {
3121 case TTF_MODE_NORMAL:
3122 if (soc_cc2cv - msoc <= 0)
3123 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003124
Nicholas Troast805c2422017-07-06 14:53:46 -07003125 divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
3126 t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
3127 HOURS_TO_SECONDS, divisor);
3128 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003129 case TTF_MODE_QNOVO:
3130 soc_per_step = 100 / MAX_CC_STEPS;
3131 for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
3132 msoc_next_step = (i + 1) * soc_per_step;
3133 if (i == msoc / soc_per_step)
3134 msoc_this_step = msoc;
3135 else
3136 msoc_this_step = i * soc_per_step;
3137
3138 /* scale ibatt by 85% to account for discharge pulses */
3139 ibatt_this_step = min(
3140 chip->ttf.cc_step.arr[i] / MILLI_UNIT,
3141 ibatt_avg) * 85 / 100;
3142 divisor = max(100, ibatt_this_step * 100);
3143 t_predicted_this_step = div_s64((s64)act_cap_mah *
3144 (msoc_next_step - msoc_this_step) *
3145 HOURS_TO_SECONDS, divisor);
3146 t_predicted += t_predicted_this_step;
3147 fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
3148 msoc_this_step, msoc_next_step,
3149 ibatt_this_step, t_predicted_this_step);
3150 }
3151 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07003152 default:
3153 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
3154 break;
3155 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003156
Nicholas Troast805c2422017-07-06 14:53:46 -07003157cv_estimate:
3158 fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003159
Nicholas Troast805c2422017-07-06 14:53:46 -07003160 iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
3161 fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
3162
3163 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
3164 tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003165 else
Nicholas Troast805c2422017-07-06 14:53:46 -07003166 tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
Nicholas Troastde5d42f2017-01-20 16:47:31 -08003167
Nicholas Troast805c2422017-07-06 14:53:46 -07003168 rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
3169 if (rc < 0) {
3170 pr_err("failed to interpolate tau rc=%d\n", rc);
3171 return rc;
3172 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003173
Nicholas Troast805c2422017-07-06 14:53:46 -07003174 /* tau is scaled linearly from 95% to 100% SOC */
3175 if (msoc >= 95)
3176 tau = tau * 2 * (100 - msoc) / 10;
3177
3178 fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
3179 t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
3180 HOURS_TO_SECONDS, NANO_UNIT);
3181 fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
3182 t_predicted += t_predicted_cv;
3183
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003184 fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
3185 if (chip->ttf.last_ms != 0) {
3186 delta_ms = ktime_ms_delta(ktime_get_boottime(),
3187 ms_to_ktime(chip->ttf.last_ms));
3188 if (delta_ms > 10000) {
3189 ttf_slope = div64_s64(
3190 (s64)(t_predicted - chip->ttf.last_ttf) *
3191 MICRO_UNIT, delta_ms);
3192 if (ttf_slope > -100)
3193 ttf_slope = -100;
3194 else if (ttf_slope < -2000)
3195 ttf_slope = -2000;
3196
3197 t_predicted = div_s64(
3198 (s64)ttf_slope * delta_ms, MICRO_UNIT) +
3199 chip->ttf.last_ttf;
3200 fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
3201 } else {
3202 t_predicted = chip->ttf.last_ttf;
3203 }
3204 }
3205
Nicholas Troast805c2422017-07-06 14:53:46 -07003206 /* clamp the ttf to 0 */
3207 if (t_predicted < 0)
3208 t_predicted = 0;
3209
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003210 fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
Nicholas Troast805c2422017-07-06 14:53:46 -07003211 *val = t_predicted;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003212 return 0;
3213}
3214
Nicholas Troast805c2422017-07-06 14:53:46 -07003215static int fg_get_time_to_full(struct fg_chip *chip, int *val)
3216{
3217 int rc;
3218
3219 mutex_lock(&chip->ttf.lock);
3220 rc = fg_get_time_to_full_locked(chip, val);
3221 mutex_unlock(&chip->ttf.lock);
3222 return rc;
3223}
3224
Nicholas Troast1769fd32016-09-07 09:20:58 -07003225#define CENTI_ICORRECT_C0 105
3226#define CENTI_ICORRECT_C1 20
3227static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
3228{
Nicholas Troast805c2422017-07-06 14:53:46 -07003229 int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003230
Nicholas Troast805c2422017-07-06 14:53:46 -07003231 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003232 if (rc < 0) {
3233 /* try to get instantaneous current */
3234 rc = fg_get_battery_current(chip, &ibatt_avg);
3235 if (rc < 0) {
3236 pr_err("failed to get battery current, rc=%d\n", rc);
3237 return rc;
3238 }
3239 }
3240
Nicholas Troast805c2422017-07-06 14:53:46 -07003241 ibatt_avg /= MILLI_UNIT;
3242 /* clamp ibatt_avg to 100mA */
3243 if (ibatt_avg < 100)
3244 ibatt_avg = 100;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003245
3246 rc = fg_get_prop_capacity(chip, &msoc);
3247 if (rc < 0) {
3248 pr_err("Error in getting capacity, rc=%d\n", rc);
3249 return rc;
3250 }
3251
Nicholas Troast805c2422017-07-06 14:53:46 -07003252 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
3253 if (rc < 0) {
3254 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
3255 return rc;
3256 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003257
Nicholas Troast805c2422017-07-06 14:53:46 -07003258 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3259 if (rc < 0) {
3260 pr_err("failed to get full soc rc=%d\n", rc);
3261 return rc;
3262 }
3263 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3264 FULL_SOC_RAW);
3265 act_cap_mah = full_soc * act_cap_mah / 100;
3266
3267 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
3268 divisor = ibatt_avg * divisor / 100;
3269 divisor = max(100, divisor);
3270 *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003271 return 0;
3272}
3273
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003274static int fg_update_maint_soc(struct fg_chip *chip)
3275{
3276 int rc = 0, msoc;
3277
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003278 if (!chip->dt.linearize_soc)
3279 return 0;
3280
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003281 mutex_lock(&chip->charge_full_lock);
3282 if (chip->delta_soc <= 0)
3283 goto out;
3284
3285 rc = fg_get_msoc(chip, &msoc);
3286 if (rc < 0) {
3287 pr_err("Error in getting msoc, rc=%d\n", rc);
3288 goto out;
3289 }
3290
3291 if (msoc > chip->maint_soc) {
3292 /*
3293 * When the monotonic SOC goes above maintenance SOC, we should
3294 * stop showing the maintenance SOC.
3295 */
3296 chip->delta_soc = 0;
3297 chip->maint_soc = 0;
3298 } else if (msoc <= chip->last_msoc) {
3299 /* MSOC is decreasing. Decrease maintenance SOC as well */
3300 chip->maint_soc -= 1;
3301 if (!(msoc % 10)) {
3302 /*
3303 * Reduce the maintenance SOC additionally by 1 whenever
3304 * it crosses a SOC multiple of 10.
3305 */
3306 chip->maint_soc -= 1;
3307 chip->delta_soc -= 1;
3308 }
3309 }
3310
3311 fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
3312 msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
3313 chip->last_msoc = msoc;
3314out:
3315 mutex_unlock(&chip->charge_full_lock);
3316 return rc;
3317}
3318
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003319static int fg_esr_validate(struct fg_chip *chip)
3320{
3321 int rc, esr_uohms;
3322 u8 buf[2];
3323
3324 if (chip->dt.esr_clamp_mohms <= 0)
3325 return 0;
3326
3327 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
3328 if (rc < 0) {
3329 pr_err("failed to get ESR, rc=%d\n", rc);
3330 return rc;
3331 }
3332
3333 if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) {
3334 pr_debug("ESR %d is > ESR_clamp\n", esr_uohms);
3335 return 0;
3336 }
3337
3338 esr_uohms = chip->dt.esr_clamp_mohms * 1000;
3339 fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf);
3340 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word,
3341 chip->sp[FG_SRAM_ESR].addr_byte, buf,
3342 chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT);
3343 if (rc < 0) {
3344 pr_err("Error in writing ESR, rc=%d\n", rc);
3345 return rc;
3346 }
3347
3348 fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms);
3349 return 0;
3350}
3351
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003352static int fg_force_esr_meas(struct fg_chip *chip)
3353{
3354 int rc;
3355 int esr_uohms;
3356
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003357 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003358 /* force esr extraction enable */
3359 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3360 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
3361 FG_IMA_DEFAULT);
3362 if (rc < 0) {
3363 pr_err("failed to enable esr extn rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003364 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003365 }
3366
3367 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3368 LD_REG_CTRL_BIT, 0);
3369 if (rc < 0) {
3370 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003371 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003372 }
3373
3374 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3375 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3376 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
3377 if (rc < 0) {
3378 pr_err("Error in configuring force ESR rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003379 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003380 }
3381
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003382 /*
3383 * Release and grab the lock again after 1.5 seconds so that prepare
3384 * callback can succeed if the request comes in between.
3385 */
3386 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
3387
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003388 /* wait 1.5 seconds for hw to measure ESR */
3389 msleep(1500);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003390
3391 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003392 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3393 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3394 0);
3395 if (rc < 0) {
3396 pr_err("Error in restoring force ESR rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003397 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003398 }
3399
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003400 /* If qnovo is disabled, then leave ESR extraction enabled */
3401 if (!chip->qnovo_enable)
3402 goto done;
3403
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003404 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3405 LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
3406 if (rc < 0) {
3407 pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003408 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003409 }
3410
3411 /* force esr extraction disable */
3412 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3413 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0,
3414 FG_IMA_DEFAULT);
3415 if (rc < 0) {
3416 pr_err("failed to disable esr extn rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003417 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003418 }
3419
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003420done:
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003421 fg_get_battery_resistance(chip, &esr_uohms);
3422 fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003423out:
3424 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003425 return rc;
3426}
3427
3428static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
3429{
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003430 int rc = 0;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003431
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003432 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003433 /* force esr extraction disable when qnovo enables */
3434 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3435 ESR_EXTRACTION_ENABLE_OFFSET,
3436 BIT(0), qnovo_enable ? 0 : BIT(0),
3437 FG_IMA_DEFAULT);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003438 if (rc < 0) {
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003439 pr_err("Error in configuring esr extraction rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003440 goto out;
3441 }
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003442
3443 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3444 LD_REG_CTRL_BIT,
3445 qnovo_enable ? LD_REG_CTRL_BIT : 0);
3446 if (rc < 0) {
3447 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003448 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003449 }
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003450
3451 fg_dbg(chip, FG_STATUS, "%s for Qnovo\n",
3452 qnovo_enable ? "Prepared" : "Unprepared");
3453 chip->qnovo_enable = qnovo_enable;
3454out:
3455 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
3456 return rc;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003457}
Nicholas Troast805c2422017-07-06 14:53:46 -07003458
3459static void ttf_work(struct work_struct *work)
3460{
3461 struct fg_chip *chip = container_of(work, struct fg_chip,
3462 ttf_work.work);
3463 int rc, ibatt_now, vbatt_now, ttf;
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003464 ktime_t ktime_now;
Nicholas Troast805c2422017-07-06 14:53:46 -07003465
3466 mutex_lock(&chip->ttf.lock);
3467 if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
3468 chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
3469 goto end_work;
3470
3471 rc = fg_get_battery_current(chip, &ibatt_now);
3472 if (rc < 0) {
3473 pr_err("failed to get battery current, rc=%d\n", rc);
3474 goto end_work;
3475 }
3476
3477 rc = fg_get_battery_voltage(chip, &vbatt_now);
3478 if (rc < 0) {
3479 pr_err("failed to get battery voltage, rc=%d\n", rc);
3480 goto end_work;
3481 }
3482
3483 fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
3484 fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
3485
3486 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
3487 rc = fg_get_time_to_full_locked(chip, &ttf);
3488 if (rc < 0) {
3489 pr_err("failed to get ttf, rc=%d\n", rc);
3490 goto end_work;
3491 }
3492
3493 /* keep the wake lock and prime the IBATT and VBATT buffers */
3494 if (ttf < 0) {
3495 /* delay for one FG cycle */
3496 schedule_delayed_work(&chip->ttf_work,
3497 msecs_to_jiffies(1500));
3498 mutex_unlock(&chip->ttf.lock);
3499 return;
3500 }
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003501
3502 /* update the TTF reference point every minute */
3503 ktime_now = ktime_get_boottime();
3504 if (ktime_ms_delta(ktime_now,
3505 ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
3506 chip->ttf.last_ms == 0) {
3507 chip->ttf.last_ttf = ttf;
3508 chip->ttf.last_ms = ktime_to_ms(ktime_now);
3509 }
Nicholas Troast805c2422017-07-06 14:53:46 -07003510 }
3511
3512 /* recurse every 10 seconds */
3513 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
3514end_work:
3515 vote(chip->awake_votable, TTF_PRIMING, false, 0);
3516 mutex_unlock(&chip->ttf.lock);
3517}
3518
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003519/* PSY CALLBACKS STAY HERE */
3520
3521static int fg_psy_get_property(struct power_supply *psy,
3522 enum power_supply_property psp,
3523 union power_supply_propval *pval)
3524{
3525 struct fg_chip *chip = power_supply_get_drvdata(psy);
3526 int rc = 0;
3527
3528 switch (psp) {
3529 case POWER_SUPPLY_PROP_CAPACITY:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08003530 rc = fg_get_prop_capacity(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003531 break;
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003532 case POWER_SUPPLY_PROP_CAPACITY_RAW:
3533 rc = fg_get_msoc_raw(chip, &pval->intval);
3534 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003535 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08003536 if (chip->battery_missing)
3537 pval->intval = 3700000;
3538 else
3539 rc = fg_get_battery_voltage(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003540 break;
3541 case POWER_SUPPLY_PROP_CURRENT_NOW:
3542 rc = fg_get_battery_current(chip, &pval->intval);
3543 break;
3544 case POWER_SUPPLY_PROP_TEMP:
3545 rc = fg_get_battery_temp(chip, &pval->intval);
3546 break;
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003547 case POWER_SUPPLY_PROP_COLD_TEMP:
3548 rc = fg_get_jeita_threshold(chip, JEITA_COLD, &pval->intval);
3549 if (rc < 0) {
3550 pr_err("Error in reading jeita_cold, rc=%d\n", rc);
3551 return rc;
3552 }
3553 break;
3554 case POWER_SUPPLY_PROP_COOL_TEMP:
3555 rc = fg_get_jeita_threshold(chip, JEITA_COOL, &pval->intval);
3556 if (rc < 0) {
3557 pr_err("Error in reading jeita_cool, rc=%d\n", rc);
3558 return rc;
3559 }
3560 break;
3561 case POWER_SUPPLY_PROP_WARM_TEMP:
3562 rc = fg_get_jeita_threshold(chip, JEITA_WARM, &pval->intval);
3563 if (rc < 0) {
3564 pr_err("Error in reading jeita_warm, rc=%d\n", rc);
3565 return rc;
3566 }
3567 break;
3568 case POWER_SUPPLY_PROP_HOT_TEMP:
3569 rc = fg_get_jeita_threshold(chip, JEITA_HOT, &pval->intval);
3570 if (rc < 0) {
3571 pr_err("Error in reading jeita_hot, rc=%d\n", rc);
3572 return rc;
3573 }
3574 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003575 case POWER_SUPPLY_PROP_RESISTANCE:
3576 rc = fg_get_battery_resistance(chip, &pval->intval);
3577 break;
3578 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3579 rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
3580 break;
3581 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003582 pval->intval = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003583 break;
3584 case POWER_SUPPLY_PROP_RESISTANCE_ID:
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08003585 pval->intval = chip->batt_id_ohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003586 break;
3587 case POWER_SUPPLY_PROP_BATTERY_TYPE:
3588 pval->strval = fg_get_battery_type(chip);
3589 break;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003590 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
3591 pval->intval = chip->bp.float_volt_uv;
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07003592 break;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003593 case POWER_SUPPLY_PROP_CYCLE_COUNT:
3594 pval->intval = fg_get_cycle_count(chip);
3595 break;
3596 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3597 pval->intval = chip->cyc_ctr.id;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003598 break;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003599 case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003600 rc = fg_get_charge_raw(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003601 break;
3602 case POWER_SUPPLY_PROP_CHARGE_NOW:
3603 pval->intval = chip->cl.init_cc_uah;
3604 break;
3605 case POWER_SUPPLY_PROP_CHARGE_FULL:
3606 pval->intval = chip->cl.learned_cc_uah;
3607 break;
3608 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003609 rc = fg_get_charge_counter(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003610 break;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07003611 case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
3612 rc = fg_get_charge_counter_shadow(chip, &pval->intval);
3613 break;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003614 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
3615 rc = fg_get_time_to_full(chip, &pval->intval);
3616 break;
3617 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
3618 rc = fg_get_time_to_empty(chip, &pval->intval);
3619 break;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003620 case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
3621 pval->intval = chip->soc_reporting_ready;
3622 break;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303623 case POWER_SUPPLY_PROP_DEBUG_BATTERY:
3624 pval->intval = is_debug_batt_id(chip);
3625 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003626 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3627 rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
3628 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003629 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07003630 if ((chip->ttf.cc_step.sel >= 0) &&
3631 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
3632 pval->intval =
3633 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003634 } else {
3635 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07003636 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003637 return -EINVAL;
3638 }
3639 break;
3640 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Nicholas Troast805c2422017-07-06 14:53:46 -07003641 pval->intval = chip->ttf.cc_step.sel;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003642 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003643 default:
Nicholas Troast1769fd32016-09-07 09:20:58 -07003644 pr_err("unsupported property %d\n", psp);
3645 rc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003646 break;
3647 }
3648
Nicholas Troast1769fd32016-09-07 09:20:58 -07003649 if (rc < 0)
3650 return -ENODATA;
3651
3652 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003653}
3654
3655static int fg_psy_set_property(struct power_supply *psy,
3656 enum power_supply_property psp,
3657 const union power_supply_propval *pval)
3658{
Nicholas Troaste29dec92016-08-24 09:35:11 -07003659 struct fg_chip *chip = power_supply_get_drvdata(psy);
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003660 int rc = 0;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003661
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003662 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003663 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3664 if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) {
3665 chip->cyc_ctr.id = pval->intval;
3666 } else {
3667 pr_err("rejecting invalid cycle_count_id = %d\n",
3668 pval->intval);
3669 return -EINVAL;
3670 }
Nicholas Troast60242812017-06-20 09:33:21 -07003671 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003672 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3673 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003674 break;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003675 case POWER_SUPPLY_PROP_RESISTANCE:
3676 rc = fg_force_esr_meas(chip);
3677 break;
3678 case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
3679 rc = fg_prepare_for_qnovo(chip, pval->intval);
3680 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003681 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07003682 if ((chip->ttf.cc_step.sel >= 0) &&
3683 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
3684 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
3685 pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003686 } else {
3687 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07003688 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003689 return -EINVAL;
3690 }
3691 break;
3692 case POWER_SUPPLY_PROP_CC_STEP_SEL:
3693 if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
Nicholas Troast805c2422017-07-06 14:53:46 -07003694 chip->ttf.cc_step.sel = pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003695 } else {
3696 pr_err("cc_step_sel is out of bounds [0, %d]\n",
3697 pval->intval);
3698 return -EINVAL;
3699 }
3700 break;
Subbaraman Narayanamurthy677e7252017-08-11 18:27:08 -07003701 case POWER_SUPPLY_PROP_CHARGE_FULL:
3702 if (chip->cl.active) {
3703 pr_warn("Capacity learning active!\n");
3704 return 0;
3705 }
3706 if (pval->intval <= 0 || pval->intval > chip->cl.nom_cap_uah) {
3707 pr_err("charge_full is out of bounds\n");
3708 return -EINVAL;
3709 }
3710 chip->cl.learned_cc_uah = pval->intval;
3711 rc = fg_save_learned_cap_to_sram(chip);
3712 if (rc < 0)
3713 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
3714 break;
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003715 case POWER_SUPPLY_PROP_COLD_TEMP:
3716 rc = fg_set_jeita_threshold(chip, JEITA_COLD, pval->intval);
3717 if (rc < 0) {
3718 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3719 return rc;
3720 }
3721 break;
3722 case POWER_SUPPLY_PROP_COOL_TEMP:
3723 rc = fg_set_jeita_threshold(chip, JEITA_COOL, pval->intval);
3724 if (rc < 0) {
3725 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
3726 return rc;
3727 }
3728 break;
3729 case POWER_SUPPLY_PROP_WARM_TEMP:
3730 rc = fg_set_jeita_threshold(chip, JEITA_WARM, pval->intval);
3731 if (rc < 0) {
3732 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
3733 return rc;
3734 }
3735 break;
3736 case POWER_SUPPLY_PROP_HOT_TEMP:
3737 rc = fg_set_jeita_threshold(chip, JEITA_HOT, pval->intval);
3738 if (rc < 0) {
3739 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
3740 return rc;
3741 }
3742 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003743 default:
3744 break;
3745 }
3746
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003747 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003748}
3749
3750static int fg_property_is_writeable(struct power_supply *psy,
3751 enum power_supply_property psp)
3752{
3753 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003754 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003755 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003756 case POWER_SUPPLY_PROP_CC_STEP:
3757 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Subbaraman Narayanamurthy677e7252017-08-11 18:27:08 -07003758 case POWER_SUPPLY_PROP_CHARGE_FULL:
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003759 case POWER_SUPPLY_PROP_COLD_TEMP:
3760 case POWER_SUPPLY_PROP_COOL_TEMP:
3761 case POWER_SUPPLY_PROP_WARM_TEMP:
3762 case POWER_SUPPLY_PROP_HOT_TEMP:
Nicholas Troaste29dec92016-08-24 09:35:11 -07003763 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003764 default:
3765 break;
3766 }
3767
3768 return 0;
3769}
3770
3771static void fg_external_power_changed(struct power_supply *psy)
3772{
3773 pr_debug("power supply changed\n");
3774}
3775
3776static int fg_notifier_cb(struct notifier_block *nb,
3777 unsigned long event, void *data)
3778{
3779 struct power_supply *psy = data;
3780 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
3781
3782 if (event != PSY_EVENT_PROP_CHANGED)
3783 return NOTIFY_OK;
3784
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08003785 if (work_pending(&chip->status_change_work))
3786 return NOTIFY_OK;
3787
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003788 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthya7249ef2017-10-03 20:34:38 -07003789 || (strcmp(psy->desc->name, "parallel") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003790 || (strcmp(psy->desc->name, "usb") == 0)) {
3791 /*
3792 * We cannot vote for awake votable here as that takes
3793 * a mutex lock and this is executed in an atomic context.
3794 */
3795 pm_stay_awake(chip->dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003796 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003797 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003798
3799 return NOTIFY_OK;
3800}
3801
3802static enum power_supply_property fg_psy_props[] = {
3803 POWER_SUPPLY_PROP_CAPACITY,
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003804 POWER_SUPPLY_PROP_CAPACITY_RAW,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003805 POWER_SUPPLY_PROP_TEMP,
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003806 POWER_SUPPLY_PROP_COLD_TEMP,
3807 POWER_SUPPLY_PROP_COOL_TEMP,
3808 POWER_SUPPLY_PROP_WARM_TEMP,
3809 POWER_SUPPLY_PROP_HOT_TEMP,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003810 POWER_SUPPLY_PROP_VOLTAGE_NOW,
3811 POWER_SUPPLY_PROP_VOLTAGE_OCV,
3812 POWER_SUPPLY_PROP_CURRENT_NOW,
3813 POWER_SUPPLY_PROP_RESISTANCE_ID,
3814 POWER_SUPPLY_PROP_RESISTANCE,
3815 POWER_SUPPLY_PROP_BATTERY_TYPE,
3816 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003817 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Nicholas Troaste29dec92016-08-24 09:35:11 -07003818 POWER_SUPPLY_PROP_CYCLE_COUNT,
3819 POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003820 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
3821 POWER_SUPPLY_PROP_CHARGE_NOW,
3822 POWER_SUPPLY_PROP_CHARGE_FULL,
3823 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07003824 POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
Nicholas Troast1769fd32016-09-07 09:20:58 -07003825 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3826 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003827 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303828 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003829 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003830 POWER_SUPPLY_PROP_CC_STEP,
3831 POWER_SUPPLY_PROP_CC_STEP_SEL,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003832};
3833
3834static const struct power_supply_desc fg_psy_desc = {
3835 .name = "bms",
3836 .type = POWER_SUPPLY_TYPE_BMS,
3837 .properties = fg_psy_props,
3838 .num_properties = ARRAY_SIZE(fg_psy_props),
3839 .get_property = fg_psy_get_property,
3840 .set_property = fg_psy_set_property,
3841 .external_power_changed = fg_external_power_changed,
3842 .property_is_writeable = fg_property_is_writeable,
3843};
3844
3845/* INIT FUNCTIONS STAY HERE */
3846
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003847#define DEFAULT_ESR_CHG_TIMER_RETRY 8
3848#define DEFAULT_ESR_CHG_TIMER_MAX 16
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003849static int fg_hw_init(struct fg_chip *chip)
3850{
3851 int rc;
3852 u8 buf[4], val;
3853
3854 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003855 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
3856 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003857 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
3858 if (rc < 0) {
3859 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
3860 return rc;
3861 }
3862
3863 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003864 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
3865 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003866 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
3867 if (rc < 0) {
3868 pr_err("Error in writing empty_volt, rc=%d\n", rc);
3869 return rc;
3870 }
3871
3872 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
3873 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003874 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
3875 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003876 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
3877 if (rc < 0) {
3878 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
3879 return rc;
3880 }
3881
3882 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
3883 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003884 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
3885 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003886 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
3887 if (rc < 0) {
3888 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
3889 return rc;
3890 }
3891
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003892 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
3893 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
3894 chip->dt.chg_term_base_curr_ma, buf);
3895 rc = fg_sram_write(chip,
3896 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
3897 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
3898 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
3899 FG_IMA_DEFAULT);
3900 if (rc < 0) {
3901 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
3902 rc);
3903 return rc;
3904 }
3905 }
3906
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003907 if (chip->dt.vbatt_low_thr_mv > 0) {
3908 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
3909 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003910 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
3911 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003912 chip->sp[FG_SRAM_VBATT_LOW].len,
3913 FG_IMA_DEFAULT);
3914 if (rc < 0) {
3915 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
3916 return rc;
3917 }
3918 }
3919
3920 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003921 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003922 chip->dt.delta_soc_thr, buf);
3923 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003924 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
3925 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
3926 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003927 FG_IMA_DEFAULT);
3928 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003929 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
3930 return rc;
3931 }
3932
3933 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
3934 chip->dt.delta_soc_thr, buf);
3935 rc = fg_sram_write(chip,
3936 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
3937 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
3938 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
3939 FG_IMA_DEFAULT);
3940 if (rc < 0) {
3941 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003942 return rc;
3943 }
3944 }
3945
cyizhaofb3eec52017-01-24 17:08:55 +08003946 /*
3947 * configure battery thermal coefficients c1,c2,c3
3948 * if its value is not zero.
3949 */
3950 if (chip->dt.batt_therm_coeffs[0] > 0) {
3951 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
3952 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
3953 if (rc < 0) {
3954 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
3955 rc);
3956 return rc;
3957 }
3958 }
3959
3960
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003961 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003962 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003963 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003964 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003965 return rc;
3966 }
3967 }
3968
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003969 if (chip->dt.recharge_volt_thr_mv > 0) {
3970 rc = fg_set_recharge_voltage(chip,
3971 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003972 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003973 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003974 rc);
3975 return rc;
3976 }
3977 }
3978
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003979 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
3980 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
3981 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
3982 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
3983 if (rc < 0) {
3984 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
3985 return rc;
3986 }
3987 }
3988
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003989 rc = fg_set_jeita_threshold(chip, JEITA_COLD,
3990 chip->dt.jeita_thresholds[JEITA_COLD] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003991 if (rc < 0) {
3992 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3993 return rc;
3994 }
3995
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003996 rc = fg_set_jeita_threshold(chip, JEITA_COOL,
3997 chip->dt.jeita_thresholds[JEITA_COOL] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003998 if (rc < 0) {
3999 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
4000 return rc;
4001 }
4002
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004003 rc = fg_set_jeita_threshold(chip, JEITA_WARM,
4004 chip->dt.jeita_thresholds[JEITA_WARM] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004005 if (rc < 0) {
4006 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
4007 return rc;
4008 }
4009
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004010 rc = fg_set_jeita_threshold(chip, JEITA_HOT,
4011 chip->dt.jeita_thresholds[JEITA_HOT] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004012 if (rc < 0) {
4013 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
4014 return rc;
4015 }
4016
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004017 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
4018 chip->esr_timer_charging_default[TIMER_RETRY] =
4019 DEFAULT_ESR_CHG_TIMER_RETRY;
4020 chip->esr_timer_charging_default[TIMER_MAX] =
4021 DEFAULT_ESR_CHG_TIMER_MAX;
4022 } else {
4023 /* We don't need this for pm660 at present */
4024 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
4025 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004026 }
4027
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004028 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
4029 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
4030 if (rc < 0) {
4031 pr_err("Error in setting ESR timer, rc=%d\n", rc);
4032 return rc;
4033 }
4034
4035 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
4036 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
4037 if (rc < 0) {
4038 pr_err("Error in setting ESR timer, rc=%d\n", rc);
4039 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004040 }
4041
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07004042 restore_cycle_counter(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004043
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004044 if (chip->dt.jeita_hyst_temp >= 0) {
4045 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
4046 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
4047 JEITA_TEMP_HYST_MASK, val);
4048 if (rc < 0) {
4049 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
4050 return rc;
4051 }
4052 }
4053
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004054 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
4055 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
4056 CHANGE_THOLD_MASK, val);
4057 if (rc < 0) {
4058 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
4059 return rc;
4060 }
4061
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07004062 rc = fg_rconn_config(chip);
4063 if (rc < 0) {
4064 pr_err("Error in configuring Rconn, rc=%d\n", rc);
4065 return rc;
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004066 }
4067
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004068 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
4069 chip->dt.esr_tight_flt_upct, buf);
4070 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
4071 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
4072 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
4073 if (rc < 0) {
4074 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
4075 return rc;
4076 }
4077
4078 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
4079 chip->dt.esr_broad_flt_upct, buf);
4080 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
4081 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
4082 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
4083 if (rc < 0) {
4084 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
4085 return rc;
4086 }
4087
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004088 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
4089 chip->dt.esr_pulse_thresh_ma, buf);
4090 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
4091 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
4092 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
4093 if (rc < 0) {
4094 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
4095 return rc;
4096 }
4097
4098 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
4099 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
4100 ESR_PULL_DOWN_IVAL_MASK, val);
4101 if (rc < 0) {
4102 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
4103 return rc;
4104 }
4105
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07004106 if (is_debug_batt_id(chip)) {
4107 val = ESR_NO_PULL_DOWN;
4108 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
4109 ESR_PULL_DOWN_MODE_MASK, val);
4110 if (rc < 0) {
4111 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
4112 return rc;
4113 }
4114 }
4115
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004116 return 0;
4117}
4118
4119static int fg_memif_init(struct fg_chip *chip)
4120{
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004121 if (chip->use_dma)
4122 return fg_dma_init(chip);
4123
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004124 return fg_ima_init(chip);
4125}
4126
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304127static int fg_adjust_timebase(struct fg_chip *chip)
4128{
4129 int rc = 0, die_temp;
4130 s32 time_base = 0;
4131 u8 buf[2] = {0};
4132
4133 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
4134 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
4135 if (rc < 0) {
4136 pr_err("Error in reading die_temp, rc:%d\n", rc);
4137 return rc;
4138 }
4139
4140 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
4141 die_temp / 1000, &time_base);
4142 if (rc < 0) {
4143 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
4144 return rc;
4145 }
4146
4147 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
4148 rc = fg_sram_write(chip,
4149 chip->sp[FG_SRAM_TIMEBASE].addr_word,
4150 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
4151 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
4152 if (rc < 0) {
4153 pr_err("Error in writing timebase, rc=%d\n", rc);
4154 return rc;
4155 }
4156 }
4157
4158 return 0;
4159}
4160
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004161/* INTERRUPT HANDLERS STAY HERE */
4162
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004163static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data)
4164{
4165 struct fg_chip *chip = data;
4166 u8 status;
4167 int rc;
4168
4169 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
4170 if (rc < 0) {
4171 pr_err("failed to read addr=0x%04x, rc=%d\n",
4172 MEM_IF_INT_RT_STS(chip), rc);
4173 return IRQ_HANDLED;
4174 }
4175
4176 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthy2d385062017-09-14 20:23:13 -07004177 complete_all(&chip->mem_grant);
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004178
4179 return IRQ_HANDLED;
4180}
4181
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004182static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
4183{
4184 struct fg_chip *chip = data;
4185 u8 status;
4186 int rc;
4187
4188 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
4189 if (rc < 0) {
4190 pr_err("failed to read addr=0x%04x, rc=%d\n",
4191 MEM_IF_INT_RT_STS(chip), rc);
4192 return IRQ_HANDLED;
4193 }
4194
4195 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004196
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07004197 mutex_lock(&chip->sram_rw_lock);
4198 rc = fg_clear_dma_errors_if_any(chip);
4199 if (rc < 0)
4200 pr_err("Error in clearing DMA error, rc=%d\n", rc);
4201
4202 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004203 rc = fg_clear_ima_errors_if_any(chip, true);
4204 if (rc < 0 && rc != -EAGAIN)
4205 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004206 }
4207
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07004208 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004209 return IRQ_HANDLED;
4210}
4211
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004212static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
4213{
4214 struct fg_chip *chip = data;
4215
4216 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4217 return IRQ_HANDLED;
4218}
4219
4220static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
4221{
4222 struct fg_chip *chip = data;
4223 u8 status;
4224 int rc;
4225
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004226 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
4227 if (rc < 0) {
4228 pr_err("failed to read addr=0x%04x, rc=%d\n",
4229 BATT_INFO_INT_RT_STS(chip), rc);
4230 return IRQ_HANDLED;
4231 }
4232
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004233 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004234 chip->battery_missing = (status & BT_MISS_BIT);
4235
4236 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07004237 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004238 chip->profile_loaded = false;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08004239 chip->soc_reporting_ready = false;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004240 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004241 }
4242
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004243 clear_battery_profile(chip);
4244 schedule_delayed_work(&chip->profile_load_work, 0);
4245
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304246 if (chip->fg_psy)
4247 power_supply_changed(chip->fg_psy);
4248
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004249 return IRQ_HANDLED;
4250}
4251
4252static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
4253{
4254 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004255 union power_supply_propval prop = {0, };
4256 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004257
4258 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004259 rc = fg_get_battery_temp(chip, &batt_temp);
4260 if (rc < 0) {
4261 pr_err("Error in getting batt_temp\n");
4262 return IRQ_HANDLED;
4263 }
4264
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004265 rc = fg_esr_filter_config(chip, batt_temp);
4266 if (rc < 0)
4267 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4268
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004269 rc = fg_slope_limit_config(chip, batt_temp);
4270 if (rc < 0)
4271 pr_err("Error in configuring slope limiter rc:%d\n", rc);
4272
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004273 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
4274 if (rc < 0)
4275 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
4276
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004277 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004278 chip->last_batt_temp = batt_temp;
4279 return IRQ_HANDLED;
4280 }
4281
4282 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
4283 &prop);
4284 chip->health = prop.intval;
4285
4286 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304287 rc = fg_adjust_timebase(chip);
4288 if (rc < 0)
4289 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4290
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07004291 rc = fg_adjust_recharge_voltage(chip);
4292 if (rc < 0)
4293 pr_err("Error in adjusting recharge_voltage, rc=%d\n",
4294 rc);
4295
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004296 chip->last_batt_temp = batt_temp;
4297 power_supply_changed(chip->batt_psy);
4298 }
4299
4300 if (abs(chip->last_batt_temp - batt_temp) > 30)
4301 pr_warn("Battery temperature last:%d current: %d\n",
4302 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004303 return IRQ_HANDLED;
4304}
4305
4306static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
4307{
4308 struct fg_chip *chip = data;
4309
4310 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4311 complete_all(&chip->soc_ready);
4312 return IRQ_HANDLED;
4313}
4314
4315static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
4316{
4317 struct fg_chip *chip = data;
4318
4319 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4320 complete_all(&chip->soc_update);
4321 return IRQ_HANDLED;
4322}
4323
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004324static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
4325{
4326 struct fg_chip *chip = data;
4327 int rc;
4328
4329 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4330 rc = fg_charge_full_update(chip);
4331 if (rc < 0)
4332 pr_err("Error in charge_full_update, rc=%d\n", rc);
4333
4334 return IRQ_HANDLED;
4335}
4336
4337static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004338{
4339 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004340 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004341
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004342 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07004343 fg_cycle_counter_update(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004344
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004345 if (chip->cl.active)
4346 fg_cap_learning_update(chip);
4347
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004348 rc = fg_charge_full_update(chip);
4349 if (rc < 0)
4350 pr_err("Error in charge_full_update, rc=%d\n", rc);
4351
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004352 rc = fg_adjust_ki_coeff_dischg(chip);
4353 if (rc < 0)
4354 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
4355
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004356 rc = fg_update_maint_soc(chip);
4357 if (rc < 0)
4358 pr_err("Error in updating maint_soc, rc=%d\n", rc);
4359
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004360 rc = fg_esr_validate(chip);
4361 if (rc < 0)
4362 pr_err("Error in validating ESR, rc=%d\n", rc);
4363
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304364 rc = fg_adjust_timebase(chip);
4365 if (rc < 0)
4366 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4367
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004368 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004369 power_supply_changed(chip->batt_psy);
4370
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004371 return IRQ_HANDLED;
4372}
4373
4374static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
4375{
4376 struct fg_chip *chip = data;
4377
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004378 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004379 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07004380 power_supply_changed(chip->batt_psy);
4381
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004382 return IRQ_HANDLED;
4383}
4384
4385static irqreturn_t fg_soc_irq_handler(int irq, void *data)
4386{
4387 struct fg_chip *chip = data;
4388
4389 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4390 return IRQ_HANDLED;
4391}
4392
4393static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
4394{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004395 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004396 return IRQ_HANDLED;
4397}
4398
4399static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
4400 /* BATT_SOC irqs */
4401 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004402 .name = "msoc-full",
4403 .handler = fg_soc_irq_handler,
4404 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004405 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004406 .name = "msoc-high",
4407 .handler = fg_soc_irq_handler,
4408 .wakeable = true,
4409 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004410 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004411 .name = "msoc-empty",
4412 .handler = fg_empty_soc_irq_handler,
4413 .wakeable = true,
4414 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004415 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004416 .name = "msoc-low",
4417 .handler = fg_soc_irq_handler,
4418 .wakeable = true,
4419 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004420 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004421 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004422 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004423 .wakeable = true,
4424 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004425 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004426 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004427 .handler = fg_delta_bsoc_irq_handler,
4428 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004429 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004430 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004431 .name = "soc-ready",
4432 .handler = fg_first_est_irq_handler,
4433 .wakeable = true,
4434 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004435 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004436 .name = "soc-update",
4437 .handler = fg_soc_update_irq_handler,
4438 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004439 /* BATT_INFO irqs */
4440 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004441 .name = "batt-temp-delta",
4442 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004443 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004444 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004445 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004446 .name = "batt-missing",
4447 .handler = fg_batt_missing_irq_handler,
4448 .wakeable = true,
4449 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004450 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004451 .name = "esr-delta",
4452 .handler = fg_dummy_irq_handler,
4453 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004454 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004455 .name = "vbatt-low",
4456 .handler = fg_vbatt_low_irq_handler,
4457 .wakeable = true,
4458 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004459 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004460 .name = "vbatt-pred-delta",
4461 .handler = fg_dummy_irq_handler,
4462 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004463 /* MEM_IF irqs */
4464 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004465 .name = "dma-grant",
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004466 .handler = fg_dma_grant_irq_handler,
4467 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004468 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004469 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004470 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004471 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004472 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004473 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004474 .name = "ima-rdy",
4475 .handler = fg_dummy_irq_handler,
4476 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004477};
4478
4479static int fg_get_irq_index_byname(const char *name)
4480{
4481 int i;
4482
4483 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
4484 if (strcmp(fg_irqs[i].name, name) == 0)
4485 return i;
4486 }
4487
4488 pr_err("%s is not in irq list\n", name);
4489 return -ENOENT;
4490}
4491
4492static int fg_register_interrupts(struct fg_chip *chip)
4493{
4494 struct device_node *child, *node = chip->dev->of_node;
4495 struct property *prop;
4496 const char *name;
4497 int rc, irq, irq_index;
4498
4499 for_each_available_child_of_node(node, child) {
4500 of_property_for_each_string(child, "interrupt-names", prop,
4501 name) {
4502 irq = of_irq_get_byname(child, name);
4503 if (irq < 0) {
4504 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
4505 name, irq);
4506 return irq;
4507 }
4508
4509 irq_index = fg_get_irq_index_byname(name);
4510 if (irq_index < 0)
4511 return irq_index;
4512
4513 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
4514 fg_irqs[irq_index].handler,
4515 IRQF_ONESHOT, name, chip);
4516 if (rc < 0) {
4517 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
4518 name, rc);
4519 return rc;
4520 }
4521
4522 fg_irqs[irq_index].irq = irq;
4523 if (fg_irqs[irq_index].wakeable)
4524 enable_irq_wake(fg_irqs[irq_index].irq);
4525 }
4526 }
4527
4528 return 0;
4529}
4530
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004531static int fg_parse_dt_property_u32_array(struct device_node *node,
4532 const char *prop_name, int *buf, int len)
4533{
4534 int rc;
4535
4536 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
4537 if (rc < 0) {
4538 if (rc == -EINVAL)
4539 return 0;
4540 else
4541 return rc;
4542 } else if (rc != len) {
4543 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
4544 rc);
4545 return -EINVAL;
4546 }
4547
4548 rc = of_property_read_u32_array(node, prop_name, buf, len);
4549 if (rc < 0) {
4550 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
4551 return rc;
4552 }
4553
4554 return 0;
4555}
4556
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004557static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
4558{
4559 struct device_node *node = chip->dev->of_node;
4560 int rc, i;
4561
4562 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
4563 &chip->dt.slope_limit_temp);
4564 if (rc < 0)
4565 return 0;
4566
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004567 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
4568 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
4569 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004570 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004571
4572 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
4573 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
4574 chip->dt.slope_limit_coeffs[i] < 0) {
4575 pr_err("Incorrect slope limit coefficient\n");
4576 return -EINVAL;
4577 }
4578 }
4579
4580 chip->slope_limit_en = true;
4581 return 0;
4582}
4583
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004584static int fg_parse_ki_coefficients(struct fg_chip *chip)
4585{
4586 struct device_node *node = chip->dev->of_node;
Subbaraman Narayanamurthye17be582017-08-08 19:28:37 -07004587 int rc, i, temp;
4588
4589 rc = of_property_read_u32(node, "qcom,ki-coeff-full-dischg", &temp);
4590 if (!rc)
4591 chip->dt.ki_coeff_full_soc_dischg = temp;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004592
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004593 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
4594 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
4595 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004596 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004597
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004598 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
4599 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
4600 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004601 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004602
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004603 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
4604 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
4605 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004606 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004607
4608 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
4609 if (chip->dt.ki_coeff_soc[i] < 0 ||
4610 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
4611 pr_err("Error in ki_coeff_soc_dischg values\n");
4612 return -EINVAL;
4613 }
4614
4615 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
4616 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
4617 pr_err("Error in ki_coeff_med_dischg values\n");
4618 return -EINVAL;
4619 }
4620
4621 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
4622 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
4623 pr_err("Error in ki_coeff_med_dischg values\n");
4624 return -EINVAL;
4625 }
4626 }
4627 chip->ki_coeff_dischg_en = true;
4628 return 0;
4629}
4630
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004631#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07004632#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004633#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004634#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004635#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07004636#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004637#define DEFAULT_DELTA_SOC_THR 1
4638#define DEFAULT_RECHARGE_SOC_THR 95
4639#define DEFAULT_BATT_TEMP_COLD 0
4640#define DEFAULT_BATT_TEMP_COOL 5
4641#define DEFAULT_BATT_TEMP_WARM 45
4642#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004643#define DEFAULT_CL_START_SOC 15
4644#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
Subbaraman Narayanamurthya01aac92017-10-11 14:05:11 -07004645#define DEFAULT_CL_MAX_TEMP_DECIDEGC 500
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004646#define DEFAULT_CL_MAX_INC_DECIPERC 5
4647#define DEFAULT_CL_MAX_DEC_DECIPERC 100
4648#define DEFAULT_CL_MIN_LIM_DECIPERC 0
4649#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004650#define BTEMP_DELTA_LOW 2
4651#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004652#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
4653#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
4654#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
4655#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
4656#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004657#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004658#define DEFAULT_ESR_PULSE_THRESH_MA 110
4659#define DEFAULT_ESR_MEAS_CURR_MA 120
Fenglin Wud10ccf12017-08-10 15:43:41 +08004660#define DEFAULT_BMD_EN_DELAY_MS 200
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004661static int fg_parse_dt(struct fg_chip *chip)
4662{
4663 struct device_node *child, *revid_node, *node = chip->dev->of_node;
4664 u32 base, temp;
4665 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004666 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004667
4668 if (!node) {
4669 dev_err(chip->dev, "device tree node missing\n");
4670 return -ENXIO;
4671 }
4672
4673 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
4674 if (!revid_node) {
4675 pr_err("Missing qcom,pmic-revid property - driver failed\n");
4676 return -EINVAL;
4677 }
4678
4679 chip->pmic_rev_id = get_revid_data(revid_node);
4680 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
4681 pr_err("Unable to get pmic_revid rc=%ld\n",
4682 PTR_ERR(chip->pmic_rev_id));
4683 /*
4684 * the revid peripheral must be registered, any failure
4685 * here only indicates that the rev-id module has not
4686 * probed yet.
4687 */
4688 return -EPROBE_DEFER;
4689 }
4690
4691 pr_debug("PMIC subtype %d Digital major %d\n",
4692 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
4693
4694 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004695 case PMI8998_SUBTYPE:
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004696 chip->use_dma = true;
Harry Yang2452b272017-03-06 13:56:14 -08004697 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
4698 chip->sp = pmi8998_v1_sram_params;
4699 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304700 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08004701 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
4702 chip->sp = pmi8998_v2_sram_params;
4703 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07004704 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004705 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07004706 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004707 break;
Harry Yange4e731b2017-03-06 14:35:09 -08004708 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304709 chip->sp = pmi8998_v2_sram_params;
4710 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07004711 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304712 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
4713 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304714 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004715 default:
4716 return -EINVAL;
4717 }
4718
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004719 if (of_get_available_child_count(node) == 0) {
4720 dev_err(chip->dev, "No child nodes specified!\n");
4721 return -ENXIO;
4722 }
4723
4724 for_each_available_child_of_node(node, child) {
4725 rc = of_property_read_u32(child, "reg", &base);
4726 if (rc < 0) {
4727 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
4728 child->full_name, rc);
4729 return rc;
4730 }
4731
4732 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
4733 if (rc < 0) {
4734 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
4735 base, rc);
4736 return rc;
4737 }
4738
4739 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004740 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004741 chip->batt_soc_base = base;
4742 break;
Harry Yang2452b272017-03-06 13:56:14 -08004743 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004744 chip->batt_info_base = base;
4745 break;
Harry Yang2452b272017-03-06 13:56:14 -08004746 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004747 chip->mem_if_base = base;
4748 break;
4749 default:
4750 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
4751 subtype);
4752 return -ENXIO;
4753 }
4754 }
4755
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004756 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
4757 if (rc < 0) {
4758 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
4759 return rc;
4760 }
4761 chip->rradc_base = base;
4762
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004763 /* Read all the optional properties below */
4764 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
4765 if (rc < 0)
4766 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
4767 else
4768 chip->dt.cutoff_volt_mv = temp;
4769
4770 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
4771 if (rc < 0)
4772 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
4773 else
4774 chip->dt.empty_volt_mv = temp;
4775
4776 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
4777 if (rc < 0)
4778 chip->dt.vbatt_low_thr_mv = -EINVAL;
4779 else
4780 chip->dt.vbatt_low_thr_mv = temp;
4781
4782 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
4783 if (rc < 0)
4784 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
4785 else
4786 chip->dt.chg_term_curr_ma = temp;
4787
4788 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
4789 if (rc < 0)
4790 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
4791 else
4792 chip->dt.sys_term_curr_ma = temp;
4793
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004794 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
4795 if (rc < 0)
4796 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
4797 else
4798 chip->dt.chg_term_base_curr_ma = temp;
4799
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004800 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
4801 if (rc < 0)
4802 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
4803 else
4804 chip->dt.delta_soc_thr = temp;
4805
4806 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
4807 if (rc < 0)
4808 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
4809 else
4810 chip->dt.recharge_soc_thr = temp;
4811
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004812 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
4813 if (rc < 0)
4814 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
4815 else
4816 chip->dt.recharge_volt_thr_mv = temp;
4817
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004818 chip->dt.auto_recharge_soc = of_property_read_bool(node,
4819 "qcom,fg-auto-recharge-soc");
4820
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004821 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
4822 if (rc < 0)
4823 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
4824 else
4825 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
4826
4827 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
4828 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
4829 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
4830 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004831 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
4832 sizeof(u32)) == NUM_JEITA_LEVELS) {
4833 rc = of_property_read_u32_array(node,
4834 "qcom,fg-jeita-thresholds",
4835 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
4836 if (rc < 0)
4837 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
4838 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004839 }
4840
cyizhaofb3eec52017-01-24 17:08:55 +08004841 if (of_property_count_elems_of_size(node,
4842 "qcom,battery-thermal-coefficients",
4843 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
4844 rc = of_property_read_u8_array(node,
4845 "qcom,battery-thermal-coefficients",
4846 chip->dt.batt_therm_coeffs,
4847 BATT_THERM_NUM_COEFFS);
4848 if (rc < 0)
4849 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
4850 rc);
4851 }
4852
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004853 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
4854 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
4855 if (rc < 0) {
4856 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
4857 chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
4858 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004859
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004860 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
4861 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
4862 if (rc < 0) {
4863 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
4864 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
4865 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004866
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004867 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
4868 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
4869 if (rc < 0) {
4870 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
4871 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
4872 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004873
Nicholas Troaste29dec92016-08-24 09:35:11 -07004874 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
4875 if (chip->cyc_ctr.en)
4876 chip->cyc_ctr.id = 1;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004877
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07004878 chip->dt.force_load_profile = of_property_read_bool(node,
4879 "qcom,fg-force-load-profile");
4880
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004881 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
4882 if (rc < 0)
4883 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
4884 else
4885 chip->dt.cl_start_soc = temp;
4886
4887 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
4888 if (rc < 0)
4889 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
4890 else
4891 chip->dt.cl_min_temp = temp;
4892
4893 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
4894 if (rc < 0)
4895 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
4896 else
4897 chip->dt.cl_max_temp = temp;
4898
4899 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
4900 if (rc < 0)
4901 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
4902 else
4903 chip->dt.cl_max_cap_inc = temp;
4904
4905 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
4906 if (rc < 0)
4907 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
4908 else
4909 chip->dt.cl_max_cap_dec = temp;
4910
4911 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
4912 if (rc < 0)
4913 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
4914 else
4915 chip->dt.cl_min_cap_limit = temp;
4916
4917 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
4918 if (rc < 0)
4919 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
4920 else
4921 chip->dt.cl_max_cap_limit = temp;
4922
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004923 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
4924 if (rc < 0)
4925 chip->dt.jeita_hyst_temp = -EINVAL;
4926 else
4927 chip->dt.jeita_hyst_temp = temp;
4928
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004929 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
4930 if (rc < 0)
4931 chip->dt.batt_temp_delta = -EINVAL;
4932 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
4933 chip->dt.batt_temp_delta = temp;
4934
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004935 chip->dt.hold_soc_while_full = of_property_read_bool(node,
4936 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004937
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07004938 chip->dt.linearize_soc = of_property_read_bool(node,
4939 "qcom,linearize-soc");
4940
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004941 rc = fg_parse_ki_coefficients(chip);
4942 if (rc < 0)
4943 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
4944
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004945 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07004946 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004947 chip->dt.rconn_mohms = temp;
4948
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004949 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
4950 &temp);
4951 if (rc < 0)
4952 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
4953 else
4954 chip->dt.esr_flt_switch_temp = temp;
4955
4956 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
4957 &temp);
4958 if (rc < 0)
4959 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
4960 else
4961 chip->dt.esr_tight_flt_upct = temp;
4962
4963 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
4964 &temp);
4965 if (rc < 0)
4966 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
4967 else
4968 chip->dt.esr_broad_flt_upct = temp;
4969
4970 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
4971 &temp);
4972 if (rc < 0)
4973 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
4974 else
4975 chip->dt.esr_tight_lt_flt_upct = temp;
4976
4977 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
4978 &temp);
4979 if (rc < 0)
4980 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
4981 else
4982 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004983
4984 rc = fg_parse_slope_limit_coefficients(chip);
4985 if (rc < 0)
4986 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
4987
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004988 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
4989 if (rc < 0)
4990 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
4991 else
4992 chip->dt.esr_clamp_mohms = temp;
4993
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004994 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
4995 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
4996 if (!rc) {
4997 /* ESR pulse qualification threshold range is 1-997 mA */
4998 if (temp > 0 && temp < 997)
4999 chip->dt.esr_pulse_thresh_ma = temp;
5000 }
5001
5002 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
5003 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
5004 if (!rc) {
5005 /* ESR measurement current range is 60-240 mA */
5006 if (temp >= 60 || temp <= 240)
5007 chip->dt.esr_meas_curr_ma = temp;
5008 }
5009
Fenglin Wud10ccf12017-08-10 15:43:41 +08005010 chip->dt.bmd_en_delay_ms = DEFAULT_BMD_EN_DELAY_MS;
5011 rc = of_property_read_u32(node, "qcom,fg-bmd-en-delay-ms", &temp);
5012 if (!rc) {
5013 if (temp > DEFAULT_BMD_EN_DELAY_MS)
5014 chip->dt.bmd_en_delay_ms = temp;
5015 }
5016
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005017 return 0;
5018}
5019
5020static void fg_cleanup(struct fg_chip *chip)
5021{
Subbaraman Narayanamurthyf580cb92017-08-30 20:27:41 -07005022 int i;
5023
5024 for (i = 0; i < FG_IRQ_MAX; i++) {
5025 if (fg_irqs[i].irq)
5026 devm_free_irq(chip->dev, fg_irqs[i].irq, chip);
5027 }
5028
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005029 power_supply_unreg_notifier(&chip->nb);
Nicholas Troast69da2252016-09-07 16:17:47 -07005030 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005031 if (chip->awake_votable)
5032 destroy_votable(chip->awake_votable);
5033
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005034 if (chip->delta_bsoc_irq_en_votable)
5035 destroy_votable(chip->delta_bsoc_irq_en_votable);
5036
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005037 if (chip->batt_miss_irq_en_votable)
5038 destroy_votable(chip->batt_miss_irq_en_votable);
5039
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005040 if (chip->batt_id_chan)
5041 iio_channel_release(chip->batt_id_chan);
5042
5043 dev_set_drvdata(chip->dev, NULL);
5044}
5045
5046static int fg_gen3_probe(struct platform_device *pdev)
5047{
5048 struct fg_chip *chip;
5049 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005050 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005051
5052 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
5053 if (!chip)
5054 return -ENOMEM;
5055
5056 chip->dev = &pdev->dev;
5057 chip->debug_mask = &fg_gen3_debug_mask;
5058 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07005059 chip->charge_status = -EINVAL;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07005060 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07005061 chip->ki_coeff_full_soc = -EINVAL;
Nicholas Troast805c2422017-07-06 14:53:46 -07005062 chip->online_status = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005063 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
5064 if (!chip->regmap) {
5065 dev_err(chip->dev, "Parent regmap is unavailable\n");
5066 return -ENXIO;
5067 }
5068
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08005069 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
5070 if (IS_ERR(chip->batt_id_chan)) {
5071 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
5072 pr_err("batt_id_chan unavailable %ld\n",
5073 PTR_ERR(chip->batt_id_chan));
5074 rc = PTR_ERR(chip->batt_id_chan);
5075 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005076 return rc;
5077 }
5078
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05305079 rc = of_property_match_string(chip->dev->of_node,
5080 "io-channel-names", "rradc_die_temp");
5081 if (rc >= 0) {
5082 chip->die_temp_chan = iio_channel_get(chip->dev,
5083 "rradc_die_temp");
5084 if (IS_ERR(chip->die_temp_chan)) {
5085 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
5086 pr_err("rradc_die_temp unavailable %ld\n",
5087 PTR_ERR(chip->die_temp_chan));
5088 rc = PTR_ERR(chip->die_temp_chan);
5089 chip->die_temp_chan = NULL;
5090 return rc;
5091 }
5092 }
5093
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005094 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
5095 chip);
5096 if (IS_ERR(chip->awake_votable)) {
5097 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005098 chip->awake_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005099 goto exit;
5100 }
5101
5102 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
5103 VOTE_SET_ANY,
5104 fg_delta_bsoc_irq_en_cb, chip);
5105 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
5106 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005107 chip->delta_bsoc_irq_en_votable = NULL;
5108 goto exit;
5109 }
5110
5111 chip->batt_miss_irq_en_votable = create_votable("FG_BATT_MISS_IRQ",
5112 VOTE_SET_ANY,
5113 fg_batt_miss_irq_en_cb, chip);
5114 if (IS_ERR(chip->batt_miss_irq_en_votable)) {
5115 rc = PTR_ERR(chip->batt_miss_irq_en_votable);
5116 chip->batt_miss_irq_en_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005117 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005118 }
5119
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08005120 rc = fg_parse_dt(chip);
5121 if (rc < 0) {
5122 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
5123 rc);
5124 goto exit;
5125 }
5126
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005127 mutex_init(&chip->bus_lock);
5128 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07005129 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07005130 mutex_init(&chip->cl.lock);
Nicholas Troast805c2422017-07-06 14:53:46 -07005131 mutex_init(&chip->ttf.lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08005132 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07005133 mutex_init(&chip->qnovo_esr_ctrl_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005134 init_completion(&chip->soc_update);
5135 init_completion(&chip->soc_ready);
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07005136 init_completion(&chip->mem_grant);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005137 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
5138 INIT_WORK(&chip->status_change_work, status_change_work);
Nicholas Troast805c2422017-07-06 14:53:46 -07005139 INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005140 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005141
5142 rc = fg_memif_init(chip);
5143 if (rc < 0) {
5144 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
5145 rc);
5146 goto exit;
5147 }
5148
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07005149 platform_set_drvdata(pdev, chip);
5150
5151 rc = fg_register_interrupts(chip);
5152 if (rc < 0) {
5153 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
5154 rc);
5155 goto exit;
5156 }
5157
5158 /* Keep SOC_UPDATE irq disabled until we require it */
5159 if (fg_irqs[SOC_UPDATE_IRQ].irq)
5160 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
5161
5162 /* Keep BSOC_DELTA_IRQ disabled until we require it */
5163 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);
5164
5165 /* Keep BATT_MISSING_IRQ disabled until we require it */
5166 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);
5167
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005168 rc = fg_hw_init(chip);
5169 if (rc < 0) {
5170 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
5171 rc);
5172 goto exit;
5173 }
5174
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005175 /* Register the power supply */
5176 fg_psy_cfg.drv_data = chip;
5177 fg_psy_cfg.of_node = NULL;
5178 fg_psy_cfg.supplied_to = NULL;
5179 fg_psy_cfg.num_supplicants = 0;
5180 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
5181 &fg_psy_cfg);
5182 if (IS_ERR(chip->fg_psy)) {
5183 pr_err("failed to register fg_psy rc = %ld\n",
5184 PTR_ERR(chip->fg_psy));
5185 goto exit;
5186 }
5187
5188 chip->nb.notifier_call = fg_notifier_cb;
5189 rc = power_supply_reg_notifier(&chip->nb);
5190 if (rc < 0) {
5191 pr_err("Couldn't register psy notifier rc = %d\n", rc);
5192 goto exit;
5193 }
5194
Nicholas Troast69da2252016-09-07 16:17:47 -07005195 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005196 if (rc < 0) {
5197 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
5198 rc);
5199 goto exit;
5200 }
5201
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005202 rc = fg_get_battery_voltage(chip, &volt_uv);
5203 if (!rc)
5204 rc = fg_get_prop_capacity(chip, &msoc);
5205
5206 if (!rc)
5207 rc = fg_get_battery_temp(chip, &batt_temp);
5208
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005209 if (!rc) {
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005210 pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08005211 msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005212 rc = fg_esr_filter_config(chip, batt_temp);
5213 if (rc < 0)
5214 pr_err("Error in configuring ESR filter rc:%d\n", rc);
5215 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005216
5217 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005218 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005219
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005220 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005221 return 0;
5222exit:
5223 fg_cleanup(chip);
5224 return rc;
5225}
5226
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005227static int fg_gen3_suspend(struct device *dev)
5228{
5229 struct fg_chip *chip = dev_get_drvdata(dev);
5230 int rc;
5231
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005232 rc = fg_esr_timer_config(chip, true);
5233 if (rc < 0)
5234 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005235
Nicholas Troast805c2422017-07-06 14:53:46 -07005236 cancel_delayed_work_sync(&chip->ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005237 if (fg_sram_dump)
5238 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005239 return 0;
5240}
5241
5242static int fg_gen3_resume(struct device *dev)
5243{
5244 struct fg_chip *chip = dev_get_drvdata(dev);
5245 int rc;
5246
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005247 rc = fg_esr_timer_config(chip, false);
5248 if (rc < 0)
5249 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005250
Nicholas Troast805c2422017-07-06 14:53:46 -07005251 schedule_delayed_work(&chip->ttf_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005252 if (fg_sram_dump)
5253 schedule_delayed_work(&chip->sram_dump_work,
5254 msecs_to_jiffies(fg_sram_dump_period_ms));
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005255 return 0;
5256}
5257
5258static const struct dev_pm_ops fg_gen3_pm_ops = {
5259 .suspend = fg_gen3_suspend,
5260 .resume = fg_gen3_resume,
5261};
5262
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005263static int fg_gen3_remove(struct platform_device *pdev)
5264{
5265 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
5266
5267 fg_cleanup(chip);
5268 return 0;
5269}
5270
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07005271static void fg_gen3_shutdown(struct platform_device *pdev)
5272{
5273 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
5274 int rc, bsoc;
5275
5276 if (chip->charge_full) {
5277 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
5278 if (rc < 0) {
5279 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
5280 return;
5281 }
5282
5283 /* We need 2 most significant bytes here */
5284 bsoc = (u32)bsoc >> 16;
5285
5286 rc = fg_configure_full_soc(chip, bsoc);
5287 if (rc < 0) {
5288 pr_err("Error in configuring full_soc, rc=%d\n", rc);
5289 return;
5290 }
5291 }
5292}
5293
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005294static const struct of_device_id fg_gen3_match_table[] = {
5295 {.compatible = FG_GEN3_DEV_NAME},
5296 {},
5297};
5298
5299static struct platform_driver fg_gen3_driver = {
5300 .driver = {
5301 .name = FG_GEN3_DEV_NAME,
5302 .owner = THIS_MODULE,
5303 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005304 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005305 },
5306 .probe = fg_gen3_probe,
5307 .remove = fg_gen3_remove,
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07005308 .shutdown = fg_gen3_shutdown,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005309};
5310
5311static int __init fg_gen3_init(void)
5312{
5313 return platform_driver_register(&fg_gen3_driver);
5314}
5315
5316static void __exit fg_gen3_exit(void)
5317{
5318 return platform_driver_unregister(&fg_gen3_driver);
5319}
5320
5321module_init(fg_gen3_init);
5322module_exit(fg_gen3_exit);
5323
5324MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
5325MODULE_LICENSE("GPL v2");
5326MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);