blob: 42bbc4c757a8102dcf9351b3228317fe2d763a74 [file] [log] [blame]
Umang Chheda14311472020-01-23 14:57:00 +05301/* Copyright (c) 2016-2020, 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>
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +053018#include <linux/spinlock.h>
19#include <linux/alarmtimer.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070020#include <linux/of_platform.h>
21#include <linux/of_batterydata.h>
22#include <linux/platform_device.h>
Subbaraman Narayanamurthy8a191dc2017-08-18 18:37:01 -070023#include <linux/thermal.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070024#include <linux/iio/consumer.h>
25#include <linux/qpnp/qpnp-revid.h>
Anirudh Ghayala209ac32018-08-23 15:08:05 +053026#include <linux/qpnp/qpnp-misc.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070027#include "fg-core.h"
28#include "fg-reg.h"
29
30#define FG_GEN3_DEV_NAME "qcom,fg-gen3"
31
32#define PERPH_SUBTYPE_REG 0x05
Harry Yang2452b272017-03-06 13:56:14 -080033#define FG_BATT_SOC_PMI8998 0x10
34#define FG_BATT_INFO_PMI8998 0x11
35#define FG_MEM_INFO_PMI8998 0x0D
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070036
37/* SRAM address and offset in ascending order */
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -070038#define ESR_PULSE_THRESH_WORD 2
39#define ESR_PULSE_THRESH_OFFSET 3
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -080040#define SLOPE_LIMIT_WORD 3
41#define SLOPE_LIMIT_OFFSET 0
Subbaraman Narayanamurthy5566f502017-12-19 19:39:03 -080042#define CUTOFF_CURR_WORD 4
43#define CUTOFF_CURR_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070044#define CUTOFF_VOLT_WORD 5
45#define CUTOFF_VOLT_OFFSET 0
46#define SYS_TERM_CURR_WORD 6
47#define SYS_TERM_CURR_OFFSET 0
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -070048#define VBATT_FULL_WORD 7
49#define VBATT_FULL_OFFSET 0
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -080050#define ESR_FILTER_WORD 8
51#define ESR_UPD_TIGHT_OFFSET 0
52#define ESR_UPD_BROAD_OFFSET 1
53#define ESR_UPD_TIGHT_LOW_TEMP_OFFSET 2
54#define ESR_UPD_BROAD_LOW_TEMP_OFFSET 3
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -070055#define KI_COEFF_MED_DISCHG_WORD 9
Anirudh Ghayalddabeee2017-04-04 06:13:48 +053056#define TIMEBASE_OFFSET 1
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -070057#define KI_COEFF_MED_DISCHG_OFFSET 3
58#define KI_COEFF_HI_DISCHG_WORD 10
59#define KI_COEFF_HI_DISCHG_OFFSET 0
60#define KI_COEFF_LOW_DISCHG_WORD 10
61#define KI_COEFF_LOW_DISCHG_OFFSET 2
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -070062#define KI_COEFF_FULL_SOC_WORD 12
63#define KI_COEFF_FULL_SOC_OFFSET 2
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -080064#define DELTA_MSOC_THR_WORD 12
65#define DELTA_MSOC_THR_OFFSET 3
66#define DELTA_BSOC_THR_WORD 13
67#define DELTA_BSOC_THR_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070068#define RECHARGE_SOC_THR_WORD 14
69#define RECHARGE_SOC_THR_OFFSET 0
70#define CHG_TERM_CURR_WORD 14
71#define CHG_TERM_CURR_OFFSET 1
Anirudh Ghayalbcb85772018-08-08 10:17:25 +053072#define SYNC_SLEEP_THR_WORD 14
73#define SYNC_SLEEP_THR_OFFSET 3
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070074#define EMPTY_VOLT_WORD 15
75#define EMPTY_VOLT_OFFSET 0
76#define VBATT_LOW_WORD 15
77#define VBATT_LOW_OFFSET 1
Nicholas Troastdcf8fe62016-08-04 14:30:02 -070078#define ESR_TIMER_DISCHG_MAX_WORD 17
79#define ESR_TIMER_DISCHG_MAX_OFFSET 0
80#define ESR_TIMER_DISCHG_INIT_WORD 17
81#define ESR_TIMER_DISCHG_INIT_OFFSET 2
82#define ESR_TIMER_CHG_MAX_WORD 18
83#define ESR_TIMER_CHG_MAX_OFFSET 0
84#define ESR_TIMER_CHG_INIT_WORD 18
85#define ESR_TIMER_CHG_INIT_OFFSET 2
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -070086#define ESR_EXTRACTION_ENABLE_WORD 19
87#define ESR_EXTRACTION_ENABLE_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070088#define PROFILE_LOAD_WORD 24
89#define PROFILE_LOAD_OFFSET 0
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -080090#define ESR_RSLOW_DISCHG_WORD 34
91#define ESR_RSLOW_DISCHG_OFFSET 0
92#define ESR_RSLOW_CHG_WORD 51
93#define ESR_RSLOW_CHG_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070094#define NOM_CAP_WORD 58
95#define NOM_CAP_OFFSET 0
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -070096#define ACT_BATT_CAP_BKUP_WORD 74
97#define ACT_BATT_CAP_BKUP_OFFSET 0
Nicholas Troaste29dec92016-08-24 09:35:11 -070098#define CYCLE_COUNT_WORD 75
99#define CYCLE_COUNT_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700100#define PROFILE_INTEGRITY_WORD 79
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800101#define SW_CONFIG_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700102#define PROFILE_INTEGRITY_OFFSET 3
103#define BATT_SOC_WORD 91
104#define BATT_SOC_OFFSET 0
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700105#define FULL_SOC_WORD 93
106#define FULL_SOC_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700107#define MONOTONIC_SOC_WORD 94
108#define MONOTONIC_SOC_OFFSET 2
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700109#define CC_SOC_WORD 95
110#define CC_SOC_OFFSET 0
111#define CC_SOC_SW_WORD 96
112#define CC_SOC_SW_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700113#define VOLTAGE_PRED_WORD 97
114#define VOLTAGE_PRED_OFFSET 0
115#define OCV_WORD 97
116#define OCV_OFFSET 2
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800117#define ESR_WORD 99
118#define ESR_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700119#define RSLOW_WORD 101
120#define RSLOW_OFFSET 0
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700121#define ACT_BATT_CAP_WORD 117
122#define ACT_BATT_CAP_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700123#define LAST_BATT_SOC_WORD 119
124#define LAST_BATT_SOC_OFFSET 0
125#define LAST_MONOTONIC_SOC_WORD 119
126#define LAST_MONOTONIC_SOC_OFFSET 2
Nicholas Troast69da2252016-09-07 16:17:47 -0700127#define ALG_FLAGS_WORD 120
128#define ALG_FLAGS_OFFSET 1
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700129
Nicholas Troasta2b40372016-08-15 10:45:39 -0700130/* v2 SRAM address and offset in ascending order */
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700131#define KI_COEFF_LOW_DISCHG_v2_WORD 9
132#define KI_COEFF_LOW_DISCHG_v2_OFFSET 3
133#define KI_COEFF_MED_DISCHG_v2_WORD 10
134#define KI_COEFF_MED_DISCHG_v2_OFFSET 0
135#define KI_COEFF_HI_DISCHG_v2_WORD 10
136#define KI_COEFF_HI_DISCHG_v2_OFFSET 1
Subbaraman Narayanamurthy13103202018-03-19 12:16:36 -0700137#define KI_COEFF_HI_CHG_v2_WORD 11
138#define KI_COEFF_HI_CHG_v2_OFFSET 2
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800139#define DELTA_BSOC_THR_v2_WORD 12
140#define DELTA_BSOC_THR_v2_OFFSET 3
141#define DELTA_MSOC_THR_v2_WORD 13
142#define DELTA_MSOC_THR_v2_OFFSET 0
Nicholas Troasta2b40372016-08-15 10:45:39 -0700143#define RECHARGE_SOC_THR_v2_WORD 14
144#define RECHARGE_SOC_THR_v2_OFFSET 1
Anirudh Ghayalbcb85772018-08-08 10:17:25 +0530145#define SYNC_SLEEP_THR_v2_WORD 14
146#define SYNC_SLEEP_THR_v2_OFFSET 2
Nicholas Troasta2b40372016-08-15 10:45:39 -0700147#define CHG_TERM_CURR_v2_WORD 15
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -0700148#define CHG_TERM_BASE_CURR_v2_OFFSET 0
Nicholas Troasta2b40372016-08-15 10:45:39 -0700149#define CHG_TERM_CURR_v2_OFFSET 1
150#define EMPTY_VOLT_v2_WORD 15
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -0700151#define EMPTY_VOLT_v2_OFFSET 3
Nicholas Troasta2b40372016-08-15 10:45:39 -0700152#define VBATT_LOW_v2_WORD 16
153#define VBATT_LOW_v2_OFFSET 0
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -0800154#define RECHARGE_VBATT_THR_v2_WORD 16
155#define RECHARGE_VBATT_THR_v2_OFFSET 1
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700156#define FLOAT_VOLT_v2_WORD 16
157#define FLOAT_VOLT_v2_OFFSET 2
Nicholas Troasta2b40372016-08-15 10:45:39 -0700158
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700159static int fg_decode_voltage_15b(struct fg_sram_param *sp,
160 enum fg_sram_param_id id, int val);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700161static int fg_decode_value_16b(struct fg_sram_param *sp,
162 enum fg_sram_param_id id, int val);
163static int fg_decode_default(struct fg_sram_param *sp,
164 enum fg_sram_param_id id, int val);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700165static int fg_decode_cc_soc(struct fg_sram_param *sp,
166 enum fg_sram_param_id id, int value);
Nicholas Troasta2b40372016-08-15 10:45:39 -0700167static void fg_encode_voltage(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700168 enum fg_sram_param_id id, int val_mv, u8 *buf);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700169static void fg_encode_current(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700170 enum fg_sram_param_id id, int val_ma, u8 *buf);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700171static void fg_encode_default(struct fg_sram_param *sp,
172 enum fg_sram_param_id id, int val, u8 *buf);
173
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800174static struct fg_irq_info fg_irqs[FG_IRQ_MAX];
175
Nicholas Troasta2b40372016-08-15 10:45:39 -0700176#define PARAM(_id, _addr_word, _addr_byte, _len, _num, _den, _offset, \
177 _enc, _dec) \
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700178 [FG_SRAM_##_id] = { \
Nicholas Troasta2b40372016-08-15 10:45:39 -0700179 .addr_word = _addr_word, \
180 .addr_byte = _addr_byte, \
181 .len = _len, \
182 .numrtr = _num, \
183 .denmtr = _den, \
184 .offset = _offset, \
185 .encode = _enc, \
186 .decode = _dec, \
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700187 } \
188
Harry Yang2452b272017-03-06 13:56:14 -0800189static struct fg_sram_param pmi8998_v1_sram_params[] = {
Nicholas Troasta2b40372016-08-15 10:45:39 -0700190 PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700191 fg_decode_default),
Nicholas Troast1769fd32016-09-07 09:20:58 -0700192 PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
193 fg_decode_default),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800194 PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
195 244141, 0, NULL, fg_decode_voltage_15b),
196 PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700197 fg_decode_voltage_15b),
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800198 PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default,
199 fg_decode_value_16b),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800200 PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700201 fg_decode_value_16b),
Nicholas Troast69da2252016-09-07 16:17:47 -0700202 PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
203 fg_decode_default),
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700204 PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL,
205 fg_decode_cc_soc),
206 PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL,
207 fg_decode_cc_soc),
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -0700208 PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
209 1, 1, 0, NULL, fg_decode_default),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700210 /* Entries below here are configurable during initialization */
211 PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700212 244141, 0, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700213 PARAM(EMPTY_VOLT, EMPTY_VOLT_WORD, EMPTY_VOLT_OFFSET, 1, 100000, 390625,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700214 -2500, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700215 PARAM(VBATT_LOW, VBATT_LOW_WORD, VBATT_LOW_OFFSET, 1, 100000, 390625,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700216 -2500, fg_encode_voltage, NULL),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800217 PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
218 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700219 PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700220 1000000, 122070, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700221 PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700222 100000, 390625, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthy5566f502017-12-19 19:39:03 -0800223 PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3,
224 1000000, 122070, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800225 PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1,
226 2048, 100, 0, fg_encode_default, NULL),
227 PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1,
228 2048, 100, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700229 PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700230 1, 256, 100, 0, fg_encode_default, NULL),
Anirudh Ghayalbcb85772018-08-08 10:17:25 +0530231 PARAM(SYNC_SLEEP_THR, SYNC_SLEEP_THR_WORD, SYNC_SLEEP_THR_OFFSET,
232 1, 100000, 390625, 0, fg_encode_default, NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700233 PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700234 ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
235 NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700236 PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700237 ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700238 NULL),
239 PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700240 ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700241 PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700242 ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -0700243 PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
244 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700245 PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_WORD,
246 KI_COEFF_MED_DISCHG_OFFSET, 1, 1000, 244141, 0,
247 fg_encode_default, NULL),
248 PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_WORD,
249 KI_COEFF_HI_DISCHG_OFFSET, 1, 1000, 244141, 0,
250 fg_encode_default, NULL),
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -0700251 PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
252 KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
253 fg_encode_default, NULL),
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -0800254 PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
255 1, 512, 1000000, 0, fg_encode_default, NULL),
256 PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
257 1, 512, 1000000, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -0800258 PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
259 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700260};
261
Harry Yang2452b272017-03-06 13:56:14 -0800262static struct fg_sram_param pmi8998_v2_sram_params[] = {
Nicholas Troasta2b40372016-08-15 10:45:39 -0700263 PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700264 fg_decode_default),
Nicholas Troast1769fd32016-09-07 09:20:58 -0700265 PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
266 fg_decode_default),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800267 PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
268 244141, 0, NULL, fg_decode_voltage_15b),
269 PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700270 fg_decode_voltage_15b),
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800271 PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default,
272 fg_decode_value_16b),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800273 PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700274 fg_decode_value_16b),
Nicholas Troast69da2252016-09-07 16:17:47 -0700275 PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
276 fg_decode_default),
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700277 PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL,
278 fg_decode_cc_soc),
279 PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL,
280 fg_decode_cc_soc),
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -0700281 PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
282 1, 1, 0, NULL, fg_decode_default),
Anirudh Ghayalddabeee2017-04-04 06:13:48 +0530283 PARAM(TIMEBASE, KI_COEFF_MED_DISCHG_WORD, TIMEBASE_OFFSET, 2, 1000,
284 61000, 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700285 /* Entries below here are configurable during initialization */
286 PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
287 244141, 0, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -0700288 PARAM(EMPTY_VOLT, EMPTY_VOLT_v2_WORD, EMPTY_VOLT_v2_OFFSET, 1, 1000,
289 15625, -2000, fg_encode_voltage, NULL),
290 PARAM(VBATT_LOW, VBATT_LOW_v2_WORD, VBATT_LOW_v2_OFFSET, 1, 1000,
291 15625, -2000, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700292 PARAM(FLOAT_VOLT, FLOAT_VOLT_v2_WORD, FLOAT_VOLT_v2_OFFSET, 1, 1000,
293 15625, -2000, fg_encode_voltage, NULL),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800294 PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
295 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700296 PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
297 1000000, 122070, 0, fg_encode_current, NULL),
298 PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1,
299 100000, 390625, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -0700300 PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD,
301 CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0,
302 fg_encode_current, NULL),
Subbaraman Narayanamurthy5566f502017-12-19 19:39:03 -0800303 PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3,
304 1000000, 122070, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800305 PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
306 1, 2048, 100, 0, fg_encode_default, NULL),
307 PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
308 1, 2048, 100, 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700309 PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD,
310 RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default,
311 NULL),
Anirudh Ghayalbcb85772018-08-08 10:17:25 +0530312 PARAM(SYNC_SLEEP_THR, SYNC_SLEEP_THR_v2_WORD, SYNC_SLEEP_THR_v2_OFFSET,
313 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -0800314 PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD,
315 RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000,
316 fg_encode_voltage, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700317 PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
318 ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
319 NULL),
320 PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
321 ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default,
322 NULL),
323 PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
324 ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
325 PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
326 ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -0700327 PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
328 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy13103202018-03-19 12:16:36 -0700329 PARAM(KI_COEFF_LOW_DISCHG, KI_COEFF_LOW_DISCHG_v2_WORD,
330 KI_COEFF_LOW_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
331 fg_encode_default, NULL),
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700332 PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_v2_WORD,
333 KI_COEFF_MED_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
334 fg_encode_default, NULL),
335 PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_v2_WORD,
336 KI_COEFF_HI_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
337 fg_encode_default, NULL),
Subbaraman Narayanamurthy13103202018-03-19 12:16:36 -0700338 PARAM(KI_COEFF_HI_CHG, KI_COEFF_HI_CHG_v2_WORD,
339 KI_COEFF_HI_CHG_v2_OFFSET, 1, 1000, 244141, 0,
340 fg_encode_default, NULL),
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -0700341 PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
342 KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
343 fg_encode_default, NULL),
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -0800344 PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
345 1, 512, 1000000, 0, fg_encode_default, NULL),
346 PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
347 1, 512, 1000000, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -0800348 PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
349 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700350};
351
Harry Yang2452b272017-03-06 13:56:14 -0800352static struct fg_alg_flag pmi8998_v1_alg_flags[] = {
Nicholas Troast69da2252016-09-07 16:17:47 -0700353 [ALG_FLAG_SOC_LT_OTG_MIN] = {
354 .name = "SOC_LT_OTG_MIN",
355 .bit = BIT(0),
356 },
357 [ALG_FLAG_SOC_LT_RECHARGE] = {
358 .name = "SOC_LT_RECHARGE",
359 .bit = BIT(1),
360 },
361 [ALG_FLAG_IBATT_LT_ITERM] = {
362 .name = "IBATT_LT_ITERM",
363 .bit = BIT(2),
364 },
365 [ALG_FLAG_IBATT_GT_HPM] = {
366 .name = "IBATT_GT_HPM",
367 .bit = BIT(3),
368 },
369 [ALG_FLAG_IBATT_GT_UPM] = {
370 .name = "IBATT_GT_UPM",
371 .bit = BIT(4),
372 },
373 [ALG_FLAG_VBATT_LT_RECHARGE] = {
374 .name = "VBATT_LT_RECHARGE",
375 .bit = BIT(5),
376 },
377 [ALG_FLAG_VBATT_GT_VFLOAT] = {
378 .invalid = true,
379 },
380};
381
Harry Yang2452b272017-03-06 13:56:14 -0800382static struct fg_alg_flag pmi8998_v2_alg_flags[] = {
Nicholas Troast69da2252016-09-07 16:17:47 -0700383 [ALG_FLAG_SOC_LT_OTG_MIN] = {
384 .name = "SOC_LT_OTG_MIN",
385 .bit = BIT(0),
386 },
387 [ALG_FLAG_SOC_LT_RECHARGE] = {
388 .name = "SOC_LT_RECHARGE",
389 .bit = BIT(1),
390 },
391 [ALG_FLAG_IBATT_LT_ITERM] = {
392 .name = "IBATT_LT_ITERM",
393 .bit = BIT(2),
394 },
395 [ALG_FLAG_IBATT_GT_HPM] = {
396 .name = "IBATT_GT_HPM",
397 .bit = BIT(4),
398 },
399 [ALG_FLAG_IBATT_GT_UPM] = {
400 .name = "IBATT_GT_UPM",
401 .bit = BIT(5),
402 },
403 [ALG_FLAG_VBATT_LT_RECHARGE] = {
404 .name = "VBATT_LT_RECHARGE",
405 .bit = BIT(6),
406 },
407 [ALG_FLAG_VBATT_GT_VFLOAT] = {
408 .name = "VBATT_GT_VFLOAT",
409 .bit = BIT(7),
410 },
411};
412
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700413static int fg_gen3_debug_mask;
414module_param_named(
415 debug_mask, fg_gen3_debug_mask, int, 0600
416);
417
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800418static bool fg_profile_dump;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700419module_param_named(
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800420 profile_dump, fg_profile_dump, bool, 0600
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700421);
422
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800423static int fg_sram_dump_period_ms = 20000;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700424module_param_named(
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800425 sram_dump_period_ms, fg_sram_dump_period_ms, int, 0600
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700426);
427
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -0700428static int fg_restart;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800429static bool fg_sram_dump;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700430
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700431/* All getters HERE */
432
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700433#define VOLTAGE_15BIT_MASK GENMASK(14, 0)
434static int fg_decode_voltage_15b(struct fg_sram_param *sp,
435 enum fg_sram_param_id id, int value)
436{
437 value &= VOLTAGE_15BIT_MASK;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800438 sp[id].value = div_u64((u64)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700439 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
440 sp[id].value);
441 return sp[id].value;
442}
443
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700444static int fg_decode_cc_soc(struct fg_sram_param *sp,
445 enum fg_sram_param_id id, int value)
446{
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800447 sp[id].value = div_s64((s64)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700448 sp[id].value = sign_extend32(sp[id].value, 31);
449 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
450 sp[id].value);
451 return sp[id].value;
452}
453
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700454static int fg_decode_value_16b(struct fg_sram_param *sp,
455 enum fg_sram_param_id id, int value)
456{
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800457 sp[id].value = div_u64((u64)(u16)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700458 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
459 sp[id].value);
460 return sp[id].value;
461}
462
Nicholas Troaste29dec92016-08-24 09:35:11 -0700463static int fg_decode_default(struct fg_sram_param *sp, enum fg_sram_param_id id,
464 int value)
465{
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700466 sp[id].value = value;
467 return sp[id].value;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700468}
469
470static int fg_decode(struct fg_sram_param *sp, enum fg_sram_param_id id,
471 int value)
472{
473 if (!sp[id].decode) {
474 pr_err("No decoding function for parameter %d\n", id);
475 return -EINVAL;
476 }
477
478 return sp[id].decode(sp, id, value);
479}
480
Nicholas Troasta2b40372016-08-15 10:45:39 -0700481static void fg_encode_voltage(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700482 enum fg_sram_param_id id, int val_mv, u8 *buf)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700483{
484 int i, mask = 0xff;
485 int64_t temp;
486
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700487 val_mv += sp[id].offset;
488 temp = (int64_t)div_u64((u64)val_mv * sp[id].numrtr, sp[id].denmtr);
489 pr_debug("temp: %llx id: %d, val_mv: %d, buf: [ ", temp, id, val_mv);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700490 for (i = 0; i < sp[id].len; i++) {
491 buf[i] = temp & mask;
492 temp >>= 8;
493 pr_debug("%x ", buf[i]);
494 }
495 pr_debug("]\n");
496}
497
498static void fg_encode_current(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700499 enum fg_sram_param_id id, int val_ma, u8 *buf)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700500{
501 int i, mask = 0xff;
502 int64_t temp;
503 s64 current_ma;
504
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700505 current_ma = val_ma;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700506 temp = (int64_t)div_s64(current_ma * sp[id].numrtr, sp[id].denmtr);
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700507 pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val_ma);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700508 for (i = 0; i < sp[id].len; i++) {
509 buf[i] = temp & mask;
510 temp >>= 8;
511 pr_debug("%x ", buf[i]);
512 }
513 pr_debug("]\n");
514}
515
516static void fg_encode_default(struct fg_sram_param *sp,
517 enum fg_sram_param_id id, int val, u8 *buf)
518{
519 int i, mask = 0xff;
520 int64_t temp;
521
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -0700522 temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700523 pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
524 for (i = 0; i < sp[id].len; i++) {
525 buf[i] = temp & mask;
526 temp >>= 8;
527 pr_debug("%x ", buf[i]);
528 }
529 pr_debug("]\n");
530}
531
532static void fg_encode(struct fg_sram_param *sp, enum fg_sram_param_id id,
533 int val, u8 *buf)
534{
535 if (!sp[id].encode) {
536 pr_err("No encoding function for parameter %d\n", id);
537 return;
538 }
539
540 sp[id].encode(sp, id, val, buf);
541}
542
543/*
544 * Please make sure *_sram_params table has the entry for the parameter
545 * obtained through this function. In addition to address, offset,
546 * length from where this SRAM parameter is read, a decode function
547 * need to be specified.
548 */
549static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id,
550 int *val)
551{
552 int temp, rc, i;
553 u8 buf[4];
554
555 if (id < 0 || id > FG_SRAM_MAX || chip->sp[id].len > sizeof(buf))
556 return -EINVAL;
557
Subbaraman Narayanamurthy0a749db2016-10-03 18:33:19 -0700558 if (chip->battery_missing)
559 return -ENODATA;
560
Nicholas Troasta2b40372016-08-15 10:45:39 -0700561 rc = fg_sram_read(chip, chip->sp[id].addr_word, chip->sp[id].addr_byte,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700562 buf, chip->sp[id].len, FG_IMA_DEFAULT);
563 if (rc < 0) {
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -0700564 pr_err("Error reading address %d[%d] rc=%d\n",
Nicholas Troasta2b40372016-08-15 10:45:39 -0700565 chip->sp[id].addr_word, chip->sp[id].addr_byte, rc);
Nicholas Troastb2d71742016-08-04 14:31:41 -0700566 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700567 }
568
569 for (i = 0, temp = 0; i < chip->sp[id].len; i++)
570 temp |= buf[i] << (8 * i);
571
572 *val = fg_decode(chip->sp, id, temp);
573 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700574}
575
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700576#define CC_SOC_30BIT GENMASK(29, 0)
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -0700577static int fg_get_charge_raw(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700578{
579 int rc, cc_soc;
580
581 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC, &cc_soc);
582 if (rc < 0) {
583 pr_err("Error in getting CC_SOC, rc=%d\n", rc);
584 return rc;
585 }
586
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +0530587 *val = div_s64((int64_t)cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700588 return 0;
589}
590
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -0700591#define BATT_SOC_32BIT GENMASK(31, 0)
592static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val)
593{
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +0530594 int rc;
595 unsigned int batt_soc;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -0700596
597 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
598 if (rc < 0) {
599 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
600 return rc;
601 }
602
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +0530603 *val = div_u64((uint64_t)batt_soc * chip->cl.learned_cc_uah,
604 BATT_SOC_32BIT);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -0700605 return 0;
606}
607
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -0700608static int fg_get_charge_counter(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700609{
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +0530610 int rc;
611 int cc_soc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700612
613 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc);
614 if (rc < 0) {
615 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
616 return rc;
617 }
618
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +0530619 *val = div_s64((int64_t)cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700620 return 0;
621}
622
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -0700623static int fg_get_jeita_threshold(struct fg_chip *chip,
624 enum jeita_levels level, int *temp_decidegC)
625{
626 int rc;
627 u8 val;
628 u16 reg;
629
630 switch (level) {
631 case JEITA_COLD:
632 reg = BATT_INFO_JEITA_TOO_COLD(chip);
633 break;
634 case JEITA_COOL:
635 reg = BATT_INFO_JEITA_COLD(chip);
636 break;
637 case JEITA_WARM:
638 reg = BATT_INFO_JEITA_HOT(chip);
639 break;
640 case JEITA_HOT:
641 reg = BATT_INFO_JEITA_TOO_HOT(chip);
642 break;
643 default:
644 return -EINVAL;
645 }
646
647 rc = fg_read(chip, reg, &val, 1);
648 if (rc < 0) {
649 pr_err("Error in reading jeita level %d, rc=%d\n", level, rc);
650 return rc;
651 }
652
653 /* Resolution is 0.5C. Base is -30C. */
654 *temp_decidegC = (((5 * val) / 10) - 30) * 10;
655 return 0;
656}
657
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700658#define BATT_TEMP_NUMR 1
659#define BATT_TEMP_DENR 1
660static int fg_get_battery_temp(struct fg_chip *chip, int *val)
661{
Subbaraman Narayanamurthyfabbb8e2016-10-21 16:55:09 -0700662 int rc = 0, temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700663 u8 buf[2];
664
665 rc = fg_read(chip, BATT_INFO_BATT_TEMP_LSB(chip), buf, 2);
666 if (rc < 0) {
667 pr_err("failed to read addr=0x%04x, rc=%d\n",
668 BATT_INFO_BATT_TEMP_LSB(chip), rc);
669 return rc;
670 }
671
672 temp = ((buf[1] & BATT_TEMP_MSB_MASK) << 8) |
673 (buf[0] & BATT_TEMP_LSB_MASK);
674 temp = DIV_ROUND_CLOSEST(temp, 4);
675
676 /* Value is in Kelvin; Convert it to deciDegC */
677 temp = (temp - 273) * 10;
678 *val = temp;
679 return 0;
680}
681
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700682static int fg_get_battery_resistance(struct fg_chip *chip, int *val)
683{
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800684 int rc, esr_uohms, rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700685
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800686 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700687 if (rc < 0) {
688 pr_err("failed to get ESR, rc=%d\n", rc);
689 return rc;
690 }
691
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800692 rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &rslow_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700693 if (rc < 0) {
694 pr_err("failed to get Rslow, rc=%d\n", rc);
695 return rc;
696 }
697
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800698 *val = esr_uohms + rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700699 return 0;
700}
701
702#define BATT_CURRENT_NUMR 488281
703#define BATT_CURRENT_DENR 1000
704static int fg_get_battery_current(struct fg_chip *chip, int *val)
705{
706 int rc = 0;
707 int64_t temp = 0;
708 u8 buf[2];
709
710 rc = fg_read(chip, BATT_INFO_IBATT_LSB(chip), buf, 2);
711 if (rc < 0) {
712 pr_err("failed to read addr=0x%04x, rc=%d\n",
713 BATT_INFO_IBATT_LSB(chip), rc);
714 return rc;
715 }
716
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530717 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700718 temp = buf[0] << 8 | buf[1];
719 else
720 temp = buf[1] << 8 | buf[0];
721
722 pr_debug("buf: %x %x temp: %llx\n", buf[0], buf[1], temp);
723 /* Sign bit is bit 15 */
724 temp = twos_compliment_extend(temp, 15);
725 *val = div_s64((s64)temp * BATT_CURRENT_NUMR, BATT_CURRENT_DENR);
726 return 0;
727}
728
729#define BATT_VOLTAGE_NUMR 122070
730#define BATT_VOLTAGE_DENR 1000
731static int fg_get_battery_voltage(struct fg_chip *chip, int *val)
732{
733 int rc = 0;
734 u16 temp = 0;
735 u8 buf[2];
736
737 rc = fg_read(chip, BATT_INFO_VBATT_LSB(chip), buf, 2);
738 if (rc < 0) {
739 pr_err("failed to read addr=0x%04x, rc=%d\n",
740 BATT_INFO_VBATT_LSB(chip), rc);
741 return rc;
742 }
743
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530744 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700745 temp = buf[0] << 8 | buf[1];
746 else
747 temp = buf[1] << 8 | buf[0];
748
749 pr_debug("buf: %x %x temp: %x\n", buf[0], buf[1], temp);
750 *val = div_u64((u64)temp * BATT_VOLTAGE_NUMR, BATT_VOLTAGE_DENR);
751 return 0;
752}
753
754#define MAX_TRIES_SOC 5
755static int fg_get_msoc_raw(struct fg_chip *chip, int *val)
756{
757 u8 cap[2];
758 int rc, tries = 0;
759
760 while (tries < MAX_TRIES_SOC) {
761 rc = fg_read(chip, BATT_SOC_FG_MONOTONIC_SOC(chip), cap, 2);
762 if (rc < 0) {
763 pr_err("failed to read addr=0x%04x, rc=%d\n",
764 BATT_SOC_FG_MONOTONIC_SOC(chip), rc);
765 return rc;
766 }
767
768 if (cap[0] == cap[1])
769 break;
770
771 tries++;
772 }
773
774 if (tries == MAX_TRIES_SOC) {
775 pr_err("shadow registers do not match\n");
776 return -EINVAL;
777 }
778
779 fg_dbg(chip, FG_POWER_SUPPLY, "raw: 0x%02x\n", cap[0]);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700780 *val = cap[0];
781 return 0;
782}
783
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800784#define FULL_CAPACITY 100
785#define FULL_SOC_RAW 255
786static int fg_get_msoc(struct fg_chip *chip, int *msoc)
787{
788 int rc;
789
790 rc = fg_get_msoc_raw(chip, msoc);
791 if (rc < 0)
792 return rc;
793
Subbaraman Narayanamurthy286d5162017-10-27 20:02:54 -0700794 /*
795 * To have better endpoints for 0 and 100, it is good to tune the
796 * calculation discarding values 0 and 255 while rounding off. Rest
797 * of the values 1-254 will be scaled to 1-99. DIV_ROUND_UP will not
798 * be suitable here as it rounds up any value higher than 252 to 100.
799 */
800 if (*msoc == FULL_SOC_RAW)
801 *msoc = 100;
802 else if (*msoc == 0)
803 *msoc = 0;
804 else
805 *msoc = DIV_ROUND_CLOSEST((*msoc - 1) * (FULL_CAPACITY - 2),
806 FULL_SOC_RAW - 2) + 1;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800807 return 0;
808}
809
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800810static bool is_batt_empty(struct fg_chip *chip)
811{
812 u8 status;
813 int rc, vbatt_uv, msoc;
814
815 rc = fg_read(chip, BATT_SOC_INT_RT_STS(chip), &status, 1);
816 if (rc < 0) {
817 pr_err("failed to read addr=0x%04x, rc=%d\n",
818 BATT_SOC_INT_RT_STS(chip), rc);
819 return false;
820 }
821
822 if (!(status & MSOC_EMPTY_BIT))
823 return false;
824
825 rc = fg_get_battery_voltage(chip, &vbatt_uv);
826 if (rc < 0) {
827 pr_err("failed to get battery voltage, rc=%d\n", rc);
828 return false;
829 }
830
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800831 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800832 if (!rc)
833 pr_warn("batt_soc_rt_sts: %x vbatt: %d uV msoc:%d\n", status,
834 vbatt_uv, msoc);
835
836 return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false);
837}
838
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800839static int fg_get_debug_batt_id(struct fg_chip *chip, int *batt_id)
840{
841 int rc;
842 u64 temp;
843 u8 buf[2];
844
845 rc = fg_read(chip, ADC_RR_FAKE_BATT_LOW_LSB(chip), buf, 2);
846 if (rc < 0) {
847 pr_err("failed to read addr=0x%04x, rc=%d\n",
848 ADC_RR_FAKE_BATT_LOW_LSB(chip), rc);
849 return rc;
850 }
851
852 /*
853 * Fake battery threshold is encoded in the following format.
854 * Threshold (code) = (battery_id in Ohms) * 0.00015 * 2^10 / 2.5
855 */
856 temp = (buf[1] << 8 | buf[0]) * 2500000;
857 do_div(temp, 150 * 1024);
858 batt_id[0] = temp;
859 rc = fg_read(chip, ADC_RR_FAKE_BATT_HIGH_LSB(chip), buf, 2);
860 if (rc < 0) {
861 pr_err("failed to read addr=0x%04x, rc=%d\n",
862 ADC_RR_FAKE_BATT_HIGH_LSB(chip), rc);
863 return rc;
864 }
865
866 temp = (buf[1] << 8 | buf[0]) * 2500000;
867 do_div(temp, 150 * 1024);
868 batt_id[1] = temp;
869 pr_debug("debug batt_id range: [%d %d]\n", batt_id[0], batt_id[1]);
870 return 0;
871}
872
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700873static bool is_debug_batt_id(struct fg_chip *chip)
874{
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800875 int debug_batt_id[2], rc;
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700876
Fenglin Wu16ef9a72017-11-06 23:24:54 +0800877 if (chip->batt_id_ohms < 0)
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700878 return false;
879
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800880 rc = fg_get_debug_batt_id(chip, debug_batt_id);
881 if (rc < 0) {
882 pr_err("Failed to get debug batt_id, rc=%d\n", rc);
883 return false;
884 }
885
886 if (is_between(debug_batt_id[0], debug_batt_id[1],
887 chip->batt_id_ohms)) {
888 fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dohms\n",
889 chip->batt_id_ohms);
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700890 return true;
891 }
892
893 return false;
894}
895
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700896#define DEBUG_BATT_SOC 67
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800897#define BATT_MISS_SOC 50
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700898#define EMPTY_SOC 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700899static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
900{
901 int rc, msoc;
902
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700903 if (is_debug_batt_id(chip)) {
904 *val = DEBUG_BATT_SOC;
905 return 0;
906 }
907
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800908 if (chip->fg_restarting) {
909 *val = chip->last_soc;
910 return 0;
911 }
912
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -0800913 if (chip->battery_missing || !chip->soc_reporting_ready) {
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800914 *val = BATT_MISS_SOC;
915 return 0;
916 }
917
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800918 if (is_batt_empty(chip)) {
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700919 *val = EMPTY_SOC;
920 return 0;
921 }
922
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700923 if (chip->charge_full) {
924 *val = FULL_CAPACITY;
925 return 0;
926 }
927
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800928 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700929 if (rc < 0)
930 return rc;
931
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -0700932 if (chip->dt.linearize_soc && chip->delta_soc > 0)
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800933 *val = chip->maint_soc;
934 else
935 *val = msoc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700936 return 0;
937}
938
Anirudh Ghayalaf38fdc2019-05-23 14:19:42 +0530939static int fg_get_prop_real_capacity(struct fg_chip *chip, int *val)
940{
941 return fg_get_msoc(chip, val);
942}
943
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700944#define DEFAULT_BATT_TYPE "Unknown Battery"
945#define MISSING_BATT_TYPE "Missing Battery"
946#define LOADING_BATT_TYPE "Loading Battery"
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -0800947#define SKIP_BATT_TYPE "Skipped loading battery"
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700948static const char *fg_get_battery_type(struct fg_chip *chip)
949{
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -0800950 if (chip->battery_missing ||
951 chip->profile_load_status == PROFILE_MISSING)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700952 return MISSING_BATT_TYPE;
953
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -0800954 if (chip->profile_load_status == PROFILE_SKIPPED)
955 return SKIP_BATT_TYPE;
956
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700957 if (chip->bp.batt_type_str) {
958 if (chip->profile_loaded)
959 return chip->bp.batt_type_str;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -0800960 else if (chip->profile_available)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700961 return LOADING_BATT_TYPE;
962 }
963
964 return DEFAULT_BATT_TYPE;
965}
966
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800967static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700968{
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800969 int rc;
970
971 rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
972 BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
973 if (rc < 0)
974 pr_err("Error in writing to %04x, rc=%d\n",
975 BATT_INFO_BATT_MISS_CFG(chip), rc);
976 return rc;
977}
978
979static int fg_get_batt_id(struct fg_chip *chip)
980{
981 int rc, ret, batt_id = 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700982
983 if (!chip->batt_id_chan)
984 return -EINVAL;
985
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800986 rc = fg_batt_missing_config(chip, false);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700987 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800988 pr_err("Error in disabling BMD, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700989 return rc;
990 }
991
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800992 rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
993 if (rc < 0) {
994 pr_err("Error in reading batt_id channel, rc:%d\n", rc);
995 goto out;
996 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700997
Fenglin Wud10ccf12017-08-10 15:43:41 +0800998 /* Wait for BATT_ID to settle down before enabling BMD again */
999 msleep(chip->dt.bmd_en_delay_ms);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001000
1001 fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
1002 chip->batt_id_ohms = batt_id;
1003out:
1004 ret = fg_batt_missing_config(chip, true);
1005 if (ret < 0) {
1006 pr_err("Error in enabling BMD, ret=%d\n", ret);
1007 return ret;
1008 }
1009
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001010 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, true, 0);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001011 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001012}
1013
1014static int fg_get_batt_profile(struct fg_chip *chip)
1015{
1016 struct device_node *node = chip->dev->of_node;
1017 struct device_node *batt_node, *profile_node;
1018 const char *data;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001019 int rc, len;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001020
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001021 batt_node = of_find_node_by_name(node, "qcom,battery-data");
1022 if (!batt_node) {
1023 pr_err("Batterydata not available\n");
1024 return -ENXIO;
1025 }
1026
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001027 profile_node = of_batterydata_get_best_profile(batt_node,
1028 chip->batt_id_ohms / 1000, NULL);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001029 if (IS_ERR(profile_node))
1030 return PTR_ERR(profile_node);
1031
1032 if (!profile_node) {
1033 pr_err("couldn't find profile handle\n");
1034 return -ENODATA;
1035 }
1036
1037 rc = of_property_read_string(profile_node, "qcom,battery-type",
1038 &chip->bp.batt_type_str);
1039 if (rc < 0) {
1040 pr_err("battery type unavailable, rc:%d\n", rc);
1041 return rc;
1042 }
1043
1044 rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
1045 &chip->bp.float_volt_uv);
1046 if (rc < 0) {
1047 pr_err("battery float voltage unavailable, rc:%d\n", rc);
1048 chip->bp.float_volt_uv = -EINVAL;
1049 }
1050
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -08001051 rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001052 &chip->bp.fastchg_curr_ma);
1053 if (rc < 0) {
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -08001054 pr_err("battery fastchg current unavailable, rc:%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001055 chip->bp.fastchg_curr_ma = -EINVAL;
1056 }
1057
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07001058 rc = of_property_read_u32(profile_node, "qcom,fg-cc-cv-threshold-mv",
1059 &chip->bp.vbatt_full_mv);
1060 if (rc < 0) {
1061 pr_err("battery cc_cv threshold unavailable, rc:%d\n", rc);
1062 chip->bp.vbatt_full_mv = -EINVAL;
1063 }
1064
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001065 data = of_get_property(profile_node, "qcom,fg-profile-data", &len);
1066 if (!data) {
1067 pr_err("No profile data available\n");
1068 return -ENODATA;
1069 }
1070
1071 if (len != PROFILE_LEN) {
1072 pr_err("battery profile incorrect size: %d\n", len);
1073 return -EINVAL;
1074 }
1075
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07001076 chip->profile_available = true;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001077 memcpy(chip->batt_profile, data, len);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08001078
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07001079 return 0;
1080}
1081
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07001082static inline void get_batt_temp_delta(int delta, u8 *val)
1083{
1084 switch (delta) {
1085 case 2:
1086 *val = BTEMP_DELTA_2K;
1087 break;
1088 case 4:
1089 *val = BTEMP_DELTA_4K;
1090 break;
1091 case 6:
1092 *val = BTEMP_DELTA_6K;
1093 break;
1094 case 10:
1095 *val = BTEMP_DELTA_10K;
1096 break;
1097 default:
1098 *val = BTEMP_DELTA_2K;
1099 break;
1100 };
1101}
1102
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07001103static inline void get_esr_meas_current(int curr_ma, u8 *val)
1104{
1105 switch (curr_ma) {
1106 case 60:
1107 *val = ESR_MEAS_CUR_60MA;
1108 break;
1109 case 120:
1110 *val = ESR_MEAS_CUR_120MA;
1111 break;
1112 case 180:
1113 *val = ESR_MEAS_CUR_180MA;
1114 break;
1115 case 240:
1116 *val = ESR_MEAS_CUR_240MA;
1117 break;
1118 default:
1119 *val = ESR_MEAS_CUR_120MA;
1120 break;
1121 };
1122
1123 *val <<= ESR_PULL_DOWN_IVAL_SHIFT;
1124}
1125
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001126static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
1127 int cycles_max, bool charging, int flags)
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001128{
1129 u8 buf[2];
1130 int rc, timer_max, timer_init;
1131
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001132 if (cycles_init < 0 || cycles_max < 0)
1133 return 0;
1134
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001135 if (charging) {
1136 timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
1137 timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
1138 } else {
1139 timer_max = FG_SRAM_ESR_TIMER_DISCHG_MAX;
1140 timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
1141 }
1142
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001143 fg_encode(chip->sp, timer_max, cycles_max, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001144 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001145 chip->sp[timer_max].addr_word,
1146 chip->sp[timer_max].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001147 chip->sp[timer_max].len, flags);
1148 if (rc < 0) {
1149 pr_err("Error in writing esr_timer_dischg_max, rc=%d\n",
1150 rc);
1151 return rc;
1152 }
1153
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001154 fg_encode(chip->sp, timer_init, cycles_init, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001155 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001156 chip->sp[timer_init].addr_word,
1157 chip->sp[timer_init].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001158 chip->sp[timer_init].len, flags);
1159 if (rc < 0) {
1160 pr_err("Error in writing esr_timer_dischg_init, rc=%d\n",
1161 rc);
1162 return rc;
1163 }
1164
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001165 fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
1166 charging ? "charging" : "discharging", cycles_init, cycles_max);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001167 return 0;
1168}
1169
Nicholas Troaste29dec92016-08-24 09:35:11 -07001170/* Other functions HERE */
1171
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001172static void fg_notify_charger(struct fg_chip *chip)
1173{
1174 union power_supply_propval prop = {0, };
1175 int rc;
1176
1177 if (!chip->batt_psy)
1178 return;
1179
1180 if (!chip->profile_available)
1181 return;
1182
1183 prop.intval = chip->bp.float_volt_uv;
1184 rc = power_supply_set_property(chip->batt_psy,
1185 POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
1186 if (rc < 0) {
1187 pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
1188 rc);
1189 return;
1190 }
1191
1192 prop.intval = chip->bp.fastchg_curr_ma * 1000;
1193 rc = power_supply_set_property(chip->batt_psy,
1194 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
1195 if (rc < 0) {
1196 pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
1197 rc);
1198 return;
1199 }
1200
1201 fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
1202}
1203
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001204static int fg_batt_miss_irq_en_cb(struct votable *votable, void *data,
1205 int enable, const char *client)
1206{
1207 struct fg_chip *chip = data;
1208
1209 if (!chip->irqs[BATT_MISSING_IRQ].irq)
1210 return 0;
1211
1212 if (enable) {
1213 enable_irq(chip->irqs[BATT_MISSING_IRQ].irq);
1214 enable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
1215 } else {
1216 disable_irq_wake(chip->irqs[BATT_MISSING_IRQ].irq);
Subbaraman Narayanamurthyd1b4c842017-09-29 16:07:28 -07001217 disable_irq_nosync(chip->irqs[BATT_MISSING_IRQ].irq);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07001218 }
1219
1220 return 0;
1221}
1222
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001223static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data,
1224 int enable, const char *client)
1225{
1226 struct fg_chip *chip = data;
1227
1228 if (!chip->irqs[BSOC_DELTA_IRQ].irq)
1229 return 0;
1230
1231 if (enable) {
1232 enable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1233 enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1234 } else {
1235 disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
Subbaraman Narayanamurthyd1b4c842017-09-29 16:07:28 -07001236 disable_irq_nosync(chip->irqs[BSOC_DELTA_IRQ].irq);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001237 }
1238
1239 return 0;
1240}
1241
Nicholas Troaste29dec92016-08-24 09:35:11 -07001242static int fg_awake_cb(struct votable *votable, void *data, int awake,
1243 const char *client)
1244{
1245 struct fg_chip *chip = data;
1246
1247 if (awake)
1248 pm_stay_awake(chip->dev);
1249 else
1250 pm_relax(chip->dev);
1251
1252 pr_debug("client: %s awake: %d\n", client, awake);
1253 return 0;
1254}
1255
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001256static bool batt_psy_initialized(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07001257{
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001258 if (chip->batt_psy)
1259 return true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07001260
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001261 chip->batt_psy = power_supply_get_by_name("battery");
Nicholas Troaste29dec92016-08-24 09:35:11 -07001262 if (!chip->batt_psy)
1263 return false;
1264
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001265 /* batt_psy is initialized, set the fcc and fv */
1266 fg_notify_charger(chip);
1267
Nicholas Troaste29dec92016-08-24 09:35:11 -07001268 return true;
1269}
1270
Nicholas Troast805c2422017-07-06 14:53:46 -07001271static bool usb_psy_initialized(struct fg_chip *chip)
1272{
1273 if (chip->usb_psy)
1274 return true;
1275
1276 chip->usb_psy = power_supply_get_by_name("usb");
1277 if (!chip->usb_psy)
1278 return false;
1279
1280 return true;
1281}
1282
1283static bool pc_port_psy_initialized(struct fg_chip *chip)
1284{
1285 if (chip->pc_port_psy)
1286 return true;
1287
1288 chip->pc_port_psy = power_supply_get_by_name("pc_port");
1289 if (!chip->pc_port_psy)
1290 return false;
1291
1292 return true;
1293}
1294
1295static bool dc_psy_initialized(struct fg_chip *chip)
1296{
1297 if (chip->dc_psy)
1298 return true;
1299
1300 chip->dc_psy = power_supply_get_by_name("dc");
1301 if (!chip->dc_psy)
1302 return false;
1303
1304 return true;
1305}
1306
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001307static bool is_parallel_charger_available(struct fg_chip *chip)
1308{
1309 if (!chip->parallel_psy)
1310 chip->parallel_psy = power_supply_get_by_name("parallel");
1311
1312 if (!chip->parallel_psy)
1313 return false;
1314
1315 return true;
1316}
1317
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301318static int fg_prime_cc_soc_sw(struct fg_chip *chip, unsigned int cc_soc_sw)
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001319{
1320 int rc;
1321
1322 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1323 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
1324 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
1325 if (rc < 0)
1326 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1327 else
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301328 fg_dbg(chip, FG_STATUS, "cc_soc_sw: %u\n", cc_soc_sw);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001329
1330 return rc;
1331}
1332
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001333static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
1334{
1335 int16_t cc_mah;
1336 int rc;
1337
1338 if (chip->battery_missing || !chip->cl.learned_cc_uah)
1339 return -EPERM;
1340
1341 cc_mah = div64_s64(chip->cl.learned_cc_uah, 1000);
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001342 /* Write to a backup register to use across reboot */
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001343 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word,
1344 chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah,
1345 chip->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT);
1346 if (rc < 0) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001347 pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc);
1348 return rc;
1349 }
1350
1351 /* Write to actual capacity register for coulomb counter operation */
1352 rc = fg_sram_write(chip, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET,
1353 (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len,
1354 FG_IMA_DEFAULT);
1355 if (rc < 0) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001356 pr_err("Error in writing act_batt_cap, rc=%d\n", rc);
1357 return rc;
1358 }
1359
1360 fg_dbg(chip, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n",
1361 chip->cl.learned_cc_uah, cc_mah);
1362 return 0;
1363}
1364
1365#define CAPACITY_DELTA_DECIPCT 500
1366static int fg_load_learned_cap_from_sram(struct fg_chip *chip)
1367{
1368 int rc, act_cap_mah;
1369 int64_t delta_cc_uah, pct_nom_cap_uah;
1370
1371 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
1372 if (rc < 0) {
1373 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1374 return rc;
1375 }
1376
1377 chip->cl.learned_cc_uah = act_cap_mah * 1000;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001378
1379 if (chip->cl.learned_cc_uah != chip->cl.nom_cap_uah) {
Subbaraman Narayanamurthy51d3c902016-10-24 14:05:44 -07001380 if (chip->cl.learned_cc_uah == 0)
1381 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
1382
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001383 delta_cc_uah = abs(chip->cl.learned_cc_uah -
1384 chip->cl.nom_cap_uah);
1385 pct_nom_cap_uah = div64_s64((int64_t)chip->cl.nom_cap_uah *
1386 CAPACITY_DELTA_DECIPCT, 1000);
1387 /*
1388 * If the learned capacity is out of range by 50% from the
1389 * nominal capacity, then overwrite the learned capacity with
1390 * the nominal capacity.
1391 */
1392 if (chip->cl.nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001393 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected, capping it to nominal: %lld\n",
1394 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001395 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001396 }
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001397
1398 rc = fg_save_learned_cap_to_sram(chip);
1399 if (rc < 0)
1400 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001401 }
1402
1403 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah:%lld nom_cap_uah: %lld\n",
1404 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
1405 return 0;
1406}
1407
1408static bool is_temp_valid_cap_learning(struct fg_chip *chip)
1409{
1410 int rc, batt_temp;
1411
1412 rc = fg_get_battery_temp(chip, &batt_temp);
1413 if (rc < 0) {
1414 pr_err("Error in getting batt_temp\n");
1415 return false;
1416 }
1417
1418 if (batt_temp > chip->dt.cl_max_temp ||
1419 batt_temp < chip->dt.cl_min_temp) {
1420 fg_dbg(chip, FG_CAP_LEARN, "batt temp %d out of range [%d %d]\n",
1421 batt_temp, chip->dt.cl_min_temp, chip->dt.cl_max_temp);
1422 return false;
1423 }
1424
1425 return true;
1426}
1427
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001428#define QNOVO_CL_SKEW_DECIPCT -30
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001429static void fg_cap_learning_post_process(struct fg_chip *chip)
1430{
1431 int64_t max_inc_val, min_dec_val, old_cap;
1432 int rc;
1433
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001434 if (is_qnovo_en(chip)) {
1435 fg_dbg(chip, FG_CAP_LEARN, "applying skew %d on current learnt capacity %lld\n",
1436 QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
1437 chip->cl.final_cc_uah = chip->cl.final_cc_uah *
1438 (1000 + QNOVO_CL_SKEW_DECIPCT);
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07001439 chip->cl.final_cc_uah = div64_u64(chip->cl.final_cc_uah, 1000);
Subbaraman Narayanamurthyd1190cf2017-06-23 18:25:09 -07001440 }
1441
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001442 max_inc_val = chip->cl.learned_cc_uah
1443 * (1000 + chip->dt.cl_max_cap_inc);
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07001444 max_inc_val = div64_u64(max_inc_val, 1000);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001445
1446 min_dec_val = chip->cl.learned_cc_uah
1447 * (1000 - chip->dt.cl_max_cap_dec);
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07001448 min_dec_val = div64_u64(min_dec_val, 1000);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001449
1450 old_cap = chip->cl.learned_cc_uah;
1451 if (chip->cl.final_cc_uah > max_inc_val)
1452 chip->cl.learned_cc_uah = max_inc_val;
1453 else if (chip->cl.final_cc_uah < min_dec_val)
1454 chip->cl.learned_cc_uah = min_dec_val;
1455 else
1456 chip->cl.learned_cc_uah =
1457 chip->cl.final_cc_uah;
1458
1459 if (chip->dt.cl_max_cap_limit) {
1460 max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
1461 chip->dt.cl_max_cap_limit);
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07001462 max_inc_val = div64_u64(max_inc_val, 1000);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001463 if (chip->cl.final_cc_uah > max_inc_val) {
1464 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
1465 chip->cl.final_cc_uah, max_inc_val);
1466 chip->cl.learned_cc_uah = max_inc_val;
1467 }
1468 }
1469
1470 if (chip->dt.cl_min_cap_limit) {
1471 min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
1472 chip->dt.cl_min_cap_limit);
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07001473 min_dec_val = div64_u64(min_dec_val, 1000);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001474 if (chip->cl.final_cc_uah < min_dec_val) {
1475 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
1476 chip->cl.final_cc_uah, min_dec_val);
1477 chip->cl.learned_cc_uah = min_dec_val;
1478 }
1479 }
1480
1481 rc = fg_save_learned_cap_to_sram(chip);
1482 if (rc < 0)
1483 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
1484
1485 fg_dbg(chip, FG_CAP_LEARN, "final cc_uah = %lld, learned capacity %lld -> %lld uah\n",
1486 chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah);
1487}
1488
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001489static int fg_cap_learning_process_full_data(struct fg_chip *chip)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001490{
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301491 int rc;
1492 unsigned int cc_soc_sw;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001493 int64_t delta_cc_uah;
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301494 unsigned int cc_soc_delta_pct;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001495
1496 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
1497 if (rc < 0) {
1498 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
1499 return rc;
1500 }
1501
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -07001502 cc_soc_delta_pct =
1503 div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
1504 CC_SOC_30BIT);
1505
1506 /* If the delta is < 50%, then skip processing full data */
1507 if (cc_soc_delta_pct < 50) {
1508 pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
1509 return -ERANGE;
1510 }
1511
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301512 delta_cc_uah = div64_u64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001513 100);
1514 chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301515 fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%u total_cc_uah=%llu\n",
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001516 cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
1517 return 0;
1518}
1519
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001520static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001521{
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301522 int rc;
1523 unsigned int batt_soc_msb, cc_soc_sw;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001524
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001525 batt_soc_msb = batt_soc >> 24;
1526 if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001527 chip->dt.cl_start_soc) {
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301528 fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %u is high!, not starting\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001529 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001530 return -EINVAL;
1531 }
1532
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301533 chip->cl.init_cc_uah = div64_u64(chip->cl.learned_cc_uah * batt_soc_msb,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001534 FULL_SOC_RAW);
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001535
1536 /* Prime cc_soc_sw with battery SOC when capacity learning begins */
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301537 cc_soc_sw = div64_u64((uint64_t)batt_soc * CC_SOC_30BIT,
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001538 BATT_SOC_32BIT);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001539 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001540 if (rc < 0) {
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001541 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1542 goto out;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001543 }
1544
1545 chip->cl.init_cc_soc_sw = cc_soc_sw;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001546 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 -07001547 batt_soc_msb, chip->cl.init_cc_soc_sw);
1548out:
1549 return rc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001550}
1551
1552static int fg_cap_learning_done(struct fg_chip *chip)
1553{
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301554 int rc;
1555 unsigned int cc_soc_sw;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001556
1557 rc = fg_cap_learning_process_full_data(chip);
1558 if (rc < 0) {
1559 pr_err("Error in processing cap learning full data, rc=%d\n",
1560 rc);
1561 goto out;
1562 }
1563
1564 /* Write a FULL value to cc_soc_sw */
1565 cc_soc_sw = CC_SOC_30BIT;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001566 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001567 if (rc < 0) {
1568 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1569 goto out;
1570 }
1571
1572 fg_cap_learning_post_process(chip);
1573out:
1574 return rc;
1575}
1576
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001577static void fg_cap_learning_update(struct fg_chip *chip)
1578{
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301579 int rc;
1580 unsigned int batt_soc, batt_soc_msb, cc_soc_sw;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001581 bool input_present = is_input_present(chip);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001582 bool prime_cc = false;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001583
1584 mutex_lock(&chip->cl.lock);
1585
1586 if (!is_temp_valid_cap_learning(chip) || !chip->cl.learned_cc_uah ||
1587 chip->battery_missing) {
1588 fg_dbg(chip, FG_CAP_LEARN, "Aborting cap_learning %lld\n",
1589 chip->cl.learned_cc_uah);
1590 chip->cl.active = false;
1591 chip->cl.init_cc_uah = 0;
1592 goto out;
1593 }
1594
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001595 if (chip->charge_status == chip->prev_charge_status)
1596 goto out;
1597
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001598 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
1599 if (rc < 0) {
1600 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1601 goto out;
1602 }
1603
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001604 batt_soc_msb = (u32)batt_soc >> 24;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001605 fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001606 chip->charge_status, chip->cl.active, batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001607
1608 /* Initialize the starting point of learning capacity */
1609 if (!chip->cl.active) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07001610 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001611 rc = fg_cap_learning_begin(chip, batt_soc);
1612 chip->cl.active = (rc == 0);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001613 } else {
1614 if ((chip->charge_status ==
1615 POWER_SUPPLY_STATUS_DISCHARGING) ||
1616 chip->charge_done)
1617 prime_cc = true;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001618 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001619 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001620 if (chip->charge_done) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001621 rc = fg_cap_learning_done(chip);
1622 if (rc < 0)
1623 pr_err("Error in completing capacity learning, rc=%d\n",
1624 rc);
1625
1626 chip->cl.active = false;
1627 chip->cl.init_cc_uah = 0;
1628 }
1629
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001630 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
1631 if (!input_present) {
1632 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1633 batt_soc_msb);
1634 chip->cl.active = false;
1635 chip->cl.init_cc_uah = 0;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001636 prime_cc = true;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001637 }
1638 }
1639
Nicholas Troast1769fd32016-09-07 09:20:58 -07001640 if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001641 if (is_qnovo_en(chip) && input_present) {
1642 /*
1643 * Don't abort the capacity learning when qnovo
1644 * is enabled and input is present where the
1645 * charging status can go to "not charging"
1646 * intermittently.
1647 */
1648 } else {
1649 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
1650 batt_soc_msb);
1651 chip->cl.active = false;
1652 chip->cl.init_cc_uah = 0;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001653 prime_cc = true;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07001654 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001655 }
1656 }
1657
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001658 /*
1659 * Prime CC_SOC_SW when the device is not charging or during charge
1660 * termination when the capacity learning is not active.
1661 */
1662
1663 if (prime_cc) {
1664 if (chip->charge_done)
1665 cc_soc_sw = CC_SOC_30BIT;
1666 else
Ashay Jaiswalbd8070f2018-06-16 19:54:05 +05301667 cc_soc_sw = div_u64((uint64_t)batt_soc *
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07001668 CC_SOC_30BIT, BATT_SOC_32BIT);
1669
1670 rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
1671 if (rc < 0)
1672 pr_err("Error in writing cc_soc_sw, rc=%d\n",
1673 rc);
1674 }
1675
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001676out:
1677 mutex_unlock(&chip->cl.lock);
1678}
1679
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07001680#define KI_COEFF_LOW_DISCHG_DEFAULT 800
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001681#define KI_COEFF_MED_DISCHG_DEFAULT 1500
1682#define KI_COEFF_HI_DISCHG_DEFAULT 2200
1683static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
1684{
1685 int rc, i, msoc;
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07001686 int ki_coeff_low = KI_COEFF_LOW_DISCHG_DEFAULT;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001687 int ki_coeff_med = KI_COEFF_MED_DISCHG_DEFAULT;
1688 int ki_coeff_hi = KI_COEFF_HI_DISCHG_DEFAULT;
1689 u8 val;
1690
1691 if (!chip->ki_coeff_dischg_en)
1692 return 0;
1693
1694 rc = fg_get_prop_capacity(chip, &msoc);
1695 if (rc < 0) {
1696 pr_err("Error in getting capacity, rc=%d\n", rc);
1697 return rc;
1698 }
1699
Nicholas Troast1769fd32016-09-07 09:20:58 -07001700 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001701 for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) {
1702 if (msoc < chip->dt.ki_coeff_soc[i]) {
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07001703 ki_coeff_low = chip->dt.ki_coeff_low_dischg[i];
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001704 ki_coeff_med = chip->dt.ki_coeff_med_dischg[i];
1705 ki_coeff_hi = chip->dt.ki_coeff_hi_dischg[i];
1706 }
1707 }
1708 }
1709
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07001710 fg_encode(chip->sp, FG_SRAM_KI_COEFF_LOW_DISCHG, ki_coeff_low, &val);
1711 rc = fg_sram_write(chip,
1712 chip->sp[FG_SRAM_KI_COEFF_LOW_DISCHG].addr_word,
1713 chip->sp[FG_SRAM_KI_COEFF_LOW_DISCHG].addr_byte, &val,
1714 chip->sp[FG_SRAM_KI_COEFF_LOW_DISCHG].len,
1715 FG_IMA_DEFAULT);
1716 if (rc < 0) {
1717 pr_err("Error in writing ki_coeff_low, rc=%d\n", rc);
1718 return rc;
1719 }
1720
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001721 fg_encode(chip->sp, FG_SRAM_KI_COEFF_MED_DISCHG, ki_coeff_med, &val);
1722 rc = fg_sram_write(chip,
1723 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_word,
1724 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_byte, &val,
1725 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].len,
1726 FG_IMA_DEFAULT);
1727 if (rc < 0) {
1728 pr_err("Error in writing ki_coeff_med, rc=%d\n", rc);
1729 return rc;
1730 }
1731
1732 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_DISCHG, ki_coeff_hi, &val);
1733 rc = fg_sram_write(chip,
1734 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_word,
1735 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_byte, &val,
1736 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].len,
1737 FG_IMA_DEFAULT);
1738 if (rc < 0) {
1739 pr_err("Error in writing ki_coeff_hi, rc=%d\n", rc);
1740 return rc;
1741 }
1742
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07001743 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_low %d ki_coeff_med %d ki_coeff_hi %d\n",
1744 ki_coeff_low, ki_coeff_med, ki_coeff_hi);
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001745 return 0;
1746}
1747
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001748#define KI_COEFF_FULL_SOC_DEFAULT 733
1749static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
1750{
1751 int rc, ki_coeff_full_soc;
1752 u8 val;
1753
1754 if (batt_temp < 0)
1755 ki_coeff_full_soc = 0;
Subbaraman Narayanamurthye17be582017-08-08 19:28:37 -07001756 else if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
1757 ki_coeff_full_soc = chip->dt.ki_coeff_full_soc_dischg;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001758 else
1759 ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
1760
1761 if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
1762 return 0;
1763
1764 fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
1765 rc = fg_sram_write(chip,
1766 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
1767 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
1768 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
1769 FG_IMA_DEFAULT);
1770 if (rc < 0) {
1771 pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
1772 return rc;
1773 }
1774
1775 chip->ki_coeff_full_soc = ki_coeff_full_soc;
1776 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
1777 ki_coeff_full_soc);
1778 return 0;
1779}
1780
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001781static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
1782{
1783 u8 buf;
1784 int rc;
1785
1786 if (chip->dt.auto_recharge_soc)
1787 return 0;
1788
1789 /* This configuration is available only for pmicobalt v2.0 and above */
1790 if (chip->wa_flags & PMI8998_V1_REV_WA)
1791 return 0;
1792
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07001793 if (voltage_mv == chip->last_recharge_volt_mv)
1794 return 0;
1795
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001796 fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
1797 voltage_mv);
1798 fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
1799 rc = fg_sram_write(chip,
1800 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
1801 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
1802 &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
1803 FG_IMA_DEFAULT);
1804 if (rc < 0) {
1805 pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
1806 rc);
1807 return rc;
1808 }
1809
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07001810 chip->last_recharge_volt_mv = voltage_mv;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001811 return 0;
1812}
1813
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07001814static int fg_configure_full_soc(struct fg_chip *chip, int bsoc)
1815{
1816 int rc;
1817 u8 full_soc[2] = {0xFF, 0xFF};
1818
1819 /*
1820 * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC
1821 * needs to be updated to reflect the same. Write battery SOC to
1822 * FULL_SOC and write a full value to MONOTONIC_SOC.
1823 */
1824 rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET,
1825 (u8 *)&bsoc, 2, FG_IMA_ATOMIC);
1826 if (rc < 0) {
1827 pr_err("failed to write full_soc rc=%d\n", rc);
1828 return rc;
1829 }
1830
1831 rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
1832 full_soc, 2, FG_IMA_ATOMIC);
1833 if (rc < 0) {
1834 pr_err("failed to write monotonic_soc rc=%d\n", rc);
1835 return rc;
1836 }
1837
1838 return 0;
1839}
1840
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001841#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001842static int fg_charge_full_update(struct fg_chip *chip)
1843{
1844 union power_supply_propval prop = {0, };
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301845 int rc, msoc, bsoc, recharge_soc, msoc_raw;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001846
1847 if (!chip->dt.hold_soc_while_full)
1848 return 0;
1849
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001850 if (!batt_psy_initialized(chip))
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001851 return 0;
1852
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001853 mutex_lock(&chip->charge_full_lock);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001854 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
1855 chip->charge_done, 0);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001856 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
1857 &prop);
1858 if (rc < 0) {
1859 pr_err("Error in getting battery health, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001860 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001861 }
1862
1863 chip->health = prop.intval;
1864 recharge_soc = chip->dt.recharge_soc_thr;
1865 recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
1866 FULL_CAPACITY);
1867 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
1868 if (rc < 0) {
1869 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001870 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001871 }
1872
1873 /* We need 2 most significant bytes here */
1874 bsoc = (u32)bsoc >> 16;
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301875 rc = fg_get_msoc_raw(chip, &msoc_raw);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001876 if (rc < 0) {
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301877 pr_err("Error in getting msoc_raw, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001878 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001879 }
Anirudh Ghayal5f556652017-08-08 14:47:56 +05301880 msoc = DIV_ROUND_CLOSEST(msoc_raw * FULL_CAPACITY, FULL_SOC_RAW);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001881
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001882 fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
1883 msoc, bsoc, chip->health, chip->charge_status,
1884 chip->charge_full);
1885 if (chip->charge_done && !chip->charge_full) {
1886 if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) {
1887 fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n");
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001888 chip->charge_full = true;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001889 /*
1890 * Lower the recharge voltage so that VBAT_LT_RECHG
1891 * signal will not be asserted soon.
1892 */
1893 rc = fg_set_recharge_voltage(chip,
1894 AUTO_RECHG_VOLT_LOW_LIMIT_MV);
1895 if (rc < 0) {
1896 pr_err("Error in reducing recharge voltage, rc=%d\n",
1897 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001898 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001899 }
1900 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001901 fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
1902 msoc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001903 }
Subbaraman Narayanamurthy9e024112017-10-05 16:05:16 -07001904 } else if ((msoc_raw <= recharge_soc || !chip->charge_done)
1905 && chip->charge_full) {
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07001906 if (chip->dt.linearize_soc) {
1907 chip->delta_soc = FULL_CAPACITY - msoc;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001908
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07001909 /*
1910 * We're spreading out the delta SOC over every 10%
1911 * change in monotonic SOC. We cannot spread more than
1912 * 9% in the range of 0-100 skipping the first 10%.
1913 */
1914 if (chip->delta_soc > 9) {
1915 chip->delta_soc = 0;
1916 chip->maint_soc = 0;
1917 } else {
1918 chip->maint_soc = FULL_CAPACITY;
1919 chip->last_msoc = msoc;
1920 }
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001921 }
1922
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001923 /*
1924 * Raise the recharge voltage so that VBAT_LT_RECHG signal
1925 * will be asserted soon as battery SOC had dropped below
1926 * the recharge SOC threshold.
1927 */
1928 rc = fg_set_recharge_voltage(chip,
1929 chip->dt.recharge_volt_thr_mv);
1930 if (rc < 0) {
1931 pr_err("Error in setting recharge voltage, rc=%d\n",
1932 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001933 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001934 }
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07001935
1936 /*
1937 * If charge_done is still set, wait for recharging or
1938 * discharging to happen.
1939 */
1940 if (chip->charge_done)
1941 goto out;
1942
1943 rc = fg_configure_full_soc(chip, bsoc);
1944 if (rc < 0)
1945 goto out;
1946
1947 chip->charge_full = false;
Anirudh Ghayale2b26cc2017-07-12 10:12:24 +05301948 fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
1949 msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001950 }
1951
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001952out:
1953 mutex_unlock(&chip->charge_full_lock);
1954 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001955}
1956
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001957#define RCONN_CONFIG_BIT BIT(0)
1958static int fg_rconn_config(struct fg_chip *chip)
1959{
1960 int rc, esr_uohms;
1961 u64 scaling_factor;
1962 u32 val = 0;
1963
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07001964 if (!chip->dt.rconn_mohms)
1965 return 0;
1966
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001967 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
1968 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1969 if (rc < 0) {
1970 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
1971 return rc;
1972 }
1973
1974 if (val & RCONN_CONFIG_BIT) {
1975 fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
1976 return 0;
1977 }
1978
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08001979 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001980 if (rc < 0) {
1981 pr_err("failed to get ESR, rc=%d\n", rc);
1982 return rc;
1983 }
1984
1985 scaling_factor = div64_u64((u64)esr_uohms * 1000,
1986 esr_uohms + (chip->dt.rconn_mohms * 1000));
1987
1988 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
1989 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1990 if (rc < 0) {
1991 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1992 return rc;
1993 }
1994
1995 val *= scaling_factor;
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07001996 val = div64_u64(val, 1000);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001997 rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
1998 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1999 if (rc < 0) {
2000 pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
2001 return rc;
2002 }
2003 fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
2004
2005 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
2006 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
2007 if (rc < 0) {
2008 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
2009 return rc;
2010 }
2011
2012 val *= scaling_factor;
Subbaraman Narayanamurthy4e0bb672018-05-02 15:26:58 -07002013 val = div64_u64(val, 1000);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08002014 rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
2015 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
2016 if (rc < 0) {
2017 pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
2018 return rc;
2019 }
2020 fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
2021 val & 0xFF);
2022
2023 val = RCONN_CONFIG_BIT;
2024 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2025 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
2026 if (rc < 0) {
2027 pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
2028 return rc;
2029 }
2030
2031 return 0;
2032}
2033
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07002034static int fg_set_jeita_threshold(struct fg_chip *chip,
2035 enum jeita_levels level, int temp_decidegC)
2036{
2037 int rc;
2038 u8 val;
2039 u16 reg;
2040
2041 if (temp_decidegC < -300 || temp_decidegC > 970)
2042 return -EINVAL;
2043
2044 /* Resolution is 0.5C. Base is -30C. */
2045 val = DIV_ROUND_CLOSEST(((temp_decidegC / 10) + 30) * 10, 5);
2046 switch (level) {
2047 case JEITA_COLD:
2048 reg = BATT_INFO_JEITA_TOO_COLD(chip);
2049 break;
2050 case JEITA_COOL:
2051 reg = BATT_INFO_JEITA_COLD(chip);
2052 break;
2053 case JEITA_WARM:
2054 reg = BATT_INFO_JEITA_HOT(chip);
2055 break;
2056 case JEITA_HOT:
2057 reg = BATT_INFO_JEITA_TOO_HOT(chip);
2058 break;
2059 default:
2060 return -EINVAL;
2061 }
2062
2063 rc = fg_write(chip, reg, &val, 1);
2064 if (rc < 0) {
2065 pr_err("Error in setting jeita level %d, rc=%d\n", level, rc);
2066 return rc;
2067 }
2068
2069 return 0;
2070}
2071
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08002072static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
2073{
2074 u8 buf[2];
2075 int rc;
2076
2077 if (volt_uv <= 0 || volt_uv > 15590000) {
2078 pr_err("Invalid voltage %d\n", volt_uv);
2079 return -EINVAL;
2080 }
2081
2082 fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
2083
2084 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
2085 chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
2086 chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
2087 if (rc < 0) {
2088 pr_err("Error in writing vbatt_full, rc=%d\n", rc);
2089 return rc;
2090 }
2091
2092 return 0;
2093}
2094
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002095static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
2096{
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002097 u8 buf;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002098 int rc;
2099
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002100 if (!chip->dt.auto_recharge_soc)
2101 return 0;
2102
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002103 if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY)
2104 return 0;
2105
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002106 fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002107 rc = fg_sram_write(chip,
2108 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002109 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002110 chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
2111 if (rc < 0) {
2112 pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
2113 return rc;
2114 }
2115
2116 return 0;
2117}
2118
2119static int fg_adjust_recharge_soc(struct fg_chip *chip)
2120{
Subbaraman Narayanamurthyd92b2462018-04-27 14:30:37 -07002121 union power_supply_propval prop = {0, };
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002122 int rc, msoc, recharge_soc, new_recharge_soc = 0;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002123 bool recharge_soc_status;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002124
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08002125 if (!chip->dt.auto_recharge_soc)
2126 return 0;
2127
Subbaraman Narayanamurthyd92b2462018-04-27 14:30:37 -07002128 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
2129 &prop);
2130 if (rc < 0) {
2131 pr_err("Error in getting battery health, rc=%d\n", rc);
2132 return rc;
2133 }
2134 chip->health = prop.intval;
2135
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002136 recharge_soc = chip->dt.recharge_soc_thr;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002137 recharge_soc_status = chip->recharge_soc_adjusted;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002138 /*
2139 * If the input is present and charging had been terminated, adjust
2140 * the recharge SOC threshold based on the monotonic SOC at which
2141 * the charge termination had happened.
2142 */
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002143 if (is_input_present(chip)) {
2144 if (chip->charge_done) {
2145 if (!chip->recharge_soc_adjusted) {
2146 /* Get raw monotonic SOC for calculation */
2147 rc = fg_get_msoc(chip, &msoc);
2148 if (rc < 0) {
2149 pr_err("Error in getting msoc, rc=%d\n",
2150 rc);
2151 return rc;
2152 }
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002153
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002154 /* Adjust the recharge_soc threshold */
2155 new_recharge_soc = msoc - (FULL_CAPACITY -
2156 recharge_soc);
2157 chip->recharge_soc_adjusted = true;
2158 } else {
2159 /* adjusted already, do nothing */
Subbaraman Narayanamurthye9427072018-08-22 12:35:10 -07002160 if (chip->health != POWER_SUPPLY_HEALTH_GOOD)
2161 return 0;
2162
2163 /*
2164 * Device is out of JEITA so restore the
2165 * default value
2166 */
2167 new_recharge_soc = recharge_soc;
2168 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002169 }
2170 } else {
Subbaraman Narayanamurthy5080b562017-12-21 17:39:07 -08002171 if (!chip->recharge_soc_adjusted)
2172 return 0;
2173
Subbaraman Narayanamurthyd92b2462018-04-27 14:30:37 -07002174 if (chip->health != POWER_SUPPLY_HEALTH_GOOD)
2175 return 0;
2176
Subbaraman Narayanamurthy5080b562017-12-21 17:39:07 -08002177 /* Restore the default value */
2178 new_recharge_soc = recharge_soc;
2179 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002180 }
2181 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002182 /* Restore the default value */
2183 new_recharge_soc = recharge_soc;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002184 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002185 }
2186
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002187 rc = fg_set_recharge_soc(chip, new_recharge_soc);
2188 if (rc < 0) {
2189 chip->recharge_soc_adjusted = recharge_soc_status;
2190 pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
2191 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002192 }
2193
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07002194 fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002195 return 0;
2196}
2197
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07002198static int fg_adjust_recharge_voltage(struct fg_chip *chip)
2199{
2200 int rc, recharge_volt_mv;
2201
2202 if (chip->dt.auto_recharge_soc)
2203 return 0;
2204
2205 fg_dbg(chip, FG_STATUS, "health: %d chg_status: %d chg_done: %d\n",
2206 chip->health, chip->charge_status, chip->charge_done);
2207
2208 recharge_volt_mv = chip->dt.recharge_volt_thr_mv;
2209
2210 /* Lower the recharge voltage in soft JEITA */
2211 if (chip->health == POWER_SUPPLY_HEALTH_WARM ||
2212 chip->health == POWER_SUPPLY_HEALTH_COOL)
2213 recharge_volt_mv -= 200;
2214
2215 rc = fg_set_recharge_voltage(chip, recharge_volt_mv);
2216 if (rc < 0) {
2217 pr_err("Error in setting recharge_voltage, rc=%d\n",
2218 rc);
2219 return rc;
2220 }
2221
2222 return 0;
2223}
2224
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002225static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
2226{
2227 enum slope_limit_status status;
2228 int rc;
2229 u8 buf;
2230
2231 if (!chip->slope_limit_en)
2232 return 0;
2233
2234 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
2235 chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
2236 if (batt_temp < chip->dt.slope_limit_temp)
2237 status = LOW_TEMP_CHARGE;
2238 else
2239 status = HIGH_TEMP_CHARGE;
2240 } else {
2241 if (batt_temp < chip->dt.slope_limit_temp)
2242 status = LOW_TEMP_DISCHARGE;
2243 else
2244 status = HIGH_TEMP_DISCHARGE;
2245 }
2246
2247 if (chip->slope_limit_sts == status)
2248 return 0;
2249
2250 fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
2251 chip->dt.slope_limit_coeffs[status], &buf);
2252 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
2253 chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
2254 chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
2255 if (rc < 0) {
2256 pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
2257 rc);
2258 return rc;
2259 }
2260
2261 chip->slope_limit_sts = status;
2262 fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
2263 buf);
2264 return 0;
2265}
2266
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002267static int __fg_esr_filter_config(struct fg_chip *chip,
2268 enum esr_filter_status esr_flt_sts)
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002269{
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002270 u8 esr_tight_flt, esr_broad_flt;
2271 int esr_tight_flt_upct, esr_broad_flt_upct;
2272 int rc;
2273
2274 if (esr_flt_sts == chip->esr_flt_sts)
2275 return 0;
2276
2277 if (esr_flt_sts == ROOM_TEMP) {
2278 esr_tight_flt_upct = chip->dt.esr_tight_flt_upct;
2279 esr_broad_flt_upct = chip->dt.esr_broad_flt_upct;
2280 } else if (esr_flt_sts == LOW_TEMP) {
2281 esr_tight_flt_upct = chip->dt.esr_tight_lt_flt_upct;
2282 esr_broad_flt_upct = chip->dt.esr_broad_lt_flt_upct;
2283 } else if (esr_flt_sts == RELAX_TEMP) {
2284 esr_tight_flt_upct = chip->dt.esr_tight_rt_flt_upct;
2285 esr_broad_flt_upct = chip->dt.esr_broad_rt_flt_upct;
2286 } else {
2287 pr_err("Unknown esr filter config\n");
2288 return 0;
2289 }
2290
2291 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, esr_tight_flt_upct,
2292 &esr_tight_flt);
2293 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
2294 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
2295 &esr_tight_flt,
2296 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
2297 if (rc < 0) {
2298 pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
2299 return rc;
2300 }
2301
2302 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER, esr_broad_flt_upct,
2303 &esr_broad_flt);
2304 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
2305 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
2306 &esr_broad_flt,
2307 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
2308 if (rc < 0) {
2309 pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
2310 return rc;
2311 }
2312
2313 chip->esr_flt_sts = esr_flt_sts;
2314 fg_dbg(chip, FG_STATUS, "applied ESR filter %d values\n", esr_flt_sts);
2315 return 0;
2316}
2317
2318#define DT_IRQ_COUNT 3
2319#define DELTA_TEMP_IRQ_TIME_MS 300000
2320#define ESR_FILTER_ALARM_TIME_MS 900000
2321static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp,
2322 bool override)
2323{
2324 enum esr_filter_status esr_flt_sts = ROOM_TEMP;
2325 bool qnovo_en, input_present, count_temp_irq = false;
2326 s64 time_ms;
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002327 int rc;
2328
2329 /*
2330 * If the battery temperature is lower than -20 C, then skip modifying
2331 * ESR filter.
2332 */
2333 if (batt_temp < -210)
2334 return 0;
2335
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002336 qnovo_en = is_qnovo_en(chip);
2337 input_present = is_input_present(chip);
2338
2339 /*
2340 * If Qnovo is enabled, after hitting a lower battery temperature of
2341 * say 6 C, count the delta battery temperature interrupts for a
2342 * certain period of time when the battery temperature increases.
2343 * Switch to relaxed filter coefficients once the temperature increase
2344 * is qualified so that ESR accuracy can be improved.
2345 */
2346 if (qnovo_en && !override) {
2347 if (input_present) {
2348 if (chip->esr_flt_sts == RELAX_TEMP) {
2349 /* do nothing */
2350 return 0;
2351 }
2352
2353 count_temp_irq = true;
2354 if (chip->delta_temp_irq_count) {
2355 /* Don't count when temperature is dropping. */
2356 if (batt_temp <= chip->last_batt_temp)
2357 count_temp_irq = false;
2358 } else {
2359 /*
2360 * Starting point for counting. Check if the
2361 * temperature is qualified.
2362 */
2363 if (batt_temp > chip->dt.esr_flt_rt_switch_temp)
2364 count_temp_irq = false;
2365 else
2366 chip->last_delta_temp_time =
2367 ktime_get();
2368 }
2369 } else {
2370 chip->delta_temp_irq_count = 0;
2371 rc = alarm_try_to_cancel(&chip->esr_filter_alarm);
2372 if (rc < 0)
2373 pr_err("Couldn't cancel esr_filter_alarm\n");
2374 }
2375 }
2376
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002377 /*
2378 * If battery temperature is lesser than 10 C (default), then apply the
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08002379 * ESR low temperature tight and broad filter values to ESR room
2380 * temperature tight and broad filters. If battery temperature is higher
2381 * than 10 C, then apply back the room temperature ESR filter
2382 * coefficients to ESR room temperature tight and broad filters.
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002383 */
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002384 if (batt_temp > chip->dt.esr_flt_switch_temp)
2385 esr_flt_sts = ROOM_TEMP;
2386 else
2387 esr_flt_sts = LOW_TEMP;
2388
2389 if (count_temp_irq) {
2390 time_ms = ktime_ms_delta(ktime_get(),
2391 chip->last_delta_temp_time);
2392 chip->delta_temp_irq_count++;
2393 fg_dbg(chip, FG_STATUS, "dt_irq_count: %d\n",
2394 chip->delta_temp_irq_count);
2395
2396 if (chip->delta_temp_irq_count >= DT_IRQ_COUNT
2397 && time_ms <= DELTA_TEMP_IRQ_TIME_MS) {
2398 fg_dbg(chip, FG_STATUS, "%d interrupts in %lld ms\n",
2399 chip->delta_temp_irq_count, time_ms);
2400 esr_flt_sts = RELAX_TEMP;
2401 }
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002402 }
2403
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002404 rc = __fg_esr_filter_config(chip, esr_flt_sts);
2405 if (rc < 0)
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002406 return rc;
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002407
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002408 if (esr_flt_sts == RELAX_TEMP)
2409 alarm_start_relative(&chip->esr_filter_alarm,
2410 ms_to_ktime(ESR_FILTER_ALARM_TIME_MS));
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002411
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08002412 return 0;
2413}
2414
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08002415#define FG_ESR_FILTER_RESTART_MS 60000
2416static void esr_filter_work(struct work_struct *work)
2417{
2418 struct fg_chip *chip = container_of(work,
2419 struct fg_chip, esr_filter_work);
2420 int rc, batt_temp;
2421
2422 rc = fg_get_battery_temp(chip, &batt_temp);
2423 if (rc < 0) {
2424 pr_err("Error in getting batt_temp\n");
2425 alarm_start_relative(&chip->esr_filter_alarm,
2426 ms_to_ktime(FG_ESR_FILTER_RESTART_MS));
2427 goto out;
2428 }
2429
2430 rc = fg_esr_filter_config(chip, batt_temp, true);
2431 if (rc < 0) {
2432 pr_err("Error in configuring ESR filter rc:%d\n", rc);
2433 alarm_start_relative(&chip->esr_filter_alarm,
2434 ms_to_ktime(FG_ESR_FILTER_RESTART_MS));
2435 }
2436
2437out:
2438 chip->delta_temp_irq_count = 0;
2439 pm_relax(chip->dev);
2440}
2441
2442static enum alarmtimer_restart fg_esr_filter_alarm_cb(struct alarm *alarm,
2443 ktime_t now)
2444{
2445 struct fg_chip *chip = container_of(alarm, struct fg_chip,
2446 esr_filter_alarm);
2447
2448 fg_dbg(chip, FG_STATUS, "ESR filter alarm triggered %lld\n",
2449 ktime_to_ms(now));
2450 /*
2451 * We cannot vote for awake votable here as that takes a mutex lock
2452 * and this is executed in an atomic context.
2453 */
2454 pm_stay_awake(chip->dev);
2455 schedule_work(&chip->esr_filter_work);
2456
2457 return ALARMTIMER_NORESTART;
2458}
2459
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002460static int fg_esr_fcc_config(struct fg_chip *chip)
2461{
2462 union power_supply_propval prop = {0, };
2463 int rc;
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002464 bool parallel_en = false, qnovo_en;
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002465
2466 if (is_parallel_charger_available(chip)) {
2467 rc = power_supply_get_property(chip->parallel_psy,
2468 POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop);
2469 if (rc < 0) {
2470 pr_err("Error in reading charging_enabled from parallel_psy, rc=%d\n",
2471 rc);
2472 return rc;
2473 }
2474 parallel_en = prop.intval;
2475 }
2476
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -07002477 qnovo_en = is_qnovo_en(chip);
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002478
2479 fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
2480 chip->charge_status, parallel_en, qnovo_en,
2481 chip->esr_fcc_ctrl_en);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002482
Nicholas Troast1769fd32016-09-07 09:20:58 -07002483 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002484 (parallel_en || qnovo_en)) {
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002485 if (chip->esr_fcc_ctrl_en)
2486 return 0;
2487
2488 /*
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002489 * When parallel charging or Qnovo is enabled, configure ESR
2490 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
2491 * request the main charger to increase FCC when it is supposed
2492 * to decrease it.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002493 */
2494 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2495 ESR_FAST_CRG_IVAL_MASK |
2496 ESR_FAST_CRG_CTL_EN_BIT,
2497 ESR_FCC_300MA | ESR_FAST_CRG_CTL_EN_BIT);
2498 if (rc < 0) {
2499 pr_err("Error in writing to %04x, rc=%d\n",
2500 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2501 return rc;
2502 }
2503
2504 chip->esr_fcc_ctrl_en = true;
2505 } else {
2506 if (!chip->esr_fcc_ctrl_en)
2507 return 0;
2508
2509 /*
2510 * If we're here, then it means either the device is not in
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002511 * charging state or parallel charging / Qnovo is disabled.
2512 * Disable ESR fast charge current control in SW.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002513 */
2514 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2515 ESR_FAST_CRG_CTL_EN_BIT, 0);
2516 if (rc < 0) {
2517 pr_err("Error in writing to %04x, rc=%d\n",
2518 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2519 return rc;
2520 }
2521
2522 chip->esr_fcc_ctrl_en = false;
2523 }
2524
2525 fg_dbg(chip, FG_STATUS, "esr_fcc_ctrl_en set to %d\n",
2526 chip->esr_fcc_ctrl_en);
2527 return 0;
2528}
2529
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002530static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
2531{
2532 int rc, cycles_init, cycles_max;
2533 bool end_of_charge = false;
2534
2535 end_of_charge = is_input_present(chip) && chip->charge_done;
2536 fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
2537
2538 /* ESR discharging timer configuration */
2539 cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
2540 chip->dt.esr_timer_awake[TIMER_RETRY];
2541 if (end_of_charge)
2542 cycles_init = 0;
2543
2544 cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
2545 chip->dt.esr_timer_awake[TIMER_MAX];
2546
2547 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
2548 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2549 if (rc < 0) {
2550 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2551 return rc;
2552 }
2553
2554 /* ESR charging timer configuration */
2555 cycles_init = cycles_max = -EINVAL;
2556 if (end_of_charge || sleep) {
2557 cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
2558 cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
2559 } else if (is_input_present(chip)) {
2560 cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
2561 cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
2562 }
2563
2564 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
2565 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2566 if (rc < 0) {
2567 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2568 return rc;
2569 }
2570
2571 return 0;
2572}
2573
Nicholas Troast805c2422017-07-06 14:53:46 -07002574static void fg_ttf_update(struct fg_chip *chip)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002575{
Nicholas Troast805c2422017-07-06 14:53:46 -07002576 int rc;
2577 int delay_ms;
2578 union power_supply_propval prop = {0, };
2579 int online = 0;
2580
2581 if (usb_psy_initialized(chip)) {
2582 rc = power_supply_get_property(chip->usb_psy,
2583 POWER_SUPPLY_PROP_ONLINE, &prop);
2584 if (rc < 0) {
2585 pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
2586 return;
2587 }
2588
2589 online = online || prop.intval;
2590 }
2591
2592 if (pc_port_psy_initialized(chip)) {
2593 rc = power_supply_get_property(chip->pc_port_psy,
2594 POWER_SUPPLY_PROP_ONLINE, &prop);
2595 if (rc < 0) {
2596 pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
2597 return;
2598 }
2599
2600 online = online || prop.intval;
2601 }
2602
2603 if (dc_psy_initialized(chip)) {
2604 rc = power_supply_get_property(chip->dc_psy,
2605 POWER_SUPPLY_PROP_ONLINE, &prop);
2606 if (rc < 0) {
2607 pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
2608 return;
2609 }
2610
2611 online = online || prop.intval;
2612 }
2613
2614
2615 if (chip->online_status == online)
Nicholas Troast1769fd32016-09-07 09:20:58 -07002616 return;
2617
Nicholas Troast805c2422017-07-06 14:53:46 -07002618 chip->online_status = online;
2619 if (online)
2620 /* wait 35 seconds for the input to settle */
2621 delay_ms = 35000;
2622 else
2623 /* wait 5 seconds for current to settle during discharge */
2624 delay_ms = 5000;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002625
Nicholas Troast805c2422017-07-06 14:53:46 -07002626 vote(chip->awake_votable, TTF_PRIMING, true, 0);
2627 cancel_delayed_work_sync(&chip->ttf_work);
2628 mutex_lock(&chip->ttf.lock);
2629 fg_circ_buf_clr(&chip->ttf.ibatt);
2630 fg_circ_buf_clr(&chip->ttf.vbatt);
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07002631 chip->ttf.last_ttf = 0;
2632 chip->ttf.last_ms = 0;
Nicholas Troast805c2422017-07-06 14:53:46 -07002633 mutex_unlock(&chip->ttf.lock);
2634 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
Nicholas Troast1769fd32016-09-07 09:20:58 -07002635}
2636
Nicholas Troaste29dec92016-08-24 09:35:11 -07002637static void restore_cycle_counter(struct fg_chip *chip)
2638{
2639 int rc = 0, i;
2640 u8 data[2];
2641
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002642 if (!chip->cyc_ctr.en)
2643 return;
2644
Nicholas Troaste29dec92016-08-24 09:35:11 -07002645 mutex_lock(&chip->cyc_ctr.lock);
2646 for (i = 0; i < BUCKET_COUNT; i++) {
2647 rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
2648 CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
2649 FG_IMA_DEFAULT);
2650 if (rc < 0)
2651 pr_err("failed to read bucket %d rc=%d\n", i, rc);
2652 else
2653 chip->cyc_ctr.count[i] = data[0] | data[1] << 8;
2654 }
2655 mutex_unlock(&chip->cyc_ctr.lock);
2656}
2657
2658static void clear_cycle_counter(struct fg_chip *chip)
2659{
2660 int rc = 0, i;
2661
2662 if (!chip->cyc_ctr.en)
2663 return;
2664
2665 mutex_lock(&chip->cyc_ctr.lock);
2666 memset(chip->cyc_ctr.count, 0, sizeof(chip->cyc_ctr.count));
2667 for (i = 0; i < BUCKET_COUNT; i++) {
2668 chip->cyc_ctr.started[i] = false;
2669 chip->cyc_ctr.last_soc[i] = 0;
2670 }
2671 rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET,
2672 (u8 *)&chip->cyc_ctr.count,
2673 sizeof(chip->cyc_ctr.count) / sizeof(u8 *),
2674 FG_IMA_DEFAULT);
2675 if (rc < 0)
2676 pr_err("failed to clear cycle counter rc=%d\n", rc);
2677
2678 mutex_unlock(&chip->cyc_ctr.lock);
2679}
2680
2681static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
2682{
2683 int rc = 0;
2684 u16 cyc_count;
2685 u8 data[2];
2686
2687 if (bucket < 0 || (bucket > BUCKET_COUNT - 1))
2688 return 0;
2689
2690 cyc_count = chip->cyc_ctr.count[bucket];
2691 cyc_count++;
2692 data[0] = cyc_count & 0xFF;
2693 data[1] = cyc_count >> 8;
2694
2695 rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
2696 CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
2697 FG_IMA_DEFAULT);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002698 if (rc < 0) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002699 pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
2700 bucket, rc);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002701 return rc;
2702 }
2703
2704 chip->cyc_ctr.count[bucket] = cyc_count;
2705 fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
2706 bucket);
2707
Nicholas Troaste29dec92016-08-24 09:35:11 -07002708 return rc;
2709}
2710
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002711static void fg_cycle_counter_update(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07002712{
2713 int rc = 0, bucket, i, batt_soc;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002714
2715 if (!chip->cyc_ctr.en)
2716 return;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002717
2718 mutex_lock(&chip->cyc_ctr.lock);
2719 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
2720 if (rc < 0) {
2721 pr_err("Failed to read battery soc rc: %d\n", rc);
2722 goto out;
2723 }
2724
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002725 /* We need only the most significant byte here */
2726 batt_soc = (u32)batt_soc >> 24;
2727
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002728 /* Find out which bucket the SOC falls in */
2729 bucket = batt_soc / BUCKET_SOC_PCT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002730
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002731 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002732 if (!chip->cyc_ctr.started[bucket]) {
2733 chip->cyc_ctr.started[bucket] = true;
2734 chip->cyc_ctr.last_soc[bucket] = batt_soc;
2735 }
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002736 } else if (chip->charge_done || !is_input_present(chip)) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002737 for (i = 0; i < BUCKET_COUNT; i++) {
2738 if (chip->cyc_ctr.started[i] &&
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002739 batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002740 rc = fg_inc_store_cycle_ctr(chip, i);
2741 if (rc < 0)
2742 pr_err("Error in storing cycle_ctr rc: %d\n",
2743 rc);
2744 chip->cyc_ctr.last_soc[i] = 0;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002745 chip->cyc_ctr.started[i] = false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002746 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002747 }
2748 }
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002749
2750 fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
2751 batt_soc, bucket, chip->charge_status);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002752out:
2753 mutex_unlock(&chip->cyc_ctr.lock);
2754}
2755
Vamshi Krishna B V56623402018-09-19 11:56:07 +05302756static int fg_get_cycle_count(struct fg_chip *chip)
2757{
2758 int i, len = 0;
2759
2760 if (!chip->cyc_ctr.en)
2761 return 0;
2762
2763 mutex_lock(&chip->cyc_ctr.lock);
2764 for (i = 0; i < BUCKET_COUNT; i++)
2765 len += chip->cyc_ctr.count[i];
2766
2767 mutex_unlock(&chip->cyc_ctr.lock);
2768
2769 len = len / BUCKET_COUNT;
2770
2771 return len;
2772}
2773
2774static const char *fg_get_cycle_counts(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07002775{
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08002776 int i, len = 0;
2777 char *buf;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002778
2779 if (!chip->cyc_ctr.en)
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08002780 return NULL;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002781
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08002782 buf = chip->cyc_ctr.counter;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002783 mutex_lock(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08002784 for (i = 0; i < BUCKET_COUNT; i++) {
2785 if (sizeof(chip->cyc_ctr.counter) - len < 8) {
2786 pr_err("Invalid length %d\n", len);
2787 mutex_unlock(&chip->cyc_ctr.lock);
2788 return NULL;
2789 }
2790
2791 len += snprintf(buf+len, 8, "%d ", chip->cyc_ctr.count[i]);
2792 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002793 mutex_unlock(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08002794
2795 buf[len] = '\0';
2796 return buf;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002797}
2798
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05302799#define ESR_SW_FCC_UA 100000 /* 100mA */
2800#define ESR_EXTRACTION_ENABLE_MASK BIT(0)
2801static void fg_esr_sw_work(struct work_struct *work)
2802{
2803 struct fg_chip *chip = container_of(work,
2804 struct fg_chip, esr_sw_work);
2805 union power_supply_propval pval = {0, };
2806 int rc, esr_uohms = 0;
2807
2808 vote(chip->awake_votable, FG_ESR_VOTER, true, 0);
2809 /*
2810 * Enable ESR extraction just before we reduce the FCC
2811 * to make sure that FG extracts the ESR. Disable ESR
2812 * extraction after FCC reduction is complete to prevent
2813 * any further HW pulses.
2814 */
2815 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
2816 ESR_EXTRACTION_ENABLE_OFFSET,
2817 ESR_EXTRACTION_ENABLE_MASK, 0x1, FG_IMA_DEFAULT);
2818 if (rc < 0) {
2819 pr_err("Failed to enable ESR extraction rc=%d\n", rc);
2820 goto done;
2821 }
2822
2823 /* delay for 1 FG cycle to complete */
2824 msleep(1500);
2825
2826 /* for FCC to 100mA */
2827 pval.intval = ESR_SW_FCC_UA;
2828 rc = power_supply_set_property(chip->batt_psy,
2829 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
2830 &pval);
2831 if (rc < 0) {
2832 pr_err("Failed to set FCC to 100mA rc=%d\n", rc);
2833 goto done;
2834 }
2835
2836 /* delay for ESR readings */
2837 msleep(3000);
2838
2839 /* FCC to 0 (removes vote) */
2840 pval.intval = 0;
2841 rc = power_supply_set_property(chip->batt_psy,
2842 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
2843 &pval);
2844 if (rc < 0) {
2845 pr_err("Failed to remove FCC vote rc=%d\n", rc);
2846 goto done;
2847 }
2848
2849 fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
2850 fg_dbg(chip, FG_STATUS, "SW ESR done ESR=%d\n", esr_uohms);
2851
2852 /* restart the alarm timer */
2853 alarm_start_relative(&chip->esr_sw_timer,
2854 ms_to_ktime(chip->esr_wakeup_ms));
2855done:
2856 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
2857 ESR_EXTRACTION_ENABLE_OFFSET,
2858 ESR_EXTRACTION_ENABLE_MASK, 0x0, FG_IMA_DEFAULT);
2859 if (rc < 0)
2860 pr_err("Failed to disable ESR extraction rc=%d\n", rc);
2861
2862
2863 vote(chip->awake_votable, FG_ESR_VOTER, false, 0);
2864 fg_relax(chip, FG_SW_ESR_WAKE);
2865}
2866
2867static enum alarmtimer_restart
2868 fg_esr_sw_timer(struct alarm *alarm, ktime_t now)
2869{
2870 struct fg_chip *chip = container_of(alarm,
2871 struct fg_chip, esr_sw_timer);
2872
2873 if (!chip->usb_present)
2874 return ALARMTIMER_NORESTART;
2875
2876 fg_stay_awake(chip, FG_SW_ESR_WAKE);
2877 schedule_work(&chip->esr_sw_work);
2878
2879 return ALARMTIMER_NORESTART;
2880}
2881
2882static int fg_config_esr_sw(struct fg_chip *chip)
2883{
2884 int rc;
2885 union power_supply_propval prop = {0, };
2886
2887 if (!chip->dt.use_esr_sw)
2888 return 0;
2889
2890 if (!usb_psy_initialized(chip))
2891 return 0;
2892
2893 rc = power_supply_get_property(chip->usb_psy,
2894 POWER_SUPPLY_PROP_PRESENT, &prop);
2895 if (rc < 0) {
2896 pr_err("Error in reading usb-status rc = %d\n", rc);
2897 return rc;
2898 }
2899
2900 if (chip->usb_present != prop.intval) {
2901 chip->usb_present = prop.intval;
2902 fg_dbg(chip, FG_STATUS, "USB status changed=%d\n",
2903 chip->usb_present);
2904 /* cancel any pending work */
2905 alarm_cancel(&chip->esr_sw_timer);
2906 cancel_work_sync(&chip->esr_sw_work);
2907
2908 if (chip->usb_present) {
2909 /* disable ESR extraction across the charging cycle */
2910 rc = fg_sram_masked_write(chip,
2911 ESR_EXTRACTION_ENABLE_WORD,
2912 ESR_EXTRACTION_ENABLE_OFFSET,
2913 ESR_EXTRACTION_ENABLE_MASK,
2914 0x0, FG_IMA_DEFAULT);
2915 if (rc < 0)
2916 return rc;
2917 /* wake up early for the first ESR on insertion */
2918 alarm_start_relative(&chip->esr_sw_timer,
2919 ms_to_ktime(chip->esr_wakeup_ms / 2));
2920 } else {
2921 /* enable ESR extraction on removal */
2922 rc = fg_sram_masked_write(chip,
2923 ESR_EXTRACTION_ENABLE_WORD,
2924 ESR_EXTRACTION_ENABLE_OFFSET,
2925 ESR_EXTRACTION_ENABLE_MASK,
2926 0x1, FG_IMA_DEFAULT);
2927 if (rc < 0)
2928 return rc;
2929 }
2930 }
2931
2932 return 0;
2933}
2934
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002935static void status_change_work(struct work_struct *work)
2936{
2937 struct fg_chip *chip = container_of(work,
2938 struct fg_chip, status_change_work);
2939 union power_supply_propval prop = {0, };
2940 int rc, batt_temp;
2941
2942 if (!batt_psy_initialized(chip)) {
2943 fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
2944 goto out;
2945 }
2946
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08002947 if (!chip->soc_reporting_ready) {
2948 fg_dbg(chip, FG_STATUS, "Profile load is not complete yet\n");
2949 goto out;
2950 }
2951
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05302952 rc = fg_config_esr_sw(chip);
2953 if (rc < 0)
2954 pr_err("Failed to config SW ESR rc=%d\n", rc);
2955
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002956 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
2957 &prop);
2958 if (rc < 0) {
2959 pr_err("Error in getting charging status, rc=%d\n", rc);
2960 goto out;
2961 }
2962
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002963 chip->charge_status = prop.intval;
2964 rc = power_supply_get_property(chip->batt_psy,
2965 POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
2966 if (rc < 0) {
2967 pr_err("Error in getting charge type, rc=%d\n", rc);
2968 goto out;
2969 }
2970
2971 chip->charge_type = prop.intval;
2972 rc = power_supply_get_property(chip->batt_psy,
2973 POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
2974 if (rc < 0) {
2975 pr_err("Error in getting charge_done, rc=%d\n", rc);
2976 goto out;
2977 }
2978
2979 chip->charge_done = prop.intval;
2980 fg_cycle_counter_update(chip);
2981 fg_cap_learning_update(chip);
2982
2983 rc = fg_charge_full_update(chip);
2984 if (rc < 0)
2985 pr_err("Error in charge_full_update, rc=%d\n", rc);
2986
2987 rc = fg_adjust_recharge_soc(chip);
2988 if (rc < 0)
2989 pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
2990
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07002991 rc = fg_adjust_recharge_voltage(chip);
2992 if (rc < 0)
2993 pr_err("Error in adjusting recharge_voltage, rc=%d\n", rc);
2994
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07002995 rc = fg_adjust_ki_coeff_dischg(chip);
2996 if (rc < 0)
2997 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
2998
2999 rc = fg_esr_fcc_config(chip);
3000 if (rc < 0)
3001 pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
3002
3003 rc = fg_get_battery_temp(chip, &batt_temp);
3004 if (!rc) {
3005 rc = fg_slope_limit_config(chip, batt_temp);
3006 if (rc < 0)
3007 pr_err("Error in configuring slope limiter rc:%d\n",
3008 rc);
3009
3010 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
3011 if (rc < 0)
3012 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
3013 rc);
3014 }
3015
3016 fg_ttf_update(chip);
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07003017 chip->prev_charge_status = chip->charge_status;
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07003018out:
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08003019 fg_dbg(chip, FG_STATUS, "charge_status:%d charge_type:%d charge_done:%d\n",
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07003020 chip->charge_status, chip->charge_type, chip->charge_done);
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05303021 fg_relax(chip, FG_STATUS_NOTIFY_WAKE);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07003022}
3023
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07003024static int fg_bp_params_config(struct fg_chip *chip)
3025{
3026 int rc = 0;
3027 u8 buf;
3028
3029 /* This SRAM register is only present in v2.0 and above */
3030 if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
3031 chip->bp.float_volt_uv > 0) {
3032 fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
3033 chip->bp.float_volt_uv / 1000, &buf);
3034 rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
3035 chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
3036 chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
3037 if (rc < 0) {
3038 pr_err("Error in writing float_volt, rc=%d\n", rc);
3039 return rc;
3040 }
3041 }
3042
3043 if (chip->bp.vbatt_full_mv > 0) {
3044 rc = fg_set_constant_chg_voltage(chip,
3045 chip->bp.vbatt_full_mv * 1000);
3046 if (rc < 0)
3047 return rc;
3048 }
3049
3050 return rc;
3051}
3052
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07003053#define PROFILE_LOAD_BIT BIT(0)
3054#define BOOTLOADER_LOAD_BIT BIT(1)
3055#define BOOTLOADER_RESTART_BIT BIT(2)
3056#define HLOS_RESTART_BIT BIT(3)
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003057static bool is_profile_load_required(struct fg_chip *chip)
3058{
Nicholas Troaste29dec92016-08-24 09:35:11 -07003059 u8 buf[PROFILE_COMP_LEN], val;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003060 bool profiles_same = false;
3061 int rc;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003062
Nicholas Troaste29dec92016-08-24 09:35:11 -07003063 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
3064 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
3065 if (rc < 0) {
3066 pr_err("failed to read profile integrity rc=%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003067 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003068 }
3069
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003070 /* Check if integrity bit is set */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07003071 if (val & PROFILE_LOAD_BIT) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003072 fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
Subbaraman Narayanamurthy73616e12017-03-20 14:37:54 -07003073
3074 /* Whitelist the values */
3075 val &= ~PROFILE_LOAD_BIT;
3076 if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
3077 val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
3078 val |= PROFILE_LOAD_BIT;
3079 pr_warn("Garbage value in profile integrity word: 0x%x\n",
3080 val);
3081 return true;
3082 }
3083
Nicholas Troaste29dec92016-08-24 09:35:11 -07003084 rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
3085 buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
3086 if (rc < 0) {
3087 pr_err("Error in reading battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08003088 chip->profile_load_status = PROFILE_SKIPPED;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003089 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003090 }
3091 profiles_same = memcmp(chip->batt_profile, buf,
3092 PROFILE_COMP_LEN) == 0;
3093 if (profiles_same) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003094 fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08003095 chip->profile_load_status = PROFILE_LOADED;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003096 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003097 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003098
3099 if (!chip->dt.force_load_profile) {
3100 pr_warn("Profiles doesn't match, skipping loading it since force_load_profile is disabled\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003101 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003102 pr_info("FG: loaded profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003103 dump_sram(buf, PROFILE_LOAD_WORD,
3104 PROFILE_COMP_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003105 pr_info("FG: available profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003106 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
3107 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003108 }
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08003109 chip->profile_load_status = PROFILE_SKIPPED;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003110 return false;
3111 }
3112
3113 fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n");
3114 } else {
3115 fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003116 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003117 pr_info("FG: profile to be loaded:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003118 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
3119 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003120 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07003121 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003122 return true;
3123}
3124
Subbaraman Narayanamurthy35051a22017-11-10 15:37:29 -08003125static void fg_update_batt_profile(struct fg_chip *chip)
3126{
3127 int rc, offset;
3128 u8 val;
3129
3130 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
3131 SW_CONFIG_OFFSET, &val, 1, FG_IMA_DEFAULT);
3132 if (rc < 0) {
3133 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
3134 return;
3135 }
3136
3137 /*
3138 * If the RCONN had not been updated, no need to update battery
3139 * profile. Else, update the battery profile so that the profile
3140 * modified by bootloader or HLOS matches with the profile read
3141 * from device tree.
3142 */
3143
3144 if (!(val & RCONN_CONFIG_BIT))
3145 return;
3146
3147 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
3148 ESR_RSLOW_CHG_OFFSET, &val, 1, FG_IMA_DEFAULT);
3149 if (rc < 0) {
3150 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
3151 return;
3152 }
3153 offset = (ESR_RSLOW_CHG_WORD - PROFILE_LOAD_WORD) * 4
3154 + ESR_RSLOW_CHG_OFFSET;
3155 chip->batt_profile[offset] = val;
3156
3157 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
3158 ESR_RSLOW_DISCHG_OFFSET, &val, 1, FG_IMA_DEFAULT);
3159 if (rc < 0) {
3160 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
3161 return;
3162 }
3163 offset = (ESR_RSLOW_DISCHG_WORD - PROFILE_LOAD_WORD) * 4
3164 + ESR_RSLOW_DISCHG_OFFSET;
3165 chip->batt_profile[offset] = val;
3166}
3167
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08003168static void clear_battery_profile(struct fg_chip *chip)
3169{
3170 u8 val = 0;
3171 int rc;
3172
3173 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
3174 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
3175 if (rc < 0)
3176 pr_err("failed to write profile integrity rc=%d\n", rc);
3177}
3178
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003179#define SOC_READY_WAIT_MS 2000
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07003180static int __fg_restart(struct fg_chip *chip)
3181{
3182 int rc, msoc;
3183 bool tried_again = false;
3184
3185 rc = fg_get_prop_capacity(chip, &msoc);
3186 if (rc < 0) {
3187 pr_err("Error in getting capacity, rc=%d\n", rc);
3188 return rc;
3189 }
3190
3191 chip->last_soc = msoc;
3192 chip->fg_restarting = true;
3193 reinit_completion(&chip->soc_ready);
3194 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT,
3195 RESTART_GO_BIT);
3196 if (rc < 0) {
3197 pr_err("Error in writing to %04x, rc=%d\n",
3198 BATT_SOC_RESTART(chip), rc);
3199 goto out;
3200 }
3201
3202wait:
3203 rc = wait_for_completion_interruptible_timeout(&chip->soc_ready,
3204 msecs_to_jiffies(SOC_READY_WAIT_MS));
3205
3206 /* If we were interrupted wait again one more time. */
3207 if (rc == -ERESTARTSYS && !tried_again) {
3208 tried_again = true;
3209 goto wait;
3210 } else if (rc <= 0) {
3211 pr_err("wait for soc_ready timed out rc=%d\n", rc);
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07003212 }
3213
3214 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
3215 if (rc < 0) {
3216 pr_err("Error in writing to %04x, rc=%d\n",
3217 BATT_SOC_RESTART(chip), rc);
3218 goto out;
3219 }
3220out:
3221 chip->fg_restarting = false;
3222 return rc;
3223}
3224
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07003225static void pl_enable_work(struct work_struct *work)
3226{
3227 struct fg_chip *chip = container_of(work,
3228 struct fg_chip,
3229 pl_enable_work.work);
3230
3231 vote(chip->pl_disable_votable, ESR_FCC_VOTER, false, 0);
3232 vote(chip->awake_votable, ESR_FCC_VOTER, false, 0);
3233}
3234
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003235static void profile_load_work(struct work_struct *work)
3236{
3237 struct fg_chip *chip = container_of(work,
3238 struct fg_chip,
3239 profile_load_work.work);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003240 u8 buf[2], val;
3241 int rc;
3242
3243 vote(chip->awake_votable, PROFILE_LOAD, true, 0);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07003244
3245 rc = fg_get_batt_id(chip);
3246 if (rc < 0) {
3247 pr_err("Error in getting battery id, rc:%d\n", rc);
3248 goto out;
3249 }
3250
3251 rc = fg_get_batt_profile(chip);
3252 if (rc < 0) {
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08003253 chip->profile_load_status = PROFILE_MISSING;
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07003254 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
3255 chip->batt_id_ohms / 1000, rc);
3256 goto out;
3257 }
3258
3259 if (!chip->profile_available)
3260 goto out;
3261
Subbaraman Narayanamurthy35051a22017-11-10 15:37:29 -08003262 fg_update_batt_profile(chip);
3263
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07003264 if (!is_profile_load_required(chip))
3265 goto done;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003266
3267 clear_cycle_counter(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003268 mutex_lock(&chip->cl.lock);
3269 chip->cl.learned_cc_uah = 0;
3270 chip->cl.active = false;
3271 mutex_unlock(&chip->cl.lock);
3272
Nicholas Troaste29dec92016-08-24 09:35:11 -07003273 fg_dbg(chip, FG_STATUS, "profile loading started\n");
3274 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
3275 if (rc < 0) {
3276 pr_err("Error in writing to %04x, rc=%d\n",
3277 BATT_SOC_RESTART(chip), rc);
3278 goto out;
3279 }
3280
3281 /* load battery profile */
3282 rc = fg_sram_write(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
3283 chip->batt_profile, PROFILE_LEN, FG_IMA_ATOMIC);
3284 if (rc < 0) {
3285 pr_err("Error in writing battery profile, rc:%d\n", rc);
3286 goto out;
3287 }
3288
Nicholas Troaste29dec92016-08-24 09:35:11 -07003289 /* Set the profile integrity bit */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07003290 val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003291 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
3292 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
3293 if (rc < 0) {
3294 pr_err("failed to write profile integrity rc=%d\n", rc);
3295 goto out;
3296 }
3297
Subbaraman Narayanamurthy9b88a302018-01-05 13:06:54 -08003298 rc = __fg_restart(chip);
3299 if (rc < 0) {
3300 pr_err("Error in restarting FG, rc=%d\n", rc);
3301 goto out;
3302 }
3303
3304 fg_dbg(chip, FG_STATUS, "SOC is ready\n");
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08003305 chip->profile_load_status = PROFILE_LOADED;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003306done:
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07003307 rc = fg_bp_params_config(chip);
3308 if (rc < 0)
3309 pr_err("Error in configuring battery profile params, rc:%d\n",
3310 rc);
3311
Nicholas Troaste29dec92016-08-24 09:35:11 -07003312 rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
3313 FG_IMA_DEFAULT);
3314 if (rc < 0) {
3315 pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD,
3316 NOM_CAP_OFFSET, rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003317 } else {
3318 chip->cl.nom_cap_uah = (int)(buf[0] | buf[1] << 8) * 1000;
3319 rc = fg_load_learned_cap_from_sram(chip);
3320 if (rc < 0)
3321 pr_err("Error in loading capacity learning data, rc:%d\n",
3322 rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003323 }
3324
Subbaraman Narayanamurthy35051a22017-11-10 15:37:29 -08003325 rc = fg_rconn_config(chip);
3326 if (rc < 0)
3327 pr_err("Error in configuring Rconn, rc=%d\n", rc);
3328
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003329 batt_psy_initialized(chip);
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07003330 fg_notify_charger(chip);
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08003331
3332 if (chip->profile_load_status == PROFILE_LOADED)
3333 chip->profile_loaded = true;
3334
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07003335 fg_dbg(chip, FG_STATUS, "profile loaded successfully");
Nicholas Troaste29dec92016-08-24 09:35:11 -07003336out:
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07003337 chip->soc_reporting_ready = true;
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07003338 vote(chip->awake_votable, ESR_FCC_VOTER, true, 0);
3339 schedule_delayed_work(&chip->pl_enable_work, msecs_to_jiffies(5000));
Nicholas Troaste29dec92016-08-24 09:35:11 -07003340 vote(chip->awake_votable, PROFILE_LOAD, false, 0);
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08003341 if (!work_pending(&chip->status_change_work)) {
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05303342 fg_stay_awake(chip, FG_STATUS_NOTIFY_WAKE);
Subbaraman Narayanamurthy55b54892017-11-21 15:33:16 -08003343 schedule_work(&chip->status_change_work);
3344 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07003345}
3346
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003347static void sram_dump_work(struct work_struct *work)
3348{
3349 struct fg_chip *chip = container_of(work, struct fg_chip,
3350 sram_dump_work.work);
3351 u8 buf[FG_SRAM_LEN];
3352 int rc;
Tirupathi Reddyce65d002017-02-10 18:06:40 +05303353 s64 timestamp_ms, quotient;
3354 s32 remainder;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003355
3356 rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
3357 if (rc < 0) {
3358 pr_err("Error in reading FG SRAM, rc:%d\n", rc);
3359 goto resched;
3360 }
3361
3362 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05303363 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
3364 fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
3365 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003366 dump_sram(buf, 0, FG_SRAM_LEN);
3367 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05303368 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
3369 fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
3370 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08003371resched:
3372 schedule_delayed_work(&chip->sram_dump_work,
3373 msecs_to_jiffies(fg_sram_dump_period_ms));
3374}
3375
3376static int fg_sram_dump_sysfs(const char *val, const struct kernel_param *kp)
3377{
3378 int rc;
3379 struct power_supply *bms_psy;
3380 struct fg_chip *chip;
3381 bool old_val = fg_sram_dump;
3382
3383 rc = param_set_bool(val, kp);
3384 if (rc) {
3385 pr_err("Unable to set fg_sram_dump: %d\n", rc);
3386 return rc;
3387 }
3388
3389 if (fg_sram_dump == old_val)
3390 return 0;
3391
3392 bms_psy = power_supply_get_by_name("bms");
3393 if (!bms_psy) {
3394 pr_err("bms psy not found\n");
3395 return -ENODEV;
3396 }
3397
3398 chip = power_supply_get_drvdata(bms_psy);
3399 if (fg_sram_dump)
3400 schedule_delayed_work(&chip->sram_dump_work,
3401 msecs_to_jiffies(fg_sram_dump_period_ms));
3402 else
3403 cancel_delayed_work_sync(&chip->sram_dump_work);
3404
3405 return 0;
3406}
3407
3408static struct kernel_param_ops fg_sram_dump_ops = {
3409 .set = fg_sram_dump_sysfs,
3410 .get = param_get_bool,
3411};
3412
3413module_param_cb(sram_dump_en, &fg_sram_dump_ops, &fg_sram_dump, 0644);
3414
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07003415static int fg_restart_sysfs(const char *val, const struct kernel_param *kp)
3416{
3417 int rc;
3418 struct power_supply *bms_psy;
3419 struct fg_chip *chip;
3420
3421 rc = param_set_int(val, kp);
3422 if (rc) {
3423 pr_err("Unable to set fg_restart: %d\n", rc);
3424 return rc;
3425 }
3426
3427 if (fg_restart != 1) {
3428 pr_err("Bad value %d\n", fg_restart);
3429 return -EINVAL;
3430 }
3431
3432 bms_psy = power_supply_get_by_name("bms");
3433 if (!bms_psy) {
3434 pr_err("bms psy not found\n");
3435 return 0;
3436 }
3437
3438 chip = power_supply_get_drvdata(bms_psy);
3439 rc = __fg_restart(chip);
3440 if (rc < 0) {
3441 pr_err("Error in restarting FG, rc=%d\n", rc);
3442 return rc;
3443 }
3444
3445 pr_info("FG restart done\n");
3446 return rc;
3447}
3448
3449static struct kernel_param_ops fg_restart_ops = {
3450 .set = fg_restart_sysfs,
3451 .get = param_get_int,
3452};
3453
3454module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
3455
Nicholas Troast1769fd32016-09-07 09:20:58 -07003456#define HOURS_TO_SECONDS 3600
3457#define OCV_SLOPE_UV 10869
3458#define MILLI_UNIT 1000
3459#define MICRO_UNIT 1000000
Nicholas Troast805c2422017-07-06 14:53:46 -07003460#define NANO_UNIT 1000000000
3461static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
Nicholas Troast1769fd32016-09-07 09:20:58 -07003462{
Nicholas Troast805c2422017-07-06 14:53:46 -07003463 int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003464 i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
3465 i, soc_per_step, msoc_this_step, msoc_next_step,
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003466 ibatt_this_step, t_predicted_this_step, ttf_slope,
Nicholas Troast805c2422017-07-06 14:53:46 -07003467 t_predicted_cv, t_predicted = 0;
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003468 s64 delta_ms;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003469
Subbaraman Narayanamurthy476e8372017-08-25 13:38:36 -07003470 if (!chip->soc_reporting_ready)
3471 return -ENODATA;
3472
Nicholas Troast1769fd32016-09-07 09:20:58 -07003473 if (chip->bp.float_volt_uv <= 0) {
3474 pr_err("battery profile is not loaded\n");
3475 return -ENODATA;
3476 }
3477
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003478 if (!batt_psy_initialized(chip)) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07003479 fg_dbg(chip, FG_TTF, "charger is not available\n");
3480 return -ENODATA;
3481 }
3482
Nicholas Troast32a22d32016-12-14 16:12:04 -08003483 rc = fg_get_prop_capacity(chip, &msoc);
3484 if (rc < 0) {
3485 pr_err("failed to get msoc rc=%d\n", rc);
3486 return rc;
3487 }
3488 fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
3489
Nicholas Troast805c2422017-07-06 14:53:46 -07003490 /* the battery is considered full if the SOC is 100% */
Nicholas Troast32a22d32016-12-14 16:12:04 -08003491 if (msoc >= 100) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07003492 *val = 0;
3493 return 0;
3494 }
3495
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003496 if (is_qnovo_en(chip))
3497 ttf_mode = TTF_MODE_QNOVO;
3498 else
3499 ttf_mode = TTF_MODE_NORMAL;
3500
3501 /* when switching TTF algorithms the TTF needs to be reset */
3502 if (chip->ttf.mode != ttf_mode) {
3503 fg_circ_buf_clr(&chip->ttf.ibatt);
3504 fg_circ_buf_clr(&chip->ttf.vbatt);
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003505 chip->ttf.last_ttf = 0;
3506 chip->ttf.last_ms = 0;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003507 chip->ttf.mode = ttf_mode;
3508 }
3509
Nicholas Troast805c2422017-07-06 14:53:46 -07003510 /* at least 10 samples are required to produce a stable IBATT */
3511 if (chip->ttf.ibatt.size < 10) {
3512 *val = -1;
3513 return 0;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003514 }
3515
Nicholas Troast805c2422017-07-06 14:53:46 -07003516 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003517 if (rc < 0) {
Nicholas Troast805c2422017-07-06 14:53:46 -07003518 pr_err("failed to get IBATT AVG rc=%d\n", rc);
3519 return rc;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003520 }
3521
Nicholas Troast805c2422017-07-06 14:53:46 -07003522 rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
3523 if (rc < 0) {
3524 pr_err("failed to get VBATT AVG rc=%d\n", rc);
3525 return rc;
3526 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003527
Nicholas Troast805c2422017-07-06 14:53:46 -07003528 ibatt_avg = -ibatt_avg / MILLI_UNIT;
3529 vbatt_avg /= MILLI_UNIT;
3530
3531 /* clamp ibatt_avg to iterm */
3532 if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
3533 ibatt_avg = abs(chip->dt.sys_term_curr_ma);
3534
Nicholas Troast1769fd32016-09-07 09:20:58 -07003535 fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
Nicholas Troast805c2422017-07-06 14:53:46 -07003536 fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003537
3538 rc = fg_get_battery_resistance(chip, &rbatt);
3539 if (rc < 0) {
3540 pr_err("failed to get battery resistance rc=%d\n", rc);
3541 return rc;
3542 }
3543
Nicholas Troast805c2422017-07-06 14:53:46 -07003544 rbatt /= MILLI_UNIT;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003545 fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
3546
Nicholas Troast805c2422017-07-06 14:53:46 -07003547 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003548 if (rc < 0) {
3549 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
3550 return rc;
3551 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003552
Nicholas Troast1769fd32016-09-07 09:20:58 -07003553 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3554 if (rc < 0) {
3555 pr_err("failed to get full soc rc=%d\n", rc);
3556 return rc;
3557 }
3558 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3559 FULL_SOC_RAW);
Nicholas Troast805c2422017-07-06 14:53:46 -07003560 act_cap_mah = full_soc * act_cap_mah / 100;
3561 fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
3562
3563 /* estimated battery current at the CC to CV transition */
3564 switch (chip->ttf.mode) {
3565 case TTF_MODE_NORMAL:
3566 i_cc2cv = ibatt_avg * vbatt_avg /
3567 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
3568 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003569 case TTF_MODE_QNOVO:
3570 i_cc2cv = min(
3571 chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
3572 ibatt_avg * vbatt_avg /
3573 max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
3574 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07003575 default:
3576 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
3577 break;
3578 }
3579 fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003580
3581 /* if we are already in CV state then we can skip estimating CC */
3582 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
Nicholas Troast805c2422017-07-06 14:53:46 -07003583 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003584
Nicholas Troast1769fd32016-09-07 09:20:58 -07003585 /* estimated SOC at the CC to CV transition */
Nicholas Troast805c2422017-07-06 14:53:46 -07003586 soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003587 soc_cc2cv = 100 - soc_cc2cv;
3588 fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
3589
Nicholas Troast805c2422017-07-06 14:53:46 -07003590 switch (chip->ttf.mode) {
3591 case TTF_MODE_NORMAL:
3592 if (soc_cc2cv - msoc <= 0)
3593 goto cv_estimate;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003594
Nicholas Troast805c2422017-07-06 14:53:46 -07003595 divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
3596 t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
3597 HOURS_TO_SECONDS, divisor);
3598 break;
Nicholas Troastb8cb40c2017-06-21 11:10:40 -07003599 case TTF_MODE_QNOVO:
3600 soc_per_step = 100 / MAX_CC_STEPS;
3601 for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
3602 msoc_next_step = (i + 1) * soc_per_step;
3603 if (i == msoc / soc_per_step)
3604 msoc_this_step = msoc;
3605 else
3606 msoc_this_step = i * soc_per_step;
3607
3608 /* scale ibatt by 85% to account for discharge pulses */
3609 ibatt_this_step = min(
3610 chip->ttf.cc_step.arr[i] / MILLI_UNIT,
3611 ibatt_avg) * 85 / 100;
3612 divisor = max(100, ibatt_this_step * 100);
3613 t_predicted_this_step = div_s64((s64)act_cap_mah *
3614 (msoc_next_step - msoc_this_step) *
3615 HOURS_TO_SECONDS, divisor);
3616 t_predicted += t_predicted_this_step;
3617 fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
3618 msoc_this_step, msoc_next_step,
3619 ibatt_this_step, t_predicted_this_step);
3620 }
3621 break;
Nicholas Troast805c2422017-07-06 14:53:46 -07003622 default:
3623 pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
3624 break;
3625 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003626
Nicholas Troast805c2422017-07-06 14:53:46 -07003627cv_estimate:
3628 fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003629
Nicholas Troast805c2422017-07-06 14:53:46 -07003630 iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
3631 fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
3632
3633 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
3634 tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003635 else
Nicholas Troast805c2422017-07-06 14:53:46 -07003636 tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
Nicholas Troastde5d42f2017-01-20 16:47:31 -08003637
Nicholas Troast805c2422017-07-06 14:53:46 -07003638 rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
3639 if (rc < 0) {
3640 pr_err("failed to interpolate tau rc=%d\n", rc);
3641 return rc;
3642 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003643
Nicholas Troast805c2422017-07-06 14:53:46 -07003644 /* tau is scaled linearly from 95% to 100% SOC */
3645 if (msoc >= 95)
3646 tau = tau * 2 * (100 - msoc) / 10;
3647
3648 fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
3649 t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
3650 HOURS_TO_SECONDS, NANO_UNIT);
3651 fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
3652 t_predicted += t_predicted_cv;
3653
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003654 fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
3655 if (chip->ttf.last_ms != 0) {
3656 delta_ms = ktime_ms_delta(ktime_get_boottime(),
3657 ms_to_ktime(chip->ttf.last_ms));
3658 if (delta_ms > 10000) {
3659 ttf_slope = div64_s64(
3660 (s64)(t_predicted - chip->ttf.last_ttf) *
3661 MICRO_UNIT, delta_ms);
3662 if (ttf_slope > -100)
3663 ttf_slope = -100;
3664 else if (ttf_slope < -2000)
3665 ttf_slope = -2000;
3666
3667 t_predicted = div_s64(
3668 (s64)ttf_slope * delta_ms, MICRO_UNIT) +
3669 chip->ttf.last_ttf;
3670 fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
3671 } else {
3672 t_predicted = chip->ttf.last_ttf;
3673 }
3674 }
3675
Nicholas Troast805c2422017-07-06 14:53:46 -07003676 /* clamp the ttf to 0 */
3677 if (t_predicted < 0)
3678 t_predicted = 0;
3679
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003680 fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
Nicholas Troast805c2422017-07-06 14:53:46 -07003681 *val = t_predicted;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003682 return 0;
3683}
3684
Nicholas Troast805c2422017-07-06 14:53:46 -07003685static int fg_get_time_to_full(struct fg_chip *chip, int *val)
3686{
3687 int rc;
3688
3689 mutex_lock(&chip->ttf.lock);
3690 rc = fg_get_time_to_full_locked(chip, val);
3691 mutex_unlock(&chip->ttf.lock);
3692 return rc;
3693}
3694
Nicholas Troast1769fd32016-09-07 09:20:58 -07003695#define CENTI_ICORRECT_C0 105
3696#define CENTI_ICORRECT_C1 20
3697static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
3698{
Nicholas Troast805c2422017-07-06 14:53:46 -07003699 int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003700
Umang Chheda14311472020-01-23 14:57:00 +05303701 mutex_lock(&chip->ttf.lock);
Nicholas Troast805c2422017-07-06 14:53:46 -07003702 rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003703 if (rc < 0) {
3704 /* try to get instantaneous current */
3705 rc = fg_get_battery_current(chip, &ibatt_avg);
3706 if (rc < 0) {
3707 pr_err("failed to get battery current, rc=%d\n", rc);
Umang Chheda14311472020-01-23 14:57:00 +05303708 mutex_unlock(&chip->ttf.lock);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003709 return rc;
3710 }
3711 }
Umang Chheda14311472020-01-23 14:57:00 +05303712 mutex_unlock(&chip->ttf.lock);
Nicholas Troast1769fd32016-09-07 09:20:58 -07003713
Nicholas Troast805c2422017-07-06 14:53:46 -07003714 ibatt_avg /= MILLI_UNIT;
3715 /* clamp ibatt_avg to 100mA */
3716 if (ibatt_avg < 100)
3717 ibatt_avg = 100;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003718
3719 rc = fg_get_prop_capacity(chip, &msoc);
3720 if (rc < 0) {
3721 pr_err("Error in getting capacity, rc=%d\n", rc);
3722 return rc;
3723 }
3724
Nicholas Troast805c2422017-07-06 14:53:46 -07003725 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
3726 if (rc < 0) {
3727 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
3728 return rc;
3729 }
Nicholas Troast1769fd32016-09-07 09:20:58 -07003730
Nicholas Troast805c2422017-07-06 14:53:46 -07003731 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
3732 if (rc < 0) {
3733 pr_err("failed to get full soc rc=%d\n", rc);
3734 return rc;
3735 }
3736 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
3737 FULL_SOC_RAW);
3738 act_cap_mah = full_soc * act_cap_mah / 100;
3739
3740 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
3741 divisor = ibatt_avg * divisor / 100;
3742 divisor = max(100, divisor);
3743 *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003744 return 0;
3745}
3746
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003747static int fg_update_maint_soc(struct fg_chip *chip)
3748{
3749 int rc = 0, msoc;
3750
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07003751 if (!chip->dt.linearize_soc)
3752 return 0;
3753
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003754 mutex_lock(&chip->charge_full_lock);
3755 if (chip->delta_soc <= 0)
3756 goto out;
3757
3758 rc = fg_get_msoc(chip, &msoc);
3759 if (rc < 0) {
3760 pr_err("Error in getting msoc, rc=%d\n", rc);
3761 goto out;
3762 }
3763
3764 if (msoc > chip->maint_soc) {
3765 /*
3766 * When the monotonic SOC goes above maintenance SOC, we should
3767 * stop showing the maintenance SOC.
3768 */
3769 chip->delta_soc = 0;
3770 chip->maint_soc = 0;
3771 } else if (msoc <= chip->last_msoc) {
3772 /* MSOC is decreasing. Decrease maintenance SOC as well */
3773 chip->maint_soc -= 1;
3774 if (!(msoc % 10)) {
3775 /*
3776 * Reduce the maintenance SOC additionally by 1 whenever
3777 * it crosses a SOC multiple of 10.
3778 */
3779 chip->maint_soc -= 1;
3780 chip->delta_soc -= 1;
3781 }
3782 }
3783
3784 fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
3785 msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
3786 chip->last_msoc = msoc;
3787out:
3788 mutex_unlock(&chip->charge_full_lock);
3789 return rc;
3790}
3791
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003792static int fg_esr_validate(struct fg_chip *chip)
3793{
3794 int rc, esr_uohms;
3795 u8 buf[2];
3796
3797 if (chip->dt.esr_clamp_mohms <= 0)
3798 return 0;
3799
3800 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
3801 if (rc < 0) {
3802 pr_err("failed to get ESR, rc=%d\n", rc);
3803 return rc;
3804 }
3805
3806 if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) {
3807 pr_debug("ESR %d is > ESR_clamp\n", esr_uohms);
3808 return 0;
3809 }
3810
3811 esr_uohms = chip->dt.esr_clamp_mohms * 1000;
3812 fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf);
3813 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word,
3814 chip->sp[FG_SRAM_ESR].addr_byte, buf,
3815 chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT);
3816 if (rc < 0) {
3817 pr_err("Error in writing ESR, rc=%d\n", rc);
3818 return rc;
3819 }
3820
3821 fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms);
3822 return 0;
3823}
3824
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003825static int fg_force_esr_meas(struct fg_chip *chip)
3826{
3827 int rc;
3828 int esr_uohms;
3829
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003830 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003831 /* force esr extraction enable */
3832 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3833 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
3834 FG_IMA_DEFAULT);
3835 if (rc < 0) {
3836 pr_err("failed to enable esr extn rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003837 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003838 }
3839
3840 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3841 LD_REG_CTRL_BIT, 0);
3842 if (rc < 0) {
3843 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003844 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003845 }
3846
3847 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3848 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3849 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
3850 if (rc < 0) {
3851 pr_err("Error in configuring force ESR rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003852 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003853 }
3854
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003855 /*
3856 * Release and grab the lock again after 1.5 seconds so that prepare
3857 * callback can succeed if the request comes in between.
3858 */
3859 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
3860
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003861 /* wait 1.5 seconds for hw to measure ESR */
3862 msleep(1500);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003863
3864 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003865 rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
3866 ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
3867 0);
3868 if (rc < 0) {
3869 pr_err("Error in restoring force ESR rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003870 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003871 }
3872
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003873 /* If qnovo is disabled, then leave ESR extraction enabled */
3874 if (!chip->qnovo_enable)
3875 goto done;
3876
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003877 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3878 LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
3879 if (rc < 0) {
3880 pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003881 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003882 }
3883
3884 /* force esr extraction disable */
3885 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3886 ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0,
3887 FG_IMA_DEFAULT);
3888 if (rc < 0) {
3889 pr_err("failed to disable esr extn rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003890 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003891 }
3892
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003893done:
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003894 fg_get_battery_resistance(chip, &esr_uohms);
3895 fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003896out:
3897 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003898 return rc;
3899}
3900
3901static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
3902{
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003903 int rc = 0;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003904
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003905 mutex_lock(&chip->qnovo_esr_ctrl_lock);
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003906 /* force esr extraction disable when qnovo enables */
3907 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
3908 ESR_EXTRACTION_ENABLE_OFFSET,
3909 BIT(0), qnovo_enable ? 0 : BIT(0),
3910 FG_IMA_DEFAULT);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003911 if (rc < 0) {
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003912 pr_err("Error in configuring esr extraction rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003913 goto out;
3914 }
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003915
3916 rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
3917 LD_REG_CTRL_BIT,
3918 qnovo_enable ? LD_REG_CTRL_BIT : 0);
3919 if (rc < 0) {
3920 pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003921 goto out;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003922 }
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07003923
3924 fg_dbg(chip, FG_STATUS, "%s for Qnovo\n",
3925 qnovo_enable ? "Prepared" : "Unprepared");
3926 chip->qnovo_enable = qnovo_enable;
3927out:
3928 mutex_unlock(&chip->qnovo_esr_ctrl_lock);
3929 return rc;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07003930}
Nicholas Troast805c2422017-07-06 14:53:46 -07003931
3932static void ttf_work(struct work_struct *work)
3933{
3934 struct fg_chip *chip = container_of(work, struct fg_chip,
3935 ttf_work.work);
3936 int rc, ibatt_now, vbatt_now, ttf;
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003937 ktime_t ktime_now;
Nicholas Troast805c2422017-07-06 14:53:46 -07003938
3939 mutex_lock(&chip->ttf.lock);
3940 if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
3941 chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
3942 goto end_work;
3943
3944 rc = fg_get_battery_current(chip, &ibatt_now);
3945 if (rc < 0) {
3946 pr_err("failed to get battery current, rc=%d\n", rc);
3947 goto end_work;
3948 }
3949
3950 rc = fg_get_battery_voltage(chip, &vbatt_now);
3951 if (rc < 0) {
3952 pr_err("failed to get battery voltage, rc=%d\n", rc);
3953 goto end_work;
3954 }
3955
3956 fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
3957 fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
3958
3959 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
3960 rc = fg_get_time_to_full_locked(chip, &ttf);
3961 if (rc < 0) {
3962 pr_err("failed to get ttf, rc=%d\n", rc);
3963 goto end_work;
3964 }
3965
3966 /* keep the wake lock and prime the IBATT and VBATT buffers */
3967 if (ttf < 0) {
3968 /* delay for one FG cycle */
3969 schedule_delayed_work(&chip->ttf_work,
3970 msecs_to_jiffies(1500));
3971 mutex_unlock(&chip->ttf.lock);
3972 return;
3973 }
Nicholas Troastb8c0b9a2017-07-10 13:14:28 -07003974
3975 /* update the TTF reference point every minute */
3976 ktime_now = ktime_get_boottime();
3977 if (ktime_ms_delta(ktime_now,
3978 ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
3979 chip->ttf.last_ms == 0) {
3980 chip->ttf.last_ttf = ttf;
3981 chip->ttf.last_ms = ktime_to_ms(ktime_now);
3982 }
Nicholas Troast805c2422017-07-06 14:53:46 -07003983 }
3984
3985 /* recurse every 10 seconds */
3986 schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
3987end_work:
3988 vote(chip->awake_votable, TTF_PRIMING, false, 0);
3989 mutex_unlock(&chip->ttf.lock);
3990}
3991
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003992/* PSY CALLBACKS STAY HERE */
3993
3994static int fg_psy_get_property(struct power_supply *psy,
3995 enum power_supply_property psp,
3996 union power_supply_propval *pval)
3997{
3998 struct fg_chip *chip = power_supply_get_drvdata(psy);
3999 int rc = 0;
4000
4001 switch (psp) {
4002 case POWER_SUPPLY_PROP_CAPACITY:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08004003 rc = fg_get_prop_capacity(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004004 break;
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07004005 case POWER_SUPPLY_PROP_CAPACITY_RAW:
4006 rc = fg_get_msoc_raw(chip, &pval->intval);
4007 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004008 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08004009 if (chip->battery_missing)
4010 pval->intval = 3700000;
4011 else
4012 rc = fg_get_battery_voltage(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004013 break;
4014 case POWER_SUPPLY_PROP_CURRENT_NOW:
4015 rc = fg_get_battery_current(chip, &pval->intval);
4016 break;
4017 case POWER_SUPPLY_PROP_TEMP:
4018 rc = fg_get_battery_temp(chip, &pval->intval);
4019 break;
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004020 case POWER_SUPPLY_PROP_COLD_TEMP:
4021 rc = fg_get_jeita_threshold(chip, JEITA_COLD, &pval->intval);
4022 if (rc < 0) {
4023 pr_err("Error in reading jeita_cold, rc=%d\n", rc);
4024 return rc;
4025 }
4026 break;
4027 case POWER_SUPPLY_PROP_COOL_TEMP:
4028 rc = fg_get_jeita_threshold(chip, JEITA_COOL, &pval->intval);
4029 if (rc < 0) {
4030 pr_err("Error in reading jeita_cool, rc=%d\n", rc);
4031 return rc;
4032 }
4033 break;
4034 case POWER_SUPPLY_PROP_WARM_TEMP:
4035 rc = fg_get_jeita_threshold(chip, JEITA_WARM, &pval->intval);
4036 if (rc < 0) {
4037 pr_err("Error in reading jeita_warm, rc=%d\n", rc);
4038 return rc;
4039 }
4040 break;
4041 case POWER_SUPPLY_PROP_HOT_TEMP:
4042 rc = fg_get_jeita_threshold(chip, JEITA_HOT, &pval->intval);
4043 if (rc < 0) {
4044 pr_err("Error in reading jeita_hot, rc=%d\n", rc);
4045 return rc;
4046 }
4047 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004048 case POWER_SUPPLY_PROP_RESISTANCE:
4049 rc = fg_get_battery_resistance(chip, &pval->intval);
4050 break;
4051 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
4052 rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
4053 break;
4054 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004055 pval->intval = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004056 break;
4057 case POWER_SUPPLY_PROP_RESISTANCE_ID:
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08004058 pval->intval = chip->batt_id_ohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004059 break;
4060 case POWER_SUPPLY_PROP_BATTERY_TYPE:
4061 pval->strval = fg_get_battery_type(chip);
4062 break;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07004063 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
4064 pval->intval = chip->bp.float_volt_uv;
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07004065 break;
Vamshi Krishna B V56623402018-09-19 11:56:07 +05304066 case POWER_SUPPLY_PROP_CYCLE_COUNT:
4067 pval->intval = fg_get_cycle_count(chip);
4068 break;
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08004069 case POWER_SUPPLY_PROP_CYCLE_COUNTS:
Vamshi Krishna B V56623402018-09-19 11:56:07 +05304070 pval->strval = fg_get_cycle_counts(chip);
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07004071 break;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004072 case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07004073 rc = fg_get_charge_raw(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004074 break;
4075 case POWER_SUPPLY_PROP_CHARGE_NOW:
4076 pval->intval = chip->cl.init_cc_uah;
4077 break;
4078 case POWER_SUPPLY_PROP_CHARGE_FULL:
4079 pval->intval = chip->cl.learned_cc_uah;
4080 break;
4081 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07004082 rc = fg_get_charge_counter(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004083 break;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07004084 case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
4085 rc = fg_get_charge_counter_shadow(chip, &pval->intval);
4086 break;
Nicholas Troast1769fd32016-09-07 09:20:58 -07004087 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
4088 rc = fg_get_time_to_full(chip, &pval->intval);
4089 break;
4090 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
4091 rc = fg_get_time_to_empty(chip, &pval->intval);
4092 break;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08004093 case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
4094 pval->intval = chip->soc_reporting_ready;
4095 break;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304096 case POWER_SUPPLY_PROP_DEBUG_BATTERY:
4097 pval->intval = is_debug_batt_id(chip);
4098 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08004099 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
4100 rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
4101 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004102 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07004103 if ((chip->ttf.cc_step.sel >= 0) &&
4104 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
4105 pval->intval =
4106 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004107 } else {
4108 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07004109 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004110 return -EINVAL;
4111 }
4112 break;
4113 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Nicholas Troast805c2422017-07-06 14:53:46 -07004114 pval->intval = chip->ttf.cc_step.sel;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004115 break;
Anirudh Ghayalaf38fdc2019-05-23 14:19:42 +05304116 case POWER_SUPPLY_PROP_REAL_CAPACITY:
4117 rc = fg_get_prop_real_capacity(chip, &pval->intval);
4118 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004119 default:
Nicholas Troast1769fd32016-09-07 09:20:58 -07004120 pr_err("unsupported property %d\n", psp);
4121 rc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004122 break;
4123 }
4124
Nicholas Troast1769fd32016-09-07 09:20:58 -07004125 if (rc < 0)
4126 return -ENODATA;
4127
4128 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004129}
4130
4131static int fg_psy_set_property(struct power_supply *psy,
4132 enum power_supply_property psp,
4133 const union power_supply_propval *pval)
4134{
Nicholas Troaste29dec92016-08-24 09:35:11 -07004135 struct fg_chip *chip = power_supply_get_drvdata(psy);
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08004136 int rc = 0;
Nicholas Troaste29dec92016-08-24 09:35:11 -07004137
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004138 switch (psp) {
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08004139 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
4140 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004141 break;
Abhijeet Dharmapurikard29bc602017-07-06 18:45:32 -07004142 case POWER_SUPPLY_PROP_RESISTANCE:
4143 rc = fg_force_esr_meas(chip);
4144 break;
4145 case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
4146 rc = fg_prepare_for_qnovo(chip, pval->intval);
4147 break;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004148 case POWER_SUPPLY_PROP_CC_STEP:
Nicholas Troast805c2422017-07-06 14:53:46 -07004149 if ((chip->ttf.cc_step.sel >= 0) &&
4150 (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
4151 chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
4152 pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004153 } else {
4154 pr_err("cc_step_sel is out of bounds [0, %d]\n",
Nicholas Troast805c2422017-07-06 14:53:46 -07004155 chip->ttf.cc_step.sel);
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004156 return -EINVAL;
4157 }
4158 break;
4159 case POWER_SUPPLY_PROP_CC_STEP_SEL:
4160 if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
Nicholas Troast805c2422017-07-06 14:53:46 -07004161 chip->ttf.cc_step.sel = pval->intval;
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004162 } else {
4163 pr_err("cc_step_sel is out of bounds [0, %d]\n",
4164 pval->intval);
4165 return -EINVAL;
4166 }
4167 break;
Subbaraman Narayanamurthy677e7252017-08-11 18:27:08 -07004168 case POWER_SUPPLY_PROP_CHARGE_FULL:
4169 if (chip->cl.active) {
4170 pr_warn("Capacity learning active!\n");
4171 return 0;
4172 }
4173 if (pval->intval <= 0 || pval->intval > chip->cl.nom_cap_uah) {
4174 pr_err("charge_full is out of bounds\n");
4175 return -EINVAL;
4176 }
4177 chip->cl.learned_cc_uah = pval->intval;
4178 rc = fg_save_learned_cap_to_sram(chip);
4179 if (rc < 0)
4180 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
4181 break;
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004182 case POWER_SUPPLY_PROP_COLD_TEMP:
4183 rc = fg_set_jeita_threshold(chip, JEITA_COLD, pval->intval);
4184 if (rc < 0) {
4185 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
4186 return rc;
4187 }
4188 break;
4189 case POWER_SUPPLY_PROP_COOL_TEMP:
4190 rc = fg_set_jeita_threshold(chip, JEITA_COOL, pval->intval);
4191 if (rc < 0) {
4192 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
4193 return rc;
4194 }
4195 break;
4196 case POWER_SUPPLY_PROP_WARM_TEMP:
4197 rc = fg_set_jeita_threshold(chip, JEITA_WARM, pval->intval);
4198 if (rc < 0) {
4199 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
4200 return rc;
4201 }
4202 break;
4203 case POWER_SUPPLY_PROP_HOT_TEMP:
4204 rc = fg_set_jeita_threshold(chip, JEITA_HOT, pval->intval);
4205 if (rc < 0) {
4206 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
4207 return rc;
4208 }
4209 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004210 default:
4211 break;
4212 }
4213
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08004214 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004215}
4216
4217static int fg_property_is_writeable(struct power_supply *psy,
4218 enum power_supply_property psp)
4219{
4220 switch (psp) {
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08004221 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004222 case POWER_SUPPLY_PROP_CC_STEP:
4223 case POWER_SUPPLY_PROP_CC_STEP_SEL:
Subbaraman Narayanamurthy677e7252017-08-11 18:27:08 -07004224 case POWER_SUPPLY_PROP_CHARGE_FULL:
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004225 case POWER_SUPPLY_PROP_COLD_TEMP:
4226 case POWER_SUPPLY_PROP_COOL_TEMP:
4227 case POWER_SUPPLY_PROP_WARM_TEMP:
4228 case POWER_SUPPLY_PROP_HOT_TEMP:
Nicholas Troaste29dec92016-08-24 09:35:11 -07004229 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004230 default:
4231 break;
4232 }
4233
4234 return 0;
4235}
4236
4237static void fg_external_power_changed(struct power_supply *psy)
4238{
4239 pr_debug("power supply changed\n");
4240}
4241
4242static int fg_notifier_cb(struct notifier_block *nb,
4243 unsigned long event, void *data)
4244{
4245 struct power_supply *psy = data;
4246 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
4247
Anirudh Ghayal65788312017-10-18 11:36:22 +05304248 spin_lock(&chip->suspend_lock);
4249 if (chip->suspended) {
4250 /* Return if we are still suspended */
4251 spin_unlock(&chip->suspend_lock);
4252 return NOTIFY_OK;
4253 }
4254 spin_unlock(&chip->suspend_lock);
4255
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004256 if (event != PSY_EVENT_PROP_CHANGED)
4257 return NOTIFY_OK;
4258
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08004259 if (work_pending(&chip->status_change_work))
4260 return NOTIFY_OK;
4261
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004262 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthya7249ef2017-10-03 20:34:38 -07004263 || (strcmp(psy->desc->name, "parallel") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004264 || (strcmp(psy->desc->name, "usb") == 0)) {
4265 /*
4266 * We cannot vote for awake votable here as that takes
4267 * a mutex lock and this is executed in an atomic context.
4268 */
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05304269 fg_stay_awake(chip, FG_STATUS_NOTIFY_WAKE);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004270 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004271 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004272
4273 return NOTIFY_OK;
4274}
4275
Anirudh Ghayala209ac32018-08-23 15:08:05 +05304276static int twm_notifier_cb(struct notifier_block *nb,
4277 unsigned long action, void *data)
4278{
4279 struct fg_chip *chip = container_of(nb, struct fg_chip, twm_nb);
4280
4281 if (action != PMIC_TWM_CLEAR &&
4282 action != PMIC_TWM_ENABLE) {
4283 pr_debug("Unsupported option %lu\n", action);
4284 return NOTIFY_OK;
4285 }
4286
4287 chip->twm_state = (u8)action;
4288
4289 return NOTIFY_OK;
4290}
4291
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004292static enum power_supply_property fg_psy_props[] = {
4293 POWER_SUPPLY_PROP_CAPACITY,
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07004294 POWER_SUPPLY_PROP_CAPACITY_RAW,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004295 POWER_SUPPLY_PROP_TEMP,
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004296 POWER_SUPPLY_PROP_COLD_TEMP,
4297 POWER_SUPPLY_PROP_COOL_TEMP,
4298 POWER_SUPPLY_PROP_WARM_TEMP,
4299 POWER_SUPPLY_PROP_HOT_TEMP,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004300 POWER_SUPPLY_PROP_VOLTAGE_NOW,
4301 POWER_SUPPLY_PROP_VOLTAGE_OCV,
4302 POWER_SUPPLY_PROP_CURRENT_NOW,
4303 POWER_SUPPLY_PROP_RESISTANCE_ID,
4304 POWER_SUPPLY_PROP_RESISTANCE,
4305 POWER_SUPPLY_PROP_BATTERY_TYPE,
4306 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07004307 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Vamshi Krishna B V56623402018-09-19 11:56:07 +05304308 POWER_SUPPLY_PROP_CYCLE_COUNT,
Subbaraman Narayanamurthyfb4239c2018-02-02 15:35:44 -08004309 POWER_SUPPLY_PROP_CYCLE_COUNTS,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004310 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
4311 POWER_SUPPLY_PROP_CHARGE_NOW,
4312 POWER_SUPPLY_PROP_CHARGE_FULL,
4313 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07004314 POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
Nicholas Troast1769fd32016-09-07 09:20:58 -07004315 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
4316 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08004317 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304318 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08004319 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Abhijeet Dharmapurikar19258922017-07-31 19:27:16 -07004320 POWER_SUPPLY_PROP_CC_STEP,
4321 POWER_SUPPLY_PROP_CC_STEP_SEL,
Anirudh Ghayalaf38fdc2019-05-23 14:19:42 +05304322 POWER_SUPPLY_PROP_REAL_CAPACITY,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004323};
4324
4325static const struct power_supply_desc fg_psy_desc = {
4326 .name = "bms",
4327 .type = POWER_SUPPLY_TYPE_BMS,
4328 .properties = fg_psy_props,
4329 .num_properties = ARRAY_SIZE(fg_psy_props),
4330 .get_property = fg_psy_get_property,
4331 .set_property = fg_psy_set_property,
4332 .external_power_changed = fg_external_power_changed,
4333 .property_is_writeable = fg_property_is_writeable,
4334};
4335
4336/* INIT FUNCTIONS STAY HERE */
4337
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004338#define DEFAULT_ESR_CHG_TIMER_RETRY 8
4339#define DEFAULT_ESR_CHG_TIMER_MAX 16
Sahil Chandna888ad482019-03-28 14:47:09 +05304340#define VOLTAGE_MODE_SAT_CLEAR_BIT BIT(3)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004341static int fg_hw_init(struct fg_chip *chip)
4342{
4343 int rc;
4344 u8 buf[4], val;
4345
4346 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07004347 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
4348 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004349 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
4350 if (rc < 0) {
4351 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
4352 return rc;
4353 }
4354
4355 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07004356 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
4357 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004358 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
4359 if (rc < 0) {
4360 pr_err("Error in writing empty_volt, rc=%d\n", rc);
4361 return rc;
4362 }
4363
4364 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
4365 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07004366 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
4367 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004368 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
4369 if (rc < 0) {
4370 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
4371 return rc;
4372 }
4373
4374 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
4375 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07004376 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
4377 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004378 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
4379 if (rc < 0) {
4380 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
4381 return rc;
4382 }
4383
Subbaraman Narayanamurthy5566f502017-12-19 19:39:03 -08004384 fg_encode(chip->sp, FG_SRAM_CUTOFF_CURR, chip->dt.cutoff_curr_ma,
4385 buf);
4386 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_CURR].addr_word,
4387 chip->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf,
4388 chip->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT);
4389 if (rc < 0) {
4390 pr_err("Error in writing cutoff_curr, rc=%d\n", rc);
4391 return rc;
4392 }
4393
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004394 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
4395 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
4396 chip->dt.chg_term_base_curr_ma, buf);
4397 rc = fg_sram_write(chip,
4398 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
4399 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
4400 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
4401 FG_IMA_DEFAULT);
4402 if (rc < 0) {
4403 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
4404 rc);
4405 return rc;
4406 }
4407 }
4408
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004409 if (chip->dt.vbatt_low_thr_mv > 0) {
4410 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
4411 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07004412 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
4413 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004414 chip->sp[FG_SRAM_VBATT_LOW].len,
4415 FG_IMA_DEFAULT);
4416 if (rc < 0) {
4417 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
4418 return rc;
4419 }
4420 }
4421
4422 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004423 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004424 chip->dt.delta_soc_thr, buf);
4425 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004426 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
4427 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
4428 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004429 FG_IMA_DEFAULT);
4430 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004431 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
4432 return rc;
4433 }
4434
4435 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
4436 chip->dt.delta_soc_thr, buf);
4437 rc = fg_sram_write(chip,
4438 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
4439 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
4440 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
4441 FG_IMA_DEFAULT);
4442 if (rc < 0) {
4443 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004444 return rc;
4445 }
4446 }
4447
cyizhaofb3eec52017-01-24 17:08:55 +08004448 /*
4449 * configure battery thermal coefficients c1,c2,c3
4450 * if its value is not zero.
4451 */
4452 if (chip->dt.batt_therm_coeffs[0] > 0) {
4453 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
4454 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
4455 if (rc < 0) {
4456 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
4457 rc);
4458 return rc;
4459 }
4460 }
4461
4462
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004463 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004464 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004465 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004466 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004467 return rc;
4468 }
4469 }
4470
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004471 if (chip->dt.recharge_volt_thr_mv > 0) {
4472 rc = fg_set_recharge_voltage(chip,
4473 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004474 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004475 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004476 rc);
4477 return rc;
4478 }
4479 }
4480
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004481 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
4482 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
4483 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
4484 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
4485 if (rc < 0) {
4486 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
4487 return rc;
4488 }
4489 }
4490
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004491 rc = fg_set_jeita_threshold(chip, JEITA_COLD,
4492 chip->dt.jeita_thresholds[JEITA_COLD] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004493 if (rc < 0) {
4494 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
4495 return rc;
4496 }
4497
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004498 rc = fg_set_jeita_threshold(chip, JEITA_COOL,
4499 chip->dt.jeita_thresholds[JEITA_COOL] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004500 if (rc < 0) {
4501 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
4502 return rc;
4503 }
4504
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004505 rc = fg_set_jeita_threshold(chip, JEITA_WARM,
4506 chip->dt.jeita_thresholds[JEITA_WARM] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004507 if (rc < 0) {
4508 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
4509 return rc;
4510 }
4511
Subbaraman Narayanamurthyedff8902017-08-11 19:24:24 -07004512 rc = fg_set_jeita_threshold(chip, JEITA_HOT,
4513 chip->dt.jeita_thresholds[JEITA_HOT] * 10);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004514 if (rc < 0) {
4515 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
4516 return rc;
4517 }
4518
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004519 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
4520 chip->esr_timer_charging_default[TIMER_RETRY] =
4521 DEFAULT_ESR_CHG_TIMER_RETRY;
4522 chip->esr_timer_charging_default[TIMER_MAX] =
4523 DEFAULT_ESR_CHG_TIMER_MAX;
4524 } else {
4525 /* We don't need this for pm660 at present */
4526 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
4527 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004528 }
4529
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004530 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
4531 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
4532 if (rc < 0) {
4533 pr_err("Error in setting ESR timer, rc=%d\n", rc);
4534 return rc;
4535 }
4536
4537 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
4538 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
4539 if (rc < 0) {
4540 pr_err("Error in setting ESR timer, rc=%d\n", rc);
4541 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004542 }
4543
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07004544 restore_cycle_counter(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004545
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004546 if (chip->dt.jeita_hyst_temp >= 0) {
4547 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
4548 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
4549 JEITA_TEMP_HYST_MASK, val);
4550 if (rc < 0) {
4551 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
4552 return rc;
4553 }
4554 }
4555
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004556 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
4557 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
4558 CHANGE_THOLD_MASK, val);
4559 if (rc < 0) {
4560 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
4561 return rc;
4562 }
4563
Sahil Chandna888ad482019-03-28 14:47:09 +05304564 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
4565 ESR_EXTRACTION_ENABLE_OFFSET,
4566 VOLTAGE_MODE_SAT_CLEAR_BIT,
4567 VOLTAGE_MODE_SAT_CLEAR_BIT,
4568 FG_IMA_DEFAULT);
4569 if (rc < 0)
4570 return rc;
4571
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004572 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
4573 chip->dt.esr_tight_flt_upct, buf);
4574 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
4575 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
4576 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
4577 if (rc < 0) {
4578 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
4579 return rc;
4580 }
4581
4582 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
4583 chip->dt.esr_broad_flt_upct, buf);
4584 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
4585 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
4586 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
4587 if (rc < 0) {
4588 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
4589 return rc;
4590 }
4591
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004592 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
4593 chip->dt.esr_pulse_thresh_ma, buf);
4594 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
4595 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
4596 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
4597 if (rc < 0) {
4598 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
4599 return rc;
4600 }
4601
4602 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
4603 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
4604 ESR_PULL_DOWN_IVAL_MASK, val);
4605 if (rc < 0) {
4606 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
4607 return rc;
4608 }
4609
Anirudh Ghayale149f562018-08-03 16:34:56 +05304610 if (is_debug_batt_id(chip) || chip->dt.disable_esr_pull_dn) {
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07004611 val = ESR_NO_PULL_DOWN;
4612 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
4613 ESR_PULL_DOWN_MODE_MASK, val);
4614 if (rc < 0) {
4615 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
4616 return rc;
4617 }
4618 }
4619
Subbaraman Narayanamurthy13103202018-03-19 12:16:36 -07004620 if (chip->dt.ki_coeff_hi_chg != -EINVAL) {
4621 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_CHG,
4622 chip->dt.ki_coeff_hi_chg, &val);
4623 rc = fg_sram_write(chip,
4624 chip->sp[FG_SRAM_KI_COEFF_HI_CHG].addr_word,
4625 chip->sp[FG_SRAM_KI_COEFF_HI_CHG].addr_byte,
4626 &val, chip->sp[FG_SRAM_KI_COEFF_HI_CHG].len,
4627 FG_IMA_DEFAULT);
4628 if (rc < 0) {
4629 pr_err("Error in writing ki_coeff_hi_chg, rc=%d\n", rc);
4630 return rc;
4631 }
4632 }
4633
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05304634 if (chip->dt.use_esr_sw) {
4635 /* Enable ESR extraction explicitly */
4636 rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
4637 ESR_EXTRACTION_ENABLE_OFFSET,
4638 ESR_EXTRACTION_ENABLE_MASK,
4639 0x1, FG_IMA_DEFAULT);
4640 if (rc < 0) {
4641 pr_err("Error in enabling ESR extraction rc=%d\n", rc);
4642 return rc;
4643 }
4644 }
4645
Anirudh Ghayalbcb85772018-08-08 10:17:25 +05304646 if (chip->dt.sync_sleep_threshold_ma != -EINVAL) {
4647 fg_encode(chip->sp, FG_SRAM_SYNC_SLEEP_THR,
4648 chip->dt.sync_sleep_threshold_ma, buf);
4649 rc = fg_sram_write(chip,
4650 chip->sp[FG_SRAM_SYNC_SLEEP_THR].addr_word,
4651 chip->sp[FG_SRAM_SYNC_SLEEP_THR].addr_byte, buf,
4652 chip->sp[FG_SRAM_SYNC_SLEEP_THR].len,
4653 FG_IMA_DEFAULT);
4654 if (rc < 0) {
4655 pr_err("Error in writing sync_sleep_threshold=%d\n",
4656 rc);
4657 return rc;
4658 }
4659 }
4660
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004661 return 0;
4662}
4663
4664static int fg_memif_init(struct fg_chip *chip)
4665{
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004666 if (chip->use_dma)
4667 return fg_dma_init(chip);
4668
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004669 return fg_ima_init(chip);
4670}
4671
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304672static int fg_adjust_timebase(struct fg_chip *chip)
4673{
4674 int rc = 0, die_temp;
4675 s32 time_base = 0;
4676 u8 buf[2] = {0};
4677
4678 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
4679 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
4680 if (rc < 0) {
4681 pr_err("Error in reading die_temp, rc:%d\n", rc);
4682 return rc;
4683 }
4684
4685 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
4686 die_temp / 1000, &time_base);
4687 if (rc < 0) {
4688 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
4689 return rc;
4690 }
4691
4692 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
4693 rc = fg_sram_write(chip,
4694 chip->sp[FG_SRAM_TIMEBASE].addr_word,
4695 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
4696 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
4697 if (rc < 0) {
4698 pr_err("Error in writing timebase, rc=%d\n", rc);
4699 return rc;
4700 }
4701 }
4702
4703 return 0;
4704}
4705
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004706/* INTERRUPT HANDLERS STAY HERE */
4707
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004708static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
4709{
4710 struct fg_chip *chip = data;
4711 u8 status;
4712 int rc;
4713
4714 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
4715 if (rc < 0) {
4716 pr_err("failed to read addr=0x%04x, rc=%d\n",
4717 MEM_IF_INT_RT_STS(chip), rc);
4718 return IRQ_HANDLED;
4719 }
4720
4721 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004722
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07004723 mutex_lock(&chip->sram_rw_lock);
4724 rc = fg_clear_dma_errors_if_any(chip);
4725 if (rc < 0)
4726 pr_err("Error in clearing DMA error, rc=%d\n", rc);
4727
4728 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004729 rc = fg_clear_ima_errors_if_any(chip, true);
4730 if (rc < 0 && rc != -EAGAIN)
4731 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004732 }
4733
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07004734 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07004735 return IRQ_HANDLED;
4736}
4737
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004738static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
4739{
4740 struct fg_chip *chip = data;
4741
4742 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4743 return IRQ_HANDLED;
4744}
4745
4746static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
4747{
4748 struct fg_chip *chip = data;
4749 u8 status;
4750 int rc;
4751
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004752 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
4753 if (rc < 0) {
4754 pr_err("failed to read addr=0x%04x, rc=%d\n",
4755 BATT_INFO_INT_RT_STS(chip), rc);
4756 return IRQ_HANDLED;
4757 }
4758
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004759 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004760 chip->battery_missing = (status & BT_MISS_BIT);
4761
4762 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07004763 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004764 chip->profile_loaded = false;
Subbaraman Narayanamurthy51a81492018-01-19 12:02:30 -08004765 chip->profile_load_status = PROFILE_NOT_LOADED;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08004766 chip->soc_reporting_ready = false;
Fenglin Wu16ef9a72017-11-06 23:24:54 +08004767 chip->batt_id_ohms = -EINVAL;
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07004768 cancel_delayed_work_sync(&chip->pl_enable_work);
4769 vote(chip->pl_disable_votable, ESR_FCC_VOTER, true, 0);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004770 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004771 }
4772
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08004773 clear_battery_profile(chip);
4774 schedule_delayed_work(&chip->profile_load_work, 0);
4775
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304776 if (chip->fg_psy)
4777 power_supply_changed(chip->fg_psy);
4778
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004779 return IRQ_HANDLED;
4780}
4781
4782static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
4783{
4784 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004785 union power_supply_propval prop = {0, };
4786 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004787
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004788 rc = fg_get_battery_temp(chip, &batt_temp);
4789 if (rc < 0) {
4790 pr_err("Error in getting batt_temp\n");
4791 return IRQ_HANDLED;
4792 }
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08004793 fg_dbg(chip, FG_IRQ, "irq %d triggered bat_temp: %d\n", irq, batt_temp);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004794
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08004795 rc = fg_esr_filter_config(chip, batt_temp, false);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004796 if (rc < 0)
4797 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4798
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004799 rc = fg_slope_limit_config(chip, batt_temp);
4800 if (rc < 0)
4801 pr_err("Error in configuring slope limiter rc:%d\n", rc);
4802
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004803 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
4804 if (rc < 0)
4805 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
4806
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004807 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004808 chip->last_batt_temp = batt_temp;
4809 return IRQ_HANDLED;
4810 }
4811
4812 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
4813 &prop);
4814 chip->health = prop.intval;
4815
4816 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304817 rc = fg_adjust_timebase(chip);
4818 if (rc < 0)
4819 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4820
Subbaraman Narayanamurthyfdca8c22017-08-04 12:25:49 -07004821 rc = fg_adjust_recharge_voltage(chip);
4822 if (rc < 0)
4823 pr_err("Error in adjusting recharge_voltage, rc=%d\n",
4824 rc);
4825
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004826 chip->last_batt_temp = batt_temp;
4827 power_supply_changed(chip->batt_psy);
4828 }
4829
4830 if (abs(chip->last_batt_temp - batt_temp) > 30)
4831 pr_warn("Battery temperature last:%d current: %d\n",
4832 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004833 return IRQ_HANDLED;
4834}
4835
4836static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
4837{
4838 struct fg_chip *chip = data;
4839
4840 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4841 complete_all(&chip->soc_ready);
4842 return IRQ_HANDLED;
4843}
4844
4845static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
4846{
4847 struct fg_chip *chip = data;
4848
4849 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4850 complete_all(&chip->soc_update);
4851 return IRQ_HANDLED;
4852}
4853
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004854static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
4855{
4856 struct fg_chip *chip = data;
4857 int rc;
4858
4859 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4860 rc = fg_charge_full_update(chip);
4861 if (rc < 0)
4862 pr_err("Error in charge_full_update, rc=%d\n", rc);
4863
4864 return IRQ_HANDLED;
4865}
4866
4867static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004868{
4869 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004870 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004871
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004872 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthyf9c0b872017-06-09 15:09:11 -07004873 fg_cycle_counter_update(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004874
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004875 if (chip->cl.active)
4876 fg_cap_learning_update(chip);
4877
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004878 rc = fg_charge_full_update(chip);
4879 if (rc < 0)
4880 pr_err("Error in charge_full_update, rc=%d\n", rc);
4881
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004882 rc = fg_adjust_ki_coeff_dischg(chip);
4883 if (rc < 0)
4884 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
4885
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004886 rc = fg_update_maint_soc(chip);
4887 if (rc < 0)
4888 pr_err("Error in updating maint_soc, rc=%d\n", rc);
4889
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004890 rc = fg_esr_validate(chip);
4891 if (rc < 0)
4892 pr_err("Error in validating ESR, rc=%d\n", rc);
4893
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304894 rc = fg_adjust_timebase(chip);
4895 if (rc < 0)
4896 pr_err("Error in adjusting timebase, rc=%d\n", rc);
4897
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004898 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004899 power_supply_changed(chip->batt_psy);
4900
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004901 return IRQ_HANDLED;
4902}
4903
4904static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
4905{
4906 struct fg_chip *chip = data;
4907
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004908 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08004909 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07004910 power_supply_changed(chip->batt_psy);
4911
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004912 return IRQ_HANDLED;
4913}
4914
4915static irqreturn_t fg_soc_irq_handler(int irq, void *data)
4916{
4917 struct fg_chip *chip = data;
4918
4919 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
4920 return IRQ_HANDLED;
4921}
4922
4923static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
4924{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004925 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004926 return IRQ_HANDLED;
4927}
4928
4929static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
4930 /* BATT_SOC irqs */
4931 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004932 .name = "msoc-full",
4933 .handler = fg_soc_irq_handler,
4934 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004935 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004936 .name = "msoc-high",
4937 .handler = fg_soc_irq_handler,
4938 .wakeable = true,
4939 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004940 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004941 .name = "msoc-empty",
4942 .handler = fg_empty_soc_irq_handler,
4943 .wakeable = true,
4944 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004945 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004946 .name = "msoc-low",
4947 .handler = fg_soc_irq_handler,
4948 .wakeable = true,
4949 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004950 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004951 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004952 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004953 .wakeable = true,
4954 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004955 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004956 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004957 .handler = fg_delta_bsoc_irq_handler,
4958 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004959 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004960 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004961 .name = "soc-ready",
4962 .handler = fg_first_est_irq_handler,
4963 .wakeable = true,
4964 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004965 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004966 .name = "soc-update",
4967 .handler = fg_soc_update_irq_handler,
4968 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004969 /* BATT_INFO irqs */
4970 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004971 .name = "batt-temp-delta",
4972 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004973 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004974 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004975 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004976 .name = "batt-missing",
4977 .handler = fg_batt_missing_irq_handler,
4978 .wakeable = true,
4979 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004980 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004981 .name = "esr-delta",
4982 .handler = fg_dummy_irq_handler,
4983 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004984 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004985 .name = "vbatt-low",
4986 .handler = fg_vbatt_low_irq_handler,
4987 .wakeable = true,
4988 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004989 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004990 .name = "vbatt-pred-delta",
4991 .handler = fg_dummy_irq_handler,
4992 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004993 /* MEM_IF irqs */
4994 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07004995 .name = "dma-grant",
Subbaraman Narayanamurthy0d054772017-11-16 18:15:37 -08004996 .handler = fg_dummy_irq_handler,
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07004997 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07004998 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004999 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07005000 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07005001 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07005002 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005003 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07005004 .name = "ima-rdy",
5005 .handler = fg_dummy_irq_handler,
5006 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005007};
5008
5009static int fg_get_irq_index_byname(const char *name)
5010{
5011 int i;
5012
5013 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
5014 if (strcmp(fg_irqs[i].name, name) == 0)
5015 return i;
5016 }
5017
5018 pr_err("%s is not in irq list\n", name);
5019 return -ENOENT;
5020}
5021
5022static int fg_register_interrupts(struct fg_chip *chip)
5023{
5024 struct device_node *child, *node = chip->dev->of_node;
5025 struct property *prop;
5026 const char *name;
5027 int rc, irq, irq_index;
5028
5029 for_each_available_child_of_node(node, child) {
5030 of_property_for_each_string(child, "interrupt-names", prop,
5031 name) {
5032 irq = of_irq_get_byname(child, name);
5033 if (irq < 0) {
5034 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
5035 name, irq);
5036 return irq;
5037 }
5038
5039 irq_index = fg_get_irq_index_byname(name);
5040 if (irq_index < 0)
5041 return irq_index;
5042
5043 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
5044 fg_irqs[irq_index].handler,
5045 IRQF_ONESHOT, name, chip);
5046 if (rc < 0) {
5047 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
5048 name, rc);
5049 return rc;
5050 }
5051
5052 fg_irqs[irq_index].irq = irq;
5053 if (fg_irqs[irq_index].wakeable)
5054 enable_irq_wake(fg_irqs[irq_index].irq);
5055 }
5056 }
5057
5058 return 0;
5059}
5060
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005061static int fg_parse_dt_property_u32_array(struct device_node *node,
5062 const char *prop_name, int *buf, int len)
5063{
5064 int rc;
5065
5066 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
5067 if (rc < 0) {
5068 if (rc == -EINVAL)
5069 return 0;
5070 else
5071 return rc;
5072 } else if (rc != len) {
5073 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
5074 rc);
5075 return -EINVAL;
5076 }
5077
5078 rc = of_property_read_u32_array(node, prop_name, buf, len);
5079 if (rc < 0) {
5080 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
5081 return rc;
5082 }
5083
5084 return 0;
5085}
5086
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08005087static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
5088{
5089 struct device_node *node = chip->dev->of_node;
5090 int rc, i;
5091
5092 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
5093 &chip->dt.slope_limit_temp);
5094 if (rc < 0)
5095 return 0;
5096
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005097 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
5098 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
5099 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08005100 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08005101
5102 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
5103 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
5104 chip->dt.slope_limit_coeffs[i] < 0) {
5105 pr_err("Incorrect slope limit coefficient\n");
5106 return -EINVAL;
5107 }
5108 }
5109
5110 chip->slope_limit_en = true;
5111 return 0;
5112}
5113
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005114static int fg_parse_ki_coefficients(struct fg_chip *chip)
5115{
5116 struct device_node *node = chip->dev->of_node;
Subbaraman Narayanamurthye17be582017-08-08 19:28:37 -07005117 int rc, i, temp;
5118
5119 rc = of_property_read_u32(node, "qcom,ki-coeff-full-dischg", &temp);
5120 if (!rc)
5121 chip->dt.ki_coeff_full_soc_dischg = temp;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005122
Subbaraman Narayanamurthy13103202018-03-19 12:16:36 -07005123 chip->dt.ki_coeff_hi_chg = -EINVAL;
5124 rc = of_property_read_u32(node, "qcom,ki-coeff-hi-chg", &temp);
5125 if (!rc)
5126 chip->dt.ki_coeff_hi_chg = temp;
5127
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07005128 if (!of_find_property(node, "qcom,ki-coeff-soc-dischg", NULL) ||
5129 (!of_find_property(node, "qcom,ki-coeff-low-dischg", NULL) &&
5130 !of_find_property(node, "qcom,ki-coeff-med-dischg", NULL) &&
5131 !of_find_property(node, "qcom,ki-coeff-hi-dischg", NULL)))
5132 return 0;
Subbaraman Narayanamurthy13103202018-03-19 12:16:36 -07005133
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005134 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
5135 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
5136 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005137 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005138
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07005139 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-low-dischg",
5140 chip->dt.ki_coeff_low_dischg, KI_COEFF_SOC_LEVELS);
5141 if (rc < 0)
5142 return rc;
5143
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005144 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
5145 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
5146 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005147 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005148
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005149 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
5150 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
5151 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005152 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005153
5154 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
5155 if (chip->dt.ki_coeff_soc[i] < 0 ||
5156 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
5157 pr_err("Error in ki_coeff_soc_dischg values\n");
5158 return -EINVAL;
5159 }
5160
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07005161 if (chip->dt.ki_coeff_low_dischg[i] < 0 ||
5162 chip->dt.ki_coeff_low_dischg[i] > KI_COEFF_MAX) {
5163 pr_err("Error in ki_coeff_low_dischg values\n");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005164 return -EINVAL;
5165 }
5166
5167 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
5168 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
5169 pr_err("Error in ki_coeff_med_dischg values\n");
5170 return -EINVAL;
5171 }
Subbaraman Narayanamurthydb5f1662018-04-04 19:47:30 -07005172
5173 if (chip->dt.ki_coeff_hi_dischg[i] < 0 ||
5174 chip->dt.ki_coeff_hi_dischg[i] > KI_COEFF_MAX) {
5175 pr_err("Error in ki_coeff_hi_dischg values\n");
5176 return -EINVAL;
5177 }
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005178 }
5179 chip->ki_coeff_dischg_en = true;
5180 return 0;
5181}
5182
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005183#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07005184#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08005185#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005186#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07005187#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07005188#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy5566f502017-12-19 19:39:03 -08005189#define DEFAULT_CUTOFF_CURR_MA 500
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005190#define DEFAULT_DELTA_SOC_THR 1
5191#define DEFAULT_RECHARGE_SOC_THR 95
5192#define DEFAULT_BATT_TEMP_COLD 0
5193#define DEFAULT_BATT_TEMP_COOL 5
5194#define DEFAULT_BATT_TEMP_WARM 45
5195#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07005196#define DEFAULT_CL_START_SOC 15
5197#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
Subbaraman Narayanamurthya01aac92017-10-11 14:05:11 -07005198#define DEFAULT_CL_MAX_TEMP_DECIDEGC 500
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07005199#define DEFAULT_CL_MAX_INC_DECIPERC 5
5200#define DEFAULT_CL_MAX_DEC_DECIPERC 100
5201#define DEFAULT_CL_MIN_LIM_DECIPERC 0
5202#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07005203#define BTEMP_DELTA_LOW 2
5204#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005205#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
5206#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
5207#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
Subbaraman Narayanamurthy5feefbb2017-12-07 19:12:27 -08005208#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 30000
5209#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 30000
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08005210#define DEFAULT_ESR_FLT_RT_DECIDEGC 60
5211#define DEFAULT_ESR_TIGHT_RT_FLT_UPCT 5860
5212#define DEFAULT_ESR_BROAD_RT_FLT_UPCT 156250
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08005213#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07005214#define DEFAULT_ESR_PULSE_THRESH_MA 110
5215#define DEFAULT_ESR_MEAS_CURR_MA 120
Fenglin Wud10ccf12017-08-10 15:43:41 +08005216#define DEFAULT_BMD_EN_DELAY_MS 200
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005217static int fg_parse_dt(struct fg_chip *chip)
5218{
5219 struct device_node *child, *revid_node, *node = chip->dev->of_node;
5220 u32 base, temp;
5221 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07005222 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005223
5224 if (!node) {
5225 dev_err(chip->dev, "device tree node missing\n");
5226 return -ENXIO;
5227 }
5228
5229 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
5230 if (!revid_node) {
5231 pr_err("Missing qcom,pmic-revid property - driver failed\n");
5232 return -EINVAL;
5233 }
5234
5235 chip->pmic_rev_id = get_revid_data(revid_node);
5236 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
5237 pr_err("Unable to get pmic_revid rc=%ld\n",
5238 PTR_ERR(chip->pmic_rev_id));
5239 /*
5240 * the revid peripheral must be registered, any failure
5241 * here only indicates that the rev-id module has not
5242 * probed yet.
5243 */
5244 return -EPROBE_DEFER;
5245 }
5246
5247 pr_debug("PMIC subtype %d Digital major %d\n",
5248 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
5249
5250 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08005251 case PMI8998_SUBTYPE:
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07005252 chip->use_dma = true;
Harry Yang2452b272017-03-06 13:56:14 -08005253 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
5254 chip->sp = pmi8998_v1_sram_params;
5255 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05305256 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08005257 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
5258 chip->sp = pmi8998_v2_sram_params;
5259 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07005260 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005261 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07005262 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005263 break;
Harry Yange4e731b2017-03-06 14:35:09 -08005264 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05305265 chip->sp = pmi8998_v2_sram_params;
5266 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07005267 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05305268 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
5269 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05305270 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005271 default:
5272 return -EINVAL;
5273 }
5274
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005275 if (of_get_available_child_count(node) == 0) {
5276 dev_err(chip->dev, "No child nodes specified!\n");
5277 return -ENXIO;
5278 }
5279
5280 for_each_available_child_of_node(node, child) {
5281 rc = of_property_read_u32(child, "reg", &base);
5282 if (rc < 0) {
5283 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
5284 child->full_name, rc);
5285 return rc;
5286 }
5287
5288 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
5289 if (rc < 0) {
5290 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
5291 base, rc);
5292 return rc;
5293 }
5294
5295 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08005296 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005297 chip->batt_soc_base = base;
5298 break;
Harry Yang2452b272017-03-06 13:56:14 -08005299 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005300 chip->batt_info_base = base;
5301 break;
Harry Yang2452b272017-03-06 13:56:14 -08005302 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005303 chip->mem_if_base = base;
5304 break;
5305 default:
5306 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
5307 subtype);
5308 return -ENXIO;
5309 }
5310 }
5311
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08005312 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
5313 if (rc < 0) {
5314 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
5315 return rc;
5316 }
5317 chip->rradc_base = base;
5318
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005319 /* Read all the optional properties below */
5320 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
5321 if (rc < 0)
5322 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
5323 else
5324 chip->dt.cutoff_volt_mv = temp;
5325
5326 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
5327 if (rc < 0)
5328 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
5329 else
5330 chip->dt.empty_volt_mv = temp;
5331
5332 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
5333 if (rc < 0)
5334 chip->dt.vbatt_low_thr_mv = -EINVAL;
5335 else
5336 chip->dt.vbatt_low_thr_mv = temp;
5337
5338 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
5339 if (rc < 0)
5340 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
5341 else
5342 chip->dt.chg_term_curr_ma = temp;
5343
5344 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
5345 if (rc < 0)
5346 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
5347 else
5348 chip->dt.sys_term_curr_ma = temp;
5349
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07005350 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
5351 if (rc < 0)
5352 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
5353 else
5354 chip->dt.chg_term_base_curr_ma = temp;
5355
Subbaraman Narayanamurthy5566f502017-12-19 19:39:03 -08005356 rc = of_property_read_u32(node, "qcom,fg-cutoff-current", &temp);
5357 if (rc < 0)
5358 chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA;
5359 else
5360 chip->dt.cutoff_curr_ma = temp;
5361
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005362 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
5363 if (rc < 0)
5364 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
5365 else
5366 chip->dt.delta_soc_thr = temp;
5367
5368 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
5369 if (rc < 0)
5370 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
5371 else
5372 chip->dt.recharge_soc_thr = temp;
5373
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08005374 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
5375 if (rc < 0)
5376 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
5377 else
5378 chip->dt.recharge_volt_thr_mv = temp;
5379
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08005380 chip->dt.auto_recharge_soc = of_property_read_bool(node,
5381 "qcom,fg-auto-recharge-soc");
5382
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005383 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
5384 if (rc < 0)
5385 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
5386 else
5387 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
5388
5389 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
5390 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
5391 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
5392 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07005393 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
5394 sizeof(u32)) == NUM_JEITA_LEVELS) {
5395 rc = of_property_read_u32_array(node,
5396 "qcom,fg-jeita-thresholds",
5397 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
5398 if (rc < 0)
5399 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
5400 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005401 }
5402
cyizhaofb3eec52017-01-24 17:08:55 +08005403 if (of_property_count_elems_of_size(node,
5404 "qcom,battery-thermal-coefficients",
5405 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
5406 rc = of_property_read_u8_array(node,
5407 "qcom,battery-thermal-coefficients",
5408 chip->dt.batt_therm_coeffs,
5409 BATT_THERM_NUM_COEFFS);
5410 if (rc < 0)
5411 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
5412 rc);
5413 }
5414
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005415 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
5416 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
5417 if (rc < 0) {
5418 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
5419 chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
5420 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005421
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005422 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
5423 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
5424 if (rc < 0) {
5425 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
5426 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
5427 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005428
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005429 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
5430 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
5431 if (rc < 0) {
5432 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
5433 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
5434 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005435
Anirudh Ghayal09d088f2018-08-08 10:08:54 +05305436 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-shutdown",
5437 chip->dt.esr_timer_shutdown, NUM_ESR_TIMERS);
5438 if (rc < 0) {
5439 chip->dt.esr_timer_shutdown[TIMER_RETRY] = -EINVAL;
5440 chip->dt.esr_timer_shutdown[TIMER_MAX] = -EINVAL;
5441 }
5442
Nicholas Troaste29dec92016-08-24 09:35:11 -07005443 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005444
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07005445 chip->dt.force_load_profile = of_property_read_bool(node,
5446 "qcom,fg-force-load-profile");
5447
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07005448 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
5449 if (rc < 0)
5450 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
5451 else
5452 chip->dt.cl_start_soc = temp;
5453
5454 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
5455 if (rc < 0)
5456 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
5457 else
5458 chip->dt.cl_min_temp = temp;
5459
5460 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
5461 if (rc < 0)
5462 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
5463 else
5464 chip->dt.cl_max_temp = temp;
5465
5466 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
5467 if (rc < 0)
5468 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
5469 else
5470 chip->dt.cl_max_cap_inc = temp;
5471
5472 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
5473 if (rc < 0)
5474 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
5475 else
5476 chip->dt.cl_max_cap_dec = temp;
5477
5478 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
5479 if (rc < 0)
5480 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
5481 else
5482 chip->dt.cl_min_cap_limit = temp;
5483
5484 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
5485 if (rc < 0)
5486 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
5487 else
5488 chip->dt.cl_max_cap_limit = temp;
5489
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07005490 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
5491 if (rc < 0)
5492 chip->dt.jeita_hyst_temp = -EINVAL;
5493 else
5494 chip->dt.jeita_hyst_temp = temp;
5495
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07005496 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
5497 if (rc < 0)
5498 chip->dt.batt_temp_delta = -EINVAL;
5499 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
5500 chip->dt.batt_temp_delta = temp;
5501
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07005502 chip->dt.hold_soc_while_full = of_property_read_bool(node,
5503 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005504
Subbaraman Narayanamurthy50fb7fd2017-07-25 20:01:25 -07005505 chip->dt.linearize_soc = of_property_read_bool(node,
5506 "qcom,linearize-soc");
5507
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07005508 rc = fg_parse_ki_coefficients(chip);
5509 if (rc < 0)
5510 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
5511
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08005512 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07005513 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08005514 chip->dt.rconn_mohms = temp;
5515
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005516 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
5517 &temp);
5518 if (rc < 0)
5519 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
5520 else
5521 chip->dt.esr_flt_switch_temp = temp;
5522
5523 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
5524 &temp);
5525 if (rc < 0)
5526 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
5527 else
5528 chip->dt.esr_tight_flt_upct = temp;
5529
5530 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
5531 &temp);
5532 if (rc < 0)
5533 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
5534 else
5535 chip->dt.esr_broad_flt_upct = temp;
5536
5537 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
5538 &temp);
5539 if (rc < 0)
5540 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
5541 else
5542 chip->dt.esr_tight_lt_flt_upct = temp;
5543
5544 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
5545 &temp);
5546 if (rc < 0)
5547 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
5548 else
5549 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08005550
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08005551 rc = of_property_read_u32(node, "qcom,fg-esr-rt-filter-switch-temp",
5552 &temp);
5553 if (rc < 0)
5554 chip->dt.esr_flt_rt_switch_temp = DEFAULT_ESR_FLT_RT_DECIDEGC;
5555 else
5556 chip->dt.esr_flt_rt_switch_temp = temp;
5557
5558 rc = of_property_read_u32(node, "qcom,fg-esr-tight-rt-filter-micro-pct",
5559 &temp);
5560 if (rc < 0)
5561 chip->dt.esr_tight_rt_flt_upct = DEFAULT_ESR_TIGHT_RT_FLT_UPCT;
5562 else
5563 chip->dt.esr_tight_rt_flt_upct = temp;
5564
5565 rc = of_property_read_u32(node, "qcom,fg-esr-broad-rt-filter-micro-pct",
5566 &temp);
5567 if (rc < 0)
5568 chip->dt.esr_broad_rt_flt_upct = DEFAULT_ESR_BROAD_RT_FLT_UPCT;
5569 else
5570 chip->dt.esr_broad_rt_flt_upct = temp;
5571
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08005572 rc = fg_parse_slope_limit_coefficients(chip);
5573 if (rc < 0)
5574 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
5575
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08005576 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
5577 if (rc < 0)
5578 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
5579 else
5580 chip->dt.esr_clamp_mohms = temp;
5581
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07005582 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
5583 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
5584 if (!rc) {
5585 /* ESR pulse qualification threshold range is 1-997 mA */
5586 if (temp > 0 && temp < 997)
5587 chip->dt.esr_pulse_thresh_ma = temp;
5588 }
5589
5590 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
5591 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
5592 if (!rc) {
5593 /* ESR measurement current range is 60-240 mA */
5594 if (temp >= 60 || temp <= 240)
5595 chip->dt.esr_meas_curr_ma = temp;
5596 }
5597
Fenglin Wud10ccf12017-08-10 15:43:41 +08005598 chip->dt.bmd_en_delay_ms = DEFAULT_BMD_EN_DELAY_MS;
5599 rc = of_property_read_u32(node, "qcom,fg-bmd-en-delay-ms", &temp);
5600 if (!rc) {
5601 if (temp > DEFAULT_BMD_EN_DELAY_MS)
5602 chip->dt.bmd_en_delay_ms = temp;
5603 }
5604
Anirudh Ghayalbcb85772018-08-08 10:17:25 +05305605 chip->dt.sync_sleep_threshold_ma = -EINVAL;
5606 rc = of_property_read_u32(node,
5607 "qcom,fg-sync-sleep-threshold-ma", &temp);
5608 if (!rc) {
5609 if (temp >= 0 && temp < 997)
5610 chip->dt.sync_sleep_threshold_ma = temp;
5611 }
5612
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05305613 chip->dt.use_esr_sw = of_property_read_bool(node, "qcom,fg-use-sw-esr");
5614
Anirudh Ghayale149f562018-08-03 16:34:56 +05305615 chip->dt.disable_esr_pull_dn = of_property_read_bool(node,
5616 "qcom,fg-disable-esr-pull-dn");
5617
Anirudh Ghayala209ac32018-08-23 15:08:05 +05305618 chip->dt.disable_fg_twm = of_property_read_bool(node,
5619 "qcom,fg-disable-in-twm");
5620
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005621 return 0;
5622}
5623
5624static void fg_cleanup(struct fg_chip *chip)
5625{
Subbaraman Narayanamurthyf580cb92017-08-30 20:27:41 -07005626 int i;
5627
Sahil Chandna2582140f2018-10-10 14:26:52 +05305628 power_supply_unreg_notifier(&chip->nb);
5629 qpnp_misc_twm_notifier_unregister(&chip->twm_nb);
5630 cancel_delayed_work_sync(&chip->ttf_work);
5631 cancel_delayed_work_sync(&chip->sram_dump_work);
5632 if (chip->dt.use_esr_sw)
5633 alarm_cancel(&chip->esr_sw_timer);
5634 cancel_work_sync(&chip->esr_sw_work);
5635 cancel_delayed_work_sync(&chip->profile_load_work);
5636 cancel_work_sync(&chip->status_change_work);
5637 cancel_work_sync(&chip->esr_filter_work);
5638 cancel_delayed_work_sync(&chip->pl_enable_work);
5639
Subbaraman Narayanamurthyf580cb92017-08-30 20:27:41 -07005640 for (i = 0; i < FG_IRQ_MAX; i++) {
5641 if (fg_irqs[i].irq)
5642 devm_free_irq(chip->dev, fg_irqs[i].irq, chip);
5643 }
5644
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08005645 alarm_try_to_cancel(&chip->esr_filter_alarm);
Nicholas Troast69da2252016-09-07 16:17:47 -07005646 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005647 if (chip->awake_votable)
5648 destroy_votable(chip->awake_votable);
5649
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005650 if (chip->delta_bsoc_irq_en_votable)
5651 destroy_votable(chip->delta_bsoc_irq_en_votable);
5652
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005653 if (chip->batt_miss_irq_en_votable)
5654 destroy_votable(chip->batt_miss_irq_en_votable);
5655
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005656 if (chip->batt_id_chan)
5657 iio_channel_release(chip->batt_id_chan);
5658
5659 dev_set_drvdata(chip->dev, NULL);
5660}
5661
Subbaraman Narayanamurthy8a191dc2017-08-18 18:37:01 -07005662static int fg_tz_get_temp(void *data, int *temperature)
5663{
5664 struct fg_chip *chip = (struct fg_chip *)data;
5665 int rc, batt_temp = 0;
5666
5667 if (!temperature)
5668 return -EINVAL;
5669
5670 rc = fg_get_battery_temp(chip, &batt_temp);
5671 if (rc < 0) {
5672 pr_err("Error in getting batt_temp\n");
5673 return rc;
5674 }
5675
5676 /* Convert deciDegC to milliDegC */
5677 *temperature = batt_temp * 100;
5678 return 0;
5679}
5680
5681static struct thermal_zone_of_device_ops fg_gen3_tz_ops = {
5682 .get_temp = fg_tz_get_temp,
5683};
5684
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005685static int fg_gen3_probe(struct platform_device *pdev)
5686{
5687 struct fg_chip *chip;
5688 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005689 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005690
5691 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
5692 if (!chip)
5693 return -ENOMEM;
5694
5695 chip->dev = &pdev->dev;
5696 chip->debug_mask = &fg_gen3_debug_mask;
5697 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07005698 chip->charge_status = -EINVAL;
Subbaraman Narayanamurthyef69cf22017-09-13 16:38:40 -07005699 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07005700 chip->ki_coeff_full_soc = -EINVAL;
Nicholas Troast805c2422017-07-06 14:53:46 -07005701 chip->online_status = -EINVAL;
Fenglin Wu16ef9a72017-11-06 23:24:54 +08005702 chip->batt_id_ohms = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005703 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
5704 if (!chip->regmap) {
5705 dev_err(chip->dev, "Parent regmap is unavailable\n");
5706 return -ENXIO;
5707 }
5708
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08005709 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
5710 if (IS_ERR(chip->batt_id_chan)) {
5711 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
5712 pr_err("batt_id_chan unavailable %ld\n",
5713 PTR_ERR(chip->batt_id_chan));
5714 rc = PTR_ERR(chip->batt_id_chan);
5715 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005716 return rc;
5717 }
5718
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05305719 rc = of_property_match_string(chip->dev->of_node,
5720 "io-channel-names", "rradc_die_temp");
5721 if (rc >= 0) {
5722 chip->die_temp_chan = iio_channel_get(chip->dev,
5723 "rradc_die_temp");
5724 if (IS_ERR(chip->die_temp_chan)) {
5725 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
5726 pr_err("rradc_die_temp unavailable %ld\n",
5727 PTR_ERR(chip->die_temp_chan));
5728 rc = PTR_ERR(chip->die_temp_chan);
5729 chip->die_temp_chan = NULL;
5730 return rc;
5731 }
5732 }
5733
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07005734 chip->pl_disable_votable = find_votable("PL_DISABLE");
5735 if (chip->pl_disable_votable == NULL) {
5736 rc = -EPROBE_DEFER;
5737 goto exit;
5738 }
5739
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005740 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
5741 chip);
5742 if (IS_ERR(chip->awake_votable)) {
5743 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005744 chip->awake_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005745 goto exit;
5746 }
5747
5748 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
5749 VOTE_SET_ANY,
5750 fg_delta_bsoc_irq_en_cb, chip);
5751 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
5752 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005753 chip->delta_bsoc_irq_en_votable = NULL;
5754 goto exit;
5755 }
5756
5757 chip->batt_miss_irq_en_votable = create_votable("FG_BATT_MISS_IRQ",
5758 VOTE_SET_ANY,
5759 fg_batt_miss_irq_en_cb, chip);
5760 if (IS_ERR(chip->batt_miss_irq_en_votable)) {
5761 rc = PTR_ERR(chip->batt_miss_irq_en_votable);
5762 chip->batt_miss_irq_en_votable = NULL;
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07005763 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005764 }
5765
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08005766 rc = fg_parse_dt(chip);
5767 if (rc < 0) {
5768 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
5769 rc);
5770 goto exit;
5771 }
5772
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005773 mutex_init(&chip->bus_lock);
5774 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07005775 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07005776 mutex_init(&chip->cl.lock);
Nicholas Troast805c2422017-07-06 14:53:46 -07005777 mutex_init(&chip->ttf.lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08005778 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy3fbcbe92017-09-12 20:19:17 -07005779 mutex_init(&chip->qnovo_esr_ctrl_lock);
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05305780 spin_lock_init(&chip->awake_lock);
Anirudh Ghayal65788312017-10-18 11:36:22 +05305781 spin_lock_init(&chip->suspend_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005782 init_completion(&chip->soc_update);
5783 init_completion(&chip->soc_ready);
5784 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
Subbaraman Narayanamurthyf40b7a42017-11-01 17:35:00 -07005785 INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005786 INIT_WORK(&chip->status_change_work, status_change_work);
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05305787 INIT_WORK(&chip->esr_sw_work, fg_esr_sw_work);
Nicholas Troast805c2422017-07-06 14:53:46 -07005788 INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005789 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08005790 INIT_WORK(&chip->esr_filter_work, esr_filter_work);
5791 alarm_init(&chip->esr_filter_alarm, ALARM_BOOTTIME,
5792 fg_esr_filter_alarm_cb);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005793
5794 rc = fg_memif_init(chip);
5795 if (rc < 0) {
5796 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
5797 rc);
5798 goto exit;
5799 }
5800
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -07005801 platform_set_drvdata(pdev, chip);
5802
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005803 rc = fg_hw_init(chip);
5804 if (rc < 0) {
5805 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
5806 rc);
5807 goto exit;
5808 }
5809
Anirudh Ghayal63e9cea2018-06-11 16:15:11 +05305810 if (chip->dt.use_esr_sw) {
5811 if (alarmtimer_get_rtcdev()) {
5812 alarm_init(&chip->esr_sw_timer, ALARM_BOOTTIME,
5813 fg_esr_sw_timer);
5814 } else {
5815 pr_err("Failed to get esw_sw alarm-timer\n");
5816 /* RTC always registers, hence defer until it passes */
5817 rc = -EPROBE_DEFER;
5818 goto exit;
5819 }
5820 if (chip->dt.esr_timer_charging[TIMER_MAX] != -EINVAL)
5821 chip->esr_wakeup_ms =
5822 chip->dt.esr_timer_charging[TIMER_MAX] * 1460;
5823 else
5824 chip->esr_wakeup_ms = 140000; /* 140 seconds */
5825 }
5826
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005827 /* Register the power supply */
5828 fg_psy_cfg.drv_data = chip;
5829 fg_psy_cfg.of_node = NULL;
5830 fg_psy_cfg.supplied_to = NULL;
5831 fg_psy_cfg.num_supplicants = 0;
5832 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
5833 &fg_psy_cfg);
5834 if (IS_ERR(chip->fg_psy)) {
5835 pr_err("failed to register fg_psy rc = %ld\n",
5836 PTR_ERR(chip->fg_psy));
5837 goto exit;
5838 }
5839
5840 chip->nb.notifier_call = fg_notifier_cb;
5841 rc = power_supply_reg_notifier(&chip->nb);
5842 if (rc < 0) {
5843 pr_err("Couldn't register psy notifier rc = %d\n", rc);
5844 goto exit;
5845 }
5846
Anirudh Ghayala209ac32018-08-23 15:08:05 +05305847 chip->twm_nb.notifier_call = twm_notifier_cb;
5848 rc = qpnp_misc_twm_notifier_register(&chip->twm_nb);
5849 if (rc < 0)
5850 pr_err("Failed to register twm_notifier_cb rc=%d\n", rc);
5851
Subbaraman Narayanamurthy0d054772017-11-16 18:15:37 -08005852 rc = fg_register_interrupts(chip);
5853 if (rc < 0) {
5854 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
5855 rc);
5856 goto exit;
5857 }
5858
5859 /* Keep SOC_UPDATE irq disabled until we require it */
5860 if (fg_irqs[SOC_UPDATE_IRQ].irq)
5861 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
5862
5863 /* Keep BSOC_DELTA_IRQ disabled until we require it */
5864 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);
5865
5866 /* Keep BATT_MISSING_IRQ disabled until we require it */
5867 vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);
5868
Nicholas Troast69da2252016-09-07 16:17:47 -07005869 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005870 if (rc < 0) {
5871 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
5872 rc);
5873 goto exit;
5874 }
5875
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005876 rc = fg_get_battery_voltage(chip, &volt_uv);
5877 if (!rc)
5878 rc = fg_get_prop_capacity(chip, &msoc);
5879
5880 if (!rc)
5881 rc = fg_get_battery_temp(chip, &batt_temp);
5882
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005883 if (!rc) {
Fenglin Wu16ef9a72017-11-06 23:24:54 +08005884 pr_info("battery SOC:%d voltage: %duV temp: %d\n",
5885 msoc, volt_uv, batt_temp);
Subbaraman Narayanamurthy11c772d2017-12-01 10:54:40 -08005886 rc = fg_esr_filter_config(chip, batt_temp, false);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08005887 if (rc < 0)
5888 pr_err("Error in configuring ESR filter rc:%d\n", rc);
5889 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005890
Subbaraman Narayanamurthy8a191dc2017-08-18 18:37:01 -07005891 chip->tz_dev = thermal_zone_of_sensor_register(chip->dev, 0, chip,
5892 &fg_gen3_tz_ops);
5893 if (IS_ERR_OR_NULL(chip->tz_dev)) {
5894 rc = PTR_ERR(chip->tz_dev);
5895 chip->tz_dev = NULL;
5896 dev_err(chip->dev, "thermal_zone_of_sensor_register() failed rc:%d\n",
5897 rc);
5898 }
5899
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005900 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthyecc06022017-04-04 16:10:35 -07005901 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005902
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08005903 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005904 return 0;
5905exit:
5906 fg_cleanup(chip);
5907 return rc;
5908}
5909
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005910static int fg_gen3_suspend(struct device *dev)
5911{
5912 struct fg_chip *chip = dev_get_drvdata(dev);
5913 int rc;
5914
Anirudh Ghayal65788312017-10-18 11:36:22 +05305915 spin_lock(&chip->suspend_lock);
5916 chip->suspended = true;
5917 spin_unlock(&chip->suspend_lock);
5918
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005919 rc = fg_esr_timer_config(chip, true);
5920 if (rc < 0)
5921 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005922
Nicholas Troast805c2422017-07-06 14:53:46 -07005923 cancel_delayed_work_sync(&chip->ttf_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005924 if (fg_sram_dump)
5925 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005926 return 0;
5927}
5928
5929static int fg_gen3_resume(struct device *dev)
5930{
5931 struct fg_chip *chip = dev_get_drvdata(dev);
5932 int rc;
5933
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07005934 rc = fg_esr_timer_config(chip, false);
5935 if (rc < 0)
5936 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005937
Nicholas Troast805c2422017-07-06 14:53:46 -07005938 schedule_delayed_work(&chip->ttf_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08005939 if (fg_sram_dump)
5940 schedule_delayed_work(&chip->sram_dump_work,
5941 msecs_to_jiffies(fg_sram_dump_period_ms));
Anirudh Ghayal65788312017-10-18 11:36:22 +05305942
5943 if (!work_pending(&chip->status_change_work)) {
5944 pm_stay_awake(chip->dev);
5945 schedule_work(&chip->status_change_work);
5946 }
5947
5948 spin_lock(&chip->suspend_lock);
5949 chip->suspended = false;
5950 spin_unlock(&chip->suspend_lock);
5951
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07005952 return 0;
5953}
5954
5955static const struct dev_pm_ops fg_gen3_pm_ops = {
5956 .suspend = fg_gen3_suspend,
5957 .resume = fg_gen3_resume,
5958};
5959
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005960static int fg_gen3_remove(struct platform_device *pdev)
5961{
5962 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
5963
Subbaraman Narayanamurthy8a191dc2017-08-18 18:37:01 -07005964 if (chip->tz_dev)
5965 thermal_zone_of_sensor_unregister(chip->dev, chip->tz_dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07005966 fg_cleanup(chip);
5967 return 0;
5968}
5969
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07005970static void fg_gen3_shutdown(struct platform_device *pdev)
5971{
5972 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
5973 int rc, bsoc;
Anirudh Ghayala209ac32018-08-23 15:08:05 +05305974 u8 mask;
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07005975
5976 if (chip->charge_full) {
5977 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
5978 if (rc < 0) {
5979 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
5980 return;
5981 }
5982
5983 /* We need 2 most significant bytes here */
5984 bsoc = (u32)bsoc >> 16;
5985
5986 rc = fg_configure_full_soc(chip, bsoc);
5987 if (rc < 0) {
5988 pr_err("Error in configuring full_soc, rc=%d\n", rc);
5989 return;
5990 }
5991 }
Anirudh Ghayal09d088f2018-08-08 10:08:54 +05305992 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_shutdown[TIMER_RETRY],
5993 chip->dt.esr_timer_shutdown[TIMER_MAX], false,
5994 FG_IMA_NO_WLOCK);
5995 if (rc < 0)
5996 pr_err("Error in setting ESR timer at shutdown, rc=%d\n", rc);
5997
Anirudh Ghayala209ac32018-08-23 15:08:05 +05305998 if (chip->twm_state == PMIC_TWM_ENABLE && chip->dt.disable_fg_twm) {
5999 rc = fg_masked_write(chip, BATT_SOC_EN_CTL(chip),
6000 FG_ALGORITHM_EN_BIT, 0);
6001 if (rc < 0)
6002 pr_err("Error in disabling FG rc=%d\n", rc);
6003
6004 mask = BCL_RST_BIT | MEM_RST_BIT | ALG_RST_BIT;
6005 rc = fg_masked_write(chip, BATT_SOC_RST_CTRL0(chip),
6006 mask, mask);
6007 if (rc < 0)
6008 pr_err("Error in disabling FG resets rc=%d\n", rc);
6009 }
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07006010}
6011
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07006012static const struct of_device_id fg_gen3_match_table[] = {
6013 {.compatible = FG_GEN3_DEV_NAME},
6014 {},
6015};
6016
6017static struct platform_driver fg_gen3_driver = {
6018 .driver = {
6019 .name = FG_GEN3_DEV_NAME,
6020 .owner = THIS_MODULE,
6021 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07006022 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07006023 },
6024 .probe = fg_gen3_probe,
6025 .remove = fg_gen3_remove,
Subbaraman Narayanamurthy9b6c38a2017-07-26 16:46:41 -07006026 .shutdown = fg_gen3_shutdown,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07006027};
6028
6029static int __init fg_gen3_init(void)
6030{
6031 return platform_driver_register(&fg_gen3_driver);
6032}
6033
6034static void __exit fg_gen3_exit(void)
6035{
6036 return platform_driver_unregister(&fg_gen3_driver);
6037}
6038
6039module_init(fg_gen3_init);
6040module_exit(fg_gen3_exit);
6041
6042MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
6043MODULE_LICENSE("GPL v2");
6044MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);