blob: 73d54c6b6d603bebccf3027129f5cf8f0d598d85 [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 }
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003086 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3087 rc = fg_set_constant_chg_voltage(chip, pval->intval);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003088 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003089 default:
3090 break;
3091 }
3092
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003093 return rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003094}
3095
3096static int fg_property_is_writeable(struct power_supply *psy,
3097 enum power_supply_property psp)
3098{
3099 switch (psp) {
Nicholas Troaste29dec92016-08-24 09:35:11 -07003100 case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003101 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
Nicholas Troaste29dec92016-08-24 09:35:11 -07003102 return 1;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003103 default:
3104 break;
3105 }
3106
3107 return 0;
3108}
3109
3110static void fg_external_power_changed(struct power_supply *psy)
3111{
3112 pr_debug("power supply changed\n");
3113}
3114
3115static int fg_notifier_cb(struct notifier_block *nb,
3116 unsigned long event, void *data)
3117{
3118 struct power_supply *psy = data;
3119 struct fg_chip *chip = container_of(nb, struct fg_chip, nb);
3120
3121 if (event != PSY_EVENT_PROP_CHANGED)
3122 return NOTIFY_OK;
3123
Subbaraman Narayanamurthy58dac182016-12-06 14:41:29 -08003124 if (work_pending(&chip->status_change_work))
3125 return NOTIFY_OK;
3126
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003127 if ((strcmp(psy->desc->name, "battery") == 0)
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003128 || (strcmp(psy->desc->name, "usb") == 0)) {
3129 /*
3130 * We cannot vote for awake votable here as that takes
3131 * a mutex lock and this is executed in an atomic context.
3132 */
3133 pm_stay_awake(chip->dev);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003134 schedule_work(&chip->status_change_work);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003135 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003136
3137 return NOTIFY_OK;
3138}
3139
3140static enum power_supply_property fg_psy_props[] = {
3141 POWER_SUPPLY_PROP_CAPACITY,
3142 POWER_SUPPLY_PROP_TEMP,
3143 POWER_SUPPLY_PROP_VOLTAGE_NOW,
3144 POWER_SUPPLY_PROP_VOLTAGE_OCV,
3145 POWER_SUPPLY_PROP_CURRENT_NOW,
3146 POWER_SUPPLY_PROP_RESISTANCE_ID,
3147 POWER_SUPPLY_PROP_RESISTANCE,
3148 POWER_SUPPLY_PROP_BATTERY_TYPE,
3149 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Abhijeet Dharmapurikar3d8b2262016-08-25 13:50:42 -07003150 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Nicholas Troaste29dec92016-08-24 09:35:11 -07003151 POWER_SUPPLY_PROP_CYCLE_COUNT,
3152 POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003153 POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
3154 POWER_SUPPLY_PROP_CHARGE_NOW,
3155 POWER_SUPPLY_PROP_CHARGE_FULL,
3156 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Nicholas Troast1769fd32016-09-07 09:20:58 -07003157 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3158 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003159 POWER_SUPPLY_PROP_SOC_REPORTING_READY,
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303160 POWER_SUPPLY_PROP_DEBUG_BATTERY,
Subbaraman Narayanamurthyef825812017-02-01 18:46:30 -08003161 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003162};
3163
3164static const struct power_supply_desc fg_psy_desc = {
3165 .name = "bms",
3166 .type = POWER_SUPPLY_TYPE_BMS,
3167 .properties = fg_psy_props,
3168 .num_properties = ARRAY_SIZE(fg_psy_props),
3169 .get_property = fg_psy_get_property,
3170 .set_property = fg_psy_set_property,
3171 .external_power_changed = fg_external_power_changed,
3172 .property_is_writeable = fg_property_is_writeable,
3173};
3174
3175/* INIT FUNCTIONS STAY HERE */
3176
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003177#define DEFAULT_ESR_CHG_TIMER_RETRY 8
3178#define DEFAULT_ESR_CHG_TIMER_MAX 16
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003179static int fg_hw_init(struct fg_chip *chip)
3180{
3181 int rc;
3182 u8 buf[4], val;
3183
3184 fg_encode(chip->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003185 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_VOLT].addr_word,
3186 chip->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003187 chip->sp[FG_SRAM_CUTOFF_VOLT].len, FG_IMA_DEFAULT);
3188 if (rc < 0) {
3189 pr_err("Error in writing cutoff_volt, rc=%d\n", rc);
3190 return rc;
3191 }
3192
3193 fg_encode(chip->sp, FG_SRAM_EMPTY_VOLT, chip->dt.empty_volt_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003194 rc = fg_sram_write(chip, chip->sp[FG_SRAM_EMPTY_VOLT].addr_word,
3195 chip->sp[FG_SRAM_EMPTY_VOLT].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003196 chip->sp[FG_SRAM_EMPTY_VOLT].len, FG_IMA_DEFAULT);
3197 if (rc < 0) {
3198 pr_err("Error in writing empty_volt, rc=%d\n", rc);
3199 return rc;
3200 }
3201
3202 fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
3203 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003204 rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
3205 chip->sp[FG_SRAM_CHG_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003206 chip->sp[FG_SRAM_CHG_TERM_CURR].len, FG_IMA_DEFAULT);
3207 if (rc < 0) {
3208 pr_err("Error in writing chg_term_curr, rc=%d\n", rc);
3209 return rc;
3210 }
3211
3212 fg_encode(chip->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma,
3213 buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003214 rc = fg_sram_write(chip, chip->sp[FG_SRAM_SYS_TERM_CURR].addr_word,
3215 chip->sp[FG_SRAM_SYS_TERM_CURR].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003216 chip->sp[FG_SRAM_SYS_TERM_CURR].len, FG_IMA_DEFAULT);
3217 if (rc < 0) {
3218 pr_err("Error in writing sys_term_curr, rc=%d\n", rc);
3219 return rc;
3220 }
3221
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003222 if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
3223 fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
3224 chip->dt.chg_term_base_curr_ma, buf);
3225 rc = fg_sram_write(chip,
3226 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
3227 chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
3228 buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
3229 FG_IMA_DEFAULT);
3230 if (rc < 0) {
3231 pr_err("Error in writing chg_term_base_curr, rc=%d\n",
3232 rc);
3233 return rc;
3234 }
3235 }
3236
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003237 if (chip->dt.vbatt_low_thr_mv > 0) {
3238 fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
3239 chip->dt.vbatt_low_thr_mv, buf);
Nicholas Troasta2b40372016-08-15 10:45:39 -07003240 rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_LOW].addr_word,
3241 chip->sp[FG_SRAM_VBATT_LOW].addr_byte, buf,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003242 chip->sp[FG_SRAM_VBATT_LOW].len,
3243 FG_IMA_DEFAULT);
3244 if (rc < 0) {
3245 pr_err("Error in writing vbatt_low_thr, rc=%d\n", rc);
3246 return rc;
3247 }
3248 }
3249
3250 if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 100) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003251 fg_encode(chip->sp, FG_SRAM_DELTA_MSOC_THR,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003252 chip->dt.delta_soc_thr, buf);
3253 rc = fg_sram_write(chip,
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003254 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_word,
3255 chip->sp[FG_SRAM_DELTA_MSOC_THR].addr_byte,
3256 buf, chip->sp[FG_SRAM_DELTA_MSOC_THR].len,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003257 FG_IMA_DEFAULT);
3258 if (rc < 0) {
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003259 pr_err("Error in writing delta_msoc_thr, rc=%d\n", rc);
3260 return rc;
3261 }
3262
3263 fg_encode(chip->sp, FG_SRAM_DELTA_BSOC_THR,
3264 chip->dt.delta_soc_thr, buf);
3265 rc = fg_sram_write(chip,
3266 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_word,
3267 chip->sp[FG_SRAM_DELTA_BSOC_THR].addr_byte,
3268 buf, chip->sp[FG_SRAM_DELTA_BSOC_THR].len,
3269 FG_IMA_DEFAULT);
3270 if (rc < 0) {
3271 pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003272 return rc;
3273 }
3274 }
3275
cyizhaofb3eec52017-01-24 17:08:55 +08003276 /*
3277 * configure battery thermal coefficients c1,c2,c3
3278 * if its value is not zero.
3279 */
3280 if (chip->dt.batt_therm_coeffs[0] > 0) {
3281 rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
3282 chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
3283 if (rc < 0) {
3284 pr_err("Error in writing battery thermal coefficients, rc=%d\n",
3285 rc);
3286 return rc;
3287 }
3288 }
3289
3290
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003291 if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003292 rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003293 if (rc < 0) {
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003294 pr_err("Error in setting recharge_soc, rc=%d\n", rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003295 return rc;
3296 }
3297 }
3298
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003299 if (chip->dt.recharge_volt_thr_mv > 0) {
3300 rc = fg_set_recharge_voltage(chip,
3301 chip->dt.recharge_volt_thr_mv);
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003302 if (rc < 0) {
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08003303 pr_err("Error in setting recharge_voltage, rc=%d\n",
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003304 rc);
3305 return rc;
3306 }
3307 }
3308
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003309 if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
3310 chip->dt.rsense_sel < SRC_SEL_RESERVED) {
3311 rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
3312 SOURCE_SELECT_MASK, chip->dt.rsense_sel);
3313 if (rc < 0) {
3314 pr_err("Error in writing rsense_sel, rc=%d\n", rc);
3315 return rc;
3316 }
3317 }
3318
3319 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
3320 rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
3321 if (rc < 0) {
3322 pr_err("Error in writing jeita_cold, rc=%d\n", rc);
3323 return rc;
3324 }
3325
3326 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
3327 rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
3328 if (rc < 0) {
3329 pr_err("Error in writing jeita_cool, rc=%d\n", rc);
3330 return rc;
3331 }
3332
3333 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
3334 rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
3335 if (rc < 0) {
3336 pr_err("Error in writing jeita_warm, rc=%d\n", rc);
3337 return rc;
3338 }
3339
3340 get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
3341 rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
3342 if (rc < 0) {
3343 pr_err("Error in writing jeita_hot, rc=%d\n", rc);
3344 return rc;
3345 }
3346
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003347 if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
3348 chip->esr_timer_charging_default[TIMER_RETRY] =
3349 DEFAULT_ESR_CHG_TIMER_RETRY;
3350 chip->esr_timer_charging_default[TIMER_MAX] =
3351 DEFAULT_ESR_CHG_TIMER_MAX;
3352 } else {
3353 /* We don't need this for pm660 at present */
3354 chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
3355 chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003356 }
3357
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003358 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
3359 chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
3360 if (rc < 0) {
3361 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3362 return rc;
3363 }
3364
3365 rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
3366 chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
3367 if (rc < 0) {
3368 pr_err("Error in setting ESR timer, rc=%d\n", rc);
3369 return rc;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07003370 }
3371
Nicholas Troaste29dec92016-08-24 09:35:11 -07003372 if (chip->cyc_ctr.en)
3373 restore_cycle_counter(chip);
3374
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003375 if (chip->dt.jeita_hyst_temp >= 0) {
3376 val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
3377 rc = fg_masked_write(chip, BATT_INFO_BATT_TEMP_CFG(chip),
3378 JEITA_TEMP_HYST_MASK, val);
3379 if (rc < 0) {
3380 pr_err("Error in writing batt_temp_cfg, rc=%d\n", rc);
3381 return rc;
3382 }
3383 }
3384
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003385 get_batt_temp_delta(chip->dt.batt_temp_delta, &val);
3386 rc = fg_masked_write(chip, BATT_INFO_BATT_TMPR_INTR(chip),
3387 CHANGE_THOLD_MASK, val);
3388 if (rc < 0) {
3389 pr_err("Error in writing batt_temp_delta, rc=%d\n", rc);
3390 return rc;
3391 }
3392
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07003393 rc = fg_rconn_config(chip);
3394 if (rc < 0) {
3395 pr_err("Error in configuring Rconn, rc=%d\n", rc);
3396 return rc;
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08003397 }
3398
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003399 fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
3400 chip->dt.esr_tight_flt_upct, buf);
3401 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
3402 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, buf,
3403 chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
3404 if (rc < 0) {
3405 pr_err("Error in writing ESR tight filter, rc=%d\n", rc);
3406 return rc;
3407 }
3408
3409 fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
3410 chip->dt.esr_broad_flt_upct, buf);
3411 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
3412 chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, buf,
3413 chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
3414 if (rc < 0) {
3415 pr_err("Error in writing ESR broad filter, rc=%d\n", rc);
3416 return rc;
3417 }
3418
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003419 fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
3420 chip->dt.esr_pulse_thresh_ma, buf);
3421 rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
3422 chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
3423 chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
3424 if (rc < 0) {
3425 pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
3426 return rc;
3427 }
3428
3429 get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
3430 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3431 ESR_PULL_DOWN_IVAL_MASK, val);
3432 if (rc < 0) {
3433 pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
3434 return rc;
3435 }
3436
Subbaraman Narayanamurthy401a1d32017-05-05 14:07:53 -07003437 if (is_debug_batt_id(chip)) {
3438 val = ESR_NO_PULL_DOWN;
3439 rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
3440 ESR_PULL_DOWN_MODE_MASK, val);
3441 if (rc < 0) {
3442 pr_err("Error in writing esr_pull_down, rc=%d\n", rc);
3443 return rc;
3444 }
3445 }
3446
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003447 return 0;
3448}
3449
3450static int fg_memif_init(struct fg_chip *chip)
3451{
3452 return fg_ima_init(chip);
3453}
3454
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303455static int fg_adjust_timebase(struct fg_chip *chip)
3456{
3457 int rc = 0, die_temp;
3458 s32 time_base = 0;
3459 u8 buf[2] = {0};
3460
3461 if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
3462 rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
3463 if (rc < 0) {
3464 pr_err("Error in reading die_temp, rc:%d\n", rc);
3465 return rc;
3466 }
3467
3468 rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
3469 die_temp / 1000, &time_base);
3470 if (rc < 0) {
3471 pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
3472 return rc;
3473 }
3474
3475 fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
3476 rc = fg_sram_write(chip,
3477 chip->sp[FG_SRAM_TIMEBASE].addr_word,
3478 chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
3479 chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
3480 if (rc < 0) {
3481 pr_err("Error in writing timebase, rc=%d\n", rc);
3482 return rc;
3483 }
3484 }
3485
3486 return 0;
3487}
3488
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003489/* INTERRUPT HANDLERS STAY HERE */
3490
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003491static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
3492{
3493 struct fg_chip *chip = data;
3494 u8 status;
3495 int rc;
3496
3497 rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
3498 if (rc < 0) {
3499 pr_err("failed to read addr=0x%04x, rc=%d\n",
3500 MEM_IF_INT_RT_STS(chip), rc);
3501 return IRQ_HANDLED;
3502 }
3503
3504 fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003505
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003506 mutex_lock(&chip->sram_rw_lock);
3507 rc = fg_clear_dma_errors_if_any(chip);
3508 if (rc < 0)
3509 pr_err("Error in clearing DMA error, rc=%d\n", rc);
3510
3511 if (status & MEM_XCP_BIT) {
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003512 rc = fg_clear_ima_errors_if_any(chip, true);
3513 if (rc < 0 && rc != -EAGAIN)
3514 pr_err("Error in checking IMA errors rc:%d\n", rc);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003515 }
3516
Subbaraman Narayanamurthy3f3040a2017-03-14 20:30:47 -07003517 mutex_unlock(&chip->sram_rw_lock);
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003518 return IRQ_HANDLED;
3519}
3520
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003521static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
3522{
3523 struct fg_chip *chip = data;
3524
3525 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3526 return IRQ_HANDLED;
3527}
3528
3529static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
3530{
3531 struct fg_chip *chip = data;
3532 u8 status;
3533 int rc;
3534
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003535 rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), &status, 1);
3536 if (rc < 0) {
3537 pr_err("failed to read addr=0x%04x, rc=%d\n",
3538 BATT_INFO_INT_RT_STS(chip), rc);
3539 return IRQ_HANDLED;
3540 }
3541
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003542 fg_dbg(chip, FG_IRQ, "irq %d triggered sts:%d\n", irq, status);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003543 chip->battery_missing = (status & BT_MISS_BIT);
3544
3545 if (chip->battery_missing) {
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07003546 chip->profile_available = false;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003547 chip->profile_loaded = false;
Subbaraman Narayanamurthyfd7f07b2016-12-14 15:10:15 -08003548 chip->soc_reporting_ready = false;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003549 return IRQ_HANDLED;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003550 }
3551
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003552 rc = fg_get_batt_id(chip);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003553 if (rc < 0) {
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003554 chip->soc_reporting_ready = true;
3555 pr_err("Error in getting battery id, rc:%d\n", rc);
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003556 return IRQ_HANDLED;
3557 }
3558
3559 rc = fg_get_batt_profile(chip);
3560 if (rc < 0) {
3561 chip->soc_reporting_ready = true;
3562 pr_err("Error in getting battery profile, rc:%d\n", rc);
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08003563 return IRQ_HANDLED;
Subbaraman Narayanamurthy34af21c2016-12-15 18:03:09 -08003564 }
3565
3566 clear_battery_profile(chip);
3567 schedule_delayed_work(&chip->profile_load_work, 0);
3568
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303569 if (chip->fg_psy)
3570 power_supply_changed(chip->fg_psy);
3571
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003572 return IRQ_HANDLED;
3573}
3574
3575static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
3576{
3577 struct fg_chip *chip = data;
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003578 union power_supply_propval prop = {0, };
3579 int rc, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003580
3581 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003582 rc = fg_get_battery_temp(chip, &batt_temp);
3583 if (rc < 0) {
3584 pr_err("Error in getting batt_temp\n");
3585 return IRQ_HANDLED;
3586 }
3587
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003588 rc = fg_esr_filter_config(chip, batt_temp);
3589 if (rc < 0)
3590 pr_err("Error in configuring ESR filter rc:%d\n", rc);
3591
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003592 rc = fg_slope_limit_config(chip, batt_temp);
3593 if (rc < 0)
3594 pr_err("Error in configuring slope limiter rc:%d\n", rc);
3595
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07003596 rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
3597 if (rc < 0)
3598 pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
3599
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003600 if (!batt_psy_initialized(chip)) {
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003601 chip->last_batt_temp = batt_temp;
3602 return IRQ_HANDLED;
3603 }
3604
3605 power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
3606 &prop);
3607 chip->health = prop.intval;
3608
3609 if (chip->last_batt_temp != batt_temp) {
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303610 rc = fg_adjust_timebase(chip);
3611 if (rc < 0)
3612 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3613
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003614 chip->last_batt_temp = batt_temp;
3615 power_supply_changed(chip->batt_psy);
3616 }
3617
3618 if (abs(chip->last_batt_temp - batt_temp) > 30)
3619 pr_warn("Battery temperature last:%d current: %d\n",
3620 chip->last_batt_temp, batt_temp);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003621 return IRQ_HANDLED;
3622}
3623
3624static irqreturn_t fg_first_est_irq_handler(int irq, void *data)
3625{
3626 struct fg_chip *chip = data;
3627
3628 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3629 complete_all(&chip->soc_ready);
3630 return IRQ_HANDLED;
3631}
3632
3633static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
3634{
3635 struct fg_chip *chip = data;
3636
3637 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3638 complete_all(&chip->soc_update);
3639 return IRQ_HANDLED;
3640}
3641
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003642static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
3643{
3644 struct fg_chip *chip = data;
3645 int rc;
3646
3647 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3648 rc = fg_charge_full_update(chip);
3649 if (rc < 0)
3650 pr_err("Error in charge_full_update, rc=%d\n", rc);
3651
3652 return IRQ_HANDLED;
3653}
3654
3655static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003656{
3657 struct fg_chip *chip = data;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003658 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003659
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003660 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Nicholas Troaste29dec92016-08-24 09:35:11 -07003661 if (chip->cyc_ctr.en)
3662 schedule_work(&chip->cycle_count_work);
3663
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003664 if (chip->cl.active)
3665 fg_cap_learning_update(chip);
3666
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07003667 rc = fg_charge_full_update(chip);
3668 if (rc < 0)
3669 pr_err("Error in charge_full_update, rc=%d\n", rc);
3670
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003671 rc = fg_adjust_ki_coeff_dischg(chip);
3672 if (rc < 0)
3673 pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
3674
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08003675 rc = fg_update_maint_soc(chip);
3676 if (rc < 0)
3677 pr_err("Error in updating maint_soc, rc=%d\n", rc);
3678
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003679 rc = fg_esr_validate(chip);
3680 if (rc < 0)
3681 pr_err("Error in validating ESR, rc=%d\n", rc);
3682
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05303683 rc = fg_adjust_timebase(chip);
3684 if (rc < 0)
3685 pr_err("Error in adjusting timebase, rc=%d\n", rc);
3686
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003687 if (batt_psy_initialized(chip))
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003688 power_supply_changed(chip->batt_psy);
3689
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003690 return IRQ_HANDLED;
3691}
3692
3693static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
3694{
3695 struct fg_chip *chip = data;
3696
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003697 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
Abhijeet Dharmapurikar2cdd1402017-01-10 15:38:27 -08003698 if (batt_psy_initialized(chip))
Nicholas Troast65e29652016-09-22 11:27:04 -07003699 power_supply_changed(chip->batt_psy);
3700
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003701 return IRQ_HANDLED;
3702}
3703
3704static irqreturn_t fg_soc_irq_handler(int irq, void *data)
3705{
3706 struct fg_chip *chip = data;
3707
3708 fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
3709 return IRQ_HANDLED;
3710}
3711
3712static irqreturn_t fg_dummy_irq_handler(int irq, void *data)
3713{
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08003714 pr_debug("irq %d triggered\n", irq);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003715 return IRQ_HANDLED;
3716}
3717
3718static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
3719 /* BATT_SOC irqs */
3720 [MSOC_FULL_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003721 .name = "msoc-full",
3722 .handler = fg_soc_irq_handler,
3723 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003724 [MSOC_HIGH_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003725 .name = "msoc-high",
3726 .handler = fg_soc_irq_handler,
3727 .wakeable = true,
3728 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003729 [MSOC_EMPTY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003730 .name = "msoc-empty",
3731 .handler = fg_empty_soc_irq_handler,
3732 .wakeable = true,
3733 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003734 [MSOC_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003735 .name = "msoc-low",
3736 .handler = fg_soc_irq_handler,
3737 .wakeable = true,
3738 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003739 [MSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003740 .name = "msoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003741 .handler = fg_delta_msoc_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003742 .wakeable = true,
3743 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003744 [BSOC_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003745 .name = "bsoc-delta",
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08003746 .handler = fg_delta_bsoc_irq_handler,
3747 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003748 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003749 [SOC_READY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003750 .name = "soc-ready",
3751 .handler = fg_first_est_irq_handler,
3752 .wakeable = true,
3753 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003754 [SOC_UPDATE_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003755 .name = "soc-update",
3756 .handler = fg_soc_update_irq_handler,
3757 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003758 /* BATT_INFO irqs */
3759 [BATT_TEMP_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003760 .name = "batt-temp-delta",
3761 .handler = fg_delta_batt_temp_irq_handler,
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003762 .wakeable = true,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003763 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003764 [BATT_MISSING_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003765 .name = "batt-missing",
3766 .handler = fg_batt_missing_irq_handler,
3767 .wakeable = true,
3768 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003769 [ESR_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003770 .name = "esr-delta",
3771 .handler = fg_dummy_irq_handler,
3772 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003773 [VBATT_LOW_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003774 .name = "vbatt-low",
3775 .handler = fg_vbatt_low_irq_handler,
3776 .wakeable = true,
3777 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003778 [VBATT_PRED_DELTA_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003779 .name = "vbatt-pred-delta",
3780 .handler = fg_dummy_irq_handler,
3781 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003782 /* MEM_IF irqs */
3783 [DMA_GRANT_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003784 .name = "dma-grant",
3785 .handler = fg_dummy_irq_handler,
3786 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003787 [MEM_XCP_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003788 .name = "mem-xcp",
Subbaraman Narayanamurthya71c9dd2016-10-14 19:38:05 -07003789 .handler = fg_mem_xcp_irq_handler,
Nicholas Troast3cc97182016-09-23 08:54:13 -07003790 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003791 [IMA_RDY_IRQ] = {
Nicholas Troast3cc97182016-09-23 08:54:13 -07003792 .name = "ima-rdy",
3793 .handler = fg_dummy_irq_handler,
3794 },
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003795};
3796
3797static int fg_get_irq_index_byname(const char *name)
3798{
3799 int i;
3800
3801 for (i = 0; i < ARRAY_SIZE(fg_irqs); i++) {
3802 if (strcmp(fg_irqs[i].name, name) == 0)
3803 return i;
3804 }
3805
3806 pr_err("%s is not in irq list\n", name);
3807 return -ENOENT;
3808}
3809
3810static int fg_register_interrupts(struct fg_chip *chip)
3811{
3812 struct device_node *child, *node = chip->dev->of_node;
3813 struct property *prop;
3814 const char *name;
3815 int rc, irq, irq_index;
3816
3817 for_each_available_child_of_node(node, child) {
3818 of_property_for_each_string(child, "interrupt-names", prop,
3819 name) {
3820 irq = of_irq_get_byname(child, name);
3821 if (irq < 0) {
3822 dev_err(chip->dev, "failed to get irq %s irq:%d\n",
3823 name, irq);
3824 return irq;
3825 }
3826
3827 irq_index = fg_get_irq_index_byname(name);
3828 if (irq_index < 0)
3829 return irq_index;
3830
3831 rc = devm_request_threaded_irq(chip->dev, irq, NULL,
3832 fg_irqs[irq_index].handler,
3833 IRQF_ONESHOT, name, chip);
3834 if (rc < 0) {
3835 dev_err(chip->dev, "failed to register irq handler for %s rc:%d\n",
3836 name, rc);
3837 return rc;
3838 }
3839
3840 fg_irqs[irq_index].irq = irq;
3841 if (fg_irqs[irq_index].wakeable)
3842 enable_irq_wake(fg_irqs[irq_index].irq);
3843 }
3844 }
3845
3846 return 0;
3847}
3848
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003849static int fg_parse_dt_property_u32_array(struct device_node *node,
3850 const char *prop_name, int *buf, int len)
3851{
3852 int rc;
3853
3854 rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
3855 if (rc < 0) {
3856 if (rc == -EINVAL)
3857 return 0;
3858 else
3859 return rc;
3860 } else if (rc != len) {
3861 pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
3862 rc);
3863 return -EINVAL;
3864 }
3865
3866 rc = of_property_read_u32_array(node, prop_name, buf, len);
3867 if (rc < 0) {
3868 pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
3869 return rc;
3870 }
3871
3872 return 0;
3873}
3874
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003875static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
3876{
3877 struct device_node *node = chip->dev->of_node;
3878 int rc, i;
3879
3880 rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
3881 &chip->dt.slope_limit_temp);
3882 if (rc < 0)
3883 return 0;
3884
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003885 rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
3886 chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
3887 if (rc < 0)
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003888 return rc;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08003889
3890 for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
3891 if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
3892 chip->dt.slope_limit_coeffs[i] < 0) {
3893 pr_err("Incorrect slope limit coefficient\n");
3894 return -EINVAL;
3895 }
3896 }
3897
3898 chip->slope_limit_en = true;
3899 return 0;
3900}
3901
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003902static int fg_parse_ki_coefficients(struct fg_chip *chip)
3903{
3904 struct device_node *node = chip->dev->of_node;
3905 int rc, i;
3906
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003907 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
3908 chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
3909 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003910 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003911
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003912 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
3913 chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
3914 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003915 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003916
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07003917 rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
3918 chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
3919 if (rc < 0)
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003920 return rc;
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07003921
3922 for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
3923 if (chip->dt.ki_coeff_soc[i] < 0 ||
3924 chip->dt.ki_coeff_soc[i] > FULL_CAPACITY) {
3925 pr_err("Error in ki_coeff_soc_dischg values\n");
3926 return -EINVAL;
3927 }
3928
3929 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
3930 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
3931 pr_err("Error in ki_coeff_med_dischg values\n");
3932 return -EINVAL;
3933 }
3934
3935 if (chip->dt.ki_coeff_med_dischg[i] < 0 ||
3936 chip->dt.ki_coeff_med_dischg[i] > KI_COEFF_MAX) {
3937 pr_err("Error in ki_coeff_med_dischg values\n");
3938 return -EINVAL;
3939 }
3940 }
3941 chip->ki_coeff_dischg_en = true;
3942 return 0;
3943}
3944
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003945#define DEFAULT_CUTOFF_VOLT_MV 3200
Subbaraman Narayanamurthy8b249942017-05-19 13:50:44 -07003946#define DEFAULT_EMPTY_VOLT_MV 2850
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08003947#define DEFAULT_RECHARGE_VOLT_MV 4250
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003948#define DEFAULT_CHG_TERM_CURR_MA 100
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07003949#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
Subbaraman Narayanamurthy4bf3ce22016-09-19 11:17:59 -07003950#define DEFAULT_SYS_TERM_CURR_MA -125
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003951#define DEFAULT_DELTA_SOC_THR 1
3952#define DEFAULT_RECHARGE_SOC_THR 95
3953#define DEFAULT_BATT_TEMP_COLD 0
3954#define DEFAULT_BATT_TEMP_COOL 5
3955#define DEFAULT_BATT_TEMP_WARM 45
3956#define DEFAULT_BATT_TEMP_HOT 50
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07003957#define DEFAULT_CL_START_SOC 15
3958#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
3959#define DEFAULT_CL_MAX_TEMP_DECIDEGC 450
3960#define DEFAULT_CL_MAX_INC_DECIPERC 5
3961#define DEFAULT_CL_MAX_DEC_DECIPERC 100
3962#define DEFAULT_CL_MIN_LIM_DECIPERC 0
3963#define DEFAULT_CL_MAX_LIM_DECIPERC 0
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07003964#define BTEMP_DELTA_LOW 2
3965#define BTEMP_DELTA_HIGH 10
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08003966#define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100
3967#define DEFAULT_ESR_TIGHT_FLT_UPCT 3907
3968#define DEFAULT_ESR_BROAD_FLT_UPCT 99610
3969#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
3970#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08003971#define DEFAULT_ESR_CLAMP_MOHMS 20
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07003972#define DEFAULT_ESR_PULSE_THRESH_MA 110
3973#define DEFAULT_ESR_MEAS_CURR_MA 120
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003974static int fg_parse_dt(struct fg_chip *chip)
3975{
3976 struct device_node *child, *revid_node, *node = chip->dev->of_node;
3977 u32 base, temp;
3978 u8 subtype;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07003979 int rc;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07003980
3981 if (!node) {
3982 dev_err(chip->dev, "device tree node missing\n");
3983 return -ENXIO;
3984 }
3985
3986 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
3987 if (!revid_node) {
3988 pr_err("Missing qcom,pmic-revid property - driver failed\n");
3989 return -EINVAL;
3990 }
3991
3992 chip->pmic_rev_id = get_revid_data(revid_node);
3993 if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
3994 pr_err("Unable to get pmic_revid rc=%ld\n",
3995 PTR_ERR(chip->pmic_rev_id));
3996 /*
3997 * the revid peripheral must be registered, any failure
3998 * here only indicates that the rev-id module has not
3999 * probed yet.
4000 */
4001 return -EPROBE_DEFER;
4002 }
4003
4004 pr_debug("PMIC subtype %d Digital major %d\n",
4005 chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
4006
4007 switch (chip->pmic_rev_id->pmic_subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004008 case PMI8998_SUBTYPE:
4009 if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) {
4010 chip->sp = pmi8998_v1_sram_params;
4011 chip->alg_flags = pmi8998_v1_alg_flags;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304012 chip->wa_flags |= PMI8998_V1_REV_WA;
Harry Yang2452b272017-03-06 13:56:14 -08004013 } else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) {
4014 chip->sp = pmi8998_v2_sram_params;
4015 chip->alg_flags = pmi8998_v2_alg_flags;
Nicholas Troast69da2252016-09-07 16:17:47 -07004016 } else {
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004017 return -EINVAL;
Nicholas Troast69da2252016-09-07 16:17:47 -07004018 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004019 break;
Harry Yange4e731b2017-03-06 14:35:09 -08004020 case PM660_SUBTYPE:
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304021 chip->sp = pmi8998_v2_sram_params;
4022 chip->alg_flags = pmi8998_v2_alg_flags;
Subbaraman Narayanamurthy9b866452017-03-27 16:29:25 -07004023 chip->use_ima_single_mode = true;
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304024 if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
4025 chip->wa_flags |= PM660_TSMC_OSC_WA;
Ashay Jaiswal63d486e2016-12-07 11:21:32 +05304026 break;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004027 default:
4028 return -EINVAL;
4029 }
4030
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004031 if (of_get_available_child_count(node) == 0) {
4032 dev_err(chip->dev, "No child nodes specified!\n");
4033 return -ENXIO;
4034 }
4035
4036 for_each_available_child_of_node(node, child) {
4037 rc = of_property_read_u32(child, "reg", &base);
4038 if (rc < 0) {
4039 dev_err(chip->dev, "reg not specified in node %s, rc=%d\n",
4040 child->full_name, rc);
4041 return rc;
4042 }
4043
4044 rc = fg_read(chip, base + PERPH_SUBTYPE_REG, &subtype, 1);
4045 if (rc < 0) {
4046 dev_err(chip->dev, "Couldn't read subtype for base %d, rc=%d\n",
4047 base, rc);
4048 return rc;
4049 }
4050
4051 switch (subtype) {
Harry Yang2452b272017-03-06 13:56:14 -08004052 case FG_BATT_SOC_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004053 chip->batt_soc_base = base;
4054 break;
Harry Yang2452b272017-03-06 13:56:14 -08004055 case FG_BATT_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004056 chip->batt_info_base = base;
4057 break;
Harry Yang2452b272017-03-06 13:56:14 -08004058 case FG_MEM_INFO_PMI8998:
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004059 chip->mem_if_base = base;
4060 break;
4061 default:
4062 dev_err(chip->dev, "Invalid peripheral subtype 0x%x\n",
4063 subtype);
4064 return -ENXIO;
4065 }
4066 }
4067
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004068 rc = of_property_read_u32(node, "qcom,rradc-base", &base);
4069 if (rc < 0) {
4070 dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
4071 return rc;
4072 }
4073 chip->rradc_base = base;
4074
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004075 /* Read all the optional properties below */
4076 rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
4077 if (rc < 0)
4078 chip->dt.cutoff_volt_mv = DEFAULT_CUTOFF_VOLT_MV;
4079 else
4080 chip->dt.cutoff_volt_mv = temp;
4081
4082 rc = of_property_read_u32(node, "qcom,fg-empty-voltage", &temp);
4083 if (rc < 0)
4084 chip->dt.empty_volt_mv = DEFAULT_EMPTY_VOLT_MV;
4085 else
4086 chip->dt.empty_volt_mv = temp;
4087
4088 rc = of_property_read_u32(node, "qcom,fg-vbatt-low-thr", &temp);
4089 if (rc < 0)
4090 chip->dt.vbatt_low_thr_mv = -EINVAL;
4091 else
4092 chip->dt.vbatt_low_thr_mv = temp;
4093
4094 rc = of_property_read_u32(node, "qcom,fg-chg-term-current", &temp);
4095 if (rc < 0)
4096 chip->dt.chg_term_curr_ma = DEFAULT_CHG_TERM_CURR_MA;
4097 else
4098 chip->dt.chg_term_curr_ma = temp;
4099
4100 rc = of_property_read_u32(node, "qcom,fg-sys-term-current", &temp);
4101 if (rc < 0)
4102 chip->dt.sys_term_curr_ma = DEFAULT_SYS_TERM_CURR_MA;
4103 else
4104 chip->dt.sys_term_curr_ma = temp;
4105
Subbaraman Narayanamurthya4e18882017-04-04 20:28:03 -07004106 rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
4107 if (rc < 0)
4108 chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
4109 else
4110 chip->dt.chg_term_base_curr_ma = temp;
4111
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004112 rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
4113 if (rc < 0)
4114 chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
4115 else
4116 chip->dt.delta_soc_thr = temp;
4117
4118 rc = of_property_read_u32(node, "qcom,fg-recharge-soc-thr", &temp);
4119 if (rc < 0)
4120 chip->dt.recharge_soc_thr = DEFAULT_RECHARGE_SOC_THR;
4121 else
4122 chip->dt.recharge_soc_thr = temp;
4123
Subbaraman Narayanamurthy4cf5c1c2016-11-17 13:58:06 -08004124 rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
4125 if (rc < 0)
4126 chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
4127 else
4128 chip->dt.recharge_volt_thr_mv = temp;
4129
Subbaraman Narayanamurthydeeaec722016-12-22 18:55:25 -08004130 chip->dt.auto_recharge_soc = of_property_read_bool(node,
4131 "qcom,fg-auto-recharge-soc");
4132
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004133 rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
4134 if (rc < 0)
4135 chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
4136 else
4137 chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK;
4138
4139 chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD;
4140 chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL;
4141 chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM;
4142 chip->dt.jeita_thresholds[JEITA_HOT] = DEFAULT_BATT_TEMP_HOT;
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004143 if (of_property_count_elems_of_size(node, "qcom,fg-jeita-thresholds",
4144 sizeof(u32)) == NUM_JEITA_LEVELS) {
4145 rc = of_property_read_u32_array(node,
4146 "qcom,fg-jeita-thresholds",
4147 chip->dt.jeita_thresholds, NUM_JEITA_LEVELS);
4148 if (rc < 0)
4149 pr_warn("Error reading Jeita thresholds, default values will be used rc:%d\n",
4150 rc);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004151 }
4152
cyizhaofb3eec52017-01-24 17:08:55 +08004153 if (of_property_count_elems_of_size(node,
4154 "qcom,battery-thermal-coefficients",
4155 sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
4156 rc = of_property_read_u8_array(node,
4157 "qcom,battery-thermal-coefficients",
4158 chip->dt.batt_therm_coeffs,
4159 BATT_THERM_NUM_COEFFS);
4160 if (rc < 0)
4161 pr_warn("Error reading battery thermal coefficients, rc:%d\n",
4162 rc);
4163 }
4164
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004165 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
4166 chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
4167 if (rc < 0) {
4168 chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
4169 chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
4170 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004171
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004172 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
4173 chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
4174 if (rc < 0) {
4175 chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
4176 chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
4177 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004178
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004179 rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
4180 chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
4181 if (rc < 0) {
4182 chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
4183 chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
4184 }
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004185
Nicholas Troaste29dec92016-08-24 09:35:11 -07004186 chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
4187 if (chip->cyc_ctr.en)
4188 chip->cyc_ctr.id = 1;
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004189
Subbaraman Narayanamurthy6da170e2016-09-21 12:36:03 -07004190 chip->dt.force_load_profile = of_property_read_bool(node,
4191 "qcom,fg-force-load-profile");
4192
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004193 rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp);
4194 if (rc < 0)
4195 chip->dt.cl_start_soc = DEFAULT_CL_START_SOC;
4196 else
4197 chip->dt.cl_start_soc = temp;
4198
4199 rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
4200 if (rc < 0)
4201 chip->dt.cl_min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
4202 else
4203 chip->dt.cl_min_temp = temp;
4204
4205 rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
4206 if (rc < 0)
4207 chip->dt.cl_max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
4208 else
4209 chip->dt.cl_max_temp = temp;
4210
4211 rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
4212 if (rc < 0)
4213 chip->dt.cl_max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
4214 else
4215 chip->dt.cl_max_cap_inc = temp;
4216
4217 rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
4218 if (rc < 0)
4219 chip->dt.cl_max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
4220 else
4221 chip->dt.cl_max_cap_dec = temp;
4222
4223 rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
4224 if (rc < 0)
4225 chip->dt.cl_min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC;
4226 else
4227 chip->dt.cl_min_cap_limit = temp;
4228
4229 rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
4230 if (rc < 0)
4231 chip->dt.cl_max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC;
4232 else
4233 chip->dt.cl_max_cap_limit = temp;
4234
Subbaraman Narayanamurthy65ff45e2016-09-23 19:11:17 -07004235 rc = of_property_read_u32(node, "qcom,fg-jeita-hyst-temp", &temp);
4236 if (rc < 0)
4237 chip->dt.jeita_hyst_temp = -EINVAL;
4238 else
4239 chip->dt.jeita_hyst_temp = temp;
4240
Subbaraman Narayanamurthy11bddec2016-09-26 11:27:24 -07004241 rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp);
4242 if (rc < 0)
4243 chip->dt.batt_temp_delta = -EINVAL;
4244 else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
4245 chip->dt.batt_temp_delta = temp;
4246
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -07004247 chip->dt.hold_soc_while_full = of_property_read_bool(node,
4248 "qcom,hold-soc-while-full");
Subbaraman Narayanamurthyc1a94ed2016-10-05 19:58:58 -07004249
4250 rc = fg_parse_ki_coefficients(chip);
4251 if (rc < 0)
4252 pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
4253
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004254 rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
Subbaraman Narayanamurthy8909f372017-03-14 19:50:57 -07004255 if (!rc)
Subbaraman Narayanamurthyc297f6de2016-11-28 18:05:20 -08004256 chip->dt.rconn_mohms = temp;
4257
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004258 rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
4259 &temp);
4260 if (rc < 0)
4261 chip->dt.esr_flt_switch_temp = DEFAULT_ESR_FLT_TEMP_DECIDEGC;
4262 else
4263 chip->dt.esr_flt_switch_temp = temp;
4264
4265 rc = of_property_read_u32(node, "qcom,fg-esr-tight-filter-micro-pct",
4266 &temp);
4267 if (rc < 0)
4268 chip->dt.esr_tight_flt_upct = DEFAULT_ESR_TIGHT_FLT_UPCT;
4269 else
4270 chip->dt.esr_tight_flt_upct = temp;
4271
4272 rc = of_property_read_u32(node, "qcom,fg-esr-broad-filter-micro-pct",
4273 &temp);
4274 if (rc < 0)
4275 chip->dt.esr_broad_flt_upct = DEFAULT_ESR_BROAD_FLT_UPCT;
4276 else
4277 chip->dt.esr_broad_flt_upct = temp;
4278
4279 rc = of_property_read_u32(node, "qcom,fg-esr-tight-lt-filter-micro-pct",
4280 &temp);
4281 if (rc < 0)
4282 chip->dt.esr_tight_lt_flt_upct = DEFAULT_ESR_TIGHT_LT_FLT_UPCT;
4283 else
4284 chip->dt.esr_tight_lt_flt_upct = temp;
4285
4286 rc = of_property_read_u32(node, "qcom,fg-esr-broad-lt-filter-micro-pct",
4287 &temp);
4288 if (rc < 0)
4289 chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
4290 else
4291 chip->dt.esr_broad_lt_flt_upct = temp;
Subbaraman Narayanamurthy94e63052017-02-09 18:06:14 -08004292
4293 rc = fg_parse_slope_limit_coefficients(chip);
4294 if (rc < 0)
4295 pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
4296
Subbaraman Narayanamurthydcfc8662017-02-24 16:04:46 -08004297 rc = of_property_read_u32(node, "qcom,fg-esr-clamp-mohms", &temp);
4298 if (rc < 0)
4299 chip->dt.esr_clamp_mohms = DEFAULT_ESR_CLAMP_MOHMS;
4300 else
4301 chip->dt.esr_clamp_mohms = temp;
4302
Subbaraman Narayanamurthye14037f2017-03-16 19:14:58 -07004303 chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
4304 rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
4305 if (!rc) {
4306 /* ESR pulse qualification threshold range is 1-997 mA */
4307 if (temp > 0 && temp < 997)
4308 chip->dt.esr_pulse_thresh_ma = temp;
4309 }
4310
4311 chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
4312 rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
4313 if (!rc) {
4314 /* ESR measurement current range is 60-240 mA */
4315 if (temp >= 60 || temp <= 240)
4316 chip->dt.esr_meas_curr_ma = temp;
4317 }
4318
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004319 return 0;
4320}
4321
4322static void fg_cleanup(struct fg_chip *chip)
4323{
4324 power_supply_unreg_notifier(&chip->nb);
Nicholas Troast69da2252016-09-07 16:17:47 -07004325 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004326 if (chip->awake_votable)
4327 destroy_votable(chip->awake_votable);
4328
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004329 if (chip->delta_bsoc_irq_en_votable)
4330 destroy_votable(chip->delta_bsoc_irq_en_votable);
4331
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004332 if (chip->batt_id_chan)
4333 iio_channel_release(chip->batt_id_chan);
4334
4335 dev_set_drvdata(chip->dev, NULL);
4336}
4337
4338static int fg_gen3_probe(struct platform_device *pdev)
4339{
4340 struct fg_chip *chip;
4341 struct power_supply_config fg_psy_cfg;
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004342 int rc, msoc, volt_uv, batt_temp;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004343
4344 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
4345 if (!chip)
4346 return -ENOMEM;
4347
4348 chip->dev = &pdev->dev;
4349 chip->debug_mask = &fg_gen3_debug_mask;
4350 chip->irqs = fg_irqs;
Nicholas Troast1769fd32016-09-07 09:20:58 -07004351 chip->charge_status = -EINVAL;
4352 chip->prev_charge_status = -EINVAL;
Subbaraman Narayanamurthy1bf973e2017-04-04 19:24:20 -07004353 chip->ki_coeff_full_soc = -EINVAL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004354 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
4355 if (!chip->regmap) {
4356 dev_err(chip->dev, "Parent regmap is unavailable\n");
4357 return -ENXIO;
4358 }
4359
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004360 chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
4361 if (IS_ERR(chip->batt_id_chan)) {
4362 if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
4363 pr_err("batt_id_chan unavailable %ld\n",
4364 PTR_ERR(chip->batt_id_chan));
4365 rc = PTR_ERR(chip->batt_id_chan);
4366 chip->batt_id_chan = NULL;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004367 return rc;
4368 }
4369
Anirudh Ghayalddabeee2017-04-04 06:13:48 +05304370 rc = of_property_match_string(chip->dev->of_node,
4371 "io-channel-names", "rradc_die_temp");
4372 if (rc >= 0) {
4373 chip->die_temp_chan = iio_channel_get(chip->dev,
4374 "rradc_die_temp");
4375 if (IS_ERR(chip->die_temp_chan)) {
4376 if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
4377 pr_err("rradc_die_temp unavailable %ld\n",
4378 PTR_ERR(chip->die_temp_chan));
4379 rc = PTR_ERR(chip->die_temp_chan);
4380 chip->die_temp_chan = NULL;
4381 return rc;
4382 }
4383 }
4384
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004385 chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
4386 chip);
4387 if (IS_ERR(chip->awake_votable)) {
4388 rc = PTR_ERR(chip->awake_votable);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004389 goto exit;
4390 }
4391
4392 chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
4393 VOTE_SET_ANY,
4394 fg_delta_bsoc_irq_en_cb, chip);
4395 if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
4396 rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
4397 goto exit;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004398 }
4399
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004400 rc = fg_parse_dt(chip);
4401 if (rc < 0) {
4402 dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
4403 rc);
4404 goto exit;
4405 }
4406
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004407 mutex_init(&chip->bus_lock);
4408 mutex_init(&chip->sram_rw_lock);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004409 mutex_init(&chip->cyc_ctr.lock);
Subbaraman Narayanamurthy07be9192016-09-14 14:48:49 -07004410 mutex_init(&chip->cl.lock);
Nicholas Troast1769fd32016-09-07 09:20:58 -07004411 mutex_init(&chip->batt_avg_lock);
Subbaraman Narayanamurthy03f7d452017-01-06 15:47:24 -08004412 mutex_init(&chip->charge_full_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004413 init_completion(&chip->soc_update);
4414 init_completion(&chip->soc_ready);
4415 INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
4416 INIT_WORK(&chip->status_change_work, status_change_work);
Nicholas Troaste29dec92016-08-24 09:35:11 -07004417 INIT_WORK(&chip->cycle_count_work, cycle_count_work);
Nicholas Troast1769fd32016-09-07 09:20:58 -07004418 INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004419 INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004420
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004421 rc = fg_get_batt_id(chip);
4422 if (rc < 0) {
4423 pr_err("Error in getting battery id, rc:%d\n", rc);
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004424 goto exit;
Subbaraman Narayanamurthy7d333512017-01-20 18:34:28 -08004425 }
4426
4427 rc = fg_get_batt_profile(chip);
4428 if (rc < 0) {
4429 chip->soc_reporting_ready = true;
4430 pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
4431 chip->batt_id_ohms / 1000, rc);
4432 }
4433
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004434 rc = fg_memif_init(chip);
4435 if (rc < 0) {
4436 dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
4437 rc);
4438 goto exit;
4439 }
4440
4441 rc = fg_hw_init(chip);
4442 if (rc < 0) {
4443 dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
4444 rc);
4445 goto exit;
4446 }
4447
4448 platform_set_drvdata(pdev, chip);
4449
4450 /* Register the power supply */
4451 fg_psy_cfg.drv_data = chip;
4452 fg_psy_cfg.of_node = NULL;
4453 fg_psy_cfg.supplied_to = NULL;
4454 fg_psy_cfg.num_supplicants = 0;
4455 chip->fg_psy = devm_power_supply_register(chip->dev, &fg_psy_desc,
4456 &fg_psy_cfg);
4457 if (IS_ERR(chip->fg_psy)) {
4458 pr_err("failed to register fg_psy rc = %ld\n",
4459 PTR_ERR(chip->fg_psy));
4460 goto exit;
4461 }
4462
4463 chip->nb.notifier_call = fg_notifier_cb;
4464 rc = power_supply_reg_notifier(&chip->nb);
4465 if (rc < 0) {
4466 pr_err("Couldn't register psy notifier rc = %d\n", rc);
4467 goto exit;
4468 }
4469
4470 rc = fg_register_interrupts(chip);
4471 if (rc < 0) {
4472 dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
4473 rc);
4474 goto exit;
4475 }
4476
4477 /* Keep SOC_UPDATE irq disabled until we require it */
4478 if (fg_irqs[SOC_UPDATE_IRQ].irq)
4479 disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
4480
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004481 /* Keep BSOC_DELTA_IRQ irq disabled until we require it */
Subbaraman Narayanamurthy53448172017-03-15 12:47:00 -07004482 rerun_election(chip->delta_bsoc_irq_en_votable);
Subbaraman Narayanamurthyfbf25372017-01-03 15:39:08 -08004483
Nicholas Troast69da2252016-09-07 16:17:47 -07004484 rc = fg_debugfs_create(chip);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004485 if (rc < 0) {
4486 dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",
4487 rc);
4488 goto exit;
4489 }
4490
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004491 rc = fg_get_battery_voltage(chip, &volt_uv);
4492 if (!rc)
4493 rc = fg_get_prop_capacity(chip, &msoc);
4494
4495 if (!rc)
4496 rc = fg_get_battery_temp(chip, &batt_temp);
4497
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004498 if (!rc) {
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004499 pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
Subbaraman Narayanamurthy243fc3f2016-11-28 16:05:09 -08004500 msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
Subbaraman Narayanamurthyb99ea4c2016-12-22 15:10:09 -08004501 rc = fg_esr_filter_config(chip, batt_temp);
4502 if (rc < 0)
4503 pr_err("Error in configuring ESR filter rc:%d\n", rc);
4504 }
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004505
4506 device_init_wakeup(chip->dev, true);
Subbaraman Narayanamurthy6e7053e2016-09-19 14:52:12 -07004507 if (chip->profile_available)
4508 schedule_delayed_work(&chip->profile_load_work, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004509
Subbaraman Narayanamurthy03e6c612016-11-09 16:40:27 -08004510 pr_debug("FG GEN3 driver probed successfully\n");
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004511 return 0;
4512exit:
4513 fg_cleanup(chip);
4514 return rc;
4515}
4516
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004517static int fg_gen3_suspend(struct device *dev)
4518{
4519 struct fg_chip *chip = dev_get_drvdata(dev);
4520 int rc;
4521
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004522 rc = fg_esr_timer_config(chip, true);
4523 if (rc < 0)
4524 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004525
Nicholas Troast1769fd32016-09-07 09:20:58 -07004526 cancel_delayed_work_sync(&chip->batt_avg_work);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004527 if (fg_sram_dump)
4528 cancel_delayed_work_sync(&chip->sram_dump_work);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004529 return 0;
4530}
4531
4532static int fg_gen3_resume(struct device *dev)
4533{
4534 struct fg_chip *chip = dev_get_drvdata(dev);
4535 int rc;
4536
Subbaraman Narayanamurthy784bd5b2017-05-17 17:43:22 -07004537 rc = fg_esr_timer_config(chip, false);
4538 if (rc < 0)
4539 pr_err("Error in configuring ESR timer, rc=%d\n", rc);
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004540
Nicholas Troast1769fd32016-09-07 09:20:58 -07004541 fg_circ_buf_clr(&chip->ibatt_circ_buf);
4542 fg_circ_buf_clr(&chip->vbatt_circ_buf);
4543 schedule_delayed_work(&chip->batt_avg_work, 0);
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08004544 if (fg_sram_dump)
4545 schedule_delayed_work(&chip->sram_dump_work,
4546 msecs_to_jiffies(fg_sram_dump_period_ms));
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004547 return 0;
4548}
4549
4550static const struct dev_pm_ops fg_gen3_pm_ops = {
4551 .suspend = fg_gen3_suspend,
4552 .resume = fg_gen3_resume,
4553};
4554
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004555static int fg_gen3_remove(struct platform_device *pdev)
4556{
4557 struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
4558
4559 fg_cleanup(chip);
4560 return 0;
4561}
4562
4563static const struct of_device_id fg_gen3_match_table[] = {
4564 {.compatible = FG_GEN3_DEV_NAME},
4565 {},
4566};
4567
4568static struct platform_driver fg_gen3_driver = {
4569 .driver = {
4570 .name = FG_GEN3_DEV_NAME,
4571 .owner = THIS_MODULE,
4572 .of_match_table = fg_gen3_match_table,
Nicholas Troastdcf8fe62016-08-04 14:30:02 -07004573 .pm = &fg_gen3_pm_ops,
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07004574 },
4575 .probe = fg_gen3_probe,
4576 .remove = fg_gen3_remove,
4577};
4578
4579static int __init fg_gen3_init(void)
4580{
4581 return platform_driver_register(&fg_gen3_driver);
4582}
4583
4584static void __exit fg_gen3_exit(void)
4585{
4586 return platform_driver_unregister(&fg_gen3_driver);
4587}
4588
4589module_init(fg_gen3_init);
4590module_exit(fg_gen3_exit);
4591
4592MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver");
4593MODULE_LICENSE("GPL v2");
4594MODULE_ALIAS("platform:" FG_GEN3_DEV_NAME);