blob: 75e79bbf9c7ca23605b42a8caf77808c9bcd22e0 [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
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -0700494 temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700495 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
Subbaraman Narayanamurthy3cf60ee2017-06-02 11:38:58 -07001323 cc_soc_delta_pct =
1324 div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
1325 CC_SOC_30BIT);
1326
1327 /* If the delta is < 50%, then skip processing full data */
1328 if (cc_soc_delta_pct < 50) {
1329 pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
1330 return -ERANGE;
1331 }
1332
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001333 delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
1334 100);
1335 chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
1336 fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n",
1337 cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
1338 return 0;
1339}
1340
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001341#define BATT_SOC_32BIT GENMASK(31, 0)
1342static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001343{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001344 int rc, cc_soc_sw, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001345
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001346 batt_soc_msb = batt_soc >> 24;
1347 if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001348 chip->dt.cl_start_soc) {
1349 fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001350 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001351 return -EINVAL;
1352 }
1353
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001354 chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001355 FULL_SOC_RAW);
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001356
1357 /* Prime cc_soc_sw with battery SOC when capacity learning begins */
1358 cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
1359 BATT_SOC_32BIT);
1360 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1361 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
1362 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001363 if (rc < 0) {
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001364 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1365 goto out;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001366 }
1367
1368 chip->cl.init_cc_soc_sw = cc_soc_sw;
1369 chip->cl.active = true;
1370 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 -07001371 batt_soc_msb, chip->cl.init_cc_soc_sw);
1372out:
1373 return rc;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001374}
1375
1376static int fg_cap_learning_done(struct fg_chip *chip)
1377{
1378 int rc, cc_soc_sw;
1379
1380 rc = fg_cap_learning_process_full_data(chip);
1381 if (rc < 0) {
1382 pr_err("Error in processing cap learning full data, rc=%d\n",
1383 rc);
1384 goto out;
1385 }
1386
1387 /* Write a FULL value to cc_soc_sw */
1388 cc_soc_sw = CC_SOC_30BIT;
1389 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
1390 chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001391 chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001392 if (rc < 0) {
1393 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
1394 goto out;
1395 }
1396
1397 fg_cap_learning_post_process(chip);
1398out:
1399 return rc;
1400}
1401
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001402static void fg_cap_learning_update(struct fg_chip *chip)
1403{
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001404 int rc, batt_soc, batt_soc_msb;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001405
1406 mutex_lock(&chip->cl.lock);
1407
1408 if (!is_temp_valid_cap_learning(chip) || !chip->cl.learned_cc_uah ||
1409 chip->battery_missing) {
1410 fg_dbg(chip, FG_CAP_LEARN, "Aborting cap_learning %lld\n",
1411 chip->cl.learned_cc_uah);
1412 chip->cl.active = false;
1413 chip->cl.init_cc_uah = 0;
1414 goto out;
1415 }
1416
1417 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
1418 if (rc < 0) {
1419 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1420 goto out;
1421 }
1422
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001423 batt_soc_msb = (u32)batt_soc >> 24;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001424 fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001425 chip->charge_status, chip->cl.active, batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001426
1427 /* Initialize the starting point of learning capacity */
1428 if (!chip->cl.active) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07001429 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001430 rc = fg_cap_learning_begin(chip, batt_soc);
1431 chip->cl.active = (rc == 0);
1432 }
1433
1434 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001435 if (chip->charge_done) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001436 rc = fg_cap_learning_done(chip);
1437 if (rc < 0)
1438 pr_err("Error in completing capacity learning, rc=%d\n",
1439 rc);
1440
1441 chip->cl.active = false;
1442 chip->cl.init_cc_uah = 0;
1443 }
1444
Nicholas Troast1769fd32016-09-07 09:20:58 -07001445 if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001446 fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07001447 batt_soc_msb);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07001448 chip->cl.active = false;
1449 chip->cl.init_cc_uah = 0;
1450 }
1451 }
1452
1453out:
1454 mutex_unlock(&chip->cl.lock);
1455}
1456
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001457#define KI_COEFF_MED_DISCHG_DEFAULT 1500
1458#define KI_COEFF_HI_DISCHG_DEFAULT 2200
1459static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
1460{
1461 int rc, i, msoc;
1462 int ki_coeff_med = KI_COEFF_MED_DISCHG_DEFAULT;
1463 int ki_coeff_hi = KI_COEFF_HI_DISCHG_DEFAULT;
1464 u8 val;
1465
1466 if (!chip->ki_coeff_dischg_en)
1467 return 0;
1468
1469 rc = fg_get_prop_capacity(chip, &msoc);
1470 if (rc < 0) {
1471 pr_err("Error in getting capacity, rc=%d\n", rc);
1472 return rc;
1473 }
1474
Nicholas Troast1769fd32016-09-07 09:20:58 -07001475 if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07001476 for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) {
1477 if (msoc < chip->dt.ki_coeff_soc[i]) {
1478 ki_coeff_med = chip->dt.ki_coeff_med_dischg[i];
1479 ki_coeff_hi = chip->dt.ki_coeff_hi_dischg[i];
1480 }
1481 }
1482 }
1483
1484 fg_encode(chip->sp, FG_SRAM_KI_COEFF_MED_DISCHG, ki_coeff_med, &val);
1485 rc = fg_sram_write(chip,
1486 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_word,
1487 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].addr_byte, &val,
1488 chip->sp[FG_SRAM_KI_COEFF_MED_DISCHG].len,
1489 FG_IMA_DEFAULT);
1490 if (rc < 0) {
1491 pr_err("Error in writing ki_coeff_med, rc=%d\n", rc);
1492 return rc;
1493 }
1494
1495 fg_encode(chip->sp, FG_SRAM_KI_COEFF_HI_DISCHG, ki_coeff_hi, &val);
1496 rc = fg_sram_write(chip,
1497 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_word,
1498 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].addr_byte, &val,
1499 chip->sp[FG_SRAM_KI_COEFF_HI_DISCHG].len,
1500 FG_IMA_DEFAULT);
1501 if (rc < 0) {
1502 pr_err("Error in writing ki_coeff_hi, rc=%d\n", rc);
1503 return rc;
1504 }
1505
1506 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_med %d ki_coeff_hi %d\n",
1507 ki_coeff_med, ki_coeff_hi);
1508 return 0;
1509}
1510
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07001511#define KI_COEFF_FULL_SOC_DEFAULT 733
1512static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
1513{
1514 int rc, ki_coeff_full_soc;
1515 u8 val;
1516
1517 if (batt_temp < 0)
1518 ki_coeff_full_soc = 0;
1519 else
1520 ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
1521
1522 if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
1523 return 0;
1524
1525 fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
1526 rc = fg_sram_write(chip,
1527 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
1528 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
1529 chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
1530 FG_IMA_DEFAULT);
1531 if (rc < 0) {
1532 pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
1533 return rc;
1534 }
1535
1536 chip->ki_coeff_full_soc = ki_coeff_full_soc;
1537 fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
1538 ki_coeff_full_soc);
1539 return 0;
1540}
1541
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001542static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
1543{
1544 u8 buf;
1545 int rc;
1546
1547 if (chip->dt.auto_recharge_soc)
1548 return 0;
1549
1550 /* This configuration is available only for pmicobalt v2.0 and above */
1551 if (chip->wa_flags & PMI8998_V1_REV_WA)
1552 return 0;
1553
1554 fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
1555 voltage_mv);
1556 fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
1557 rc = fg_sram_write(chip,
1558 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
1559 chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
1560 &buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
1561 FG_IMA_DEFAULT);
1562 if (rc < 0) {
1563 pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
1564 rc);
1565 return rc;
1566 }
1567
1568 return 0;
1569}
1570
1571#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001572static int fg_charge_full_update(struct fg_chip *chip)
1573{
1574 union power_supply_propval prop = {0, };
1575 int rc, msoc, bsoc, recharge_soc;
1576 u8 full_soc[2] = {0xFF, 0xFF};
1577
1578 if (!chip->dt.hold_soc_while_full)
1579 return 0;
1580
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08001581 if (!batt_psy_initialized(chip))
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001582 return 0;
1583
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001584 mutex_lock(&chip->charge_full_lock);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07001585 vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
1586 chip->charge_done, 0);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001587 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
1588 &prop);
1589 if (rc < 0) {
1590 pr_err("Error in getting battery health, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001591 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001592 }
1593
1594 chip->health = prop.intval;
1595 recharge_soc = chip->dt.recharge_soc_thr;
1596 recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
1597 FULL_CAPACITY);
1598 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
1599 if (rc < 0) {
1600 pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001601 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001602 }
1603
1604 /* We need 2 most significant bytes here */
1605 bsoc = (u32)bsoc >> 16;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001606 rc = fg_get_msoc(chip, &msoc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001607 if (rc < 0) {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001608 pr_err("Error in getting msoc, rc=%d\n", rc);
1609 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001610 }
1611
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001612 fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
1613 msoc, bsoc, chip->health, chip->charge_status,
1614 chip->charge_full);
1615 if (chip->charge_done && !chip->charge_full) {
1616 if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) {
1617 fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n");
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001618 chip->charge_full = true;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001619 /*
1620 * Lower the recharge voltage so that VBAT_LT_RECHG
1621 * signal will not be asserted soon.
1622 */
1623 rc = fg_set_recharge_voltage(chip,
1624 AUTO_RECHG_VOLT_LOW_LIMIT_MV);
1625 if (rc < 0) {
1626 pr_err("Error in reducing recharge voltage, rc=%d\n",
1627 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001628 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001629 }
1630 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001631 fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
1632 msoc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001633 }
1634 } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001635 chip->delta_soc = FULL_CAPACITY - msoc;
1636
1637 /*
1638 * We're spreading out the delta SOC over every 10% change
1639 * in monotonic SOC. We cannot spread more than 9% in the
1640 * range of 0-100 skipping the first 10%.
1641 */
1642 if (chip->delta_soc > 9) {
1643 chip->delta_soc = 0;
1644 chip->maint_soc = 0;
1645 } else {
1646 chip->maint_soc = FULL_CAPACITY;
1647 chip->last_msoc = msoc;
1648 }
1649
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001650 chip->charge_full = false;
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001651
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001652 /*
1653 * Raise the recharge voltage so that VBAT_LT_RECHG signal
1654 * will be asserted soon as battery SOC had dropped below
1655 * the recharge SOC threshold.
1656 */
1657 rc = fg_set_recharge_voltage(chip,
1658 chip->dt.recharge_volt_thr_mv);
1659 if (rc < 0) {
1660 pr_err("Error in setting recharge voltage, rc=%d\n",
1661 rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001662 goto out;
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001663 }
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001664 fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d delta_soc: %d\n",
1665 bsoc >> 8, recharge_soc, chip->delta_soc);
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001666 } else {
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001667 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001668 }
1669
1670 if (!chip->charge_full)
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001671 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001672
1673 /*
1674 * During JEITA conditions, charge_full can happen early. FULL_SOC
1675 * and MONOTONIC_SOC needs to be updated to reflect the same. Write
1676 * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
1677 */
1678 rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
1679 FG_IMA_ATOMIC);
1680 if (rc < 0) {
1681 pr_err("failed to write full_soc rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001682 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001683 }
1684
1685 rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
1686 full_soc, 2, FG_IMA_ATOMIC);
1687 if (rc < 0) {
1688 pr_err("failed to write monotonic_soc rc=%d\n", rc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001689 goto out;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001690 }
1691
1692 fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08001693out:
1694 mutex_unlock(&chip->charge_full_lock);
1695 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001696}
1697
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001698#define RCONN_CONFIG_BIT BIT(0)
1699static int fg_rconn_config(struct fg_chip *chip)
1700{
1701 int rc, esr_uohms;
1702 u64 scaling_factor;
1703 u32 val = 0;
1704
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07001705 if (!chip->dt.rconn_mohms)
1706 return 0;
1707
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001708 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
1709 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1710 if (rc < 0) {
1711 pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
1712 return rc;
1713 }
1714
1715 if (val & RCONN_CONFIG_BIT) {
1716 fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
1717 return 0;
1718 }
1719
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08001720 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08001721 if (rc < 0) {
1722 pr_err("failed to get ESR, rc=%d\n", rc);
1723 return rc;
1724 }
1725
1726 scaling_factor = div64_u64((u64)esr_uohms * 1000,
1727 esr_uohms + (chip->dt.rconn_mohms * 1000));
1728
1729 rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
1730 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1731 if (rc < 0) {
1732 pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1733 return rc;
1734 }
1735
1736 val *= scaling_factor;
1737 do_div(val, 1000);
1738 rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
1739 ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1740 if (rc < 0) {
1741 pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
1742 return rc;
1743 }
1744 fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
1745
1746 rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
1747 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1748 if (rc < 0) {
1749 pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1750 return rc;
1751 }
1752
1753 val *= scaling_factor;
1754 do_div(val, 1000);
1755 rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
1756 ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1757 if (rc < 0) {
1758 pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
1759 return rc;
1760 }
1761 fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
1762 val & 0xFF);
1763
1764 val = RCONN_CONFIG_BIT;
1765 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
1766 SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
1767 if (rc < 0) {
1768 pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
1769 return rc;
1770 }
1771
1772 return 0;
1773}
1774
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08001775static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
1776{
1777 u8 buf[2];
1778 int rc;
1779
1780 if (volt_uv <= 0 || volt_uv > 15590000) {
1781 pr_err("Invalid voltage %d\n", volt_uv);
1782 return -EINVAL;
1783 }
1784
1785 fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
1786
1787 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
1788 chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
1789 chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
1790 if (rc < 0) {
1791 pr_err("Error in writing vbatt_full, rc=%d\n", rc);
1792 return rc;
1793 }
1794
1795 return 0;
1796}
1797
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001798static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
1799{
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001800 u8 buf;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001801 int rc;
1802
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001803 if (!chip->dt.auto_recharge_soc)
1804 return 0;
1805
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001806 if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY)
1807 return 0;
1808
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001809 fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, &buf);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001810 rc = fg_sram_write(chip,
1811 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001812 chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, &buf,
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001813 chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
1814 if (rc < 0) {
1815 pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
1816 return rc;
1817 }
1818
1819 return 0;
1820}
1821
1822static int fg_adjust_recharge_soc(struct fg_chip *chip)
1823{
1824 int rc, msoc, recharge_soc, new_recharge_soc = 0;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001825 bool recharge_soc_status;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001826
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08001827 if (!chip->dt.auto_recharge_soc)
1828 return 0;
1829
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001830 recharge_soc = chip->dt.recharge_soc_thr;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001831 recharge_soc_status = chip->recharge_soc_adjusted;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001832 /*
1833 * If the input is present and charging had been terminated, adjust
1834 * the recharge SOC threshold based on the monotonic SOC at which
1835 * the charge termination had happened.
1836 */
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001837 if (is_input_present(chip)) {
1838 if (chip->charge_done) {
1839 if (!chip->recharge_soc_adjusted) {
1840 /* Get raw monotonic SOC for calculation */
1841 rc = fg_get_msoc(chip, &msoc);
1842 if (rc < 0) {
1843 pr_err("Error in getting msoc, rc=%d\n",
1844 rc);
1845 return rc;
1846 }
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001847
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001848 /* Adjust the recharge_soc threshold */
1849 new_recharge_soc = msoc - (FULL_CAPACITY -
1850 recharge_soc);
1851 chip->recharge_soc_adjusted = true;
1852 } else {
1853 /* adjusted already, do nothing */
1854 return 0;
1855 }
1856 } else {
1857 /* Charging, do nothing */
1858 return 0;
1859 }
1860 } else {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001861 /* Restore the default value */
1862 new_recharge_soc = recharge_soc;
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001863 chip->recharge_soc_adjusted = false;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001864 }
1865
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001866 rc = fg_set_recharge_soc(chip, new_recharge_soc);
1867 if (rc < 0) {
1868 chip->recharge_soc_adjusted = recharge_soc_status;
1869 pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
1870 return rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001871 }
1872
Subbaraman Narayanamurthyebe7e2b2017-03-13 12:50:12 -07001873 fg_dbg(chip, FG_STATUS, "resume soc set to %d\n", new_recharge_soc);
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07001874 return 0;
1875}
1876
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08001877static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
1878{
1879 enum slope_limit_status status;
1880 int rc;
1881 u8 buf;
1882
1883 if (!chip->slope_limit_en)
1884 return 0;
1885
1886 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
1887 chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
1888 if (batt_temp < chip->dt.slope_limit_temp)
1889 status = LOW_TEMP_CHARGE;
1890 else
1891 status = HIGH_TEMP_CHARGE;
1892 } else {
1893 if (batt_temp < chip->dt.slope_limit_temp)
1894 status = LOW_TEMP_DISCHARGE;
1895 else
1896 status = HIGH_TEMP_DISCHARGE;
1897 }
1898
1899 if (chip->slope_limit_sts == status)
1900 return 0;
1901
1902 fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
1903 chip->dt.slope_limit_coeffs[status], &buf);
1904 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
1905 chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
1906 chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
1907 if (rc < 0) {
1908 pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
1909 rc);
1910 return rc;
1911 }
1912
1913 chip->slope_limit_sts = status;
1914 fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
1915 buf);
1916 return 0;
1917}
1918
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001919static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
1920{
1921 u8 esr_tight_lt_flt, esr_broad_lt_flt;
1922 bool cold_temp = false;
1923 int rc;
1924
1925 /*
1926 * If the battery temperature is lower than -20 C, then skip modifying
1927 * ESR filter.
1928 */
1929 if (batt_temp < -210)
1930 return 0;
1931
1932 /*
1933 * If battery temperature is lesser than 10 C (default), then apply the
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001934 * ESR low temperature tight and broad filter values to ESR room
1935 * temperature tight and broad filters. If battery temperature is higher
1936 * than 10 C, then apply back the room temperature ESR filter
1937 * coefficients to ESR room temperature tight and broad filters.
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001938 */
1939 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,
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001942 chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
1943 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
1944 chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001945 } else if (batt_temp <= chip->dt.esr_flt_switch_temp
1946 && !chip->esr_flt_cold_temp_en) {
1947 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
1948 chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
1949 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
1950 chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001951 cold_temp = true;
1952 } else {
1953 return 0;
1954 }
1955
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001956 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
1957 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
1958 &esr_tight_lt_flt,
1959 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001960 if (rc < 0) {
1961 pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
1962 return rc;
1963 }
1964
Subbaraman Narayanamurthy5000eb62017-02-08 20:39:16 -08001965 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
1966 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
1967 &esr_broad_lt_flt,
1968 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08001969 if (rc < 0) {
1970 pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
1971 return rc;
1972 }
1973
1974 chip->esr_flt_cold_temp_en = cold_temp;
1975 fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n",
1976 cold_temp ? "cold" : "normal");
1977 return 0;
1978}
1979
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001980static int fg_esr_fcc_config(struct fg_chip *chip)
1981{
1982 union power_supply_propval prop = {0, };
1983 int rc;
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07001984 bool parallel_en = false, qnovo_en = false;
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07001985
1986 if (is_parallel_charger_available(chip)) {
1987 rc = power_supply_get_property(chip->parallel_psy,
1988 POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop);
1989 if (rc < 0) {
1990 pr_err("Error in reading charging_enabled from parallel_psy, rc=%d\n",
1991 rc);
1992 return rc;
1993 }
1994 parallel_en = prop.intval;
1995 }
1996
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07001997 rc = power_supply_get_property(chip->batt_psy,
1998 POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, &prop);
1999 if (!rc)
2000 qnovo_en = prop.intval;
2001
2002 fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
2003 chip->charge_status, parallel_en, qnovo_en,
2004 chip->esr_fcc_ctrl_en);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002005
Nicholas Troast1769fd32016-09-07 09:20:58 -07002006 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002007 (parallel_en || qnovo_en)) {
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002008 if (chip->esr_fcc_ctrl_en)
2009 return 0;
2010
2011 /*
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002012 * When parallel charging or Qnovo is enabled, configure ESR
2013 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
2014 * request the main charger to increase FCC when it is supposed
2015 * to decrease it.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002016 */
2017 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2018 ESR_FAST_CRG_IVAL_MASK |
2019 ESR_FAST_CRG_CTL_EN_BIT,
2020 ESR_FCC_300MA | ESR_FAST_CRG_CTL_EN_BIT);
2021 if (rc < 0) {
2022 pr_err("Error in writing to %04x, rc=%d\n",
2023 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2024 return rc;
2025 }
2026
2027 chip->esr_fcc_ctrl_en = true;
2028 } else {
2029 if (!chip->esr_fcc_ctrl_en)
2030 return 0;
2031
2032 /*
2033 * If we're here, then it means either the device is not in
Subbaraman Narayanamurthyf6357232017-04-19 14:55:35 -07002034 * charging state or parallel charging / Qnovo is disabled.
2035 * Disable ESR fast charge current control in SW.
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002036 */
2037 rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
2038 ESR_FAST_CRG_CTL_EN_BIT, 0);
2039 if (rc < 0) {
2040 pr_err("Error in writing to %04x, rc=%d\n",
2041 BATT_INFO_ESR_FAST_CRG_CFG(chip), rc);
2042 return rc;
2043 }
2044
2045 chip->esr_fcc_ctrl_en = false;
2046 }
2047
2048 fg_dbg(chip, FG_STATUS, "esr_fcc_ctrl_en set to %d\n",
2049 chip->esr_fcc_ctrl_en);
2050 return 0;
2051}
2052
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002053static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
2054{
2055 int rc, cycles_init, cycles_max;
2056 bool end_of_charge = false;
2057
2058 end_of_charge = is_input_present(chip) && chip->charge_done;
2059 fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
2060
2061 /* ESR discharging timer configuration */
2062 cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
2063 chip->dt.esr_timer_awake[TIMER_RETRY];
2064 if (end_of_charge)
2065 cycles_init = 0;
2066
2067 cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
2068 chip->dt.esr_timer_awake[TIMER_MAX];
2069
2070 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
2071 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2072 if (rc < 0) {
2073 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2074 return rc;
2075 }
2076
2077 /* ESR charging timer configuration */
2078 cycles_init = cycles_max = -EINVAL;
2079 if (end_of_charge || sleep) {
2080 cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
2081 cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
2082 } else if (is_input_present(chip)) {
2083 cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
2084 cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
2085 }
2086
2087 rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
2088 sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
2089 if (rc < 0) {
2090 pr_err("Error in setting ESR timer, rc=%d\n", rc);
2091 return rc;
2092 }
2093
2094 return 0;
2095}
2096
Nicholas Troast1769fd32016-09-07 09:20:58 -07002097static void fg_batt_avg_update(struct fg_chip *chip)
2098{
2099 if (chip->charge_status == chip->prev_charge_status)
2100 return;
2101
2102 cancel_delayed_work_sync(&chip->batt_avg_work);
2103 fg_circ_buf_clr(&chip->ibatt_circ_buf);
2104 fg_circ_buf_clr(&chip->vbatt_circ_buf);
2105
2106 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
2107 chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
2108 schedule_delayed_work(&chip->batt_avg_work,
2109 msecs_to_jiffies(2000));
2110}
2111
Nicholas Troaste29dec92016-08-24 09:35:11 -07002112static void status_change_work(struct work_struct *work)
2113{
2114 struct fg_chip *chip = container_of(work,
2115 struct fg_chip, status_change_work);
2116 union power_supply_propval prop = {0, };
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002117 int rc, batt_temp;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002118
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002119 if (!batt_psy_initialized(chip)) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002120 fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002121 goto out;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002122 }
2123
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002124 rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
Nicholas Troaste29dec92016-08-24 09:35:11 -07002125 &prop);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002126 if (rc < 0) {
2127 pr_err("Error in getting charging status, rc=%d\n", rc);
2128 goto out;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002129 }
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002130
Nicholas Troast1769fd32016-09-07 09:20:58 -07002131 chip->prev_charge_status = chip->charge_status;
2132 chip->charge_status = prop.intval;
2133 rc = power_supply_get_property(chip->batt_psy,
2134 POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
2135 if (rc < 0) {
2136 pr_err("Error in getting charge type, rc=%d\n", rc);
2137 goto out;
2138 }
2139
2140 chip->charge_type = prop.intval;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002141 rc = power_supply_get_property(chip->batt_psy,
2142 POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
2143 if (rc < 0) {
2144 pr_err("Error in getting charge_done, rc=%d\n", rc);
2145 goto out;
2146 }
2147
2148 chip->charge_done = prop.intval;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002149 if (chip->cyc_ctr.en)
2150 schedule_work(&chip->cycle_count_work);
2151
2152 fg_cap_learning_update(chip);
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07002153
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002154 rc = fg_charge_full_update(chip);
2155 if (rc < 0)
2156 pr_err("Error in charge_full_update, rc=%d\n", rc);
2157
2158 rc = fg_adjust_recharge_soc(chip);
2159 if (rc < 0)
2160 pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002161
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07002162 rc = fg_adjust_ki_coeff_dischg(chip);
2163 if (rc < 0)
2164 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
Subbaraman Narayanamurthya9aacae2016-11-01 19:31:44 -07002165
2166 rc = fg_esr_fcc_config(chip);
2167 if (rc < 0)
2168 pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002169
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07002170 rc = fg_esr_timer_config(chip, false);
2171 if (rc < 0)
2172 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
2173
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002174 rc = fg_get_battery_temp(chip, &batt_temp);
2175 if (!rc) {
2176 rc = fg_slope_limit_config(chip, batt_temp);
2177 if (rc < 0)
2178 pr_err("Error in configuring slope limiter rc:%d\n",
2179 rc);
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07002180
2181 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
2182 if (rc < 0)
2183 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
2184 rc);
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08002185 }
2186
Nicholas Troast1769fd32016-09-07 09:20:58 -07002187 fg_batt_avg_update(chip);
2188
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002189out:
Nicholas Troast1769fd32016-09-07 09:20:58 -07002190 fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
2191 chip->charge_status, chip->charge_type, chip->charge_done);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002192 pm_relax(chip->dev);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002193}
2194
2195static void restore_cycle_counter(struct fg_chip *chip)
2196{
2197 int rc = 0, i;
2198 u8 data[2];
2199
2200 mutex_lock(&chip->cyc_ctr.lock);
2201 for (i = 0; i < BUCKET_COUNT; i++) {
2202 rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
2203 CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2,
2204 FG_IMA_DEFAULT);
2205 if (rc < 0)
2206 pr_err("failed to read bucket %d rc=%d\n", i, rc);
2207 else
2208 chip->cyc_ctr.count[i] = data[0] | data[1] << 8;
2209 }
2210 mutex_unlock(&chip->cyc_ctr.lock);
2211}
2212
2213static void clear_cycle_counter(struct fg_chip *chip)
2214{
2215 int rc = 0, i;
2216
2217 if (!chip->cyc_ctr.en)
2218 return;
2219
2220 mutex_lock(&chip->cyc_ctr.lock);
2221 memset(chip->cyc_ctr.count, 0, sizeof(chip->cyc_ctr.count));
2222 for (i = 0; i < BUCKET_COUNT; i++) {
2223 chip->cyc_ctr.started[i] = false;
2224 chip->cyc_ctr.last_soc[i] = 0;
2225 }
2226 rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET,
2227 (u8 *)&chip->cyc_ctr.count,
2228 sizeof(chip->cyc_ctr.count) / sizeof(u8 *),
2229 FG_IMA_DEFAULT);
2230 if (rc < 0)
2231 pr_err("failed to clear cycle counter rc=%d\n", rc);
2232
2233 mutex_unlock(&chip->cyc_ctr.lock);
2234}
2235
2236static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket)
2237{
2238 int rc = 0;
2239 u16 cyc_count;
2240 u8 data[2];
2241
2242 if (bucket < 0 || (bucket > BUCKET_COUNT - 1))
2243 return 0;
2244
2245 cyc_count = chip->cyc_ctr.count[bucket];
2246 cyc_count++;
2247 data[0] = cyc_count & 0xFF;
2248 data[1] = cyc_count >> 8;
2249
2250 rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
2251 CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
2252 FG_IMA_DEFAULT);
2253 if (rc < 0)
2254 pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
2255 bucket, rc);
2256 else
2257 chip->cyc_ctr.count[bucket] = cyc_count;
2258 return rc;
2259}
2260
2261static void cycle_count_work(struct work_struct *work)
2262{
2263 int rc = 0, bucket, i, batt_soc;
2264 struct fg_chip *chip = container_of(work,
2265 struct fg_chip,
2266 cycle_count_work);
2267
2268 mutex_lock(&chip->cyc_ctr.lock);
2269 rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
2270 if (rc < 0) {
2271 pr_err("Failed to read battery soc rc: %d\n", rc);
2272 goto out;
2273 }
2274
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07002275 /* We need only the most significant byte here */
2276 batt_soc = (u32)batt_soc >> 24;
2277
Nicholas Troast1769fd32016-09-07 09:20:58 -07002278 if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002279 /* Find out which bucket the SOC falls in */
2280 bucket = batt_soc / BUCKET_SOC_PCT;
2281 pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
2282
2283 /*
2284 * If we've started counting for the previous bucket,
2285 * then store the counter for that bucket if the
2286 * counter for current bucket is getting started.
2287 */
2288 if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
2289 !chip->cyc_ctr.started[bucket]) {
2290 rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
2291 if (rc < 0) {
2292 pr_err("Error in storing cycle_ctr rc: %d\n",
2293 rc);
2294 goto out;
2295 } else {
2296 chip->cyc_ctr.started[bucket - 1] = false;
2297 chip->cyc_ctr.last_soc[bucket - 1] = 0;
2298 }
2299 }
2300 if (!chip->cyc_ctr.started[bucket]) {
2301 chip->cyc_ctr.started[bucket] = true;
2302 chip->cyc_ctr.last_soc[bucket] = batt_soc;
2303 }
2304 } else {
2305 for (i = 0; i < BUCKET_COUNT; i++) {
2306 if (chip->cyc_ctr.started[i] &&
2307 batt_soc > chip->cyc_ctr.last_soc[i]) {
2308 rc = fg_inc_store_cycle_ctr(chip, i);
2309 if (rc < 0)
2310 pr_err("Error in storing cycle_ctr rc: %d\n",
2311 rc);
2312 chip->cyc_ctr.last_soc[i] = 0;
2313 }
2314 chip->cyc_ctr.started[i] = false;
2315 }
2316 }
2317out:
2318 mutex_unlock(&chip->cyc_ctr.lock);
2319}
2320
2321static int fg_get_cycle_count(struct fg_chip *chip)
2322{
2323 int count;
2324
2325 if (!chip->cyc_ctr.en)
2326 return 0;
2327
2328 if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT))
2329 return -EINVAL;
2330
2331 mutex_lock(&chip->cyc_ctr.lock);
2332 count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1];
2333 mutex_unlock(&chip->cyc_ctr.lock);
2334 return count;
2335}
2336
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002337static int fg_bp_params_config(struct fg_chip *chip)
2338{
2339 int rc = 0;
2340 u8 buf;
2341
2342 /* This SRAM register is only present in v2.0 and above */
2343 if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
2344 chip->bp.float_volt_uv > 0) {
2345 fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
2346 chip->bp.float_volt_uv / 1000, &buf);
2347 rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
2348 chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
2349 chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
2350 if (rc < 0) {
2351 pr_err("Error in writing float_volt, rc=%d\n", rc);
2352 return rc;
2353 }
2354 }
2355
2356 if (chip->bp.vbatt_full_mv > 0) {
2357 rc = fg_set_constant_chg_voltage(chip,
2358 chip->bp.vbatt_full_mv * 1000);
2359 if (rc < 0)
2360 return rc;
2361 }
2362
2363 return rc;
2364}
2365
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002366#define PROFILE_LOAD_BIT BIT(0)
2367#define BOOTLOADER_LOAD_BIT BIT(1)
2368#define BOOTLOADER_RESTART_BIT BIT(2)
2369#define HLOS_RESTART_BIT BIT(3)
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002370static bool is_profile_load_required(struct fg_chip *chip)
2371{
Nicholas Troaste29dec92016-08-24 09:35:11 -07002372 u8 buf[PROFILE_COMP_LEN], val;
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002373 bool profiles_same = false;
2374 int rc;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002375
Nicholas Troaste29dec92016-08-24 09:35:11 -07002376 rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
2377 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2378 if (rc < 0) {
2379 pr_err("failed to read profile integrity rc=%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002380 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002381 }
2382
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002383 /* Check if integrity bit is set */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002384 if (val & PROFILE_LOAD_BIT) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07002385 fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
Subbaraman Narayanamurthy73616e12017-03-20 14:37:54 -07002386
2387 /* Whitelist the values */
2388 val &= ~PROFILE_LOAD_BIT;
2389 if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
2390 val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
2391 val |= PROFILE_LOAD_BIT;
2392 pr_warn("Garbage value in profile integrity word: 0x%x\n",
2393 val);
2394 return true;
2395 }
2396
Nicholas Troaste29dec92016-08-24 09:35:11 -07002397 rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2398 buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
2399 if (rc < 0) {
2400 pr_err("Error in reading battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002401 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002402 }
2403 profiles_same = memcmp(chip->batt_profile, buf,
2404 PROFILE_COMP_LEN) == 0;
2405 if (profiles_same) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002406 fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
2407 return false;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002408 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002409
2410 if (!chip->dt.force_load_profile) {
2411 pr_warn("Profiles doesn't match, skipping loading it since force_load_profile is disabled\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002412 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002413 pr_info("FG: loaded profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002414 dump_sram(buf, PROFILE_LOAD_WORD,
2415 PROFILE_COMP_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002416 pr_info("FG: available profile:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002417 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2418 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002419 }
2420 return false;
2421 }
2422
2423 fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n");
2424 } else {
2425 fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002426 if (fg_profile_dump) {
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002427 pr_info("FG: profile to be loaded:\n");
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002428 dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
2429 PROFILE_LEN);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002430 }
Nicholas Troaste29dec92016-08-24 09:35:11 -07002431 }
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002432 return true;
2433}
2434
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08002435static void clear_battery_profile(struct fg_chip *chip)
2436{
2437 u8 val = 0;
2438 int rc;
2439
2440 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2441 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2442 if (rc < 0)
2443 pr_err("failed to write profile integrity rc=%d\n", rc);
2444}
2445
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002446#define SOC_READY_WAIT_MS 2000
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002447static int __fg_restart(struct fg_chip *chip)
2448{
2449 int rc, msoc;
2450 bool tried_again = false;
2451
2452 rc = fg_get_prop_capacity(chip, &msoc);
2453 if (rc < 0) {
2454 pr_err("Error in getting capacity, rc=%d\n", rc);
2455 return rc;
2456 }
2457
2458 chip->last_soc = msoc;
2459 chip->fg_restarting = true;
2460 reinit_completion(&chip->soc_ready);
2461 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT,
2462 RESTART_GO_BIT);
2463 if (rc < 0) {
2464 pr_err("Error in writing to %04x, rc=%d\n",
2465 BATT_SOC_RESTART(chip), rc);
2466 goto out;
2467 }
2468
2469wait:
2470 rc = wait_for_completion_interruptible_timeout(&chip->soc_ready,
2471 msecs_to_jiffies(SOC_READY_WAIT_MS));
2472
2473 /* If we were interrupted wait again one more time. */
2474 if (rc == -ERESTARTSYS && !tried_again) {
2475 tried_again = true;
2476 goto wait;
2477 } else if (rc <= 0) {
2478 pr_err("wait for soc_ready timed out rc=%d\n", rc);
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002479 }
2480
2481 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2482 if (rc < 0) {
2483 pr_err("Error in writing to %04x, rc=%d\n",
2484 BATT_SOC_RESTART(chip), rc);
2485 goto out;
2486 }
2487out:
2488 chip->fg_restarting = false;
2489 return rc;
2490}
2491
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002492static void profile_load_work(struct work_struct *work)
2493{
2494 struct fg_chip *chip = container_of(work,
2495 struct fg_chip,
2496 profile_load_work.work);
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07002497 u8 buf[2], val;
2498 int rc;
2499
2500 vote(chip->awake_votable, PROFILE_LOAD, true, 0);
2501 if (!is_profile_load_required(chip))
2502 goto done;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002503
2504 clear_cycle_counter(chip);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002505 mutex_lock(&chip->cl.lock);
2506 chip->cl.learned_cc_uah = 0;
2507 chip->cl.active = false;
2508 mutex_unlock(&chip->cl.lock);
2509
Nicholas Troaste29dec92016-08-24 09:35:11 -07002510 fg_dbg(chip, FG_STATUS, "profile loading started\n");
2511 rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0);
2512 if (rc < 0) {
2513 pr_err("Error in writing to %04x, rc=%d\n",
2514 BATT_SOC_RESTART(chip), rc);
2515 goto out;
2516 }
2517
2518 /* load battery profile */
2519 rc = fg_sram_write(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
2520 chip->batt_profile, PROFILE_LEN, FG_IMA_ATOMIC);
2521 if (rc < 0) {
2522 pr_err("Error in writing battery profile, rc:%d\n", rc);
2523 goto out;
2524 }
2525
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002526 rc = __fg_restart(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002527 if (rc < 0) {
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002528 pr_err("Error in restarting FG, rc=%d\n", rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002529 goto out;
2530 }
2531
2532 fg_dbg(chip, FG_STATUS, "SOC is ready\n");
2533
2534 /* Set the profile integrity bit */
Subbaraman Narayanamurthy402a6722016-10-26 18:12:10 -07002535 val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT;
Nicholas Troaste29dec92016-08-24 09:35:11 -07002536 rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
2537 PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT);
2538 if (rc < 0) {
2539 pr_err("failed to write profile integrity rc=%d\n", rc);
2540 goto out;
2541 }
2542
Nicholas Troaste29dec92016-08-24 09:35:11 -07002543done:
Subbaraman Narayanamurthy3a0d1732017-03-27 14:05:51 -07002544 rc = fg_bp_params_config(chip);
2545 if (rc < 0)
2546 pr_err("Error in configuring battery profile params, rc:%d\n",
2547 rc);
2548
Nicholas Troaste29dec92016-08-24 09:35:11 -07002549 rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
2550 FG_IMA_DEFAULT);
2551 if (rc < 0) {
2552 pr_err("Error in reading %04x[%d] rc=%d\n", NOM_CAP_WORD,
2553 NOM_CAP_OFFSET, rc);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07002554 } else {
2555 chip->cl.nom_cap_uah = (int)(buf[0] | buf[1] << 8) * 1000;
2556 rc = fg_load_learned_cap_from_sram(chip);
2557 if (rc < 0)
2558 pr_err("Error in loading capacity learning data, rc:%d\n",
2559 rc);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002560 }
2561
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002562 batt_psy_initialized(chip);
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07002563 fg_notify_charger(chip);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002564 chip->profile_loaded = true;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08002565 chip->soc_reporting_ready = true;
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002566 fg_dbg(chip, FG_STATUS, "profile loaded successfully");
Nicholas Troaste29dec92016-08-24 09:35:11 -07002567out:
2568 vote(chip->awake_votable, PROFILE_LOAD, false, 0);
Nicholas Troaste29dec92016-08-24 09:35:11 -07002569}
2570
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002571static void sram_dump_work(struct work_struct *work)
2572{
2573 struct fg_chip *chip = container_of(work, struct fg_chip,
2574 sram_dump_work.work);
2575 u8 buf[FG_SRAM_LEN];
2576 int rc;
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302577 s64 timestamp_ms, quotient;
2578 s32 remainder;
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002579
2580 rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
2581 if (rc < 0) {
2582 pr_err("Error in reading FG SRAM, rc:%d\n", rc);
2583 goto resched;
2584 }
2585
2586 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302587 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2588 fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
2589 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002590 dump_sram(buf, 0, FG_SRAM_LEN);
2591 timestamp_ms = ktime_to_ms(ktime_get_boottime());
Tirupathi Reddyce65d002017-02-10 18:06:40 +05302592 quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
2593 fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
2594 quotient, remainder);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08002595resched:
2596 schedule_delayed_work(&chip->sram_dump_work,
2597 msecs_to_jiffies(fg_sram_dump_period_ms));
2598}
2599
2600static int fg_sram_dump_sysfs(const char *val, const struct kernel_param *kp)
2601{
2602 int rc;
2603 struct power_supply *bms_psy;
2604 struct fg_chip *chip;
2605 bool old_val = fg_sram_dump;
2606
2607 rc = param_set_bool(val, kp);
2608 if (rc) {
2609 pr_err("Unable to set fg_sram_dump: %d\n", rc);
2610 return rc;
2611 }
2612
2613 if (fg_sram_dump == old_val)
2614 return 0;
2615
2616 bms_psy = power_supply_get_by_name("bms");
2617 if (!bms_psy) {
2618 pr_err("bms psy not found\n");
2619 return -ENODEV;
2620 }
2621
2622 chip = power_supply_get_drvdata(bms_psy);
2623 if (fg_sram_dump)
2624 schedule_delayed_work(&chip->sram_dump_work,
2625 msecs_to_jiffies(fg_sram_dump_period_ms));
2626 else
2627 cancel_delayed_work_sync(&chip->sram_dump_work);
2628
2629 return 0;
2630}
2631
2632static struct kernel_param_ops fg_sram_dump_ops = {
2633 .set = fg_sram_dump_sysfs,
2634 .get = param_get_bool,
2635};
2636
2637module_param_cb(sram_dump_en, &fg_sram_dump_ops, &fg_sram_dump, 0644);
2638
Subbaraman Narayanamurthy4f8e7d22016-09-22 19:36:39 -07002639static int fg_restart_sysfs(const char *val, const struct kernel_param *kp)
2640{
2641 int rc;
2642 struct power_supply *bms_psy;
2643 struct fg_chip *chip;
2644
2645 rc = param_set_int(val, kp);
2646 if (rc) {
2647 pr_err("Unable to set fg_restart: %d\n", rc);
2648 return rc;
2649 }
2650
2651 if (fg_restart != 1) {
2652 pr_err("Bad value %d\n", fg_restart);
2653 return -EINVAL;
2654 }
2655
2656 bms_psy = power_supply_get_by_name("bms");
2657 if (!bms_psy) {
2658 pr_err("bms psy not found\n");
2659 return 0;
2660 }
2661
2662 chip = power_supply_get_drvdata(bms_psy);
2663 rc = __fg_restart(chip);
2664 if (rc < 0) {
2665 pr_err("Error in restarting FG, rc=%d\n", rc);
2666 return rc;
2667 }
2668
2669 pr_info("FG restart done\n");
2670 return rc;
2671}
2672
2673static struct kernel_param_ops fg_restart_ops = {
2674 .set = fg_restart_sysfs,
2675 .get = param_get_int,
2676};
2677
2678module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
2679
Nicholas Troast1769fd32016-09-07 09:20:58 -07002680#define BATT_AVG_POLL_PERIOD_MS 10000
2681static void batt_avg_work(struct work_struct *work)
2682{
2683 struct fg_chip *chip = container_of(work, struct fg_chip,
2684 batt_avg_work.work);
2685 int rc, ibatt_now, vbatt_now;
2686
2687 mutex_lock(&chip->batt_avg_lock);
2688 rc = fg_get_battery_current(chip, &ibatt_now);
2689 if (rc < 0) {
2690 pr_err("failed to get battery current, rc=%d\n", rc);
2691 goto reschedule;
2692 }
2693
2694 rc = fg_get_battery_voltage(chip, &vbatt_now);
2695 if (rc < 0) {
2696 pr_err("failed to get battery voltage, rc=%d\n", rc);
2697 goto reschedule;
2698 }
2699
2700 fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now);
2701 fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now);
2702
2703reschedule:
2704 mutex_unlock(&chip->batt_avg_lock);
2705 schedule_delayed_work(&chip->batt_avg_work,
2706 msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS));
2707}
2708
Nicholas Troast1769fd32016-09-07 09:20:58 -07002709#define HOURS_TO_SECONDS 3600
2710#define OCV_SLOPE_UV 10869
2711#define MILLI_UNIT 1000
2712#define MICRO_UNIT 1000000
2713static int fg_get_time_to_full(struct fg_chip *chip, int *val)
2714{
2715 int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc,
2716 act_cap_uah;
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002717 s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale;
Nicholas Troast1769fd32016-09-07 09:20:58 -07002718 s64 t_predicted_cc = 0, t_predicted_cv = 0;
2719
2720 if (chip->bp.float_volt_uv <= 0) {
2721 pr_err("battery profile is not loaded\n");
2722 return -ENODATA;
2723 }
2724
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08002725 if (!batt_psy_initialized(chip)) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07002726 fg_dbg(chip, FG_TTF, "charger is not available\n");
2727 return -ENODATA;
2728 }
2729
Nicholas Troast32a22d32016-12-14 16:12:04 -08002730 rc = fg_get_prop_capacity(chip, &msoc);
2731 if (rc < 0) {
2732 pr_err("failed to get msoc rc=%d\n", rc);
2733 return rc;
2734 }
2735 fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
2736
2737 if (msoc >= 100) {
Nicholas Troast1769fd32016-09-07 09:20:58 -07002738 *val = 0;
2739 return 0;
2740 }
2741
2742 mutex_lock(&chip->batt_avg_lock);
2743 rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
2744 if (rc < 0) {
2745 /* try to get instantaneous current */
2746 rc = fg_get_battery_current(chip, &ibatt_avg);
2747 if (rc < 0) {
2748 mutex_unlock(&chip->batt_avg_lock);
2749 pr_err("failed to get battery current, rc=%d\n", rc);
2750 return rc;
2751 }
2752 }
2753
2754 rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg);
2755 if (rc < 0) {
2756 /* try to get instantaneous voltage */
2757 rc = fg_get_battery_voltage(chip, &vbatt_avg);
2758 if (rc < 0) {
2759 mutex_unlock(&chip->batt_avg_lock);
2760 pr_err("failed to get battery voltage, rc=%d\n", rc);
2761 return rc;
2762 }
2763 }
2764
2765 mutex_unlock(&chip->batt_avg_lock);
2766 fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
2767
2768 /* clamp ibatt_avg to -150mA */
2769 if (ibatt_avg > -150000)
2770 ibatt_avg = -150000;
2771 fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
2772
2773 /* reverse polarity to be consistent with unsigned current settings */
2774 ibatt_avg = abs(ibatt_avg);
2775
2776 /* estimated battery current at the CC to CV transition */
2777 i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv);
2778 fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
2779
2780 rc = fg_get_battery_resistance(chip, &rbatt);
2781 if (rc < 0) {
2782 pr_err("failed to get battery resistance rc=%d\n", rc);
2783 return rc;
2784 }
2785
2786 /* clamp rbatt to 50mOhms */
2787 if (rbatt < 50000)
2788 rbatt = 50000;
2789
2790 fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
2791
2792 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
2793 if (rc < 0) {
2794 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
2795 return rc;
2796 }
2797 act_cap_uah *= MILLI_UNIT;
2798 fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah);
2799
Nicholas Troast1769fd32016-09-07 09:20:58 -07002800 rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
2801 if (rc < 0) {
2802 pr_err("failed to get full soc rc=%d\n", rc);
2803 return rc;
2804 }
2805 full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
2806 FULL_SOC_RAW);
2807 fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc);
2808
2809 /* if we are already in CV state then we can skip estimating CC */
2810 if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
2811 goto skip_cc_estimate;
2812
2813 /* if the charger is current limited then use power approximation */
2814 if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000)
2815 ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT);
2816 else
2817 ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT);
2818 ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv;
2819 fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv);
2820
2821 soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV);
2822 /* estimated SOC at the CC to CV transition */
2823 soc_cc2cv = 100 - soc_cc2cv;
2824 fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
2825
2826 /* the esimated SOC may be lower than the current SOC */
2827 if (soc_cc2cv - msoc <= 0)
2828 goto skip_cc_estimate;
2829
2830 t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100);
2831 t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100);
2832 t_predicted_cc *= HOURS_TO_SECONDS;
2833 t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2);
2834
2835skip_cc_estimate:
2836 fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc);
2837
2838 /* CV estimate starts here */
Nicholas Troast32a22d32016-12-14 16:12:04 -08002839 if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER)
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002840 ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002841 else
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002842 ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200);
2843
2844 if (msoc < 95)
2845 centi_tau_scale = 100;
2846 else
2847 centi_tau_scale = 20 * (100 - msoc);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002848
2849 fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val);
2850 rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val);
2851 fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val);
2852 t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT);
Nicholas Troastde5d42f2017-01-20 16:47:31 -08002853 t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100);
Nicholas Troast1769fd32016-09-07 09:20:58 -07002854 t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT);
2855 t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT);
2856 fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv);
2857 *val = t_predicted_cc + t_predicted_cv;
2858 return 0;
2859}
2860
2861#define CENTI_ICORRECT_C0 105
2862#define CENTI_ICORRECT_C1 20
2863static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
2864{
2865 int rc, ibatt_avg, msoc, act_cap_uah;
2866 s32 divisor;
2867 s64 t_predicted;
2868
2869 rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
2870 if (rc < 0) {
2871 /* try to get instantaneous current */
2872 rc = fg_get_battery_current(chip, &ibatt_avg);
2873 if (rc < 0) {
2874 pr_err("failed to get battery current, rc=%d\n", rc);
2875 return rc;
2876 }
2877 }
2878
2879 /* clamp ibatt_avg to 150mA */
2880 if (ibatt_avg < 150000)
2881 ibatt_avg = 150000;
2882
2883 rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
2884 if (rc < 0) {
2885 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
2886 return rc;
2887 }
2888 act_cap_uah *= MILLI_UNIT;
2889
2890 rc = fg_get_prop_capacity(chip, &msoc);
2891 if (rc < 0) {
2892 pr_err("Error in getting capacity, rc=%d\n", rc);
2893 return rc;
2894 }
2895
2896 t_predicted = div_s64((s64)msoc * act_cap_uah, 100);
2897 t_predicted *= HOURS_TO_SECONDS;
2898 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
2899 divisor = div_s64((s64)divisor * ibatt_avg, 10000);
2900 if (divisor > 0)
2901 t_predicted = div_s64(t_predicted, divisor);
2902
2903 *val = t_predicted;
2904 return 0;
2905}
2906
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08002907static int fg_update_maint_soc(struct fg_chip *chip)
2908{
2909 int rc = 0, msoc;
2910
2911 mutex_lock(&chip->charge_full_lock);
2912 if (chip->delta_soc <= 0)
2913 goto out;
2914
2915 rc = fg_get_msoc(chip, &msoc);
2916 if (rc < 0) {
2917 pr_err("Error in getting msoc, rc=%d\n", rc);
2918 goto out;
2919 }
2920
2921 if (msoc > chip->maint_soc) {
2922 /*
2923 * When the monotonic SOC goes above maintenance SOC, we should
2924 * stop showing the maintenance SOC.
2925 */
2926 chip->delta_soc = 0;
2927 chip->maint_soc = 0;
2928 } else if (msoc <= chip->last_msoc) {
2929 /* MSOC is decreasing. Decrease maintenance SOC as well */
2930 chip->maint_soc -= 1;
2931 if (!(msoc % 10)) {
2932 /*
2933 * Reduce the maintenance SOC additionally by 1 whenever
2934 * it crosses a SOC multiple of 10.
2935 */
2936 chip->maint_soc -= 1;
2937 chip->delta_soc -= 1;
2938 }
2939 }
2940
2941 fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n",
2942 msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc);
2943 chip->last_msoc = msoc;
2944out:
2945 mutex_unlock(&chip->charge_full_lock);
2946 return rc;
2947}
2948
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08002949static int fg_esr_validate(struct fg_chip *chip)
2950{
2951 int rc, esr_uohms;
2952 u8 buf[2];
2953
2954 if (chip->dt.esr_clamp_mohms <= 0)
2955 return 0;
2956
2957 rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms);
2958 if (rc < 0) {
2959 pr_err("failed to get ESR, rc=%d\n", rc);
2960 return rc;
2961 }
2962
2963 if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) {
2964 pr_debug("ESR %d is > ESR_clamp\n", esr_uohms);
2965 return 0;
2966 }
2967
2968 esr_uohms = chip->dt.esr_clamp_mohms * 1000;
2969 fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf);
2970 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word,
2971 chip->sp[FG_SRAM_ESR].addr_byte, buf,
2972 chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT);
2973 if (rc < 0) {
2974 pr_err("Error in writing ESR, rc=%d\n", rc);
2975 return rc;
2976 }
2977
2978 fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms);
2979 return 0;
2980}
2981
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002982/* PSY CALLBACKS STAY HERE */
2983
2984static int fg_psy_get_property(struct power_supply *psy,
2985 enum power_supply_property psp,
2986 union power_supply_propval *pval)
2987{
2988 struct fg_chip *chip = power_supply_get_drvdata(psy);
2989 int rc = 0;
2990
2991 switch (psp) {
2992 case POWER_SUPPLY_PROP_CAPACITY:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08002993 rc = fg_get_prop_capacity(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002994 break;
2995 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Subbaraman Narayanamurthye55a6aa2017-01-24 18:45:14 -08002996 if (chip->battery_missing)
2997 pval->intval = 3700000;
2998 else
2999 rc = fg_get_battery_voltage(chip, &pval->intval);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003000 break;
3001 case POWER_SUPPLY_PROP_CURRENT_NOW:
3002 rc = fg_get_battery_current(chip, &pval->intval);
3003 break;
3004 case POWER_SUPPLY_PROP_TEMP:
3005 rc = fg_get_battery_temp(chip, &pval->intval);
3006 break;
3007 case POWER_SUPPLY_PROP_RESISTANCE:
3008 rc = fg_get_battery_resistance(chip, &pval->intval);
3009 break;
3010 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3011 rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval);
3012 break;
3013 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003014 pval->intval = chip->cl.nom_cap_uah;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003015 break;
3016 case POWER_SUPPLY_PROP_RESISTANCE_ID:
Subbaraman Narayanamurthy76cce8d2016-12-22 15:09:38 -08003017 pval->intval = chip->batt_id_ohms;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003018 break;
3019 case POWER_SUPPLY_PROP_BATTERY_TYPE:
3020 pval->strval = fg_get_battery_type(chip);
3021 break;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003022 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
3023 pval->intval = chip->bp.float_volt_uv;
Subbaraman Narayanamurthya6b1fd82016-10-17 20:08:59 -07003024 break;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003025 case POWER_SUPPLY_PROP_CYCLE_COUNT:
3026 pval->intval = fg_get_cycle_count(chip);
3027 break;
3028 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3029 pval->intval = chip->cyc_ctr.id;
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003030 break;
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003031 case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003032 rc = fg_get_charge_raw(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003033 break;
3034 case POWER_SUPPLY_PROP_CHARGE_NOW:
3035 pval->intval = chip->cl.init_cc_uah;
3036 break;
3037 case POWER_SUPPLY_PROP_CHARGE_FULL:
3038 pval->intval = chip->cl.learned_cc_uah;
3039 break;
3040 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Subbaraman Narayanamurthydd6ea382017-03-15 13:15:31 -07003041 rc = fg_get_charge_counter(chip, &pval->intval);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003042 break;
Nicholas Troast1769fd32016-09-07 09:20:58 -07003043 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
3044 rc = fg_get_time_to_full(chip, &pval->intval);
3045 break;
3046 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
3047 rc = fg_get_time_to_empty(chip, &pval->intval);
3048 break;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003049 case POWER_SUPPLY_PROP_SOC_REPORTING_READY:
3050 pval->intval = chip->soc_reporting_ready;
3051 break;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303052 case POWER_SUPPLY_PROP_DEBUG_BATTERY:
3053 pval->intval = is_debug_batt_id(chip);
3054 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003055 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3056 rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
3057 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003058 default:
Nicholas Troast1769fd32016-09-07 09:20:58 -07003059 pr_err("unsupported property %d\n", psp);
3060 rc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003061 break;
3062 }
3063
Nicholas Troast1769fd32016-09-07 09:20:58 -07003064 if (rc < 0)
3065 return -ENODATA;
3066
3067 return 0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003068}
3069
3070static int fg_psy_set_property(struct power_supply *psy,
3071 enum power_supply_property psp,
3072 const union power_supply_propval *pval)
3073{
Nicholas Troaste29dec92016-08-24 09:35:11 -07003074 struct fg_chip *chip = power_supply_get_drvdata(psy);
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003075 int rc = 0;
Nicholas Troaste29dec92016-08-24 09:35:11 -07003076
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003077 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003078 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
3079 if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) {
3080 chip->cyc_ctr.id = pval->intval;
3081 } else {
3082 pr_err("rejecting invalid cycle_count_id = %d\n",
3083 pval->intval);
3084 return -EINVAL;
3085 }
Nicholas Troast60242812017-06-20 09:33:21 -07003086 break;
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003087 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3088 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003089 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003090 default:
3091 break;
3092 }
3093
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003094 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003095}
3096
3097static int fg_property_is_writeable(struct power_supply *psy,
3098 enum power_supply_property psp)
3099{
3100 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003101 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003102 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Nicholas Troaste29dec92016-08-24 09:35:11 -07003103 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003104 default:
3105 break;
3106 }
3107
3108 return 0;
3109}
3110
3111static void fg_external_power_changed(struct power_supply *psy)
3112{
3113 pr_debug("power supply changed\n");
3114}
3115
3116static int fg_notifier_cb(struct notifier_block *nb,
3117 unsigned long event, void *data)
3118{
3119 struct power_supply *psy = data;
3120 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
3121
3122 if (event != PSY_EVENT_PROP_CHANGED)
3123 return NOTIFY_OK;
3124
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08003125 if (work_pending(&chip->status_change_work))
3126 return NOTIFY_OK;
3127
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003128 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003129 || (strcmp(psy->desc->name, "usb") == 0)) {
3130 /*
3131 * We cannot vote for awake votable here as that takes
3132 * a mutex lock and this is executed in an atomic context.
3133 */
3134 pm_stay_awake(chip->dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003135 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003136 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003137
3138 return NOTIFY_OK;
3139}
3140
3141static enum power_supply_property fg_psy_props[] = {
3142 POWER_SUPPLY_PROP_CAPACITY,
3143 POWER_SUPPLY_PROP_TEMP,
3144 POWER_SUPPLY_PROP_VOLTAGE_NOW,
3145 POWER_SUPPLY_PROP_VOLTAGE_OCV,
3146 POWER_SUPPLY_PROP_CURRENT_NOW,
3147 POWER_SUPPLY_PROP_RESISTANCE_ID,
3148 POWER_SUPPLY_PROP_RESISTANCE,
3149 POWER_SUPPLY_PROP_BATTERY_TYPE,
3150 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003151 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Nicholas Troaste29dec92016-08-24 09:35:11 -07003152 POWER_SUPPLY_PROP_CYCLE_COUNT,
3153 POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003154 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
3155 POWER_SUPPLY_PROP_CHARGE_NOW,
3156 POWER_SUPPLY_PROP_CHARGE_FULL,
3157 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Nicholas Troast1769fd32016-09-07 09:20:58 -07003158 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3159 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003160 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303161 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003162 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003163};
3164
3165static const struct power_supply_desc fg_psy_desc = {
3166 .name = "bms",
3167 .type = POWER_SUPPLY_TYPE_BMS,
3168 .properties = fg_psy_props,
3169 .num_properties = ARRAY_SIZE(fg_psy_props),
3170 .get_property = fg_psy_get_property,
3171 .set_property = fg_psy_set_property,
3172 .external_power_changed = fg_external_power_changed,
3173 .property_is_writeable = fg_property_is_writeable,
3174};
3175
3176/* INIT FUNCTIONS STAY HERE */
3177
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003178#define DEFAULT_ESR_CHG_TIMER_RETRY 8
3179#define DEFAULT_ESR_CHG_TIMER_MAX 16
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003180static int fg_hw_init(struct fg_chip *chip)
3181{
3182 int rc;
3183 u8 buf[4], val;
3184
3185 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003186 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
3187 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003188 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
3189 if (rc < 0) {
3190 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
3191 return rc;
3192 }
3193
3194 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003195 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
3196 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003197 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
3198 if (rc < 0) {
3199 pr_err("Error in writing empty_volt, rc=%d\n", rc);
3200 return rc;
3201 }
3202
3203 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
3204 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003205 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
3206 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003207 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
3208 if (rc < 0) {
3209 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
3210 return rc;
3211 }
3212
3213 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
3214 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003215 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
3216 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003217 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
3218 if (rc < 0) {
3219 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
3220 return rc;
3221 }
3222
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003223 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
3224 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
3225 chip->dt.chg_term_base_curr_ma, buf);
3226 rc = fg_sram_write(chip,
3227 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
3228 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
3229 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
3230 FG_IMA_DEFAULT);
3231 if (rc < 0) {
3232 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
3233 rc);
3234 return rc;
3235 }
3236 }
3237
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003238 if (chip->dt.vbatt_low_thr_mv > 0) {
3239 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
3240 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003241 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
3242 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003243 chip->sp[FG_SRAM_VBATT_LOW].len,
3244 FG_IMA_DEFAULT);
3245 if (rc < 0) {
3246 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
3247 return rc;
3248 }
3249 }
3250
3251 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003252 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003253 chip->dt.delta_soc_thr, buf);
3254 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003255 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
3256 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
3257 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003258 FG_IMA_DEFAULT);
3259 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003260 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
3261 return rc;
3262 }
3263
3264 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
3265 chip->dt.delta_soc_thr, buf);
3266 rc = fg_sram_write(chip,
3267 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
3268 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
3269 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
3270 FG_IMA_DEFAULT);
3271 if (rc < 0) {
3272 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003273 return rc;
3274 }
3275 }
3276
cyizhaofb3eec52017-01-24 17:08:55 +08003277 /*
3278 * configure battery thermal coefficients c1,c2,c3
3279 * if its value is not zero.
3280 */
3281 if (chip->dt.batt_therm_coeffs[0] > 0) {
3282 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
3283 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
3284 if (rc < 0) {
3285 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
3286 rc);
3287 return rc;
3288 }
3289 }
3290
3291
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003292 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003293 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003294 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003295 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003296 return rc;
3297 }
3298 }
3299
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003300 if (chip->dt.recharge_volt_thr_mv > 0) {
3301 rc = fg_set_recharge_voltage(chip,
3302 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003303 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003304 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003305 rc);
3306 return rc;
3307 }
3308 }
3309
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003310 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
3311 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
3312 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
3313 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
3314 if (rc < 0) {
3315 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
3316 return rc;
3317 }
3318 }
3319
3320 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
3321 rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
3322 if (rc < 0) {
3323 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3324 return rc;
3325 }
3326
3327 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
3328 rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
3329 if (rc < 0) {
3330 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
3331 return rc;
3332 }
3333
3334 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
3335 rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
3336 if (rc < 0) {
3337 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
3338 return rc;
3339 }
3340
3341 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
3342 rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
3343 if (rc < 0) {
3344 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
3345 return rc;
3346 }
3347
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003348 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
3349 chip->esr_timer_charging_default[TIMER_RETRY] =
3350 DEFAULT_ESR_CHG_TIMER_RETRY;
3351 chip->esr_timer_charging_default[TIMER_MAX] =
3352 DEFAULT_ESR_CHG_TIMER_MAX;
3353 } else {
3354 /* We don't need this for pm660 at present */
3355 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
3356 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003357 }
3358
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003359 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
3360 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
3361 if (rc < 0) {
3362 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3363 return rc;
3364 }
3365
3366 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
3367 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
3368 if (rc < 0) {
3369 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3370 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003371 }
3372
Nicholas Troaste29dec92016-08-24 09:35:11 -07003373 if (chip->cyc_ctr.en)
3374 restore_cycle_counter(chip);
3375
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003376 if (chip->dt.jeita_hyst_temp >= 0) {
3377 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
3378 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
3379 JEITA_TEMP_HYST_MASK, val);
3380 if (rc < 0) {
3381 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
3382 return rc;
3383 }
3384 }
3385
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003386 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
3387 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
3388 CHANGE_THOLD_MASK, val);
3389 if (rc < 0) {
3390 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
3391 return rc;
3392 }
3393
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07003394 rc = fg_rconn_config(chip);
3395 if (rc < 0) {
3396 pr_err("Error in configuring Rconn, rc=%d\n", rc);
3397 return rc;
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08003398 }
3399
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003400 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
3401 chip->dt.esr_tight_flt_upct, buf);
3402 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
3403 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
3404 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
3405 if (rc < 0) {
3406 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
3407 return rc;
3408 }
3409
3410 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
3411 chip->dt.esr_broad_flt_upct, buf);
3412 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
3413 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
3414 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
3415 if (rc < 0) {
3416 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
3417 return rc;
3418 }
3419
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003420 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
3421 chip->dt.esr_pulse_thresh_ma, buf);
3422 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
3423 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
3424 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
3425 if (rc < 0) {
3426 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
3427 return rc;
3428 }
3429
3430 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
3431 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3432 ESR_PULL_DOWN_IVAL_MASK, val);
3433 if (rc < 0) {
3434 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
3435 return rc;
3436 }
3437
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07003438 if (is_debug_batt_id(chip)) {
3439 val = ESR_NO_PULL_DOWN;
3440 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3441 ESR_PULL_DOWN_MODE_MASK, val);
3442 if (rc < 0) {
3443 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
3444 return rc;
3445 }
3446 }
3447
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003448 return 0;
3449}
3450
3451static int fg_memif_init(struct fg_chip *chip)
3452{
3453 return fg_ima_init(chip);
3454}
3455
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303456static int fg_adjust_timebase(struct fg_chip *chip)
3457{
3458 int rc = 0, die_temp;
3459 s32 time_base = 0;
3460 u8 buf[2] = {0};
3461
3462 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
3463 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
3464 if (rc < 0) {
3465 pr_err("Error in reading die_temp, rc:%d\n", rc);
3466 return rc;
3467 }
3468
3469 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
3470 die_temp / 1000, &time_base);
3471 if (rc < 0) {
3472 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
3473 return rc;
3474 }
3475
3476 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
3477 rc = fg_sram_write(chip,
3478 chip->sp[FG_SRAM_TIMEBASE].addr_word,
3479 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
3480 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
3481 if (rc < 0) {
3482 pr_err("Error in writing timebase, rc=%d\n", rc);
3483 return rc;
3484 }
3485 }
3486
3487 return 0;
3488}
3489
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003490/* INTERRUPT HANDLERS STAY HERE */
3491
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003492static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
3493{
3494 struct fg_chip *chip = data;
3495 u8 status;
3496 int rc;
3497
3498 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
3499 if (rc < 0) {
3500 pr_err("failed to read addr=0x%04x, rc=%d\n",
3501 MEM_IF_INT_RT_STS(chip), rc);
3502 return IRQ_HANDLED;
3503 }
3504
3505 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003506
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003507 mutex_lock(&chip->sram_rw_lock);
3508 rc = fg_clear_dma_errors_if_any(chip);
3509 if (rc < 0)
3510 pr_err("Error in clearing DMA error, rc=%d\n", rc);
3511
3512 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003513 rc = fg_clear_ima_errors_if_any(chip, true);
3514 if (rc < 0 && rc != -EAGAIN)
3515 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003516 }
3517
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003518 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003519 return IRQ_HANDLED;
3520}
3521
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003522static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
3523{
3524 struct fg_chip *chip = data;
3525
3526 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3527 return IRQ_HANDLED;
3528}
3529
3530static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
3531{
3532 struct fg_chip *chip = data;
3533 u8 status;
3534 int rc;
3535
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003536 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
3537 if (rc < 0) {
3538 pr_err("failed to read addr=0x%04x, rc=%d\n",
3539 BATT_INFO_INT_RT_STS(chip), rc);
3540 return IRQ_HANDLED;
3541 }
3542
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003543 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003544 chip->battery_missing = (status & BT_MISS_BIT);
3545
3546 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07003547 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003548 chip->profile_loaded = false;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003549 chip->soc_reporting_ready = false;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003550 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003551 }
3552
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003553 rc = fg_get_batt_id(chip);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003554 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003555 chip->soc_reporting_ready = true;
3556 pr_err("Error in getting battery id, rc:%d\n", rc);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003557 return IRQ_HANDLED;
3558 }
3559
3560 rc = fg_get_batt_profile(chip);
3561 if (rc < 0) {
3562 chip->soc_reporting_ready = true;
3563 pr_err("Error in getting battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003564 return IRQ_HANDLED;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003565 }
3566
3567 clear_battery_profile(chip);
3568 schedule_delayed_work(&chip->profile_load_work, 0);
3569
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303570 if (chip->fg_psy)
3571 power_supply_changed(chip->fg_psy);
3572
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003573 return IRQ_HANDLED;
3574}
3575
3576static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
3577{
3578 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003579 union power_supply_propval prop = {0, };
3580 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003581
3582 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003583 rc = fg_get_battery_temp(chip, &batt_temp);
3584 if (rc < 0) {
3585 pr_err("Error in getting batt_temp\n");
3586 return IRQ_HANDLED;
3587 }
3588
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003589 rc = fg_esr_filter_config(chip, batt_temp);
3590 if (rc < 0)
3591 pr_err("Error in configuring ESR filter rc:%d\n", rc);
3592
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003593 rc = fg_slope_limit_config(chip, batt_temp);
3594 if (rc < 0)
3595 pr_err("Error in configuring slope limiter rc:%d\n", rc);
3596
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07003597 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
3598 if (rc < 0)
3599 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
3600
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003601 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003602 chip->last_batt_temp = batt_temp;
3603 return IRQ_HANDLED;
3604 }
3605
3606 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
3607 &prop);
3608 chip->health = prop.intval;
3609
3610 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303611 rc = fg_adjust_timebase(chip);
3612 if (rc < 0)
3613 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3614
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003615 chip->last_batt_temp = batt_temp;
3616 power_supply_changed(chip->batt_psy);
3617 }
3618
3619 if (abs(chip->last_batt_temp - batt_temp) > 30)
3620 pr_warn("Battery temperature last:%d current: %d\n",
3621 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003622 return IRQ_HANDLED;
3623}
3624
3625static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
3626{
3627 struct fg_chip *chip = data;
3628
3629 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3630 complete_all(&chip->soc_ready);
3631 return IRQ_HANDLED;
3632}
3633
3634static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
3635{
3636 struct fg_chip *chip = data;
3637
3638 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3639 complete_all(&chip->soc_update);
3640 return IRQ_HANDLED;
3641}
3642
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003643static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
3644{
3645 struct fg_chip *chip = data;
3646 int rc;
3647
3648 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3649 rc = fg_charge_full_update(chip);
3650 if (rc < 0)
3651 pr_err("Error in charge_full_update, rc=%d\n", rc);
3652
3653 return IRQ_HANDLED;
3654}
3655
3656static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003657{
3658 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003659 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003660
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003661 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003662 if (chip->cyc_ctr.en)
3663 schedule_work(&chip->cycle_count_work);
3664
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003665 if (chip->cl.active)
3666 fg_cap_learning_update(chip);
3667
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003668 rc = fg_charge_full_update(chip);
3669 if (rc < 0)
3670 pr_err("Error in charge_full_update, rc=%d\n", rc);
3671
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003672 rc = fg_adjust_ki_coeff_dischg(chip);
3673 if (rc < 0)
3674 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
3675
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003676 rc = fg_update_maint_soc(chip);
3677 if (rc < 0)
3678 pr_err("Error in updating maint_soc, rc=%d\n", rc);
3679
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003680 rc = fg_esr_validate(chip);
3681 if (rc < 0)
3682 pr_err("Error in validating ESR, rc=%d\n", rc);
3683
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303684 rc = fg_adjust_timebase(chip);
3685 if (rc < 0)
3686 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3687
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003688 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003689 power_supply_changed(chip->batt_psy);
3690
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003691 return IRQ_HANDLED;
3692}
3693
3694static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
3695{
3696 struct fg_chip *chip = data;
3697
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003698 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003699 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07003700 power_supply_changed(chip->batt_psy);
3701
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003702 return IRQ_HANDLED;
3703}
3704
3705static irqreturn_t fg_soc_irq_handler(int irq, void *data)
3706{
3707 struct fg_chip *chip = data;
3708
3709 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3710 return IRQ_HANDLED;
3711}
3712
3713static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
3714{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003715 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003716 return IRQ_HANDLED;
3717}
3718
3719static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
3720 /* BATT_SOC irqs */
3721 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003722 .name = "msoc-full",
3723 .handler = fg_soc_irq_handler,
3724 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003725 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003726 .name = "msoc-high",
3727 .handler = fg_soc_irq_handler,
3728 .wakeable = true,
3729 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003730 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003731 .name = "msoc-empty",
3732 .handler = fg_empty_soc_irq_handler,
3733 .wakeable = true,
3734 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003735 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003736 .name = "msoc-low",
3737 .handler = fg_soc_irq_handler,
3738 .wakeable = true,
3739 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003740 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003741 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003742 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003743 .wakeable = true,
3744 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003745 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003746 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003747 .handler = fg_delta_bsoc_irq_handler,
3748 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003749 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003750 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003751 .name = "soc-ready",
3752 .handler = fg_first_est_irq_handler,
3753 .wakeable = true,
3754 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003755 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003756 .name = "soc-update",
3757 .handler = fg_soc_update_irq_handler,
3758 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003759 /* BATT_INFO irqs */
3760 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003761 .name = "batt-temp-delta",
3762 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003763 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003764 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003765 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003766 .name = "batt-missing",
3767 .handler = fg_batt_missing_irq_handler,
3768 .wakeable = true,
3769 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003770 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003771 .name = "esr-delta",
3772 .handler = fg_dummy_irq_handler,
3773 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003774 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003775 .name = "vbatt-low",
3776 .handler = fg_vbatt_low_irq_handler,
3777 .wakeable = true,
3778 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003779 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003780 .name = "vbatt-pred-delta",
3781 .handler = fg_dummy_irq_handler,
3782 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003783 /* MEM_IF irqs */
3784 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003785 .name = "dma-grant",
3786 .handler = fg_dummy_irq_handler,
3787 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003788 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003789 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003790 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003791 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003792 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003793 .name = "ima-rdy",
3794 .handler = fg_dummy_irq_handler,
3795 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003796};
3797
3798static int fg_get_irq_index_byname(const char *name)
3799{
3800 int i;
3801
3802 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
3803 if (strcmp(fg_irqs[i].name, name) == 0)
3804 return i;
3805 }
3806
3807 pr_err("%s is not in irq list\n", name);
3808 return -ENOENT;
3809}
3810
3811static int fg_register_interrupts(struct fg_chip *chip)
3812{
3813 struct device_node *child, *node = chip->dev->of_node;
3814 struct property *prop;
3815 const char *name;
3816 int rc, irq, irq_index;
3817
3818 for_each_available_child_of_node(node, child) {
3819 of_property_for_each_string(child, "interrupt-names", prop,
3820 name) {
3821 irq = of_irq_get_byname(child, name);
3822 if (irq < 0) {
3823 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
3824 name, irq);
3825 return irq;
3826 }
3827
3828 irq_index = fg_get_irq_index_byname(name);
3829 if (irq_index < 0)
3830 return irq_index;
3831
3832 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
3833 fg_irqs[irq_index].handler,
3834 IRQF_ONESHOT, name, chip);
3835 if (rc < 0) {
3836 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
3837 name, rc);
3838 return rc;
3839 }
3840
3841 fg_irqs[irq_index].irq = irq;
3842 if (fg_irqs[irq_index].wakeable)
3843 enable_irq_wake(fg_irqs[irq_index].irq);
3844 }
3845 }
3846
3847 return 0;
3848}
3849
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003850static int fg_parse_dt_property_u32_array(struct device_node *node,
3851 const char *prop_name, int *buf, int len)
3852{
3853 int rc;
3854
3855 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
3856 if (rc < 0) {
3857 if (rc == -EINVAL)
3858 return 0;
3859 else
3860 return rc;
3861 } else if (rc != len) {
3862 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
3863 rc);
3864 return -EINVAL;
3865 }
3866
3867 rc = of_property_read_u32_array(node, prop_name, buf, len);
3868 if (rc < 0) {
3869 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
3870 return rc;
3871 }
3872
3873 return 0;
3874}
3875
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003876static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
3877{
3878 struct device_node *node = chip->dev->of_node;
3879 int rc, i;
3880
3881 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
3882 &chip->dt.slope_limit_temp);
3883 if (rc < 0)
3884 return 0;
3885
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003886 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
3887 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
3888 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003889 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003890
3891 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
3892 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
3893 chip->dt.slope_limit_coeffs[i] < 0) {
3894 pr_err("Incorrect slope limit coefficient\n");
3895 return -EINVAL;
3896 }
3897 }
3898
3899 chip->slope_limit_en = true;
3900 return 0;
3901}
3902
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003903static int fg_parse_ki_coefficients(struct fg_chip *chip)
3904{
3905 struct device_node *node = chip->dev->of_node;
3906 int rc, i;
3907
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003908 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
3909 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
3910 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003911 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003912
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003913 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
3914 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
3915 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003916 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003917
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003918 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
3919 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
3920 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003921 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003922
3923 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
3924 if (chip->dt.ki_coeff_soc[i] < 0 ||
3925 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
3926 pr_err("Error in ki_coeff_soc_dischg values\n");
3927 return -EINVAL;
3928 }
3929
3930 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
3931 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
3932 pr_err("Error in ki_coeff_med_dischg values\n");
3933 return -EINVAL;
3934 }
3935
3936 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
3937 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
3938 pr_err("Error in ki_coeff_med_dischg values\n");
3939 return -EINVAL;
3940 }
3941 }
3942 chip->ki_coeff_dischg_en = true;
3943 return 0;
3944}
3945
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003946#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07003947#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003948#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003949#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003950#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07003951#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003952#define DEFAULT_DELTA_SOC_THR 1
3953#define DEFAULT_RECHARGE_SOC_THR 95
3954#define DEFAULT_BATT_TEMP_COLD 0
3955#define DEFAULT_BATT_TEMP_COOL 5
3956#define DEFAULT_BATT_TEMP_WARM 45
3957#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003958#define DEFAULT_CL_START_SOC 15
3959#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
3960#define DEFAULT_CL_MAX_TEMP_DECIDEGC 450
3961#define DEFAULT_CL_MAX_INC_DECIPERC 5
3962#define DEFAULT_CL_MAX_DEC_DECIPERC 100
3963#define DEFAULT_CL_MIN_LIM_DECIPERC 0
3964#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003965#define BTEMP_DELTA_LOW 2
3966#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003967#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
3968#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
3969#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
3970#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
3971#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003972#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003973#define DEFAULT_ESR_PULSE_THRESH_MA 110
3974#define DEFAULT_ESR_MEAS_CURR_MA 120
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003975static int fg_parse_dt(struct fg_chip *chip)
3976{
3977 struct device_node *child, *revid_node, *node = chip->dev->of_node;
3978 u32 base, temp;
3979 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003980 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003981
3982 if (!node) {
3983 dev_err(chip->dev, "device tree node missing\n");
3984 return -ENXIO;
3985 }
3986
3987 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
3988 if (!revid_node) {
3989 pr_err("Missing qcom,pmic-revid property - driver failed\n");
3990 return -EINVAL;
3991 }
3992
3993 chip->pmic_rev_id = get_revid_data(revid_node);
3994 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
3995 pr_err("Unable to get pmic_revid rc=%ld\n",
3996 PTR_ERR(chip->pmic_rev_id));
3997 /*
3998 * the revid peripheral must be registered, any failure
3999 * here only indicates that the rev-id module has not
4000 * probed yet.
4001 */
4002 return -EPROBE_DEFER;
4003 }
4004
4005 pr_debug("PMIC subtype %d Digital major %d\n",
4006 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
4007
4008 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004009 case PMI8998_SUBTYPE:
4010 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
4011 chip->sp = pmi8998_v1_sram_params;
4012 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304013 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08004014 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
4015 chip->sp = pmi8998_v2_sram_params;
4016 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07004017 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004018 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07004019 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004020 break;
Harry Yange4e731b2017-03-06 14:35:09 -08004021 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304022 chip->sp = pmi8998_v2_sram_params;
4023 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07004024 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304025 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
4026 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304027 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004028 default:
4029 return -EINVAL;
4030 }
4031
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004032 if (of_get_available_child_count(node) == 0) {
4033 dev_err(chip->dev, "No child nodes specified!\n");
4034 return -ENXIO;
4035 }
4036
4037 for_each_available_child_of_node(node, child) {
4038 rc = of_property_read_u32(child, "reg", &base);
4039 if (rc < 0) {
4040 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
4041 child->full_name, rc);
4042 return rc;
4043 }
4044
4045 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
4046 if (rc < 0) {
4047 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
4048 base, rc);
4049 return rc;
4050 }
4051
4052 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004053 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004054 chip->batt_soc_base = base;
4055 break;
Harry Yang2452b272017-03-06 13:56:14 -08004056 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004057 chip->batt_info_base = base;
4058 break;
Harry Yang2452b272017-03-06 13:56:14 -08004059 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004060 chip->mem_if_base = base;
4061 break;
4062 default:
4063 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
4064 subtype);
4065 return -ENXIO;
4066 }
4067 }
4068
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004069 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
4070 if (rc < 0) {
4071 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
4072 return rc;
4073 }
4074 chip->rradc_base = base;
4075
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004076 /* Read all the optional properties below */
4077 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
4078 if (rc < 0)
4079 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
4080 else
4081 chip->dt.cutoff_volt_mv = temp;
4082
4083 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
4084 if (rc < 0)
4085 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
4086 else
4087 chip->dt.empty_volt_mv = temp;
4088
4089 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
4090 if (rc < 0)
4091 chip->dt.vbatt_low_thr_mv = -EINVAL;
4092 else
4093 chip->dt.vbatt_low_thr_mv = temp;
4094
4095 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
4096 if (rc < 0)
4097 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
4098 else
4099 chip->dt.chg_term_curr_ma = temp;
4100
4101 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
4102 if (rc < 0)
4103 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
4104 else
4105 chip->dt.sys_term_curr_ma = temp;
4106
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004107 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
4108 if (rc < 0)
4109 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
4110 else
4111 chip->dt.chg_term_base_curr_ma = temp;
4112
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004113 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
4114 if (rc < 0)
4115 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
4116 else
4117 chip->dt.delta_soc_thr = temp;
4118
4119 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
4120 if (rc < 0)
4121 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
4122 else
4123 chip->dt.recharge_soc_thr = temp;
4124
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004125 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
4126 if (rc < 0)
4127 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
4128 else
4129 chip->dt.recharge_volt_thr_mv = temp;
4130
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004131 chip->dt.auto_recharge_soc = of_property_read_bool(node,
4132 "qcom,fg-auto-recharge-soc");
4133
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004134 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
4135 if (rc < 0)
4136 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
4137 else
4138 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
4139
4140 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
4141 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
4142 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
4143 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004144 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
4145 sizeof(u32)) == NUM_JEITA_LEVELS) {
4146 rc = of_property_read_u32_array(node,
4147 "qcom,fg-jeita-thresholds",
4148 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
4149 if (rc < 0)
4150 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
4151 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004152 }
4153
cyizhaofb3eec52017-01-24 17:08:55 +08004154 if (of_property_count_elems_of_size(node,
4155 "qcom,battery-thermal-coefficients",
4156 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
4157 rc = of_property_read_u8_array(node,
4158 "qcom,battery-thermal-coefficients",
4159 chip->dt.batt_therm_coeffs,
4160 BATT_THERM_NUM_COEFFS);
4161 if (rc < 0)
4162 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
4163 rc);
4164 }
4165
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004166 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
4167 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
4168 if (rc < 0) {
4169 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
4170 chip->dt.esr_timer_charging[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-awake",
4174 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
4175 if (rc < 0) {
4176 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
4177 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
4178 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004179
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004180 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
4181 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
4182 if (rc < 0) {
4183 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
4184 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
4185 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004186
Nicholas Troaste29dec92016-08-24 09:35:11 -07004187 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
4188 if (chip->cyc_ctr.en)
4189 chip->cyc_ctr.id = 1;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004190
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07004191 chip->dt.force_load_profile = of_property_read_bool(node,
4192 "qcom,fg-force-load-profile");
4193
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004194 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
4195 if (rc < 0)
4196 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
4197 else
4198 chip->dt.cl_start_soc = temp;
4199
4200 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
4201 if (rc < 0)
4202 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
4203 else
4204 chip->dt.cl_min_temp = temp;
4205
4206 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
4207 if (rc < 0)
4208 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
4209 else
4210 chip->dt.cl_max_temp = temp;
4211
4212 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
4213 if (rc < 0)
4214 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
4215 else
4216 chip->dt.cl_max_cap_inc = temp;
4217
4218 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
4219 if (rc < 0)
4220 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
4221 else
4222 chip->dt.cl_max_cap_dec = temp;
4223
4224 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
4225 if (rc < 0)
4226 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
4227 else
4228 chip->dt.cl_min_cap_limit = temp;
4229
4230 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
4231 if (rc < 0)
4232 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
4233 else
4234 chip->dt.cl_max_cap_limit = temp;
4235
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004236 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
4237 if (rc < 0)
4238 chip->dt.jeita_hyst_temp = -EINVAL;
4239 else
4240 chip->dt.jeita_hyst_temp = temp;
4241
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004242 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
4243 if (rc < 0)
4244 chip->dt.batt_temp_delta = -EINVAL;
4245 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
4246 chip->dt.batt_temp_delta = temp;
4247
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004248 chip->dt.hold_soc_while_full = of_property_read_bool(node,
4249 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004250
4251 rc = fg_parse_ki_coefficients(chip);
4252 if (rc < 0)
4253 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
4254
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004255 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07004256 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004257 chip->dt.rconn_mohms = temp;
4258
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004259 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
4260 &temp);
4261 if (rc < 0)
4262 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
4263 else
4264 chip->dt.esr_flt_switch_temp = temp;
4265
4266 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
4267 &temp);
4268 if (rc < 0)
4269 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
4270 else
4271 chip->dt.esr_tight_flt_upct = temp;
4272
4273 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
4274 &temp);
4275 if (rc < 0)
4276 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
4277 else
4278 chip->dt.esr_broad_flt_upct = temp;
4279
4280 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
4281 &temp);
4282 if (rc < 0)
4283 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
4284 else
4285 chip->dt.esr_tight_lt_flt_upct = temp;
4286
4287 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
4288 &temp);
4289 if (rc < 0)
4290 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
4291 else
4292 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004293
4294 rc = fg_parse_slope_limit_coefficients(chip);
4295 if (rc < 0)
4296 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
4297
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004298 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
4299 if (rc < 0)
4300 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
4301 else
4302 chip->dt.esr_clamp_mohms = temp;
4303
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004304 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
4305 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
4306 if (!rc) {
4307 /* ESR pulse qualification threshold range is 1-997 mA */
4308 if (temp > 0 && temp < 997)
4309 chip->dt.esr_pulse_thresh_ma = temp;
4310 }
4311
4312 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
4313 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
4314 if (!rc) {
4315 /* ESR measurement current range is 60-240 mA */
4316 if (temp >= 60 || temp <= 240)
4317 chip->dt.esr_meas_curr_ma = temp;
4318 }
4319
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004320 return 0;
4321}
4322
4323static void fg_cleanup(struct fg_chip *chip)
4324{
4325 power_supply_unreg_notifier(&chip->nb);
Nicholas Troast69da2252016-09-07 16:17:47 -07004326 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004327 if (chip->awake_votable)
4328 destroy_votable(chip->awake_votable);
4329
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004330 if (chip->delta_bsoc_irq_en_votable)
4331 destroy_votable(chip->delta_bsoc_irq_en_votable);
4332
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004333 if (chip->batt_id_chan)
4334 iio_channel_release(chip->batt_id_chan);
4335
4336 dev_set_drvdata(chip->dev, NULL);
4337}
4338
4339static int fg_gen3_probe(struct platform_device *pdev)
4340{
4341 struct fg_chip *chip;
4342 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004343 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004344
4345 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
4346 if (!chip)
4347 return -ENOMEM;
4348
4349 chip->dev = &pdev->dev;
4350 chip->debug_mask = &fg_gen3_debug_mask;
4351 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07004352 chip->charge_status = -EINVAL;
4353 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004354 chip->ki_coeff_full_soc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004355 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
4356 if (!chip->regmap) {
4357 dev_err(chip->dev, "Parent regmap is unavailable\n");
4358 return -ENXIO;
4359 }
4360
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004361 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
4362 if (IS_ERR(chip->batt_id_chan)) {
4363 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
4364 pr_err("batt_id_chan unavailable %ld\n",
4365 PTR_ERR(chip->batt_id_chan));
4366 rc = PTR_ERR(chip->batt_id_chan);
4367 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004368 return rc;
4369 }
4370
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304371 rc = of_property_match_string(chip->dev->of_node,
4372 "io-channel-names", "rradc_die_temp");
4373 if (rc >= 0) {
4374 chip->die_temp_chan = iio_channel_get(chip->dev,
4375 "rradc_die_temp");
4376 if (IS_ERR(chip->die_temp_chan)) {
4377 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
4378 pr_err("rradc_die_temp unavailable %ld\n",
4379 PTR_ERR(chip->die_temp_chan));
4380 rc = PTR_ERR(chip->die_temp_chan);
4381 chip->die_temp_chan = NULL;
4382 return rc;
4383 }
4384 }
4385
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004386 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
4387 chip);
4388 if (IS_ERR(chip->awake_votable)) {
4389 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004390 goto exit;
4391 }
4392
4393 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
4394 VOTE_SET_ANY,
4395 fg_delta_bsoc_irq_en_cb, chip);
4396 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
4397 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
4398 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004399 }
4400
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004401 rc = fg_parse_dt(chip);
4402 if (rc < 0) {
4403 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
4404 rc);
4405 goto exit;
4406 }
4407
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004408 mutex_init(&chip->bus_lock);
4409 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004410 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004411 mutex_init(&chip->cl.lock);
Nicholas Troast1769fd32016-09-07 09:20:58 -07004412 mutex_init(&chip->batt_avg_lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004413 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004414 init_completion(&chip->soc_update);
4415 init_completion(&chip->soc_ready);
4416 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
4417 INIT_WORK(&chip->status_change_work, status_change_work);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004418 INIT_WORK(&chip->cycle_count_work, cycle_count_work);
Nicholas Troast1769fd32016-09-07 09:20:58 -07004419 INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004420 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004421
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004422 rc = fg_get_batt_id(chip);
4423 if (rc < 0) {
4424 pr_err("Error in getting battery id, rc:%d\n", rc);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004425 goto exit;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004426 }
4427
4428 rc = fg_get_batt_profile(chip);
4429 if (rc < 0) {
4430 chip->soc_reporting_ready = true;
4431 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
4432 chip->batt_id_ohms / 1000, rc);
4433 }
4434
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004435 rc = fg_memif_init(chip);
4436 if (rc < 0) {
4437 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
4438 rc);
4439 goto exit;
4440 }
4441
4442 rc = fg_hw_init(chip);
4443 if (rc < 0) {
4444 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
4445 rc);
4446 goto exit;
4447 }
4448
4449 platform_set_drvdata(pdev, chip);
4450
4451 /* Register the power supply */
4452 fg_psy_cfg.drv_data = chip;
4453 fg_psy_cfg.of_node = NULL;
4454 fg_psy_cfg.supplied_to = NULL;
4455 fg_psy_cfg.num_supplicants = 0;
4456 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
4457 &fg_psy_cfg);
4458 if (IS_ERR(chip->fg_psy)) {
4459 pr_err("failed to register fg_psy rc = %ld\n",
4460 PTR_ERR(chip->fg_psy));
4461 goto exit;
4462 }
4463
4464 chip->nb.notifier_call = fg_notifier_cb;
4465 rc = power_supply_reg_notifier(&chip->nb);
4466 if (rc < 0) {
4467 pr_err("Couldn't register psy notifier rc = %d\n", rc);
4468 goto exit;
4469 }
4470
4471 rc = fg_register_interrupts(chip);
4472 if (rc < 0) {
4473 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
4474 rc);
4475 goto exit;
4476 }
4477
4478 /* Keep SOC_UPDATE irq disabled until we require it */
4479 if (fg_irqs[SOC_UPDATE_IRQ].irq)
4480 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
4481
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004482 /* Keep BSOC_DELTA_IRQ irq disabled until we require it */
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004483 rerun_election(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004484
Nicholas Troast69da2252016-09-07 16:17:47 -07004485 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004486 if (rc < 0) {
4487 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
4488 rc);
4489 goto exit;
4490 }
4491
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004492 rc = fg_get_battery_voltage(chip, &volt_uv);
4493 if (!rc)
4494 rc = fg_get_prop_capacity(chip, &msoc);
4495
4496 if (!rc)
4497 rc = fg_get_battery_temp(chip, &batt_temp);
4498
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004499 if (!rc) {
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004500 pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004501 msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004502 rc = fg_esr_filter_config(chip, batt_temp);
4503 if (rc < 0)
4504 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4505 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004506
4507 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07004508 if (chip->profile_available)
4509 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004510
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004511 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004512 return 0;
4513exit:
4514 fg_cleanup(chip);
4515 return rc;
4516}
4517
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004518static int fg_gen3_suspend(struct device *dev)
4519{
4520 struct fg_chip *chip = dev_get_drvdata(dev);
4521 int rc;
4522
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004523 rc = fg_esr_timer_config(chip, true);
4524 if (rc < 0)
4525 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004526
Nicholas Troast1769fd32016-09-07 09:20:58 -07004527 cancel_delayed_work_sync(&chip->batt_avg_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004528 if (fg_sram_dump)
4529 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004530 return 0;
4531}
4532
4533static int fg_gen3_resume(struct device *dev)
4534{
4535 struct fg_chip *chip = dev_get_drvdata(dev);
4536 int rc;
4537
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004538 rc = fg_esr_timer_config(chip, false);
4539 if (rc < 0)
4540 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004541
Nicholas Troast1769fd32016-09-07 09:20:58 -07004542 fg_circ_buf_clr(&chip->ibatt_circ_buf);
4543 fg_circ_buf_clr(&chip->vbatt_circ_buf);
4544 schedule_delayed_work(&chip->batt_avg_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004545 if (fg_sram_dump)
4546 schedule_delayed_work(&chip->sram_dump_work,
4547 msecs_to_jiffies(fg_sram_dump_period_ms));
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004548 return 0;
4549}
4550
4551static const struct dev_pm_ops fg_gen3_pm_ops = {
4552 .suspend = fg_gen3_suspend,
4553 .resume = fg_gen3_resume,
4554};
4555
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004556static int fg_gen3_remove(struct platform_device *pdev)
4557{
4558 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
4559
4560 fg_cleanup(chip);
4561 return 0;
4562}
4563
4564static const struct of_device_id fg_gen3_match_table[] = {
4565 {.compatible = FG_GEN3_DEV_NAME},
4566 {},
4567};
4568
4569static struct platform_driver fg_gen3_driver = {
4570 .driver = {
4571 .name = FG_GEN3_DEV_NAME,
4572 .owner = THIS_MODULE,
4573 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004574 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004575 },
4576 .probe = fg_gen3_probe,
4577 .remove = fg_gen3_remove,
4578};
4579
4580static int __init fg_gen3_init(void)
4581{
4582 return platform_driver_register(&fg_gen3_driver);
4583}
4584
4585static void __exit fg_gen3_exit(void)
4586{
4587 return platform_driver_unregister(&fg_gen3_driver);
4588}
4589
4590module_init(fg_gen3_init);
4591module_exit(fg_gen3_exit);
4592
4593MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
4594MODULE_LICENSE("GPL v2");
4595MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);