blob: 1fd6bd85eaea8882ce59a6ace71ebead67c50d54 [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 Narayanamurthydd6ea382017-03-15 13:15:31 -0700565static int fg_get_charge_counter(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700566{
567 int rc, cc_soc;
568
569 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc);
570 if (rc < 0) {
571 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
572 return rc;
573 }
574
575 *val = div_s64(cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT);
576 return 0;
577}
578
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700579#define BATT_TEMP_NUMR 1
580#define BATT_TEMP_DENR 1
581static int fg_get_battery_temp(struct fg_chip *chip, int *val)
582{
Subbaraman Narayanamurthyfabbb8e2016-10-21 16:55:09 -0700583 int rc = 0, temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700584 u8 buf[2];
585
586 rc = fg_read(chip, BATT_INFO_BATT_TEMP_LSB(chip), buf, 2);
587 if (rc < 0) {
588 pr_err("failed to read addr=0x%04x, rc=%d\n",
589 BATT_INFO_BATT_TEMP_LSB(chip), rc);
590 return rc;
591 }
592
593 temp = ((buf[1] & BATT_TEMP_MSB_MASK) << 8) |
594 (buf[0] & BATT_TEMP_LSB_MASK);
595 temp = DIV_ROUND_CLOSEST(temp, 4);
596
597 /* Value is in Kelvin; Convert it to deciDegC */
598 temp = (temp - 273) * 10;
599 *val = temp;
600 return 0;
601}
602
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700603static int fg_get_battery_resistance(struct fg_chip *chip, int *val)
604{
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800605 int rc, esr_uohms, rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700606
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800607 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700608 if (rc < 0) {
609 pr_err("failed to get ESR, rc=%d\n", rc);
610 return rc;
611 }
612
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800613 rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &rslow_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700614 if (rc < 0) {
615 pr_err("failed to get Rslow, rc=%d\n", rc);
616 return rc;
617 }
618
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800619 *val = esr_uohms + rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700620 return 0;
621}
622
623#define BATT_CURRENT_NUMR 488281
624#define BATT_CURRENT_DENR 1000
625static int fg_get_battery_current(struct fg_chip *chip, int *val)
626{
627 int rc = 0;
628 int64_t temp = 0;
629 u8 buf[2];
630
631 rc = fg_read(chip, BATT_INFO_IBATT_LSB(chip), buf, 2);
632 if (rc < 0) {
633 pr_err("failed to read addr=0x%04x, rc=%d\n",
634 BATT_INFO_IBATT_LSB(chip), rc);
635 return rc;
636 }
637
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530638 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700639 temp = buf[0] << 8 | buf[1];
640 else
641 temp = buf[1] << 8 | buf[0];
642
643 pr_debug("buf: %x %x temp: %llx\n", buf[0], buf[1], temp);
644 /* Sign bit is bit 15 */
645 temp = twos_compliment_extend(temp, 15);
646 *val = div_s64((s64)temp * BATT_CURRENT_NUMR, BATT_CURRENT_DENR);
647 return 0;
648}
649
650#define BATT_VOLTAGE_NUMR 122070
651#define BATT_VOLTAGE_DENR 1000
652static int fg_get_battery_voltage(struct fg_chip *chip, int *val)
653{
654 int rc = 0;
655 u16 temp = 0;
656 u8 buf[2];
657
658 rc = fg_read(chip, BATT_INFO_VBATT_LSB(chip), buf, 2);
659 if (rc < 0) {
660 pr_err("failed to read addr=0x%04x, rc=%d\n",
661 BATT_INFO_VBATT_LSB(chip), rc);
662 return rc;
663 }
664
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530665 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700666 temp = buf[0] << 8 | buf[1];
667 else
668 temp = buf[1] << 8 | buf[0];
669
670 pr_debug("buf: %x %x temp: %x\n", buf[0], buf[1], temp);
671 *val = div_u64((u64)temp * BATT_VOLTAGE_NUMR, BATT_VOLTAGE_DENR);
672 return 0;
673}
674
675#define MAX_TRIES_SOC 5
676static int fg_get_msoc_raw(struct fg_chip *chip, int *val)
677{
678 u8 cap[2];
679 int rc, tries = 0;
680
681 while (tries < MAX_TRIES_SOC) {
682 rc = fg_read(chip, BATT_SOC_FG_MONOTONIC_SOC(chip), cap, 2);
683 if (rc < 0) {
684 pr_err("failed to read addr=0x%04x, rc=%d\n",
685 BATT_SOC_FG_MONOTONIC_SOC(chip), rc);
686 return rc;
687 }
688
689 if (cap[0] == cap[1])
690 break;
691
692 tries++;
693 }
694
695 if (tries == MAX_TRIES_SOC) {
696 pr_err("shadow registers do not match\n");
697 return -EINVAL;
698 }
699
700 fg_dbg(chip, FG_POWER_SUPPLY, "raw: 0x%02x\n", cap[0]);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700701 *val = cap[0];
702 return 0;
703}
704
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800705#define FULL_CAPACITY 100
706#define FULL_SOC_RAW 255
707static int fg_get_msoc(struct fg_chip *chip, int *msoc)
708{
709 int rc;
710
711 rc = fg_get_msoc_raw(chip, msoc);
712 if (rc < 0)
713 return rc;
714
715 *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW);
716 return 0;
717}
718
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800719static bool is_batt_empty(struct fg_chip *chip)
720{
721 u8 status;
722 int rc, vbatt_uv, msoc;
723
724 rc = fg_read(chip, BATT_SOC_INT_RT_STS(chip), &status, 1);
725 if (rc < 0) {
726 pr_err("failed to read addr=0x%04x, rc=%d\n",
727 BATT_SOC_INT_RT_STS(chip), rc);
728 return false;
729 }
730
731 if (!(status & MSOC_EMPTY_BIT))
732 return false;
733
734 rc = fg_get_battery_voltage(chip, &vbatt_uv);
735 if (rc < 0) {
736 pr_err("failed to get battery voltage, rc=%d\n", rc);
737 return false;
738 }
739
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800740 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800741 if (!rc)
742 pr_warn("batt_soc_rt_sts: %x vbatt: %d uV msoc:%d\n", status,
743 vbatt_uv, msoc);
744
745 return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false);
746}
747
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800748static int fg_get_debug_batt_id(struct fg_chip *chip, int *batt_id)
749{
750 int rc;
751 u64 temp;
752 u8 buf[2];
753
754 rc = fg_read(chip, ADC_RR_FAKE_BATT_LOW_LSB(chip), buf, 2);
755 if (rc < 0) {
756 pr_err("failed to read addr=0x%04x, rc=%d\n",
757 ADC_RR_FAKE_BATT_LOW_LSB(chip), rc);
758 return rc;
759 }
760
761 /*
762 * Fake battery threshold is encoded in the following format.
763 * Threshold (code) = (battery_id in Ohms) * 0.00015 * 2^10 / 2.5
764 */
765 temp = (buf[1] << 8 | buf[0]) * 2500000;
766 do_div(temp, 150 * 1024);
767 batt_id[0] = temp;
768 rc = fg_read(chip, ADC_RR_FAKE_BATT_HIGH_LSB(chip), buf, 2);
769 if (rc < 0) {
770 pr_err("failed to read addr=0x%04x, rc=%d\n",
771 ADC_RR_FAKE_BATT_HIGH_LSB(chip), rc);
772 return rc;
773 }
774
775 temp = (buf[1] << 8 | buf[0]) * 2500000;
776 do_div(temp, 150 * 1024);
777 batt_id[1] = temp;
778 pr_debug("debug batt_id range: [%d %d]\n", batt_id[0], batt_id[1]);
779 return 0;
780}
781
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700782static bool is_debug_batt_id(struct fg_chip *chip)
783{
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800784 int debug_batt_id[2], rc;
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700785
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800786 if (!chip->batt_id_ohms)
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700787 return false;
788
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800789 rc = fg_get_debug_batt_id(chip, debug_batt_id);
790 if (rc < 0) {
791 pr_err("Failed to get debug batt_id, rc=%d\n", rc);
792 return false;
793 }
794
795 if (is_between(debug_batt_id[0], debug_batt_id[1],
796 chip->batt_id_ohms)) {
797 fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dohms\n",
798 chip->batt_id_ohms);
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700799 return true;
800 }
801
802 return false;
803}
804
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700805#define DEBUG_BATT_SOC 67
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800806#define BATT_MISS_SOC 50
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700807#define EMPTY_SOC 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700808static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
809{
810 int rc, msoc;
811
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700812 if (is_debug_batt_id(chip)) {
813 *val = DEBUG_BATT_SOC;
814 return 0;
815 }
816
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800817 if (chip->fg_restarting) {
818 *val = chip->last_soc;
819 return 0;
820 }
821
822 if (chip->battery_missing) {
823 *val = BATT_MISS_SOC;
824 return 0;
825 }
826
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800827 if (is_batt_empty(chip)) {
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700828 *val = EMPTY_SOC;
829 return 0;
830 }
831
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700832 if (chip->charge_full) {
833 *val = FULL_CAPACITY;
834 return 0;
835 }
836
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800837 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700838 if (rc < 0)
839 return rc;
840
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800841 if (chip->delta_soc > 0)
842 *val = chip->maint_soc;
843 else
844 *val = msoc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700845 return 0;
846}
847
848#define DEFAULT_BATT_TYPE "Unknown Battery"
849#define MISSING_BATT_TYPE "Missing Battery"
850#define LOADING_BATT_TYPE "Loading Battery"
851static const char *fg_get_battery_type(struct fg_chip *chip)
852{
853 if (chip->battery_missing)
854 return MISSING_BATT_TYPE;
855
856 if (chip->bp.batt_type_str) {
857 if (chip->profile_loaded)
858 return chip->bp.batt_type_str;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -0800859 else if (chip->profile_available)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700860 return LOADING_BATT_TYPE;
861 }
862
863 return DEFAULT_BATT_TYPE;
864}
865
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800866static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700867{
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800868 int rc;
869
870 rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
871 BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
872 if (rc < 0)
873 pr_err("Error in writing to %04x, rc=%d\n",
874 BATT_INFO_BATT_MISS_CFG(chip), rc);
875 return rc;
876}
877
878static int fg_get_batt_id(struct fg_chip *chip)
879{
880 int rc, ret, batt_id = 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700881
882 if (!chip->batt_id_chan)
883 return -EINVAL;
884
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800885 rc = fg_batt_missing_config(chip, false);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700886 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800887 pr_err("Error in disabling BMD, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700888 return rc;
889 }
890
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800891 rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
892 if (rc < 0) {
893 pr_err("Error in reading batt_id channel, rc:%d\n", rc);
894 goto out;
895 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700896
Fenglin Wud10ccf12017-08-10 15:43:41 +0800897 /* Wait for BATT_ID to settle down before enabling BMD again */
898 msleep(chip->dt.bmd_en_delay_ms);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800899
900 fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
901 chip->batt_id_ohms = batt_id;
902out:
903 ret = fg_batt_missing_config(chip, true);
904 if (ret < 0) {
905 pr_err("Error in enabling BMD, ret=%d\n", ret);
906 return ret;
907 }
908
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -0700909 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, true, 0);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800910 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700911}
912
913static int fg_get_batt_profile(struct fg_chip *chip)
914{
915 struct device_node *node = chip->dev->of_node;
916 struct device_node *batt_node, *profile_node;
917 const char *data;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800918 int rc, len;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700919
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700920 batt_node = of_find_node_by_name(node, "qcom,battery-data");
921 if (!batt_node) {
922 pr_err("Batterydata not available\n");
923 return -ENXIO;
924 }
925
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800926 profile_node = of_batterydata_get_best_profile(batt_node,
927 chip->batt_id_ohms / 1000, NULL);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700928 if (IS_ERR(profile_node))
929 return PTR_ERR(profile_node);
930
931 if (!profile_node) {
932 pr_err("couldn't find profile handle\n");
933 return -ENODATA;
934 }
935
936 rc = of_property_read_string(profile_node, "qcom,battery-type",
937 &chip->bp.batt_type_str);
938 if (rc < 0) {
939 pr_err("battery type unavailable, rc:%d\n", rc);
940 return rc;
941 }
942
943 rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
944 &chip->bp.float_volt_uv);
945 if (rc < 0) {
946 pr_err("battery float voltage unavailable, rc:%d\n", rc);
947 chip->bp.float_volt_uv = -EINVAL;
948 }
949
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -0800950 rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700951 &chip->bp.fastchg_curr_ma);
952 if (rc < 0) {
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -0800953 pr_err("battery fastchg current unavailable, rc:%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700954 chip->bp.fastchg_curr_ma = -EINVAL;
955 }
956
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700957 rc = of_property_read_u32(profile_node, "qcom,fg-cc-cv-threshold-mv",
958 &chip->bp.vbatt_full_mv);
959 if (rc < 0) {
960 pr_err("battery cc_cv threshold unavailable, rc:%d\n", rc);
961 chip->bp.vbatt_full_mv = -EINVAL;
962 }
963
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700964 data = of_get_property(profile_node, "qcom,fg-profile-data", &len);
965 if (!data) {
966 pr_err("No profile data available\n");
967 return -ENODATA;
968 }
969
970 if (len != PROFILE_LEN) {
971 pr_err("battery profile incorrect size: %d\n", len);
972 return -EINVAL;
973 }
974
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700975 chip->profile_available = true;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700976 memcpy(chip->batt_profile, data, len);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800977
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700978 return 0;
979}
980
981static inline void get_temp_setpoint(int threshold, u8 *val)
982{
983 /* Resolution is 0.5C. Base is -30C. */
984 *val = DIV_ROUND_CLOSEST((threshold + 30) * 10, 5);
985}
986
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -0700987static inline void get_batt_temp_delta(int delta, u8 *val)
988{
989 switch (delta) {
990 case 2:
991 *val = BTEMP_DELTA_2K;
992 break;
993 case 4:
994 *val = BTEMP_DELTA_4K;
995 break;
996 case 6:
997 *val = BTEMP_DELTA_6K;
998 break;
999 case 10:
1000 *val = BTEMP_DELTA_10K;
1001 break;
1002 default:
1003 *val = BTEMP_DELTA_2K;
1004 break;
1005 };
1006}
1007
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07001008static inline void get_esr_meas_current(int curr_ma, u8 *val)
1009{
1010 switch (curr_ma) {
1011 case 60:
1012 *val = ESR_MEAS_CUR_60MA;
1013 break;
1014 case 120:
1015 *val = ESR_MEAS_CUR_120MA;
1016 break;
1017 case 180:
1018 *val = ESR_MEAS_CUR_180MA;
1019 break;
1020 case 240:
1021 *val = ESR_MEAS_CUR_240MA;
1022 break;
1023 default:
1024 *val = ESR_MEAS_CUR_120MA;
1025 break;
1026 };
1027
1028 *val <<= ESR_PULL_DOWN_IVAL_SHIFT;
1029}
1030
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001031static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
1032 int cycles_max, bool charging, int flags)
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001033{
1034 u8 buf[2];
1035 int rc, timer_max, timer_init;
1036
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001037 if (cycles_init < 0 || cycles_max < 0)
1038 return 0;
1039
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001040 if (charging) {
1041 timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
1042 timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
1043 } else {
1044 timer_max = FG_SRAM_ESR_TIMER_DISCHG_MAX;
1045 timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
1046 }
1047
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001048 fg_encode(chip->sp, timer_max, cycles_max, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001049 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001050 chip->sp[timer_max].addr_word,
1051 chip->sp[timer_max].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001052 chip->sp[timer_max].len, flags);
1053 if (rc < 0) {
1054 pr_err("Error in writing esr_timer_dischg_max, rc=%d\n",
1055 rc);
1056 return rc;
1057 }
1058
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001059 fg_encode(chip->sp, timer_init, cycles_init, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001060 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001061 chip->sp[timer_init].addr_word,
1062 chip->sp[timer_init].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001063 chip->sp[timer_init].len, flags);
1064 if (rc < 0) {
1065 pr_err("Error in writing esr_timer_dischg_init, rc=%d\n",
1066 rc);
1067 return rc;
1068 }
1069
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001070 fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
1071 charging ? "charging" : "discharging", cycles_init, cycles_max);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001072 return 0;
1073}
1074
Nicholas Troaste29dec92016-08-24 09:35:11 -07001075/* Other functions HERE */
1076
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001077static void fg_notify_charger(struct fg_chip *chip)
1078{
1079 union power_supply_propval prop = {0, };
1080 int rc;
1081
1082 if (!chip->batt_psy)
1083 return;
1084
1085 if (!chip->profile_available)
1086 return;
1087
1088 prop.intval = chip->bp.float_volt_uv;
1089 rc = power_supply_set_property(chip->batt_psy,
1090 POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
1091 if (rc < 0) {
1092 pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
1093 rc);
1094 return;
1095 }
1096
1097 prop.intval = chip->bp.fastchg_curr_ma * 1000;
1098 rc = power_supply_set_property(chip->batt_psy,
1099 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
1100 if (rc < 0) {
1101 pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
1102 rc);
1103 return;
1104 }
1105
1106 fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
1107}
1108
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001109static int fg_batt_miss_irq_en_cb(struct votable *votable, void *data,
1110 int enable, const char *client)
1111{
1112 struct fg_chip *chip = data;
1113
1114 if (!chip->irqs[BATT_MISSING_IRQ].irq)
1115 return 0;
1116
1117 if (enable) {
1118 enable_irq(chip->irqs[BATT_MISSING_IRQ].irq);
1119 enable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
1120 } else {
1121 disable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
1122 disable_irq(chip->irqs[BATT_MISSING_IRQ].irq);
1123 }
1124
1125 return 0;
1126}
1127
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001128static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data,
1129 int enable, const char *client)
1130{
1131 struct fg_chip *chip = data;
1132
1133 if (!chip->irqs[BSOC_DELTA_IRQ].irq)
1134 return 0;
1135
1136 if (enable) {
1137 enable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1138 enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1139 } else {
1140 disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1141 disable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1142 }
1143
1144 return 0;
1145}
1146
Nicholas Troaste29dec92016-08-24 09:35:11 -07001147static int fg_awake_cb(struct votable *votable, void *data, int awake,
1148 const char *client)
1149{
1150 struct fg_chip *chip = data;
1151
1152 if (awake)
1153 pm_stay_awake(chip->dev);
1154 else
1155 pm_relax(chip->dev);
1156
1157 pr_debug("client: %s awake: %d\n", client, awake);
1158 return 0;
1159}
1160
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001161static bool batt_psy_initialized(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07001162{
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001163 if (chip->batt_psy)
1164 return true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07001165
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001166 chip->batt_psy = power_supply_get_by_name("battery");
Nicholas Troaste29dec92016-08-24 09:35:11 -07001167 if (!chip->batt_psy)
1168 return false;
1169
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001170 /* batt_psy is initialized, set the fcc and fv */
1171 fg_notify_charger(chip);
1172
Nicholas Troaste29dec92016-08-24 09:35:11 -07001173 return true;
1174}
1175
Nicholas Troast805c2422017-07-06 14:53:46 -07001176static bool usb_psy_initialized(struct fg_chip *chip)
1177{
1178 if (chip->usb_psy)
1179 return true;
1180
1181 chip->usb_psy = power_supply_get_by_name("usb");
1182 if (!chip->usb_psy)
1183 return false;
1184
1185 return true;
1186}
1187
1188static bool pc_port_psy_initialized(struct fg_chip *chip)
1189{
1190 if (chip->pc_port_psy)
1191 return true;
1192
1193 chip->pc_port_psy = power_supply_get_by_name("pc_port");
1194 if (!chip->pc_port_psy)
1195 return false;
1196
1197 return true;
1198}
1199
1200static bool dc_psy_initialized(struct fg_chip *chip)
1201{
1202 if (chip->dc_psy)
1203 return true;
1204
1205 chip->dc_psy = power_supply_get_by_name("dc");
1206 if (!chip->dc_psy)
1207 return false;
1208
1209 return true;
1210}
1211
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001212static bool is_parallel_charger_available(struct fg_chip *chip)
1213{
1214 if (!chip->parallel_psy)
1215 chip->parallel_psy = power_supply_get_by_name("parallel");
1216
1217 if (!chip->parallel_psy)
1218 return false;
1219
1220 return true;
1221}
1222
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001223static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
1224{
1225 int16_t cc_mah;
1226 int rc;
1227
1228 if (chip->battery_missing || !chip->cl.learned_cc_uah)
1229 return -EPERM;
1230
1231 cc_mah = div64_s64(chip->cl.learned_cc_uah, 1000);
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001232 /* Write to a backup register to use across reboot */
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001233 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word,
1234 chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah,
1235 chip->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT);
1236 if (rc < 0) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001237 pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc);
1238 return rc;
1239 }
1240
1241 /* Write to actual capacity register for coulomb counter operation */
1242 rc = fg_sram_write(chip, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET,
1243 (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len,
1244 FG_IMA_DEFAULT);
1245 if (rc < 0) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001246 pr_err("Error in writing act_batt_cap, rc=%d\n", rc);
1247 return rc;
1248 }
1249
1250 fg_dbg(chip, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n",
1251 chip->cl.learned_cc_uah, cc_mah);
1252 return 0;
1253}
1254
1255#define CAPACITY_DELTA_DECIPCT 500
1256static int fg_load_learned_cap_from_sram(struct fg_chip *chip)
1257{
1258 int rc, act_cap_mah;
1259 int64_t delta_cc_uah, pct_nom_cap_uah;
1260
1261 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
1262 if (rc < 0) {
1263 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1264 return rc;
1265 }
1266
1267 chip->cl.learned_cc_uah = act_cap_mah * 1000;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001268
1269 if (chip->cl.learned_cc_uah != chip->cl.nom_cap_uah) {
Subbaraman Narayanamurthy51d3c902016-10-24 14:05:44 -07001270 if (chip->cl.learned_cc_uah == 0)
1271 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
1272
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001273 delta_cc_uah = abs(chip->cl.learned_cc_uah -
1274 chip->cl.nom_cap_uah);
1275 pct_nom_cap_uah = div64_s64((int64_t)chip->cl.nom_cap_uah *
1276 CAPACITY_DELTA_DECIPCT, 1000);
1277 /*
1278 * If the learned capacity is out of range by 50% from the
1279 * nominal capacity, then overwrite the learned capacity with
1280 * the nominal capacity.
1281 */
1282 if (chip->cl.nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001283 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected, capping it to nominal: %lld\n",
1284 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001285 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001286 }
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001287
1288 rc = fg_save_learned_cap_to_sram(chip);
1289 if (rc < 0)
1290 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001291 }
1292
1293 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah:%lld nom_cap_uah: %lld\n",
1294 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
1295 return 0;
1296}
1297
1298static bool is_temp_valid_cap_learning(struct fg_chip *chip)
1299{
1300 int rc, batt_temp;
1301
1302 rc = fg_get_battery_temp(chip, &batt_temp);
1303 if (rc < 0) {
1304 pr_err("Error in getting batt_temp\n");
1305 return false;
1306 }
1307
1308 if (batt_temp > chip->dt.cl_max_temp ||
1309 batt_temp < chip->dt.cl_min_temp) {
1310 fg_dbg(chip, FG_CAP_LEARN, "batt temp %d out of range [%d %d]\n",
1311 batt_temp, chip->dt.cl_min_temp, chip->dt.cl_max_temp);
1312 return false;
1313 }
1314
1315 return true;
1316}
1317
1318static void fg_cap_learning_post_process(struct fg_chip *chip)
1319{
1320 int64_t max_inc_val, min_dec_val, old_cap;
1321 int rc;
1322
1323 max_inc_val = chip->cl.learned_cc_uah
1324 * (1000 + chip->dt.cl_max_cap_inc);
1325 do_div(max_inc_val, 1000);
1326
1327 min_dec_val = chip->cl.learned_cc_uah
1328 * (1000 - chip->dt.cl_max_cap_dec);
1329 do_div(min_dec_val, 1000);
1330
1331 old_cap = chip->cl.learned_cc_uah;
1332 if (chip->cl.final_cc_uah > max_inc_val)
1333 chip->cl.learned_cc_uah = max_inc_val;
1334 else if (chip->cl.final_cc_uah < min_dec_val)
1335 chip->cl.learned_cc_uah = min_dec_val;
1336 else
1337 chip->cl.learned_cc_uah =
1338 chip->cl.final_cc_uah;
1339
1340 if (chip->dt.cl_max_cap_limit) {
1341 max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
1342 chip->dt.cl_max_cap_limit);
1343 do_div(max_inc_val, 1000);
1344 if (chip->cl.final_cc_uah > max_inc_val) {
1345 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
1346 chip->cl.final_cc_uah, max_inc_val);
1347 chip->cl.learned_cc_uah = max_inc_val;
1348 }
1349 }
1350
1351 if (chip->dt.cl_min_cap_limit) {
1352 min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
1353 chip->dt.cl_min_cap_limit);
1354 do_div(min_dec_val, 1000);
1355 if (chip->cl.final_cc_uah < min_dec_val) {
1356 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
1357 chip->cl.final_cc_uah, min_dec_val);
1358 chip->cl.learned_cc_uah = min_dec_val;
1359 }
1360 }
1361
1362 rc = fg_save_learned_cap_to_sram(chip);
1363 if (rc < 0)
1364 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
1365
1366 fg_dbg(chip, FG_CAP_LEARN, "final cc_uah = %lld, learned capacity %lld -> %lld uah\n",
1367 chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah);
1368}
1369
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001370static int fg_cap_learning_process_full_data(struct fg_chip *chip)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001371{
1372 int rc, cc_soc_sw, cc_soc_delta_pct;
1373 int64_t delta_cc_uah;
1374
1375 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
1376 if (rc < 0) {
1377 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
1378 return rc;
1379 }
1380
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -07001381 cc_soc_delta_pct =
1382 div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
1383 CC_SOC_30BIT);
1384
1385 /* If the delta is < 50%, then skip processing full data */
1386 if (cc_soc_delta_pct < 50) {
1387 pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
1388 return -ERANGE;
1389 }
1390
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001391 delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
1392 100);
1393 chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
1394 fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n",
1395 cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
1396 return 0;
1397}
1398
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001399#define BATT_SOC_32BIT GENMASK(31, 0)
1400static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001401{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001402 int rc, cc_soc_sw, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001403
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001404 batt_soc_msb = batt_soc >> 24;
1405 if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001406 chip->dt.cl_start_soc) {
1407 fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001408 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001409 return -EINVAL;
1410 }
1411
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001412 chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001413 FULL_SOC_RAW);
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001414
1415 /* Prime cc_soc_sw with battery SOC when capacity learning begins */
1416 cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
1417 BATT_SOC_32BIT);
1418 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1419 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
1420 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001421 if (rc < 0) {
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001422 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1423 goto out;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001424 }
1425
1426 chip->cl.init_cc_soc_sw = cc_soc_sw;
1427 chip->cl.active = true;
1428 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 -07001429 batt_soc_msb, chip->cl.init_cc_soc_sw);
1430out:
1431 return rc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001432}
1433
1434static int fg_cap_learning_done(struct fg_chip *chip)
1435{
1436 int rc, cc_soc_sw;
1437
1438 rc = fg_cap_learning_process_full_data(chip);
1439 if (rc < 0) {
1440 pr_err("Error in processing cap learning full data, rc=%d\n",
1441 rc);
1442 goto out;
1443 }
1444
1445 /* Write a FULL value to cc_soc_sw */
1446 cc_soc_sw = CC_SOC_30BIT;
1447 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1448 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001449 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001450 if (rc < 0) {
1451 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1452 goto out;
1453 }
1454
1455 fg_cap_learning_post_process(chip);
1456out:
1457 return rc;
1458}
1459
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001460static void fg_cap_learning_update(struct fg_chip *chip)
1461{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001462 int rc, batt_soc, batt_soc_msb;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001463 bool input_present = is_input_present(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001464
1465 mutex_lock(&chip->cl.lock);
1466
1467 if (!is_temp_valid_cap_learning(chip) || !chip->cl.learned_cc_uah ||
1468 chip->battery_missing) {
1469 fg_dbg(chip, FG_CAP_LEARN, "Aborting cap_learning %lld\n",
1470 chip->cl.learned_cc_uah);
1471 chip->cl.active = false;
1472 chip->cl.init_cc_uah = 0;
1473 goto out;
1474 }
1475
1476 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
1477 if (rc < 0) {
1478 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1479 goto out;
1480 }
1481
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001482 batt_soc_msb = (u32)batt_soc >> 24;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001483 fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001484 chip->charge_status, chip->cl.active, batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001485
1486 /* Initialize the starting point of learning capacity */
1487 if (!chip->cl.active) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07001488 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001489 rc = fg_cap_learning_begin(chip, batt_soc);
1490 chip->cl.active = (rc == 0);
1491 }
1492
1493 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001494 if (chip->charge_done) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001495 rc = fg_cap_learning_done(chip);
1496 if (rc < 0)
1497 pr_err("Error in completing capacity learning, rc=%d\n",
1498 rc);
1499
1500 chip->cl.active = false;
1501 chip->cl.init_cc_uah = 0;
1502 }
1503
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001504 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
1505 if (!input_present) {
1506 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1507 batt_soc_msb);
1508 chip->cl.active = false;
1509 chip->cl.init_cc_uah = 0;
1510 }
1511 }
1512
Nicholas Troast1769fd32016-09-07 09:20:58 -07001513 if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001514 if (is_qnovo_en(chip) && input_present) {
1515 /*
1516 * Don't abort the capacity learning when qnovo
1517 * is enabled and input is present where the
1518 * charging status can go to "not charging"
1519 * intermittently.
1520 */
1521 } else {
1522 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1523 batt_soc_msb);
1524 chip->cl.active = false;
1525 chip->cl.init_cc_uah = 0;
1526 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001527 }
1528 }
1529
1530out:
1531 mutex_unlock(&chip->cl.lock);
1532}
1533
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001534#define KI_COEFF_MED_DISCHG_DEFAULT 1500
1535#define KI_COEFF_HI_DISCHG_DEFAULT 2200
1536static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
1537{
1538 int rc, i, msoc;
1539 int ki_coeff_med = KI_COEFF_MED_DISCHG_DEFAULT;
1540 int ki_coeff_hi = KI_COEFF_HI_DISCHG_DEFAULT;
1541 u8 val;
1542
1543 if (!chip->ki_coeff_dischg_en)
1544 return 0;
1545
1546 rc = fg_get_prop_capacity(chip, &msoc);
1547 if (rc < 0) {
1548 pr_err("Error in getting capacity, rc=%d\n", rc);
1549 return rc;
1550 }
1551
Nicholas Troast1769fd32016-09-07 09:20:58 -07001552 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001553 for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) {
1554 if (msoc < chip->dt.ki_coeff_soc[i]) {
1555 ki_coeff_med = chip->dt.ki_coeff_med_dischg[i];
1556 ki_coeff_hi = chip->dt.ki_coeff_hi_dischg[i];
1557 }
1558 }
1559 }
1560
1561 fg_encode(chip->sp, FG_SRAM_KI_COEFF_MED_DISCHG, ki_coeff_med, &val);
1562 rc = fg_sram_write(chip,
1563 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_word,
1564 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_byte, &val,
1565 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].len,
1566 FG_IMA_DEFAULT);
1567 if (rc < 0) {
1568 pr_err("Error in writing ki_coeff_med, rc=%d\n", rc);
1569 return rc;
1570 }
1571
1572 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_DISCHG, ki_coeff_hi, &val);
1573 rc = fg_sram_write(chip,
1574 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_word,
1575 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_byte, &val,
1576 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].len,
1577 FG_IMA_DEFAULT);
1578 if (rc < 0) {
1579 pr_err("Error in writing ki_coeff_hi, rc=%d\n", rc);
1580 return rc;
1581 }
1582
1583 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_med %d ki_coeff_hi %d\n",
1584 ki_coeff_med, ki_coeff_hi);
1585 return 0;
1586}
1587
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001588#define KI_COEFF_FULL_SOC_DEFAULT 733
1589static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
1590{
1591 int rc, ki_coeff_full_soc;
1592 u8 val;
1593
1594 if (batt_temp < 0)
1595 ki_coeff_full_soc = 0;
1596 else
1597 ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
1598
1599 if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
1600 return 0;
1601
1602 fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
1603 rc = fg_sram_write(chip,
1604 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
1605 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
1606 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
1607 FG_IMA_DEFAULT);
1608 if (rc < 0) {
1609 pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
1610 return rc;
1611 }
1612
1613 chip->ki_coeff_full_soc = ki_coeff_full_soc;
1614 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
1615 ki_coeff_full_soc);
1616 return 0;
1617}
1618
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001619static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
1620{
1621 u8 buf;
1622 int rc;
1623
1624 if (chip->dt.auto_recharge_soc)
1625 return 0;
1626
1627 /* This configuration is available only for pmicobalt v2.0 and above */
1628 if (chip->wa_flags & PMI8998_V1_REV_WA)
1629 return 0;
1630
1631 fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
1632 voltage_mv);
1633 fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
1634 rc = fg_sram_write(chip,
1635 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
1636 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
1637 &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
1638 FG_IMA_DEFAULT);
1639 if (rc < 0) {
1640 pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
1641 rc);
1642 return rc;
1643 }
1644
1645 return 0;
1646}
1647
1648#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001649static int fg_charge_full_update(struct fg_chip *chip)
1650{
1651 union power_supply_propval prop = {0, };
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301652 int rc, msoc, bsoc, recharge_soc, msoc_raw;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001653 u8 full_soc[2] = {0xFF, 0xFF};
1654
1655 if (!chip->dt.hold_soc_while_full)
1656 return 0;
1657
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001658 if (!batt_psy_initialized(chip))
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001659 return 0;
1660
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001661 mutex_lock(&chip->charge_full_lock);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001662 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
1663 chip->charge_done, 0);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001664 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
1665 &prop);
1666 if (rc < 0) {
1667 pr_err("Error in getting battery health, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001668 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001669 }
1670
1671 chip->health = prop.intval;
1672 recharge_soc = chip->dt.recharge_soc_thr;
1673 recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
1674 FULL_CAPACITY);
1675 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
1676 if (rc < 0) {
1677 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001678 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001679 }
1680
1681 /* We need 2 most significant bytes here */
1682 bsoc = (u32)bsoc >> 16;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001683 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001684 if (rc < 0) {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001685 pr_err("Error in getting msoc, rc=%d\n", rc);
1686 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001687 }
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301688 msoc_raw = DIV_ROUND_CLOSEST(msoc * FULL_SOC_RAW, FULL_CAPACITY);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001689
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001690 fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
1691 msoc, bsoc, chip->health, chip->charge_status,
1692 chip->charge_full);
1693 if (chip->charge_done && !chip->charge_full) {
1694 if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) {
1695 fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n");
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001696 chip->charge_full = true;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001697 /*
1698 * Lower the recharge voltage so that VBAT_LT_RECHG
1699 * signal will not be asserted soon.
1700 */
1701 rc = fg_set_recharge_voltage(chip,
1702 AUTO_RECHG_VOLT_LOW_LIMIT_MV);
1703 if (rc < 0) {
1704 pr_err("Error in reducing recharge voltage, rc=%d\n",
1705 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001706 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001707 }
1708 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001709 fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
1710 msoc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001711 }
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301712 } else if (msoc_raw < recharge_soc && chip->charge_full) {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001713 chip->delta_soc = FULL_CAPACITY - msoc;
1714
1715 /*
1716 * We're spreading out the delta SOC over every 10% change
1717 * in monotonic SOC. We cannot spread more than 9% in the
1718 * range of 0-100 skipping the first 10%.
1719 */
1720 if (chip->delta_soc > 9) {
1721 chip->delta_soc = 0;
1722 chip->maint_soc = 0;
1723 } else {
1724 chip->maint_soc = FULL_CAPACITY;
1725 chip->last_msoc = msoc;
1726 }
1727
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001728 chip->charge_full = false;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001729
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001730 /*
1731 * Raise the recharge voltage so that VBAT_LT_RECHG signal
1732 * will be asserted soon as battery SOC had dropped below
1733 * the recharge SOC threshold.
1734 */
1735 rc = fg_set_recharge_voltage(chip,
1736 chip->dt.recharge_volt_thr_mv);
1737 if (rc < 0) {
1738 pr_err("Error in setting recharge voltage, rc=%d\n",
1739 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001740 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001741 }
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301742 fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
1743 msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001744 } else {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001745 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001746 }
1747
1748 if (!chip->charge_full)
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001749 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001750
1751 /*
1752 * During JEITA conditions, charge_full can happen early. FULL_SOC
1753 * and MONOTONIC_SOC needs to be updated to reflect the same. Write
1754 * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
1755 */
1756 rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
1757 FG_IMA_ATOMIC);
1758 if (rc < 0) {
1759 pr_err("failed to write full_soc rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001760 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001761 }
1762
1763 rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
1764 full_soc, 2, FG_IMA_ATOMIC);
1765 if (rc < 0) {
1766 pr_err("failed to write monotonic_soc rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001767 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001768 }
1769
1770 fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001771out:
1772 mutex_unlock(&chip->charge_full_lock);
1773 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001774}
1775
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001776#define RCONN_CONFIG_BIT BIT(0)
1777static int fg_rconn_config(struct fg_chip *chip)
1778{
1779 int rc, esr_uohms;
1780 u64 scaling_factor;
1781 u32 val = 0;
1782
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07001783 if (!chip->dt.rconn_mohms)
1784 return 0;
1785
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001786 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
1787 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1788 if (rc < 0) {
1789 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
1790 return rc;
1791 }
1792
1793 if (val & RCONN_CONFIG_BIT) {
1794 fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
1795 return 0;
1796 }
1797
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08001798 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001799 if (rc < 0) {
1800 pr_err("failed to get ESR, rc=%d\n", rc);
1801 return rc;
1802 }
1803
1804 scaling_factor = div64_u64((u64)esr_uohms * 1000,
1805 esr_uohms + (chip->dt.rconn_mohms * 1000));
1806
1807 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
1808 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1809 if (rc < 0) {
1810 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1811 return rc;
1812 }
1813
1814 val *= scaling_factor;
1815 do_div(val, 1000);
1816 rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
1817 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1818 if (rc < 0) {
1819 pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1820 return rc;
1821 }
1822 fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
1823
1824 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
1825 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1826 if (rc < 0) {
1827 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1828 return rc;
1829 }
1830
1831 val *= scaling_factor;
1832 do_div(val, 1000);
1833 rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
1834 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1835 if (rc < 0) {
1836 pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1837 return rc;
1838 }
1839 fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
1840 val & 0xFF);
1841
1842 val = RCONN_CONFIG_BIT;
1843 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
1844 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1845 if (rc < 0) {
1846 pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
1847 return rc;
1848 }
1849
1850 return 0;
1851}
1852
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08001853static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
1854{
1855 u8 buf[2];
1856 int rc;
1857
1858 if (volt_uv <= 0 || volt_uv > 15590000) {
1859 pr_err("Invalid voltage %d\n", volt_uv);
1860 return -EINVAL;
1861 }
1862
1863 fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
1864
1865 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
1866 chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
1867 chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
1868 if (rc < 0) {
1869 pr_err("Error in writing vbatt_full, rc=%d\n", rc);
1870 return rc;
1871 }
1872
1873 return 0;
1874}
1875
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001876static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
1877{
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001878 u8 buf;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001879 int rc;
1880
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001881 if (!chip->dt.auto_recharge_soc)
1882 return 0;
1883
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001884 if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY)
1885 return 0;
1886
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001887 fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001888 rc = fg_sram_write(chip,
1889 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001890 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001891 chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
1892 if (rc < 0) {
1893 pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
1894 return rc;
1895 }
1896
1897 return 0;
1898}
1899
1900static int fg_adjust_recharge_soc(struct fg_chip *chip)
1901{
1902 int rc, msoc, recharge_soc, new_recharge_soc = 0;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001903 bool recharge_soc_status;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001904
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001905 if (!chip->dt.auto_recharge_soc)
1906 return 0;
1907
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001908 recharge_soc = chip->dt.recharge_soc_thr;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001909 recharge_soc_status = chip->recharge_soc_adjusted;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001910 /*
1911 * If the input is present and charging had been terminated, adjust
1912 * the recharge SOC threshold based on the monotonic SOC at which
1913 * the charge termination had happened.
1914 */
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001915 if (is_input_present(chip)) {
1916 if (chip->charge_done) {
1917 if (!chip->recharge_soc_adjusted) {
1918 /* Get raw monotonic SOC for calculation */
1919 rc = fg_get_msoc(chip, &msoc);
1920 if (rc < 0) {
1921 pr_err("Error in getting msoc, rc=%d\n",
1922 rc);
1923 return rc;
1924 }
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001925
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001926 /* Adjust the recharge_soc threshold */
1927 new_recharge_soc = msoc - (FULL_CAPACITY -
1928 recharge_soc);
1929 chip->recharge_soc_adjusted = true;
1930 } else {
1931 /* adjusted already, do nothing */
1932 return 0;
1933 }
1934 } else {
1935 /* Charging, do nothing */
1936 return 0;
1937 }
1938 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001939 /* Restore the default value */
1940 new_recharge_soc = recharge_soc;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001941 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001942 }
1943
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001944 rc = fg_set_recharge_soc(chip, new_recharge_soc);
1945 if (rc < 0) {
1946 chip->recharge_soc_adjusted = recharge_soc_status;
1947 pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
1948 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001949 }
1950
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001951 fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001952 return 0;
1953}
1954
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08001955static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
1956{
1957 enum slope_limit_status status;
1958 int rc;
1959 u8 buf;
1960
1961 if (!chip->slope_limit_en)
1962 return 0;
1963
1964 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
1965 chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
1966 if (batt_temp < chip->dt.slope_limit_temp)
1967 status = LOW_TEMP_CHARGE;
1968 else
1969 status = HIGH_TEMP_CHARGE;
1970 } else {
1971 if (batt_temp < chip->dt.slope_limit_temp)
1972 status = LOW_TEMP_DISCHARGE;
1973 else
1974 status = HIGH_TEMP_DISCHARGE;
1975 }
1976
1977 if (chip->slope_limit_sts == status)
1978 return 0;
1979
1980 fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
1981 chip->dt.slope_limit_coeffs[status], &buf);
1982 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
1983 chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
1984 chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
1985 if (rc < 0) {
1986 pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
1987 rc);
1988 return rc;
1989 }
1990
1991 chip->slope_limit_sts = status;
1992 fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
1993 buf);
1994 return 0;
1995}
1996
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001997static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
1998{
1999 u8 esr_tight_lt_flt, esr_broad_lt_flt;
2000 bool cold_temp = false;
2001 int rc;
2002
2003 /*
2004 * If the battery temperature is lower than -20 C, then skip modifying
2005 * ESR filter.
2006 */
2007 if (batt_temp < -210)
2008 return 0;
2009
2010 /*
2011 * If battery temperature is lesser than 10 C (default), then apply the
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002012 * ESR low temperature tight and broad filter values to ESR room
2013 * temperature tight and broad filters. If battery temperature is higher
2014 * than 10 C, then apply back the room temperature ESR filter
2015 * coefficients to ESR room temperature tight and broad filters.
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002016 */
2017 if (batt_temp > chip->dt.esr_flt_switch_temp
2018 && chip->esr_flt_cold_temp_en) {
2019 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002020 chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
2021 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
2022 chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002023 } else if (batt_temp <= chip->dt.esr_flt_switch_temp
2024 && !chip->esr_flt_cold_temp_en) {
2025 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
2026 chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
2027 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
2028 chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002029 cold_temp = true;
2030 } else {
2031 return 0;
2032 }
2033
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002034 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
2035 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
2036 &esr_tight_lt_flt,
2037 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002038 if (rc < 0) {
2039 pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
2040 return rc;
2041 }
2042
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002043 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
2044 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
2045 &esr_broad_lt_flt,
2046 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002047 if (rc < 0) {
2048 pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
2049 return rc;
2050 }
2051
2052 chip->esr_flt_cold_temp_en = cold_temp;
2053 fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n",
2054 cold_temp ? "cold" : "normal");
2055 return 0;
2056}
2057
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002058static int fg_esr_fcc_config(struct fg_chip *chip)
2059{
2060 union power_supply_propval prop = {0, };
2061 int rc;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002062 bool parallel_en = false, qnovo_en;
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002063
2064 if (is_parallel_charger_available(chip)) {
2065 rc = power_supply_get_property(chip->parallel_psy,
2066 POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop);
2067 if (rc < 0) {
2068 pr_err("Error in reading charging_enabled from parallel_psy, rc=%d\n",
2069 rc);
2070 return rc;
2071 }
2072 parallel_en = prop.intval;
2073 }
2074
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002075 qnovo_en = is_qnovo_en(chip);
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002076
2077 fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
2078 chip->charge_status, parallel_en, qnovo_en,
2079 chip->esr_fcc_ctrl_en);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002080
Nicholas Troast1769fd32016-09-07 09:20:58 -07002081 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002082 (parallel_en || qnovo_en)) {
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002083 if (chip->esr_fcc_ctrl_en)
2084 return 0;
2085
2086 /*
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002087 * When parallel charging or Qnovo is enabled, configure ESR
2088 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
2089 * request the main charger to increase FCC when it is supposed
2090 * to decrease it.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002091 */
2092 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2093 ESR_FAST_CRG_IVAL_MASK |
2094 ESR_FAST_CRG_CTL_EN_BIT,
2095 ESR_FCC_300MA | ESR_FAST_CRG_CTL_EN_BIT);
2096 if (rc < 0) {
2097 pr_err("Error in writing to %04x, rc=%d\n",
2098 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2099 return rc;
2100 }
2101
2102 chip->esr_fcc_ctrl_en = true;
2103 } else {
2104 if (!chip->esr_fcc_ctrl_en)
2105 return 0;
2106
2107 /*
2108 * If we're here, then it means either the device is not in
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002109 * charging state or parallel charging / Qnovo is disabled.
2110 * Disable ESR fast charge current control in SW.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002111 */
2112 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2113 ESR_FAST_CRG_CTL_EN_BIT, 0);
2114 if (rc < 0) {
2115 pr_err("Error in writing to %04x, rc=%d\n",
2116 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2117 return rc;
2118 }
2119
2120 chip->esr_fcc_ctrl_en = false;
2121 }
2122
2123 fg_dbg(chip, FG_STATUS, "esr_fcc_ctrl_en set to %d\n",
2124 chip->esr_fcc_ctrl_en);
2125 return 0;
2126}
2127
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002128static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
2129{
2130 int rc, cycles_init, cycles_max;
2131 bool end_of_charge = false;
2132
2133 end_of_charge = is_input_present(chip) && chip->charge_done;
2134 fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
2135
2136 /* ESR discharging timer configuration */
2137 cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
2138 chip->dt.esr_timer_awake[TIMER_RETRY];
2139 if (end_of_charge)
2140 cycles_init = 0;
2141
2142 cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
2143 chip->dt.esr_timer_awake[TIMER_MAX];
2144
2145 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
2146 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2147 if (rc < 0) {
2148 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2149 return rc;
2150 }
2151
2152 /* ESR charging timer configuration */
2153 cycles_init = cycles_max = -EINVAL;
2154 if (end_of_charge || sleep) {
2155 cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
2156 cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
2157 } else if (is_input_present(chip)) {
2158 cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
2159 cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
2160 }
2161
2162 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
2163 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2164 if (rc < 0) {
2165 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2166 return rc;
2167 }
2168
2169 return 0;
2170}
2171
Nicholas Troast805c2422017-07-06 14:53:46 -07002172static void fg_ttf_update(struct fg_chip *chip)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002173{
Nicholas Troast805c2422017-07-06 14:53:46 -07002174 int rc;
2175 int delay_ms;
2176 union power_supply_propval prop = {0, };
2177 int online = 0;
2178
2179 if (usb_psy_initialized(chip)) {
2180 rc = power_supply_get_property(chip->usb_psy,
2181 POWER_SUPPLY_PROP_ONLINE, &prop);
2182 if (rc < 0) {
2183 pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
2184 return;
2185 }
2186
2187 online = online || prop.intval;
2188 }
2189
2190 if (pc_port_psy_initialized(chip)) {
2191 rc = power_supply_get_property(chip->pc_port_psy,
2192 POWER_SUPPLY_PROP_ONLINE, &prop);
2193 if (rc < 0) {
2194 pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
2195 return;
2196 }
2197
2198 online = online || prop.intval;
2199 }
2200
2201 if (dc_psy_initialized(chip)) {
2202 rc = power_supply_get_property(chip->dc_psy,
2203 POWER_SUPPLY_PROP_ONLINE, &prop);
2204 if (rc < 0) {
2205 pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
2206 return;
2207 }
2208
2209 online = online || prop.intval;
2210 }
2211
2212
2213 if (chip->online_status == online)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002214 return;
2215
Nicholas Troast805c2422017-07-06 14:53:46 -07002216 chip->online_status = online;
2217 if (online)
2218 /* wait 35 seconds for the input to settle */
2219 delay_ms = 35000;
2220 else
2221 /* wait 5 seconds for current to settle during discharge */
2222 delay_ms = 5000;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002223
Nicholas Troast805c2422017-07-06 14:53:46 -07002224 vote(chip->awake_votable, TTF_PRIMING, true, 0);
2225 cancel_delayed_work_sync(&chip->ttf_work);
2226 mutex_lock(&chip->ttf.lock);
2227 fg_circ_buf_clr(&chip->ttf.ibatt);
2228 fg_circ_buf_clr(&chip->ttf.vbatt);
2229 mutex_unlock(&chip->ttf.lock);
2230 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
Nicholas Troast1769fd32016-09-07 09:20:58 -07002231}
2232
Nicholas Troaste29dec92016-08-24 09:35:11 -07002233static void status_change_work(struct work_struct *work)
2234{
2235 struct fg_chip *chip = container_of(work,
2236 struct fg_chip, status_change_work);
2237 union power_supply_propval prop = {0, };
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002238 int rc, batt_temp;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002239
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002240 if (!batt_psy_initialized(chip)) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002241 fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002242 goto out;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002243 }
2244
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002245 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
Nicholas Troaste29dec92016-08-24 09:35:11 -07002246 &prop);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002247 if (rc < 0) {
2248 pr_err("Error in getting charging status, rc=%d\n", rc);
2249 goto out;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002250 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002251
Nicholas Troast1769fd32016-09-07 09:20:58 -07002252 chip->prev_charge_status = chip->charge_status;
2253 chip->charge_status = prop.intval;
2254 rc = power_supply_get_property(chip->batt_psy,
2255 POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
2256 if (rc < 0) {
2257 pr_err("Error in getting charge type, rc=%d\n", rc);
2258 goto out;
2259 }
2260
2261 chip->charge_type = prop.intval;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002262 rc = power_supply_get_property(chip->batt_psy,
2263 POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
2264 if (rc < 0) {
2265 pr_err("Error in getting charge_done, rc=%d\n", rc);
2266 goto out;
2267 }
2268
2269 chip->charge_done = prop.intval;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002270 if (chip->cyc_ctr.en)
2271 schedule_work(&chip->cycle_count_work);
2272
2273 fg_cap_learning_update(chip);
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07002274
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002275 rc = fg_charge_full_update(chip);
2276 if (rc < 0)
2277 pr_err("Error in charge_full_update, rc=%d\n", rc);
2278
2279 rc = fg_adjust_recharge_soc(chip);
2280 if (rc < 0)
2281 pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002282
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07002283 rc = fg_adjust_ki_coeff_dischg(chip);
2284 if (rc < 0)
2285 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002286
2287 rc = fg_esr_fcc_config(chip);
2288 if (rc < 0)
2289 pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002290
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002291 rc = fg_esr_timer_config(chip, false);
2292 if (rc < 0)
2293 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
2294
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002295 rc = fg_get_battery_temp(chip, &batt_temp);
2296 if (!rc) {
2297 rc = fg_slope_limit_config(chip, batt_temp);
2298 if (rc < 0)
2299 pr_err("Error in configuring slope limiter rc:%d\n",
2300 rc);
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07002301
2302 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
2303 if (rc < 0)
2304 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
2305 rc);
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002306 }
2307
Nicholas Troast805c2422017-07-06 14:53:46 -07002308 fg_ttf_update(chip);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002309
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002310out:
Nicholas Troast1769fd32016-09-07 09:20:58 -07002311 fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
2312 chip->charge_status, chip->charge_type, chip->charge_done);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002313 pm_relax(chip->dev);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002314}
2315
2316static void restore_cycle_counter(struct fg_chip *chip)
2317{
2318 int rc = 0, i;
2319 u8 data[2];
2320
2321 mutex_lock(&chip->cyc_ctr.lock);
2322 for (i = 0; i < BUCKET_COUNT; i++) {
2323 rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
2324 CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
2325 FG_IMA_DEFAULT);
2326 if (rc < 0)
2327 pr_err("failed to read bucket %d rc=%d\n", i, rc);
2328 else
2329 chip->cyc_ctr.count[i] = data[0] | data[1] << 8;
2330 }
2331 mutex_unlock(&chip->cyc_ctr.lock);
2332}
2333
2334static void clear_cycle_counter(struct fg_chip *chip)
2335{
2336 int rc = 0, i;
2337
2338 if (!chip->cyc_ctr.en)
2339 return;
2340
2341 mutex_lock(&chip->cyc_ctr.lock);
2342 memset(chip->cyc_ctr.count, 0, sizeof(chip->cyc_ctr.count));
2343 for (i = 0; i < BUCKET_COUNT; i++) {
2344 chip->cyc_ctr.started[i] = false;
2345 chip->cyc_ctr.last_soc[i] = 0;
2346 }
2347 rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET,
2348 (u8 *)&chip->cyc_ctr.count,
2349 sizeof(chip->cyc_ctr.count) / sizeof(u8 *),
2350 FG_IMA_DEFAULT);
2351 if (rc < 0)
2352 pr_err("failed to clear cycle counter rc=%d\n", rc);
2353
2354 mutex_unlock(&chip->cyc_ctr.lock);
2355}
2356
2357static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
2358{
2359 int rc = 0;
2360 u16 cyc_count;
2361 u8 data[2];
2362
2363 if (bucket < 0 || (bucket > BUCKET_COUNT - 1))
2364 return 0;
2365
2366 cyc_count = chip->cyc_ctr.count[bucket];
2367 cyc_count++;
2368 data[0] = cyc_count & 0xFF;
2369 data[1] = cyc_count >> 8;
2370
2371 rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
2372 CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
2373 FG_IMA_DEFAULT);
2374 if (rc < 0)
2375 pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
2376 bucket, rc);
2377 else
2378 chip->cyc_ctr.count[bucket] = cyc_count;
2379 return rc;
2380}
2381
2382static void cycle_count_work(struct work_struct *work)
2383{
2384 int rc = 0, bucket, i, batt_soc;
2385 struct fg_chip *chip = container_of(work,
2386 struct fg_chip,
2387 cycle_count_work);
2388
2389 mutex_lock(&chip->cyc_ctr.lock);
2390 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
2391 if (rc < 0) {
2392 pr_err("Failed to read battery soc rc: %d\n", rc);
2393 goto out;
2394 }
2395
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002396 /* We need only the most significant byte here */
2397 batt_soc = (u32)batt_soc >> 24;
2398
Nicholas Troast1769fd32016-09-07 09:20:58 -07002399 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002400 /* Find out which bucket the SOC falls in */
2401 bucket = batt_soc / BUCKET_SOC_PCT;
2402 pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
2403
2404 /*
2405 * If we've started counting for the previous bucket,
2406 * then store the counter for that bucket if the
2407 * counter for current bucket is getting started.
2408 */
2409 if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
2410 !chip->cyc_ctr.started[bucket]) {
2411 rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
2412 if (rc < 0) {
2413 pr_err("Error in storing cycle_ctr rc: %d\n",
2414 rc);
2415 goto out;
2416 } else {
2417 chip->cyc_ctr.started[bucket - 1] = false;
2418 chip->cyc_ctr.last_soc[bucket - 1] = 0;
2419 }
2420 }
2421 if (!chip->cyc_ctr.started[bucket]) {
2422 chip->cyc_ctr.started[bucket] = true;
2423 chip->cyc_ctr.last_soc[bucket] = batt_soc;
2424 }
2425 } else {
2426 for (i = 0; i < BUCKET_COUNT; i++) {
2427 if (chip->cyc_ctr.started[i] &&
2428 batt_soc > chip->cyc_ctr.last_soc[i]) {
2429 rc = fg_inc_store_cycle_ctr(chip, i);
2430 if (rc < 0)
2431 pr_err("Error in storing cycle_ctr rc: %d\n",
2432 rc);
2433 chip->cyc_ctr.last_soc[i] = 0;
2434 }
2435 chip->cyc_ctr.started[i] = false;
2436 }
2437 }
2438out:
2439 mutex_unlock(&chip->cyc_ctr.lock);
2440}
2441
2442static int fg_get_cycle_count(struct fg_chip *chip)
2443{
2444 int count;
2445
2446 if (!chip->cyc_ctr.en)
2447 return 0;
2448
2449 if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT))
2450 return -EINVAL;
2451
2452 mutex_lock(&chip->cyc_ctr.lock);
2453 count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1];
2454 mutex_unlock(&chip->cyc_ctr.lock);
2455 return count;
2456}
2457
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002458static int fg_bp_params_config(struct fg_chip *chip)
2459{
2460 int rc = 0;
2461 u8 buf;
2462
2463 /* This SRAM register is only present in v2.0 and above */
2464 if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
2465 chip->bp.float_volt_uv > 0) {
2466 fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
2467 chip->bp.float_volt_uv / 1000, &buf);
2468 rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
2469 chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
2470 chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
2471 if (rc < 0) {
2472 pr_err("Error in writing float_volt, rc=%d\n", rc);
2473 return rc;
2474 }
2475 }
2476
2477 if (chip->bp.vbatt_full_mv > 0) {
2478 rc = fg_set_constant_chg_voltage(chip,
2479 chip->bp.vbatt_full_mv * 1000);
2480 if (rc < 0)
2481 return rc;
2482 }
2483
2484 return rc;
2485}
2486
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002487#define PROFILE_LOAD_BIT BIT(0)
2488#define BOOTLOADER_LOAD_BIT BIT(1)
2489#define BOOTLOADER_RESTART_BIT BIT(2)
2490#define HLOS_RESTART_BIT BIT(3)
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002491static bool is_profile_load_required(struct fg_chip *chip)
2492{
Nicholas Troaste29dec92016-08-24 09:35:11 -07002493 u8 buf[PROFILE_COMP_LEN], val;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002494 bool profiles_same = false;
2495 int rc;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002496
Nicholas Troaste29dec92016-08-24 09:35:11 -07002497 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
2498 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2499 if (rc < 0) {
2500 pr_err("failed to read profile integrity rc=%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002501 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002502 }
2503
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002504 /* Check if integrity bit is set */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002505 if (val & PROFILE_LOAD_BIT) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002506 fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
Subbaraman Narayanamurthy73616e12017-03-20 14:37:54 -07002507
2508 /* Whitelist the values */
2509 val &= ~PROFILE_LOAD_BIT;
2510 if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
2511 val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
2512 val |= PROFILE_LOAD_BIT;
2513 pr_warn("Garbage value in profile integrity word: 0x%x\n",
2514 val);
2515 return true;
2516 }
2517
Nicholas Troaste29dec92016-08-24 09:35:11 -07002518 rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2519 buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
2520 if (rc < 0) {
2521 pr_err("Error in reading battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002522 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002523 }
2524 profiles_same = memcmp(chip->batt_profile, buf,
2525 PROFILE_COMP_LEN) == 0;
2526 if (profiles_same) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002527 fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
2528 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002529 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002530
2531 if (!chip->dt.force_load_profile) {
2532 pr_warn("Profiles doesn't match, skipping loading it since force_load_profile is disabled\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002533 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002534 pr_info("FG: loaded profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002535 dump_sram(buf, PROFILE_LOAD_WORD,
2536 PROFILE_COMP_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002537 pr_info("FG: available profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002538 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2539 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002540 }
2541 return false;
2542 }
2543
2544 fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n");
2545 } else {
2546 fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002547 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002548 pr_info("FG: profile to be loaded:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002549 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2550 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002551 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002552 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002553 return true;
2554}
2555
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08002556static void clear_battery_profile(struct fg_chip *chip)
2557{
2558 u8 val = 0;
2559 int rc;
2560
2561 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2562 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2563 if (rc < 0)
2564 pr_err("failed to write profile integrity rc=%d\n", rc);
2565}
2566
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002567#define SOC_READY_WAIT_MS 2000
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002568static int __fg_restart(struct fg_chip *chip)
2569{
2570 int rc, msoc;
2571 bool tried_again = false;
2572
2573 rc = fg_get_prop_capacity(chip, &msoc);
2574 if (rc < 0) {
2575 pr_err("Error in getting capacity, rc=%d\n", rc);
2576 return rc;
2577 }
2578
2579 chip->last_soc = msoc;
2580 chip->fg_restarting = true;
2581 reinit_completion(&chip->soc_ready);
2582 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT,
2583 RESTART_GO_BIT);
2584 if (rc < 0) {
2585 pr_err("Error in writing to %04x, rc=%d\n",
2586 BATT_SOC_RESTART(chip), rc);
2587 goto out;
2588 }
2589
2590wait:
2591 rc = wait_for_completion_interruptible_timeout(&chip->soc_ready,
2592 msecs_to_jiffies(SOC_READY_WAIT_MS));
2593
2594 /* If we were interrupted wait again one more time. */
2595 if (rc == -ERESTARTSYS && !tried_again) {
2596 tried_again = true;
2597 goto wait;
2598 } else if (rc <= 0) {
2599 pr_err("wait for soc_ready timed out rc=%d\n", rc);
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002600 }
2601
2602 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2603 if (rc < 0) {
2604 pr_err("Error in writing to %04x, rc=%d\n",
2605 BATT_SOC_RESTART(chip), rc);
2606 goto out;
2607 }
2608out:
2609 chip->fg_restarting = false;
2610 return rc;
2611}
2612
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002613static void profile_load_work(struct work_struct *work)
2614{
2615 struct fg_chip *chip = container_of(work,
2616 struct fg_chip,
2617 profile_load_work.work);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002618 u8 buf[2], val;
2619 int rc;
2620
2621 vote(chip->awake_votable, PROFILE_LOAD, true, 0);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07002622
2623 rc = fg_get_batt_id(chip);
2624 if (rc < 0) {
2625 pr_err("Error in getting battery id, rc:%d\n", rc);
2626 goto out;
2627 }
2628
2629 rc = fg_get_batt_profile(chip);
2630 if (rc < 0) {
2631 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
2632 chip->batt_id_ohms / 1000, rc);
2633 goto out;
2634 }
2635
2636 if (!chip->profile_available)
2637 goto out;
2638
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002639 if (!is_profile_load_required(chip))
2640 goto done;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002641
2642 clear_cycle_counter(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002643 mutex_lock(&chip->cl.lock);
2644 chip->cl.learned_cc_uah = 0;
2645 chip->cl.active = false;
2646 mutex_unlock(&chip->cl.lock);
2647
Nicholas Troaste29dec92016-08-24 09:35:11 -07002648 fg_dbg(chip, FG_STATUS, "profile loading started\n");
2649 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2650 if (rc < 0) {
2651 pr_err("Error in writing to %04x, rc=%d\n",
2652 BATT_SOC_RESTART(chip), rc);
2653 goto out;
2654 }
2655
2656 /* load battery profile */
2657 rc = fg_sram_write(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2658 chip->batt_profile, PROFILE_LEN, FG_IMA_ATOMIC);
2659 if (rc < 0) {
2660 pr_err("Error in writing battery profile, rc:%d\n", rc);
2661 goto out;
2662 }
2663
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002664 rc = __fg_restart(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002665 if (rc < 0) {
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002666 pr_err("Error in restarting FG, rc=%d\n", rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002667 goto out;
2668 }
2669
2670 fg_dbg(chip, FG_STATUS, "SOC is ready\n");
2671
2672 /* Set the profile integrity bit */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002673 val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002674 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2675 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2676 if (rc < 0) {
2677 pr_err("failed to write profile integrity rc=%d\n", rc);
2678 goto out;
2679 }
2680
Nicholas Troaste29dec92016-08-24 09:35:11 -07002681done:
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002682 rc = fg_bp_params_config(chip);
2683 if (rc < 0)
2684 pr_err("Error in configuring battery profile params, rc:%d\n",
2685 rc);
2686
Nicholas Troaste29dec92016-08-24 09:35:11 -07002687 rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
2688 FG_IMA_DEFAULT);
2689 if (rc < 0) {
2690 pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD,
2691 NOM_CAP_OFFSET, rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002692 } else {
2693 chip->cl.nom_cap_uah = (int)(buf[0] | buf[1] << 8) * 1000;
2694 rc = fg_load_learned_cap_from_sram(chip);
2695 if (rc < 0)
2696 pr_err("Error in loading capacity learning data, rc:%d\n",
2697 rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002698 }
2699
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002700 batt_psy_initialized(chip);
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07002701 fg_notify_charger(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002702 chip->profile_loaded = true;
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002703 fg_dbg(chip, FG_STATUS, "profile loaded successfully");
Nicholas Troaste29dec92016-08-24 09:35:11 -07002704out:
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07002705 chip->soc_reporting_ready = true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002706 vote(chip->awake_votable, PROFILE_LOAD, false, 0);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002707}
2708
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002709static void sram_dump_work(struct work_struct *work)
2710{
2711 struct fg_chip *chip = container_of(work, struct fg_chip,
2712 sram_dump_work.work);
2713 u8 buf[FG_SRAM_LEN];
2714 int rc;
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302715 s64 timestamp_ms, quotient;
2716 s32 remainder;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002717
2718 rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
2719 if (rc < 0) {
2720 pr_err("Error in reading FG SRAM, rc:%d\n", rc);
2721 goto resched;
2722 }
2723
2724 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302725 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2726 fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
2727 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002728 dump_sram(buf, 0, FG_SRAM_LEN);
2729 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302730 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2731 fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
2732 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002733resched:
2734 schedule_delayed_work(&chip->sram_dump_work,
2735 msecs_to_jiffies(fg_sram_dump_period_ms));
2736}
2737
2738static int fg_sram_dump_sysfs(const char *val, const struct kernel_param *kp)
2739{
2740 int rc;
2741 struct power_supply *bms_psy;
2742 struct fg_chip *chip;
2743 bool old_val = fg_sram_dump;
2744
2745 rc = param_set_bool(val, kp);
2746 if (rc) {
2747 pr_err("Unable to set fg_sram_dump: %d\n", rc);
2748 return rc;
2749 }
2750
2751 if (fg_sram_dump == old_val)
2752 return 0;
2753
2754 bms_psy = power_supply_get_by_name("bms");
2755 if (!bms_psy) {
2756 pr_err("bms psy not found\n");
2757 return -ENODEV;
2758 }
2759
2760 chip = power_supply_get_drvdata(bms_psy);
2761 if (fg_sram_dump)
2762 schedule_delayed_work(&chip->sram_dump_work,
2763 msecs_to_jiffies(fg_sram_dump_period_ms));
2764 else
2765 cancel_delayed_work_sync(&chip->sram_dump_work);
2766
2767 return 0;
2768}
2769
2770static struct kernel_param_ops fg_sram_dump_ops = {
2771 .set = fg_sram_dump_sysfs,
2772 .get = param_get_bool,
2773};
2774
2775module_param_cb(sram_dump_en, &fg_sram_dump_ops, &fg_sram_dump, 0644);
2776
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002777static int fg_restart_sysfs(const char *val, const struct kernel_param *kp)
2778{
2779 int rc;
2780 struct power_supply *bms_psy;
2781 struct fg_chip *chip;
2782
2783 rc = param_set_int(val, kp);
2784 if (rc) {
2785 pr_err("Unable to set fg_restart: %d\n", rc);
2786 return rc;
2787 }
2788
2789 if (fg_restart != 1) {
2790 pr_err("Bad value %d\n", fg_restart);
2791 return -EINVAL;
2792 }
2793
2794 bms_psy = power_supply_get_by_name("bms");
2795 if (!bms_psy) {
2796 pr_err("bms psy not found\n");
2797 return 0;
2798 }
2799
2800 chip = power_supply_get_drvdata(bms_psy);
2801 rc = __fg_restart(chip);
2802 if (rc < 0) {
2803 pr_err("Error in restarting FG, rc=%d\n", rc);
2804 return rc;
2805 }
2806
2807 pr_info("FG restart done\n");
2808 return rc;
2809}
2810
2811static struct kernel_param_ops fg_restart_ops = {
2812 .set = fg_restart_sysfs,
2813 .get = param_get_int,
2814};
2815
2816module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
2817
Nicholas Troast1769fd32016-09-07 09:20:58 -07002818#define HOURS_TO_SECONDS 3600
2819#define OCV_SLOPE_UV 10869
2820#define MILLI_UNIT 1000
2821#define MICRO_UNIT 1000000
Nicholas Troast805c2422017-07-06 14:53:46 -07002822#define NANO_UNIT 1000000000
2823static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002824{
Nicholas Troast805c2422017-07-06 14:53:46 -07002825 int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07002826 i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
2827 i, soc_per_step, msoc_this_step, msoc_next_step,
2828 ibatt_this_step, t_predicted_this_step,
Nicholas Troast805c2422017-07-06 14:53:46 -07002829 t_predicted_cv, t_predicted = 0;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002830
2831 if (chip->bp.float_volt_uv <= 0) {
2832 pr_err("battery profile is not loaded\n");
2833 return -ENODATA;
2834 }
2835
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002836 if (!batt_psy_initialized(chip)) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07002837 fg_dbg(chip, FG_TTF, "charger is not available\n");
2838 return -ENODATA;
2839 }
2840
Nicholas Troast32a22d32016-12-14 16:12:04 -08002841 rc = fg_get_prop_capacity(chip, &msoc);
2842 if (rc < 0) {
2843 pr_err("failed to get msoc rc=%d\n", rc);
2844 return rc;
2845 }
2846 fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
2847
Nicholas Troast805c2422017-07-06 14:53:46 -07002848 /* the battery is considered full if the SOC is 100% */
Nicholas Troast32a22d32016-12-14 16:12:04 -08002849 if (msoc >= 100) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07002850 *val = 0;
2851 return 0;
2852 }
2853
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07002854 if (is_qnovo_en(chip))
2855 ttf_mode = TTF_MODE_QNOVO;
2856 else
2857 ttf_mode = TTF_MODE_NORMAL;
2858
2859 /* when switching TTF algorithms the TTF needs to be reset */
2860 if (chip->ttf.mode != ttf_mode) {
2861 fg_circ_buf_clr(&chip->ttf.ibatt);
2862 fg_circ_buf_clr(&chip->ttf.vbatt);
2863 chip->ttf.mode = ttf_mode;
2864 }
2865
Nicholas Troast805c2422017-07-06 14:53:46 -07002866 /* at least 10 samples are required to produce a stable IBATT */
2867 if (chip->ttf.ibatt.size < 10) {
2868 *val = -1;
2869 return 0;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002870 }
2871
Nicholas Troast805c2422017-07-06 14:53:46 -07002872 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002873 if (rc < 0) {
Nicholas Troast805c2422017-07-06 14:53:46 -07002874 pr_err("failed to get IBATT AVG rc=%d\n", rc);
2875 return rc;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002876 }
2877
Nicholas Troast805c2422017-07-06 14:53:46 -07002878 rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
2879 if (rc < 0) {
2880 pr_err("failed to get VBATT AVG rc=%d\n", rc);
2881 return rc;
2882 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07002883
Nicholas Troast805c2422017-07-06 14:53:46 -07002884 ibatt_avg = -ibatt_avg / MILLI_UNIT;
2885 vbatt_avg /= MILLI_UNIT;
2886
2887 /* clamp ibatt_avg to iterm */
2888 if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
2889 ibatt_avg = abs(chip->dt.sys_term_curr_ma);
2890
Nicholas Troast1769fd32016-09-07 09:20:58 -07002891 fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
Nicholas Troast805c2422017-07-06 14:53:46 -07002892 fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002893
2894 rc = fg_get_battery_resistance(chip, &rbatt);
2895 if (rc < 0) {
2896 pr_err("failed to get battery resistance rc=%d\n", rc);
2897 return rc;
2898 }
2899
Nicholas Troast805c2422017-07-06 14:53:46 -07002900 rbatt /= MILLI_UNIT;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002901 fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
2902
Nicholas Troast805c2422017-07-06 14:53:46 -07002903 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002904 if (rc < 0) {
2905 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
2906 return rc;
2907 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07002908
Nicholas Troast1769fd32016-09-07 09:20:58 -07002909 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
2910 if (rc < 0) {
2911 pr_err("failed to get full soc rc=%d\n", rc);
2912 return rc;
2913 }
2914 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
2915 FULL_SOC_RAW);
Nicholas Troast805c2422017-07-06 14:53:46 -07002916 act_cap_mah = full_soc * act_cap_mah / 100;
2917 fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
2918
2919 /* estimated battery current at the CC to CV transition */
2920 switch (chip->ttf.mode) {
2921 case TTF_MODE_NORMAL:
2922 i_cc2cv = ibatt_avg * vbatt_avg /
2923 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
2924 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07002925 case TTF_MODE_QNOVO:
2926 i_cc2cv = min(
2927 chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
2928 ibatt_avg * vbatt_avg /
2929 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
2930 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07002931 default:
2932 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
2933 break;
2934 }
2935 fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002936
2937 /* if we are already in CV state then we can skip estimating CC */
2938 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
Nicholas Troast805c2422017-07-06 14:53:46 -07002939 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002940
Nicholas Troast1769fd32016-09-07 09:20:58 -07002941 /* estimated SOC at the CC to CV transition */
Nicholas Troast805c2422017-07-06 14:53:46 -07002942 soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002943 soc_cc2cv = 100 - soc_cc2cv;
2944 fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
2945
Nicholas Troast805c2422017-07-06 14:53:46 -07002946 switch (chip->ttf.mode) {
2947 case TTF_MODE_NORMAL:
2948 if (soc_cc2cv - msoc <= 0)
2949 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002950
Nicholas Troast805c2422017-07-06 14:53:46 -07002951 divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
2952 t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
2953 HOURS_TO_SECONDS, divisor);
2954 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07002955 case TTF_MODE_QNOVO:
2956 soc_per_step = 100 / MAX_CC_STEPS;
2957 for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
2958 msoc_next_step = (i + 1) * soc_per_step;
2959 if (i == msoc / soc_per_step)
2960 msoc_this_step = msoc;
2961 else
2962 msoc_this_step = i * soc_per_step;
2963
2964 /* scale ibatt by 85% to account for discharge pulses */
2965 ibatt_this_step = min(
2966 chip->ttf.cc_step.arr[i] / MILLI_UNIT,
2967 ibatt_avg) * 85 / 100;
2968 divisor = max(100, ibatt_this_step * 100);
2969 t_predicted_this_step = div_s64((s64)act_cap_mah *
2970 (msoc_next_step - msoc_this_step) *
2971 HOURS_TO_SECONDS, divisor);
2972 t_predicted += t_predicted_this_step;
2973 fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
2974 msoc_this_step, msoc_next_step,
2975 ibatt_this_step, t_predicted_this_step);
2976 }
2977 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07002978 default:
2979 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
2980 break;
2981 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07002982
Nicholas Troast805c2422017-07-06 14:53:46 -07002983cv_estimate:
2984 fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002985
Nicholas Troast805c2422017-07-06 14:53:46 -07002986 iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
2987 fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
2988
2989 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
2990 tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002991 else
Nicholas Troast805c2422017-07-06 14:53:46 -07002992 tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002993
Nicholas Troast805c2422017-07-06 14:53:46 -07002994 rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
2995 if (rc < 0) {
2996 pr_err("failed to interpolate tau rc=%d\n", rc);
2997 return rc;
2998 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07002999
Nicholas Troast805c2422017-07-06 14:53:46 -07003000 /* tau is scaled linearly from 95% to 100% SOC */
3001 if (msoc >= 95)
3002 tau = tau * 2 * (100 - msoc) / 10;
3003
3004 fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
3005 t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
3006 HOURS_TO_SECONDS, NANO_UNIT);
3007 fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
3008 t_predicted += t_predicted_cv;
3009
3010 /* clamp the ttf to 0 */
3011 if (t_predicted < 0)
3012 t_predicted = 0;
3013
3014 fg_dbg(chip, FG_TTF, "t_predicted=%d\n", t_predicted);
3015 *val = t_predicted;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003016 return 0;
3017}
3018
Nicholas Troast805c2422017-07-06 14:53:46 -07003019static int fg_get_time_to_full(struct fg_chip *chip, int *val)
3020{
3021 int rc;
3022
3023 mutex_lock(&chip->ttf.lock);
3024 rc = fg_get_time_to_full_locked(chip, val);
3025 mutex_unlock(&chip->ttf.lock);
3026 return rc;
3027}
3028
Nicholas Troast1769fd32016-09-07 09:20:58 -07003029#define CENTI_ICORRECT_C0 105
3030#define CENTI_ICORRECT_C1 20
3031static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
3032{
Nicholas Troast805c2422017-07-06 14:53:46 -07003033 int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003034
Nicholas Troast805c2422017-07-06 14:53:46 -07003035 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003036 if (rc < 0) {
3037 /* try to get instantaneous current */
3038 rc = fg_get_battery_current(chip, &ibatt_avg);
3039 if (rc < 0) {
3040 pr_err("failed to get battery current, rc=%d\n", rc);
3041 return rc;
3042 }
3043 }
3044
Nicholas Troast805c2422017-07-06 14:53:46 -07003045 ibatt_avg /= MILLI_UNIT;
3046 /* clamp ibatt_avg to 100mA */
3047 if (ibatt_avg < 100)
3048 ibatt_avg = 100;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003049
3050 rc = fg_get_prop_capacity(chip, &msoc);
3051 if (rc < 0) {
3052 pr_err("Error in getting capacity, rc=%d\n", rc);
3053 return rc;
3054 }
3055
Nicholas Troast805c2422017-07-06 14:53:46 -07003056 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
3057 if (rc < 0) {
3058 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
3059 return rc;
3060 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003061
Nicholas Troast805c2422017-07-06 14:53:46 -07003062 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3063 if (rc < 0) {
3064 pr_err("failed to get full soc rc=%d\n", rc);
3065 return rc;
3066 }
3067 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3068 FULL_SOC_RAW);
3069 act_cap_mah = full_soc * act_cap_mah / 100;
3070
3071 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
3072 divisor = ibatt_avg * divisor / 100;
3073 divisor = max(100, divisor);
3074 *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003075 return 0;
3076}
3077
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003078static int fg_update_maint_soc(struct fg_chip *chip)
3079{
3080 int rc = 0, msoc;
3081
3082 mutex_lock(&chip->charge_full_lock);
3083 if (chip->delta_soc <= 0)
3084 goto out;
3085
3086 rc = fg_get_msoc(chip, &msoc);
3087 if (rc < 0) {
3088 pr_err("Error in getting msoc, rc=%d\n", rc);
3089 goto out;
3090 }
3091
3092 if (msoc > chip->maint_soc) {
3093 /*
3094 * When the monotonic SOC goes above maintenance SOC, we should
3095 * stop showing the maintenance SOC.
3096 */
3097 chip->delta_soc = 0;
3098 chip->maint_soc = 0;
3099 } else if (msoc <= chip->last_msoc) {
3100 /* MSOC is decreasing. Decrease maintenance SOC as well */
3101 chip->maint_soc -= 1;
3102 if (!(msoc % 10)) {
3103 /*
3104 * Reduce the maintenance SOC additionally by 1 whenever
3105 * it crosses a SOC multiple of 10.
3106 */
3107 chip->maint_soc -= 1;
3108 chip->delta_soc -= 1;
3109 }
3110 }
3111
3112 fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
3113 msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
3114 chip->last_msoc = msoc;
3115out:
3116 mutex_unlock(&chip->charge_full_lock);
3117 return rc;
3118}
3119
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003120static int fg_esr_validate(struct fg_chip *chip)
3121{
3122 int rc, esr_uohms;
3123 u8 buf[2];
3124
3125 if (chip->dt.esr_clamp_mohms <= 0)
3126 return 0;
3127
3128 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
3129 if (rc < 0) {
3130 pr_err("failed to get ESR, rc=%d\n", rc);
3131 return rc;
3132 }
3133
3134 if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) {
3135 pr_debug("ESR %d is > ESR_clamp\n", esr_uohms);
3136 return 0;
3137 }
3138
3139 esr_uohms = chip->dt.esr_clamp_mohms * 1000;
3140 fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf);
3141 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word,
3142 chip->sp[FG_SRAM_ESR].addr_byte, buf,
3143 chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT);
3144 if (rc < 0) {
3145 pr_err("Error in writing ESR, rc=%d\n", rc);
3146 return rc;
3147 }
3148
3149 fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms);
3150 return 0;
3151}
3152
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003153static int fg_force_esr_meas(struct fg_chip *chip)
3154{
3155 int rc;
3156 int esr_uohms;
3157
3158 /* force esr extraction enable */
3159 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3160 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
3161 FG_IMA_DEFAULT);
3162 if (rc < 0) {
3163 pr_err("failed to enable esr extn rc=%d\n", rc);
3164 return rc;
3165 }
3166
3167 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3168 LD_REG_CTRL_BIT, 0);
3169 if (rc < 0) {
3170 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
3171 return rc;
3172 }
3173
3174 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3175 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3176 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
3177 if (rc < 0) {
3178 pr_err("Error in configuring force ESR rc=%d\n", rc);
3179 return rc;
3180 }
3181
3182 /* wait 1.5 seconds for hw to measure ESR */
3183 msleep(1500);
3184 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3185 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3186 0);
3187 if (rc < 0) {
3188 pr_err("Error in restoring force ESR rc=%d\n", rc);
3189 return rc;
3190 }
3191
3192 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3193 LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
3194 if (rc < 0) {
3195 pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
3196 return rc;
3197 }
3198
3199 /* force esr extraction disable */
3200 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3201 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0,
3202 FG_IMA_DEFAULT);
3203 if (rc < 0) {
3204 pr_err("failed to disable esr extn rc=%d\n", rc);
3205 return rc;
3206 }
3207
3208 fg_get_battery_resistance(chip, &esr_uohms);
3209 fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
3210
3211 return rc;
3212}
3213
3214static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
3215{
3216 int rc;
3217
3218 /* force esr extraction disable when qnovo enables */
3219 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3220 ESR_EXTRACTION_ENABLE_OFFSET,
3221 BIT(0), qnovo_enable ? 0 : BIT(0),
3222 FG_IMA_DEFAULT);
3223 if (rc < 0)
3224 pr_err("Error in configuring esr extraction rc=%d\n", rc);
3225
3226 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3227 LD_REG_CTRL_BIT,
3228 qnovo_enable ? LD_REG_CTRL_BIT : 0);
3229 if (rc < 0) {
3230 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
3231 return rc;
3232 }
3233 fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
3234 return 0;
3235}
Nicholas Troast805c2422017-07-06 14:53:46 -07003236
3237static void ttf_work(struct work_struct *work)
3238{
3239 struct fg_chip *chip = container_of(work, struct fg_chip,
3240 ttf_work.work);
3241 int rc, ibatt_now, vbatt_now, ttf;
3242
3243 mutex_lock(&chip->ttf.lock);
3244 if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
3245 chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
3246 goto end_work;
3247
3248 rc = fg_get_battery_current(chip, &ibatt_now);
3249 if (rc < 0) {
3250 pr_err("failed to get battery current, rc=%d\n", rc);
3251 goto end_work;
3252 }
3253
3254 rc = fg_get_battery_voltage(chip, &vbatt_now);
3255 if (rc < 0) {
3256 pr_err("failed to get battery voltage, rc=%d\n", rc);
3257 goto end_work;
3258 }
3259
3260 fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
3261 fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
3262
3263 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
3264 rc = fg_get_time_to_full_locked(chip, &ttf);
3265 if (rc < 0) {
3266 pr_err("failed to get ttf, rc=%d\n", rc);
3267 goto end_work;
3268 }
3269
3270 /* keep the wake lock and prime the IBATT and VBATT buffers */
3271 if (ttf < 0) {
3272 /* delay for one FG cycle */
3273 schedule_delayed_work(&chip->ttf_work,
3274 msecs_to_jiffies(1500));
3275 mutex_unlock(&chip->ttf.lock);
3276 return;
3277 }
3278 }
3279
3280 /* recurse every 10 seconds */
3281 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
3282end_work:
3283 vote(chip->awake_votable, TTF_PRIMING, false, 0);
3284 mutex_unlock(&chip->ttf.lock);
3285}
3286
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003287/* PSY CALLBACKS STAY HERE */
3288
3289static int fg_psy_get_property(struct power_supply *psy,
3290 enum power_supply_property psp,
3291 union power_supply_propval *pval)
3292{
3293 struct fg_chip *chip = power_supply_get_drvdata(psy);
3294 int rc = 0;
3295
3296 switch (psp) {
3297 case POWER_SUPPLY_PROP_CAPACITY:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08003298 rc = fg_get_prop_capacity(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003299 break;
3300 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08003301 if (chip->battery_missing)
3302 pval->intval = 3700000;
3303 else
3304 rc = fg_get_battery_voltage(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003305 break;
3306 case POWER_SUPPLY_PROP_CURRENT_NOW:
3307 rc = fg_get_battery_current(chip, &pval->intval);
3308 break;
3309 case POWER_SUPPLY_PROP_TEMP:
3310 rc = fg_get_battery_temp(chip, &pval->intval);
3311 break;
3312 case POWER_SUPPLY_PROP_RESISTANCE:
3313 rc = fg_get_battery_resistance(chip, &pval->intval);
3314 break;
3315 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3316 rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
3317 break;
3318 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003319 pval->intval = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003320 break;
3321 case POWER_SUPPLY_PROP_RESISTANCE_ID:
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08003322 pval->intval = chip->batt_id_ohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003323 break;
3324 case POWER_SUPPLY_PROP_BATTERY_TYPE:
3325 pval->strval = fg_get_battery_type(chip);
3326 break;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003327 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
3328 pval->intval = chip->bp.float_volt_uv;
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07003329 break;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003330 case POWER_SUPPLY_PROP_CYCLE_COUNT:
3331 pval->intval = fg_get_cycle_count(chip);
3332 break;
3333 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3334 pval->intval = chip->cyc_ctr.id;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003335 break;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003336 case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003337 rc = fg_get_charge_raw(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003338 break;
3339 case POWER_SUPPLY_PROP_CHARGE_NOW:
3340 pval->intval = chip->cl.init_cc_uah;
3341 break;
3342 case POWER_SUPPLY_PROP_CHARGE_FULL:
3343 pval->intval = chip->cl.learned_cc_uah;
3344 break;
3345 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003346 rc = fg_get_charge_counter(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003347 break;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003348 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
3349 rc = fg_get_time_to_full(chip, &pval->intval);
3350 break;
3351 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
3352 rc = fg_get_time_to_empty(chip, &pval->intval);
3353 break;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003354 case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
3355 pval->intval = chip->soc_reporting_ready;
3356 break;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303357 case POWER_SUPPLY_PROP_DEBUG_BATTERY:
3358 pval->intval = is_debug_batt_id(chip);
3359 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003360 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3361 rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
3362 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003363 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07003364 if ((chip->ttf.cc_step.sel >= 0) &&
3365 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
3366 pval->intval =
3367 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003368 } else {
3369 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07003370 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003371 return -EINVAL;
3372 }
3373 break;
3374 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Nicholas Troast805c2422017-07-06 14:53:46 -07003375 pval->intval = chip->ttf.cc_step.sel;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003376 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003377 default:
Nicholas Troast1769fd32016-09-07 09:20:58 -07003378 pr_err("unsupported property %d\n", psp);
3379 rc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003380 break;
3381 }
3382
Nicholas Troast1769fd32016-09-07 09:20:58 -07003383 if (rc < 0)
3384 return -ENODATA;
3385
3386 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003387}
3388
3389static int fg_psy_set_property(struct power_supply *psy,
3390 enum power_supply_property psp,
3391 const union power_supply_propval *pval)
3392{
Nicholas Troaste29dec92016-08-24 09:35:11 -07003393 struct fg_chip *chip = power_supply_get_drvdata(psy);
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003394 int rc = 0;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003395
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003396 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003397 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3398 if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) {
3399 chip->cyc_ctr.id = pval->intval;
3400 } else {
3401 pr_err("rejecting invalid cycle_count_id = %d\n",
3402 pval->intval);
3403 return -EINVAL;
3404 }
Nicholas Troast60242812017-06-20 09:33:21 -07003405 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003406 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3407 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003408 break;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003409 case POWER_SUPPLY_PROP_RESISTANCE:
3410 rc = fg_force_esr_meas(chip);
3411 break;
3412 case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
3413 rc = fg_prepare_for_qnovo(chip, pval->intval);
3414 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003415 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07003416 if ((chip->ttf.cc_step.sel >= 0) &&
3417 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
3418 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
3419 pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003420 } else {
3421 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07003422 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003423 return -EINVAL;
3424 }
3425 break;
3426 case POWER_SUPPLY_PROP_CC_STEP_SEL:
3427 if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
Nicholas Troast805c2422017-07-06 14:53:46 -07003428 chip->ttf.cc_step.sel = pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003429 } else {
3430 pr_err("cc_step_sel is out of bounds [0, %d]\n",
3431 pval->intval);
3432 return -EINVAL;
3433 }
3434 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003435 default:
3436 break;
3437 }
3438
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003439 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003440}
3441
3442static int fg_property_is_writeable(struct power_supply *psy,
3443 enum power_supply_property psp)
3444{
3445 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003446 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003447 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003448 case POWER_SUPPLY_PROP_CC_STEP:
3449 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Nicholas Troaste29dec92016-08-24 09:35:11 -07003450 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003451 default:
3452 break;
3453 }
3454
3455 return 0;
3456}
3457
3458static void fg_external_power_changed(struct power_supply *psy)
3459{
3460 pr_debug("power supply changed\n");
3461}
3462
3463static int fg_notifier_cb(struct notifier_block *nb,
3464 unsigned long event, void *data)
3465{
3466 struct power_supply *psy = data;
3467 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
3468
3469 if (event != PSY_EVENT_PROP_CHANGED)
3470 return NOTIFY_OK;
3471
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08003472 if (work_pending(&chip->status_change_work))
3473 return NOTIFY_OK;
3474
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003475 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003476 || (strcmp(psy->desc->name, "usb") == 0)) {
3477 /*
3478 * We cannot vote for awake votable here as that takes
3479 * a mutex lock and this is executed in an atomic context.
3480 */
3481 pm_stay_awake(chip->dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003482 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003483 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003484
3485 return NOTIFY_OK;
3486}
3487
3488static enum power_supply_property fg_psy_props[] = {
3489 POWER_SUPPLY_PROP_CAPACITY,
3490 POWER_SUPPLY_PROP_TEMP,
3491 POWER_SUPPLY_PROP_VOLTAGE_NOW,
3492 POWER_SUPPLY_PROP_VOLTAGE_OCV,
3493 POWER_SUPPLY_PROP_CURRENT_NOW,
3494 POWER_SUPPLY_PROP_RESISTANCE_ID,
3495 POWER_SUPPLY_PROP_RESISTANCE,
3496 POWER_SUPPLY_PROP_BATTERY_TYPE,
3497 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003498 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Nicholas Troaste29dec92016-08-24 09:35:11 -07003499 POWER_SUPPLY_PROP_CYCLE_COUNT,
3500 POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003501 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
3502 POWER_SUPPLY_PROP_CHARGE_NOW,
3503 POWER_SUPPLY_PROP_CHARGE_FULL,
3504 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Nicholas Troast1769fd32016-09-07 09:20:58 -07003505 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3506 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003507 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303508 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003509 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07003510 POWER_SUPPLY_PROP_CC_STEP,
3511 POWER_SUPPLY_PROP_CC_STEP_SEL,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003512};
3513
3514static const struct power_supply_desc fg_psy_desc = {
3515 .name = "bms",
3516 .type = POWER_SUPPLY_TYPE_BMS,
3517 .properties = fg_psy_props,
3518 .num_properties = ARRAY_SIZE(fg_psy_props),
3519 .get_property = fg_psy_get_property,
3520 .set_property = fg_psy_set_property,
3521 .external_power_changed = fg_external_power_changed,
3522 .property_is_writeable = fg_property_is_writeable,
3523};
3524
3525/* INIT FUNCTIONS STAY HERE */
3526
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003527#define DEFAULT_ESR_CHG_TIMER_RETRY 8
3528#define DEFAULT_ESR_CHG_TIMER_MAX 16
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003529static int fg_hw_init(struct fg_chip *chip)
3530{
3531 int rc;
3532 u8 buf[4], val;
3533
3534 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003535 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
3536 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003537 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
3538 if (rc < 0) {
3539 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
3540 return rc;
3541 }
3542
3543 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003544 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
3545 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003546 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
3547 if (rc < 0) {
3548 pr_err("Error in writing empty_volt, rc=%d\n", rc);
3549 return rc;
3550 }
3551
3552 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
3553 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003554 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
3555 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003556 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
3557 if (rc < 0) {
3558 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
3559 return rc;
3560 }
3561
3562 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
3563 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003564 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
3565 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003566 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
3567 if (rc < 0) {
3568 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
3569 return rc;
3570 }
3571
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003572 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
3573 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
3574 chip->dt.chg_term_base_curr_ma, buf);
3575 rc = fg_sram_write(chip,
3576 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
3577 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
3578 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
3579 FG_IMA_DEFAULT);
3580 if (rc < 0) {
3581 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
3582 rc);
3583 return rc;
3584 }
3585 }
3586
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003587 if (chip->dt.vbatt_low_thr_mv > 0) {
3588 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
3589 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003590 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
3591 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003592 chip->sp[FG_SRAM_VBATT_LOW].len,
3593 FG_IMA_DEFAULT);
3594 if (rc < 0) {
3595 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
3596 return rc;
3597 }
3598 }
3599
3600 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003601 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003602 chip->dt.delta_soc_thr, buf);
3603 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003604 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
3605 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
3606 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003607 FG_IMA_DEFAULT);
3608 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003609 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
3610 return rc;
3611 }
3612
3613 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
3614 chip->dt.delta_soc_thr, buf);
3615 rc = fg_sram_write(chip,
3616 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
3617 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
3618 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
3619 FG_IMA_DEFAULT);
3620 if (rc < 0) {
3621 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003622 return rc;
3623 }
3624 }
3625
cyizhaofb3eec52017-01-24 17:08:55 +08003626 /*
3627 * configure battery thermal coefficients c1,c2,c3
3628 * if its value is not zero.
3629 */
3630 if (chip->dt.batt_therm_coeffs[0] > 0) {
3631 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
3632 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
3633 if (rc < 0) {
3634 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
3635 rc);
3636 return rc;
3637 }
3638 }
3639
3640
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003641 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003642 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003643 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003644 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003645 return rc;
3646 }
3647 }
3648
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003649 if (chip->dt.recharge_volt_thr_mv > 0) {
3650 rc = fg_set_recharge_voltage(chip,
3651 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003652 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003653 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003654 rc);
3655 return rc;
3656 }
3657 }
3658
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003659 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
3660 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
3661 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
3662 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
3663 if (rc < 0) {
3664 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
3665 return rc;
3666 }
3667 }
3668
3669 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
3670 rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
3671 if (rc < 0) {
3672 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3673 return rc;
3674 }
3675
3676 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
3677 rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
3678 if (rc < 0) {
3679 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
3680 return rc;
3681 }
3682
3683 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
3684 rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
3685 if (rc < 0) {
3686 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
3687 return rc;
3688 }
3689
3690 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
3691 rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
3692 if (rc < 0) {
3693 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
3694 return rc;
3695 }
3696
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003697 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
3698 chip->esr_timer_charging_default[TIMER_RETRY] =
3699 DEFAULT_ESR_CHG_TIMER_RETRY;
3700 chip->esr_timer_charging_default[TIMER_MAX] =
3701 DEFAULT_ESR_CHG_TIMER_MAX;
3702 } else {
3703 /* We don't need this for pm660 at present */
3704 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
3705 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003706 }
3707
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003708 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
3709 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
3710 if (rc < 0) {
3711 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3712 return rc;
3713 }
3714
3715 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
3716 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
3717 if (rc < 0) {
3718 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3719 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003720 }
3721
Nicholas Troaste29dec92016-08-24 09:35:11 -07003722 if (chip->cyc_ctr.en)
3723 restore_cycle_counter(chip);
3724
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003725 if (chip->dt.jeita_hyst_temp >= 0) {
3726 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
3727 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
3728 JEITA_TEMP_HYST_MASK, val);
3729 if (rc < 0) {
3730 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
3731 return rc;
3732 }
3733 }
3734
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003735 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
3736 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
3737 CHANGE_THOLD_MASK, val);
3738 if (rc < 0) {
3739 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
3740 return rc;
3741 }
3742
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07003743 rc = fg_rconn_config(chip);
3744 if (rc < 0) {
3745 pr_err("Error in configuring Rconn, rc=%d\n", rc);
3746 return rc;
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08003747 }
3748
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003749 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
3750 chip->dt.esr_tight_flt_upct, buf);
3751 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
3752 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
3753 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
3754 if (rc < 0) {
3755 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
3756 return rc;
3757 }
3758
3759 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
3760 chip->dt.esr_broad_flt_upct, buf);
3761 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
3762 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
3763 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
3764 if (rc < 0) {
3765 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
3766 return rc;
3767 }
3768
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003769 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
3770 chip->dt.esr_pulse_thresh_ma, buf);
3771 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
3772 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
3773 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
3774 if (rc < 0) {
3775 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
3776 return rc;
3777 }
3778
3779 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
3780 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3781 ESR_PULL_DOWN_IVAL_MASK, val);
3782 if (rc < 0) {
3783 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
3784 return rc;
3785 }
3786
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07003787 if (is_debug_batt_id(chip)) {
3788 val = ESR_NO_PULL_DOWN;
3789 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3790 ESR_PULL_DOWN_MODE_MASK, val);
3791 if (rc < 0) {
3792 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
3793 return rc;
3794 }
3795 }
3796
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003797 return 0;
3798}
3799
3800static int fg_memif_init(struct fg_chip *chip)
3801{
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07003802 if (chip->use_dma)
3803 return fg_dma_init(chip);
3804
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003805 return fg_ima_init(chip);
3806}
3807
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303808static int fg_adjust_timebase(struct fg_chip *chip)
3809{
3810 int rc = 0, die_temp;
3811 s32 time_base = 0;
3812 u8 buf[2] = {0};
3813
3814 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
3815 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
3816 if (rc < 0) {
3817 pr_err("Error in reading die_temp, rc:%d\n", rc);
3818 return rc;
3819 }
3820
3821 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
3822 die_temp / 1000, &time_base);
3823 if (rc < 0) {
3824 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
3825 return rc;
3826 }
3827
3828 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
3829 rc = fg_sram_write(chip,
3830 chip->sp[FG_SRAM_TIMEBASE].addr_word,
3831 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
3832 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
3833 if (rc < 0) {
3834 pr_err("Error in writing timebase, rc=%d\n", rc);
3835 return rc;
3836 }
3837 }
3838
3839 return 0;
3840}
3841
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003842/* INTERRUPT HANDLERS STAY HERE */
3843
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07003844static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data)
3845{
3846 struct fg_chip *chip = data;
3847 u8 status;
3848 int rc;
3849
3850 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
3851 if (rc < 0) {
3852 pr_err("failed to read addr=0x%04x, rc=%d\n",
3853 MEM_IF_INT_RT_STS(chip), rc);
3854 return IRQ_HANDLED;
3855 }
3856
3857 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
3858 if (status & MEM_GNT_BIT)
3859 complete_all(&chip->mem_grant);
3860
3861 return IRQ_HANDLED;
3862}
3863
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003864static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
3865{
3866 struct fg_chip *chip = data;
3867 u8 status;
3868 int rc;
3869
3870 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
3871 if (rc < 0) {
3872 pr_err("failed to read addr=0x%04x, rc=%d\n",
3873 MEM_IF_INT_RT_STS(chip), rc);
3874 return IRQ_HANDLED;
3875 }
3876
3877 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003878
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003879 mutex_lock(&chip->sram_rw_lock);
3880 rc = fg_clear_dma_errors_if_any(chip);
3881 if (rc < 0)
3882 pr_err("Error in clearing DMA error, rc=%d\n", rc);
3883
3884 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003885 rc = fg_clear_ima_errors_if_any(chip, true);
3886 if (rc < 0 && rc != -EAGAIN)
3887 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003888 }
3889
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003890 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003891 return IRQ_HANDLED;
3892}
3893
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003894static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
3895{
3896 struct fg_chip *chip = data;
3897
3898 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3899 return IRQ_HANDLED;
3900}
3901
3902static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
3903{
3904 struct fg_chip *chip = data;
3905 u8 status;
3906 int rc;
3907
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003908 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
3909 if (rc < 0) {
3910 pr_err("failed to read addr=0x%04x, rc=%d\n",
3911 BATT_INFO_INT_RT_STS(chip), rc);
3912 return IRQ_HANDLED;
3913 }
3914
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003915 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003916 chip->battery_missing = (status & BT_MISS_BIT);
3917
3918 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07003919 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003920 chip->profile_loaded = false;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003921 chip->soc_reporting_ready = false;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003922 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003923 }
3924
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003925 clear_battery_profile(chip);
3926 schedule_delayed_work(&chip->profile_load_work, 0);
3927
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303928 if (chip->fg_psy)
3929 power_supply_changed(chip->fg_psy);
3930
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003931 return IRQ_HANDLED;
3932}
3933
3934static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
3935{
3936 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003937 union power_supply_propval prop = {0, };
3938 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003939
3940 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003941 rc = fg_get_battery_temp(chip, &batt_temp);
3942 if (rc < 0) {
3943 pr_err("Error in getting batt_temp\n");
3944 return IRQ_HANDLED;
3945 }
3946
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003947 rc = fg_esr_filter_config(chip, batt_temp);
3948 if (rc < 0)
3949 pr_err("Error in configuring ESR filter rc:%d\n", rc);
3950
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003951 rc = fg_slope_limit_config(chip, batt_temp);
3952 if (rc < 0)
3953 pr_err("Error in configuring slope limiter rc:%d\n", rc);
3954
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07003955 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
3956 if (rc < 0)
3957 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
3958
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003959 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003960 chip->last_batt_temp = batt_temp;
3961 return IRQ_HANDLED;
3962 }
3963
3964 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
3965 &prop);
3966 chip->health = prop.intval;
3967
3968 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303969 rc = fg_adjust_timebase(chip);
3970 if (rc < 0)
3971 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3972
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003973 chip->last_batt_temp = batt_temp;
3974 power_supply_changed(chip->batt_psy);
3975 }
3976
3977 if (abs(chip->last_batt_temp - batt_temp) > 30)
3978 pr_warn("Battery temperature last:%d current: %d\n",
3979 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003980 return IRQ_HANDLED;
3981}
3982
3983static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
3984{
3985 struct fg_chip *chip = data;
3986
3987 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3988 complete_all(&chip->soc_ready);
3989 return IRQ_HANDLED;
3990}
3991
3992static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
3993{
3994 struct fg_chip *chip = data;
3995
3996 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3997 complete_all(&chip->soc_update);
3998 return IRQ_HANDLED;
3999}
4000
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004001static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
4002{
4003 struct fg_chip *chip = data;
4004 int rc;
4005
4006 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4007 rc = fg_charge_full_update(chip);
4008 if (rc < 0)
4009 pr_err("Error in charge_full_update, rc=%d\n", rc);
4010
4011 return IRQ_HANDLED;
4012}
4013
4014static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004015{
4016 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004017 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004018
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004019 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004020 if (chip->cyc_ctr.en)
4021 schedule_work(&chip->cycle_count_work);
4022
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004023 if (chip->cl.active)
4024 fg_cap_learning_update(chip);
4025
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004026 rc = fg_charge_full_update(chip);
4027 if (rc < 0)
4028 pr_err("Error in charge_full_update, rc=%d\n", rc);
4029
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004030 rc = fg_adjust_ki_coeff_dischg(chip);
4031 if (rc < 0)
4032 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
4033
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004034 rc = fg_update_maint_soc(chip);
4035 if (rc < 0)
4036 pr_err("Error in updating maint_soc, rc=%d\n", rc);
4037
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004038 rc = fg_esr_validate(chip);
4039 if (rc < 0)
4040 pr_err("Error in validating ESR, rc=%d\n", rc);
4041
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304042 rc = fg_adjust_timebase(chip);
4043 if (rc < 0)
4044 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4045
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004046 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004047 power_supply_changed(chip->batt_psy);
4048
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004049 return IRQ_HANDLED;
4050}
4051
4052static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
4053{
4054 struct fg_chip *chip = data;
4055
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004056 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004057 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07004058 power_supply_changed(chip->batt_psy);
4059
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004060 return IRQ_HANDLED;
4061}
4062
4063static irqreturn_t fg_soc_irq_handler(int irq, void *data)
4064{
4065 struct fg_chip *chip = data;
4066
4067 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4068 return IRQ_HANDLED;
4069}
4070
4071static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
4072{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004073 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004074 return IRQ_HANDLED;
4075}
4076
4077static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
4078 /* BATT_SOC irqs */
4079 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004080 .name = "msoc-full",
4081 .handler = fg_soc_irq_handler,
4082 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004083 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004084 .name = "msoc-high",
4085 .handler = fg_soc_irq_handler,
4086 .wakeable = true,
4087 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004088 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004089 .name = "msoc-empty",
4090 .handler = fg_empty_soc_irq_handler,
4091 .wakeable = true,
4092 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004093 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004094 .name = "msoc-low",
4095 .handler = fg_soc_irq_handler,
4096 .wakeable = true,
4097 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004098 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004099 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004100 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004101 .wakeable = true,
4102 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004103 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004104 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004105 .handler = fg_delta_bsoc_irq_handler,
4106 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004107 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004108 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004109 .name = "soc-ready",
4110 .handler = fg_first_est_irq_handler,
4111 .wakeable = true,
4112 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004113 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004114 .name = "soc-update",
4115 .handler = fg_soc_update_irq_handler,
4116 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004117 /* BATT_INFO irqs */
4118 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004119 .name = "batt-temp-delta",
4120 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004121 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004122 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004123 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004124 .name = "batt-missing",
4125 .handler = fg_batt_missing_irq_handler,
4126 .wakeable = true,
4127 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004128 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004129 .name = "esr-delta",
4130 .handler = fg_dummy_irq_handler,
4131 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004132 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004133 .name = "vbatt-low",
4134 .handler = fg_vbatt_low_irq_handler,
4135 .wakeable = true,
4136 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004137 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004138 .name = "vbatt-pred-delta",
4139 .handler = fg_dummy_irq_handler,
4140 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004141 /* MEM_IF irqs */
4142 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004143 .name = "dma-grant",
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004144 .handler = fg_dma_grant_irq_handler,
4145 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004146 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004147 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004148 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004149 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004150 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004151 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004152 .name = "ima-rdy",
4153 .handler = fg_dummy_irq_handler,
4154 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004155};
4156
4157static int fg_get_irq_index_byname(const char *name)
4158{
4159 int i;
4160
4161 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
4162 if (strcmp(fg_irqs[i].name, name) == 0)
4163 return i;
4164 }
4165
4166 pr_err("%s is not in irq list\n", name);
4167 return -ENOENT;
4168}
4169
4170static int fg_register_interrupts(struct fg_chip *chip)
4171{
4172 struct device_node *child, *node = chip->dev->of_node;
4173 struct property *prop;
4174 const char *name;
4175 int rc, irq, irq_index;
4176
4177 for_each_available_child_of_node(node, child) {
4178 of_property_for_each_string(child, "interrupt-names", prop,
4179 name) {
4180 irq = of_irq_get_byname(child, name);
4181 if (irq < 0) {
4182 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
4183 name, irq);
4184 return irq;
4185 }
4186
4187 irq_index = fg_get_irq_index_byname(name);
4188 if (irq_index < 0)
4189 return irq_index;
4190
4191 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
4192 fg_irqs[irq_index].handler,
4193 IRQF_ONESHOT, name, chip);
4194 if (rc < 0) {
4195 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
4196 name, rc);
4197 return rc;
4198 }
4199
4200 fg_irqs[irq_index].irq = irq;
4201 if (fg_irqs[irq_index].wakeable)
4202 enable_irq_wake(fg_irqs[irq_index].irq);
4203 }
4204 }
4205
4206 return 0;
4207}
4208
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004209static int fg_parse_dt_property_u32_array(struct device_node *node,
4210 const char *prop_name, int *buf, int len)
4211{
4212 int rc;
4213
4214 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
4215 if (rc < 0) {
4216 if (rc == -EINVAL)
4217 return 0;
4218 else
4219 return rc;
4220 } else if (rc != len) {
4221 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
4222 rc);
4223 return -EINVAL;
4224 }
4225
4226 rc = of_property_read_u32_array(node, prop_name, buf, len);
4227 if (rc < 0) {
4228 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
4229 return rc;
4230 }
4231
4232 return 0;
4233}
4234
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004235static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
4236{
4237 struct device_node *node = chip->dev->of_node;
4238 int rc, i;
4239
4240 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
4241 &chip->dt.slope_limit_temp);
4242 if (rc < 0)
4243 return 0;
4244
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004245 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
4246 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
4247 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004248 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004249
4250 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
4251 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
4252 chip->dt.slope_limit_coeffs[i] < 0) {
4253 pr_err("Incorrect slope limit coefficient\n");
4254 return -EINVAL;
4255 }
4256 }
4257
4258 chip->slope_limit_en = true;
4259 return 0;
4260}
4261
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004262static int fg_parse_ki_coefficients(struct fg_chip *chip)
4263{
4264 struct device_node *node = chip->dev->of_node;
4265 int rc, i;
4266
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004267 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
4268 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
4269 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004270 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004271
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004272 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
4273 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
4274 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004275 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004276
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004277 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
4278 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
4279 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004280 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004281
4282 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
4283 if (chip->dt.ki_coeff_soc[i] < 0 ||
4284 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
4285 pr_err("Error in ki_coeff_soc_dischg values\n");
4286 return -EINVAL;
4287 }
4288
4289 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
4290 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
4291 pr_err("Error in ki_coeff_med_dischg values\n");
4292 return -EINVAL;
4293 }
4294
4295 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
4296 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
4297 pr_err("Error in ki_coeff_med_dischg values\n");
4298 return -EINVAL;
4299 }
4300 }
4301 chip->ki_coeff_dischg_en = true;
4302 return 0;
4303}
4304
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004305#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07004306#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004307#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004308#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004309#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07004310#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004311#define DEFAULT_DELTA_SOC_THR 1
4312#define DEFAULT_RECHARGE_SOC_THR 95
4313#define DEFAULT_BATT_TEMP_COLD 0
4314#define DEFAULT_BATT_TEMP_COOL 5
4315#define DEFAULT_BATT_TEMP_WARM 45
4316#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004317#define DEFAULT_CL_START_SOC 15
4318#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
4319#define DEFAULT_CL_MAX_TEMP_DECIDEGC 450
4320#define DEFAULT_CL_MAX_INC_DECIPERC 5
4321#define DEFAULT_CL_MAX_DEC_DECIPERC 100
4322#define DEFAULT_CL_MIN_LIM_DECIPERC 0
4323#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004324#define BTEMP_DELTA_LOW 2
4325#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004326#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
4327#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
4328#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
4329#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
4330#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004331#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004332#define DEFAULT_ESR_PULSE_THRESH_MA 110
4333#define DEFAULT_ESR_MEAS_CURR_MA 120
Fenglin Wud10ccf12017-08-10 15:43:41 +08004334#define DEFAULT_BMD_EN_DELAY_MS 200
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004335static int fg_parse_dt(struct fg_chip *chip)
4336{
4337 struct device_node *child, *revid_node, *node = chip->dev->of_node;
4338 u32 base, temp;
4339 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004340 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004341
4342 if (!node) {
4343 dev_err(chip->dev, "device tree node missing\n");
4344 return -ENXIO;
4345 }
4346
4347 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
4348 if (!revid_node) {
4349 pr_err("Missing qcom,pmic-revid property - driver failed\n");
4350 return -EINVAL;
4351 }
4352
4353 chip->pmic_rev_id = get_revid_data(revid_node);
4354 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
4355 pr_err("Unable to get pmic_revid rc=%ld\n",
4356 PTR_ERR(chip->pmic_rev_id));
4357 /*
4358 * the revid peripheral must be registered, any failure
4359 * here only indicates that the rev-id module has not
4360 * probed yet.
4361 */
4362 return -EPROBE_DEFER;
4363 }
4364
4365 pr_debug("PMIC subtype %d Digital major %d\n",
4366 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
4367
4368 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004369 case PMI8998_SUBTYPE:
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004370 chip->use_dma = true;
Harry Yang2452b272017-03-06 13:56:14 -08004371 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
4372 chip->sp = pmi8998_v1_sram_params;
4373 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304374 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08004375 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
4376 chip->sp = pmi8998_v2_sram_params;
4377 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07004378 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004379 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07004380 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004381 break;
Harry Yange4e731b2017-03-06 14:35:09 -08004382 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304383 chip->sp = pmi8998_v2_sram_params;
4384 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07004385 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304386 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
4387 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304388 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004389 default:
4390 return -EINVAL;
4391 }
4392
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004393 if (of_get_available_child_count(node) == 0) {
4394 dev_err(chip->dev, "No child nodes specified!\n");
4395 return -ENXIO;
4396 }
4397
4398 for_each_available_child_of_node(node, child) {
4399 rc = of_property_read_u32(child, "reg", &base);
4400 if (rc < 0) {
4401 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
4402 child->full_name, rc);
4403 return rc;
4404 }
4405
4406 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
4407 if (rc < 0) {
4408 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
4409 base, rc);
4410 return rc;
4411 }
4412
4413 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004414 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004415 chip->batt_soc_base = base;
4416 break;
Harry Yang2452b272017-03-06 13:56:14 -08004417 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004418 chip->batt_info_base = base;
4419 break;
Harry Yang2452b272017-03-06 13:56:14 -08004420 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004421 chip->mem_if_base = base;
4422 break;
4423 default:
4424 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
4425 subtype);
4426 return -ENXIO;
4427 }
4428 }
4429
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004430 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
4431 if (rc < 0) {
4432 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
4433 return rc;
4434 }
4435 chip->rradc_base = base;
4436
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004437 /* Read all the optional properties below */
4438 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
4439 if (rc < 0)
4440 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
4441 else
4442 chip->dt.cutoff_volt_mv = temp;
4443
4444 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
4445 if (rc < 0)
4446 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
4447 else
4448 chip->dt.empty_volt_mv = temp;
4449
4450 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
4451 if (rc < 0)
4452 chip->dt.vbatt_low_thr_mv = -EINVAL;
4453 else
4454 chip->dt.vbatt_low_thr_mv = temp;
4455
4456 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
4457 if (rc < 0)
4458 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
4459 else
4460 chip->dt.chg_term_curr_ma = temp;
4461
4462 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
4463 if (rc < 0)
4464 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
4465 else
4466 chip->dt.sys_term_curr_ma = temp;
4467
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004468 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
4469 if (rc < 0)
4470 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
4471 else
4472 chip->dt.chg_term_base_curr_ma = temp;
4473
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004474 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
4475 if (rc < 0)
4476 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
4477 else
4478 chip->dt.delta_soc_thr = temp;
4479
4480 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
4481 if (rc < 0)
4482 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
4483 else
4484 chip->dt.recharge_soc_thr = temp;
4485
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004486 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
4487 if (rc < 0)
4488 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
4489 else
4490 chip->dt.recharge_volt_thr_mv = temp;
4491
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004492 chip->dt.auto_recharge_soc = of_property_read_bool(node,
4493 "qcom,fg-auto-recharge-soc");
4494
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004495 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
4496 if (rc < 0)
4497 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
4498 else
4499 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
4500
4501 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
4502 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
4503 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
4504 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004505 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
4506 sizeof(u32)) == NUM_JEITA_LEVELS) {
4507 rc = of_property_read_u32_array(node,
4508 "qcom,fg-jeita-thresholds",
4509 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
4510 if (rc < 0)
4511 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
4512 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004513 }
4514
cyizhaofb3eec52017-01-24 17:08:55 +08004515 if (of_property_count_elems_of_size(node,
4516 "qcom,battery-thermal-coefficients",
4517 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
4518 rc = of_property_read_u8_array(node,
4519 "qcom,battery-thermal-coefficients",
4520 chip->dt.batt_therm_coeffs,
4521 BATT_THERM_NUM_COEFFS);
4522 if (rc < 0)
4523 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
4524 rc);
4525 }
4526
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004527 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
4528 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
4529 if (rc < 0) {
4530 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
4531 chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
4532 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004533
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004534 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
4535 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
4536 if (rc < 0) {
4537 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
4538 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
4539 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004540
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004541 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
4542 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
4543 if (rc < 0) {
4544 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
4545 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
4546 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004547
Nicholas Troaste29dec92016-08-24 09:35:11 -07004548 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
4549 if (chip->cyc_ctr.en)
4550 chip->cyc_ctr.id = 1;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004551
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07004552 chip->dt.force_load_profile = of_property_read_bool(node,
4553 "qcom,fg-force-load-profile");
4554
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004555 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
4556 if (rc < 0)
4557 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
4558 else
4559 chip->dt.cl_start_soc = temp;
4560
4561 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
4562 if (rc < 0)
4563 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
4564 else
4565 chip->dt.cl_min_temp = temp;
4566
4567 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
4568 if (rc < 0)
4569 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
4570 else
4571 chip->dt.cl_max_temp = temp;
4572
4573 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
4574 if (rc < 0)
4575 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
4576 else
4577 chip->dt.cl_max_cap_inc = temp;
4578
4579 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
4580 if (rc < 0)
4581 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
4582 else
4583 chip->dt.cl_max_cap_dec = temp;
4584
4585 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
4586 if (rc < 0)
4587 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
4588 else
4589 chip->dt.cl_min_cap_limit = temp;
4590
4591 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
4592 if (rc < 0)
4593 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
4594 else
4595 chip->dt.cl_max_cap_limit = temp;
4596
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004597 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
4598 if (rc < 0)
4599 chip->dt.jeita_hyst_temp = -EINVAL;
4600 else
4601 chip->dt.jeita_hyst_temp = temp;
4602
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004603 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
4604 if (rc < 0)
4605 chip->dt.batt_temp_delta = -EINVAL;
4606 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
4607 chip->dt.batt_temp_delta = temp;
4608
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004609 chip->dt.hold_soc_while_full = of_property_read_bool(node,
4610 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004611
4612 rc = fg_parse_ki_coefficients(chip);
4613 if (rc < 0)
4614 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
4615
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004616 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07004617 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004618 chip->dt.rconn_mohms = temp;
4619
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004620 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
4621 &temp);
4622 if (rc < 0)
4623 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
4624 else
4625 chip->dt.esr_flt_switch_temp = temp;
4626
4627 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
4628 &temp);
4629 if (rc < 0)
4630 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
4631 else
4632 chip->dt.esr_tight_flt_upct = temp;
4633
4634 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
4635 &temp);
4636 if (rc < 0)
4637 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
4638 else
4639 chip->dt.esr_broad_flt_upct = temp;
4640
4641 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
4642 &temp);
4643 if (rc < 0)
4644 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
4645 else
4646 chip->dt.esr_tight_lt_flt_upct = temp;
4647
4648 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
4649 &temp);
4650 if (rc < 0)
4651 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
4652 else
4653 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004654
4655 rc = fg_parse_slope_limit_coefficients(chip);
4656 if (rc < 0)
4657 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
4658
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004659 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
4660 if (rc < 0)
4661 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
4662 else
4663 chip->dt.esr_clamp_mohms = temp;
4664
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004665 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
4666 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
4667 if (!rc) {
4668 /* ESR pulse qualification threshold range is 1-997 mA */
4669 if (temp > 0 && temp < 997)
4670 chip->dt.esr_pulse_thresh_ma = temp;
4671 }
4672
4673 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
4674 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
4675 if (!rc) {
4676 /* ESR measurement current range is 60-240 mA */
4677 if (temp >= 60 || temp <= 240)
4678 chip->dt.esr_meas_curr_ma = temp;
4679 }
4680
Fenglin Wud10ccf12017-08-10 15:43:41 +08004681 chip->dt.bmd_en_delay_ms = DEFAULT_BMD_EN_DELAY_MS;
4682 rc = of_property_read_u32(node, "qcom,fg-bmd-en-delay-ms", &temp);
4683 if (!rc) {
4684 if (temp > DEFAULT_BMD_EN_DELAY_MS)
4685 chip->dt.bmd_en_delay_ms = temp;
4686 }
4687
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004688 return 0;
4689}
4690
4691static void fg_cleanup(struct fg_chip *chip)
4692{
4693 power_supply_unreg_notifier(&chip->nb);
Nicholas Troast69da2252016-09-07 16:17:47 -07004694 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004695 if (chip->awake_votable)
4696 destroy_votable(chip->awake_votable);
4697
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004698 if (chip->delta_bsoc_irq_en_votable)
4699 destroy_votable(chip->delta_bsoc_irq_en_votable);
4700
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07004701 if (chip->batt_miss_irq_en_votable)
4702 destroy_votable(chip->batt_miss_irq_en_votable);
4703
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004704 if (chip->batt_id_chan)
4705 iio_channel_release(chip->batt_id_chan);
4706
4707 dev_set_drvdata(chip->dev, NULL);
4708}
4709
4710static int fg_gen3_probe(struct platform_device *pdev)
4711{
4712 struct fg_chip *chip;
4713 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004714 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004715
4716 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
4717 if (!chip)
4718 return -ENOMEM;
4719
4720 chip->dev = &pdev->dev;
4721 chip->debug_mask = &fg_gen3_debug_mask;
4722 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07004723 chip->charge_status = -EINVAL;
4724 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004725 chip->ki_coeff_full_soc = -EINVAL;
Nicholas Troast805c2422017-07-06 14:53:46 -07004726 chip->online_status = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004727 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
4728 if (!chip->regmap) {
4729 dev_err(chip->dev, "Parent regmap is unavailable\n");
4730 return -ENXIO;
4731 }
4732
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004733 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
4734 if (IS_ERR(chip->batt_id_chan)) {
4735 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
4736 pr_err("batt_id_chan unavailable %ld\n",
4737 PTR_ERR(chip->batt_id_chan));
4738 rc = PTR_ERR(chip->batt_id_chan);
4739 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004740 return rc;
4741 }
4742
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304743 rc = of_property_match_string(chip->dev->of_node,
4744 "io-channel-names", "rradc_die_temp");
4745 if (rc >= 0) {
4746 chip->die_temp_chan = iio_channel_get(chip->dev,
4747 "rradc_die_temp");
4748 if (IS_ERR(chip->die_temp_chan)) {
4749 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
4750 pr_err("rradc_die_temp unavailable %ld\n",
4751 PTR_ERR(chip->die_temp_chan));
4752 rc = PTR_ERR(chip->die_temp_chan);
4753 chip->die_temp_chan = NULL;
4754 return rc;
4755 }
4756 }
4757
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004758 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
4759 chip);
4760 if (IS_ERR(chip->awake_votable)) {
4761 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07004762 chip->awake_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004763 goto exit;
4764 }
4765
4766 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
4767 VOTE_SET_ANY,
4768 fg_delta_bsoc_irq_en_cb, chip);
4769 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
4770 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07004771 chip->delta_bsoc_irq_en_votable = NULL;
4772 goto exit;
4773 }
4774
4775 chip->batt_miss_irq_en_votable = create_votable("FG_BATT_MISS_IRQ",
4776 VOTE_SET_ANY,
4777 fg_batt_miss_irq_en_cb, chip);
4778 if (IS_ERR(chip->batt_miss_irq_en_votable)) {
4779 rc = PTR_ERR(chip->batt_miss_irq_en_votable);
4780 chip->batt_miss_irq_en_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004781 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004782 }
4783
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004784 rc = fg_parse_dt(chip);
4785 if (rc < 0) {
4786 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
4787 rc);
4788 goto exit;
4789 }
4790
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004791 mutex_init(&chip->bus_lock);
4792 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004793 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004794 mutex_init(&chip->cl.lock);
Nicholas Troast805c2422017-07-06 14:53:46 -07004795 mutex_init(&chip->ttf.lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004796 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004797 init_completion(&chip->soc_update);
4798 init_completion(&chip->soc_ready);
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004799 init_completion(&chip->mem_grant);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004800 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
4801 INIT_WORK(&chip->status_change_work, status_change_work);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004802 INIT_WORK(&chip->cycle_count_work, cycle_count_work);
Nicholas Troast805c2422017-07-06 14:53:46 -07004803 INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004804 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004805
4806 rc = fg_memif_init(chip);
4807 if (rc < 0) {
4808 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
4809 rc);
4810 goto exit;
4811 }
4812
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004813 platform_set_drvdata(pdev, chip);
4814
4815 rc = fg_register_interrupts(chip);
4816 if (rc < 0) {
4817 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
4818 rc);
4819 goto exit;
4820 }
4821
4822 /* Keep SOC_UPDATE irq disabled until we require it */
4823 if (fg_irqs[SOC_UPDATE_IRQ].irq)
4824 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
4825
4826 /* Keep BSOC_DELTA_IRQ disabled until we require it */
4827 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);
4828
4829 /* Keep BATT_MISSING_IRQ disabled until we require it */
4830 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);
4831
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004832 rc = fg_hw_init(chip);
4833 if (rc < 0) {
4834 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
4835 rc);
4836 goto exit;
4837 }
4838
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004839 /* Register the power supply */
4840 fg_psy_cfg.drv_data = chip;
4841 fg_psy_cfg.of_node = NULL;
4842 fg_psy_cfg.supplied_to = NULL;
4843 fg_psy_cfg.num_supplicants = 0;
4844 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
4845 &fg_psy_cfg);
4846 if (IS_ERR(chip->fg_psy)) {
4847 pr_err("failed to register fg_psy rc = %ld\n",
4848 PTR_ERR(chip->fg_psy));
4849 goto exit;
4850 }
4851
4852 chip->nb.notifier_call = fg_notifier_cb;
4853 rc = power_supply_reg_notifier(&chip->nb);
4854 if (rc < 0) {
4855 pr_err("Couldn't register psy notifier rc = %d\n", rc);
4856 goto exit;
4857 }
4858
Nicholas Troast69da2252016-09-07 16:17:47 -07004859 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004860 if (rc < 0) {
4861 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
4862 rc);
4863 goto exit;
4864 }
4865
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004866 rc = fg_get_battery_voltage(chip, &volt_uv);
4867 if (!rc)
4868 rc = fg_get_prop_capacity(chip, &msoc);
4869
4870 if (!rc)
4871 rc = fg_get_battery_temp(chip, &batt_temp);
4872
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004873 if (!rc) {
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004874 pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004875 msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004876 rc = fg_esr_filter_config(chip, batt_temp);
4877 if (rc < 0)
4878 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4879 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004880
4881 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07004882 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004883
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004884 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004885 return 0;
4886exit:
4887 fg_cleanup(chip);
4888 return rc;
4889}
4890
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004891static int fg_gen3_suspend(struct device *dev)
4892{
4893 struct fg_chip *chip = dev_get_drvdata(dev);
4894 int rc;
4895
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004896 rc = fg_esr_timer_config(chip, true);
4897 if (rc < 0)
4898 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004899
Nicholas Troast805c2422017-07-06 14:53:46 -07004900 cancel_delayed_work_sync(&chip->ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004901 if (fg_sram_dump)
4902 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004903 return 0;
4904}
4905
4906static int fg_gen3_resume(struct device *dev)
4907{
4908 struct fg_chip *chip = dev_get_drvdata(dev);
4909 int rc;
4910
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004911 rc = fg_esr_timer_config(chip, false);
4912 if (rc < 0)
4913 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004914
Nicholas Troast805c2422017-07-06 14:53:46 -07004915 schedule_delayed_work(&chip->ttf_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004916 if (fg_sram_dump)
4917 schedule_delayed_work(&chip->sram_dump_work,
4918 msecs_to_jiffies(fg_sram_dump_period_ms));
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004919 return 0;
4920}
4921
4922static const struct dev_pm_ops fg_gen3_pm_ops = {
4923 .suspend = fg_gen3_suspend,
4924 .resume = fg_gen3_resume,
4925};
4926
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004927static int fg_gen3_remove(struct platform_device *pdev)
4928{
4929 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
4930
4931 fg_cleanup(chip);
4932 return 0;
4933}
4934
4935static const struct of_device_id fg_gen3_match_table[] = {
4936 {.compatible = FG_GEN3_DEV_NAME},
4937 {},
4938};
4939
4940static struct platform_driver fg_gen3_driver = {
4941 .driver = {
4942 .name = FG_GEN3_DEV_NAME,
4943 .owner = THIS_MODULE,
4944 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004945 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004946 },
4947 .probe = fg_gen3_probe,
4948 .remove = fg_gen3_remove,
4949};
4950
4951static int __init fg_gen3_init(void)
4952{
4953 return platform_driver_register(&fg_gen3_driver);
4954}
4955
4956static void __exit fg_gen3_exit(void)
4957{
4958 return platform_driver_unregister(&fg_gen3_driver);
4959}
4960
4961module_init(fg_gen3_init);
4962module_exit(fg_gen3_exit);
4963
4964MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
4965MODULE_LICENSE("GPL v2");
4966MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);