blob: 8c53b2e4c8e8551735aee40a9af04ea39382d6ac [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
Subbaraman Narayanamurthy286d5162017-10-27 20:02:54 -0700765 /*
766 * To have better endpoints for 0 and 100, it is good to tune the
767 * calculation discarding values 0 and 255 while rounding off. Rest
768 * of the values 1-254 will be scaled to 1-99. DIV_ROUND_UP will not
769 * be suitable here as it rounds up any value higher than 252 to 100.
770 */
771 if (*msoc == FULL_SOC_RAW)
772 *msoc = 100;
773 else if (*msoc == 0)
774 *msoc = 0;
775 else
776 *msoc = DIV_ROUND_CLOSEST((*msoc - 1) * (FULL_CAPACITY - 2),
777 FULL_SOC_RAW - 2) + 1;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800778 return 0;
779}
780
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800781static bool is_batt_empty(struct fg_chip *chip)
782{
783 u8 status;
784 int rc, vbatt_uv, msoc;
785
786 rc = fg_read(chip, BATT_SOC_INT_RT_STS(chip), &status, 1);
787 if (rc < 0) {
788 pr_err("failed to read addr=0x%04x, rc=%d\n",
789 BATT_SOC_INT_RT_STS(chip), rc);
790 return false;
791 }
792
793 if (!(status & MSOC_EMPTY_BIT))
794 return false;
795
796 rc = fg_get_battery_voltage(chip, &vbatt_uv);
797 if (rc < 0) {
798 pr_err("failed to get battery voltage, rc=%d\n", rc);
799 return false;
800 }
801
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800802 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800803 if (!rc)
804 pr_warn("batt_soc_rt_sts: %x vbatt: %d uV msoc:%d\n", status,
805 vbatt_uv, msoc);
806
807 return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false);
808}
809
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800810static int fg_get_debug_batt_id(struct fg_chip *chip, int *batt_id)
811{
812 int rc;
813 u64 temp;
814 u8 buf[2];
815
816 rc = fg_read(chip, ADC_RR_FAKE_BATT_LOW_LSB(chip), buf, 2);
817 if (rc < 0) {
818 pr_err("failed to read addr=0x%04x, rc=%d\n",
819 ADC_RR_FAKE_BATT_LOW_LSB(chip), rc);
820 return rc;
821 }
822
823 /*
824 * Fake battery threshold is encoded in the following format.
825 * Threshold (code) = (battery_id in Ohms) * 0.00015 * 2^10 / 2.5
826 */
827 temp = (buf[1] << 8 | buf[0]) * 2500000;
828 do_div(temp, 150 * 1024);
829 batt_id[0] = temp;
830 rc = fg_read(chip, ADC_RR_FAKE_BATT_HIGH_LSB(chip), buf, 2);
831 if (rc < 0) {
832 pr_err("failed to read addr=0x%04x, rc=%d\n",
833 ADC_RR_FAKE_BATT_HIGH_LSB(chip), rc);
834 return rc;
835 }
836
837 temp = (buf[1] << 8 | buf[0]) * 2500000;
838 do_div(temp, 150 * 1024);
839 batt_id[1] = temp;
840 pr_debug("debug batt_id range: [%d %d]\n", batt_id[0], batt_id[1]);
841 return 0;
842}
843
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700844static bool is_debug_batt_id(struct fg_chip *chip)
845{
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800846 int debug_batt_id[2], rc;
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700847
Fenglin Wu16ef9a72017-11-06 23:24:54 +0800848 if (chip->batt_id_ohms < 0)
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700849 return false;
850
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800851 rc = fg_get_debug_batt_id(chip, debug_batt_id);
852 if (rc < 0) {
853 pr_err("Failed to get debug batt_id, rc=%d\n", rc);
854 return false;
855 }
856
857 if (is_between(debug_batt_id[0], debug_batt_id[1],
858 chip->batt_id_ohms)) {
859 fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dohms\n",
860 chip->batt_id_ohms);
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700861 return true;
862 }
863
864 return false;
865}
866
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700867#define DEBUG_BATT_SOC 67
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800868#define BATT_MISS_SOC 50
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700869#define EMPTY_SOC 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700870static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
871{
872 int rc, msoc;
873
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700874 if (is_debug_batt_id(chip)) {
875 *val = DEBUG_BATT_SOC;
876 return 0;
877 }
878
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800879 if (chip->fg_restarting) {
880 *val = chip->last_soc;
881 return 0;
882 }
883
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -0800884 if (chip->battery_missing || !chip->soc_reporting_ready) {
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800885 *val = BATT_MISS_SOC;
886 return 0;
887 }
888
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800889 if (is_batt_empty(chip)) {
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700890 *val = EMPTY_SOC;
891 return 0;
892 }
893
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700894 if (chip->charge_full) {
895 *val = FULL_CAPACITY;
896 return 0;
897 }
898
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800899 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700900 if (rc < 0)
901 return rc;
902
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -0700903 if (chip->dt.linearize_soc && chip->delta_soc > 0)
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800904 *val = chip->maint_soc;
905 else
906 *val = msoc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700907 return 0;
908}
909
910#define DEFAULT_BATT_TYPE "Unknown Battery"
911#define MISSING_BATT_TYPE "Missing Battery"
912#define LOADING_BATT_TYPE "Loading Battery"
913static const char *fg_get_battery_type(struct fg_chip *chip)
914{
915 if (chip->battery_missing)
916 return MISSING_BATT_TYPE;
917
918 if (chip->bp.batt_type_str) {
919 if (chip->profile_loaded)
920 return chip->bp.batt_type_str;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -0800921 else if (chip->profile_available)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700922 return LOADING_BATT_TYPE;
923 }
924
925 return DEFAULT_BATT_TYPE;
926}
927
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800928static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700929{
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800930 int rc;
931
932 rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
933 BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
934 if (rc < 0)
935 pr_err("Error in writing to %04x, rc=%d\n",
936 BATT_INFO_BATT_MISS_CFG(chip), rc);
937 return rc;
938}
939
940static int fg_get_batt_id(struct fg_chip *chip)
941{
942 int rc, ret, batt_id = 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700943
944 if (!chip->batt_id_chan)
945 return -EINVAL;
946
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800947 rc = fg_batt_missing_config(chip, false);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700948 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800949 pr_err("Error in disabling BMD, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700950 return rc;
951 }
952
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800953 rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
954 if (rc < 0) {
955 pr_err("Error in reading batt_id channel, rc:%d\n", rc);
956 goto out;
957 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700958
Fenglin Wud10ccf12017-08-10 15:43:41 +0800959 /* Wait for BATT_ID to settle down before enabling BMD again */
960 msleep(chip->dt.bmd_en_delay_ms);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800961
962 fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
963 chip->batt_id_ohms = batt_id;
964out:
965 ret = fg_batt_missing_config(chip, true);
966 if (ret < 0) {
967 pr_err("Error in enabling BMD, ret=%d\n", ret);
968 return ret;
969 }
970
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -0700971 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, true, 0);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800972 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700973}
974
975static int fg_get_batt_profile(struct fg_chip *chip)
976{
977 struct device_node *node = chip->dev->of_node;
978 struct device_node *batt_node, *profile_node;
979 const char *data;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800980 int rc, len;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700981
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700982 batt_node = of_find_node_by_name(node, "qcom,battery-data");
983 if (!batt_node) {
984 pr_err("Batterydata not available\n");
985 return -ENXIO;
986 }
987
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800988 profile_node = of_batterydata_get_best_profile(batt_node,
989 chip->batt_id_ohms / 1000, NULL);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700990 if (IS_ERR(profile_node))
991 return PTR_ERR(profile_node);
992
993 if (!profile_node) {
994 pr_err("couldn't find profile handle\n");
995 return -ENODATA;
996 }
997
998 rc = of_property_read_string(profile_node, "qcom,battery-type",
999 &chip->bp.batt_type_str);
1000 if (rc < 0) {
1001 pr_err("battery type unavailable, rc:%d\n", rc);
1002 return rc;
1003 }
1004
1005 rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
1006 &chip->bp.float_volt_uv);
1007 if (rc < 0) {
1008 pr_err("battery float voltage unavailable, rc:%d\n", rc);
1009 chip->bp.float_volt_uv = -EINVAL;
1010 }
1011
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -08001012 rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001013 &chip->bp.fastchg_curr_ma);
1014 if (rc < 0) {
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -08001015 pr_err("battery fastchg current unavailable, rc:%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001016 chip->bp.fastchg_curr_ma = -EINVAL;
1017 }
1018
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07001019 rc = of_property_read_u32(profile_node, "qcom,fg-cc-cv-threshold-mv",
1020 &chip->bp.vbatt_full_mv);
1021 if (rc < 0) {
1022 pr_err("battery cc_cv threshold unavailable, rc:%d\n", rc);
1023 chip->bp.vbatt_full_mv = -EINVAL;
1024 }
1025
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001026 data = of_get_property(profile_node, "qcom,fg-profile-data", &len);
1027 if (!data) {
1028 pr_err("No profile data available\n");
1029 return -ENODATA;
1030 }
1031
1032 if (len != PROFILE_LEN) {
1033 pr_err("battery profile incorrect size: %d\n", len);
1034 return -EINVAL;
1035 }
1036
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07001037 chip->profile_available = true;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001038 memcpy(chip->batt_profile, data, len);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001039
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001040 return 0;
1041}
1042
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07001043static inline void get_batt_temp_delta(int delta, u8 *val)
1044{
1045 switch (delta) {
1046 case 2:
1047 *val = BTEMP_DELTA_2K;
1048 break;
1049 case 4:
1050 *val = BTEMP_DELTA_4K;
1051 break;
1052 case 6:
1053 *val = BTEMP_DELTA_6K;
1054 break;
1055 case 10:
1056 *val = BTEMP_DELTA_10K;
1057 break;
1058 default:
1059 *val = BTEMP_DELTA_2K;
1060 break;
1061 };
1062}
1063
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07001064static inline void get_esr_meas_current(int curr_ma, u8 *val)
1065{
1066 switch (curr_ma) {
1067 case 60:
1068 *val = ESR_MEAS_CUR_60MA;
1069 break;
1070 case 120:
1071 *val = ESR_MEAS_CUR_120MA;
1072 break;
1073 case 180:
1074 *val = ESR_MEAS_CUR_180MA;
1075 break;
1076 case 240:
1077 *val = ESR_MEAS_CUR_240MA;
1078 break;
1079 default:
1080 *val = ESR_MEAS_CUR_120MA;
1081 break;
1082 };
1083
1084 *val <<= ESR_PULL_DOWN_IVAL_SHIFT;
1085}
1086
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001087static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
1088 int cycles_max, bool charging, int flags)
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001089{
1090 u8 buf[2];
1091 int rc, timer_max, timer_init;
1092
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001093 if (cycles_init < 0 || cycles_max < 0)
1094 return 0;
1095
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001096 if (charging) {
1097 timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
1098 timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
1099 } else {
1100 timer_max = FG_SRAM_ESR_TIMER_DISCHG_MAX;
1101 timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
1102 }
1103
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001104 fg_encode(chip->sp, timer_max, cycles_max, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001105 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001106 chip->sp[timer_max].addr_word,
1107 chip->sp[timer_max].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001108 chip->sp[timer_max].len, flags);
1109 if (rc < 0) {
1110 pr_err("Error in writing esr_timer_dischg_max, rc=%d\n",
1111 rc);
1112 return rc;
1113 }
1114
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001115 fg_encode(chip->sp, timer_init, cycles_init, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001116 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001117 chip->sp[timer_init].addr_word,
1118 chip->sp[timer_init].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001119 chip->sp[timer_init].len, flags);
1120 if (rc < 0) {
1121 pr_err("Error in writing esr_timer_dischg_init, rc=%d\n",
1122 rc);
1123 return rc;
1124 }
1125
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001126 fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
1127 charging ? "charging" : "discharging", cycles_init, cycles_max);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001128 return 0;
1129}
1130
Nicholas Troaste29dec92016-08-24 09:35:11 -07001131/* Other functions HERE */
1132
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001133static void fg_notify_charger(struct fg_chip *chip)
1134{
1135 union power_supply_propval prop = {0, };
1136 int rc;
1137
1138 if (!chip->batt_psy)
1139 return;
1140
1141 if (!chip->profile_available)
1142 return;
1143
1144 prop.intval = chip->bp.float_volt_uv;
1145 rc = power_supply_set_property(chip->batt_psy,
1146 POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
1147 if (rc < 0) {
1148 pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
1149 rc);
1150 return;
1151 }
1152
1153 prop.intval = chip->bp.fastchg_curr_ma * 1000;
1154 rc = power_supply_set_property(chip->batt_psy,
1155 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
1156 if (rc < 0) {
1157 pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
1158 rc);
1159 return;
1160 }
1161
1162 fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
1163}
1164
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001165static int fg_batt_miss_irq_en_cb(struct votable *votable, void *data,
1166 int enable, const char *client)
1167{
1168 struct fg_chip *chip = data;
1169
1170 if (!chip->irqs[BATT_MISSING_IRQ].irq)
1171 return 0;
1172
1173 if (enable) {
1174 enable_irq(chip->irqs[BATT_MISSING_IRQ].irq);
1175 enable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
1176 } else {
1177 disable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
Subbaraman Narayanamurthyd1b4c842017-09-29 16:07:28 -07001178 disable_irq_nosync(chip->irqs[BATT_MISSING_IRQ].irq);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001179 }
1180
1181 return 0;
1182}
1183
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001184static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data,
1185 int enable, const char *client)
1186{
1187 struct fg_chip *chip = data;
1188
1189 if (!chip->irqs[BSOC_DELTA_IRQ].irq)
1190 return 0;
1191
1192 if (enable) {
1193 enable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1194 enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1195 } else {
1196 disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
Subbaraman Narayanamurthyd1b4c842017-09-29 16:07:28 -07001197 disable_irq_nosync(chip->irqs[BSOC_DELTA_IRQ].irq);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001198 }
1199
1200 return 0;
1201}
1202
Nicholas Troaste29dec92016-08-24 09:35:11 -07001203static int fg_awake_cb(struct votable *votable, void *data, int awake,
1204 const char *client)
1205{
1206 struct fg_chip *chip = data;
1207
1208 if (awake)
1209 pm_stay_awake(chip->dev);
1210 else
1211 pm_relax(chip->dev);
1212
1213 pr_debug("client: %s awake: %d\n", client, awake);
1214 return 0;
1215}
1216
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001217static bool batt_psy_initialized(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07001218{
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001219 if (chip->batt_psy)
1220 return true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07001221
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001222 chip->batt_psy = power_supply_get_by_name("battery");
Nicholas Troaste29dec92016-08-24 09:35:11 -07001223 if (!chip->batt_psy)
1224 return false;
1225
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001226 /* batt_psy is initialized, set the fcc and fv */
1227 fg_notify_charger(chip);
1228
Nicholas Troaste29dec92016-08-24 09:35:11 -07001229 return true;
1230}
1231
Nicholas Troast805c2422017-07-06 14:53:46 -07001232static bool usb_psy_initialized(struct fg_chip *chip)
1233{
1234 if (chip->usb_psy)
1235 return true;
1236
1237 chip->usb_psy = power_supply_get_by_name("usb");
1238 if (!chip->usb_psy)
1239 return false;
1240
1241 return true;
1242}
1243
1244static bool pc_port_psy_initialized(struct fg_chip *chip)
1245{
1246 if (chip->pc_port_psy)
1247 return true;
1248
1249 chip->pc_port_psy = power_supply_get_by_name("pc_port");
1250 if (!chip->pc_port_psy)
1251 return false;
1252
1253 return true;
1254}
1255
1256static bool dc_psy_initialized(struct fg_chip *chip)
1257{
1258 if (chip->dc_psy)
1259 return true;
1260
1261 chip->dc_psy = power_supply_get_by_name("dc");
1262 if (!chip->dc_psy)
1263 return false;
1264
1265 return true;
1266}
1267
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001268static bool is_parallel_charger_available(struct fg_chip *chip)
1269{
1270 if (!chip->parallel_psy)
1271 chip->parallel_psy = power_supply_get_by_name("parallel");
1272
1273 if (!chip->parallel_psy)
1274 return false;
1275
1276 return true;
1277}
1278
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001279static int fg_prime_cc_soc_sw(struct fg_chip *chip, int cc_soc_sw)
1280{
1281 int rc;
1282
1283 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1284 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
1285 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
1286 if (rc < 0)
1287 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1288 else
1289 fg_dbg(chip, FG_STATUS, "cc_soc_sw: %x\n", cc_soc_sw);
1290
1291 return rc;
1292}
1293
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001294static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
1295{
1296 int16_t cc_mah;
1297 int rc;
1298
1299 if (chip->battery_missing || !chip->cl.learned_cc_uah)
1300 return -EPERM;
1301
1302 cc_mah = div64_s64(chip->cl.learned_cc_uah, 1000);
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001303 /* Write to a backup register to use across reboot */
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001304 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word,
1305 chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah,
1306 chip->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT);
1307 if (rc < 0) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001308 pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc);
1309 return rc;
1310 }
1311
1312 /* Write to actual capacity register for coulomb counter operation */
1313 rc = fg_sram_write(chip, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET,
1314 (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len,
1315 FG_IMA_DEFAULT);
1316 if (rc < 0) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001317 pr_err("Error in writing act_batt_cap, rc=%d\n", rc);
1318 return rc;
1319 }
1320
1321 fg_dbg(chip, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n",
1322 chip->cl.learned_cc_uah, cc_mah);
1323 return 0;
1324}
1325
1326#define CAPACITY_DELTA_DECIPCT 500
1327static int fg_load_learned_cap_from_sram(struct fg_chip *chip)
1328{
1329 int rc, act_cap_mah;
1330 int64_t delta_cc_uah, pct_nom_cap_uah;
1331
1332 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
1333 if (rc < 0) {
1334 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1335 return rc;
1336 }
1337
1338 chip->cl.learned_cc_uah = act_cap_mah * 1000;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001339
1340 if (chip->cl.learned_cc_uah != chip->cl.nom_cap_uah) {
Subbaraman Narayanamurthy51d3c902016-10-24 14:05:44 -07001341 if (chip->cl.learned_cc_uah == 0)
1342 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
1343
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001344 delta_cc_uah = abs(chip->cl.learned_cc_uah -
1345 chip->cl.nom_cap_uah);
1346 pct_nom_cap_uah = div64_s64((int64_t)chip->cl.nom_cap_uah *
1347 CAPACITY_DELTA_DECIPCT, 1000);
1348 /*
1349 * If the learned capacity is out of range by 50% from the
1350 * nominal capacity, then overwrite the learned capacity with
1351 * the nominal capacity.
1352 */
1353 if (chip->cl.nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001354 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected, capping it to nominal: %lld\n",
1355 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001356 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001357 }
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001358
1359 rc = fg_save_learned_cap_to_sram(chip);
1360 if (rc < 0)
1361 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001362 }
1363
1364 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah:%lld nom_cap_uah: %lld\n",
1365 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
1366 return 0;
1367}
1368
1369static bool is_temp_valid_cap_learning(struct fg_chip *chip)
1370{
1371 int rc, batt_temp;
1372
1373 rc = fg_get_battery_temp(chip, &batt_temp);
1374 if (rc < 0) {
1375 pr_err("Error in getting batt_temp\n");
1376 return false;
1377 }
1378
1379 if (batt_temp > chip->dt.cl_max_temp ||
1380 batt_temp < chip->dt.cl_min_temp) {
1381 fg_dbg(chip, FG_CAP_LEARN, "batt temp %d out of range [%d %d]\n",
1382 batt_temp, chip->dt.cl_min_temp, chip->dt.cl_max_temp);
1383 return false;
1384 }
1385
1386 return true;
1387}
1388
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001389#define QNOVO_CL_SKEW_DECIPCT -30
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001390static void fg_cap_learning_post_process(struct fg_chip *chip)
1391{
1392 int64_t max_inc_val, min_dec_val, old_cap;
1393 int rc;
1394
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001395 if (is_qnovo_en(chip)) {
1396 fg_dbg(chip, FG_CAP_LEARN, "applying skew %d on current learnt capacity %lld\n",
1397 QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
1398 chip->cl.final_cc_uah = chip->cl.final_cc_uah *
1399 (1000 + QNOVO_CL_SKEW_DECIPCT);
1400 do_div(chip->cl.final_cc_uah, 1000);
1401 }
1402
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001403 max_inc_val = chip->cl.learned_cc_uah
1404 * (1000 + chip->dt.cl_max_cap_inc);
1405 do_div(max_inc_val, 1000);
1406
1407 min_dec_val = chip->cl.learned_cc_uah
1408 * (1000 - chip->dt.cl_max_cap_dec);
1409 do_div(min_dec_val, 1000);
1410
1411 old_cap = chip->cl.learned_cc_uah;
1412 if (chip->cl.final_cc_uah > max_inc_val)
1413 chip->cl.learned_cc_uah = max_inc_val;
1414 else if (chip->cl.final_cc_uah < min_dec_val)
1415 chip->cl.learned_cc_uah = min_dec_val;
1416 else
1417 chip->cl.learned_cc_uah =
1418 chip->cl.final_cc_uah;
1419
1420 if (chip->dt.cl_max_cap_limit) {
1421 max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
1422 chip->dt.cl_max_cap_limit);
1423 do_div(max_inc_val, 1000);
1424 if (chip->cl.final_cc_uah > max_inc_val) {
1425 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
1426 chip->cl.final_cc_uah, max_inc_val);
1427 chip->cl.learned_cc_uah = max_inc_val;
1428 }
1429 }
1430
1431 if (chip->dt.cl_min_cap_limit) {
1432 min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
1433 chip->dt.cl_min_cap_limit);
1434 do_div(min_dec_val, 1000);
1435 if (chip->cl.final_cc_uah < min_dec_val) {
1436 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
1437 chip->cl.final_cc_uah, min_dec_val);
1438 chip->cl.learned_cc_uah = min_dec_val;
1439 }
1440 }
1441
1442 rc = fg_save_learned_cap_to_sram(chip);
1443 if (rc < 0)
1444 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
1445
1446 fg_dbg(chip, FG_CAP_LEARN, "final cc_uah = %lld, learned capacity %lld -> %lld uah\n",
1447 chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah);
1448}
1449
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001450static int fg_cap_learning_process_full_data(struct fg_chip *chip)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001451{
1452 int rc, cc_soc_sw, cc_soc_delta_pct;
1453 int64_t delta_cc_uah;
1454
1455 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
1456 if (rc < 0) {
1457 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
1458 return rc;
1459 }
1460
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -07001461 cc_soc_delta_pct =
1462 div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
1463 CC_SOC_30BIT);
1464
1465 /* If the delta is < 50%, then skip processing full data */
1466 if (cc_soc_delta_pct < 50) {
1467 pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
1468 return -ERANGE;
1469 }
1470
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001471 delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
1472 100);
1473 chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
1474 fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n",
1475 cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
1476 return 0;
1477}
1478
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001479static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001480{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001481 int rc, cc_soc_sw, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001482
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001483 batt_soc_msb = batt_soc >> 24;
1484 if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001485 chip->dt.cl_start_soc) {
1486 fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001487 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001488 return -EINVAL;
1489 }
1490
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001491 chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001492 FULL_SOC_RAW);
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001493
1494 /* Prime cc_soc_sw with battery SOC when capacity learning begins */
1495 cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
1496 BATT_SOC_32BIT);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001497 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001498 if (rc < 0) {
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001499 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1500 goto out;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001501 }
1502
1503 chip->cl.init_cc_soc_sw = cc_soc_sw;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001504 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 -07001505 batt_soc_msb, chip->cl.init_cc_soc_sw);
1506out:
1507 return rc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001508}
1509
1510static int fg_cap_learning_done(struct fg_chip *chip)
1511{
1512 int rc, cc_soc_sw;
1513
1514 rc = fg_cap_learning_process_full_data(chip);
1515 if (rc < 0) {
1516 pr_err("Error in processing cap learning full data, rc=%d\n",
1517 rc);
1518 goto out;
1519 }
1520
1521 /* Write a FULL value to cc_soc_sw */
1522 cc_soc_sw = CC_SOC_30BIT;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001523 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001524 if (rc < 0) {
1525 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1526 goto out;
1527 }
1528
1529 fg_cap_learning_post_process(chip);
1530out:
1531 return rc;
1532}
1533
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001534static void fg_cap_learning_update(struct fg_chip *chip)
1535{
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001536 int rc, batt_soc, batt_soc_msb, cc_soc_sw;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001537 bool input_present = is_input_present(chip);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001538 bool prime_cc = false;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001539
1540 mutex_lock(&chip->cl.lock);
1541
1542 if (!is_temp_valid_cap_learning(chip) || !chip->cl.learned_cc_uah ||
1543 chip->battery_missing) {
1544 fg_dbg(chip, FG_CAP_LEARN, "Aborting cap_learning %lld\n",
1545 chip->cl.learned_cc_uah);
1546 chip->cl.active = false;
1547 chip->cl.init_cc_uah = 0;
1548 goto out;
1549 }
1550
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001551 if (chip->charge_status == chip->prev_charge_status)
1552 goto out;
1553
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001554 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
1555 if (rc < 0) {
1556 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1557 goto out;
1558 }
1559
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001560 batt_soc_msb = (u32)batt_soc >> 24;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001561 fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001562 chip->charge_status, chip->cl.active, batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001563
1564 /* Initialize the starting point of learning capacity */
1565 if (!chip->cl.active) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07001566 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001567 rc = fg_cap_learning_begin(chip, batt_soc);
1568 chip->cl.active = (rc == 0);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001569 } else {
1570 if ((chip->charge_status ==
1571 POWER_SUPPLY_STATUS_DISCHARGING) ||
1572 chip->charge_done)
1573 prime_cc = true;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001574 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001575 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001576 if (chip->charge_done) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001577 rc = fg_cap_learning_done(chip);
1578 if (rc < 0)
1579 pr_err("Error in completing capacity learning, rc=%d\n",
1580 rc);
1581
1582 chip->cl.active = false;
1583 chip->cl.init_cc_uah = 0;
1584 }
1585
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001586 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
1587 if (!input_present) {
1588 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1589 batt_soc_msb);
1590 chip->cl.active = false;
1591 chip->cl.init_cc_uah = 0;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001592 prime_cc = true;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001593 }
1594 }
1595
Nicholas Troast1769fd32016-09-07 09:20:58 -07001596 if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001597 if (is_qnovo_en(chip) && input_present) {
1598 /*
1599 * Don't abort the capacity learning when qnovo
1600 * is enabled and input is present where the
1601 * charging status can go to "not charging"
1602 * intermittently.
1603 */
1604 } else {
1605 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1606 batt_soc_msb);
1607 chip->cl.active = false;
1608 chip->cl.init_cc_uah = 0;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001609 prime_cc = true;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001610 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001611 }
1612 }
1613
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001614 /*
1615 * Prime CC_SOC_SW when the device is not charging or during charge
1616 * termination when the capacity learning is not active.
1617 */
1618
1619 if (prime_cc) {
1620 if (chip->charge_done)
1621 cc_soc_sw = CC_SOC_30BIT;
1622 else
1623 cc_soc_sw = div_u64((u32)batt_soc *
1624 CC_SOC_30BIT, BATT_SOC_32BIT);
1625
1626 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
1627 if (rc < 0)
1628 pr_err("Error in writing cc_soc_sw, rc=%d\n",
1629 rc);
1630 }
1631
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001632out:
1633 mutex_unlock(&chip->cl.lock);
1634}
1635
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001636#define KI_COEFF_MED_DISCHG_DEFAULT 1500
1637#define KI_COEFF_HI_DISCHG_DEFAULT 2200
1638static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
1639{
1640 int rc, i, msoc;
1641 int ki_coeff_med = KI_COEFF_MED_DISCHG_DEFAULT;
1642 int ki_coeff_hi = KI_COEFF_HI_DISCHG_DEFAULT;
1643 u8 val;
1644
1645 if (!chip->ki_coeff_dischg_en)
1646 return 0;
1647
1648 rc = fg_get_prop_capacity(chip, &msoc);
1649 if (rc < 0) {
1650 pr_err("Error in getting capacity, rc=%d\n", rc);
1651 return rc;
1652 }
1653
Nicholas Troast1769fd32016-09-07 09:20:58 -07001654 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001655 for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) {
1656 if (msoc < chip->dt.ki_coeff_soc[i]) {
1657 ki_coeff_med = chip->dt.ki_coeff_med_dischg[i];
1658 ki_coeff_hi = chip->dt.ki_coeff_hi_dischg[i];
1659 }
1660 }
1661 }
1662
1663 fg_encode(chip->sp, FG_SRAM_KI_COEFF_MED_DISCHG, ki_coeff_med, &val);
1664 rc = fg_sram_write(chip,
1665 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_word,
1666 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_byte, &val,
1667 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].len,
1668 FG_IMA_DEFAULT);
1669 if (rc < 0) {
1670 pr_err("Error in writing ki_coeff_med, rc=%d\n", rc);
1671 return rc;
1672 }
1673
1674 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_DISCHG, ki_coeff_hi, &val);
1675 rc = fg_sram_write(chip,
1676 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_word,
1677 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_byte, &val,
1678 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].len,
1679 FG_IMA_DEFAULT);
1680 if (rc < 0) {
1681 pr_err("Error in writing ki_coeff_hi, rc=%d\n", rc);
1682 return rc;
1683 }
1684
1685 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_med %d ki_coeff_hi %d\n",
1686 ki_coeff_med, ki_coeff_hi);
1687 return 0;
1688}
1689
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001690#define KI_COEFF_FULL_SOC_DEFAULT 733
1691static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
1692{
1693 int rc, ki_coeff_full_soc;
1694 u8 val;
1695
1696 if (batt_temp < 0)
1697 ki_coeff_full_soc = 0;
Subbaraman Narayanamurthye17be582017-08-08 19:28:37 -07001698 else if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
1699 ki_coeff_full_soc = chip->dt.ki_coeff_full_soc_dischg;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001700 else
1701 ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
1702
1703 if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
1704 return 0;
1705
1706 fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
1707 rc = fg_sram_write(chip,
1708 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
1709 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
1710 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
1711 FG_IMA_DEFAULT);
1712 if (rc < 0) {
1713 pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
1714 return rc;
1715 }
1716
1717 chip->ki_coeff_full_soc = ki_coeff_full_soc;
1718 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
1719 ki_coeff_full_soc);
1720 return 0;
1721}
1722
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001723static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
1724{
1725 u8 buf;
1726 int rc;
1727
1728 if (chip->dt.auto_recharge_soc)
1729 return 0;
1730
1731 /* This configuration is available only for pmicobalt v2.0 and above */
1732 if (chip->wa_flags & PMI8998_V1_REV_WA)
1733 return 0;
1734
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07001735 if (voltage_mv == chip->last_recharge_volt_mv)
1736 return 0;
1737
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001738 fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
1739 voltage_mv);
1740 fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
1741 rc = fg_sram_write(chip,
1742 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
1743 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
1744 &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
1745 FG_IMA_DEFAULT);
1746 if (rc < 0) {
1747 pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
1748 rc);
1749 return rc;
1750 }
1751
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07001752 chip->last_recharge_volt_mv = voltage_mv;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001753 return 0;
1754}
1755
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07001756static int fg_configure_full_soc(struct fg_chip *chip, int bsoc)
1757{
1758 int rc;
1759 u8 full_soc[2] = {0xFF, 0xFF};
1760
1761 /*
1762 * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC
1763 * needs to be updated to reflect the same. Write battery SOC to
1764 * FULL_SOC and write a full value to MONOTONIC_SOC.
1765 */
1766 rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET,
1767 (u8 *)&bsoc, 2, FG_IMA_ATOMIC);
1768 if (rc < 0) {
1769 pr_err("failed to write full_soc rc=%d\n", rc);
1770 return rc;
1771 }
1772
1773 rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
1774 full_soc, 2, FG_IMA_ATOMIC);
1775 if (rc < 0) {
1776 pr_err("failed to write monotonic_soc rc=%d\n", rc);
1777 return rc;
1778 }
1779
1780 return 0;
1781}
1782
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001783#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001784static int fg_charge_full_update(struct fg_chip *chip)
1785{
1786 union power_supply_propval prop = {0, };
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301787 int rc, msoc, bsoc, recharge_soc, msoc_raw;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001788
1789 if (!chip->dt.hold_soc_while_full)
1790 return 0;
1791
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001792 if (!batt_psy_initialized(chip))
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001793 return 0;
1794
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001795 mutex_lock(&chip->charge_full_lock);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001796 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
1797 chip->charge_done, 0);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001798 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
1799 &prop);
1800 if (rc < 0) {
1801 pr_err("Error in getting battery health, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001802 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001803 }
1804
1805 chip->health = prop.intval;
1806 recharge_soc = chip->dt.recharge_soc_thr;
1807 recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
1808 FULL_CAPACITY);
1809 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
1810 if (rc < 0) {
1811 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001812 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001813 }
1814
1815 /* We need 2 most significant bytes here */
1816 bsoc = (u32)bsoc >> 16;
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301817 rc = fg_get_msoc_raw(chip, &msoc_raw);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001818 if (rc < 0) {
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301819 pr_err("Error in getting msoc_raw, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001820 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001821 }
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301822 msoc = DIV_ROUND_CLOSEST(msoc_raw * FULL_CAPACITY, FULL_SOC_RAW);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001823
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001824 fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
1825 msoc, bsoc, chip->health, chip->charge_status,
1826 chip->charge_full);
1827 if (chip->charge_done && !chip->charge_full) {
1828 if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) {
1829 fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n");
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001830 chip->charge_full = true;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001831 /*
1832 * Lower the recharge voltage so that VBAT_LT_RECHG
1833 * signal will not be asserted soon.
1834 */
1835 rc = fg_set_recharge_voltage(chip,
1836 AUTO_RECHG_VOLT_LOW_LIMIT_MV);
1837 if (rc < 0) {
1838 pr_err("Error in reducing recharge voltage, rc=%d\n",
1839 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001840 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001841 }
1842 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001843 fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
1844 msoc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001845 }
Subbaraman Narayanamurthy9e024112017-10-05 16:05:16 -07001846 } else if ((msoc_raw <= recharge_soc || !chip->charge_done)
1847 && chip->charge_full) {
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07001848 if (chip->dt.linearize_soc) {
1849 chip->delta_soc = FULL_CAPACITY - msoc;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001850
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07001851 /*
1852 * We're spreading out the delta SOC over every 10%
1853 * change in monotonic SOC. We cannot spread more than
1854 * 9% in the range of 0-100 skipping the first 10%.
1855 */
1856 if (chip->delta_soc > 9) {
1857 chip->delta_soc = 0;
1858 chip->maint_soc = 0;
1859 } else {
1860 chip->maint_soc = FULL_CAPACITY;
1861 chip->last_msoc = msoc;
1862 }
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001863 }
1864
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001865 /*
1866 * Raise the recharge voltage so that VBAT_LT_RECHG signal
1867 * will be asserted soon as battery SOC had dropped below
1868 * the recharge SOC threshold.
1869 */
1870 rc = fg_set_recharge_voltage(chip,
1871 chip->dt.recharge_volt_thr_mv);
1872 if (rc < 0) {
1873 pr_err("Error in setting recharge voltage, rc=%d\n",
1874 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001875 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001876 }
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07001877
1878 /*
1879 * If charge_done is still set, wait for recharging or
1880 * discharging to happen.
1881 */
1882 if (chip->charge_done)
1883 goto out;
1884
1885 rc = fg_configure_full_soc(chip, bsoc);
1886 if (rc < 0)
1887 goto out;
1888
1889 chip->charge_full = false;
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301890 fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
1891 msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001892 }
1893
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001894out:
1895 mutex_unlock(&chip->charge_full_lock);
1896 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001897}
1898
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001899#define RCONN_CONFIG_BIT BIT(0)
1900static int fg_rconn_config(struct fg_chip *chip)
1901{
1902 int rc, esr_uohms;
1903 u64 scaling_factor;
1904 u32 val = 0;
1905
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07001906 if (!chip->dt.rconn_mohms)
1907 return 0;
1908
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001909 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
1910 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1911 if (rc < 0) {
1912 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
1913 return rc;
1914 }
1915
1916 if (val & RCONN_CONFIG_BIT) {
1917 fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
1918 return 0;
1919 }
1920
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08001921 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001922 if (rc < 0) {
1923 pr_err("failed to get ESR, rc=%d\n", rc);
1924 return rc;
1925 }
1926
1927 scaling_factor = div64_u64((u64)esr_uohms * 1000,
1928 esr_uohms + (chip->dt.rconn_mohms * 1000));
1929
1930 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
1931 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1932 if (rc < 0) {
1933 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1934 return rc;
1935 }
1936
1937 val *= scaling_factor;
1938 do_div(val, 1000);
1939 rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
1940 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1941 if (rc < 0) {
1942 pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1943 return rc;
1944 }
1945 fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
1946
1947 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
1948 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1949 if (rc < 0) {
1950 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1951 return rc;
1952 }
1953
1954 val *= scaling_factor;
1955 do_div(val, 1000);
1956 rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
1957 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1958 if (rc < 0) {
1959 pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1960 return rc;
1961 }
1962 fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
1963 val & 0xFF);
1964
1965 val = RCONN_CONFIG_BIT;
1966 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
1967 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1968 if (rc < 0) {
1969 pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
1970 return rc;
1971 }
1972
1973 return 0;
1974}
1975
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07001976static int fg_set_jeita_threshold(struct fg_chip *chip,
1977 enum jeita_levels level, int temp_decidegC)
1978{
1979 int rc;
1980 u8 val;
1981 u16 reg;
1982
1983 if (temp_decidegC < -300 || temp_decidegC > 970)
1984 return -EINVAL;
1985
1986 /* Resolution is 0.5C. Base is -30C. */
1987 val = DIV_ROUND_CLOSEST(((temp_decidegC / 10) + 30) * 10, 5);
1988 switch (level) {
1989 case JEITA_COLD:
1990 reg = BATT_INFO_JEITA_TOO_COLD(chip);
1991 break;
1992 case JEITA_COOL:
1993 reg = BATT_INFO_JEITA_COLD(chip);
1994 break;
1995 case JEITA_WARM:
1996 reg = BATT_INFO_JEITA_HOT(chip);
1997 break;
1998 case JEITA_HOT:
1999 reg = BATT_INFO_JEITA_TOO_HOT(chip);
2000 break;
2001 default:
2002 return -EINVAL;
2003 }
2004
2005 rc = fg_write(chip, reg, &val, 1);
2006 if (rc < 0) {
2007 pr_err("Error in setting jeita level %d, rc=%d\n", level, rc);
2008 return rc;
2009 }
2010
2011 return 0;
2012}
2013
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08002014static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
2015{
2016 u8 buf[2];
2017 int rc;
2018
2019 if (volt_uv <= 0 || volt_uv > 15590000) {
2020 pr_err("Invalid voltage %d\n", volt_uv);
2021 return -EINVAL;
2022 }
2023
2024 fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
2025
2026 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
2027 chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
2028 chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
2029 if (rc < 0) {
2030 pr_err("Error in writing vbatt_full, rc=%d\n", rc);
2031 return rc;
2032 }
2033
2034 return 0;
2035}
2036
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002037static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
2038{
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002039 u8 buf;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002040 int rc;
2041
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002042 if (!chip->dt.auto_recharge_soc)
2043 return 0;
2044
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002045 if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY)
2046 return 0;
2047
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002048 fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002049 rc = fg_sram_write(chip,
2050 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002051 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002052 chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
2053 if (rc < 0) {
2054 pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
2055 return rc;
2056 }
2057
2058 return 0;
2059}
2060
2061static int fg_adjust_recharge_soc(struct fg_chip *chip)
2062{
2063 int rc, msoc, recharge_soc, new_recharge_soc = 0;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002064 bool recharge_soc_status;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002065
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002066 if (!chip->dt.auto_recharge_soc)
2067 return 0;
2068
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002069 recharge_soc = chip->dt.recharge_soc_thr;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002070 recharge_soc_status = chip->recharge_soc_adjusted;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002071 /*
2072 * If the input is present and charging had been terminated, adjust
2073 * the recharge SOC threshold based on the monotonic SOC at which
2074 * the charge termination had happened.
2075 */
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002076 if (is_input_present(chip)) {
2077 if (chip->charge_done) {
2078 if (!chip->recharge_soc_adjusted) {
2079 /* Get raw monotonic SOC for calculation */
2080 rc = fg_get_msoc(chip, &msoc);
2081 if (rc < 0) {
2082 pr_err("Error in getting msoc, rc=%d\n",
2083 rc);
2084 return rc;
2085 }
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002086
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002087 /* Adjust the recharge_soc threshold */
2088 new_recharge_soc = msoc - (FULL_CAPACITY -
2089 recharge_soc);
2090 chip->recharge_soc_adjusted = true;
2091 } else {
2092 /* adjusted already, do nothing */
2093 return 0;
2094 }
2095 } else {
2096 /* Charging, do nothing */
2097 return 0;
2098 }
2099 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002100 /* Restore the default value */
2101 new_recharge_soc = recharge_soc;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002102 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002103 }
2104
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002105 rc = fg_set_recharge_soc(chip, new_recharge_soc);
2106 if (rc < 0) {
2107 chip->recharge_soc_adjusted = recharge_soc_status;
2108 pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
2109 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002110 }
2111
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002112 fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002113 return 0;
2114}
2115
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07002116static int fg_adjust_recharge_voltage(struct fg_chip *chip)
2117{
2118 int rc, recharge_volt_mv;
2119
2120 if (chip->dt.auto_recharge_soc)
2121 return 0;
2122
2123 fg_dbg(chip, FG_STATUS, "health: %d chg_status: %d chg_done: %d\n",
2124 chip->health, chip->charge_status, chip->charge_done);
2125
2126 recharge_volt_mv = chip->dt.recharge_volt_thr_mv;
2127
2128 /* Lower the recharge voltage in soft JEITA */
2129 if (chip->health == POWER_SUPPLY_HEALTH_WARM ||
2130 chip->health == POWER_SUPPLY_HEALTH_COOL)
2131 recharge_volt_mv -= 200;
2132
2133 rc = fg_set_recharge_voltage(chip, recharge_volt_mv);
2134 if (rc < 0) {
2135 pr_err("Error in setting recharge_voltage, rc=%d\n",
2136 rc);
2137 return rc;
2138 }
2139
2140 return 0;
2141}
2142
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002143static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
2144{
2145 enum slope_limit_status status;
2146 int rc;
2147 u8 buf;
2148
2149 if (!chip->slope_limit_en)
2150 return 0;
2151
2152 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
2153 chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
2154 if (batt_temp < chip->dt.slope_limit_temp)
2155 status = LOW_TEMP_CHARGE;
2156 else
2157 status = HIGH_TEMP_CHARGE;
2158 } else {
2159 if (batt_temp < chip->dt.slope_limit_temp)
2160 status = LOW_TEMP_DISCHARGE;
2161 else
2162 status = HIGH_TEMP_DISCHARGE;
2163 }
2164
2165 if (chip->slope_limit_sts == status)
2166 return 0;
2167
2168 fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
2169 chip->dt.slope_limit_coeffs[status], &buf);
2170 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
2171 chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
2172 chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
2173 if (rc < 0) {
2174 pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
2175 rc);
2176 return rc;
2177 }
2178
2179 chip->slope_limit_sts = status;
2180 fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
2181 buf);
2182 return 0;
2183}
2184
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002185static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
2186{
2187 u8 esr_tight_lt_flt, esr_broad_lt_flt;
2188 bool cold_temp = false;
2189 int rc;
2190
2191 /*
2192 * If the battery temperature is lower than -20 C, then skip modifying
2193 * ESR filter.
2194 */
2195 if (batt_temp < -210)
2196 return 0;
2197
2198 /*
2199 * If battery temperature is lesser than 10 C (default), then apply the
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002200 * ESR low temperature tight and broad filter values to ESR room
2201 * temperature tight and broad filters. If battery temperature is higher
2202 * than 10 C, then apply back the room temperature ESR filter
2203 * coefficients to ESR room temperature tight and broad filters.
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002204 */
2205 if (batt_temp > chip->dt.esr_flt_switch_temp
2206 && chip->esr_flt_cold_temp_en) {
2207 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002208 chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
2209 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
2210 chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002211 } else if (batt_temp <= chip->dt.esr_flt_switch_temp
2212 && !chip->esr_flt_cold_temp_en) {
2213 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
2214 chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
2215 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
2216 chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002217 cold_temp = true;
2218 } else {
2219 return 0;
2220 }
2221
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002222 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
2223 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
2224 &esr_tight_lt_flt,
2225 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002226 if (rc < 0) {
2227 pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
2228 return rc;
2229 }
2230
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002231 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
2232 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
2233 &esr_broad_lt_flt,
2234 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002235 if (rc < 0) {
2236 pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
2237 return rc;
2238 }
2239
2240 chip->esr_flt_cold_temp_en = cold_temp;
2241 fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n",
2242 cold_temp ? "cold" : "normal");
2243 return 0;
2244}
2245
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002246static int fg_esr_fcc_config(struct fg_chip *chip)
2247{
2248 union power_supply_propval prop = {0, };
2249 int rc;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002250 bool parallel_en = false, qnovo_en;
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002251
2252 if (is_parallel_charger_available(chip)) {
2253 rc = power_supply_get_property(chip->parallel_psy,
2254 POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop);
2255 if (rc < 0) {
2256 pr_err("Error in reading charging_enabled from parallel_psy, rc=%d\n",
2257 rc);
2258 return rc;
2259 }
2260 parallel_en = prop.intval;
2261 }
2262
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002263 qnovo_en = is_qnovo_en(chip);
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002264
2265 fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
2266 chip->charge_status, parallel_en, qnovo_en,
2267 chip->esr_fcc_ctrl_en);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002268
Nicholas Troast1769fd32016-09-07 09:20:58 -07002269 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002270 (parallel_en || qnovo_en)) {
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002271 if (chip->esr_fcc_ctrl_en)
2272 return 0;
2273
2274 /*
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002275 * When parallel charging or Qnovo is enabled, configure ESR
2276 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
2277 * request the main charger to increase FCC when it is supposed
2278 * to decrease it.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002279 */
2280 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2281 ESR_FAST_CRG_IVAL_MASK |
2282 ESR_FAST_CRG_CTL_EN_BIT,
2283 ESR_FCC_300MA | ESR_FAST_CRG_CTL_EN_BIT);
2284 if (rc < 0) {
2285 pr_err("Error in writing to %04x, rc=%d\n",
2286 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2287 return rc;
2288 }
2289
2290 chip->esr_fcc_ctrl_en = true;
2291 } else {
2292 if (!chip->esr_fcc_ctrl_en)
2293 return 0;
2294
2295 /*
2296 * If we're here, then it means either the device is not in
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002297 * charging state or parallel charging / Qnovo is disabled.
2298 * Disable ESR fast charge current control in SW.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002299 */
2300 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2301 ESR_FAST_CRG_CTL_EN_BIT, 0);
2302 if (rc < 0) {
2303 pr_err("Error in writing to %04x, rc=%d\n",
2304 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2305 return rc;
2306 }
2307
2308 chip->esr_fcc_ctrl_en = false;
2309 }
2310
2311 fg_dbg(chip, FG_STATUS, "esr_fcc_ctrl_en set to %d\n",
2312 chip->esr_fcc_ctrl_en);
2313 return 0;
2314}
2315
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002316static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
2317{
2318 int rc, cycles_init, cycles_max;
2319 bool end_of_charge = false;
2320
2321 end_of_charge = is_input_present(chip) && chip->charge_done;
2322 fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
2323
2324 /* ESR discharging timer configuration */
2325 cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
2326 chip->dt.esr_timer_awake[TIMER_RETRY];
2327 if (end_of_charge)
2328 cycles_init = 0;
2329
2330 cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
2331 chip->dt.esr_timer_awake[TIMER_MAX];
2332
2333 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
2334 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2335 if (rc < 0) {
2336 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2337 return rc;
2338 }
2339
2340 /* ESR charging timer configuration */
2341 cycles_init = cycles_max = -EINVAL;
2342 if (end_of_charge || sleep) {
2343 cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
2344 cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
2345 } else if (is_input_present(chip)) {
2346 cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
2347 cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
2348 }
2349
2350 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
2351 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2352 if (rc < 0) {
2353 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2354 return rc;
2355 }
2356
2357 return 0;
2358}
2359
Nicholas Troast805c2422017-07-06 14:53:46 -07002360static void fg_ttf_update(struct fg_chip *chip)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002361{
Nicholas Troast805c2422017-07-06 14:53:46 -07002362 int rc;
2363 int delay_ms;
2364 union power_supply_propval prop = {0, };
2365 int online = 0;
2366
2367 if (usb_psy_initialized(chip)) {
2368 rc = power_supply_get_property(chip->usb_psy,
2369 POWER_SUPPLY_PROP_ONLINE, &prop);
2370 if (rc < 0) {
2371 pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
2372 return;
2373 }
2374
2375 online = online || prop.intval;
2376 }
2377
2378 if (pc_port_psy_initialized(chip)) {
2379 rc = power_supply_get_property(chip->pc_port_psy,
2380 POWER_SUPPLY_PROP_ONLINE, &prop);
2381 if (rc < 0) {
2382 pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
2383 return;
2384 }
2385
2386 online = online || prop.intval;
2387 }
2388
2389 if (dc_psy_initialized(chip)) {
2390 rc = power_supply_get_property(chip->dc_psy,
2391 POWER_SUPPLY_PROP_ONLINE, &prop);
2392 if (rc < 0) {
2393 pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
2394 return;
2395 }
2396
2397 online = online || prop.intval;
2398 }
2399
2400
2401 if (chip->online_status == online)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002402 return;
2403
Nicholas Troast805c2422017-07-06 14:53:46 -07002404 chip->online_status = online;
2405 if (online)
2406 /* wait 35 seconds for the input to settle */
2407 delay_ms = 35000;
2408 else
2409 /* wait 5 seconds for current to settle during discharge */
2410 delay_ms = 5000;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002411
Nicholas Troast805c2422017-07-06 14:53:46 -07002412 vote(chip->awake_votable, TTF_PRIMING, true, 0);
2413 cancel_delayed_work_sync(&chip->ttf_work);
2414 mutex_lock(&chip->ttf.lock);
2415 fg_circ_buf_clr(&chip->ttf.ibatt);
2416 fg_circ_buf_clr(&chip->ttf.vbatt);
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07002417 chip->ttf.last_ttf = 0;
2418 chip->ttf.last_ms = 0;
Nicholas Troast805c2422017-07-06 14:53:46 -07002419 mutex_unlock(&chip->ttf.lock);
2420 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
Nicholas Troast1769fd32016-09-07 09:20:58 -07002421}
2422
Nicholas Troaste29dec92016-08-24 09:35:11 -07002423static void restore_cycle_counter(struct fg_chip *chip)
2424{
2425 int rc = 0, i;
2426 u8 data[2];
2427
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002428 if (!chip->cyc_ctr.en)
2429 return;
2430
Nicholas Troaste29dec92016-08-24 09:35:11 -07002431 mutex_lock(&chip->cyc_ctr.lock);
2432 for (i = 0; i < BUCKET_COUNT; i++) {
2433 rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
2434 CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
2435 FG_IMA_DEFAULT);
2436 if (rc < 0)
2437 pr_err("failed to read bucket %d rc=%d\n", i, rc);
2438 else
2439 chip->cyc_ctr.count[i] = data[0] | data[1] << 8;
2440 }
2441 mutex_unlock(&chip->cyc_ctr.lock);
2442}
2443
2444static void clear_cycle_counter(struct fg_chip *chip)
2445{
2446 int rc = 0, i;
2447
2448 if (!chip->cyc_ctr.en)
2449 return;
2450
2451 mutex_lock(&chip->cyc_ctr.lock);
2452 memset(chip->cyc_ctr.count, 0, sizeof(chip->cyc_ctr.count));
2453 for (i = 0; i < BUCKET_COUNT; i++) {
2454 chip->cyc_ctr.started[i] = false;
2455 chip->cyc_ctr.last_soc[i] = 0;
2456 }
2457 rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET,
2458 (u8 *)&chip->cyc_ctr.count,
2459 sizeof(chip->cyc_ctr.count) / sizeof(u8 *),
2460 FG_IMA_DEFAULT);
2461 if (rc < 0)
2462 pr_err("failed to clear cycle counter rc=%d\n", rc);
2463
2464 mutex_unlock(&chip->cyc_ctr.lock);
2465}
2466
2467static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
2468{
2469 int rc = 0;
2470 u16 cyc_count;
2471 u8 data[2];
2472
2473 if (bucket < 0 || (bucket > BUCKET_COUNT - 1))
2474 return 0;
2475
2476 cyc_count = chip->cyc_ctr.count[bucket];
2477 cyc_count++;
2478 data[0] = cyc_count & 0xFF;
2479 data[1] = cyc_count >> 8;
2480
2481 rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
2482 CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
2483 FG_IMA_DEFAULT);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002484 if (rc < 0) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002485 pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
2486 bucket, rc);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002487 return rc;
2488 }
2489
2490 chip->cyc_ctr.count[bucket] = cyc_count;
2491 fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
2492 bucket);
2493
Nicholas Troaste29dec92016-08-24 09:35:11 -07002494 return rc;
2495}
2496
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002497static void fg_cycle_counter_update(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07002498{
2499 int rc = 0, bucket, i, batt_soc;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002500
2501 if (!chip->cyc_ctr.en)
2502 return;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002503
2504 mutex_lock(&chip->cyc_ctr.lock);
2505 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
2506 if (rc < 0) {
2507 pr_err("Failed to read battery soc rc: %d\n", rc);
2508 goto out;
2509 }
2510
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002511 /* We need only the most significant byte here */
2512 batt_soc = (u32)batt_soc >> 24;
2513
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002514 /* Find out which bucket the SOC falls in */
2515 bucket = batt_soc / BUCKET_SOC_PCT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002516
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002517 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002518 if (!chip->cyc_ctr.started[bucket]) {
2519 chip->cyc_ctr.started[bucket] = true;
2520 chip->cyc_ctr.last_soc[bucket] = batt_soc;
2521 }
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002522 } else if (chip->charge_done || !is_input_present(chip)) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002523 for (i = 0; i < BUCKET_COUNT; i++) {
2524 if (chip->cyc_ctr.started[i] &&
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002525 batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002526 rc = fg_inc_store_cycle_ctr(chip, i);
2527 if (rc < 0)
2528 pr_err("Error in storing cycle_ctr rc: %d\n",
2529 rc);
2530 chip->cyc_ctr.last_soc[i] = 0;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002531 chip->cyc_ctr.started[i] = false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002532 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002533 }
2534 }
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002535
2536 fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
2537 batt_soc, bucket, chip->charge_status);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002538out:
2539 mutex_unlock(&chip->cyc_ctr.lock);
2540}
2541
2542static int fg_get_cycle_count(struct fg_chip *chip)
2543{
2544 int count;
2545
2546 if (!chip->cyc_ctr.en)
2547 return 0;
2548
2549 if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT))
2550 return -EINVAL;
2551
2552 mutex_lock(&chip->cyc_ctr.lock);
2553 count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1];
2554 mutex_unlock(&chip->cyc_ctr.lock);
2555 return count;
2556}
2557
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002558static void status_change_work(struct work_struct *work)
2559{
2560 struct fg_chip *chip = container_of(work,
2561 struct fg_chip, status_change_work);
2562 union power_supply_propval prop = {0, };
2563 int rc, batt_temp;
2564
2565 if (!batt_psy_initialized(chip)) {
2566 fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
2567 goto out;
2568 }
2569
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08002570 if (!chip->soc_reporting_ready) {
2571 fg_dbg(chip, FG_STATUS, "Profile load is not complete yet\n");
2572 goto out;
2573 }
2574
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002575 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
2576 &prop);
2577 if (rc < 0) {
2578 pr_err("Error in getting charging status, rc=%d\n", rc);
2579 goto out;
2580 }
2581
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002582 chip->charge_status = prop.intval;
2583 rc = power_supply_get_property(chip->batt_psy,
2584 POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
2585 if (rc < 0) {
2586 pr_err("Error in getting charge type, rc=%d\n", rc);
2587 goto out;
2588 }
2589
2590 chip->charge_type = prop.intval;
2591 rc = power_supply_get_property(chip->batt_psy,
2592 POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
2593 if (rc < 0) {
2594 pr_err("Error in getting charge_done, rc=%d\n", rc);
2595 goto out;
2596 }
2597
2598 chip->charge_done = prop.intval;
2599 fg_cycle_counter_update(chip);
2600 fg_cap_learning_update(chip);
2601
2602 rc = fg_charge_full_update(chip);
2603 if (rc < 0)
2604 pr_err("Error in charge_full_update, rc=%d\n", rc);
2605
2606 rc = fg_adjust_recharge_soc(chip);
2607 if (rc < 0)
2608 pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
2609
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07002610 rc = fg_adjust_recharge_voltage(chip);
2611 if (rc < 0)
2612 pr_err("Error in adjusting recharge_voltage, rc=%d\n", rc);
2613
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002614 rc = fg_adjust_ki_coeff_dischg(chip);
2615 if (rc < 0)
2616 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
2617
2618 rc = fg_esr_fcc_config(chip);
2619 if (rc < 0)
2620 pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
2621
2622 rc = fg_get_battery_temp(chip, &batt_temp);
2623 if (!rc) {
2624 rc = fg_slope_limit_config(chip, batt_temp);
2625 if (rc < 0)
2626 pr_err("Error in configuring slope limiter rc:%d\n",
2627 rc);
2628
2629 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
2630 if (rc < 0)
2631 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
2632 rc);
2633 }
2634
2635 fg_ttf_update(chip);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07002636 chip->prev_charge_status = chip->charge_status;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002637out:
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08002638 fg_dbg(chip, FG_STATUS, "charge_status:%d charge_type:%d charge_done:%d\n",
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002639 chip->charge_status, chip->charge_type, chip->charge_done);
2640 pm_relax(chip->dev);
2641}
2642
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002643static int fg_bp_params_config(struct fg_chip *chip)
2644{
2645 int rc = 0;
2646 u8 buf;
2647
2648 /* This SRAM register is only present in v2.0 and above */
2649 if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
2650 chip->bp.float_volt_uv > 0) {
2651 fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
2652 chip->bp.float_volt_uv / 1000, &buf);
2653 rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
2654 chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
2655 chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
2656 if (rc < 0) {
2657 pr_err("Error in writing float_volt, rc=%d\n", rc);
2658 return rc;
2659 }
2660 }
2661
2662 if (chip->bp.vbatt_full_mv > 0) {
2663 rc = fg_set_constant_chg_voltage(chip,
2664 chip->bp.vbatt_full_mv * 1000);
2665 if (rc < 0)
2666 return rc;
2667 }
2668
2669 return rc;
2670}
2671
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002672#define PROFILE_LOAD_BIT BIT(0)
2673#define BOOTLOADER_LOAD_BIT BIT(1)
2674#define BOOTLOADER_RESTART_BIT BIT(2)
2675#define HLOS_RESTART_BIT BIT(3)
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002676static bool is_profile_load_required(struct fg_chip *chip)
2677{
Nicholas Troaste29dec92016-08-24 09:35:11 -07002678 u8 buf[PROFILE_COMP_LEN], val;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002679 bool profiles_same = false;
2680 int rc;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002681
Nicholas Troaste29dec92016-08-24 09:35:11 -07002682 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
2683 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2684 if (rc < 0) {
2685 pr_err("failed to read profile integrity rc=%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002686 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002687 }
2688
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002689 /* Check if integrity bit is set */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002690 if (val & PROFILE_LOAD_BIT) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002691 fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
Subbaraman Narayanamurthy73616e12017-03-20 14:37:54 -07002692
2693 /* Whitelist the values */
2694 val &= ~PROFILE_LOAD_BIT;
2695 if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
2696 val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
2697 val |= PROFILE_LOAD_BIT;
2698 pr_warn("Garbage value in profile integrity word: 0x%x\n",
2699 val);
2700 return true;
2701 }
2702
Nicholas Troaste29dec92016-08-24 09:35:11 -07002703 rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2704 buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
2705 if (rc < 0) {
2706 pr_err("Error in reading battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002707 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002708 }
2709 profiles_same = memcmp(chip->batt_profile, buf,
2710 PROFILE_COMP_LEN) == 0;
2711 if (profiles_same) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002712 fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
2713 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002714 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002715
2716 if (!chip->dt.force_load_profile) {
2717 pr_warn("Profiles doesn't match, skipping loading it since force_load_profile is disabled\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002718 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002719 pr_info("FG: loaded profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002720 dump_sram(buf, PROFILE_LOAD_WORD,
2721 PROFILE_COMP_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002722 pr_info("FG: available profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002723 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2724 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002725 }
2726 return false;
2727 }
2728
2729 fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n");
2730 } else {
2731 fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002732 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002733 pr_info("FG: profile to be loaded:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002734 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2735 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002736 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002737 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002738 return true;
2739}
2740
Subbaraman Narayanamurthy35051a22017-11-10 15:37:29 -08002741static void fg_update_batt_profile(struct fg_chip *chip)
2742{
2743 int rc, offset;
2744 u8 val;
2745
2746 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
2747 SW_CONFIG_OFFSET, &val, 1, FG_IMA_DEFAULT);
2748 if (rc < 0) {
2749 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
2750 return;
2751 }
2752
2753 /*
2754 * If the RCONN had not been updated, no need to update battery
2755 * profile. Else, update the battery profile so that the profile
2756 * modified by bootloader or HLOS matches with the profile read
2757 * from device tree.
2758 */
2759
2760 if (!(val & RCONN_CONFIG_BIT))
2761 return;
2762
2763 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
2764 ESR_RSLOW_CHG_OFFSET, &val, 1, FG_IMA_DEFAULT);
2765 if (rc < 0) {
2766 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
2767 return;
2768 }
2769 offset = (ESR_RSLOW_CHG_WORD - PROFILE_LOAD_WORD) * 4
2770 + ESR_RSLOW_CHG_OFFSET;
2771 chip->batt_profile[offset] = val;
2772
2773 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
2774 ESR_RSLOW_DISCHG_OFFSET, &val, 1, FG_IMA_DEFAULT);
2775 if (rc < 0) {
2776 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
2777 return;
2778 }
2779 offset = (ESR_RSLOW_DISCHG_WORD - PROFILE_LOAD_WORD) * 4
2780 + ESR_RSLOW_DISCHG_OFFSET;
2781 chip->batt_profile[offset] = val;
2782}
2783
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08002784static void clear_battery_profile(struct fg_chip *chip)
2785{
2786 u8 val = 0;
2787 int rc;
2788
2789 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2790 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2791 if (rc < 0)
2792 pr_err("failed to write profile integrity rc=%d\n", rc);
2793}
2794
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002795#define SOC_READY_WAIT_MS 2000
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002796static int __fg_restart(struct fg_chip *chip)
2797{
2798 int rc, msoc;
2799 bool tried_again = false;
2800
2801 rc = fg_get_prop_capacity(chip, &msoc);
2802 if (rc < 0) {
2803 pr_err("Error in getting capacity, rc=%d\n", rc);
2804 return rc;
2805 }
2806
2807 chip->last_soc = msoc;
2808 chip->fg_restarting = true;
2809 reinit_completion(&chip->soc_ready);
2810 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT,
2811 RESTART_GO_BIT);
2812 if (rc < 0) {
2813 pr_err("Error in writing to %04x, rc=%d\n",
2814 BATT_SOC_RESTART(chip), rc);
2815 goto out;
2816 }
2817
2818wait:
2819 rc = wait_for_completion_interruptible_timeout(&chip->soc_ready,
2820 msecs_to_jiffies(SOC_READY_WAIT_MS));
2821
2822 /* If we were interrupted wait again one more time. */
2823 if (rc == -ERESTARTSYS && !tried_again) {
2824 tried_again = true;
2825 goto wait;
2826 } else if (rc <= 0) {
2827 pr_err("wait for soc_ready timed out rc=%d\n", rc);
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002828 }
2829
2830 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2831 if (rc < 0) {
2832 pr_err("Error in writing to %04x, rc=%d\n",
2833 BATT_SOC_RESTART(chip), rc);
2834 goto out;
2835 }
2836out:
2837 chip->fg_restarting = false;
2838 return rc;
2839}
2840
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07002841static void pl_enable_work(struct work_struct *work)
2842{
2843 struct fg_chip *chip = container_of(work,
2844 struct fg_chip,
2845 pl_enable_work.work);
2846
2847 vote(chip->pl_disable_votable, ESR_FCC_VOTER, false, 0);
2848 vote(chip->awake_votable, ESR_FCC_VOTER, false, 0);
2849}
2850
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002851static void profile_load_work(struct work_struct *work)
2852{
2853 struct fg_chip *chip = container_of(work,
2854 struct fg_chip,
2855 profile_load_work.work);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002856 u8 buf[2], val;
2857 int rc;
2858
2859 vote(chip->awake_votable, PROFILE_LOAD, true, 0);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07002860
2861 rc = fg_get_batt_id(chip);
2862 if (rc < 0) {
2863 pr_err("Error in getting battery id, rc:%d\n", rc);
2864 goto out;
2865 }
2866
2867 rc = fg_get_batt_profile(chip);
2868 if (rc < 0) {
2869 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
2870 chip->batt_id_ohms / 1000, rc);
2871 goto out;
2872 }
2873
2874 if (!chip->profile_available)
2875 goto out;
2876
Subbaraman Narayanamurthy35051a22017-11-10 15:37:29 -08002877 fg_update_batt_profile(chip);
2878
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002879 if (!is_profile_load_required(chip))
2880 goto done;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002881
2882 clear_cycle_counter(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002883 mutex_lock(&chip->cl.lock);
2884 chip->cl.learned_cc_uah = 0;
2885 chip->cl.active = false;
2886 mutex_unlock(&chip->cl.lock);
2887
Nicholas Troaste29dec92016-08-24 09:35:11 -07002888 fg_dbg(chip, FG_STATUS, "profile loading started\n");
2889 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2890 if (rc < 0) {
2891 pr_err("Error in writing to %04x, rc=%d\n",
2892 BATT_SOC_RESTART(chip), rc);
2893 goto out;
2894 }
2895
2896 /* load battery profile */
2897 rc = fg_sram_write(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2898 chip->batt_profile, PROFILE_LEN, FG_IMA_ATOMIC);
2899 if (rc < 0) {
2900 pr_err("Error in writing battery profile, rc:%d\n", rc);
2901 goto out;
2902 }
2903
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002904 rc = __fg_restart(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002905 if (rc < 0) {
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002906 pr_err("Error in restarting FG, rc=%d\n", rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002907 goto out;
2908 }
2909
2910 fg_dbg(chip, FG_STATUS, "SOC is ready\n");
2911
2912 /* Set the profile integrity bit */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002913 val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002914 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2915 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2916 if (rc < 0) {
2917 pr_err("failed to write profile integrity rc=%d\n", rc);
2918 goto out;
2919 }
2920
Nicholas Troaste29dec92016-08-24 09:35:11 -07002921done:
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002922 rc = fg_bp_params_config(chip);
2923 if (rc < 0)
2924 pr_err("Error in configuring battery profile params, rc:%d\n",
2925 rc);
2926
Nicholas Troaste29dec92016-08-24 09:35:11 -07002927 rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
2928 FG_IMA_DEFAULT);
2929 if (rc < 0) {
2930 pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD,
2931 NOM_CAP_OFFSET, rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002932 } else {
2933 chip->cl.nom_cap_uah = (int)(buf[0] | buf[1] << 8) * 1000;
2934 rc = fg_load_learned_cap_from_sram(chip);
2935 if (rc < 0)
2936 pr_err("Error in loading capacity learning data, rc:%d\n",
2937 rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002938 }
2939
Subbaraman Narayanamurthy35051a22017-11-10 15:37:29 -08002940 rc = fg_rconn_config(chip);
2941 if (rc < 0)
2942 pr_err("Error in configuring Rconn, rc=%d\n", rc);
2943
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002944 batt_psy_initialized(chip);
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07002945 fg_notify_charger(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002946 chip->profile_loaded = true;
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002947 fg_dbg(chip, FG_STATUS, "profile loaded successfully");
Nicholas Troaste29dec92016-08-24 09:35:11 -07002948out:
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07002949 chip->soc_reporting_ready = true;
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07002950 vote(chip->awake_votable, ESR_FCC_VOTER, true, 0);
2951 schedule_delayed_work(&chip->pl_enable_work, msecs_to_jiffies(5000));
Nicholas Troaste29dec92016-08-24 09:35:11 -07002952 vote(chip->awake_votable, PROFILE_LOAD, false, 0);
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08002953 if (!work_pending(&chip->status_change_work)) {
2954 pm_stay_awake(chip->dev);
2955 schedule_work(&chip->status_change_work);
2956 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002957}
2958
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002959static void sram_dump_work(struct work_struct *work)
2960{
2961 struct fg_chip *chip = container_of(work, struct fg_chip,
2962 sram_dump_work.work);
2963 u8 buf[FG_SRAM_LEN];
2964 int rc;
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302965 s64 timestamp_ms, quotient;
2966 s32 remainder;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002967
2968 rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
2969 if (rc < 0) {
2970 pr_err("Error in reading FG SRAM, rc:%d\n", rc);
2971 goto resched;
2972 }
2973
2974 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302975 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2976 fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
2977 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002978 dump_sram(buf, 0, FG_SRAM_LEN);
2979 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302980 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2981 fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
2982 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002983resched:
2984 schedule_delayed_work(&chip->sram_dump_work,
2985 msecs_to_jiffies(fg_sram_dump_period_ms));
2986}
2987
2988static int fg_sram_dump_sysfs(const char *val, const struct kernel_param *kp)
2989{
2990 int rc;
2991 struct power_supply *bms_psy;
2992 struct fg_chip *chip;
2993 bool old_val = fg_sram_dump;
2994
2995 rc = param_set_bool(val, kp);
2996 if (rc) {
2997 pr_err("Unable to set fg_sram_dump: %d\n", rc);
2998 return rc;
2999 }
3000
3001 if (fg_sram_dump == old_val)
3002 return 0;
3003
3004 bms_psy = power_supply_get_by_name("bms");
3005 if (!bms_psy) {
3006 pr_err("bms psy not found\n");
3007 return -ENODEV;
3008 }
3009
3010 chip = power_supply_get_drvdata(bms_psy);
3011 if (fg_sram_dump)
3012 schedule_delayed_work(&chip->sram_dump_work,
3013 msecs_to_jiffies(fg_sram_dump_period_ms));
3014 else
3015 cancel_delayed_work_sync(&chip->sram_dump_work);
3016
3017 return 0;
3018}
3019
3020static struct kernel_param_ops fg_sram_dump_ops = {
3021 .set = fg_sram_dump_sysfs,
3022 .get = param_get_bool,
3023};
3024
3025module_param_cb(sram_dump_en, &fg_sram_dump_ops, &fg_sram_dump, 0644);
3026
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07003027static int fg_restart_sysfs(const char *val, const struct kernel_param *kp)
3028{
3029 int rc;
3030 struct power_supply *bms_psy;
3031 struct fg_chip *chip;
3032
3033 rc = param_set_int(val, kp);
3034 if (rc) {
3035 pr_err("Unable to set fg_restart: %d\n", rc);
3036 return rc;
3037 }
3038
3039 if (fg_restart != 1) {
3040 pr_err("Bad value %d\n", fg_restart);
3041 return -EINVAL;
3042 }
3043
3044 bms_psy = power_supply_get_by_name("bms");
3045 if (!bms_psy) {
3046 pr_err("bms psy not found\n");
3047 return 0;
3048 }
3049
3050 chip = power_supply_get_drvdata(bms_psy);
3051 rc = __fg_restart(chip);
3052 if (rc < 0) {
3053 pr_err("Error in restarting FG, rc=%d\n", rc);
3054 return rc;
3055 }
3056
3057 pr_info("FG restart done\n");
3058 return rc;
3059}
3060
3061static struct kernel_param_ops fg_restart_ops = {
3062 .set = fg_restart_sysfs,
3063 .get = param_get_int,
3064};
3065
3066module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
3067
Nicholas Troast1769fd32016-09-07 09:20:58 -07003068#define HOURS_TO_SECONDS 3600
3069#define OCV_SLOPE_UV 10869
3070#define MILLI_UNIT 1000
3071#define MICRO_UNIT 1000000
Nicholas Troast805c2422017-07-06 14:53:46 -07003072#define NANO_UNIT 1000000000
3073static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
Nicholas Troast1769fd32016-09-07 09:20:58 -07003074{
Nicholas Troast805c2422017-07-06 14:53:46 -07003075 int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003076 i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
3077 i, soc_per_step, msoc_this_step, msoc_next_step,
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003078 ibatt_this_step, t_predicted_this_step, ttf_slope,
Nicholas Troast805c2422017-07-06 14:53:46 -07003079 t_predicted_cv, t_predicted = 0;
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003080 s64 delta_ms;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003081
Subbaraman Narayanamurthy476e8372017-08-25 13:38:36 -07003082 if (!chip->soc_reporting_ready)
3083 return -ENODATA;
3084
Nicholas Troast1769fd32016-09-07 09:20:58 -07003085 if (chip->bp.float_volt_uv <= 0) {
3086 pr_err("battery profile is not loaded\n");
3087 return -ENODATA;
3088 }
3089
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003090 if (!batt_psy_initialized(chip)) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07003091 fg_dbg(chip, FG_TTF, "charger is not available\n");
3092 return -ENODATA;
3093 }
3094
Nicholas Troast32a22d32016-12-14 16:12:04 -08003095 rc = fg_get_prop_capacity(chip, &msoc);
3096 if (rc < 0) {
3097 pr_err("failed to get msoc rc=%d\n", rc);
3098 return rc;
3099 }
3100 fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
3101
Nicholas Troast805c2422017-07-06 14:53:46 -07003102 /* the battery is considered full if the SOC is 100% */
Nicholas Troast32a22d32016-12-14 16:12:04 -08003103 if (msoc >= 100) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07003104 *val = 0;
3105 return 0;
3106 }
3107
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003108 if (is_qnovo_en(chip))
3109 ttf_mode = TTF_MODE_QNOVO;
3110 else
3111 ttf_mode = TTF_MODE_NORMAL;
3112
3113 /* when switching TTF algorithms the TTF needs to be reset */
3114 if (chip->ttf.mode != ttf_mode) {
3115 fg_circ_buf_clr(&chip->ttf.ibatt);
3116 fg_circ_buf_clr(&chip->ttf.vbatt);
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003117 chip->ttf.last_ttf = 0;
3118 chip->ttf.last_ms = 0;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003119 chip->ttf.mode = ttf_mode;
3120 }
3121
Nicholas Troast805c2422017-07-06 14:53:46 -07003122 /* at least 10 samples are required to produce a stable IBATT */
3123 if (chip->ttf.ibatt.size < 10) {
3124 *val = -1;
3125 return 0;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003126 }
3127
Nicholas Troast805c2422017-07-06 14:53:46 -07003128 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003129 if (rc < 0) {
Nicholas Troast805c2422017-07-06 14:53:46 -07003130 pr_err("failed to get IBATT AVG rc=%d\n", rc);
3131 return rc;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003132 }
3133
Nicholas Troast805c2422017-07-06 14:53:46 -07003134 rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
3135 if (rc < 0) {
3136 pr_err("failed to get VBATT AVG rc=%d\n", rc);
3137 return rc;
3138 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003139
Nicholas Troast805c2422017-07-06 14:53:46 -07003140 ibatt_avg = -ibatt_avg / MILLI_UNIT;
3141 vbatt_avg /= MILLI_UNIT;
3142
3143 /* clamp ibatt_avg to iterm */
3144 if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
3145 ibatt_avg = abs(chip->dt.sys_term_curr_ma);
3146
Nicholas Troast1769fd32016-09-07 09:20:58 -07003147 fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
Nicholas Troast805c2422017-07-06 14:53:46 -07003148 fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003149
3150 rc = fg_get_battery_resistance(chip, &rbatt);
3151 if (rc < 0) {
3152 pr_err("failed to get battery resistance rc=%d\n", rc);
3153 return rc;
3154 }
3155
Nicholas Troast805c2422017-07-06 14:53:46 -07003156 rbatt /= MILLI_UNIT;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003157 fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
3158
Nicholas Troast805c2422017-07-06 14:53:46 -07003159 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003160 if (rc < 0) {
3161 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
3162 return rc;
3163 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003164
Nicholas Troast1769fd32016-09-07 09:20:58 -07003165 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3166 if (rc < 0) {
3167 pr_err("failed to get full soc rc=%d\n", rc);
3168 return rc;
3169 }
3170 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3171 FULL_SOC_RAW);
Nicholas Troast805c2422017-07-06 14:53:46 -07003172 act_cap_mah = full_soc * act_cap_mah / 100;
3173 fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
3174
3175 /* estimated battery current at the CC to CV transition */
3176 switch (chip->ttf.mode) {
3177 case TTF_MODE_NORMAL:
3178 i_cc2cv = ibatt_avg * vbatt_avg /
3179 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
3180 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003181 case TTF_MODE_QNOVO:
3182 i_cc2cv = min(
3183 chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
3184 ibatt_avg * vbatt_avg /
3185 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
3186 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07003187 default:
3188 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
3189 break;
3190 }
3191 fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003192
3193 /* if we are already in CV state then we can skip estimating CC */
3194 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
Nicholas Troast805c2422017-07-06 14:53:46 -07003195 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003196
Nicholas Troast1769fd32016-09-07 09:20:58 -07003197 /* estimated SOC at the CC to CV transition */
Nicholas Troast805c2422017-07-06 14:53:46 -07003198 soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003199 soc_cc2cv = 100 - soc_cc2cv;
3200 fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
3201
Nicholas Troast805c2422017-07-06 14:53:46 -07003202 switch (chip->ttf.mode) {
3203 case TTF_MODE_NORMAL:
3204 if (soc_cc2cv - msoc <= 0)
3205 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003206
Nicholas Troast805c2422017-07-06 14:53:46 -07003207 divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
3208 t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
3209 HOURS_TO_SECONDS, divisor);
3210 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003211 case TTF_MODE_QNOVO:
3212 soc_per_step = 100 / MAX_CC_STEPS;
3213 for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
3214 msoc_next_step = (i + 1) * soc_per_step;
3215 if (i == msoc / soc_per_step)
3216 msoc_this_step = msoc;
3217 else
3218 msoc_this_step = i * soc_per_step;
3219
3220 /* scale ibatt by 85% to account for discharge pulses */
3221 ibatt_this_step = min(
3222 chip->ttf.cc_step.arr[i] / MILLI_UNIT,
3223 ibatt_avg) * 85 / 100;
3224 divisor = max(100, ibatt_this_step * 100);
3225 t_predicted_this_step = div_s64((s64)act_cap_mah *
3226 (msoc_next_step - msoc_this_step) *
3227 HOURS_TO_SECONDS, divisor);
3228 t_predicted += t_predicted_this_step;
3229 fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
3230 msoc_this_step, msoc_next_step,
3231 ibatt_this_step, t_predicted_this_step);
3232 }
3233 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07003234 default:
3235 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
3236 break;
3237 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003238
Nicholas Troast805c2422017-07-06 14:53:46 -07003239cv_estimate:
3240 fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003241
Nicholas Troast805c2422017-07-06 14:53:46 -07003242 iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
3243 fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
3244
3245 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
3246 tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003247 else
Nicholas Troast805c2422017-07-06 14:53:46 -07003248 tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
Nicholas Troastde5d42f2017-01-20 16:47:31 -08003249
Nicholas Troast805c2422017-07-06 14:53:46 -07003250 rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
3251 if (rc < 0) {
3252 pr_err("failed to interpolate tau rc=%d\n", rc);
3253 return rc;
3254 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003255
Nicholas Troast805c2422017-07-06 14:53:46 -07003256 /* tau is scaled linearly from 95% to 100% SOC */
3257 if (msoc >= 95)
3258 tau = tau * 2 * (100 - msoc) / 10;
3259
3260 fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
3261 t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
3262 HOURS_TO_SECONDS, NANO_UNIT);
3263 fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
3264 t_predicted += t_predicted_cv;
3265
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003266 fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
3267 if (chip->ttf.last_ms != 0) {
3268 delta_ms = ktime_ms_delta(ktime_get_boottime(),
3269 ms_to_ktime(chip->ttf.last_ms));
3270 if (delta_ms > 10000) {
3271 ttf_slope = div64_s64(
3272 (s64)(t_predicted - chip->ttf.last_ttf) *
3273 MICRO_UNIT, delta_ms);
3274 if (ttf_slope > -100)
3275 ttf_slope = -100;
3276 else if (ttf_slope < -2000)
3277 ttf_slope = -2000;
3278
3279 t_predicted = div_s64(
3280 (s64)ttf_slope * delta_ms, MICRO_UNIT) +
3281 chip->ttf.last_ttf;
3282 fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
3283 } else {
3284 t_predicted = chip->ttf.last_ttf;
3285 }
3286 }
3287
Nicholas Troast805c2422017-07-06 14:53:46 -07003288 /* clamp the ttf to 0 */
3289 if (t_predicted < 0)
3290 t_predicted = 0;
3291
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003292 fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
Nicholas Troast805c2422017-07-06 14:53:46 -07003293 *val = t_predicted;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003294 return 0;
3295}
3296
Nicholas Troast805c2422017-07-06 14:53:46 -07003297static int fg_get_time_to_full(struct fg_chip *chip, int *val)
3298{
3299 int rc;
3300
3301 mutex_lock(&chip->ttf.lock);
3302 rc = fg_get_time_to_full_locked(chip, val);
3303 mutex_unlock(&chip->ttf.lock);
3304 return rc;
3305}
3306
Nicholas Troast1769fd32016-09-07 09:20:58 -07003307#define CENTI_ICORRECT_C0 105
3308#define CENTI_ICORRECT_C1 20
3309static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
3310{
Nicholas Troast805c2422017-07-06 14:53:46 -07003311 int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003312
Nicholas Troast805c2422017-07-06 14:53:46 -07003313 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003314 if (rc < 0) {
3315 /* try to get instantaneous current */
3316 rc = fg_get_battery_current(chip, &ibatt_avg);
3317 if (rc < 0) {
3318 pr_err("failed to get battery current, rc=%d\n", rc);
3319 return rc;
3320 }
3321 }
3322
Nicholas Troast805c2422017-07-06 14:53:46 -07003323 ibatt_avg /= MILLI_UNIT;
3324 /* clamp ibatt_avg to 100mA */
3325 if (ibatt_avg < 100)
3326 ibatt_avg = 100;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003327
3328 rc = fg_get_prop_capacity(chip, &msoc);
3329 if (rc < 0) {
3330 pr_err("Error in getting capacity, rc=%d\n", rc);
3331 return rc;
3332 }
3333
Nicholas Troast805c2422017-07-06 14:53:46 -07003334 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
3335 if (rc < 0) {
3336 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
3337 return rc;
3338 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003339
Nicholas Troast805c2422017-07-06 14:53:46 -07003340 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3341 if (rc < 0) {
3342 pr_err("failed to get full soc rc=%d\n", rc);
3343 return rc;
3344 }
3345 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3346 FULL_SOC_RAW);
3347 act_cap_mah = full_soc * act_cap_mah / 100;
3348
3349 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
3350 divisor = ibatt_avg * divisor / 100;
3351 divisor = max(100, divisor);
3352 *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003353 return 0;
3354}
3355
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003356static int fg_update_maint_soc(struct fg_chip *chip)
3357{
3358 int rc = 0, msoc;
3359
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003360 if (!chip->dt.linearize_soc)
3361 return 0;
3362
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003363 mutex_lock(&chip->charge_full_lock);
3364 if (chip->delta_soc <= 0)
3365 goto out;
3366
3367 rc = fg_get_msoc(chip, &msoc);
3368 if (rc < 0) {
3369 pr_err("Error in getting msoc, rc=%d\n", rc);
3370 goto out;
3371 }
3372
3373 if (msoc > chip->maint_soc) {
3374 /*
3375 * When the monotonic SOC goes above maintenance SOC, we should
3376 * stop showing the maintenance SOC.
3377 */
3378 chip->delta_soc = 0;
3379 chip->maint_soc = 0;
3380 } else if (msoc <= chip->last_msoc) {
3381 /* MSOC is decreasing. Decrease maintenance SOC as well */
3382 chip->maint_soc -= 1;
3383 if (!(msoc % 10)) {
3384 /*
3385 * Reduce the maintenance SOC additionally by 1 whenever
3386 * it crosses a SOC multiple of 10.
3387 */
3388 chip->maint_soc -= 1;
3389 chip->delta_soc -= 1;
3390 }
3391 }
3392
3393 fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
3394 msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
3395 chip->last_msoc = msoc;
3396out:
3397 mutex_unlock(&chip->charge_full_lock);
3398 return rc;
3399}
3400
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003401static int fg_esr_validate(struct fg_chip *chip)
3402{
3403 int rc, esr_uohms;
3404 u8 buf[2];
3405
3406 if (chip->dt.esr_clamp_mohms <= 0)
3407 return 0;
3408
3409 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
3410 if (rc < 0) {
3411 pr_err("failed to get ESR, rc=%d\n", rc);
3412 return rc;
3413 }
3414
3415 if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) {
3416 pr_debug("ESR %d is > ESR_clamp\n", esr_uohms);
3417 return 0;
3418 }
3419
3420 esr_uohms = chip->dt.esr_clamp_mohms * 1000;
3421 fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf);
3422 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word,
3423 chip->sp[FG_SRAM_ESR].addr_byte, buf,
3424 chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT);
3425 if (rc < 0) {
3426 pr_err("Error in writing ESR, rc=%d\n", rc);
3427 return rc;
3428 }
3429
3430 fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms);
3431 return 0;
3432}
3433
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003434static int fg_force_esr_meas(struct fg_chip *chip)
3435{
3436 int rc;
3437 int esr_uohms;
3438
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003439 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003440 /* force esr extraction enable */
3441 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3442 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
3443 FG_IMA_DEFAULT);
3444 if (rc < 0) {
3445 pr_err("failed to enable esr extn rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003446 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003447 }
3448
3449 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3450 LD_REG_CTRL_BIT, 0);
3451 if (rc < 0) {
3452 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003453 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003454 }
3455
3456 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3457 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3458 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
3459 if (rc < 0) {
3460 pr_err("Error in configuring force ESR rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003461 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003462 }
3463
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003464 /*
3465 * Release and grab the lock again after 1.5 seconds so that prepare
3466 * callback can succeed if the request comes in between.
3467 */
3468 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
3469
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003470 /* wait 1.5 seconds for hw to measure ESR */
3471 msleep(1500);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003472
3473 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003474 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3475 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3476 0);
3477 if (rc < 0) {
3478 pr_err("Error in restoring force ESR rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003479 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003480 }
3481
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003482 /* If qnovo is disabled, then leave ESR extraction enabled */
3483 if (!chip->qnovo_enable)
3484 goto done;
3485
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003486 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3487 LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
3488 if (rc < 0) {
3489 pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003490 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003491 }
3492
3493 /* force esr extraction disable */
3494 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3495 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0,
3496 FG_IMA_DEFAULT);
3497 if (rc < 0) {
3498 pr_err("failed to disable esr extn rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003499 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003500 }
3501
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003502done:
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003503 fg_get_battery_resistance(chip, &esr_uohms);
3504 fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003505out:
3506 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003507 return rc;
3508}
3509
3510static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
3511{
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003512 int rc = 0;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003513
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003514 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003515 /* force esr extraction disable when qnovo enables */
3516 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3517 ESR_EXTRACTION_ENABLE_OFFSET,
3518 BIT(0), qnovo_enable ? 0 : BIT(0),
3519 FG_IMA_DEFAULT);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003520 if (rc < 0) {
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003521 pr_err("Error in configuring esr extraction rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003522 goto out;
3523 }
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003524
3525 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3526 LD_REG_CTRL_BIT,
3527 qnovo_enable ? LD_REG_CTRL_BIT : 0);
3528 if (rc < 0) {
3529 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003530 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003531 }
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003532
3533 fg_dbg(chip, FG_STATUS, "%s for Qnovo\n",
3534 qnovo_enable ? "Prepared" : "Unprepared");
3535 chip->qnovo_enable = qnovo_enable;
3536out:
3537 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
3538 return rc;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003539}
Nicholas Troast805c2422017-07-06 14:53:46 -07003540
3541static void ttf_work(struct work_struct *work)
3542{
3543 struct fg_chip *chip = container_of(work, struct fg_chip,
3544 ttf_work.work);
3545 int rc, ibatt_now, vbatt_now, ttf;
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003546 ktime_t ktime_now;
Nicholas Troast805c2422017-07-06 14:53:46 -07003547
3548 mutex_lock(&chip->ttf.lock);
3549 if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
3550 chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
3551 goto end_work;
3552
3553 rc = fg_get_battery_current(chip, &ibatt_now);
3554 if (rc < 0) {
3555 pr_err("failed to get battery current, rc=%d\n", rc);
3556 goto end_work;
3557 }
3558
3559 rc = fg_get_battery_voltage(chip, &vbatt_now);
3560 if (rc < 0) {
3561 pr_err("failed to get battery voltage, rc=%d\n", rc);
3562 goto end_work;
3563 }
3564
3565 fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
3566 fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
3567
3568 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
3569 rc = fg_get_time_to_full_locked(chip, &ttf);
3570 if (rc < 0) {
3571 pr_err("failed to get ttf, rc=%d\n", rc);
3572 goto end_work;
3573 }
3574
3575 /* keep the wake lock and prime the IBATT and VBATT buffers */
3576 if (ttf < 0) {
3577 /* delay for one FG cycle */
3578 schedule_delayed_work(&chip->ttf_work,
3579 msecs_to_jiffies(1500));
3580 mutex_unlock(&chip->ttf.lock);
3581 return;
3582 }
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003583
3584 /* update the TTF reference point every minute */
3585 ktime_now = ktime_get_boottime();
3586 if (ktime_ms_delta(ktime_now,
3587 ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
3588 chip->ttf.last_ms == 0) {
3589 chip->ttf.last_ttf = ttf;
3590 chip->ttf.last_ms = ktime_to_ms(ktime_now);
3591 }
Nicholas Troast805c2422017-07-06 14:53:46 -07003592 }
3593
3594 /* recurse every 10 seconds */
3595 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
3596end_work:
3597 vote(chip->awake_votable, TTF_PRIMING, false, 0);
3598 mutex_unlock(&chip->ttf.lock);
3599}
3600
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003601/* PSY CALLBACKS STAY HERE */
3602
3603static int fg_psy_get_property(struct power_supply *psy,
3604 enum power_supply_property psp,
3605 union power_supply_propval *pval)
3606{
3607 struct fg_chip *chip = power_supply_get_drvdata(psy);
3608 int rc = 0;
3609
3610 switch (psp) {
3611 case POWER_SUPPLY_PROP_CAPACITY:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08003612 rc = fg_get_prop_capacity(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003613 break;
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003614 case POWER_SUPPLY_PROP_CAPACITY_RAW:
3615 rc = fg_get_msoc_raw(chip, &pval->intval);
3616 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003617 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08003618 if (chip->battery_missing)
3619 pval->intval = 3700000;
3620 else
3621 rc = fg_get_battery_voltage(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003622 break;
3623 case POWER_SUPPLY_PROP_CURRENT_NOW:
3624 rc = fg_get_battery_current(chip, &pval->intval);
3625 break;
3626 case POWER_SUPPLY_PROP_TEMP:
3627 rc = fg_get_battery_temp(chip, &pval->intval);
3628 break;
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003629 case POWER_SUPPLY_PROP_COLD_TEMP:
3630 rc = fg_get_jeita_threshold(chip, JEITA_COLD, &pval->intval);
3631 if (rc < 0) {
3632 pr_err("Error in reading jeita_cold, rc=%d\n", rc);
3633 return rc;
3634 }
3635 break;
3636 case POWER_SUPPLY_PROP_COOL_TEMP:
3637 rc = fg_get_jeita_threshold(chip, JEITA_COOL, &pval->intval);
3638 if (rc < 0) {
3639 pr_err("Error in reading jeita_cool, rc=%d\n", rc);
3640 return rc;
3641 }
3642 break;
3643 case POWER_SUPPLY_PROP_WARM_TEMP:
3644 rc = fg_get_jeita_threshold(chip, JEITA_WARM, &pval->intval);
3645 if (rc < 0) {
3646 pr_err("Error in reading jeita_warm, rc=%d\n", rc);
3647 return rc;
3648 }
3649 break;
3650 case POWER_SUPPLY_PROP_HOT_TEMP:
3651 rc = fg_get_jeita_threshold(chip, JEITA_HOT, &pval->intval);
3652 if (rc < 0) {
3653 pr_err("Error in reading jeita_hot, rc=%d\n", rc);
3654 return rc;
3655 }
3656 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003657 case POWER_SUPPLY_PROP_RESISTANCE:
3658 rc = fg_get_battery_resistance(chip, &pval->intval);
3659 break;
3660 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3661 rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
3662 break;
3663 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003664 pval->intval = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003665 break;
3666 case POWER_SUPPLY_PROP_RESISTANCE_ID:
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08003667 pval->intval = chip->batt_id_ohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003668 break;
3669 case POWER_SUPPLY_PROP_BATTERY_TYPE:
3670 pval->strval = fg_get_battery_type(chip);
3671 break;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003672 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
3673 pval->intval = chip->bp.float_volt_uv;
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07003674 break;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003675 case POWER_SUPPLY_PROP_CYCLE_COUNT:
3676 pval->intval = fg_get_cycle_count(chip);
3677 break;
3678 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3679 pval->intval = chip->cyc_ctr.id;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003680 break;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003681 case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003682 rc = fg_get_charge_raw(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003683 break;
3684 case POWER_SUPPLY_PROP_CHARGE_NOW:
3685 pval->intval = chip->cl.init_cc_uah;
3686 break;
3687 case POWER_SUPPLY_PROP_CHARGE_FULL:
3688 pval->intval = chip->cl.learned_cc_uah;
3689 break;
3690 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003691 rc = fg_get_charge_counter(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003692 break;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07003693 case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
3694 rc = fg_get_charge_counter_shadow(chip, &pval->intval);
3695 break;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003696 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
3697 rc = fg_get_time_to_full(chip, &pval->intval);
3698 break;
3699 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
3700 rc = fg_get_time_to_empty(chip, &pval->intval);
3701 break;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003702 case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
3703 pval->intval = chip->soc_reporting_ready;
3704 break;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303705 case POWER_SUPPLY_PROP_DEBUG_BATTERY:
3706 pval->intval = is_debug_batt_id(chip);
3707 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003708 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3709 rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
3710 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003711 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07003712 if ((chip->ttf.cc_step.sel >= 0) &&
3713 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
3714 pval->intval =
3715 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003716 } else {
3717 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07003718 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003719 return -EINVAL;
3720 }
3721 break;
3722 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Nicholas Troast805c2422017-07-06 14:53:46 -07003723 pval->intval = chip->ttf.cc_step.sel;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003724 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003725 default:
Nicholas Troast1769fd32016-09-07 09:20:58 -07003726 pr_err("unsupported property %d\n", psp);
3727 rc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003728 break;
3729 }
3730
Nicholas Troast1769fd32016-09-07 09:20:58 -07003731 if (rc < 0)
3732 return -ENODATA;
3733
3734 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003735}
3736
3737static int fg_psy_set_property(struct power_supply *psy,
3738 enum power_supply_property psp,
3739 const union power_supply_propval *pval)
3740{
Nicholas Troaste29dec92016-08-24 09:35:11 -07003741 struct fg_chip *chip = power_supply_get_drvdata(psy);
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003742 int rc = 0;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003743
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003744 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003745 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3746 if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) {
3747 chip->cyc_ctr.id = pval->intval;
3748 } else {
3749 pr_err("rejecting invalid cycle_count_id = %d\n",
3750 pval->intval);
3751 return -EINVAL;
3752 }
Nicholas Troast60242812017-06-20 09:33:21 -07003753 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003754 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3755 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003756 break;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003757 case POWER_SUPPLY_PROP_RESISTANCE:
3758 rc = fg_force_esr_meas(chip);
3759 break;
3760 case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
3761 rc = fg_prepare_for_qnovo(chip, pval->intval);
3762 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003763 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07003764 if ((chip->ttf.cc_step.sel >= 0) &&
3765 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
3766 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
3767 pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003768 } else {
3769 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07003770 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003771 return -EINVAL;
3772 }
3773 break;
3774 case POWER_SUPPLY_PROP_CC_STEP_SEL:
3775 if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
Nicholas Troast805c2422017-07-06 14:53:46 -07003776 chip->ttf.cc_step.sel = pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003777 } else {
3778 pr_err("cc_step_sel is out of bounds [0, %d]\n",
3779 pval->intval);
3780 return -EINVAL;
3781 }
3782 break;
Subbaraman Narayanamurthy677e7252017-08-11 18:27:08 -07003783 case POWER_SUPPLY_PROP_CHARGE_FULL:
3784 if (chip->cl.active) {
3785 pr_warn("Capacity learning active!\n");
3786 return 0;
3787 }
3788 if (pval->intval <= 0 || pval->intval > chip->cl.nom_cap_uah) {
3789 pr_err("charge_full is out of bounds\n");
3790 return -EINVAL;
3791 }
3792 chip->cl.learned_cc_uah = pval->intval;
3793 rc = fg_save_learned_cap_to_sram(chip);
3794 if (rc < 0)
3795 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
3796 break;
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003797 case POWER_SUPPLY_PROP_COLD_TEMP:
3798 rc = fg_set_jeita_threshold(chip, JEITA_COLD, pval->intval);
3799 if (rc < 0) {
3800 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3801 return rc;
3802 }
3803 break;
3804 case POWER_SUPPLY_PROP_COOL_TEMP:
3805 rc = fg_set_jeita_threshold(chip, JEITA_COOL, pval->intval);
3806 if (rc < 0) {
3807 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
3808 return rc;
3809 }
3810 break;
3811 case POWER_SUPPLY_PROP_WARM_TEMP:
3812 rc = fg_set_jeita_threshold(chip, JEITA_WARM, pval->intval);
3813 if (rc < 0) {
3814 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
3815 return rc;
3816 }
3817 break;
3818 case POWER_SUPPLY_PROP_HOT_TEMP:
3819 rc = fg_set_jeita_threshold(chip, JEITA_HOT, pval->intval);
3820 if (rc < 0) {
3821 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
3822 return rc;
3823 }
3824 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003825 default:
3826 break;
3827 }
3828
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003829 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003830}
3831
3832static int fg_property_is_writeable(struct power_supply *psy,
3833 enum power_supply_property psp)
3834{
3835 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003836 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003837 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003838 case POWER_SUPPLY_PROP_CC_STEP:
3839 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Subbaraman Narayanamurthy677e7252017-08-11 18:27:08 -07003840 case POWER_SUPPLY_PROP_CHARGE_FULL:
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003841 case POWER_SUPPLY_PROP_COLD_TEMP:
3842 case POWER_SUPPLY_PROP_COOL_TEMP:
3843 case POWER_SUPPLY_PROP_WARM_TEMP:
3844 case POWER_SUPPLY_PROP_HOT_TEMP:
Nicholas Troaste29dec92016-08-24 09:35:11 -07003845 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003846 default:
3847 break;
3848 }
3849
3850 return 0;
3851}
3852
3853static void fg_external_power_changed(struct power_supply *psy)
3854{
3855 pr_debug("power supply changed\n");
3856}
3857
3858static int fg_notifier_cb(struct notifier_block *nb,
3859 unsigned long event, void *data)
3860{
3861 struct power_supply *psy = data;
3862 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
3863
3864 if (event != PSY_EVENT_PROP_CHANGED)
3865 return NOTIFY_OK;
3866
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08003867 if (work_pending(&chip->status_change_work))
3868 return NOTIFY_OK;
3869
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003870 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthya7249ef2017-10-03 20:34:38 -07003871 || (strcmp(psy->desc->name, "parallel") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003872 || (strcmp(psy->desc->name, "usb") == 0)) {
3873 /*
3874 * We cannot vote for awake votable here as that takes
3875 * a mutex lock and this is executed in an atomic context.
3876 */
3877 pm_stay_awake(chip->dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003878 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003879 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003880
3881 return NOTIFY_OK;
3882}
3883
3884static enum power_supply_property fg_psy_props[] = {
3885 POWER_SUPPLY_PROP_CAPACITY,
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003886 POWER_SUPPLY_PROP_CAPACITY_RAW,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003887 POWER_SUPPLY_PROP_TEMP,
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07003888 POWER_SUPPLY_PROP_COLD_TEMP,
3889 POWER_SUPPLY_PROP_COOL_TEMP,
3890 POWER_SUPPLY_PROP_WARM_TEMP,
3891 POWER_SUPPLY_PROP_HOT_TEMP,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003892 POWER_SUPPLY_PROP_VOLTAGE_NOW,
3893 POWER_SUPPLY_PROP_VOLTAGE_OCV,
3894 POWER_SUPPLY_PROP_CURRENT_NOW,
3895 POWER_SUPPLY_PROP_RESISTANCE_ID,
3896 POWER_SUPPLY_PROP_RESISTANCE,
3897 POWER_SUPPLY_PROP_BATTERY_TYPE,
3898 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003899 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Nicholas Troaste29dec92016-08-24 09:35:11 -07003900 POWER_SUPPLY_PROP_CYCLE_COUNT,
3901 POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003902 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
3903 POWER_SUPPLY_PROP_CHARGE_NOW,
3904 POWER_SUPPLY_PROP_CHARGE_FULL,
3905 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07003906 POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
Nicholas Troast1769fd32016-09-07 09:20:58 -07003907 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3908 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003909 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303910 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003911 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003912 POWER_SUPPLY_PROP_CC_STEP,
3913 POWER_SUPPLY_PROP_CC_STEP_SEL,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003914};
3915
3916static const struct power_supply_desc fg_psy_desc = {
3917 .name = "bms",
3918 .type = POWER_SUPPLY_TYPE_BMS,
3919 .properties = fg_psy_props,
3920 .num_properties = ARRAY_SIZE(fg_psy_props),
3921 .get_property = fg_psy_get_property,
3922 .set_property = fg_psy_set_property,
3923 .external_power_changed = fg_external_power_changed,
3924 .property_is_writeable = fg_property_is_writeable,
3925};
3926
3927/* INIT FUNCTIONS STAY HERE */
3928
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003929#define DEFAULT_ESR_CHG_TIMER_RETRY 8
3930#define DEFAULT_ESR_CHG_TIMER_MAX 16
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003931static int fg_hw_init(struct fg_chip *chip)
3932{
3933 int rc;
3934 u8 buf[4], val;
3935
3936 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003937 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
3938 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003939 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
3940 if (rc < 0) {
3941 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
3942 return rc;
3943 }
3944
3945 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003946 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
3947 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003948 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
3949 if (rc < 0) {
3950 pr_err("Error in writing empty_volt, rc=%d\n", rc);
3951 return rc;
3952 }
3953
3954 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
3955 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003956 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
3957 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003958 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
3959 if (rc < 0) {
3960 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
3961 return rc;
3962 }
3963
3964 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
3965 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003966 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
3967 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003968 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
3969 if (rc < 0) {
3970 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
3971 return rc;
3972 }
3973
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003974 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
3975 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
3976 chip->dt.chg_term_base_curr_ma, buf);
3977 rc = fg_sram_write(chip,
3978 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
3979 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
3980 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
3981 FG_IMA_DEFAULT);
3982 if (rc < 0) {
3983 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
3984 rc);
3985 return rc;
3986 }
3987 }
3988
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003989 if (chip->dt.vbatt_low_thr_mv > 0) {
3990 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
3991 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003992 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
3993 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003994 chip->sp[FG_SRAM_VBATT_LOW].len,
3995 FG_IMA_DEFAULT);
3996 if (rc < 0) {
3997 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
3998 return rc;
3999 }
4000 }
4001
4002 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004003 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004004 chip->dt.delta_soc_thr, buf);
4005 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004006 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
4007 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
4008 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004009 FG_IMA_DEFAULT);
4010 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004011 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
4012 return rc;
4013 }
4014
4015 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
4016 chip->dt.delta_soc_thr, buf);
4017 rc = fg_sram_write(chip,
4018 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
4019 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
4020 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
4021 FG_IMA_DEFAULT);
4022 if (rc < 0) {
4023 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004024 return rc;
4025 }
4026 }
4027
cyizhaofb3eec52017-01-24 17:08:55 +08004028 /*
4029 * configure battery thermal coefficients c1,c2,c3
4030 * if its value is not zero.
4031 */
4032 if (chip->dt.batt_therm_coeffs[0] > 0) {
4033 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
4034 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
4035 if (rc < 0) {
4036 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
4037 rc);
4038 return rc;
4039 }
4040 }
4041
4042
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004043 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004044 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004045 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004046 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004047 return rc;
4048 }
4049 }
4050
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004051 if (chip->dt.recharge_volt_thr_mv > 0) {
4052 rc = fg_set_recharge_voltage(chip,
4053 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004054 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004055 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004056 rc);
4057 return rc;
4058 }
4059 }
4060
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004061 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
4062 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
4063 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
4064 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
4065 if (rc < 0) {
4066 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
4067 return rc;
4068 }
4069 }
4070
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004071 rc = fg_set_jeita_threshold(chip, JEITA_COLD,
4072 chip->dt.jeita_thresholds[JEITA_COLD] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004073 if (rc < 0) {
4074 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
4075 return rc;
4076 }
4077
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004078 rc = fg_set_jeita_threshold(chip, JEITA_COOL,
4079 chip->dt.jeita_thresholds[JEITA_COOL] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004080 if (rc < 0) {
4081 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
4082 return rc;
4083 }
4084
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004085 rc = fg_set_jeita_threshold(chip, JEITA_WARM,
4086 chip->dt.jeita_thresholds[JEITA_WARM] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004087 if (rc < 0) {
4088 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
4089 return rc;
4090 }
4091
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004092 rc = fg_set_jeita_threshold(chip, JEITA_HOT,
4093 chip->dt.jeita_thresholds[JEITA_HOT] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004094 if (rc < 0) {
4095 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
4096 return rc;
4097 }
4098
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004099 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
4100 chip->esr_timer_charging_default[TIMER_RETRY] =
4101 DEFAULT_ESR_CHG_TIMER_RETRY;
4102 chip->esr_timer_charging_default[TIMER_MAX] =
4103 DEFAULT_ESR_CHG_TIMER_MAX;
4104 } else {
4105 /* We don't need this for pm660 at present */
4106 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
4107 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004108 }
4109
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004110 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
4111 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
4112 if (rc < 0) {
4113 pr_err("Error in setting ESR timer, rc=%d\n", rc);
4114 return rc;
4115 }
4116
4117 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
4118 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
4119 if (rc < 0) {
4120 pr_err("Error in setting ESR timer, rc=%d\n", rc);
4121 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004122 }
4123
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07004124 restore_cycle_counter(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004125
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004126 if (chip->dt.jeita_hyst_temp >= 0) {
4127 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
4128 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
4129 JEITA_TEMP_HYST_MASK, val);
4130 if (rc < 0) {
4131 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
4132 return rc;
4133 }
4134 }
4135
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004136 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
4137 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
4138 CHANGE_THOLD_MASK, val);
4139 if (rc < 0) {
4140 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
4141 return rc;
4142 }
4143
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004144 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
4145 chip->dt.esr_tight_flt_upct, buf);
4146 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
4147 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
4148 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
4149 if (rc < 0) {
4150 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
4151 return rc;
4152 }
4153
4154 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
4155 chip->dt.esr_broad_flt_upct, buf);
4156 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
4157 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
4158 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
4159 if (rc < 0) {
4160 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
4161 return rc;
4162 }
4163
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004164 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
4165 chip->dt.esr_pulse_thresh_ma, buf);
4166 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
4167 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
4168 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
4169 if (rc < 0) {
4170 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
4171 return rc;
4172 }
4173
4174 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
4175 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
4176 ESR_PULL_DOWN_IVAL_MASK, val);
4177 if (rc < 0) {
4178 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
4179 return rc;
4180 }
4181
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07004182 if (is_debug_batt_id(chip)) {
4183 val = ESR_NO_PULL_DOWN;
4184 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
4185 ESR_PULL_DOWN_MODE_MASK, val);
4186 if (rc < 0) {
4187 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
4188 return rc;
4189 }
4190 }
4191
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004192 return 0;
4193}
4194
4195static int fg_memif_init(struct fg_chip *chip)
4196{
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004197 if (chip->use_dma)
4198 return fg_dma_init(chip);
4199
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004200 return fg_ima_init(chip);
4201}
4202
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304203static int fg_adjust_timebase(struct fg_chip *chip)
4204{
4205 int rc = 0, die_temp;
4206 s32 time_base = 0;
4207 u8 buf[2] = {0};
4208
4209 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
4210 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
4211 if (rc < 0) {
4212 pr_err("Error in reading die_temp, rc:%d\n", rc);
4213 return rc;
4214 }
4215
4216 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
4217 die_temp / 1000, &time_base);
4218 if (rc < 0) {
4219 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
4220 return rc;
4221 }
4222
4223 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
4224 rc = fg_sram_write(chip,
4225 chip->sp[FG_SRAM_TIMEBASE].addr_word,
4226 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
4227 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
4228 if (rc < 0) {
4229 pr_err("Error in writing timebase, rc=%d\n", rc);
4230 return rc;
4231 }
4232 }
4233
4234 return 0;
4235}
4236
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004237/* INTERRUPT HANDLERS STAY HERE */
4238
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004239static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
4240{
4241 struct fg_chip *chip = data;
4242 u8 status;
4243 int rc;
4244
4245 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
4246 if (rc < 0) {
4247 pr_err("failed to read addr=0x%04x, rc=%d\n",
4248 MEM_IF_INT_RT_STS(chip), rc);
4249 return IRQ_HANDLED;
4250 }
4251
4252 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004253
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07004254 mutex_lock(&chip->sram_rw_lock);
4255 rc = fg_clear_dma_errors_if_any(chip);
4256 if (rc < 0)
4257 pr_err("Error in clearing DMA error, rc=%d\n", rc);
4258
4259 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004260 rc = fg_clear_ima_errors_if_any(chip, true);
4261 if (rc < 0 && rc != -EAGAIN)
4262 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004263 }
4264
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07004265 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004266 return IRQ_HANDLED;
4267}
4268
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004269static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
4270{
4271 struct fg_chip *chip = data;
4272
4273 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4274 return IRQ_HANDLED;
4275}
4276
4277static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
4278{
4279 struct fg_chip *chip = data;
4280 u8 status;
4281 int rc;
4282
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004283 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
4284 if (rc < 0) {
4285 pr_err("failed to read addr=0x%04x, rc=%d\n",
4286 BATT_INFO_INT_RT_STS(chip), rc);
4287 return IRQ_HANDLED;
4288 }
4289
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004290 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004291 chip->battery_missing = (status & BT_MISS_BIT);
4292
4293 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07004294 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004295 chip->profile_loaded = false;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08004296 chip->soc_reporting_ready = false;
Fenglin Wu16ef9a72017-11-06 23:24:54 +08004297 chip->batt_id_ohms = -EINVAL;
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07004298 cancel_delayed_work_sync(&chip->pl_enable_work);
4299 vote(chip->pl_disable_votable, ESR_FCC_VOTER, true, 0);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004300 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004301 }
4302
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004303 clear_battery_profile(chip);
4304 schedule_delayed_work(&chip->profile_load_work, 0);
4305
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304306 if (chip->fg_psy)
4307 power_supply_changed(chip->fg_psy);
4308
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004309 return IRQ_HANDLED;
4310}
4311
4312static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
4313{
4314 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004315 union power_supply_propval prop = {0, };
4316 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004317
4318 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004319 rc = fg_get_battery_temp(chip, &batt_temp);
4320 if (rc < 0) {
4321 pr_err("Error in getting batt_temp\n");
4322 return IRQ_HANDLED;
4323 }
4324
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004325 rc = fg_esr_filter_config(chip, batt_temp);
4326 if (rc < 0)
4327 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4328
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004329 rc = fg_slope_limit_config(chip, batt_temp);
4330 if (rc < 0)
4331 pr_err("Error in configuring slope limiter rc:%d\n", rc);
4332
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004333 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
4334 if (rc < 0)
4335 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
4336
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004337 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004338 chip->last_batt_temp = batt_temp;
4339 return IRQ_HANDLED;
4340 }
4341
4342 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
4343 &prop);
4344 chip->health = prop.intval;
4345
4346 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304347 rc = fg_adjust_timebase(chip);
4348 if (rc < 0)
4349 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4350
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07004351 rc = fg_adjust_recharge_voltage(chip);
4352 if (rc < 0)
4353 pr_err("Error in adjusting recharge_voltage, rc=%d\n",
4354 rc);
4355
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004356 chip->last_batt_temp = batt_temp;
4357 power_supply_changed(chip->batt_psy);
4358 }
4359
4360 if (abs(chip->last_batt_temp - batt_temp) > 30)
4361 pr_warn("Battery temperature last:%d current: %d\n",
4362 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004363 return IRQ_HANDLED;
4364}
4365
4366static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
4367{
4368 struct fg_chip *chip = data;
4369
4370 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4371 complete_all(&chip->soc_ready);
4372 return IRQ_HANDLED;
4373}
4374
4375static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
4376{
4377 struct fg_chip *chip = data;
4378
4379 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4380 complete_all(&chip->soc_update);
4381 return IRQ_HANDLED;
4382}
4383
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004384static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
4385{
4386 struct fg_chip *chip = data;
4387 int rc;
4388
4389 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4390 rc = fg_charge_full_update(chip);
4391 if (rc < 0)
4392 pr_err("Error in charge_full_update, rc=%d\n", rc);
4393
4394 return IRQ_HANDLED;
4395}
4396
4397static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004398{
4399 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004400 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004401
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004402 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07004403 fg_cycle_counter_update(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004404
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004405 if (chip->cl.active)
4406 fg_cap_learning_update(chip);
4407
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004408 rc = fg_charge_full_update(chip);
4409 if (rc < 0)
4410 pr_err("Error in charge_full_update, rc=%d\n", rc);
4411
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004412 rc = fg_adjust_ki_coeff_dischg(chip);
4413 if (rc < 0)
4414 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
4415
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004416 rc = fg_update_maint_soc(chip);
4417 if (rc < 0)
4418 pr_err("Error in updating maint_soc, rc=%d\n", rc);
4419
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004420 rc = fg_esr_validate(chip);
4421 if (rc < 0)
4422 pr_err("Error in validating ESR, rc=%d\n", rc);
4423
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304424 rc = fg_adjust_timebase(chip);
4425 if (rc < 0)
4426 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4427
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004428 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004429 power_supply_changed(chip->batt_psy);
4430
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004431 return IRQ_HANDLED;
4432}
4433
4434static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
4435{
4436 struct fg_chip *chip = data;
4437
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004438 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004439 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07004440 power_supply_changed(chip->batt_psy);
4441
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004442 return IRQ_HANDLED;
4443}
4444
4445static irqreturn_t fg_soc_irq_handler(int irq, void *data)
4446{
4447 struct fg_chip *chip = data;
4448
4449 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4450 return IRQ_HANDLED;
4451}
4452
4453static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
4454{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004455 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004456 return IRQ_HANDLED;
4457}
4458
4459static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
4460 /* BATT_SOC irqs */
4461 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004462 .name = "msoc-full",
4463 .handler = fg_soc_irq_handler,
4464 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004465 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004466 .name = "msoc-high",
4467 .handler = fg_soc_irq_handler,
4468 .wakeable = true,
4469 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004470 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004471 .name = "msoc-empty",
4472 .handler = fg_empty_soc_irq_handler,
4473 .wakeable = true,
4474 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004475 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004476 .name = "msoc-low",
4477 .handler = fg_soc_irq_handler,
4478 .wakeable = true,
4479 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004480 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004481 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004482 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004483 .wakeable = true,
4484 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004485 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004486 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004487 .handler = fg_delta_bsoc_irq_handler,
4488 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004489 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004490 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004491 .name = "soc-ready",
4492 .handler = fg_first_est_irq_handler,
4493 .wakeable = true,
4494 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004495 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004496 .name = "soc-update",
4497 .handler = fg_soc_update_irq_handler,
4498 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004499 /* BATT_INFO irqs */
4500 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004501 .name = "batt-temp-delta",
4502 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004503 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004504 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004505 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004506 .name = "batt-missing",
4507 .handler = fg_batt_missing_irq_handler,
4508 .wakeable = true,
4509 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004510 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004511 .name = "esr-delta",
4512 .handler = fg_dummy_irq_handler,
4513 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004514 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004515 .name = "vbatt-low",
4516 .handler = fg_vbatt_low_irq_handler,
4517 .wakeable = true,
4518 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004519 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004520 .name = "vbatt-pred-delta",
4521 .handler = fg_dummy_irq_handler,
4522 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004523 /* MEM_IF irqs */
4524 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004525 .name = "dma-grant",
Subbaraman Narayanamurthy0d054772017-11-16 18:15:37 -08004526 .handler = fg_dummy_irq_handler,
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004527 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004528 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004529 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004530 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004531 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004532 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004533 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004534 .name = "ima-rdy",
4535 .handler = fg_dummy_irq_handler,
4536 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004537};
4538
4539static int fg_get_irq_index_byname(const char *name)
4540{
4541 int i;
4542
4543 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
4544 if (strcmp(fg_irqs[i].name, name) == 0)
4545 return i;
4546 }
4547
4548 pr_err("%s is not in irq list\n", name);
4549 return -ENOENT;
4550}
4551
4552static int fg_register_interrupts(struct fg_chip *chip)
4553{
4554 struct device_node *child, *node = chip->dev->of_node;
4555 struct property *prop;
4556 const char *name;
4557 int rc, irq, irq_index;
4558
4559 for_each_available_child_of_node(node, child) {
4560 of_property_for_each_string(child, "interrupt-names", prop,
4561 name) {
4562 irq = of_irq_get_byname(child, name);
4563 if (irq < 0) {
4564 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
4565 name, irq);
4566 return irq;
4567 }
4568
4569 irq_index = fg_get_irq_index_byname(name);
4570 if (irq_index < 0)
4571 return irq_index;
4572
4573 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
4574 fg_irqs[irq_index].handler,
4575 IRQF_ONESHOT, name, chip);
4576 if (rc < 0) {
4577 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
4578 name, rc);
4579 return rc;
4580 }
4581
4582 fg_irqs[irq_index].irq = irq;
4583 if (fg_irqs[irq_index].wakeable)
4584 enable_irq_wake(fg_irqs[irq_index].irq);
4585 }
4586 }
4587
4588 return 0;
4589}
4590
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004591static int fg_parse_dt_property_u32_array(struct device_node *node,
4592 const char *prop_name, int *buf, int len)
4593{
4594 int rc;
4595
4596 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
4597 if (rc < 0) {
4598 if (rc == -EINVAL)
4599 return 0;
4600 else
4601 return rc;
4602 } else if (rc != len) {
4603 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
4604 rc);
4605 return -EINVAL;
4606 }
4607
4608 rc = of_property_read_u32_array(node, prop_name, buf, len);
4609 if (rc < 0) {
4610 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
4611 return rc;
4612 }
4613
4614 return 0;
4615}
4616
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004617static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
4618{
4619 struct device_node *node = chip->dev->of_node;
4620 int rc, i;
4621
4622 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
4623 &chip->dt.slope_limit_temp);
4624 if (rc < 0)
4625 return 0;
4626
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004627 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
4628 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
4629 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004630 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004631
4632 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
4633 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
4634 chip->dt.slope_limit_coeffs[i] < 0) {
4635 pr_err("Incorrect slope limit coefficient\n");
4636 return -EINVAL;
4637 }
4638 }
4639
4640 chip->slope_limit_en = true;
4641 return 0;
4642}
4643
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004644static int fg_parse_ki_coefficients(struct fg_chip *chip)
4645{
4646 struct device_node *node = chip->dev->of_node;
Subbaraman Narayanamurthye17be582017-08-08 19:28:37 -07004647 int rc, i, temp;
4648
4649 rc = of_property_read_u32(node, "qcom,ki-coeff-full-dischg", &temp);
4650 if (!rc)
4651 chip->dt.ki_coeff_full_soc_dischg = temp;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004652
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004653 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
4654 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
4655 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004656 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004657
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004658 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
4659 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
4660 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004661 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004662
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004663 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
4664 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
4665 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004666 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004667
4668 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
4669 if (chip->dt.ki_coeff_soc[i] < 0 ||
4670 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
4671 pr_err("Error in ki_coeff_soc_dischg values\n");
4672 return -EINVAL;
4673 }
4674
4675 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
4676 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
4677 pr_err("Error in ki_coeff_med_dischg values\n");
4678 return -EINVAL;
4679 }
4680
4681 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
4682 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
4683 pr_err("Error in ki_coeff_med_dischg values\n");
4684 return -EINVAL;
4685 }
4686 }
4687 chip->ki_coeff_dischg_en = true;
4688 return 0;
4689}
4690
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004691#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07004692#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004693#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004694#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004695#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07004696#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004697#define DEFAULT_DELTA_SOC_THR 1
4698#define DEFAULT_RECHARGE_SOC_THR 95
4699#define DEFAULT_BATT_TEMP_COLD 0
4700#define DEFAULT_BATT_TEMP_COOL 5
4701#define DEFAULT_BATT_TEMP_WARM 45
4702#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004703#define DEFAULT_CL_START_SOC 15
4704#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
Subbaraman Narayanamurthya01aac92017-10-11 14:05:11 -07004705#define DEFAULT_CL_MAX_TEMP_DECIDEGC 500
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004706#define DEFAULT_CL_MAX_INC_DECIPERC 5
4707#define DEFAULT_CL_MAX_DEC_DECIPERC 100
4708#define DEFAULT_CL_MIN_LIM_DECIPERC 0
4709#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004710#define BTEMP_DELTA_LOW 2
4711#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004712#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
4713#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
4714#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
4715#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
4716#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004717#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004718#define DEFAULT_ESR_PULSE_THRESH_MA 110
4719#define DEFAULT_ESR_MEAS_CURR_MA 120
Fenglin Wud10ccf12017-08-10 15:43:41 +08004720#define DEFAULT_BMD_EN_DELAY_MS 200
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004721static int fg_parse_dt(struct fg_chip *chip)
4722{
4723 struct device_node *child, *revid_node, *node = chip->dev->of_node;
4724 u32 base, temp;
4725 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004726 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004727
4728 if (!node) {
4729 dev_err(chip->dev, "device tree node missing\n");
4730 return -ENXIO;
4731 }
4732
4733 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
4734 if (!revid_node) {
4735 pr_err("Missing qcom,pmic-revid property - driver failed\n");
4736 return -EINVAL;
4737 }
4738
4739 chip->pmic_rev_id = get_revid_data(revid_node);
4740 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
4741 pr_err("Unable to get pmic_revid rc=%ld\n",
4742 PTR_ERR(chip->pmic_rev_id));
4743 /*
4744 * the revid peripheral must be registered, any failure
4745 * here only indicates that the rev-id module has not
4746 * probed yet.
4747 */
4748 return -EPROBE_DEFER;
4749 }
4750
4751 pr_debug("PMIC subtype %d Digital major %d\n",
4752 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
4753
4754 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004755 case PMI8998_SUBTYPE:
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004756 chip->use_dma = true;
Harry Yang2452b272017-03-06 13:56:14 -08004757 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
4758 chip->sp = pmi8998_v1_sram_params;
4759 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304760 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08004761 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
4762 chip->sp = pmi8998_v2_sram_params;
4763 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07004764 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004765 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07004766 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004767 break;
Harry Yange4e731b2017-03-06 14:35:09 -08004768 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304769 chip->sp = pmi8998_v2_sram_params;
4770 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07004771 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304772 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
4773 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304774 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004775 default:
4776 return -EINVAL;
4777 }
4778
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004779 if (of_get_available_child_count(node) == 0) {
4780 dev_err(chip->dev, "No child nodes specified!\n");
4781 return -ENXIO;
4782 }
4783
4784 for_each_available_child_of_node(node, child) {
4785 rc = of_property_read_u32(child, "reg", &base);
4786 if (rc < 0) {
4787 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
4788 child->full_name, rc);
4789 return rc;
4790 }
4791
4792 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
4793 if (rc < 0) {
4794 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
4795 base, rc);
4796 return rc;
4797 }
4798
4799 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004800 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004801 chip->batt_soc_base = base;
4802 break;
Harry Yang2452b272017-03-06 13:56:14 -08004803 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004804 chip->batt_info_base = base;
4805 break;
Harry Yang2452b272017-03-06 13:56:14 -08004806 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004807 chip->mem_if_base = base;
4808 break;
4809 default:
4810 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
4811 subtype);
4812 return -ENXIO;
4813 }
4814 }
4815
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004816 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
4817 if (rc < 0) {
4818 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
4819 return rc;
4820 }
4821 chip->rradc_base = base;
4822
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004823 /* Read all the optional properties below */
4824 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
4825 if (rc < 0)
4826 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
4827 else
4828 chip->dt.cutoff_volt_mv = temp;
4829
4830 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
4831 if (rc < 0)
4832 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
4833 else
4834 chip->dt.empty_volt_mv = temp;
4835
4836 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
4837 if (rc < 0)
4838 chip->dt.vbatt_low_thr_mv = -EINVAL;
4839 else
4840 chip->dt.vbatt_low_thr_mv = temp;
4841
4842 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
4843 if (rc < 0)
4844 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
4845 else
4846 chip->dt.chg_term_curr_ma = temp;
4847
4848 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
4849 if (rc < 0)
4850 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
4851 else
4852 chip->dt.sys_term_curr_ma = temp;
4853
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004854 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
4855 if (rc < 0)
4856 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
4857 else
4858 chip->dt.chg_term_base_curr_ma = temp;
4859
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004860 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
4861 if (rc < 0)
4862 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
4863 else
4864 chip->dt.delta_soc_thr = temp;
4865
4866 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
4867 if (rc < 0)
4868 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
4869 else
4870 chip->dt.recharge_soc_thr = temp;
4871
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004872 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
4873 if (rc < 0)
4874 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
4875 else
4876 chip->dt.recharge_volt_thr_mv = temp;
4877
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004878 chip->dt.auto_recharge_soc = of_property_read_bool(node,
4879 "qcom,fg-auto-recharge-soc");
4880
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004881 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
4882 if (rc < 0)
4883 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
4884 else
4885 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
4886
4887 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
4888 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
4889 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
4890 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004891 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
4892 sizeof(u32)) == NUM_JEITA_LEVELS) {
4893 rc = of_property_read_u32_array(node,
4894 "qcom,fg-jeita-thresholds",
4895 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
4896 if (rc < 0)
4897 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
4898 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004899 }
4900
cyizhaofb3eec52017-01-24 17:08:55 +08004901 if (of_property_count_elems_of_size(node,
4902 "qcom,battery-thermal-coefficients",
4903 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
4904 rc = of_property_read_u8_array(node,
4905 "qcom,battery-thermal-coefficients",
4906 chip->dt.batt_therm_coeffs,
4907 BATT_THERM_NUM_COEFFS);
4908 if (rc < 0)
4909 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
4910 rc);
4911 }
4912
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004913 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
4914 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
4915 if (rc < 0) {
4916 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
4917 chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
4918 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004919
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004920 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
4921 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
4922 if (rc < 0) {
4923 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
4924 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
4925 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004926
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004927 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
4928 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
4929 if (rc < 0) {
4930 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
4931 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
4932 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004933
Nicholas Troaste29dec92016-08-24 09:35:11 -07004934 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
4935 if (chip->cyc_ctr.en)
4936 chip->cyc_ctr.id = 1;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004937
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07004938 chip->dt.force_load_profile = of_property_read_bool(node,
4939 "qcom,fg-force-load-profile");
4940
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004941 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
4942 if (rc < 0)
4943 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
4944 else
4945 chip->dt.cl_start_soc = temp;
4946
4947 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
4948 if (rc < 0)
4949 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
4950 else
4951 chip->dt.cl_min_temp = temp;
4952
4953 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
4954 if (rc < 0)
4955 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
4956 else
4957 chip->dt.cl_max_temp = temp;
4958
4959 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
4960 if (rc < 0)
4961 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
4962 else
4963 chip->dt.cl_max_cap_inc = temp;
4964
4965 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
4966 if (rc < 0)
4967 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
4968 else
4969 chip->dt.cl_max_cap_dec = temp;
4970
4971 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
4972 if (rc < 0)
4973 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
4974 else
4975 chip->dt.cl_min_cap_limit = temp;
4976
4977 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
4978 if (rc < 0)
4979 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
4980 else
4981 chip->dt.cl_max_cap_limit = temp;
4982
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004983 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
4984 if (rc < 0)
4985 chip->dt.jeita_hyst_temp = -EINVAL;
4986 else
4987 chip->dt.jeita_hyst_temp = temp;
4988
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004989 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
4990 if (rc < 0)
4991 chip->dt.batt_temp_delta = -EINVAL;
4992 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
4993 chip->dt.batt_temp_delta = temp;
4994
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004995 chip->dt.hold_soc_while_full = of_property_read_bool(node,
4996 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004997
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07004998 chip->dt.linearize_soc = of_property_read_bool(node,
4999 "qcom,linearize-soc");
5000
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005001 rc = fg_parse_ki_coefficients(chip);
5002 if (rc < 0)
5003 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
5004
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08005005 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07005006 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08005007 chip->dt.rconn_mohms = temp;
5008
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005009 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
5010 &temp);
5011 if (rc < 0)
5012 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
5013 else
5014 chip->dt.esr_flt_switch_temp = temp;
5015
5016 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
5017 &temp);
5018 if (rc < 0)
5019 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
5020 else
5021 chip->dt.esr_tight_flt_upct = temp;
5022
5023 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
5024 &temp);
5025 if (rc < 0)
5026 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
5027 else
5028 chip->dt.esr_broad_flt_upct = temp;
5029
5030 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
5031 &temp);
5032 if (rc < 0)
5033 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
5034 else
5035 chip->dt.esr_tight_lt_flt_upct = temp;
5036
5037 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
5038 &temp);
5039 if (rc < 0)
5040 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
5041 else
5042 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08005043
5044 rc = fg_parse_slope_limit_coefficients(chip);
5045 if (rc < 0)
5046 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
5047
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08005048 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
5049 if (rc < 0)
5050 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
5051 else
5052 chip->dt.esr_clamp_mohms = temp;
5053
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07005054 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
5055 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
5056 if (!rc) {
5057 /* ESR pulse qualification threshold range is 1-997 mA */
5058 if (temp > 0 && temp < 997)
5059 chip->dt.esr_pulse_thresh_ma = temp;
5060 }
5061
5062 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
5063 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
5064 if (!rc) {
5065 /* ESR measurement current range is 60-240 mA */
5066 if (temp >= 60 || temp <= 240)
5067 chip->dt.esr_meas_curr_ma = temp;
5068 }
5069
Fenglin Wud10ccf12017-08-10 15:43:41 +08005070 chip->dt.bmd_en_delay_ms = DEFAULT_BMD_EN_DELAY_MS;
5071 rc = of_property_read_u32(node, "qcom,fg-bmd-en-delay-ms", &temp);
5072 if (!rc) {
5073 if (temp > DEFAULT_BMD_EN_DELAY_MS)
5074 chip->dt.bmd_en_delay_ms = temp;
5075 }
5076
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005077 return 0;
5078}
5079
5080static void fg_cleanup(struct fg_chip *chip)
5081{
Subbaraman Narayanamurthyf580cb92017-08-30 20:27:41 -07005082 int i;
5083
5084 for (i = 0; i < FG_IRQ_MAX; i++) {
5085 if (fg_irqs[i].irq)
5086 devm_free_irq(chip->dev, fg_irqs[i].irq, chip);
5087 }
5088
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005089 power_supply_unreg_notifier(&chip->nb);
Nicholas Troast69da2252016-09-07 16:17:47 -07005090 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005091 if (chip->awake_votable)
5092 destroy_votable(chip->awake_votable);
5093
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005094 if (chip->delta_bsoc_irq_en_votable)
5095 destroy_votable(chip->delta_bsoc_irq_en_votable);
5096
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005097 if (chip->batt_miss_irq_en_votable)
5098 destroy_votable(chip->batt_miss_irq_en_votable);
5099
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005100 if (chip->batt_id_chan)
5101 iio_channel_release(chip->batt_id_chan);
5102
5103 dev_set_drvdata(chip->dev, NULL);
5104}
5105
5106static int fg_gen3_probe(struct platform_device *pdev)
5107{
5108 struct fg_chip *chip;
5109 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005110 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005111
5112 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
5113 if (!chip)
5114 return -ENOMEM;
5115
5116 chip->dev = &pdev->dev;
5117 chip->debug_mask = &fg_gen3_debug_mask;
5118 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07005119 chip->charge_status = -EINVAL;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07005120 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07005121 chip->ki_coeff_full_soc = -EINVAL;
Nicholas Troast805c2422017-07-06 14:53:46 -07005122 chip->online_status = -EINVAL;
Fenglin Wu16ef9a72017-11-06 23:24:54 +08005123 chip->batt_id_ohms = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005124 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
5125 if (!chip->regmap) {
5126 dev_err(chip->dev, "Parent regmap is unavailable\n");
5127 return -ENXIO;
5128 }
5129
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08005130 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
5131 if (IS_ERR(chip->batt_id_chan)) {
5132 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
5133 pr_err("batt_id_chan unavailable %ld\n",
5134 PTR_ERR(chip->batt_id_chan));
5135 rc = PTR_ERR(chip->batt_id_chan);
5136 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005137 return rc;
5138 }
5139
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05305140 rc = of_property_match_string(chip->dev->of_node,
5141 "io-channel-names", "rradc_die_temp");
5142 if (rc >= 0) {
5143 chip->die_temp_chan = iio_channel_get(chip->dev,
5144 "rradc_die_temp");
5145 if (IS_ERR(chip->die_temp_chan)) {
5146 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
5147 pr_err("rradc_die_temp unavailable %ld\n",
5148 PTR_ERR(chip->die_temp_chan));
5149 rc = PTR_ERR(chip->die_temp_chan);
5150 chip->die_temp_chan = NULL;
5151 return rc;
5152 }
5153 }
5154
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07005155 chip->pl_disable_votable = find_votable("PL_DISABLE");
5156 if (chip->pl_disable_votable == NULL) {
5157 rc = -EPROBE_DEFER;
5158 goto exit;
5159 }
5160
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005161 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
5162 chip);
5163 if (IS_ERR(chip->awake_votable)) {
5164 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005165 chip->awake_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005166 goto exit;
5167 }
5168
5169 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
5170 VOTE_SET_ANY,
5171 fg_delta_bsoc_irq_en_cb, chip);
5172 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
5173 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005174 chip->delta_bsoc_irq_en_votable = NULL;
5175 goto exit;
5176 }
5177
5178 chip->batt_miss_irq_en_votable = create_votable("FG_BATT_MISS_IRQ",
5179 VOTE_SET_ANY,
5180 fg_batt_miss_irq_en_cb, chip);
5181 if (IS_ERR(chip->batt_miss_irq_en_votable)) {
5182 rc = PTR_ERR(chip->batt_miss_irq_en_votable);
5183 chip->batt_miss_irq_en_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005184 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005185 }
5186
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08005187 rc = fg_parse_dt(chip);
5188 if (rc < 0) {
5189 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
5190 rc);
5191 goto exit;
5192 }
5193
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005194 mutex_init(&chip->bus_lock);
5195 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07005196 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07005197 mutex_init(&chip->cl.lock);
Nicholas Troast805c2422017-07-06 14:53:46 -07005198 mutex_init(&chip->ttf.lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08005199 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07005200 mutex_init(&chip->qnovo_esr_ctrl_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005201 init_completion(&chip->soc_update);
5202 init_completion(&chip->soc_ready);
5203 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07005204 INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005205 INIT_WORK(&chip->status_change_work, status_change_work);
Nicholas Troast805c2422017-07-06 14:53:46 -07005206 INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005207 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005208
5209 rc = fg_memif_init(chip);
5210 if (rc < 0) {
5211 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
5212 rc);
5213 goto exit;
5214 }
5215
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07005216 platform_set_drvdata(pdev, chip);
5217
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005218 rc = fg_hw_init(chip);
5219 if (rc < 0) {
5220 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
5221 rc);
5222 goto exit;
5223 }
5224
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005225 /* Register the power supply */
5226 fg_psy_cfg.drv_data = chip;
5227 fg_psy_cfg.of_node = NULL;
5228 fg_psy_cfg.supplied_to = NULL;
5229 fg_psy_cfg.num_supplicants = 0;
5230 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
5231 &fg_psy_cfg);
5232 if (IS_ERR(chip->fg_psy)) {
5233 pr_err("failed to register fg_psy rc = %ld\n",
5234 PTR_ERR(chip->fg_psy));
5235 goto exit;
5236 }
5237
5238 chip->nb.notifier_call = fg_notifier_cb;
5239 rc = power_supply_reg_notifier(&chip->nb);
5240 if (rc < 0) {
5241 pr_err("Couldn't register psy notifier rc = %d\n", rc);
5242 goto exit;
5243 }
5244
Subbaraman Narayanamurthy0d054772017-11-16 18:15:37 -08005245 rc = fg_register_interrupts(chip);
5246 if (rc < 0) {
5247 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
5248 rc);
5249 goto exit;
5250 }
5251
5252 /* Keep SOC_UPDATE irq disabled until we require it */
5253 if (fg_irqs[SOC_UPDATE_IRQ].irq)
5254 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
5255
5256 /* Keep BSOC_DELTA_IRQ disabled until we require it */
5257 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);
5258
5259 /* Keep BATT_MISSING_IRQ disabled until we require it */
5260 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);
5261
Nicholas Troast69da2252016-09-07 16:17:47 -07005262 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005263 if (rc < 0) {
5264 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
5265 rc);
5266 goto exit;
5267 }
5268
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005269 rc = fg_get_battery_voltage(chip, &volt_uv);
5270 if (!rc)
5271 rc = fg_get_prop_capacity(chip, &msoc);
5272
5273 if (!rc)
5274 rc = fg_get_battery_temp(chip, &batt_temp);
5275
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005276 if (!rc) {
Fenglin Wu16ef9a72017-11-06 23:24:54 +08005277 pr_info("battery SOC:%d voltage: %duV temp: %d\n",
5278 msoc, volt_uv, batt_temp);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005279 rc = fg_esr_filter_config(chip, batt_temp);
5280 if (rc < 0)
5281 pr_err("Error in configuring ESR filter rc:%d\n", rc);
5282 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005283
5284 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005285 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005286
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005287 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005288 return 0;
5289exit:
5290 fg_cleanup(chip);
5291 return rc;
5292}
5293
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005294static int fg_gen3_suspend(struct device *dev)
5295{
5296 struct fg_chip *chip = dev_get_drvdata(dev);
5297 int rc;
5298
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005299 rc = fg_esr_timer_config(chip, true);
5300 if (rc < 0)
5301 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005302
Nicholas Troast805c2422017-07-06 14:53:46 -07005303 cancel_delayed_work_sync(&chip->ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005304 if (fg_sram_dump)
5305 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005306 return 0;
5307}
5308
5309static int fg_gen3_resume(struct device *dev)
5310{
5311 struct fg_chip *chip = dev_get_drvdata(dev);
5312 int rc;
5313
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005314 rc = fg_esr_timer_config(chip, false);
5315 if (rc < 0)
5316 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005317
Nicholas Troast805c2422017-07-06 14:53:46 -07005318 schedule_delayed_work(&chip->ttf_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005319 if (fg_sram_dump)
5320 schedule_delayed_work(&chip->sram_dump_work,
5321 msecs_to_jiffies(fg_sram_dump_period_ms));
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005322 return 0;
5323}
5324
5325static const struct dev_pm_ops fg_gen3_pm_ops = {
5326 .suspend = fg_gen3_suspend,
5327 .resume = fg_gen3_resume,
5328};
5329
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005330static int fg_gen3_remove(struct platform_device *pdev)
5331{
5332 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
5333
5334 fg_cleanup(chip);
5335 return 0;
5336}
5337
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07005338static void fg_gen3_shutdown(struct platform_device *pdev)
5339{
5340 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
5341 int rc, bsoc;
5342
5343 if (chip->charge_full) {
5344 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
5345 if (rc < 0) {
5346 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
5347 return;
5348 }
5349
5350 /* We need 2 most significant bytes here */
5351 bsoc = (u32)bsoc >> 16;
5352
5353 rc = fg_configure_full_soc(chip, bsoc);
5354 if (rc < 0) {
5355 pr_err("Error in configuring full_soc, rc=%d\n", rc);
5356 return;
5357 }
5358 }
5359}
5360
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005361static const struct of_device_id fg_gen3_match_table[] = {
5362 {.compatible = FG_GEN3_DEV_NAME},
5363 {},
5364};
5365
5366static struct platform_driver fg_gen3_driver = {
5367 .driver = {
5368 .name = FG_GEN3_DEV_NAME,
5369 .owner = THIS_MODULE,
5370 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005371 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005372 },
5373 .probe = fg_gen3_probe,
5374 .remove = fg_gen3_remove,
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07005375 .shutdown = fg_gen3_shutdown,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005376};
5377
5378static int __init fg_gen3_init(void)
5379{
5380 return platform_driver_register(&fg_gen3_driver);
5381}
5382
5383static void __exit fg_gen3_exit(void)
5384{
5385 return platform_driver_unregister(&fg_gen3_driver);
5386}
5387
5388module_init(fg_gen3_init);
5389module_exit(fg_gen3_exit);
5390
5391MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
5392MODULE_LICENSE("GPL v2");
5393MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);