blob: a5c9dcec600ab554c17546e554a2efca8645910f [file] [log] [blame]
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "FG: %s: " fmt, __func__
14
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -080015#include <linux/ktime.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070016#include <linux/of.h>
17#include <linux/of_irq.h>
18#include <linux/of_platform.h>
19#include <linux/of_batterydata.h>
20#include <linux/platform_device.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070021#include <linux/iio/consumer.h>
22#include <linux/qpnp/qpnp-revid.h>
23#include "fg-core.h"
24#include "fg-reg.h"
25
26#define FG_GEN3_DEV_NAME "qcom,fg-gen3"
27
28#define PERPH_SUBTYPE_REG 0x05
Harry Yang2452b272017-03-06 13:56:14 -080029#define FG_BATT_SOC_PMI8998 0x10
30#define FG_BATT_INFO_PMI8998 0x11
31#define FG_MEM_INFO_PMI8998 0x0D
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070032
33/* SRAM address and offset in ascending order */
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -070034#define ESR_PULSE_THRESH_WORD 2
35#define ESR_PULSE_THRESH_OFFSET 3
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -080036#define SLOPE_LIMIT_WORD 3
37#define SLOPE_LIMIT_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070038#define CUTOFF_VOLT_WORD 5
39#define CUTOFF_VOLT_OFFSET 0
40#define SYS_TERM_CURR_WORD 6
41#define SYS_TERM_CURR_OFFSET 0
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -070042#define VBATT_FULL_WORD 7
43#define VBATT_FULL_OFFSET 0
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -080044#define ESR_FILTER_WORD 8
45#define ESR_UPD_TIGHT_OFFSET 0
46#define ESR_UPD_BROAD_OFFSET 1
47#define ESR_UPD_TIGHT_LOW_TEMP_OFFSET 2
48#define ESR_UPD_BROAD_LOW_TEMP_OFFSET 3
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -070049#define KI_COEFF_MED_DISCHG_WORD 9
Anirudh Ghayalddabeee2017-04-04 06:13:48 +053050#define TIMEBASE_OFFSET 1
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -070051#define KI_COEFF_MED_DISCHG_OFFSET 3
52#define KI_COEFF_HI_DISCHG_WORD 10
53#define KI_COEFF_HI_DISCHG_OFFSET 0
54#define KI_COEFF_LOW_DISCHG_WORD 10
55#define KI_COEFF_LOW_DISCHG_OFFSET 2
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -070056#define KI_COEFF_FULL_SOC_WORD 12
57#define KI_COEFF_FULL_SOC_OFFSET 2
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -080058#define DELTA_MSOC_THR_WORD 12
59#define DELTA_MSOC_THR_OFFSET 3
60#define DELTA_BSOC_THR_WORD 13
61#define DELTA_BSOC_THR_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070062#define RECHARGE_SOC_THR_WORD 14
63#define RECHARGE_SOC_THR_OFFSET 0
64#define CHG_TERM_CURR_WORD 14
65#define CHG_TERM_CURR_OFFSET 1
66#define EMPTY_VOLT_WORD 15
67#define EMPTY_VOLT_OFFSET 0
68#define VBATT_LOW_WORD 15
69#define VBATT_LOW_OFFSET 1
Nicholas Troastdcf8fe62016-08-04 14:30:02 -070070#define ESR_TIMER_DISCHG_MAX_WORD 17
71#define ESR_TIMER_DISCHG_MAX_OFFSET 0
72#define ESR_TIMER_DISCHG_INIT_WORD 17
73#define ESR_TIMER_DISCHG_INIT_OFFSET 2
74#define ESR_TIMER_CHG_MAX_WORD 18
75#define ESR_TIMER_CHG_MAX_OFFSET 0
76#define ESR_TIMER_CHG_INIT_WORD 18
77#define ESR_TIMER_CHG_INIT_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070078#define PROFILE_LOAD_WORD 24
79#define PROFILE_LOAD_OFFSET 0
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -080080#define ESR_RSLOW_DISCHG_WORD 34
81#define ESR_RSLOW_DISCHG_OFFSET 0
82#define ESR_RSLOW_CHG_WORD 51
83#define ESR_RSLOW_CHG_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070084#define NOM_CAP_WORD 58
85#define NOM_CAP_OFFSET 0
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -070086#define ACT_BATT_CAP_BKUP_WORD 74
87#define ACT_BATT_CAP_BKUP_OFFSET 0
Nicholas Troaste29dec92016-08-24 09:35:11 -070088#define CYCLE_COUNT_WORD 75
89#define CYCLE_COUNT_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070090#define PROFILE_INTEGRITY_WORD 79
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -080091#define SW_CONFIG_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070092#define PROFILE_INTEGRITY_OFFSET 3
93#define BATT_SOC_WORD 91
94#define BATT_SOC_OFFSET 0
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -070095#define FULL_SOC_WORD 93
96#define FULL_SOC_OFFSET 2
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070097#define MONOTONIC_SOC_WORD 94
98#define MONOTONIC_SOC_OFFSET 2
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -070099#define CC_SOC_WORD 95
100#define CC_SOC_OFFSET 0
101#define CC_SOC_SW_WORD 96
102#define CC_SOC_SW_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700103#define VOLTAGE_PRED_WORD 97
104#define VOLTAGE_PRED_OFFSET 0
105#define OCV_WORD 97
106#define OCV_OFFSET 2
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800107#define ESR_WORD 99
108#define ESR_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700109#define RSLOW_WORD 101
110#define RSLOW_OFFSET 0
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700111#define ACT_BATT_CAP_WORD 117
112#define ACT_BATT_CAP_OFFSET 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700113#define LAST_BATT_SOC_WORD 119
114#define LAST_BATT_SOC_OFFSET 0
115#define LAST_MONOTONIC_SOC_WORD 119
116#define LAST_MONOTONIC_SOC_OFFSET 2
Nicholas Troast69da2252016-09-07 16:17:47 -0700117#define ALG_FLAGS_WORD 120
118#define ALG_FLAGS_OFFSET 1
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700119
Nicholas Troasta2b40372016-08-15 10:45:39 -0700120/* v2 SRAM address and offset in ascending order */
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700121#define KI_COEFF_LOW_DISCHG_v2_WORD 9
122#define KI_COEFF_LOW_DISCHG_v2_OFFSET 3
123#define KI_COEFF_MED_DISCHG_v2_WORD 10
124#define KI_COEFF_MED_DISCHG_v2_OFFSET 0
125#define KI_COEFF_HI_DISCHG_v2_WORD 10
126#define KI_COEFF_HI_DISCHG_v2_OFFSET 1
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800127#define DELTA_BSOC_THR_v2_WORD 12
128#define DELTA_BSOC_THR_v2_OFFSET 3
129#define DELTA_MSOC_THR_v2_WORD 13
130#define DELTA_MSOC_THR_v2_OFFSET 0
Nicholas Troasta2b40372016-08-15 10:45:39 -0700131#define RECHARGE_SOC_THR_v2_WORD 14
132#define RECHARGE_SOC_THR_v2_OFFSET 1
133#define CHG_TERM_CURR_v2_WORD 15
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -0700134#define CHG_TERM_BASE_CURR_v2_OFFSET 0
Nicholas Troasta2b40372016-08-15 10:45:39 -0700135#define CHG_TERM_CURR_v2_OFFSET 1
136#define EMPTY_VOLT_v2_WORD 15
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -0700137#define EMPTY_VOLT_v2_OFFSET 3
Nicholas Troasta2b40372016-08-15 10:45:39 -0700138#define VBATT_LOW_v2_WORD 16
139#define VBATT_LOW_v2_OFFSET 0
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -0800140#define RECHARGE_VBATT_THR_v2_WORD 16
141#define RECHARGE_VBATT_THR_v2_OFFSET 1
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700142#define FLOAT_VOLT_v2_WORD 16
143#define FLOAT_VOLT_v2_OFFSET 2
Nicholas Troasta2b40372016-08-15 10:45:39 -0700144
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700145static int fg_decode_voltage_15b(struct fg_sram_param *sp,
146 enum fg_sram_param_id id, int val);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700147static int fg_decode_value_16b(struct fg_sram_param *sp,
148 enum fg_sram_param_id id, int val);
149static int fg_decode_default(struct fg_sram_param *sp,
150 enum fg_sram_param_id id, int val);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700151static int fg_decode_cc_soc(struct fg_sram_param *sp,
152 enum fg_sram_param_id id, int value);
Nicholas Troasta2b40372016-08-15 10:45:39 -0700153static void fg_encode_voltage(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700154 enum fg_sram_param_id id, int val_mv, u8 *buf);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700155static void fg_encode_current(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700156 enum fg_sram_param_id id, int val_ma, u8 *buf);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700157static void fg_encode_default(struct fg_sram_param *sp,
158 enum fg_sram_param_id id, int val, u8 *buf);
159
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800160static struct fg_irq_info fg_irqs[FG_IRQ_MAX];
161
Nicholas Troasta2b40372016-08-15 10:45:39 -0700162#define PARAM(_id, _addr_word, _addr_byte, _len, _num, _den, _offset, \
163 _enc, _dec) \
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700164 [FG_SRAM_##_id] = { \
Nicholas Troasta2b40372016-08-15 10:45:39 -0700165 .addr_word = _addr_word, \
166 .addr_byte = _addr_byte, \
167 .len = _len, \
168 .numrtr = _num, \
169 .denmtr = _den, \
170 .offset = _offset, \
171 .encode = _enc, \
172 .decode = _dec, \
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700173 } \
174
Harry Yang2452b272017-03-06 13:56:14 -0800175static struct fg_sram_param pmi8998_v1_sram_params[] = {
Nicholas Troasta2b40372016-08-15 10:45:39 -0700176 PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700177 fg_decode_default),
Nicholas Troast1769fd32016-09-07 09:20:58 -0700178 PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
179 fg_decode_default),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800180 PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
181 244141, 0, NULL, fg_decode_voltage_15b),
182 PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700183 fg_decode_voltage_15b),
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800184 PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default,
185 fg_decode_value_16b),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800186 PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700187 fg_decode_value_16b),
Nicholas Troast69da2252016-09-07 16:17:47 -0700188 PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
189 fg_decode_default),
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700190 PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL,
191 fg_decode_cc_soc),
192 PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL,
193 fg_decode_cc_soc),
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -0700194 PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
195 1, 1, 0, NULL, fg_decode_default),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700196 /* Entries below here are configurable during initialization */
197 PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700198 244141, 0, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700199 PARAM(EMPTY_VOLT, EMPTY_VOLT_WORD, EMPTY_VOLT_OFFSET, 1, 100000, 390625,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700200 -2500, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700201 PARAM(VBATT_LOW, VBATT_LOW_WORD, VBATT_LOW_OFFSET, 1, 100000, 390625,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700202 -2500, fg_encode_voltage, NULL),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800203 PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
204 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700205 PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700206 1000000, 122070, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700207 PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700208 100000, 390625, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800209 PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1,
210 2048, 100, 0, fg_encode_default, NULL),
211 PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1,
212 2048, 100, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700213 PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700214 1, 256, 100, 0, fg_encode_default, NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700215 PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700216 ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
217 NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700218 PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700219 ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700220 NULL),
221 PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700222 ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Nicholas Troastdcf8fe62016-08-04 14:30:02 -0700223 PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700224 ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -0700225 PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
226 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700227 PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_WORD,
228 KI_COEFF_MED_DISCHG_OFFSET, 1, 1000, 244141, 0,
229 fg_encode_default, NULL),
230 PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_WORD,
231 KI_COEFF_HI_DISCHG_OFFSET, 1, 1000, 244141, 0,
232 fg_encode_default, NULL),
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -0700233 PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
234 KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
235 fg_encode_default, NULL),
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -0800236 PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
237 1, 512, 1000000, 0, fg_encode_default, NULL),
238 PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
239 1, 512, 1000000, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -0800240 PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
241 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700242};
243
Harry Yang2452b272017-03-06 13:56:14 -0800244static struct fg_sram_param pmi8998_v2_sram_params[] = {
Nicholas Troasta2b40372016-08-15 10:45:39 -0700245 PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700246 fg_decode_default),
Nicholas Troast1769fd32016-09-07 09:20:58 -0700247 PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
248 fg_decode_default),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800249 PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
250 244141, 0, NULL, fg_decode_voltage_15b),
251 PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700252 fg_decode_voltage_15b),
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800253 PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default,
254 fg_decode_value_16b),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800255 PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
Nicholas Troasta2b40372016-08-15 10:45:39 -0700256 fg_decode_value_16b),
Nicholas Troast69da2252016-09-07 16:17:47 -0700257 PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
258 fg_decode_default),
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700259 PARAM(CC_SOC, CC_SOC_WORD, CC_SOC_OFFSET, 4, 1, 1, 0, NULL,
260 fg_decode_cc_soc),
261 PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL,
262 fg_decode_cc_soc),
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -0700263 PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
264 1, 1, 0, NULL, fg_decode_default),
Anirudh Ghayalddabeee2017-04-04 06:13:48 +0530265 PARAM(TIMEBASE, KI_COEFF_MED_DISCHG_WORD, TIMEBASE_OFFSET, 2, 1000,
266 61000, 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700267 /* Entries below here are configurable during initialization */
268 PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
269 244141, 0, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -0700270 PARAM(EMPTY_VOLT, EMPTY_VOLT_v2_WORD, EMPTY_VOLT_v2_OFFSET, 1, 1000,
271 15625, -2000, fg_encode_voltage, NULL),
272 PARAM(VBATT_LOW, VBATT_LOW_v2_WORD, VBATT_LOW_v2_OFFSET, 1, 1000,
273 15625, -2000, fg_encode_voltage, NULL),
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700274 PARAM(FLOAT_VOLT, FLOAT_VOLT_v2_WORD, FLOAT_VOLT_v2_OFFSET, 1, 1000,
275 15625, -2000, fg_encode_voltage, NULL),
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800276 PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
277 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700278 PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
279 1000000, 122070, 0, fg_encode_current, NULL),
280 PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1,
281 100000, 390625, 0, fg_encode_current, NULL),
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -0700282 PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD,
283 CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0,
284 fg_encode_current, NULL),
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -0800285 PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
286 1, 2048, 100, 0, fg_encode_default, NULL),
287 PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
288 1, 2048, 100, 0, fg_encode_default, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700289 PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD,
290 RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default,
291 NULL),
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -0800292 PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD,
293 RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000,
294 fg_encode_voltage, NULL),
Nicholas Troasta2b40372016-08-15 10:45:39 -0700295 PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
296 ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
297 NULL),
298 PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
299 ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default,
300 NULL),
301 PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
302 ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
303 PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
304 ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -0700305 PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
306 1, 100000, 390625, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -0700307 PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_v2_WORD,
308 KI_COEFF_MED_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
309 fg_encode_default, NULL),
310 PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_v2_WORD,
311 KI_COEFF_HI_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
312 fg_encode_default, NULL),
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -0700313 PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
314 KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
315 fg_encode_default, NULL),
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -0800316 PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
317 1, 512, 1000000, 0, fg_encode_default, NULL),
318 PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
319 1, 512, 1000000, 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -0800320 PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
321 0, fg_encode_default, NULL),
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700322};
323
Harry Yang2452b272017-03-06 13:56:14 -0800324static struct fg_alg_flag pmi8998_v1_alg_flags[] = {
Nicholas Troast69da2252016-09-07 16:17:47 -0700325 [ALG_FLAG_SOC_LT_OTG_MIN] = {
326 .name = "SOC_LT_OTG_MIN",
327 .bit = BIT(0),
328 },
329 [ALG_FLAG_SOC_LT_RECHARGE] = {
330 .name = "SOC_LT_RECHARGE",
331 .bit = BIT(1),
332 },
333 [ALG_FLAG_IBATT_LT_ITERM] = {
334 .name = "IBATT_LT_ITERM",
335 .bit = BIT(2),
336 },
337 [ALG_FLAG_IBATT_GT_HPM] = {
338 .name = "IBATT_GT_HPM",
339 .bit = BIT(3),
340 },
341 [ALG_FLAG_IBATT_GT_UPM] = {
342 .name = "IBATT_GT_UPM",
343 .bit = BIT(4),
344 },
345 [ALG_FLAG_VBATT_LT_RECHARGE] = {
346 .name = "VBATT_LT_RECHARGE",
347 .bit = BIT(5),
348 },
349 [ALG_FLAG_VBATT_GT_VFLOAT] = {
350 .invalid = true,
351 },
352};
353
Harry Yang2452b272017-03-06 13:56:14 -0800354static struct fg_alg_flag pmi8998_v2_alg_flags[] = {
Nicholas Troast69da2252016-09-07 16:17:47 -0700355 [ALG_FLAG_SOC_LT_OTG_MIN] = {
356 .name = "SOC_LT_OTG_MIN",
357 .bit = BIT(0),
358 },
359 [ALG_FLAG_SOC_LT_RECHARGE] = {
360 .name = "SOC_LT_RECHARGE",
361 .bit = BIT(1),
362 },
363 [ALG_FLAG_IBATT_LT_ITERM] = {
364 .name = "IBATT_LT_ITERM",
365 .bit = BIT(2),
366 },
367 [ALG_FLAG_IBATT_GT_HPM] = {
368 .name = "IBATT_GT_HPM",
369 .bit = BIT(4),
370 },
371 [ALG_FLAG_IBATT_GT_UPM] = {
372 .name = "IBATT_GT_UPM",
373 .bit = BIT(5),
374 },
375 [ALG_FLAG_VBATT_LT_RECHARGE] = {
376 .name = "VBATT_LT_RECHARGE",
377 .bit = BIT(6),
378 },
379 [ALG_FLAG_VBATT_GT_VFLOAT] = {
380 .name = "VBATT_GT_VFLOAT",
381 .bit = BIT(7),
382 },
383};
384
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700385static int fg_gen3_debug_mask;
386module_param_named(
387 debug_mask, fg_gen3_debug_mask, int, 0600
388);
389
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800390static bool fg_profile_dump;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700391module_param_named(
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800392 profile_dump, fg_profile_dump, bool, 0600
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700393);
394
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800395static int fg_sram_dump_period_ms = 20000;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700396module_param_named(
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800397 sram_dump_period_ms, fg_sram_dump_period_ms, int, 0600
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700398);
399
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -0700400static int fg_restart;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800401static bool fg_sram_dump;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -0700402
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700403/* All getters HERE */
404
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700405#define VOLTAGE_15BIT_MASK GENMASK(14, 0)
406static int fg_decode_voltage_15b(struct fg_sram_param *sp,
407 enum fg_sram_param_id id, int value)
408{
409 value &= VOLTAGE_15BIT_MASK;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800410 sp[id].value = div_u64((u64)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy68d105c2016-10-03 18:30:32 -0700411 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
412 sp[id].value);
413 return sp[id].value;
414}
415
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700416static int fg_decode_cc_soc(struct fg_sram_param *sp,
417 enum fg_sram_param_id id, int value)
418{
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800419 sp[id].value = div_s64((s64)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700420 sp[id].value = sign_extend32(sp[id].value, 31);
421 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
422 sp[id].value);
423 return sp[id].value;
424}
425
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700426static int fg_decode_value_16b(struct fg_sram_param *sp,
427 enum fg_sram_param_id id, int value)
428{
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -0800429 sp[id].value = div_u64((u64)(u16)value * sp[id].denmtr, sp[id].numrtr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700430 pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
431 sp[id].value);
432 return sp[id].value;
433}
434
Nicholas Troaste29dec92016-08-24 09:35:11 -0700435static int fg_decode_default(struct fg_sram_param *sp, enum fg_sram_param_id id,
436 int value)
437{
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700438 sp[id].value = value;
439 return sp[id].value;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700440}
441
442static int fg_decode(struct fg_sram_param *sp, enum fg_sram_param_id id,
443 int value)
444{
445 if (!sp[id].decode) {
446 pr_err("No decoding function for parameter %d\n", id);
447 return -EINVAL;
448 }
449
450 return sp[id].decode(sp, id, value);
451}
452
Nicholas Troasta2b40372016-08-15 10:45:39 -0700453static void fg_encode_voltage(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700454 enum fg_sram_param_id id, int val_mv, u8 *buf)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700455{
456 int i, mask = 0xff;
457 int64_t temp;
458
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700459 val_mv += sp[id].offset;
460 temp = (int64_t)div_u64((u64)val_mv * sp[id].numrtr, sp[id].denmtr);
461 pr_debug("temp: %llx id: %d, val_mv: %d, buf: [ ", temp, id, val_mv);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700462 for (i = 0; i < sp[id].len; i++) {
463 buf[i] = temp & mask;
464 temp >>= 8;
465 pr_debug("%x ", buf[i]);
466 }
467 pr_debug("]\n");
468}
469
470static void fg_encode_current(struct fg_sram_param *sp,
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700471 enum fg_sram_param_id id, int val_ma, u8 *buf)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700472{
473 int i, mask = 0xff;
474 int64_t temp;
475 s64 current_ma;
476
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700477 current_ma = val_ma;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700478 temp = (int64_t)div_s64(current_ma * sp[id].numrtr, sp[id].denmtr);
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700479 pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val_ma);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700480 for (i = 0; i < sp[id].len; i++) {
481 buf[i] = temp & mask;
482 temp >>= 8;
483 pr_debug("%x ", buf[i]);
484 }
485 pr_debug("]\n");
486}
487
488static void fg_encode_default(struct fg_sram_param *sp,
489 enum fg_sram_param_id id, int val, u8 *buf)
490{
491 int i, mask = 0xff;
492 int64_t temp;
493
494 temp = DIV_ROUND_CLOSEST(val * sp[id].numrtr, sp[id].denmtr);
495 pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
496 for (i = 0; i < sp[id].len; i++) {
497 buf[i] = temp & mask;
498 temp >>= 8;
499 pr_debug("%x ", buf[i]);
500 }
501 pr_debug("]\n");
502}
503
504static void fg_encode(struct fg_sram_param *sp, enum fg_sram_param_id id,
505 int val, u8 *buf)
506{
507 if (!sp[id].encode) {
508 pr_err("No encoding function for parameter %d\n", id);
509 return;
510 }
511
512 sp[id].encode(sp, id, val, buf);
513}
514
515/*
516 * Please make sure *_sram_params table has the entry for the parameter
517 * obtained through this function. In addition to address, offset,
518 * length from where this SRAM parameter is read, a decode function
519 * need to be specified.
520 */
521static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id,
522 int *val)
523{
524 int temp, rc, i;
525 u8 buf[4];
526
527 if (id < 0 || id > FG_SRAM_MAX || chip->sp[id].len > sizeof(buf))
528 return -EINVAL;
529
Subbaraman Narayanamurthy0a749db2016-10-03 18:33:19 -0700530 if (chip->battery_missing)
531 return -ENODATA;
532
Nicholas Troasta2b40372016-08-15 10:45:39 -0700533 rc = fg_sram_read(chip, chip->sp[id].addr_word, chip->sp[id].addr_byte,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700534 buf, chip->sp[id].len, FG_IMA_DEFAULT);
535 if (rc < 0) {
536 pr_err("Error reading address 0x%04x[%d] rc=%d\n",
Nicholas Troasta2b40372016-08-15 10:45:39 -0700537 chip->sp[id].addr_word, chip->sp[id].addr_byte, rc);
Nicholas Troastb2d71742016-08-04 14:31:41 -0700538 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700539 }
540
541 for (i = 0, temp = 0; i < chip->sp[id].len; i++)
542 temp |= buf[i] << (8 * i);
543
544 *val = fg_decode(chip->sp, id, temp);
545 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700546}
547
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700548#define CC_SOC_30BIT GENMASK(29, 0)
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -0700549static int fg_get_charge_raw(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700550{
551 int rc, cc_soc;
552
553 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC, &cc_soc);
554 if (rc < 0) {
555 pr_err("Error in getting CC_SOC, rc=%d\n", rc);
556 return rc;
557 }
558
559 *val = div_s64(cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT);
560 return 0;
561}
562
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -0700563static int fg_get_charge_counter(struct fg_chip *chip, int *val)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -0700564{
565 int rc, cc_soc;
566
567 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc);
568 if (rc < 0) {
569 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
570 return rc;
571 }
572
573 *val = div_s64(cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT);
574 return 0;
575}
576
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700577#define BATT_TEMP_NUMR 1
578#define BATT_TEMP_DENR 1
579static int fg_get_battery_temp(struct fg_chip *chip, int *val)
580{
Subbaraman Narayanamurthyfabbb8e2016-10-21 16:55:09 -0700581 int rc = 0, temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700582 u8 buf[2];
583
584 rc = fg_read(chip, BATT_INFO_BATT_TEMP_LSB(chip), buf, 2);
585 if (rc < 0) {
586 pr_err("failed to read addr=0x%04x, rc=%d\n",
587 BATT_INFO_BATT_TEMP_LSB(chip), rc);
588 return rc;
589 }
590
591 temp = ((buf[1] & BATT_TEMP_MSB_MASK) << 8) |
592 (buf[0] & BATT_TEMP_LSB_MASK);
593 temp = DIV_ROUND_CLOSEST(temp, 4);
594
595 /* Value is in Kelvin; Convert it to deciDegC */
596 temp = (temp - 273) * 10;
597 *val = temp;
598 return 0;
599}
600
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700601static int fg_get_battery_resistance(struct fg_chip *chip, int *val)
602{
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800603 int rc, esr_uohms, rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700604
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -0800605 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700606 if (rc < 0) {
607 pr_err("failed to get ESR, rc=%d\n", rc);
608 return rc;
609 }
610
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800611 rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &rslow_uohms);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700612 if (rc < 0) {
613 pr_err("failed to get Rslow, rc=%d\n", rc);
614 return rc;
615 }
616
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -0800617 *val = esr_uohms + rslow_uohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700618 return 0;
619}
620
621#define BATT_CURRENT_NUMR 488281
622#define BATT_CURRENT_DENR 1000
623static int fg_get_battery_current(struct fg_chip *chip, int *val)
624{
625 int rc = 0;
626 int64_t temp = 0;
627 u8 buf[2];
628
629 rc = fg_read(chip, BATT_INFO_IBATT_LSB(chip), buf, 2);
630 if (rc < 0) {
631 pr_err("failed to read addr=0x%04x, rc=%d\n",
632 BATT_INFO_IBATT_LSB(chip), rc);
633 return rc;
634 }
635
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530636 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700637 temp = buf[0] << 8 | buf[1];
638 else
639 temp = buf[1] << 8 | buf[0];
640
641 pr_debug("buf: %x %x temp: %llx\n", buf[0], buf[1], temp);
642 /* Sign bit is bit 15 */
643 temp = twos_compliment_extend(temp, 15);
644 *val = div_s64((s64)temp * BATT_CURRENT_NUMR, BATT_CURRENT_DENR);
645 return 0;
646}
647
648#define BATT_VOLTAGE_NUMR 122070
649#define BATT_VOLTAGE_DENR 1000
650static int fg_get_battery_voltage(struct fg_chip *chip, int *val)
651{
652 int rc = 0;
653 u16 temp = 0;
654 u8 buf[2];
655
656 rc = fg_read(chip, BATT_INFO_VBATT_LSB(chip), buf, 2);
657 if (rc < 0) {
658 pr_err("failed to read addr=0x%04x, rc=%d\n",
659 BATT_INFO_VBATT_LSB(chip), rc);
660 return rc;
661 }
662
Ashay Jaiswal63d486e2016-12-07 11:21:32 +0530663 if (chip->wa_flags & PMI8998_V1_REV_WA)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700664 temp = buf[0] << 8 | buf[1];
665 else
666 temp = buf[1] << 8 | buf[0];
667
668 pr_debug("buf: %x %x temp: %x\n", buf[0], buf[1], temp);
669 *val = div_u64((u64)temp * BATT_VOLTAGE_NUMR, BATT_VOLTAGE_DENR);
670 return 0;
671}
672
673#define MAX_TRIES_SOC 5
674static int fg_get_msoc_raw(struct fg_chip *chip, int *val)
675{
676 u8 cap[2];
677 int rc, tries = 0;
678
679 while (tries < MAX_TRIES_SOC) {
680 rc = fg_read(chip, BATT_SOC_FG_MONOTONIC_SOC(chip), cap, 2);
681 if (rc < 0) {
682 pr_err("failed to read addr=0x%04x, rc=%d\n",
683 BATT_SOC_FG_MONOTONIC_SOC(chip), rc);
684 return rc;
685 }
686
687 if (cap[0] == cap[1])
688 break;
689
690 tries++;
691 }
692
693 if (tries == MAX_TRIES_SOC) {
694 pr_err("shadow registers do not match\n");
695 return -EINVAL;
696 }
697
698 fg_dbg(chip, FG_POWER_SUPPLY, "raw: 0x%02x\n", cap[0]);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700699 *val = cap[0];
700 return 0;
701}
702
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800703#define FULL_CAPACITY 100
704#define FULL_SOC_RAW 255
705static int fg_get_msoc(struct fg_chip *chip, int *msoc)
706{
707 int rc;
708
709 rc = fg_get_msoc_raw(chip, msoc);
710 if (rc < 0)
711 return rc;
712
713 *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW);
714 return 0;
715}
716
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800717static bool is_batt_empty(struct fg_chip *chip)
718{
719 u8 status;
720 int rc, vbatt_uv, msoc;
721
722 rc = fg_read(chip, BATT_SOC_INT_RT_STS(chip), &status, 1);
723 if (rc < 0) {
724 pr_err("failed to read addr=0x%04x, rc=%d\n",
725 BATT_SOC_INT_RT_STS(chip), rc);
726 return false;
727 }
728
729 if (!(status & MSOC_EMPTY_BIT))
730 return false;
731
732 rc = fg_get_battery_voltage(chip, &vbatt_uv);
733 if (rc < 0) {
734 pr_err("failed to get battery voltage, rc=%d\n", rc);
735 return false;
736 }
737
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800738 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800739 if (!rc)
740 pr_warn("batt_soc_rt_sts: %x vbatt: %d uV msoc:%d\n", status,
741 vbatt_uv, msoc);
742
743 return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false);
744}
745
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800746static int fg_get_debug_batt_id(struct fg_chip *chip, int *batt_id)
747{
748 int rc;
749 u64 temp;
750 u8 buf[2];
751
752 rc = fg_read(chip, ADC_RR_FAKE_BATT_LOW_LSB(chip), buf, 2);
753 if (rc < 0) {
754 pr_err("failed to read addr=0x%04x, rc=%d\n",
755 ADC_RR_FAKE_BATT_LOW_LSB(chip), rc);
756 return rc;
757 }
758
759 /*
760 * Fake battery threshold is encoded in the following format.
761 * Threshold (code) = (battery_id in Ohms) * 0.00015 * 2^10 / 2.5
762 */
763 temp = (buf[1] << 8 | buf[0]) * 2500000;
764 do_div(temp, 150 * 1024);
765 batt_id[0] = temp;
766 rc = fg_read(chip, ADC_RR_FAKE_BATT_HIGH_LSB(chip), buf, 2);
767 if (rc < 0) {
768 pr_err("failed to read addr=0x%04x, rc=%d\n",
769 ADC_RR_FAKE_BATT_HIGH_LSB(chip), rc);
770 return rc;
771 }
772
773 temp = (buf[1] << 8 | buf[0]) * 2500000;
774 do_div(temp, 150 * 1024);
775 batt_id[1] = temp;
776 pr_debug("debug batt_id range: [%d %d]\n", batt_id[0], batt_id[1]);
777 return 0;
778}
779
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700780static bool is_debug_batt_id(struct fg_chip *chip)
781{
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800782 int debug_batt_id[2], rc;
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700783
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800784 if (!chip->batt_id_ohms)
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700785 return false;
786
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -0800787 rc = fg_get_debug_batt_id(chip, debug_batt_id);
788 if (rc < 0) {
789 pr_err("Failed to get debug batt_id, rc=%d\n", rc);
790 return false;
791 }
792
793 if (is_between(debug_batt_id[0], debug_batt_id[1],
794 chip->batt_id_ohms)) {
795 fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dohms\n",
796 chip->batt_id_ohms);
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700797 return true;
798 }
799
800 return false;
801}
802
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700803#define DEBUG_BATT_SOC 67
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800804#define BATT_MISS_SOC 50
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700805#define EMPTY_SOC 0
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700806static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
807{
808 int rc, msoc;
809
Subbaraman Narayanamurthy2d65d5b2016-11-03 12:02:52 -0700810 if (is_debug_batt_id(chip)) {
811 *val = DEBUG_BATT_SOC;
812 return 0;
813 }
814
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -0800815 if (chip->fg_restarting) {
816 *val = chip->last_soc;
817 return 0;
818 }
819
820 if (chip->battery_missing) {
821 *val = BATT_MISS_SOC;
822 return 0;
823 }
824
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -0800825 if (is_batt_empty(chip)) {
Subbaraman Narayanamurthyc7b33322016-11-01 16:29:46 -0700826 *val = EMPTY_SOC;
827 return 0;
828 }
829
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700830 if (chip->charge_full) {
831 *val = FULL_CAPACITY;
832 return 0;
833 }
834
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800835 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700836 if (rc < 0)
837 return rc;
838
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -0800839 if (chip->delta_soc > 0)
840 *val = chip->maint_soc;
841 else
842 *val = msoc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700843 return 0;
844}
845
846#define DEFAULT_BATT_TYPE "Unknown Battery"
847#define MISSING_BATT_TYPE "Missing Battery"
848#define LOADING_BATT_TYPE "Loading Battery"
849static const char *fg_get_battery_type(struct fg_chip *chip)
850{
851 if (chip->battery_missing)
852 return MISSING_BATT_TYPE;
853
854 if (chip->bp.batt_type_str) {
855 if (chip->profile_loaded)
856 return chip->bp.batt_type_str;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -0800857 else if (chip->profile_available)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700858 return LOADING_BATT_TYPE;
859 }
860
861 return DEFAULT_BATT_TYPE;
862}
863
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800864static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700865{
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800866 int rc;
867
868 rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
869 BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
870 if (rc < 0)
871 pr_err("Error in writing to %04x, rc=%d\n",
872 BATT_INFO_BATT_MISS_CFG(chip), rc);
873 return rc;
874}
875
876static int fg_get_batt_id(struct fg_chip *chip)
877{
878 int rc, ret, batt_id = 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700879
880 if (!chip->batt_id_chan)
881 return -EINVAL;
882
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800883 rc = fg_batt_missing_config(chip, false);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700884 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800885 pr_err("Error in disabling BMD, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700886 return rc;
887 }
888
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800889 rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
890 if (rc < 0) {
891 pr_err("Error in reading batt_id channel, rc:%d\n", rc);
892 goto out;
893 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700894
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800895 /* Wait for 200ms before enabling BMD again */
896 msleep(200);
897
898 fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
899 chip->batt_id_ohms = batt_id;
900out:
901 ret = fg_batt_missing_config(chip, true);
902 if (ret < 0) {
903 pr_err("Error in enabling BMD, ret=%d\n", ret);
904 return ret;
905 }
906
907 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700908}
909
910static int fg_get_batt_profile(struct fg_chip *chip)
911{
912 struct device_node *node = chip->dev->of_node;
913 struct device_node *batt_node, *profile_node;
914 const char *data;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800915 int rc, len;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700916
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700917 batt_node = of_find_node_by_name(node, "qcom,battery-data");
918 if (!batt_node) {
919 pr_err("Batterydata not available\n");
920 return -ENXIO;
921 }
922
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800923 profile_node = of_batterydata_get_best_profile(batt_node,
924 chip->batt_id_ohms / 1000, NULL);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700925 if (IS_ERR(profile_node))
926 return PTR_ERR(profile_node);
927
928 if (!profile_node) {
929 pr_err("couldn't find profile handle\n");
930 return -ENODATA;
931 }
932
933 rc = of_property_read_string(profile_node, "qcom,battery-type",
934 &chip->bp.batt_type_str);
935 if (rc < 0) {
936 pr_err("battery type unavailable, rc:%d\n", rc);
937 return rc;
938 }
939
940 rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
941 &chip->bp.float_volt_uv);
942 if (rc < 0) {
943 pr_err("battery float voltage unavailable, rc:%d\n", rc);
944 chip->bp.float_volt_uv = -EINVAL;
945 }
946
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -0800947 rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700948 &chip->bp.fastchg_curr_ma);
949 if (rc < 0) {
Subbaraman Narayanamurthy5f653bb2016-12-09 15:24:12 -0800950 pr_err("battery fastchg current unavailable, rc:%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700951 chip->bp.fastchg_curr_ma = -EINVAL;
952 }
953
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700954 rc = of_property_read_u32(profile_node, "qcom,fg-cc-cv-threshold-mv",
955 &chip->bp.vbatt_full_mv);
956 if (rc < 0) {
957 pr_err("battery cc_cv threshold unavailable, rc:%d\n", rc);
958 chip->bp.vbatt_full_mv = -EINVAL;
959 }
960
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700961 data = of_get_property(profile_node, "qcom,fg-profile-data", &len);
962 if (!data) {
963 pr_err("No profile data available\n");
964 return -ENODATA;
965 }
966
967 if (len != PROFILE_LEN) {
968 pr_err("battery profile incorrect size: %d\n", len);
969 return -EINVAL;
970 }
971
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -0700972 chip->profile_available = true;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700973 memcpy(chip->batt_profile, data, len);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -0800974
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700975 return 0;
976}
977
978static inline void get_temp_setpoint(int threshold, u8 *val)
979{
980 /* Resolution is 0.5C. Base is -30C. */
981 *val = DIV_ROUND_CLOSEST((threshold + 30) * 10, 5);
982}
983
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -0700984static inline void get_batt_temp_delta(int delta, u8 *val)
985{
986 switch (delta) {
987 case 2:
988 *val = BTEMP_DELTA_2K;
989 break;
990 case 4:
991 *val = BTEMP_DELTA_4K;
992 break;
993 case 6:
994 *val = BTEMP_DELTA_6K;
995 break;
996 case 10:
997 *val = BTEMP_DELTA_10K;
998 break;
999 default:
1000 *val = BTEMP_DELTA_2K;
1001 break;
1002 };
1003}
1004
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07001005static inline void get_esr_meas_current(int curr_ma, u8 *val)
1006{
1007 switch (curr_ma) {
1008 case 60:
1009 *val = ESR_MEAS_CUR_60MA;
1010 break;
1011 case 120:
1012 *val = ESR_MEAS_CUR_120MA;
1013 break;
1014 case 180:
1015 *val = ESR_MEAS_CUR_180MA;
1016 break;
1017 case 240:
1018 *val = ESR_MEAS_CUR_240MA;
1019 break;
1020 default:
1021 *val = ESR_MEAS_CUR_120MA;
1022 break;
1023 };
1024
1025 *val <<= ESR_PULL_DOWN_IVAL_SHIFT;
1026}
1027
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001028static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
1029 int cycles_max, bool charging, int flags)
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001030{
1031 u8 buf[2];
1032 int rc, timer_max, timer_init;
1033
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001034 if (cycles_init < 0 || cycles_max < 0)
1035 return 0;
1036
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001037 if (charging) {
1038 timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
1039 timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
1040 } else {
1041 timer_max = FG_SRAM_ESR_TIMER_DISCHG_MAX;
1042 timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
1043 }
1044
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001045 fg_encode(chip->sp, timer_max, cycles_max, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001046 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001047 chip->sp[timer_max].addr_word,
1048 chip->sp[timer_max].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001049 chip->sp[timer_max].len, flags);
1050 if (rc < 0) {
1051 pr_err("Error in writing esr_timer_dischg_max, rc=%d\n",
1052 rc);
1053 return rc;
1054 }
1055
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001056 fg_encode(chip->sp, timer_init, cycles_init, buf);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001057 rc = fg_sram_write(chip,
Nicholas Troasta2b40372016-08-15 10:45:39 -07001058 chip->sp[timer_init].addr_word,
1059 chip->sp[timer_init].addr_byte, buf,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001060 chip->sp[timer_init].len, flags);
1061 if (rc < 0) {
1062 pr_err("Error in writing esr_timer_dischg_init, rc=%d\n",
1063 rc);
1064 return rc;
1065 }
1066
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07001067 fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
1068 charging ? "charging" : "discharging", cycles_init, cycles_max);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07001069 return 0;
1070}
1071
Nicholas Troaste29dec92016-08-24 09:35:11 -07001072/* Other functions HERE */
1073
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001074static void fg_notify_charger(struct fg_chip *chip)
1075{
1076 union power_supply_propval prop = {0, };
1077 int rc;
1078
1079 if (!chip->batt_psy)
1080 return;
1081
1082 if (!chip->profile_available)
1083 return;
1084
1085 prop.intval = chip->bp.float_volt_uv;
1086 rc = power_supply_set_property(chip->batt_psy,
1087 POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
1088 if (rc < 0) {
1089 pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
1090 rc);
1091 return;
1092 }
1093
1094 prop.intval = chip->bp.fastchg_curr_ma * 1000;
1095 rc = power_supply_set_property(chip->batt_psy,
1096 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
1097 if (rc < 0) {
1098 pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
1099 rc);
1100 return;
1101 }
1102
1103 fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
1104}
1105
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001106static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data,
1107 int enable, const char *client)
1108{
1109 struct fg_chip *chip = data;
1110
1111 if (!chip->irqs[BSOC_DELTA_IRQ].irq)
1112 return 0;
1113
1114 if (enable) {
1115 enable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1116 enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1117 } else {
1118 disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
1119 disable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
1120 }
1121
1122 return 0;
1123}
1124
Nicholas Troaste29dec92016-08-24 09:35:11 -07001125static int fg_awake_cb(struct votable *votable, void *data, int awake,
1126 const char *client)
1127{
1128 struct fg_chip *chip = data;
1129
1130 if (awake)
1131 pm_stay_awake(chip->dev);
1132 else
1133 pm_relax(chip->dev);
1134
1135 pr_debug("client: %s awake: %d\n", client, awake);
1136 return 0;
1137}
1138
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001139static bool batt_psy_initialized(struct fg_chip *chip)
Nicholas Troaste29dec92016-08-24 09:35:11 -07001140{
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001141 if (chip->batt_psy)
1142 return true;
Nicholas Troaste29dec92016-08-24 09:35:11 -07001143
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001144 chip->batt_psy = power_supply_get_by_name("battery");
Nicholas Troaste29dec92016-08-24 09:35:11 -07001145 if (!chip->batt_psy)
1146 return false;
1147
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001148 /* batt_psy is initialized, set the fcc and fv */
1149 fg_notify_charger(chip);
1150
Nicholas Troaste29dec92016-08-24 09:35:11 -07001151 return true;
1152}
1153
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001154static bool is_parallel_charger_available(struct fg_chip *chip)
1155{
1156 if (!chip->parallel_psy)
1157 chip->parallel_psy = power_supply_get_by_name("parallel");
1158
1159 if (!chip->parallel_psy)
1160 return false;
1161
1162 return true;
1163}
1164
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001165static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
1166{
1167 int16_t cc_mah;
1168 int rc;
1169
1170 if (chip->battery_missing || !chip->cl.learned_cc_uah)
1171 return -EPERM;
1172
1173 cc_mah = div64_s64(chip->cl.learned_cc_uah, 1000);
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001174 /* Write to a backup register to use across reboot */
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001175 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word,
1176 chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah,
1177 chip->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT);
1178 if (rc < 0) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001179 pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc);
1180 return rc;
1181 }
1182
1183 /* Write to actual capacity register for coulomb counter operation */
1184 rc = fg_sram_write(chip, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET,
1185 (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len,
1186 FG_IMA_DEFAULT);
1187 if (rc < 0) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001188 pr_err("Error in writing act_batt_cap, rc=%d\n", rc);
1189 return rc;
1190 }
1191
1192 fg_dbg(chip, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n",
1193 chip->cl.learned_cc_uah, cc_mah);
1194 return 0;
1195}
1196
1197#define CAPACITY_DELTA_DECIPCT 500
1198static int fg_load_learned_cap_from_sram(struct fg_chip *chip)
1199{
1200 int rc, act_cap_mah;
1201 int64_t delta_cc_uah, pct_nom_cap_uah;
1202
1203 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
1204 if (rc < 0) {
1205 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1206 return rc;
1207 }
1208
1209 chip->cl.learned_cc_uah = act_cap_mah * 1000;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001210
1211 if (chip->cl.learned_cc_uah != chip->cl.nom_cap_uah) {
Subbaraman Narayanamurthy51d3c902016-10-24 14:05:44 -07001212 if (chip->cl.learned_cc_uah == 0)
1213 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
1214
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001215 delta_cc_uah = abs(chip->cl.learned_cc_uah -
1216 chip->cl.nom_cap_uah);
1217 pct_nom_cap_uah = div64_s64((int64_t)chip->cl.nom_cap_uah *
1218 CAPACITY_DELTA_DECIPCT, 1000);
1219 /*
1220 * If the learned capacity is out of range by 50% from the
1221 * nominal capacity, then overwrite the learned capacity with
1222 * the nominal capacity.
1223 */
1224 if (chip->cl.nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) {
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001225 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected, capping it to nominal: %lld\n",
1226 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001227 chip->cl.learned_cc_uah = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001228 }
Subbaraman Narayanamurthy2932f602016-10-17 14:01:34 -07001229
1230 rc = fg_save_learned_cap_to_sram(chip);
1231 if (rc < 0)
1232 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001233 }
1234
1235 fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah:%lld nom_cap_uah: %lld\n",
1236 chip->cl.learned_cc_uah, chip->cl.nom_cap_uah);
1237 return 0;
1238}
1239
1240static bool is_temp_valid_cap_learning(struct fg_chip *chip)
1241{
1242 int rc, batt_temp;
1243
1244 rc = fg_get_battery_temp(chip, &batt_temp);
1245 if (rc < 0) {
1246 pr_err("Error in getting batt_temp\n");
1247 return false;
1248 }
1249
1250 if (batt_temp > chip->dt.cl_max_temp ||
1251 batt_temp < chip->dt.cl_min_temp) {
1252 fg_dbg(chip, FG_CAP_LEARN, "batt temp %d out of range [%d %d]\n",
1253 batt_temp, chip->dt.cl_min_temp, chip->dt.cl_max_temp);
1254 return false;
1255 }
1256
1257 return true;
1258}
1259
1260static void fg_cap_learning_post_process(struct fg_chip *chip)
1261{
1262 int64_t max_inc_val, min_dec_val, old_cap;
1263 int rc;
1264
1265 max_inc_val = chip->cl.learned_cc_uah
1266 * (1000 + chip->dt.cl_max_cap_inc);
1267 do_div(max_inc_val, 1000);
1268
1269 min_dec_val = chip->cl.learned_cc_uah
1270 * (1000 - chip->dt.cl_max_cap_dec);
1271 do_div(min_dec_val, 1000);
1272
1273 old_cap = chip->cl.learned_cc_uah;
1274 if (chip->cl.final_cc_uah > max_inc_val)
1275 chip->cl.learned_cc_uah = max_inc_val;
1276 else if (chip->cl.final_cc_uah < min_dec_val)
1277 chip->cl.learned_cc_uah = min_dec_val;
1278 else
1279 chip->cl.learned_cc_uah =
1280 chip->cl.final_cc_uah;
1281
1282 if (chip->dt.cl_max_cap_limit) {
1283 max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
1284 chip->dt.cl_max_cap_limit);
1285 do_div(max_inc_val, 1000);
1286 if (chip->cl.final_cc_uah > max_inc_val) {
1287 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
1288 chip->cl.final_cc_uah, max_inc_val);
1289 chip->cl.learned_cc_uah = max_inc_val;
1290 }
1291 }
1292
1293 if (chip->dt.cl_min_cap_limit) {
1294 min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
1295 chip->dt.cl_min_cap_limit);
1296 do_div(min_dec_val, 1000);
1297 if (chip->cl.final_cc_uah < min_dec_val) {
1298 fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
1299 chip->cl.final_cc_uah, min_dec_val);
1300 chip->cl.learned_cc_uah = min_dec_val;
1301 }
1302 }
1303
1304 rc = fg_save_learned_cap_to_sram(chip);
1305 if (rc < 0)
1306 pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
1307
1308 fg_dbg(chip, FG_CAP_LEARN, "final cc_uah = %lld, learned capacity %lld -> %lld uah\n",
1309 chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah);
1310}
1311
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001312static int fg_cap_learning_process_full_data(struct fg_chip *chip)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001313{
1314 int rc, cc_soc_sw, cc_soc_delta_pct;
1315 int64_t delta_cc_uah;
1316
1317 rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
1318 if (rc < 0) {
1319 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
1320 return rc;
1321 }
1322
1323 cc_soc_delta_pct = DIV_ROUND_CLOSEST(
1324 abs(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
1325 CC_SOC_30BIT);
1326 delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
1327 100);
1328 chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
1329 fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n",
1330 cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
1331 return 0;
1332}
1333
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001334#define BATT_SOC_32BIT GENMASK(31, 0)
1335static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001336{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001337 int rc, cc_soc_sw, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001338
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001339 batt_soc_msb = batt_soc >> 24;
1340 if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001341 chip->dt.cl_start_soc) {
1342 fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001343 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001344 return -EINVAL;
1345 }
1346
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001347 chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001348 FULL_SOC_RAW);
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001349
1350 /* Prime cc_soc_sw with battery SOC when capacity learning begins */
1351 cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
1352 BATT_SOC_32BIT);
1353 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1354 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
1355 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001356 if (rc < 0) {
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001357 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1358 goto out;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001359 }
1360
1361 chip->cl.init_cc_soc_sw = cc_soc_sw;
1362 chip->cl.active = true;
1363 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 -07001364 batt_soc_msb, chip->cl.init_cc_soc_sw);
1365out:
1366 return rc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001367}
1368
1369static int fg_cap_learning_done(struct fg_chip *chip)
1370{
1371 int rc, cc_soc_sw;
1372
1373 rc = fg_cap_learning_process_full_data(chip);
1374 if (rc < 0) {
1375 pr_err("Error in processing cap learning full data, rc=%d\n",
1376 rc);
1377 goto out;
1378 }
1379
1380 /* Write a FULL value to cc_soc_sw */
1381 cc_soc_sw = CC_SOC_30BIT;
1382 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1383 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001384 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001385 if (rc < 0) {
1386 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1387 goto out;
1388 }
1389
1390 fg_cap_learning_post_process(chip);
1391out:
1392 return rc;
1393}
1394
1395#define FULL_SOC_RAW 255
1396static void fg_cap_learning_update(struct fg_chip *chip)
1397{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001398 int rc, batt_soc, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001399
1400 mutex_lock(&chip->cl.lock);
1401
1402 if (!is_temp_valid_cap_learning(chip) || !chip->cl.learned_cc_uah ||
1403 chip->battery_missing) {
1404 fg_dbg(chip, FG_CAP_LEARN, "Aborting cap_learning %lld\n",
1405 chip->cl.learned_cc_uah);
1406 chip->cl.active = false;
1407 chip->cl.init_cc_uah = 0;
1408 goto out;
1409 }
1410
1411 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
1412 if (rc < 0) {
1413 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1414 goto out;
1415 }
1416
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001417 batt_soc_msb = (u32)batt_soc >> 24;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001418 fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001419 chip->charge_status, chip->cl.active, batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001420
1421 /* Initialize the starting point of learning capacity */
1422 if (!chip->cl.active) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07001423 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001424 rc = fg_cap_learning_begin(chip, batt_soc);
1425 chip->cl.active = (rc == 0);
1426 }
1427
1428 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001429 if (chip->charge_done) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001430 rc = fg_cap_learning_done(chip);
1431 if (rc < 0)
1432 pr_err("Error in completing capacity learning, rc=%d\n",
1433 rc);
1434
1435 chip->cl.active = false;
1436 chip->cl.init_cc_uah = 0;
1437 }
1438
Nicholas Troast1769fd32016-09-07 09:20:58 -07001439 if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001440 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001441 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001442 chip->cl.active = false;
1443 chip->cl.init_cc_uah = 0;
1444 }
1445 }
1446
1447out:
1448 mutex_unlock(&chip->cl.lock);
1449}
1450
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001451#define KI_COEFF_MED_DISCHG_DEFAULT 1500
1452#define KI_COEFF_HI_DISCHG_DEFAULT 2200
1453static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
1454{
1455 int rc, i, msoc;
1456 int ki_coeff_med = KI_COEFF_MED_DISCHG_DEFAULT;
1457 int ki_coeff_hi = KI_COEFF_HI_DISCHG_DEFAULT;
1458 u8 val;
1459
1460 if (!chip->ki_coeff_dischg_en)
1461 return 0;
1462
1463 rc = fg_get_prop_capacity(chip, &msoc);
1464 if (rc < 0) {
1465 pr_err("Error in getting capacity, rc=%d\n", rc);
1466 return rc;
1467 }
1468
Nicholas Troast1769fd32016-09-07 09:20:58 -07001469 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001470 for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) {
1471 if (msoc < chip->dt.ki_coeff_soc[i]) {
1472 ki_coeff_med = chip->dt.ki_coeff_med_dischg[i];
1473 ki_coeff_hi = chip->dt.ki_coeff_hi_dischg[i];
1474 }
1475 }
1476 }
1477
1478 fg_encode(chip->sp, FG_SRAM_KI_COEFF_MED_DISCHG, ki_coeff_med, &val);
1479 rc = fg_sram_write(chip,
1480 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_word,
1481 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_byte, &val,
1482 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].len,
1483 FG_IMA_DEFAULT);
1484 if (rc < 0) {
1485 pr_err("Error in writing ki_coeff_med, rc=%d\n", rc);
1486 return rc;
1487 }
1488
1489 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_DISCHG, ki_coeff_hi, &val);
1490 rc = fg_sram_write(chip,
1491 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_word,
1492 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_byte, &val,
1493 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].len,
1494 FG_IMA_DEFAULT);
1495 if (rc < 0) {
1496 pr_err("Error in writing ki_coeff_hi, rc=%d\n", rc);
1497 return rc;
1498 }
1499
1500 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_med %d ki_coeff_hi %d\n",
1501 ki_coeff_med, ki_coeff_hi);
1502 return 0;
1503}
1504
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001505#define KI_COEFF_FULL_SOC_DEFAULT 733
1506static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
1507{
1508 int rc, ki_coeff_full_soc;
1509 u8 val;
1510
1511 if (batt_temp < 0)
1512 ki_coeff_full_soc = 0;
1513 else
1514 ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
1515
1516 if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
1517 return 0;
1518
1519 fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
1520 rc = fg_sram_write(chip,
1521 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
1522 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
1523 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
1524 FG_IMA_DEFAULT);
1525 if (rc < 0) {
1526 pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
1527 return rc;
1528 }
1529
1530 chip->ki_coeff_full_soc = ki_coeff_full_soc;
1531 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
1532 ki_coeff_full_soc);
1533 return 0;
1534}
1535
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001536static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
1537{
1538 u8 buf;
1539 int rc;
1540
1541 if (chip->dt.auto_recharge_soc)
1542 return 0;
1543
1544 /* This configuration is available only for pmicobalt v2.0 and above */
1545 if (chip->wa_flags & PMI8998_V1_REV_WA)
1546 return 0;
1547
1548 fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
1549 voltage_mv);
1550 fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
1551 rc = fg_sram_write(chip,
1552 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
1553 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
1554 &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
1555 FG_IMA_DEFAULT);
1556 if (rc < 0) {
1557 pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
1558 rc);
1559 return rc;
1560 }
1561
1562 return 0;
1563}
1564
1565#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001566static int fg_charge_full_update(struct fg_chip *chip)
1567{
1568 union power_supply_propval prop = {0, };
1569 int rc, msoc, bsoc, recharge_soc;
1570 u8 full_soc[2] = {0xFF, 0xFF};
1571
1572 if (!chip->dt.hold_soc_while_full)
1573 return 0;
1574
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001575 if (!batt_psy_initialized(chip))
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001576 return 0;
1577
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001578 mutex_lock(&chip->charge_full_lock);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001579 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
1580 chip->charge_done, 0);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001581 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
1582 &prop);
1583 if (rc < 0) {
1584 pr_err("Error in getting battery health, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001585 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001586 }
1587
1588 chip->health = prop.intval;
1589 recharge_soc = chip->dt.recharge_soc_thr;
1590 recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
1591 FULL_CAPACITY);
1592 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
1593 if (rc < 0) {
1594 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001595 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001596 }
1597
1598 /* We need 2 most significant bytes here */
1599 bsoc = (u32)bsoc >> 16;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001600 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001601 if (rc < 0) {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001602 pr_err("Error in getting msoc, rc=%d\n", rc);
1603 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001604 }
1605
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001606 fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
1607 msoc, bsoc, chip->health, chip->charge_status,
1608 chip->charge_full);
1609 if (chip->charge_done && !chip->charge_full) {
1610 if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) {
1611 fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n");
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001612 chip->charge_full = true;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001613 /*
1614 * Lower the recharge voltage so that VBAT_LT_RECHG
1615 * signal will not be asserted soon.
1616 */
1617 rc = fg_set_recharge_voltage(chip,
1618 AUTO_RECHG_VOLT_LOW_LIMIT_MV);
1619 if (rc < 0) {
1620 pr_err("Error in reducing recharge voltage, rc=%d\n",
1621 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001622 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001623 }
1624 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001625 fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
1626 msoc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001627 }
1628 } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001629 chip->delta_soc = FULL_CAPACITY - msoc;
1630
1631 /*
1632 * We're spreading out the delta SOC over every 10% change
1633 * in monotonic SOC. We cannot spread more than 9% in the
1634 * range of 0-100 skipping the first 10%.
1635 */
1636 if (chip->delta_soc > 9) {
1637 chip->delta_soc = 0;
1638 chip->maint_soc = 0;
1639 } else {
1640 chip->maint_soc = FULL_CAPACITY;
1641 chip->last_msoc = msoc;
1642 }
1643
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001644 chip->charge_full = false;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001645
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001646 /*
1647 * Raise the recharge voltage so that VBAT_LT_RECHG signal
1648 * will be asserted soon as battery SOC had dropped below
1649 * the recharge SOC threshold.
1650 */
1651 rc = fg_set_recharge_voltage(chip,
1652 chip->dt.recharge_volt_thr_mv);
1653 if (rc < 0) {
1654 pr_err("Error in setting recharge voltage, rc=%d\n",
1655 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001656 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001657 }
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001658 fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d delta_soc: %d\n",
1659 bsoc >> 8, recharge_soc, chip->delta_soc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001660 } else {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001661 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001662 }
1663
1664 if (!chip->charge_full)
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001665 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001666
1667 /*
1668 * During JEITA conditions, charge_full can happen early. FULL_SOC
1669 * and MONOTONIC_SOC needs to be updated to reflect the same. Write
1670 * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
1671 */
1672 rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
1673 FG_IMA_ATOMIC);
1674 if (rc < 0) {
1675 pr_err("failed to write full_soc rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001676 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001677 }
1678
1679 rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
1680 full_soc, 2, FG_IMA_ATOMIC);
1681 if (rc < 0) {
1682 pr_err("failed to write monotonic_soc rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001683 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001684 }
1685
1686 fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001687out:
1688 mutex_unlock(&chip->charge_full_lock);
1689 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001690}
1691
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001692#define RCONN_CONFIG_BIT BIT(0)
1693static int fg_rconn_config(struct fg_chip *chip)
1694{
1695 int rc, esr_uohms;
1696 u64 scaling_factor;
1697 u32 val = 0;
1698
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07001699 if (!chip->dt.rconn_mohms)
1700 return 0;
1701
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001702 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
1703 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1704 if (rc < 0) {
1705 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
1706 return rc;
1707 }
1708
1709 if (val & RCONN_CONFIG_BIT) {
1710 fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
1711 return 0;
1712 }
1713
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08001714 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001715 if (rc < 0) {
1716 pr_err("failed to get ESR, rc=%d\n", rc);
1717 return rc;
1718 }
1719
1720 scaling_factor = div64_u64((u64)esr_uohms * 1000,
1721 esr_uohms + (chip->dt.rconn_mohms * 1000));
1722
1723 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
1724 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1725 if (rc < 0) {
1726 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1727 return rc;
1728 }
1729
1730 val *= scaling_factor;
1731 do_div(val, 1000);
1732 rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
1733 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1734 if (rc < 0) {
1735 pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1736 return rc;
1737 }
1738 fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
1739
1740 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
1741 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1742 if (rc < 0) {
1743 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1744 return rc;
1745 }
1746
1747 val *= scaling_factor;
1748 do_div(val, 1000);
1749 rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
1750 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1751 if (rc < 0) {
1752 pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1753 return rc;
1754 }
1755 fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
1756 val & 0xFF);
1757
1758 val = RCONN_CONFIG_BIT;
1759 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
1760 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1761 if (rc < 0) {
1762 pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
1763 return rc;
1764 }
1765
1766 return 0;
1767}
1768
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08001769static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
1770{
1771 u8 buf[2];
1772 int rc;
1773
1774 if (volt_uv <= 0 || volt_uv > 15590000) {
1775 pr_err("Invalid voltage %d\n", volt_uv);
1776 return -EINVAL;
1777 }
1778
1779 fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
1780
1781 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
1782 chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
1783 chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
1784 if (rc < 0) {
1785 pr_err("Error in writing vbatt_full, rc=%d\n", rc);
1786 return rc;
1787 }
1788
1789 return 0;
1790}
1791
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001792static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
1793{
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001794 u8 buf;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001795 int rc;
1796
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001797 if (!chip->dt.auto_recharge_soc)
1798 return 0;
1799
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001800 if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY)
1801 return 0;
1802
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001803 fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001804 rc = fg_sram_write(chip,
1805 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001806 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001807 chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
1808 if (rc < 0) {
1809 pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
1810 return rc;
1811 }
1812
1813 return 0;
1814}
1815
1816static int fg_adjust_recharge_soc(struct fg_chip *chip)
1817{
1818 int rc, msoc, recharge_soc, new_recharge_soc = 0;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001819 bool recharge_soc_status;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001820
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001821 if (!chip->dt.auto_recharge_soc)
1822 return 0;
1823
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001824 recharge_soc = chip->dt.recharge_soc_thr;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001825 recharge_soc_status = chip->recharge_soc_adjusted;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001826 /*
1827 * If the input is present and charging had been terminated, adjust
1828 * the recharge SOC threshold based on the monotonic SOC at which
1829 * the charge termination had happened.
1830 */
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001831 if (is_input_present(chip)) {
1832 if (chip->charge_done) {
1833 if (!chip->recharge_soc_adjusted) {
1834 /* Get raw monotonic SOC for calculation */
1835 rc = fg_get_msoc(chip, &msoc);
1836 if (rc < 0) {
1837 pr_err("Error in getting msoc, rc=%d\n",
1838 rc);
1839 return rc;
1840 }
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001841
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001842 /* Adjust the recharge_soc threshold */
1843 new_recharge_soc = msoc - (FULL_CAPACITY -
1844 recharge_soc);
1845 chip->recharge_soc_adjusted = true;
1846 } else {
1847 /* adjusted already, do nothing */
1848 return 0;
1849 }
1850 } else {
1851 /* Charging, do nothing */
1852 return 0;
1853 }
1854 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001855 /* Restore the default value */
1856 new_recharge_soc = recharge_soc;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001857 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001858 }
1859
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001860 rc = fg_set_recharge_soc(chip, new_recharge_soc);
1861 if (rc < 0) {
1862 chip->recharge_soc_adjusted = recharge_soc_status;
1863 pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
1864 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001865 }
1866
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001867 fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001868 return 0;
1869}
1870
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08001871static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
1872{
1873 enum slope_limit_status status;
1874 int rc;
1875 u8 buf;
1876
1877 if (!chip->slope_limit_en)
1878 return 0;
1879
1880 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
1881 chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
1882 if (batt_temp < chip->dt.slope_limit_temp)
1883 status = LOW_TEMP_CHARGE;
1884 else
1885 status = HIGH_TEMP_CHARGE;
1886 } else {
1887 if (batt_temp < chip->dt.slope_limit_temp)
1888 status = LOW_TEMP_DISCHARGE;
1889 else
1890 status = HIGH_TEMP_DISCHARGE;
1891 }
1892
1893 if (chip->slope_limit_sts == status)
1894 return 0;
1895
1896 fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
1897 chip->dt.slope_limit_coeffs[status], &buf);
1898 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
1899 chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
1900 chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
1901 if (rc < 0) {
1902 pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
1903 rc);
1904 return rc;
1905 }
1906
1907 chip->slope_limit_sts = status;
1908 fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
1909 buf);
1910 return 0;
1911}
1912
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001913static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
1914{
1915 u8 esr_tight_lt_flt, esr_broad_lt_flt;
1916 bool cold_temp = false;
1917 int rc;
1918
1919 /*
1920 * If the battery temperature is lower than -20 C, then skip modifying
1921 * ESR filter.
1922 */
1923 if (batt_temp < -210)
1924 return 0;
1925
1926 /*
1927 * If battery temperature is lesser than 10 C (default), then apply the
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001928 * ESR low temperature tight and broad filter values to ESR room
1929 * temperature tight and broad filters. If battery temperature is higher
1930 * than 10 C, then apply back the room temperature ESR filter
1931 * coefficients to ESR room temperature tight and broad filters.
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001932 */
1933 if (batt_temp > chip->dt.esr_flt_switch_temp
1934 && chip->esr_flt_cold_temp_en) {
1935 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001936 chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
1937 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
1938 chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001939 } else if (batt_temp <= chip->dt.esr_flt_switch_temp
1940 && !chip->esr_flt_cold_temp_en) {
1941 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
1942 chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
1943 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
1944 chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001945 cold_temp = true;
1946 } else {
1947 return 0;
1948 }
1949
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001950 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
1951 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
1952 &esr_tight_lt_flt,
1953 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001954 if (rc < 0) {
1955 pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
1956 return rc;
1957 }
1958
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001959 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
1960 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
1961 &esr_broad_lt_flt,
1962 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001963 if (rc < 0) {
1964 pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
1965 return rc;
1966 }
1967
1968 chip->esr_flt_cold_temp_en = cold_temp;
1969 fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n",
1970 cold_temp ? "cold" : "normal");
1971 return 0;
1972}
1973
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001974static int fg_esr_fcc_config(struct fg_chip *chip)
1975{
1976 union power_supply_propval prop = {0, };
1977 int rc;
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07001978 bool parallel_en = false, qnovo_en = false;
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001979
1980 if (is_parallel_charger_available(chip)) {
1981 rc = power_supply_get_property(chip->parallel_psy,
1982 POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop);
1983 if (rc < 0) {
1984 pr_err("Error in reading charging_enabled from parallel_psy, rc=%d\n",
1985 rc);
1986 return rc;
1987 }
1988 parallel_en = prop.intval;
1989 }
1990
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07001991 rc = power_supply_get_property(chip->batt_psy,
1992 POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, &prop);
1993 if (!rc)
1994 qnovo_en = prop.intval;
1995
1996 fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
1997 chip->charge_status, parallel_en, qnovo_en,
1998 chip->esr_fcc_ctrl_en);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001999
Nicholas Troast1769fd32016-09-07 09:20:58 -07002000 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002001 (parallel_en || qnovo_en)) {
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002002 if (chip->esr_fcc_ctrl_en)
2003 return 0;
2004
2005 /*
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002006 * When parallel charging or Qnovo is enabled, configure ESR
2007 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
2008 * request the main charger to increase FCC when it is supposed
2009 * to decrease it.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002010 */
2011 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2012 ESR_FAST_CRG_IVAL_MASK |
2013 ESR_FAST_CRG_CTL_EN_BIT,
2014 ESR_FCC_300MA | ESR_FAST_CRG_CTL_EN_BIT);
2015 if (rc < 0) {
2016 pr_err("Error in writing to %04x, rc=%d\n",
2017 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2018 return rc;
2019 }
2020
2021 chip->esr_fcc_ctrl_en = true;
2022 } else {
2023 if (!chip->esr_fcc_ctrl_en)
2024 return 0;
2025
2026 /*
2027 * If we're here, then it means either the device is not in
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002028 * charging state or parallel charging / Qnovo is disabled.
2029 * Disable ESR fast charge current control in SW.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002030 */
2031 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2032 ESR_FAST_CRG_CTL_EN_BIT, 0);
2033 if (rc < 0) {
2034 pr_err("Error in writing to %04x, rc=%d\n",
2035 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2036 return rc;
2037 }
2038
2039 chip->esr_fcc_ctrl_en = false;
2040 }
2041
2042 fg_dbg(chip, FG_STATUS, "esr_fcc_ctrl_en set to %d\n",
2043 chip->esr_fcc_ctrl_en);
2044 return 0;
2045}
2046
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002047static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
2048{
2049 int rc, cycles_init, cycles_max;
2050 bool end_of_charge = false;
2051
2052 end_of_charge = is_input_present(chip) && chip->charge_done;
2053 fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
2054
2055 /* ESR discharging timer configuration */
2056 cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
2057 chip->dt.esr_timer_awake[TIMER_RETRY];
2058 if (end_of_charge)
2059 cycles_init = 0;
2060
2061 cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
2062 chip->dt.esr_timer_awake[TIMER_MAX];
2063
2064 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
2065 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2066 if (rc < 0) {
2067 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2068 return rc;
2069 }
2070
2071 /* ESR charging timer configuration */
2072 cycles_init = cycles_max = -EINVAL;
2073 if (end_of_charge || sleep) {
2074 cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
2075 cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
2076 } else if (is_input_present(chip)) {
2077 cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
2078 cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
2079 }
2080
2081 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
2082 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2083 if (rc < 0) {
2084 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2085 return rc;
2086 }
2087
2088 return 0;
2089}
2090
Nicholas Troast1769fd32016-09-07 09:20:58 -07002091static void fg_batt_avg_update(struct fg_chip *chip)
2092{
2093 if (chip->charge_status == chip->prev_charge_status)
2094 return;
2095
2096 cancel_delayed_work_sync(&chip->batt_avg_work);
2097 fg_circ_buf_clr(&chip->ibatt_circ_buf);
2098 fg_circ_buf_clr(&chip->vbatt_circ_buf);
2099
2100 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
2101 chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
2102 schedule_delayed_work(&chip->batt_avg_work,
2103 msecs_to_jiffies(2000));
2104}
2105
Nicholas Troaste29dec92016-08-24 09:35:11 -07002106static void status_change_work(struct work_struct *work)
2107{
2108 struct fg_chip *chip = container_of(work,
2109 struct fg_chip, status_change_work);
2110 union power_supply_propval prop = {0, };
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002111 int rc, batt_temp;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002112
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002113 if (!batt_psy_initialized(chip)) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002114 fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002115 goto out;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002116 }
2117
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002118 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
Nicholas Troaste29dec92016-08-24 09:35:11 -07002119 &prop);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002120 if (rc < 0) {
2121 pr_err("Error in getting charging status, rc=%d\n", rc);
2122 goto out;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002123 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002124
Nicholas Troast1769fd32016-09-07 09:20:58 -07002125 chip->prev_charge_status = chip->charge_status;
2126 chip->charge_status = prop.intval;
2127 rc = power_supply_get_property(chip->batt_psy,
2128 POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
2129 if (rc < 0) {
2130 pr_err("Error in getting charge type, rc=%d\n", rc);
2131 goto out;
2132 }
2133
2134 chip->charge_type = prop.intval;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002135 rc = power_supply_get_property(chip->batt_psy,
2136 POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
2137 if (rc < 0) {
2138 pr_err("Error in getting charge_done, rc=%d\n", rc);
2139 goto out;
2140 }
2141
2142 chip->charge_done = prop.intval;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002143 if (chip->cyc_ctr.en)
2144 schedule_work(&chip->cycle_count_work);
2145
2146 fg_cap_learning_update(chip);
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07002147
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002148 rc = fg_charge_full_update(chip);
2149 if (rc < 0)
2150 pr_err("Error in charge_full_update, rc=%d\n", rc);
2151
2152 rc = fg_adjust_recharge_soc(chip);
2153 if (rc < 0)
2154 pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002155
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07002156 rc = fg_adjust_ki_coeff_dischg(chip);
2157 if (rc < 0)
2158 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002159
2160 rc = fg_esr_fcc_config(chip);
2161 if (rc < 0)
2162 pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002163
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002164 rc = fg_esr_timer_config(chip, false);
2165 if (rc < 0)
2166 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
2167
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002168 rc = fg_get_battery_temp(chip, &batt_temp);
2169 if (!rc) {
2170 rc = fg_slope_limit_config(chip, batt_temp);
2171 if (rc < 0)
2172 pr_err("Error in configuring slope limiter rc:%d\n",
2173 rc);
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07002174
2175 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
2176 if (rc < 0)
2177 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
2178 rc);
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002179 }
2180
Nicholas Troast1769fd32016-09-07 09:20:58 -07002181 fg_batt_avg_update(chip);
2182
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002183out:
Nicholas Troast1769fd32016-09-07 09:20:58 -07002184 fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
2185 chip->charge_status, chip->charge_type, chip->charge_done);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002186 pm_relax(chip->dev);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002187}
2188
2189static void restore_cycle_counter(struct fg_chip *chip)
2190{
2191 int rc = 0, i;
2192 u8 data[2];
2193
2194 mutex_lock(&chip->cyc_ctr.lock);
2195 for (i = 0; i < BUCKET_COUNT; i++) {
2196 rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
2197 CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
2198 FG_IMA_DEFAULT);
2199 if (rc < 0)
2200 pr_err("failed to read bucket %d rc=%d\n", i, rc);
2201 else
2202 chip->cyc_ctr.count[i] = data[0] | data[1] << 8;
2203 }
2204 mutex_unlock(&chip->cyc_ctr.lock);
2205}
2206
2207static void clear_cycle_counter(struct fg_chip *chip)
2208{
2209 int rc = 0, i;
2210
2211 if (!chip->cyc_ctr.en)
2212 return;
2213
2214 mutex_lock(&chip->cyc_ctr.lock);
2215 memset(chip->cyc_ctr.count, 0, sizeof(chip->cyc_ctr.count));
2216 for (i = 0; i < BUCKET_COUNT; i++) {
2217 chip->cyc_ctr.started[i] = false;
2218 chip->cyc_ctr.last_soc[i] = 0;
2219 }
2220 rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET,
2221 (u8 *)&chip->cyc_ctr.count,
2222 sizeof(chip->cyc_ctr.count) / sizeof(u8 *),
2223 FG_IMA_DEFAULT);
2224 if (rc < 0)
2225 pr_err("failed to clear cycle counter rc=%d\n", rc);
2226
2227 mutex_unlock(&chip->cyc_ctr.lock);
2228}
2229
2230static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
2231{
2232 int rc = 0;
2233 u16 cyc_count;
2234 u8 data[2];
2235
2236 if (bucket < 0 || (bucket > BUCKET_COUNT - 1))
2237 return 0;
2238
2239 cyc_count = chip->cyc_ctr.count[bucket];
2240 cyc_count++;
2241 data[0] = cyc_count & 0xFF;
2242 data[1] = cyc_count >> 8;
2243
2244 rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
2245 CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
2246 FG_IMA_DEFAULT);
2247 if (rc < 0)
2248 pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
2249 bucket, rc);
2250 else
2251 chip->cyc_ctr.count[bucket] = cyc_count;
2252 return rc;
2253}
2254
2255static void cycle_count_work(struct work_struct *work)
2256{
2257 int rc = 0, bucket, i, batt_soc;
2258 struct fg_chip *chip = container_of(work,
2259 struct fg_chip,
2260 cycle_count_work);
2261
2262 mutex_lock(&chip->cyc_ctr.lock);
2263 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
2264 if (rc < 0) {
2265 pr_err("Failed to read battery soc rc: %d\n", rc);
2266 goto out;
2267 }
2268
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002269 /* We need only the most significant byte here */
2270 batt_soc = (u32)batt_soc >> 24;
2271
Nicholas Troast1769fd32016-09-07 09:20:58 -07002272 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002273 /* Find out which bucket the SOC falls in */
2274 bucket = batt_soc / BUCKET_SOC_PCT;
2275 pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
2276
2277 /*
2278 * If we've started counting for the previous bucket,
2279 * then store the counter for that bucket if the
2280 * counter for current bucket is getting started.
2281 */
2282 if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
2283 !chip->cyc_ctr.started[bucket]) {
2284 rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
2285 if (rc < 0) {
2286 pr_err("Error in storing cycle_ctr rc: %d\n",
2287 rc);
2288 goto out;
2289 } else {
2290 chip->cyc_ctr.started[bucket - 1] = false;
2291 chip->cyc_ctr.last_soc[bucket - 1] = 0;
2292 }
2293 }
2294 if (!chip->cyc_ctr.started[bucket]) {
2295 chip->cyc_ctr.started[bucket] = true;
2296 chip->cyc_ctr.last_soc[bucket] = batt_soc;
2297 }
2298 } else {
2299 for (i = 0; i < BUCKET_COUNT; i++) {
2300 if (chip->cyc_ctr.started[i] &&
2301 batt_soc > chip->cyc_ctr.last_soc[i]) {
2302 rc = fg_inc_store_cycle_ctr(chip, i);
2303 if (rc < 0)
2304 pr_err("Error in storing cycle_ctr rc: %d\n",
2305 rc);
2306 chip->cyc_ctr.last_soc[i] = 0;
2307 }
2308 chip->cyc_ctr.started[i] = false;
2309 }
2310 }
2311out:
2312 mutex_unlock(&chip->cyc_ctr.lock);
2313}
2314
2315static int fg_get_cycle_count(struct fg_chip *chip)
2316{
2317 int count;
2318
2319 if (!chip->cyc_ctr.en)
2320 return 0;
2321
2322 if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT))
2323 return -EINVAL;
2324
2325 mutex_lock(&chip->cyc_ctr.lock);
2326 count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1];
2327 mutex_unlock(&chip->cyc_ctr.lock);
2328 return count;
2329}
2330
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002331static int fg_bp_params_config(struct fg_chip *chip)
2332{
2333 int rc = 0;
2334 u8 buf;
2335
2336 /* This SRAM register is only present in v2.0 and above */
2337 if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
2338 chip->bp.float_volt_uv > 0) {
2339 fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
2340 chip->bp.float_volt_uv / 1000, &buf);
2341 rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
2342 chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
2343 chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
2344 if (rc < 0) {
2345 pr_err("Error in writing float_volt, rc=%d\n", rc);
2346 return rc;
2347 }
2348 }
2349
2350 if (chip->bp.vbatt_full_mv > 0) {
2351 rc = fg_set_constant_chg_voltage(chip,
2352 chip->bp.vbatt_full_mv * 1000);
2353 if (rc < 0)
2354 return rc;
2355 }
2356
2357 return rc;
2358}
2359
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002360#define PROFILE_LOAD_BIT BIT(0)
2361#define BOOTLOADER_LOAD_BIT BIT(1)
2362#define BOOTLOADER_RESTART_BIT BIT(2)
2363#define HLOS_RESTART_BIT BIT(3)
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002364static bool is_profile_load_required(struct fg_chip *chip)
2365{
Nicholas Troaste29dec92016-08-24 09:35:11 -07002366 u8 buf[PROFILE_COMP_LEN], val;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002367 bool profiles_same = false;
2368 int rc;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002369
Nicholas Troaste29dec92016-08-24 09:35:11 -07002370 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
2371 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2372 if (rc < 0) {
2373 pr_err("failed to read profile integrity rc=%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002374 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002375 }
2376
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002377 /* Check if integrity bit is set */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002378 if (val & PROFILE_LOAD_BIT) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002379 fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
Subbaraman Narayanamurthy73616e12017-03-20 14:37:54 -07002380
2381 /* Whitelist the values */
2382 val &= ~PROFILE_LOAD_BIT;
2383 if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
2384 val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
2385 val |= PROFILE_LOAD_BIT;
2386 pr_warn("Garbage value in profile integrity word: 0x%x\n",
2387 val);
2388 return true;
2389 }
2390
Nicholas Troaste29dec92016-08-24 09:35:11 -07002391 rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2392 buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
2393 if (rc < 0) {
2394 pr_err("Error in reading battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002395 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002396 }
2397 profiles_same = memcmp(chip->batt_profile, buf,
2398 PROFILE_COMP_LEN) == 0;
2399 if (profiles_same) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002400 fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
2401 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002402 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002403
2404 if (!chip->dt.force_load_profile) {
2405 pr_warn("Profiles doesn't match, skipping loading it since force_load_profile is disabled\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002406 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002407 pr_info("FG: loaded profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002408 dump_sram(buf, PROFILE_LOAD_WORD,
2409 PROFILE_COMP_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002410 pr_info("FG: available profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002411 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2412 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002413 }
2414 return false;
2415 }
2416
2417 fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n");
2418 } else {
2419 fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002420 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002421 pr_info("FG: profile to be loaded:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002422 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2423 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002424 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002425 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002426 return true;
2427}
2428
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08002429static void clear_battery_profile(struct fg_chip *chip)
2430{
2431 u8 val = 0;
2432 int rc;
2433
2434 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2435 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2436 if (rc < 0)
2437 pr_err("failed to write profile integrity rc=%d\n", rc);
2438}
2439
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002440#define SOC_READY_WAIT_MS 2000
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002441static int __fg_restart(struct fg_chip *chip)
2442{
2443 int rc, msoc;
2444 bool tried_again = false;
2445
2446 rc = fg_get_prop_capacity(chip, &msoc);
2447 if (rc < 0) {
2448 pr_err("Error in getting capacity, rc=%d\n", rc);
2449 return rc;
2450 }
2451
2452 chip->last_soc = msoc;
2453 chip->fg_restarting = true;
2454 reinit_completion(&chip->soc_ready);
2455 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT,
2456 RESTART_GO_BIT);
2457 if (rc < 0) {
2458 pr_err("Error in writing to %04x, rc=%d\n",
2459 BATT_SOC_RESTART(chip), rc);
2460 goto out;
2461 }
2462
2463wait:
2464 rc = wait_for_completion_interruptible_timeout(&chip->soc_ready,
2465 msecs_to_jiffies(SOC_READY_WAIT_MS));
2466
2467 /* If we were interrupted wait again one more time. */
2468 if (rc == -ERESTARTSYS && !tried_again) {
2469 tried_again = true;
2470 goto wait;
2471 } else if (rc <= 0) {
2472 pr_err("wait for soc_ready timed out rc=%d\n", rc);
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002473 }
2474
2475 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2476 if (rc < 0) {
2477 pr_err("Error in writing to %04x, rc=%d\n",
2478 BATT_SOC_RESTART(chip), rc);
2479 goto out;
2480 }
2481out:
2482 chip->fg_restarting = false;
2483 return rc;
2484}
2485
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002486static void profile_load_work(struct work_struct *work)
2487{
2488 struct fg_chip *chip = container_of(work,
2489 struct fg_chip,
2490 profile_load_work.work);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002491 u8 buf[2], val;
2492 int rc;
2493
2494 vote(chip->awake_votable, PROFILE_LOAD, true, 0);
2495 if (!is_profile_load_required(chip))
2496 goto done;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002497
2498 clear_cycle_counter(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002499 mutex_lock(&chip->cl.lock);
2500 chip->cl.learned_cc_uah = 0;
2501 chip->cl.active = false;
2502 mutex_unlock(&chip->cl.lock);
2503
Nicholas Troaste29dec92016-08-24 09:35:11 -07002504 fg_dbg(chip, FG_STATUS, "profile loading started\n");
2505 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2506 if (rc < 0) {
2507 pr_err("Error in writing to %04x, rc=%d\n",
2508 BATT_SOC_RESTART(chip), rc);
2509 goto out;
2510 }
2511
2512 /* load battery profile */
2513 rc = fg_sram_write(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2514 chip->batt_profile, PROFILE_LEN, FG_IMA_ATOMIC);
2515 if (rc < 0) {
2516 pr_err("Error in writing battery profile, rc:%d\n", rc);
2517 goto out;
2518 }
2519
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002520 rc = __fg_restart(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002521 if (rc < 0) {
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002522 pr_err("Error in restarting FG, rc=%d\n", rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002523 goto out;
2524 }
2525
2526 fg_dbg(chip, FG_STATUS, "SOC is ready\n");
2527
2528 /* Set the profile integrity bit */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002529 val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002530 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2531 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2532 if (rc < 0) {
2533 pr_err("failed to write profile integrity rc=%d\n", rc);
2534 goto out;
2535 }
2536
Nicholas Troaste29dec92016-08-24 09:35:11 -07002537done:
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002538 rc = fg_bp_params_config(chip);
2539 if (rc < 0)
2540 pr_err("Error in configuring battery profile params, rc:%d\n",
2541 rc);
2542
Nicholas Troaste29dec92016-08-24 09:35:11 -07002543 rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
2544 FG_IMA_DEFAULT);
2545 if (rc < 0) {
2546 pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD,
2547 NOM_CAP_OFFSET, rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002548 } else {
2549 chip->cl.nom_cap_uah = (int)(buf[0] | buf[1] << 8) * 1000;
2550 rc = fg_load_learned_cap_from_sram(chip);
2551 if (rc < 0)
2552 pr_err("Error in loading capacity learning data, rc:%d\n",
2553 rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002554 }
2555
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002556 batt_psy_initialized(chip);
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07002557 fg_notify_charger(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002558 chip->profile_loaded = true;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08002559 chip->soc_reporting_ready = true;
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002560 fg_dbg(chip, FG_STATUS, "profile loaded successfully");
Nicholas Troaste29dec92016-08-24 09:35:11 -07002561out:
2562 vote(chip->awake_votable, PROFILE_LOAD, false, 0);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002563}
2564
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002565static void sram_dump_work(struct work_struct *work)
2566{
2567 struct fg_chip *chip = container_of(work, struct fg_chip,
2568 sram_dump_work.work);
2569 u8 buf[FG_SRAM_LEN];
2570 int rc;
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302571 s64 timestamp_ms, quotient;
2572 s32 remainder;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002573
2574 rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
2575 if (rc < 0) {
2576 pr_err("Error in reading FG SRAM, rc:%d\n", rc);
2577 goto resched;
2578 }
2579
2580 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302581 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2582 fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
2583 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002584 dump_sram(buf, 0, FG_SRAM_LEN);
2585 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302586 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2587 fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
2588 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002589resched:
2590 schedule_delayed_work(&chip->sram_dump_work,
2591 msecs_to_jiffies(fg_sram_dump_period_ms));
2592}
2593
2594static int fg_sram_dump_sysfs(const char *val, const struct kernel_param *kp)
2595{
2596 int rc;
2597 struct power_supply *bms_psy;
2598 struct fg_chip *chip;
2599 bool old_val = fg_sram_dump;
2600
2601 rc = param_set_bool(val, kp);
2602 if (rc) {
2603 pr_err("Unable to set fg_sram_dump: %d\n", rc);
2604 return rc;
2605 }
2606
2607 if (fg_sram_dump == old_val)
2608 return 0;
2609
2610 bms_psy = power_supply_get_by_name("bms");
2611 if (!bms_psy) {
2612 pr_err("bms psy not found\n");
2613 return -ENODEV;
2614 }
2615
2616 chip = power_supply_get_drvdata(bms_psy);
2617 if (fg_sram_dump)
2618 schedule_delayed_work(&chip->sram_dump_work,
2619 msecs_to_jiffies(fg_sram_dump_period_ms));
2620 else
2621 cancel_delayed_work_sync(&chip->sram_dump_work);
2622
2623 return 0;
2624}
2625
2626static struct kernel_param_ops fg_sram_dump_ops = {
2627 .set = fg_sram_dump_sysfs,
2628 .get = param_get_bool,
2629};
2630
2631module_param_cb(sram_dump_en, &fg_sram_dump_ops, &fg_sram_dump, 0644);
2632
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002633static int fg_restart_sysfs(const char *val, const struct kernel_param *kp)
2634{
2635 int rc;
2636 struct power_supply *bms_psy;
2637 struct fg_chip *chip;
2638
2639 rc = param_set_int(val, kp);
2640 if (rc) {
2641 pr_err("Unable to set fg_restart: %d\n", rc);
2642 return rc;
2643 }
2644
2645 if (fg_restart != 1) {
2646 pr_err("Bad value %d\n", fg_restart);
2647 return -EINVAL;
2648 }
2649
2650 bms_psy = power_supply_get_by_name("bms");
2651 if (!bms_psy) {
2652 pr_err("bms psy not found\n");
2653 return 0;
2654 }
2655
2656 chip = power_supply_get_drvdata(bms_psy);
2657 rc = __fg_restart(chip);
2658 if (rc < 0) {
2659 pr_err("Error in restarting FG, rc=%d\n", rc);
2660 return rc;
2661 }
2662
2663 pr_info("FG restart done\n");
2664 return rc;
2665}
2666
2667static struct kernel_param_ops fg_restart_ops = {
2668 .set = fg_restart_sysfs,
2669 .get = param_get_int,
2670};
2671
2672module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
2673
Nicholas Troast1769fd32016-09-07 09:20:58 -07002674#define BATT_AVG_POLL_PERIOD_MS 10000
2675static void batt_avg_work(struct work_struct *work)
2676{
2677 struct fg_chip *chip = container_of(work, struct fg_chip,
2678 batt_avg_work.work);
2679 int rc, ibatt_now, vbatt_now;
2680
2681 mutex_lock(&chip->batt_avg_lock);
2682 rc = fg_get_battery_current(chip, &ibatt_now);
2683 if (rc < 0) {
2684 pr_err("failed to get battery current, rc=%d\n", rc);
2685 goto reschedule;
2686 }
2687
2688 rc = fg_get_battery_voltage(chip, &vbatt_now);
2689 if (rc < 0) {
2690 pr_err("failed to get battery voltage, rc=%d\n", rc);
2691 goto reschedule;
2692 }
2693
2694 fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now);
2695 fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now);
2696
2697reschedule:
2698 mutex_unlock(&chip->batt_avg_lock);
2699 schedule_delayed_work(&chip->batt_avg_work,
2700 msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS));
2701}
2702
Nicholas Troast1769fd32016-09-07 09:20:58 -07002703#define HOURS_TO_SECONDS 3600
2704#define OCV_SLOPE_UV 10869
2705#define MILLI_UNIT 1000
2706#define MICRO_UNIT 1000000
2707static int fg_get_time_to_full(struct fg_chip *chip, int *val)
2708{
2709 int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc,
2710 act_cap_uah;
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002711 s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002712 s64 t_predicted_cc = 0, t_predicted_cv = 0;
2713
2714 if (chip->bp.float_volt_uv <= 0) {
2715 pr_err("battery profile is not loaded\n");
2716 return -ENODATA;
2717 }
2718
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002719 if (!batt_psy_initialized(chip)) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07002720 fg_dbg(chip, FG_TTF, "charger is not available\n");
2721 return -ENODATA;
2722 }
2723
Nicholas Troast32a22d32016-12-14 16:12:04 -08002724 rc = fg_get_prop_capacity(chip, &msoc);
2725 if (rc < 0) {
2726 pr_err("failed to get msoc rc=%d\n", rc);
2727 return rc;
2728 }
2729 fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
2730
2731 if (msoc >= 100) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07002732 *val = 0;
2733 return 0;
2734 }
2735
2736 mutex_lock(&chip->batt_avg_lock);
2737 rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
2738 if (rc < 0) {
2739 /* try to get instantaneous current */
2740 rc = fg_get_battery_current(chip, &ibatt_avg);
2741 if (rc < 0) {
2742 mutex_unlock(&chip->batt_avg_lock);
2743 pr_err("failed to get battery current, rc=%d\n", rc);
2744 return rc;
2745 }
2746 }
2747
2748 rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg);
2749 if (rc < 0) {
2750 /* try to get instantaneous voltage */
2751 rc = fg_get_battery_voltage(chip, &vbatt_avg);
2752 if (rc < 0) {
2753 mutex_unlock(&chip->batt_avg_lock);
2754 pr_err("failed to get battery voltage, rc=%d\n", rc);
2755 return rc;
2756 }
2757 }
2758
2759 mutex_unlock(&chip->batt_avg_lock);
2760 fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
2761
2762 /* clamp ibatt_avg to -150mA */
2763 if (ibatt_avg > -150000)
2764 ibatt_avg = -150000;
2765 fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
2766
2767 /* reverse polarity to be consistent with unsigned current settings */
2768 ibatt_avg = abs(ibatt_avg);
2769
2770 /* estimated battery current at the CC to CV transition */
2771 i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv);
2772 fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
2773
2774 rc = fg_get_battery_resistance(chip, &rbatt);
2775 if (rc < 0) {
2776 pr_err("failed to get battery resistance rc=%d\n", rc);
2777 return rc;
2778 }
2779
2780 /* clamp rbatt to 50mOhms */
2781 if (rbatt < 50000)
2782 rbatt = 50000;
2783
2784 fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
2785
2786 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
2787 if (rc < 0) {
2788 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
2789 return rc;
2790 }
2791 act_cap_uah *= MILLI_UNIT;
2792 fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah);
2793
Nicholas Troast1769fd32016-09-07 09:20:58 -07002794 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
2795 if (rc < 0) {
2796 pr_err("failed to get full soc rc=%d\n", rc);
2797 return rc;
2798 }
2799 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
2800 FULL_SOC_RAW);
2801 fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc);
2802
2803 /* if we are already in CV state then we can skip estimating CC */
2804 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
2805 goto skip_cc_estimate;
2806
2807 /* if the charger is current limited then use power approximation */
2808 if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000)
2809 ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT);
2810 else
2811 ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT);
2812 ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv;
2813 fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv);
2814
2815 soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV);
2816 /* estimated SOC at the CC to CV transition */
2817 soc_cc2cv = 100 - soc_cc2cv;
2818 fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
2819
2820 /* the esimated SOC may be lower than the current SOC */
2821 if (soc_cc2cv - msoc <= 0)
2822 goto skip_cc_estimate;
2823
2824 t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100);
2825 t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100);
2826 t_predicted_cc *= HOURS_TO_SECONDS;
2827 t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2);
2828
2829skip_cc_estimate:
2830 fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc);
2831
2832 /* CV estimate starts here */
Nicholas Troast32a22d32016-12-14 16:12:04 -08002833 if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER)
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002834 ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002835 else
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002836 ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200);
2837
2838 if (msoc < 95)
2839 centi_tau_scale = 100;
2840 else
2841 centi_tau_scale = 20 * (100 - msoc);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002842
2843 fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val);
2844 rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val);
2845 fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val);
2846 t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT);
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002847 t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002848 t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT);
2849 t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT);
2850 fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv);
2851 *val = t_predicted_cc + t_predicted_cv;
2852 return 0;
2853}
2854
2855#define CENTI_ICORRECT_C0 105
2856#define CENTI_ICORRECT_C1 20
2857static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
2858{
2859 int rc, ibatt_avg, msoc, act_cap_uah;
2860 s32 divisor;
2861 s64 t_predicted;
2862
2863 rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
2864 if (rc < 0) {
2865 /* try to get instantaneous current */
2866 rc = fg_get_battery_current(chip, &ibatt_avg);
2867 if (rc < 0) {
2868 pr_err("failed to get battery current, rc=%d\n", rc);
2869 return rc;
2870 }
2871 }
2872
2873 /* clamp ibatt_avg to 150mA */
2874 if (ibatt_avg < 150000)
2875 ibatt_avg = 150000;
2876
2877 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
2878 if (rc < 0) {
2879 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
2880 return rc;
2881 }
2882 act_cap_uah *= MILLI_UNIT;
2883
2884 rc = fg_get_prop_capacity(chip, &msoc);
2885 if (rc < 0) {
2886 pr_err("Error in getting capacity, rc=%d\n", rc);
2887 return rc;
2888 }
2889
2890 t_predicted = div_s64((s64)msoc * act_cap_uah, 100);
2891 t_predicted *= HOURS_TO_SECONDS;
2892 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
2893 divisor = div_s64((s64)divisor * ibatt_avg, 10000);
2894 if (divisor > 0)
2895 t_predicted = div_s64(t_predicted, divisor);
2896
2897 *val = t_predicted;
2898 return 0;
2899}
2900
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08002901static int fg_update_maint_soc(struct fg_chip *chip)
2902{
2903 int rc = 0, msoc;
2904
2905 mutex_lock(&chip->charge_full_lock);
2906 if (chip->delta_soc <= 0)
2907 goto out;
2908
2909 rc = fg_get_msoc(chip, &msoc);
2910 if (rc < 0) {
2911 pr_err("Error in getting msoc, rc=%d\n", rc);
2912 goto out;
2913 }
2914
2915 if (msoc > chip->maint_soc) {
2916 /*
2917 * When the monotonic SOC goes above maintenance SOC, we should
2918 * stop showing the maintenance SOC.
2919 */
2920 chip->delta_soc = 0;
2921 chip->maint_soc = 0;
2922 } else if (msoc <= chip->last_msoc) {
2923 /* MSOC is decreasing. Decrease maintenance SOC as well */
2924 chip->maint_soc -= 1;
2925 if (!(msoc % 10)) {
2926 /*
2927 * Reduce the maintenance SOC additionally by 1 whenever
2928 * it crosses a SOC multiple of 10.
2929 */
2930 chip->maint_soc -= 1;
2931 chip->delta_soc -= 1;
2932 }
2933 }
2934
2935 fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
2936 msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
2937 chip->last_msoc = msoc;
2938out:
2939 mutex_unlock(&chip->charge_full_lock);
2940 return rc;
2941}
2942
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08002943static int fg_esr_validate(struct fg_chip *chip)
2944{
2945 int rc, esr_uohms;
2946 u8 buf[2];
2947
2948 if (chip->dt.esr_clamp_mohms <= 0)
2949 return 0;
2950
2951 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
2952 if (rc < 0) {
2953 pr_err("failed to get ESR, rc=%d\n", rc);
2954 return rc;
2955 }
2956
2957 if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) {
2958 pr_debug("ESR %d is > ESR_clamp\n", esr_uohms);
2959 return 0;
2960 }
2961
2962 esr_uohms = chip->dt.esr_clamp_mohms * 1000;
2963 fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf);
2964 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word,
2965 chip->sp[FG_SRAM_ESR].addr_byte, buf,
2966 chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT);
2967 if (rc < 0) {
2968 pr_err("Error in writing ESR, rc=%d\n", rc);
2969 return rc;
2970 }
2971
2972 fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms);
2973 return 0;
2974}
2975
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002976/* PSY CALLBACKS STAY HERE */
2977
2978static int fg_psy_get_property(struct power_supply *psy,
2979 enum power_supply_property psp,
2980 union power_supply_propval *pval)
2981{
2982 struct fg_chip *chip = power_supply_get_drvdata(psy);
2983 int rc = 0;
2984
2985 switch (psp) {
2986 case POWER_SUPPLY_PROP_CAPACITY:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08002987 rc = fg_get_prop_capacity(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002988 break;
2989 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08002990 if (chip->battery_missing)
2991 pval->intval = 3700000;
2992 else
2993 rc = fg_get_battery_voltage(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002994 break;
2995 case POWER_SUPPLY_PROP_CURRENT_NOW:
2996 rc = fg_get_battery_current(chip, &pval->intval);
2997 break;
2998 case POWER_SUPPLY_PROP_TEMP:
2999 rc = fg_get_battery_temp(chip, &pval->intval);
3000 break;
3001 case POWER_SUPPLY_PROP_RESISTANCE:
3002 rc = fg_get_battery_resistance(chip, &pval->intval);
3003 break;
3004 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3005 rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
3006 break;
3007 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003008 pval->intval = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003009 break;
3010 case POWER_SUPPLY_PROP_RESISTANCE_ID:
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08003011 pval->intval = chip->batt_id_ohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003012 break;
3013 case POWER_SUPPLY_PROP_BATTERY_TYPE:
3014 pval->strval = fg_get_battery_type(chip);
3015 break;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003016 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
3017 pval->intval = chip->bp.float_volt_uv;
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07003018 break;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003019 case POWER_SUPPLY_PROP_CYCLE_COUNT:
3020 pval->intval = fg_get_cycle_count(chip);
3021 break;
3022 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3023 pval->intval = chip->cyc_ctr.id;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003024 break;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003025 case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003026 rc = fg_get_charge_raw(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003027 break;
3028 case POWER_SUPPLY_PROP_CHARGE_NOW:
3029 pval->intval = chip->cl.init_cc_uah;
3030 break;
3031 case POWER_SUPPLY_PROP_CHARGE_FULL:
3032 pval->intval = chip->cl.learned_cc_uah;
3033 break;
3034 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003035 rc = fg_get_charge_counter(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003036 break;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003037 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
3038 rc = fg_get_time_to_full(chip, &pval->intval);
3039 break;
3040 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
3041 rc = fg_get_time_to_empty(chip, &pval->intval);
3042 break;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003043 case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
3044 pval->intval = chip->soc_reporting_ready;
3045 break;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303046 case POWER_SUPPLY_PROP_DEBUG_BATTERY:
3047 pval->intval = is_debug_batt_id(chip);
3048 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003049 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3050 rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
3051 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003052 default:
Nicholas Troast1769fd32016-09-07 09:20:58 -07003053 pr_err("unsupported property %d\n", psp);
3054 rc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003055 break;
3056 }
3057
Nicholas Troast1769fd32016-09-07 09:20:58 -07003058 if (rc < 0)
3059 return -ENODATA;
3060
3061 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003062}
3063
3064static int fg_psy_set_property(struct power_supply *psy,
3065 enum power_supply_property psp,
3066 const union power_supply_propval *pval)
3067{
Nicholas Troaste29dec92016-08-24 09:35:11 -07003068 struct fg_chip *chip = power_supply_get_drvdata(psy);
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003069 int rc = 0;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003070
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003071 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003072 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3073 if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) {
3074 chip->cyc_ctr.id = pval->intval;
3075 } else {
3076 pr_err("rejecting invalid cycle_count_id = %d\n",
3077 pval->intval);
3078 return -EINVAL;
3079 }
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003080 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3081 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003082 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003083 default:
3084 break;
3085 }
3086
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003087 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003088}
3089
3090static int fg_property_is_writeable(struct power_supply *psy,
3091 enum power_supply_property psp)
3092{
3093 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003094 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003095 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Nicholas Troaste29dec92016-08-24 09:35:11 -07003096 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003097 default:
3098 break;
3099 }
3100
3101 return 0;
3102}
3103
3104static void fg_external_power_changed(struct power_supply *psy)
3105{
3106 pr_debug("power supply changed\n");
3107}
3108
3109static int fg_notifier_cb(struct notifier_block *nb,
3110 unsigned long event, void *data)
3111{
3112 struct power_supply *psy = data;
3113 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
3114
3115 if (event != PSY_EVENT_PROP_CHANGED)
3116 return NOTIFY_OK;
3117
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08003118 if (work_pending(&chip->status_change_work))
3119 return NOTIFY_OK;
3120
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003121 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003122 || (strcmp(psy->desc->name, "usb") == 0)) {
3123 /*
3124 * We cannot vote for awake votable here as that takes
3125 * a mutex lock and this is executed in an atomic context.
3126 */
3127 pm_stay_awake(chip->dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003128 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003129 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003130
3131 return NOTIFY_OK;
3132}
3133
3134static enum power_supply_property fg_psy_props[] = {
3135 POWER_SUPPLY_PROP_CAPACITY,
3136 POWER_SUPPLY_PROP_TEMP,
3137 POWER_SUPPLY_PROP_VOLTAGE_NOW,
3138 POWER_SUPPLY_PROP_VOLTAGE_OCV,
3139 POWER_SUPPLY_PROP_CURRENT_NOW,
3140 POWER_SUPPLY_PROP_RESISTANCE_ID,
3141 POWER_SUPPLY_PROP_RESISTANCE,
3142 POWER_SUPPLY_PROP_BATTERY_TYPE,
3143 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003144 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Nicholas Troaste29dec92016-08-24 09:35:11 -07003145 POWER_SUPPLY_PROP_CYCLE_COUNT,
3146 POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003147 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
3148 POWER_SUPPLY_PROP_CHARGE_NOW,
3149 POWER_SUPPLY_PROP_CHARGE_FULL,
3150 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Nicholas Troast1769fd32016-09-07 09:20:58 -07003151 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3152 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003153 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303154 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003155 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003156};
3157
3158static const struct power_supply_desc fg_psy_desc = {
3159 .name = "bms",
3160 .type = POWER_SUPPLY_TYPE_BMS,
3161 .properties = fg_psy_props,
3162 .num_properties = ARRAY_SIZE(fg_psy_props),
3163 .get_property = fg_psy_get_property,
3164 .set_property = fg_psy_set_property,
3165 .external_power_changed = fg_external_power_changed,
3166 .property_is_writeable = fg_property_is_writeable,
3167};
3168
3169/* INIT FUNCTIONS STAY HERE */
3170
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003171#define DEFAULT_ESR_CHG_TIMER_RETRY 8
3172#define DEFAULT_ESR_CHG_TIMER_MAX 16
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003173static int fg_hw_init(struct fg_chip *chip)
3174{
3175 int rc;
3176 u8 buf[4], val;
3177
3178 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003179 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
3180 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003181 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
3182 if (rc < 0) {
3183 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
3184 return rc;
3185 }
3186
3187 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003188 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
3189 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003190 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
3191 if (rc < 0) {
3192 pr_err("Error in writing empty_volt, rc=%d\n", rc);
3193 return rc;
3194 }
3195
3196 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
3197 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003198 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
3199 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003200 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
3201 if (rc < 0) {
3202 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
3203 return rc;
3204 }
3205
3206 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
3207 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003208 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
3209 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003210 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
3211 if (rc < 0) {
3212 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
3213 return rc;
3214 }
3215
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003216 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
3217 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
3218 chip->dt.chg_term_base_curr_ma, buf);
3219 rc = fg_sram_write(chip,
3220 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
3221 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
3222 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
3223 FG_IMA_DEFAULT);
3224 if (rc < 0) {
3225 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
3226 rc);
3227 return rc;
3228 }
3229 }
3230
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003231 if (chip->dt.vbatt_low_thr_mv > 0) {
3232 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
3233 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003234 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
3235 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003236 chip->sp[FG_SRAM_VBATT_LOW].len,
3237 FG_IMA_DEFAULT);
3238 if (rc < 0) {
3239 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
3240 return rc;
3241 }
3242 }
3243
3244 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003245 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003246 chip->dt.delta_soc_thr, buf);
3247 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003248 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
3249 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
3250 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003251 FG_IMA_DEFAULT);
3252 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003253 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
3254 return rc;
3255 }
3256
3257 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
3258 chip->dt.delta_soc_thr, buf);
3259 rc = fg_sram_write(chip,
3260 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
3261 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
3262 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
3263 FG_IMA_DEFAULT);
3264 if (rc < 0) {
3265 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003266 return rc;
3267 }
3268 }
3269
cyizhaofb3eec52017-01-24 17:08:55 +08003270 /*
3271 * configure battery thermal coefficients c1,c2,c3
3272 * if its value is not zero.
3273 */
3274 if (chip->dt.batt_therm_coeffs[0] > 0) {
3275 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
3276 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
3277 if (rc < 0) {
3278 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
3279 rc);
3280 return rc;
3281 }
3282 }
3283
3284
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003285 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003286 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003287 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003288 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003289 return rc;
3290 }
3291 }
3292
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003293 if (chip->dt.recharge_volt_thr_mv > 0) {
3294 rc = fg_set_recharge_voltage(chip,
3295 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003296 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003297 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003298 rc);
3299 return rc;
3300 }
3301 }
3302
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003303 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
3304 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
3305 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
3306 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
3307 if (rc < 0) {
3308 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
3309 return rc;
3310 }
3311 }
3312
3313 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
3314 rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
3315 if (rc < 0) {
3316 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3317 return rc;
3318 }
3319
3320 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
3321 rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
3322 if (rc < 0) {
3323 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
3324 return rc;
3325 }
3326
3327 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
3328 rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
3329 if (rc < 0) {
3330 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
3331 return rc;
3332 }
3333
3334 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
3335 rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
3336 if (rc < 0) {
3337 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
3338 return rc;
3339 }
3340
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003341 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
3342 chip->esr_timer_charging_default[TIMER_RETRY] =
3343 DEFAULT_ESR_CHG_TIMER_RETRY;
3344 chip->esr_timer_charging_default[TIMER_MAX] =
3345 DEFAULT_ESR_CHG_TIMER_MAX;
3346 } else {
3347 /* We don't need this for pm660 at present */
3348 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
3349 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003350 }
3351
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003352 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
3353 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
3354 if (rc < 0) {
3355 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3356 return rc;
3357 }
3358
3359 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
3360 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
3361 if (rc < 0) {
3362 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3363 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003364 }
3365
Nicholas Troaste29dec92016-08-24 09:35:11 -07003366 if (chip->cyc_ctr.en)
3367 restore_cycle_counter(chip);
3368
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003369 if (chip->dt.jeita_hyst_temp >= 0) {
3370 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
3371 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
3372 JEITA_TEMP_HYST_MASK, val);
3373 if (rc < 0) {
3374 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
3375 return rc;
3376 }
3377 }
3378
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003379 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
3380 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
3381 CHANGE_THOLD_MASK, val);
3382 if (rc < 0) {
3383 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
3384 return rc;
3385 }
3386
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07003387 rc = fg_rconn_config(chip);
3388 if (rc < 0) {
3389 pr_err("Error in configuring Rconn, rc=%d\n", rc);
3390 return rc;
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08003391 }
3392
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003393 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
3394 chip->dt.esr_tight_flt_upct, buf);
3395 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
3396 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
3397 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
3398 if (rc < 0) {
3399 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
3400 return rc;
3401 }
3402
3403 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
3404 chip->dt.esr_broad_flt_upct, buf);
3405 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
3406 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
3407 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
3408 if (rc < 0) {
3409 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
3410 return rc;
3411 }
3412
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003413 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
3414 chip->dt.esr_pulse_thresh_ma, buf);
3415 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
3416 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
3417 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
3418 if (rc < 0) {
3419 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
3420 return rc;
3421 }
3422
3423 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
3424 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3425 ESR_PULL_DOWN_IVAL_MASK, val);
3426 if (rc < 0) {
3427 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
3428 return rc;
3429 }
3430
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07003431 if (is_debug_batt_id(chip)) {
3432 val = ESR_NO_PULL_DOWN;
3433 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3434 ESR_PULL_DOWN_MODE_MASK, val);
3435 if (rc < 0) {
3436 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
3437 return rc;
3438 }
3439 }
3440
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003441 return 0;
3442}
3443
3444static int fg_memif_init(struct fg_chip *chip)
3445{
3446 return fg_ima_init(chip);
3447}
3448
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303449static int fg_adjust_timebase(struct fg_chip *chip)
3450{
3451 int rc = 0, die_temp;
3452 s32 time_base = 0;
3453 u8 buf[2] = {0};
3454
3455 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
3456 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
3457 if (rc < 0) {
3458 pr_err("Error in reading die_temp, rc:%d\n", rc);
3459 return rc;
3460 }
3461
3462 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
3463 die_temp / 1000, &time_base);
3464 if (rc < 0) {
3465 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
3466 return rc;
3467 }
3468
3469 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
3470 rc = fg_sram_write(chip,
3471 chip->sp[FG_SRAM_TIMEBASE].addr_word,
3472 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
3473 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
3474 if (rc < 0) {
3475 pr_err("Error in writing timebase, rc=%d\n", rc);
3476 return rc;
3477 }
3478 }
3479
3480 return 0;
3481}
3482
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003483/* INTERRUPT HANDLERS STAY HERE */
3484
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003485static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
3486{
3487 struct fg_chip *chip = data;
3488 u8 status;
3489 int rc;
3490
3491 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
3492 if (rc < 0) {
3493 pr_err("failed to read addr=0x%04x, rc=%d\n",
3494 MEM_IF_INT_RT_STS(chip), rc);
3495 return IRQ_HANDLED;
3496 }
3497
3498 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003499
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003500 mutex_lock(&chip->sram_rw_lock);
3501 rc = fg_clear_dma_errors_if_any(chip);
3502 if (rc < 0)
3503 pr_err("Error in clearing DMA error, rc=%d\n", rc);
3504
3505 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003506 rc = fg_clear_ima_errors_if_any(chip, true);
3507 if (rc < 0 && rc != -EAGAIN)
3508 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003509 }
3510
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003511 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003512 return IRQ_HANDLED;
3513}
3514
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003515static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
3516{
3517 struct fg_chip *chip = data;
3518
3519 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3520 return IRQ_HANDLED;
3521}
3522
3523static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
3524{
3525 struct fg_chip *chip = data;
3526 u8 status;
3527 int rc;
3528
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003529 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
3530 if (rc < 0) {
3531 pr_err("failed to read addr=0x%04x, rc=%d\n",
3532 BATT_INFO_INT_RT_STS(chip), rc);
3533 return IRQ_HANDLED;
3534 }
3535
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003536 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003537 chip->battery_missing = (status & BT_MISS_BIT);
3538
3539 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07003540 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003541 chip->profile_loaded = false;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003542 chip->soc_reporting_ready = false;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003543 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003544 }
3545
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003546 rc = fg_get_batt_id(chip);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003547 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003548 chip->soc_reporting_ready = true;
3549 pr_err("Error in getting battery id, rc:%d\n", rc);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003550 return IRQ_HANDLED;
3551 }
3552
3553 rc = fg_get_batt_profile(chip);
3554 if (rc < 0) {
3555 chip->soc_reporting_ready = true;
3556 pr_err("Error in getting battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003557 return IRQ_HANDLED;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003558 }
3559
3560 clear_battery_profile(chip);
3561 schedule_delayed_work(&chip->profile_load_work, 0);
3562
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303563 if (chip->fg_psy)
3564 power_supply_changed(chip->fg_psy);
3565
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003566 return IRQ_HANDLED;
3567}
3568
3569static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
3570{
3571 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003572 union power_supply_propval prop = {0, };
3573 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003574
3575 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003576 rc = fg_get_battery_temp(chip, &batt_temp);
3577 if (rc < 0) {
3578 pr_err("Error in getting batt_temp\n");
3579 return IRQ_HANDLED;
3580 }
3581
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003582 rc = fg_esr_filter_config(chip, batt_temp);
3583 if (rc < 0)
3584 pr_err("Error in configuring ESR filter rc:%d\n", rc);
3585
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003586 rc = fg_slope_limit_config(chip, batt_temp);
3587 if (rc < 0)
3588 pr_err("Error in configuring slope limiter rc:%d\n", rc);
3589
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07003590 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
3591 if (rc < 0)
3592 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
3593
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003594 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003595 chip->last_batt_temp = batt_temp;
3596 return IRQ_HANDLED;
3597 }
3598
3599 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
3600 &prop);
3601 chip->health = prop.intval;
3602
3603 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303604 rc = fg_adjust_timebase(chip);
3605 if (rc < 0)
3606 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3607
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003608 chip->last_batt_temp = batt_temp;
3609 power_supply_changed(chip->batt_psy);
3610 }
3611
3612 if (abs(chip->last_batt_temp - batt_temp) > 30)
3613 pr_warn("Battery temperature last:%d current: %d\n",
3614 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003615 return IRQ_HANDLED;
3616}
3617
3618static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
3619{
3620 struct fg_chip *chip = data;
3621
3622 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3623 complete_all(&chip->soc_ready);
3624 return IRQ_HANDLED;
3625}
3626
3627static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
3628{
3629 struct fg_chip *chip = data;
3630
3631 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3632 complete_all(&chip->soc_update);
3633 return IRQ_HANDLED;
3634}
3635
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003636static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
3637{
3638 struct fg_chip *chip = data;
3639 int rc;
3640
3641 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3642 rc = fg_charge_full_update(chip);
3643 if (rc < 0)
3644 pr_err("Error in charge_full_update, rc=%d\n", rc);
3645
3646 return IRQ_HANDLED;
3647}
3648
3649static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003650{
3651 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003652 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003653
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003654 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003655 if (chip->cyc_ctr.en)
3656 schedule_work(&chip->cycle_count_work);
3657
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003658 if (chip->cl.active)
3659 fg_cap_learning_update(chip);
3660
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003661 rc = fg_charge_full_update(chip);
3662 if (rc < 0)
3663 pr_err("Error in charge_full_update, rc=%d\n", rc);
3664
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003665 rc = fg_adjust_ki_coeff_dischg(chip);
3666 if (rc < 0)
3667 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
3668
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003669 rc = fg_update_maint_soc(chip);
3670 if (rc < 0)
3671 pr_err("Error in updating maint_soc, rc=%d\n", rc);
3672
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003673 rc = fg_esr_validate(chip);
3674 if (rc < 0)
3675 pr_err("Error in validating ESR, rc=%d\n", rc);
3676
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303677 rc = fg_adjust_timebase(chip);
3678 if (rc < 0)
3679 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3680
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003681 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003682 power_supply_changed(chip->batt_psy);
3683
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003684 return IRQ_HANDLED;
3685}
3686
3687static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
3688{
3689 struct fg_chip *chip = data;
3690
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003691 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003692 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07003693 power_supply_changed(chip->batt_psy);
3694
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003695 return IRQ_HANDLED;
3696}
3697
3698static irqreturn_t fg_soc_irq_handler(int irq, void *data)
3699{
3700 struct fg_chip *chip = data;
3701
3702 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3703 return IRQ_HANDLED;
3704}
3705
3706static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
3707{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003708 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003709 return IRQ_HANDLED;
3710}
3711
3712static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
3713 /* BATT_SOC irqs */
3714 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003715 .name = "msoc-full",
3716 .handler = fg_soc_irq_handler,
3717 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003718 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003719 .name = "msoc-high",
3720 .handler = fg_soc_irq_handler,
3721 .wakeable = true,
3722 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003723 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003724 .name = "msoc-empty",
3725 .handler = fg_empty_soc_irq_handler,
3726 .wakeable = true,
3727 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003728 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003729 .name = "msoc-low",
3730 .handler = fg_soc_irq_handler,
3731 .wakeable = true,
3732 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003733 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003734 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003735 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003736 .wakeable = true,
3737 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003738 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003739 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003740 .handler = fg_delta_bsoc_irq_handler,
3741 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003742 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003743 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003744 .name = "soc-ready",
3745 .handler = fg_first_est_irq_handler,
3746 .wakeable = true,
3747 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003748 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003749 .name = "soc-update",
3750 .handler = fg_soc_update_irq_handler,
3751 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003752 /* BATT_INFO irqs */
3753 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003754 .name = "batt-temp-delta",
3755 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003756 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003757 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003758 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003759 .name = "batt-missing",
3760 .handler = fg_batt_missing_irq_handler,
3761 .wakeable = true,
3762 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003763 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003764 .name = "esr-delta",
3765 .handler = fg_dummy_irq_handler,
3766 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003767 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003768 .name = "vbatt-low",
3769 .handler = fg_vbatt_low_irq_handler,
3770 .wakeable = true,
3771 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003772 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003773 .name = "vbatt-pred-delta",
3774 .handler = fg_dummy_irq_handler,
3775 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003776 /* MEM_IF irqs */
3777 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003778 .name = "dma-grant",
3779 .handler = fg_dummy_irq_handler,
3780 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003781 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003782 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003783 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003784 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003785 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003786 .name = "ima-rdy",
3787 .handler = fg_dummy_irq_handler,
3788 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003789};
3790
3791static int fg_get_irq_index_byname(const char *name)
3792{
3793 int i;
3794
3795 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
3796 if (strcmp(fg_irqs[i].name, name) == 0)
3797 return i;
3798 }
3799
3800 pr_err("%s is not in irq list\n", name);
3801 return -ENOENT;
3802}
3803
3804static int fg_register_interrupts(struct fg_chip *chip)
3805{
3806 struct device_node *child, *node = chip->dev->of_node;
3807 struct property *prop;
3808 const char *name;
3809 int rc, irq, irq_index;
3810
3811 for_each_available_child_of_node(node, child) {
3812 of_property_for_each_string(child, "interrupt-names", prop,
3813 name) {
3814 irq = of_irq_get_byname(child, name);
3815 if (irq < 0) {
3816 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
3817 name, irq);
3818 return irq;
3819 }
3820
3821 irq_index = fg_get_irq_index_byname(name);
3822 if (irq_index < 0)
3823 return irq_index;
3824
3825 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
3826 fg_irqs[irq_index].handler,
3827 IRQF_ONESHOT, name, chip);
3828 if (rc < 0) {
3829 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
3830 name, rc);
3831 return rc;
3832 }
3833
3834 fg_irqs[irq_index].irq = irq;
3835 if (fg_irqs[irq_index].wakeable)
3836 enable_irq_wake(fg_irqs[irq_index].irq);
3837 }
3838 }
3839
3840 return 0;
3841}
3842
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003843static int fg_parse_dt_property_u32_array(struct device_node *node,
3844 const char *prop_name, int *buf, int len)
3845{
3846 int rc;
3847
3848 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
3849 if (rc < 0) {
3850 if (rc == -EINVAL)
3851 return 0;
3852 else
3853 return rc;
3854 } else if (rc != len) {
3855 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
3856 rc);
3857 return -EINVAL;
3858 }
3859
3860 rc = of_property_read_u32_array(node, prop_name, buf, len);
3861 if (rc < 0) {
3862 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
3863 return rc;
3864 }
3865
3866 return 0;
3867}
3868
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003869static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
3870{
3871 struct device_node *node = chip->dev->of_node;
3872 int rc, i;
3873
3874 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
3875 &chip->dt.slope_limit_temp);
3876 if (rc < 0)
3877 return 0;
3878
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003879 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
3880 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
3881 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003882 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003883
3884 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
3885 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
3886 chip->dt.slope_limit_coeffs[i] < 0) {
3887 pr_err("Incorrect slope limit coefficient\n");
3888 return -EINVAL;
3889 }
3890 }
3891
3892 chip->slope_limit_en = true;
3893 return 0;
3894}
3895
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003896static int fg_parse_ki_coefficients(struct fg_chip *chip)
3897{
3898 struct device_node *node = chip->dev->of_node;
3899 int rc, i;
3900
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003901 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
3902 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
3903 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003904 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003905
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003906 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
3907 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
3908 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003909 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003910
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003911 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
3912 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
3913 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003914 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003915
3916 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
3917 if (chip->dt.ki_coeff_soc[i] < 0 ||
3918 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
3919 pr_err("Error in ki_coeff_soc_dischg values\n");
3920 return -EINVAL;
3921 }
3922
3923 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
3924 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
3925 pr_err("Error in ki_coeff_med_dischg values\n");
3926 return -EINVAL;
3927 }
3928
3929 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
3930 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
3931 pr_err("Error in ki_coeff_med_dischg values\n");
3932 return -EINVAL;
3933 }
3934 }
3935 chip->ki_coeff_dischg_en = true;
3936 return 0;
3937}
3938
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003939#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07003940#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003941#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003942#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003943#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07003944#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003945#define DEFAULT_DELTA_SOC_THR 1
3946#define DEFAULT_RECHARGE_SOC_THR 95
3947#define DEFAULT_BATT_TEMP_COLD 0
3948#define DEFAULT_BATT_TEMP_COOL 5
3949#define DEFAULT_BATT_TEMP_WARM 45
3950#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003951#define DEFAULT_CL_START_SOC 15
3952#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
3953#define DEFAULT_CL_MAX_TEMP_DECIDEGC 450
3954#define DEFAULT_CL_MAX_INC_DECIPERC 5
3955#define DEFAULT_CL_MAX_DEC_DECIPERC 100
3956#define DEFAULT_CL_MIN_LIM_DECIPERC 0
3957#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003958#define BTEMP_DELTA_LOW 2
3959#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003960#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
3961#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
3962#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
3963#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
3964#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003965#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003966#define DEFAULT_ESR_PULSE_THRESH_MA 110
3967#define DEFAULT_ESR_MEAS_CURR_MA 120
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003968static int fg_parse_dt(struct fg_chip *chip)
3969{
3970 struct device_node *child, *revid_node, *node = chip->dev->of_node;
3971 u32 base, temp;
3972 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003973 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003974
3975 if (!node) {
3976 dev_err(chip->dev, "device tree node missing\n");
3977 return -ENXIO;
3978 }
3979
3980 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
3981 if (!revid_node) {
3982 pr_err("Missing qcom,pmic-revid property - driver failed\n");
3983 return -EINVAL;
3984 }
3985
3986 chip->pmic_rev_id = get_revid_data(revid_node);
3987 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
3988 pr_err("Unable to get pmic_revid rc=%ld\n",
3989 PTR_ERR(chip->pmic_rev_id));
3990 /*
3991 * the revid peripheral must be registered, any failure
3992 * here only indicates that the rev-id module has not
3993 * probed yet.
3994 */
3995 return -EPROBE_DEFER;
3996 }
3997
3998 pr_debug("PMIC subtype %d Digital major %d\n",
3999 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
4000
4001 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004002 case PMI8998_SUBTYPE:
4003 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
4004 chip->sp = pmi8998_v1_sram_params;
4005 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304006 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08004007 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
4008 chip->sp = pmi8998_v2_sram_params;
4009 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07004010 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004011 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07004012 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004013 break;
Harry Yange4e731b2017-03-06 14:35:09 -08004014 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304015 chip->sp = pmi8998_v2_sram_params;
4016 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07004017 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304018 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
4019 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304020 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004021 default:
4022 return -EINVAL;
4023 }
4024
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004025 if (of_get_available_child_count(node) == 0) {
4026 dev_err(chip->dev, "No child nodes specified!\n");
4027 return -ENXIO;
4028 }
4029
4030 for_each_available_child_of_node(node, child) {
4031 rc = of_property_read_u32(child, "reg", &base);
4032 if (rc < 0) {
4033 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
4034 child->full_name, rc);
4035 return rc;
4036 }
4037
4038 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
4039 if (rc < 0) {
4040 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
4041 base, rc);
4042 return rc;
4043 }
4044
4045 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004046 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004047 chip->batt_soc_base = base;
4048 break;
Harry Yang2452b272017-03-06 13:56:14 -08004049 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004050 chip->batt_info_base = base;
4051 break;
Harry Yang2452b272017-03-06 13:56:14 -08004052 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004053 chip->mem_if_base = base;
4054 break;
4055 default:
4056 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
4057 subtype);
4058 return -ENXIO;
4059 }
4060 }
4061
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004062 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
4063 if (rc < 0) {
4064 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
4065 return rc;
4066 }
4067 chip->rradc_base = base;
4068
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004069 /* Read all the optional properties below */
4070 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
4071 if (rc < 0)
4072 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
4073 else
4074 chip->dt.cutoff_volt_mv = temp;
4075
4076 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
4077 if (rc < 0)
4078 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
4079 else
4080 chip->dt.empty_volt_mv = temp;
4081
4082 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
4083 if (rc < 0)
4084 chip->dt.vbatt_low_thr_mv = -EINVAL;
4085 else
4086 chip->dt.vbatt_low_thr_mv = temp;
4087
4088 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
4089 if (rc < 0)
4090 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
4091 else
4092 chip->dt.chg_term_curr_ma = temp;
4093
4094 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
4095 if (rc < 0)
4096 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
4097 else
4098 chip->dt.sys_term_curr_ma = temp;
4099
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004100 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
4101 if (rc < 0)
4102 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
4103 else
4104 chip->dt.chg_term_base_curr_ma = temp;
4105
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004106 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
4107 if (rc < 0)
4108 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
4109 else
4110 chip->dt.delta_soc_thr = temp;
4111
4112 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
4113 if (rc < 0)
4114 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
4115 else
4116 chip->dt.recharge_soc_thr = temp;
4117
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004118 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
4119 if (rc < 0)
4120 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
4121 else
4122 chip->dt.recharge_volt_thr_mv = temp;
4123
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004124 chip->dt.auto_recharge_soc = of_property_read_bool(node,
4125 "qcom,fg-auto-recharge-soc");
4126
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004127 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
4128 if (rc < 0)
4129 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
4130 else
4131 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
4132
4133 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
4134 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
4135 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
4136 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004137 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
4138 sizeof(u32)) == NUM_JEITA_LEVELS) {
4139 rc = of_property_read_u32_array(node,
4140 "qcom,fg-jeita-thresholds",
4141 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
4142 if (rc < 0)
4143 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
4144 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004145 }
4146
cyizhaofb3eec52017-01-24 17:08:55 +08004147 if (of_property_count_elems_of_size(node,
4148 "qcom,battery-thermal-coefficients",
4149 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
4150 rc = of_property_read_u8_array(node,
4151 "qcom,battery-thermal-coefficients",
4152 chip->dt.batt_therm_coeffs,
4153 BATT_THERM_NUM_COEFFS);
4154 if (rc < 0)
4155 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
4156 rc);
4157 }
4158
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004159 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
4160 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
4161 if (rc < 0) {
4162 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
4163 chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
4164 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004165
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004166 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
4167 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
4168 if (rc < 0) {
4169 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
4170 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
4171 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004172
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004173 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
4174 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
4175 if (rc < 0) {
4176 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
4177 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
4178 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004179
Nicholas Troaste29dec92016-08-24 09:35:11 -07004180 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
4181 if (chip->cyc_ctr.en)
4182 chip->cyc_ctr.id = 1;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004183
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07004184 chip->dt.force_load_profile = of_property_read_bool(node,
4185 "qcom,fg-force-load-profile");
4186
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004187 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
4188 if (rc < 0)
4189 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
4190 else
4191 chip->dt.cl_start_soc = temp;
4192
4193 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
4194 if (rc < 0)
4195 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
4196 else
4197 chip->dt.cl_min_temp = temp;
4198
4199 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
4200 if (rc < 0)
4201 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
4202 else
4203 chip->dt.cl_max_temp = temp;
4204
4205 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
4206 if (rc < 0)
4207 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
4208 else
4209 chip->dt.cl_max_cap_inc = temp;
4210
4211 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
4212 if (rc < 0)
4213 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
4214 else
4215 chip->dt.cl_max_cap_dec = temp;
4216
4217 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
4218 if (rc < 0)
4219 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
4220 else
4221 chip->dt.cl_min_cap_limit = temp;
4222
4223 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
4224 if (rc < 0)
4225 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
4226 else
4227 chip->dt.cl_max_cap_limit = temp;
4228
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004229 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
4230 if (rc < 0)
4231 chip->dt.jeita_hyst_temp = -EINVAL;
4232 else
4233 chip->dt.jeita_hyst_temp = temp;
4234
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004235 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
4236 if (rc < 0)
4237 chip->dt.batt_temp_delta = -EINVAL;
4238 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
4239 chip->dt.batt_temp_delta = temp;
4240
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004241 chip->dt.hold_soc_while_full = of_property_read_bool(node,
4242 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004243
4244 rc = fg_parse_ki_coefficients(chip);
4245 if (rc < 0)
4246 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
4247
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004248 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07004249 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004250 chip->dt.rconn_mohms = temp;
4251
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004252 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
4253 &temp);
4254 if (rc < 0)
4255 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
4256 else
4257 chip->dt.esr_flt_switch_temp = temp;
4258
4259 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
4260 &temp);
4261 if (rc < 0)
4262 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
4263 else
4264 chip->dt.esr_tight_flt_upct = temp;
4265
4266 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
4267 &temp);
4268 if (rc < 0)
4269 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
4270 else
4271 chip->dt.esr_broad_flt_upct = temp;
4272
4273 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
4274 &temp);
4275 if (rc < 0)
4276 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
4277 else
4278 chip->dt.esr_tight_lt_flt_upct = temp;
4279
4280 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
4281 &temp);
4282 if (rc < 0)
4283 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
4284 else
4285 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004286
4287 rc = fg_parse_slope_limit_coefficients(chip);
4288 if (rc < 0)
4289 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
4290
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004291 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
4292 if (rc < 0)
4293 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
4294 else
4295 chip->dt.esr_clamp_mohms = temp;
4296
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004297 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
4298 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
4299 if (!rc) {
4300 /* ESR pulse qualification threshold range is 1-997 mA */
4301 if (temp > 0 && temp < 997)
4302 chip->dt.esr_pulse_thresh_ma = temp;
4303 }
4304
4305 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
4306 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
4307 if (!rc) {
4308 /* ESR measurement current range is 60-240 mA */
4309 if (temp >= 60 || temp <= 240)
4310 chip->dt.esr_meas_curr_ma = temp;
4311 }
4312
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004313 return 0;
4314}
4315
4316static void fg_cleanup(struct fg_chip *chip)
4317{
4318 power_supply_unreg_notifier(&chip->nb);
Nicholas Troast69da2252016-09-07 16:17:47 -07004319 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004320 if (chip->awake_votable)
4321 destroy_votable(chip->awake_votable);
4322
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004323 if (chip->delta_bsoc_irq_en_votable)
4324 destroy_votable(chip->delta_bsoc_irq_en_votable);
4325
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004326 if (chip->batt_id_chan)
4327 iio_channel_release(chip->batt_id_chan);
4328
4329 dev_set_drvdata(chip->dev, NULL);
4330}
4331
4332static int fg_gen3_probe(struct platform_device *pdev)
4333{
4334 struct fg_chip *chip;
4335 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004336 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004337
4338 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
4339 if (!chip)
4340 return -ENOMEM;
4341
4342 chip->dev = &pdev->dev;
4343 chip->debug_mask = &fg_gen3_debug_mask;
4344 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07004345 chip->charge_status = -EINVAL;
4346 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004347 chip->ki_coeff_full_soc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004348 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
4349 if (!chip->regmap) {
4350 dev_err(chip->dev, "Parent regmap is unavailable\n");
4351 return -ENXIO;
4352 }
4353
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004354 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
4355 if (IS_ERR(chip->batt_id_chan)) {
4356 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
4357 pr_err("batt_id_chan unavailable %ld\n",
4358 PTR_ERR(chip->batt_id_chan));
4359 rc = PTR_ERR(chip->batt_id_chan);
4360 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004361 return rc;
4362 }
4363
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304364 rc = of_property_match_string(chip->dev->of_node,
4365 "io-channel-names", "rradc_die_temp");
4366 if (rc >= 0) {
4367 chip->die_temp_chan = iio_channel_get(chip->dev,
4368 "rradc_die_temp");
4369 if (IS_ERR(chip->die_temp_chan)) {
4370 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
4371 pr_err("rradc_die_temp unavailable %ld\n",
4372 PTR_ERR(chip->die_temp_chan));
4373 rc = PTR_ERR(chip->die_temp_chan);
4374 chip->die_temp_chan = NULL;
4375 return rc;
4376 }
4377 }
4378
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004379 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
4380 chip);
4381 if (IS_ERR(chip->awake_votable)) {
4382 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004383 goto exit;
4384 }
4385
4386 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
4387 VOTE_SET_ANY,
4388 fg_delta_bsoc_irq_en_cb, chip);
4389 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
4390 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
4391 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004392 }
4393
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004394 rc = fg_parse_dt(chip);
4395 if (rc < 0) {
4396 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
4397 rc);
4398 goto exit;
4399 }
4400
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004401 mutex_init(&chip->bus_lock);
4402 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004403 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004404 mutex_init(&chip->cl.lock);
Nicholas Troast1769fd32016-09-07 09:20:58 -07004405 mutex_init(&chip->batt_avg_lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004406 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004407 init_completion(&chip->soc_update);
4408 init_completion(&chip->soc_ready);
4409 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
4410 INIT_WORK(&chip->status_change_work, status_change_work);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004411 INIT_WORK(&chip->cycle_count_work, cycle_count_work);
Nicholas Troast1769fd32016-09-07 09:20:58 -07004412 INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004413 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004414
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004415 rc = fg_get_batt_id(chip);
4416 if (rc < 0) {
4417 pr_err("Error in getting battery id, rc:%d\n", rc);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004418 goto exit;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004419 }
4420
4421 rc = fg_get_batt_profile(chip);
4422 if (rc < 0) {
4423 chip->soc_reporting_ready = true;
4424 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
4425 chip->batt_id_ohms / 1000, rc);
4426 }
4427
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004428 rc = fg_memif_init(chip);
4429 if (rc < 0) {
4430 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
4431 rc);
4432 goto exit;
4433 }
4434
4435 rc = fg_hw_init(chip);
4436 if (rc < 0) {
4437 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
4438 rc);
4439 goto exit;
4440 }
4441
4442 platform_set_drvdata(pdev, chip);
4443
4444 /* Register the power supply */
4445 fg_psy_cfg.drv_data = chip;
4446 fg_psy_cfg.of_node = NULL;
4447 fg_psy_cfg.supplied_to = NULL;
4448 fg_psy_cfg.num_supplicants = 0;
4449 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
4450 &fg_psy_cfg);
4451 if (IS_ERR(chip->fg_psy)) {
4452 pr_err("failed to register fg_psy rc = %ld\n",
4453 PTR_ERR(chip->fg_psy));
4454 goto exit;
4455 }
4456
4457 chip->nb.notifier_call = fg_notifier_cb;
4458 rc = power_supply_reg_notifier(&chip->nb);
4459 if (rc < 0) {
4460 pr_err("Couldn't register psy notifier rc = %d\n", rc);
4461 goto exit;
4462 }
4463
4464 rc = fg_register_interrupts(chip);
4465 if (rc < 0) {
4466 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
4467 rc);
4468 goto exit;
4469 }
4470
4471 /* Keep SOC_UPDATE irq disabled until we require it */
4472 if (fg_irqs[SOC_UPDATE_IRQ].irq)
4473 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
4474
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004475 /* Keep BSOC_DELTA_IRQ irq disabled until we require it */
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004476 rerun_election(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004477
Nicholas Troast69da2252016-09-07 16:17:47 -07004478 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004479 if (rc < 0) {
4480 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
4481 rc);
4482 goto exit;
4483 }
4484
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004485 rc = fg_get_battery_voltage(chip, &volt_uv);
4486 if (!rc)
4487 rc = fg_get_prop_capacity(chip, &msoc);
4488
4489 if (!rc)
4490 rc = fg_get_battery_temp(chip, &batt_temp);
4491
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004492 if (!rc) {
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004493 pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004494 msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004495 rc = fg_esr_filter_config(chip, batt_temp);
4496 if (rc < 0)
4497 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4498 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004499
4500 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07004501 if (chip->profile_available)
4502 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004503
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004504 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004505 return 0;
4506exit:
4507 fg_cleanup(chip);
4508 return rc;
4509}
4510
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004511static int fg_gen3_suspend(struct device *dev)
4512{
4513 struct fg_chip *chip = dev_get_drvdata(dev);
4514 int rc;
4515
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004516 rc = fg_esr_timer_config(chip, true);
4517 if (rc < 0)
4518 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004519
Nicholas Troast1769fd32016-09-07 09:20:58 -07004520 cancel_delayed_work_sync(&chip->batt_avg_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004521 if (fg_sram_dump)
4522 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004523 return 0;
4524}
4525
4526static int fg_gen3_resume(struct device *dev)
4527{
4528 struct fg_chip *chip = dev_get_drvdata(dev);
4529 int rc;
4530
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004531 rc = fg_esr_timer_config(chip, false);
4532 if (rc < 0)
4533 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004534
Nicholas Troast1769fd32016-09-07 09:20:58 -07004535 fg_circ_buf_clr(&chip->ibatt_circ_buf);
4536 fg_circ_buf_clr(&chip->vbatt_circ_buf);
4537 schedule_delayed_work(&chip->batt_avg_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004538 if (fg_sram_dump)
4539 schedule_delayed_work(&chip->sram_dump_work,
4540 msecs_to_jiffies(fg_sram_dump_period_ms));
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004541 return 0;
4542}
4543
4544static const struct dev_pm_ops fg_gen3_pm_ops = {
4545 .suspend = fg_gen3_suspend,
4546 .resume = fg_gen3_resume,
4547};
4548
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004549static int fg_gen3_remove(struct platform_device *pdev)
4550{
4551 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
4552
4553 fg_cleanup(chip);
4554 return 0;
4555}
4556
4557static const struct of_device_id fg_gen3_match_table[] = {
4558 {.compatible = FG_GEN3_DEV_NAME},
4559 {},
4560};
4561
4562static struct platform_driver fg_gen3_driver = {
4563 .driver = {
4564 .name = FG_GEN3_DEV_NAME,
4565 .owner = THIS_MODULE,
4566 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004567 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004568 },
4569 .probe = fg_gen3_probe,
4570 .remove = fg_gen3_remove,
4571};
4572
4573static int __init fg_gen3_init(void)
4574{
4575 return platform_driver_register(&fg_gen3_driver);
4576}
4577
4578static void __exit fg_gen3_exit(void)
4579{
4580 return platform_driver_unregister(&fg_gen3_driver);
4581}
4582
4583module_init(fg_gen3_init);
4584module_exit(fg_gen3_exit);
4585
4586MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
4587MODULE_LICENSE("GPL v2");
4588MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);