blob: 86d923d2974ff33d8ead6156a6b3aaa9d2362877 [file] [log] [blame]
Xiaozhe Shi28f5dd52013-01-04 12:19:58 -08001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Xiaozhe Shib19f7032012-08-16 12:14: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
Xiaozhe Shi73a65692012-09-18 17:51:57 -070013#define pr_fmt(fmt) "BMS: %s: " fmt, __func__
Xiaozhe Shib19f7032012-08-16 12:14:16 -070014
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/init.h>
18#include <linux/slab.h>
19#include <linux/err.h>
20#include <linux/of.h>
21#include <linux/of_device.h>
22#include <linux/power_supply.h>
23#include <linux/spmi.h>
Xiaozhe Shie118c692012-09-24 15:17:43 -070024#include <linux/rtc.h>
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -070025#include <linux/delay.h>
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070026#include <linux/qpnp/qpnp-adc.h>
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -070027#include <linux/qpnp/power-on.h>
Xiaozhe Shiaf203c22013-06-19 12:01:38 -070028#include <linux/of_batterydata.h>
Xiaozhe Shib19f7032012-08-16 12:14:16 -070029
Xiaozhe Shib19f7032012-08-16 12:14:16 -070030/* BMS Register Offsets */
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -070031#define REVISION1 0x0
32#define REVISION2 0x1
Xiaozhe Shib19f7032012-08-16 12:14:16 -070033#define BMS1_STATUS1 0x8
34#define BMS1_MODE_CTL 0X40
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070035/* Coulomb counter clear registers */
Xiaozhe Shib19f7032012-08-16 12:14:16 -070036#define BMS1_CC_DATA_CTL 0x42
Xiaozhe Shia045a562012-11-28 16:55:39 -080037#define BMS1_CC_CLEAR_CTL 0x43
Xiaozhe Shi20640b52013-01-03 11:49:30 -080038/* BMS Tolerances */
39#define BMS1_TOL_CTL 0X44
Xiaozhe Shib19f7032012-08-16 12:14:16 -070040/* OCV limit registers */
41#define BMS1_OCV_USE_LOW_LIMIT_THR0 0x48
42#define BMS1_OCV_USE_LOW_LIMIT_THR1 0x49
43#define BMS1_OCV_USE_HIGH_LIMIT_THR0 0x4A
44#define BMS1_OCV_USE_HIGH_LIMIT_THR1 0x4B
45#define BMS1_OCV_USE_LIMIT_CTL 0x4C
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -070046/* Delay control */
47#define BMS1_S1_DELAY_CTL 0x5A
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -080048/* OCV interrupt threshold */
49#define BMS1_OCV_THR0 0x50
50/* SW CC interrupt threshold */
51#define BMS1_SW_CC_THR0 0xA0
Xiaozhe Shib19f7032012-08-16 12:14:16 -070052/* OCV for r registers */
53#define BMS1_OCV_FOR_R_DATA0 0x80
Xiaozhe Shib19f7032012-08-16 12:14:16 -070054#define BMS1_VSENSE_FOR_R_DATA0 0x82
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070055/* Coulomb counter data */
Xiaozhe Shib19f7032012-08-16 12:14:16 -070056#define BMS1_CC_DATA0 0x8A
Xiaozhe Shif3da8622013-06-10 14:50:56 -070057/* Shadow Coulomb counter data */
58#define BMS1_SW_CC_DATA0 0xA8
Xiaozhe Shib19f7032012-08-16 12:14:16 -070059/* OCV for soc data */
60#define BMS1_OCV_FOR_SOC_DATA0 0x90
Xiaozhe Shib19f7032012-08-16 12:14:16 -070061#define BMS1_VSENSE_PON_DATA0 0x94
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070062#define BMS1_VSENSE_AVG_DATA0 0x98
Xiaozhe Shib19f7032012-08-16 12:14:16 -070063#define BMS1_VBAT_AVG_DATA0 0x9E
Xiaozhe Shib19f7032012-08-16 12:14:16 -070064/* Extra bms registers */
Xiaozhe Shi57058942013-03-27 16:54:54 -070065#define SOC_STORAGE_REG 0xB0
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070066#define IAVG_STORAGE_REG 0xB1
Anirudh Ghayale0c02932013-07-08 16:26:35 +053067#define BMS_FCC_COUNT 0xB2
68#define BMS_FCC_BASE_REG 0xB3 /* FCC updates - 0xB3 to 0xB7 */
69#define BMS_CHGCYL_BASE_REG 0xB8 /* FCC chgcyl - 0xB8 to 0xBC */
70#define CHARGE_INCREASE_STORAGE 0xBD
Anirudh Ghayald71d9f82013-06-05 11:11:46 +053071#define CHARGE_CYCLE_STORAGE_LSB 0xBE /* LSB=0xBE, MSB=0xBF */
72
Xiaozhe Shic40b3972012-11-30 14:11:16 -080073/* IADC Channel Select */
74#define IADC1_BMS_ADC_CH_SEL_CTL 0x48
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -070075#define IADC1_BMS_ADC_INT_RSNSN_CTL 0x49
76#define IADC1_BMS_FAST_AVG_EN 0x5B
Xiaozhe Shib19f7032012-08-16 12:14:16 -070077
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070078/* Configuration for saving of shutdown soc/iavg */
79#define IGNORE_SOC_TEMP_DECIDEG 50
80#define IAVG_STEP_SIZE_MA 50
81#define IAVG_START 600
Xiaozhe Shif5f966d2013-02-19 14:23:11 -080082#define IAVG_INVALID 0xFF
Xiaozhe Shic7cbd052013-03-29 12:03:11 -070083#define SOC_INVALID 0xFF
Xiaozhe Shicd7e5302012-10-17 12:29:53 -070084
Xiaozhe Shie118c692012-09-24 15:17:43 -070085#define IAVG_SAMPLES 16
86
Anirudh Ghayald71d9f82013-06-05 11:11:46 +053087/* FCC learning constants */
Anirudh Ghayale0c02932013-07-08 16:26:35 +053088#define MAX_FCC_CYCLES 5
Anirudh Ghayald71d9f82013-06-05 11:11:46 +053089#define DELTA_FCC_PERCENT 5
90#define VALID_FCC_CHGCYL_RANGE 50
Anirudh Ghayale0c02932013-07-08 16:26:35 +053091#define CHGCYL_RESOLUTION 20
92#define FCC_DEFAULT_TEMP 250
Anirudh Ghayald71d9f82013-06-05 11:11:46 +053093
Xiaozhe Shib19f7032012-08-16 12:14:16 -070094#define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
95
Xiaozhe Shif3da8622013-06-10 14:50:56 -070096enum {
97 SHDW_CC,
98 CC
99};
100
101enum {
102 NORESET,
103 RESET
104};
105
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700106struct soc_params {
107 int fcc_uah;
108 int cc_uah;
Xiaozhe Shi904f1f72012-12-04 12:47:21 -0800109 int rbatt_mohm;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700110 int iavg_ua;
111 int uuc_uah;
112 int ocv_charge_uah;
Xiaozhe Shif36d2862013-01-04 10:17:35 -0800113 int delta_time_s;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700114};
115
116struct raw_soc_params {
117 uint16_t last_good_ocv_raw;
118 int64_t cc;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700119 int64_t shdw_cc;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700120 int last_good_ocv_uv;
121};
122
Anirudh Ghayale0c02932013-07-08 16:26:35 +0530123struct fcc_sample {
Anirudh Ghayald71d9f82013-06-05 11:11:46 +0530124 int fcc_new;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +0530125 int chargecycles;
126};
127
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800128struct bms_irq {
129 unsigned int irq;
130 unsigned long disabled;
131};
132
133struct bms_wakeup_source {
134 struct wakeup_source source;
135 unsigned long disabled;
136};
137
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700138struct qpnp_bms_chip {
139 struct device *dev;
140 struct power_supply bms_psy;
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -0700141 bool bms_psy_registered;
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -0700142 struct power_supply *batt_psy;
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700143 struct spmi_device *spmi;
144 u16 base;
Xiaozhe Shic40b3972012-11-30 14:11:16 -0800145 u16 iadc_base;
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700146
147 u8 revision1;
148 u8 revision2;
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -0700149
150 u8 iadc_bms_revision1;
151 u8 iadc_bms_revision2;
152
Xiaozhe Shid5d21412013-02-06 17:14:41 -0800153 int battery_present;
Xiaozhe Shi890fbf42013-05-02 16:42:53 -0700154 int battery_status;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800155 bool new_battery;
Xiaozhe Shi890fbf42013-05-02 16:42:53 -0700156 bool done_charging;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800157 bool last_soc_invalid;
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700158 /* platform data */
Abhijeet Dharmapurikareef88662012-11-08 17:26:29 -0800159 int r_sense_uohm;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700160 unsigned int v_cutoff_uv;
Abhijeet Dharmapurikareef88662012-11-08 17:26:29 -0800161 int max_voltage_uv;
162 int r_conn_mohm;
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700163 int shutdown_soc_valid_limit;
164 int adjust_soc_low_threshold;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700165 int chg_term_ua;
Xiaozhe Shi73a65692012-09-18 17:51:57 -0700166 enum battery_type batt_type;
Xiaozhe Shi976618f2013-04-30 10:49:30 -0700167 unsigned int fcc_mah;
Xiaozhe Shi73a65692012-09-18 17:51:57 -0700168 struct single_row_lut *fcc_temp_lut;
169 struct single_row_lut *fcc_sf_lut;
170 struct pc_temp_ocv_lut *pc_temp_ocv_lut;
171 struct sf_lut *pc_sf_lut;
172 struct sf_lut *rbatt_sf_lut;
173 int default_rbatt_mohm;
Xiaozhe Shi1a10aff2013-04-01 15:40:05 -0700174 int rbatt_capacitive_mohm;
Xiaozhe Shi6dc56f12013-05-02 15:56:55 -0700175 int rbatt_mohm;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700176
177 struct delayed_work calculate_soc_delayed_work;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800178 struct work_struct recalc_work;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700179
180 struct mutex bms_output_lock;
181 struct mutex last_ocv_uv_mutex;
Xiaozhe Shia6618a22013-03-27 10:26:29 -0700182 struct mutex vbat_monitor_mutex;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700183 struct mutex soc_invalidation_mutex;
Xiaozhe Shi04da0992013-04-26 16:32:14 -0700184 struct mutex last_soc_mutex;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700185
Xiaozhe Shic40b3972012-11-30 14:11:16 -0800186 bool use_external_rsense;
Xiaozhe Shibdf14742012-12-05 12:41:48 -0800187 bool use_ocv_thresholds;
Xiaozhe Shic40b3972012-11-30 14:11:16 -0800188
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700189 bool ignore_shutdown_soc;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800190 bool shutdown_soc_invalid;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700191 int shutdown_soc;
192 int shutdown_iavg_ma;
193
Xiaozhe Shi4be85782013-02-22 17:33:40 -0800194 struct wake_lock low_voltage_wake_lock;
Xiaozhe Shi4be85782013-02-22 17:33:40 -0800195 int low_voltage_threshold;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700196 int low_soc_calc_threshold;
197 int low_soc_calculate_soc_ms;
198 int calculate_soc_ms;
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800199 struct bms_wakeup_source soc_wake_source;
Xiaozhe Shia6618a22013-03-27 10:26:29 -0700200 struct wake_lock cv_wake_lock;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700201
Xiaozhe Shie118c692012-09-24 15:17:43 -0700202 uint16_t ocv_reading_at_100;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700203 uint16_t prev_last_good_ocv_raw;
204 int last_ocv_uv;
Xiaozhe Shicc48e992013-05-28 16:42:24 -0700205 int charging_adjusted_ocv;
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800206 int last_ocv_temp;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700207 int last_cc_uah;
Xiaozhe Shi04da0992013-04-26 16:32:14 -0700208 unsigned long last_soc_change_sec;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700209 unsigned long tm_sec;
Xiaozhe Shi04da0992013-04-26 16:32:14 -0700210 unsigned long report_tm_sec;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700211 bool first_time_calc_soc;
212 bool first_time_calc_uuc;
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -0700213 int64_t software_cc_uah;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700214 int64_t software_shdw_cc_uah;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700215
216 int iavg_samples_ma[IAVG_SAMPLES];
217 int iavg_index;
218 int iavg_num_samples;
219 struct timespec t_soc_queried;
220 int last_soc;
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -0700221 int last_soc_est;
Xiaozhe Shicc137262013-03-10 06:21:41 -0700222 int last_soc_unbound;
Xiaozhe Shi04da0992013-04-26 16:32:14 -0700223 bool was_charging_at_sleep;
224 int charge_start_tm_sec;
225 int catch_up_time_sec;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700226 struct single_row_lut *adjusted_fcc_temp_lut;
227
Xiaozhe Shia6618a22013-03-27 10:26:29 -0700228 struct qpnp_adc_tm_btm_param vbat_monitor_params;
Xiaozhe Shi535494d2013-04-05 12:27:51 -0700229 struct qpnp_adc_tm_btm_param die_temp_monitor_params;
230 int temperature_margin;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700231 unsigned int vadc_v0625;
232 unsigned int vadc_v1250;
233
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700234 int prev_uuc_iavg_ma;
235 int prev_pc_unusable;
236 int ibat_at_cv_ua;
237 int soc_at_cv;
238 int prev_chg_soc;
239 int calculated_soc;
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -0800240 int prev_voltage_based_soc;
241 bool use_voltage_soc;
Xiaozhe Shia6618a22013-03-27 10:26:29 -0700242 bool in_cv_range;
Xiaozhe Shibdf14742012-12-05 12:41:48 -0800243
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -0800244 int prev_batt_terminal_uv;
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -0700245 int high_ocv_correction_limit_uv;
246 int low_ocv_correction_limit_uv;
247 int flat_ocv_threshold_uv;
248 int hold_soc_est;
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -0800249
Xiaozhe Shibdf14742012-12-05 12:41:48 -0800250 int ocv_high_threshold_uv;
251 int ocv_low_threshold_uv;
Xiaozhe Shicdeee312012-12-18 15:10:18 -0800252 unsigned long last_recalc_time;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +0530253
Anirudh Ghayale0c02932013-07-08 16:26:35 +0530254 struct fcc_sample *fcc_learning_samples;
255 u8 fcc_sample_count;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +0530256 int enable_fcc_learning;
257 int min_fcc_learning_soc;
258 int min_fcc_ocv_pc;
259 int min_fcc_learning_samples;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +0530260 int start_soc;
261 int end_soc;
262 int start_pc;
263 int start_cc_uah;
264 int start_real_soc;
265 int end_cc_uah;
266 uint16_t fcc_new_mah;
267 int fcc_new_batt_temp;
268 uint16_t charge_cycles;
269 u8 charge_increase;
Anirudh Ghayale0c02932013-07-08 16:26:35 +0530270 int fcc_resolution;
271 bool battery_removed;
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800272 struct bms_irq sw_cc_thr_irq;
273 struct bms_irq ocv_thr_irq;
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700274};
275
276static struct of_device_id qpnp_bms_match_table[] = {
277 { .compatible = QPNP_BMS_DEV_NAME },
278 {}
279};
280
281static char *qpnp_bms_supplicants[] = {
282 "battery"
283};
284
285static enum power_supply_property msm_bms_power_props[] = {
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700286 POWER_SUPPLY_PROP_CAPACITY,
287 POWER_SUPPLY_PROP_CURRENT_NOW,
Xiaozhe Shi6dc56f12013-05-02 15:56:55 -0700288 POWER_SUPPLY_PROP_RESISTANCE,
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -0700289 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700290 POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700291 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
Anirudh Ghayalc9d981a2013-06-24 09:50:33 +0530292 POWER_SUPPLY_PROP_CHARGE_FULL,
Anirudh Ghayal9dd582d2013-06-07 17:48:58 +0530293 POWER_SUPPLY_PROP_CYCLE_COUNT,
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700294};
295
Anirudh Ghayale0c02932013-07-08 16:26:35 +0530296static int discard_backup_fcc_data(struct qpnp_bms_chip *chip);
297static void backup_charge_cycle(struct qpnp_bms_chip *chip);
298
Xiaozhe Shi20640b52013-01-03 11:49:30 -0800299static bool bms_reset;
Xiaozhe Shi781b0a22012-11-05 17:18:27 -0800300
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700301static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
302 u16 base, int count)
303{
304 int rc;
305 struct spmi_device *spmi = chip->spmi;
306
307 rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700308 if (rc) {
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700309 pr_err("SPMI read failed rc=%d\n", rc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700310 return rc;
311 }
Xiaozhe Shib19f7032012-08-16 12:14:16 -0700312 return 0;
313}
314
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700315static int qpnp_write_wrapper(struct qpnp_bms_chip *chip, u8 *val,
316 u16 base, int count)
317{
318 int rc;
319 struct spmi_device *spmi = chip->spmi;
320
321 rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, val, count);
322 if (rc) {
323 pr_err("SPMI write failed rc=%d\n", rc);
324 return rc;
325 }
326 return 0;
327}
328
Xiaozhe Shidffbe692012-12-11 15:35:46 -0800329static int qpnp_masked_write_base(struct qpnp_bms_chip *chip, u16 addr,
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700330 u8 mask, u8 val)
331{
332 int rc;
333 u8 reg;
334
Xiaozhe Shidffbe692012-12-11 15:35:46 -0800335 rc = qpnp_read_wrapper(chip, &reg, addr, 1);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700336 if (rc) {
Xiaozhe Shidffbe692012-12-11 15:35:46 -0800337 pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700338 return rc;
339 }
340 reg &= ~mask;
341 reg |= val & mask;
Xiaozhe Shidffbe692012-12-11 15:35:46 -0800342 rc = qpnp_write_wrapper(chip, &reg, addr, 1);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700343 if (rc) {
344 pr_err("write failed addr = %03X, val = %02x, mask = %02x, reg = %02x, rc = %d\n",
Xiaozhe Shidffbe692012-12-11 15:35:46 -0800345 addr, val, mask, reg, rc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700346 return rc;
347 }
348 return 0;
349}
350
Xiaozhe Shidffbe692012-12-11 15:35:46 -0800351static int qpnp_masked_write_iadc(struct qpnp_bms_chip *chip, u16 addr,
352 u8 mask, u8 val)
353{
354 return qpnp_masked_write_base(chip, chip->iadc_base + addr, mask, val);
355}
356
357static int qpnp_masked_write(struct qpnp_bms_chip *chip, u16 addr,
358 u8 mask, u8 val)
359{
360 return qpnp_masked_write_base(chip, chip->base + addr, mask, val);
361}
362
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800363static void bms_stay_awake(struct bms_wakeup_source *source)
364{
365 if (__test_and_clear_bit(0, &source->disabled)) {
366 __pm_stay_awake(&source->source);
367 pr_debug("enabled source %s\n", source->source.name);
368 }
369}
370
371static void bms_relax(struct bms_wakeup_source *source)
372{
373 if (!__test_and_set_bit(0, &source->disabled)) {
374 __pm_relax(&source->source);
375 pr_debug("disabled source %s\n", source->source.name);
376 }
377}
378
379static void enable_bms_irq(struct bms_irq *irq)
380{
381 if (__test_and_clear_bit(0, &irq->disabled)) {
382 enable_irq(irq->irq);
383 pr_debug("enabled irq %d\n", irq->irq);
384 }
385}
386
387static void disable_bms_irq(struct bms_irq *irq)
388{
389 if (!__test_and_set_bit(0, &irq->disabled)) {
390 disable_irq(irq->irq);
391 pr_debug("disabled irq %d\n", irq->irq);
392 }
393}
394
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700395#define HOLD_OREG_DATA BIT(0)
396static int lock_output_data(struct qpnp_bms_chip *chip)
397{
398 int rc;
399
400 rc = qpnp_masked_write(chip, BMS1_CC_DATA_CTL,
401 HOLD_OREG_DATA, HOLD_OREG_DATA);
402 if (rc) {
403 pr_err("couldnt lock bms output rc = %d\n", rc);
404 return rc;
405 }
406 return 0;
407}
408
409static int unlock_output_data(struct qpnp_bms_chip *chip)
410{
411 int rc;
412
413 rc = qpnp_masked_write(chip, BMS1_CC_DATA_CTL, HOLD_OREG_DATA, 0);
414 if (rc) {
415 pr_err("fail to unlock BMS_CONTROL rc = %d\n", rc);
416 return rc;
417 }
418 return 0;
419}
420
421#define V_PER_BIT_MUL_FACTOR 97656
422#define V_PER_BIT_DIV_FACTOR 1000
423#define VADC_INTRINSIC_OFFSET 0x6000
424
Xiaozhe Shibdf14742012-12-05 12:41:48 -0800425static int vadc_reading_to_uv(int reading)
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700426{
427 if (reading <= VADC_INTRINSIC_OFFSET)
428 return 0;
429
430 return (reading - VADC_INTRINSIC_OFFSET)
431 * V_PER_BIT_MUL_FACTOR / V_PER_BIT_DIV_FACTOR;
432}
433
434#define VADC_CALIB_UV 625000
435#define VBATT_MUL_FACTOR 3
Xiaozhe Shibdf14742012-12-05 12:41:48 -0800436static int adjust_vbatt_reading(struct qpnp_bms_chip *chip, int reading_uv)
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700437{
438 s64 numerator, denominator;
439
440 if (reading_uv == 0)
441 return 0;
442
443 /* don't adjust if not calibrated */
444 if (chip->vadc_v0625 == 0 || chip->vadc_v1250 == 0) {
445 pr_debug("No cal yet return %d\n",
446 VBATT_MUL_FACTOR * reading_uv);
447 return VBATT_MUL_FACTOR * reading_uv;
448 }
449
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700450 numerator = ((s64)reading_uv - chip->vadc_v0625) * VADC_CALIB_UV;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700451 denominator = (s64)chip->vadc_v1250 - chip->vadc_v0625;
452 if (denominator == 0)
453 return reading_uv * VBATT_MUL_FACTOR;
454 return (VADC_CALIB_UV + div_s64(numerator, denominator))
455 * VBATT_MUL_FACTOR;
456}
457
Xiaozhe Shibdf14742012-12-05 12:41:48 -0800458static int convert_vbatt_uv_to_raw(struct qpnp_bms_chip *chip,
459 int unadjusted_vbatt)
460{
461 int scaled_vbatt = unadjusted_vbatt / VBATT_MUL_FACTOR;
462
463 if (scaled_vbatt <= 0)
464 return VADC_INTRINSIC_OFFSET;
465 return ((scaled_vbatt * V_PER_BIT_DIV_FACTOR) / V_PER_BIT_MUL_FACTOR)
466 + VADC_INTRINSIC_OFFSET;
467}
468
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700469static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
470 uint16_t reading)
471{
Xiaozhe Shi4dbc01b2013-04-30 11:27:52 -0700472 int64_t uv;
473 int rc;
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700474
475 uv = vadc_reading_to_uv(reading);
Xiaozhe Shi4dbc01b2013-04-30 11:27:52 -0700476 pr_debug("%u raw converted into %lld uv\n", reading, uv);
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700477 uv = adjust_vbatt_reading(chip, uv);
Xiaozhe Shi4dbc01b2013-04-30 11:27:52 -0700478 pr_debug("adjusted into %lld uv\n", uv);
479 rc = qpnp_vbat_sns_comp_result(&uv);
480 if (rc)
481 pr_debug("could not compensate vbatt\n");
482 pr_debug("compensated into %lld uv\n", uv);
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700483 return uv;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700484}
485
486#define CC_READING_RESOLUTION_N 542535
487#define CC_READING_RESOLUTION_D 100000
Xiaozhe Shi8f5dd1b2013-04-30 10:27:58 -0700488static s64 cc_reading_to_uv(s64 reading)
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700489{
490 return div_s64(reading * CC_READING_RESOLUTION_N,
491 CC_READING_RESOLUTION_D);
492}
493
Xiaozhe Shi0c484932013-02-05 16:14:10 -0800494#define QPNP_ADC_GAIN_IDEAL 3291LL
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700495static s64 cc_adjust_for_gain(s64 uv, uint16_t gain)
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700496{
497 s64 result_uv;
498
499 pr_debug("adjusting_uv = %lld\n", uv);
Xiaozhe Shi820a47a2012-11-27 13:23:27 -0800500 if (gain == 0) {
501 pr_debug("gain is %d, not adjusting\n", gain);
502 return uv;
503 }
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700504 pr_debug("adjusting by factor: %lld/%hu = %lld%%\n",
Xiaozhe Shi0c484932013-02-05 16:14:10 -0800505 QPNP_ADC_GAIN_IDEAL, gain,
506 div_s64(QPNP_ADC_GAIN_IDEAL * 100LL, (s64)gain));
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700507
Xiaozhe Shi0c484932013-02-05 16:14:10 -0800508 result_uv = div_s64(uv * QPNP_ADC_GAIN_IDEAL, (s64)gain);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700509 pr_debug("result_uv = %lld\n", result_uv);
510 return result_uv;
511}
512
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800513static s64 cc_reverse_adjust_for_gain(s64 uv)
514{
515 struct qpnp_iadc_calib calibration;
516 int gain;
517 s64 result_uv;
518
519 qpnp_iadc_get_gain_and_offset(&calibration);
520 gain = (int)calibration.gain_raw - (int)calibration.offset_raw;
521
522 pr_debug("reverse adjusting_uv = %lld\n", uv);
523 if (gain == 0) {
524 pr_debug("gain is %d, not adjusting\n", gain);
525 return uv;
526 }
527 pr_debug("adjusting by factor: %hu/%lld = %lld%%\n",
528 gain, QPNP_ADC_GAIN_IDEAL,
529 div64_s64((s64)gain * 100LL,
530 (s64)QPNP_ADC_GAIN_IDEAL));
531
532 result_uv = div64_s64(uv * (s64)gain, QPNP_ADC_GAIN_IDEAL);
533 pr_debug("result_uv = %lld\n", result_uv);
534 return result_uv;
535}
536
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700537static int convert_vsense_to_uv(struct qpnp_bms_chip *chip,
538 int16_t reading)
539{
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700540 struct qpnp_iadc_calib calibration;
541
542 qpnp_iadc_get_gain_and_offset(&calibration);
543 return cc_adjust_for_gain(cc_reading_to_uv(reading),
Xiaozhe Shi0c484932013-02-05 16:14:10 -0800544 calibration.gain_raw - calibration.offset_raw);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700545}
546
547static int read_vsense_avg(struct qpnp_bms_chip *chip, int *result_uv)
548{
549 int rc;
550 int16_t reading;
551
552 rc = qpnp_read_wrapper(chip, (u8 *)&reading,
553 chip->base + BMS1_VSENSE_AVG_DATA0, 2);
554
555 if (rc) {
556 pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
557 return rc;
558 }
559
560 *result_uv = convert_vsense_to_uv(chip, reading);
561 return 0;
562}
563
564static int get_battery_current(struct qpnp_bms_chip *chip, int *result_ua)
565{
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -0700566 int rc, vsense_uv = 0;
567 int64_t temp_current;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700568
Xiaozhe Shid0a79542012-11-06 10:00:38 -0800569 if (chip->r_sense_uohm == 0) {
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700570 pr_err("r_sense is zero\n");
571 return -EINVAL;
572 }
573
574 mutex_lock(&chip->bms_output_lock);
575 lock_output_data(chip);
576 read_vsense_avg(chip, &vsense_uv);
577 unlock_output_data(chip);
578 mutex_unlock(&chip->bms_output_lock);
579
580 pr_debug("vsense_uv=%duV\n", vsense_uv);
581 /* cast for signed division */
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -0700582 temp_current = div_s64((vsense_uv * 1000000LL),
583 (int)chip->r_sense_uohm);
584
585 rc = qpnp_iadc_comp_result(&temp_current);
586 if (rc)
587 pr_debug("error compensation failed: %d\n", rc);
588
589 *result_ua = temp_current;
590 pr_debug("err compensated ibat=%duA\n", *result_ua);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700591 return 0;
592}
593
594static int get_battery_voltage(int *result_uv)
595{
596 int rc;
597 struct qpnp_vadc_result adc_result;
598
599 rc = qpnp_vadc_read(VBAT_SNS, &adc_result);
600 if (rc) {
601 pr_err("error reading adc channel = %d, rc = %d\n",
602 VBAT_SNS, rc);
603 return rc;
604 }
605 pr_debug("mvolts phy = %lld meas = 0x%llx\n", adc_result.physical,
606 adc_result.measurement);
607 *result_uv = (int)adc_result.physical;
608 return 0;
609}
610
Xiaozhe Shie118c692012-09-24 15:17:43 -0700611#define CC_36_BIT_MASK 0xFFFFFFFFFLL
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800612static uint64_t convert_s64_to_s36(int64_t raw64)
613{
614 return (uint64_t) raw64 & CC_36_BIT_MASK;
615}
616
617#define SIGN_EXTEND_36_TO_64_MASK (-1LL ^ CC_36_BIT_MASK)
618static int64_t convert_s36_to_s64(uint64_t raw36)
619{
620 raw36 = raw36 & CC_36_BIT_MASK;
621 /* convert 36 bit signed value into 64 signed value */
622 return (raw36 >> 35) == 0LL ?
623 raw36 : (SIGN_EXTEND_36_TO_64_MASK | raw36);
624}
625
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700626static int read_cc_raw(struct qpnp_bms_chip *chip, int64_t *reading,
627 int cc_type)
Xiaozhe Shie118c692012-09-24 15:17:43 -0700628{
629 int64_t raw_reading;
630 int rc;
631
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700632 if (cc_type == SHDW_CC)
633 rc = qpnp_read_wrapper(chip, (u8 *)&raw_reading,
634 chip->base + BMS1_SW_CC_DATA0, 5);
635 else
636 rc = qpnp_read_wrapper(chip, (u8 *)&raw_reading,
637 chip->base + BMS1_CC_DATA0, 5);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700638 if (rc) {
639 pr_err("Error reading cc: rc = %d\n", rc);
640 return -ENXIO;
641 }
642
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -0800643 *reading = convert_s36_to_s64(raw_reading);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700644
645 return 0;
646}
647
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700648static int calib_vadc(struct qpnp_bms_chip *chip)
649{
Xiaozhe Shif62c0152013-03-28 17:57:19 -0700650 int rc, raw_0625, raw_1250;
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700651 struct qpnp_vadc_result result;
652
653 rc = qpnp_vadc_read(REF_625MV, &result);
654 if (rc) {
655 pr_debug("vadc read failed with rc = %d\n", rc);
656 return rc;
657 }
Xiaozhe Shif62c0152013-03-28 17:57:19 -0700658 raw_0625 = result.adc_code;
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700659
660 rc = qpnp_vadc_read(REF_125V, &result);
661 if (rc) {
662 pr_debug("vadc read failed with rc = %d\n", rc);
663 return rc;
664 }
Xiaozhe Shif62c0152013-03-28 17:57:19 -0700665 raw_1250 = result.adc_code;
666 chip->vadc_v0625 = vadc_reading_to_uv(raw_0625);
667 chip->vadc_v1250 = vadc_reading_to_uv(raw_1250);
668 pr_debug("vadc calib: 0625 = %d raw (%d uv), 1250 = %d raw (%d uv)\n",
669 raw_0625, chip->vadc_v0625,
670 raw_1250, chip->vadc_v1250);
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700671 return 0;
672}
673
Xiaozhe Shie118c692012-09-24 15:17:43 -0700674static void convert_and_store_ocv(struct qpnp_bms_chip *chip,
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800675 struct raw_soc_params *raw,
676 int batt_temp)
Xiaozhe Shie118c692012-09-24 15:17:43 -0700677{
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700678 int rc;
679
680 pr_debug("prev_last_good_ocv_raw = %d, last_good_ocv_raw = %d\n",
681 chip->prev_last_good_ocv_raw,
682 raw->last_good_ocv_raw);
683 rc = calib_vadc(chip);
684 if (rc)
685 pr_err("Vadc reference voltage read failed, rc = %d\n", rc);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700686 chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
687 raw->last_good_ocv_uv = convert_vbatt_raw_to_uv(chip,
688 raw->last_good_ocv_raw);
689 chip->last_ocv_uv = raw->last_good_ocv_uv;
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800690 chip->last_ocv_temp = batt_temp;
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -0700691 chip->software_cc_uah = 0;
Xiaozhe Shi4e376652012-10-25 12:38:50 -0700692 pr_debug("last_good_ocv_uv = %d\n", raw->last_good_ocv_uv);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700693}
694
Xiaozhe Shia045a562012-11-28 16:55:39 -0800695#define CLEAR_CC BIT(7)
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700696#define CLEAR_SHDW_CC BIT(6)
Xiaozhe Shia045a562012-11-28 16:55:39 -0800697/**
698 * reset both cc and sw-cc.
699 * note: this should only be ever called from one thread
700 * or there may be a race condition where CC is never enabled
701 * again
702 */
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700703static void reset_cc(struct qpnp_bms_chip *chip, u8 flags)
Xiaozhe Shia045a562012-11-28 16:55:39 -0800704{
705 int rc;
706
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700707 pr_debug("resetting cc manually with flags %hhu\n", flags);
708 mutex_lock(&chip->bms_output_lock);
Xiaozhe Shia045a562012-11-28 16:55:39 -0800709 rc = qpnp_masked_write(chip, BMS1_CC_CLEAR_CTL,
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700710 flags,
711 flags);
Xiaozhe Shia045a562012-11-28 16:55:39 -0800712 if (rc)
713 pr_err("cc reset failed: %d\n", rc);
714
715 /* wait for 100us for cc to reset */
716 udelay(100);
717
718 rc = qpnp_masked_write(chip, BMS1_CC_CLEAR_CTL,
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700719 flags, 0);
Xiaozhe Shia045a562012-11-28 16:55:39 -0800720 if (rc)
721 pr_err("cc reenable failed: %d\n", rc);
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700722 mutex_unlock(&chip->bms_output_lock);
Xiaozhe Shia045a562012-11-28 16:55:39 -0800723}
724
Xiaozhe Shi890fbf42013-05-02 16:42:53 -0700725static int get_battery_status(struct qpnp_bms_chip *chip)
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800726{
727 union power_supply_propval ret = {0,};
728
729 if (chip->batt_psy == NULL)
730 chip->batt_psy = power_supply_get_by_name("battery");
731 if (chip->batt_psy) {
732 /* if battery has been registered, use the status property */
733 chip->batt_psy->get_property(chip->batt_psy,
734 POWER_SUPPLY_PROP_STATUS, &ret);
Xiaozhe Shi890fbf42013-05-02 16:42:53 -0700735 return ret.intval;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800736 }
737
738 /* Default to false if the battery power supply is not registered. */
739 pr_debug("battery power supply is not registered\n");
Xiaozhe Shi890fbf42013-05-02 16:42:53 -0700740 return POWER_SUPPLY_STATUS_UNKNOWN;
741}
742
743static bool is_battery_charging(struct qpnp_bms_chip *chip)
744{
745 return get_battery_status(chip) == POWER_SUPPLY_STATUS_CHARGING;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800746}
747
Xiaozhe Shia6618a22013-03-27 10:26:29 -0700748static bool is_battery_present(struct qpnp_bms_chip *chip)
749{
750 union power_supply_propval ret = {0,};
751
752 if (chip->batt_psy == NULL)
753 chip->batt_psy = power_supply_get_by_name("battery");
754 if (chip->batt_psy) {
755 /* if battery has been registered, use the status property */
756 chip->batt_psy->get_property(chip->batt_psy,
757 POWER_SUPPLY_PROP_PRESENT, &ret);
758 return ret.intval;
759 }
760
761 /* Default to false if the battery power supply is not registered. */
762 pr_debug("battery power supply is not registered\n");
763 return false;
764}
765
Xiaozhe Shi8658c982013-04-30 11:33:07 -0700766static bool is_battery_full(struct qpnp_bms_chip *chip)
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800767{
Xiaozhe Shi890fbf42013-05-02 16:42:53 -0700768 return get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800769}
770
771static int get_simultaneous_batt_v_and_i(struct qpnp_bms_chip *chip,
772 int *ibat_ua, int *vbat_uv)
773{
774 struct qpnp_iadc_result i_result;
775 struct qpnp_vadc_result v_result;
776 enum qpnp_iadc_channels iadc_channel;
777 int rc;
778
779 iadc_channel = chip->use_external_rsense ?
780 EXTERNAL_RSENSE : INTERNAL_RSENSE;
Xiaozhe Shi8658c982013-04-30 11:33:07 -0700781 if (is_battery_full(chip)) {
782 rc = get_battery_current(chip, ibat_ua);
783 if (rc) {
784 pr_err("bms current read failed with rc: %d\n", rc);
785 return rc;
786 }
787 rc = qpnp_vadc_read(VBAT_SNS, &v_result);
788 if (rc) {
789 pr_err("vadc read failed with rc: %d\n", rc);
790 return rc;
791 }
792 *vbat_uv = (int)v_result.physical;
793 } else {
794 rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
795 VBAT_SNS, &v_result);
796 if (rc) {
797 pr_err("adc sync read failed with rc: %d\n", rc);
798 return rc;
799 }
800 /*
801 * reverse the current read by the iadc, since the bms uses
802 * flipped battery current polarity.
803 */
804 *ibat_ua = -1 * (int)i_result.result_ua;
805 *vbat_uv = (int)v_result.physical;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800806 }
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800807
808 return 0;
809}
810
811static int estimate_ocv(struct qpnp_bms_chip *chip)
812{
813 int ibat_ua, vbat_uv, ocv_est_uv;
814 int rc;
Xiaozhe Shi1a10aff2013-04-01 15:40:05 -0700815 int rbatt_mohm = chip->default_rbatt_mohm + chip->r_conn_mohm
816 + chip->rbatt_capacitive_mohm;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800817
818 rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
819 if (rc) {
820 pr_err("simultaneous failed rc = %d\n", rc);
821 return rc;
822 }
823
824 ocv_est_uv = vbat_uv + (ibat_ua * rbatt_mohm) / 1000;
825 pr_debug("estimated pon ocv = %d\n", ocv_est_uv);
826 return ocv_est_uv;
827}
828
829static void reset_for_new_battery(struct qpnp_bms_chip *chip, int batt_temp)
830{
831 chip->last_ocv_uv = estimate_ocv(chip);
Xiaozhe Shi04da0992013-04-26 16:32:14 -0700832 mutex_lock(&chip->last_soc_mutex);
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800833 chip->last_soc = -EINVAL;
Xiaozhe Shi04da0992013-04-26 16:32:14 -0700834 chip->last_soc_invalid = true;
835 mutex_unlock(&chip->last_soc_mutex);
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800836 chip->soc_at_cv = -EINVAL;
837 chip->shutdown_soc_invalid = true;
838 chip->shutdown_soc = 0;
839 chip->shutdown_iavg_ma = 0;
840 chip->prev_pc_unusable = -EINVAL;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700841 reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -0700842 chip->software_cc_uah = 0;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700843 chip->software_shdw_cc_uah = 0;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800844 chip->last_cc_uah = INT_MIN;
845 chip->last_ocv_temp = batt_temp;
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -0800846 chip->prev_batt_terminal_uv = 0;
Anirudh Ghayale0c02932013-07-08 16:26:35 +0530847 if (chip->enable_fcc_learning) {
848 chip->adjusted_fcc_temp_lut = NULL;
849 chip->fcc_new_mah = -EINVAL;
850 /* reset the charge-cycle and charge-increase registers */
851 chip->charge_increase = 0;
852 chip->charge_cycles = 0;
853 backup_charge_cycle(chip);
854 /* discard all the FCC learnt data and reset the local table */
855 discard_backup_fcc_data(chip);
856 memset(chip->fcc_learning_samples, 0,
857 chip->min_fcc_learning_samples *
858 sizeof(struct fcc_sample));
859 }
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800860}
861
Abhijeet Dharmapurikar15f30fb2012-12-27 17:20:29 -0800862#define OCV_RAW_UNINITIALIZED 0xFFFF
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -0700863#define MIN_OCV_UV 2000000
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700864static int read_soc_params_raw(struct qpnp_bms_chip *chip,
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800865 struct raw_soc_params *raw,
866 int batt_temp)
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700867{
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -0700868 bool warm_reset = false;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700869 int rc;
870
871 mutex_lock(&chip->bms_output_lock);
Xiaozhe Shia045a562012-11-28 16:55:39 -0800872
Xiaozhe Shie118c692012-09-24 15:17:43 -0700873 lock_output_data(chip);
874
875 rc = qpnp_read_wrapper(chip, (u8 *)&raw->last_good_ocv_raw,
876 chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
877 if (rc) {
878 pr_err("Error reading ocv: rc = %d\n", rc);
879 return -ENXIO;
880 }
881
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700882 rc = read_cc_raw(chip, &raw->cc, CC);
883 rc = read_cc_raw(chip, &raw->shdw_cc, SHDW_CC);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700884 if (rc) {
885 pr_err("Failed to read raw cc data, rc = %d\n", rc);
886 return rc;
887 }
888
889 unlock_output_data(chip);
890 mutex_unlock(&chip->bms_output_lock);
891
Abhijeet Dharmapurikar15f30fb2012-12-27 17:20:29 -0800892 if (chip->prev_last_good_ocv_raw == OCV_RAW_UNINITIALIZED) {
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800893 convert_and_store_ocv(chip, raw, batt_temp);
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -0700894 pr_debug("PON_OCV_UV = %d, cc = %llx\n",
895 chip->last_ocv_uv, raw->cc);
896 warm_reset = qpnp_pon_is_warm_reset();
897 if (raw->last_good_ocv_uv < MIN_OCV_UV
898 || warm_reset > 0) {
899 pr_debug("OCV is stale or bad, estimating new OCV.\n");
900 chip->last_ocv_uv = estimate_ocv(chip);
901 raw->last_good_ocv_uv = chip->last_ocv_uv;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700902 reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -0700903 pr_debug("New PON_OCV_UV = %d, cc = %llx\n",
904 chip->last_ocv_uv, raw->cc);
905 }
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800906 } else if (chip->new_battery) {
907 /* if a new battery was inserted, estimate the ocv */
908 reset_for_new_battery(chip, batt_temp);
909 raw->cc = 0;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700910 raw->shdw_cc = 0;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -0800911 raw->last_good_ocv_uv = chip->last_ocv_uv;
912 chip->new_battery = false;
Xiaozhe Shi74548b92013-05-02 16:47:08 -0700913 } else if (chip->done_charging) {
914 chip->done_charging = false;
915 /* if we just finished charging, reset CC and fake 100% */
916 chip->ocv_reading_at_100 = raw->last_good_ocv_raw;
917 chip->last_ocv_uv = chip->max_voltage_uv;
918 raw->last_good_ocv_uv = chip->max_voltage_uv;
919 raw->cc = 0;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700920 raw->shdw_cc = 0;
921 reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
Xiaozhe Shi74548b92013-05-02 16:47:08 -0700922 chip->last_ocv_temp = batt_temp;
923 chip->software_cc_uah = 0;
Xiaozhe Shif3da8622013-06-10 14:50:56 -0700924 chip->software_shdw_cc_uah = 0;
Xiaozhe Shi74548b92013-05-02 16:47:08 -0700925 chip->last_cc_uah = INT_MIN;
926 pr_debug("EOC Battery full ocv_reading = 0x%x\n",
927 chip->ocv_reading_at_100);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700928 } else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800929 convert_and_store_ocv(chip, raw, batt_temp);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700930 /* forget the old cc value upon ocv */
Xiaozhe Shif36d2862013-01-04 10:17:35 -0800931 chip->last_cc_uah = INT_MIN;
Xiaozhe Shie118c692012-09-24 15:17:43 -0700932 } else {
933 raw->last_good_ocv_uv = chip->last_ocv_uv;
934 }
935
Xiaozhe Shi74548b92013-05-02 16:47:08 -0700936 /* stop faking a high OCV if we get a new OCV */
937 if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw)
Abhijeet Dharmapurikar15f30fb2012-12-27 17:20:29 -0800938 chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
Xiaozhe Shi74548b92013-05-02 16:47:08 -0700939
Xiaozhe Shie118c692012-09-24 15:17:43 -0700940 pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
941 raw->last_good_ocv_raw, raw->last_good_ocv_uv);
942 pr_debug("cc_raw= 0x%llx\n", raw->cc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -0700943 return 0;
944}
945
Xiaozhe Shie118c692012-09-24 15:17:43 -0700946static int calculate_pc(struct qpnp_bms_chip *chip, int ocv_uv,
947 int batt_temp)
948{
949 int pc;
950
951 pc = interpolate_pc(chip->pc_temp_ocv_lut,
952 batt_temp / 10, ocv_uv / 1000);
953 pr_debug("pc = %u %% for ocv = %d uv batt_temp = %d\n",
954 pc, ocv_uv, batt_temp);
955 /* Multiply the initial FCC value by the scale factor. */
956 return pc;
957}
958
959static int calculate_fcc(struct qpnp_bms_chip *chip, int batt_temp)
960{
961 int fcc_uah;
962
963 if (chip->adjusted_fcc_temp_lut == NULL) {
964 /* interpolate_fcc returns a mv value. */
965 fcc_uah = interpolate_fcc(chip->fcc_temp_lut,
966 batt_temp) * 1000;
967 pr_debug("fcc = %d uAh\n", fcc_uah);
968 return fcc_uah;
969 } else {
970 return 1000 * interpolate_fcc(chip->adjusted_fcc_temp_lut,
971 batt_temp);
972 }
973}
974
975/* calculate remaining charge at the time of ocv */
976static int calculate_ocv_charge(struct qpnp_bms_chip *chip,
977 struct raw_soc_params *raw,
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800978 int fcc_uah)
Xiaozhe Shie118c692012-09-24 15:17:43 -0700979{
980 int ocv_uv, pc;
981
982 ocv_uv = raw->last_good_ocv_uv;
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -0800983 pc = calculate_pc(chip, ocv_uv, chip->last_ocv_temp);
Xiaozhe Shie118c692012-09-24 15:17:43 -0700984 pr_debug("ocv_uv = %d pc = %d\n", ocv_uv, pc);
985 return (fcc_uah * pc) / 100;
986}
987
Xiaozhe Shie118c692012-09-24 15:17:43 -0700988#define CC_READING_TICKS 56
989#define SLEEP_CLK_HZ 32764
990#define SECONDS_PER_HOUR 3600
991
Xiaozhe Shia9b597d2013-02-12 11:00:39 -0800992static s64 cc_uv_to_pvh(s64 cc_uv)
Xiaozhe Shie118c692012-09-24 15:17:43 -0700993{
Xiaozhe Shia9b597d2013-02-12 11:00:39 -0800994 /* Note that it is necessary need to multiply by 1000000 to convert
995 * from uvh to pvh here.
996 * However, the maximum Coulomb Counter value is 2^35, which can cause
997 * an over flow.
998 * Multiply by 100000 first to perserve as much precision as possible
999 * then multiply by 10 after doing the division in order to avoid
1000 * overflow on the maximum Coulomb Counter value.
1001 */
1002 return div_s64(cc_uv * CC_READING_TICKS * 100000,
1003 SLEEP_CLK_HZ * SECONDS_PER_HOUR) * 10;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001004}
1005
1006/**
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07001007 * calculate_cc() - converts a hardware coulomb counter reading into uah
Xiaozhe Shie118c692012-09-24 15:17:43 -07001008 * @chip: the bms chip pointer
1009 * @cc: the cc reading from bms h/w
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001010 * @cc_type: calcualte cc from regular or shadow coulomb counter
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07001011 * @clear_cc: whether this function should clear the hardware counter
1012 * after reading
Xiaozhe Shie118c692012-09-24 15:17:43 -07001013 *
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07001014 * Converts the 64 bit hardware coulomb counter into microamp-hour by taking
1015 * into account hardware resolution and adc errors.
1016 *
1017 * Return: the coulomb counter based charge in uAh (micro-amp hour)
Xiaozhe Shie118c692012-09-24 15:17:43 -07001018 */
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001019static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc,
1020 int cc_type, int clear_cc)
Xiaozhe Shie118c692012-09-24 15:17:43 -07001021{
Xiaozhe Shi4e376652012-10-25 12:38:50 -07001022 struct qpnp_iadc_calib calibration;
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07001023 struct qpnp_vadc_result result;
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001024 int64_t cc_voltage_uv, cc_pvh, cc_uah, *software_counter;
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07001025 int rc;
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07001026
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001027 software_counter = cc_type == SHDW_CC ?
1028 &chip->software_shdw_cc_uah : &chip->software_cc_uah;
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07001029 rc = qpnp_vadc_read(DIE_TEMP, &result);
1030 if (rc) {
1031 pr_err("could not read pmic die temperature: %d\n", rc);
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001032 return *software_counter;
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07001033 }
1034
Xiaozhe Shi4e376652012-10-25 12:38:50 -07001035 qpnp_iadc_get_gain_and_offset(&calibration);
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001036 pr_debug("%scc = %lld, die_temp = %lld\n",
1037 cc_type == SHDW_CC ? "shdw_" : "",
1038 cc, result.physical);
Xiaozhe Shi8f5dd1b2013-04-30 10:27:58 -07001039 cc_voltage_uv = cc_reading_to_uv(cc);
Xiaozhe Shi0c484932013-02-05 16:14:10 -08001040 cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
1041 calibration.gain_raw
1042 - calibration.offset_raw);
Xiaozhe Shia9b597d2013-02-12 11:00:39 -08001043 cc_pvh = cc_uv_to_pvh(cc_voltage_uv);
Xiaozhe Shia9b597d2013-02-12 11:00:39 -08001044 cc_uah = div_s64(cc_pvh, chip->r_sense_uohm);
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07001045 rc = qpnp_iadc_comp_result(&cc_uah);
1046 if (rc)
1047 pr_debug("error compensation failed: %d\n", rc);
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001048 if (clear_cc == RESET) {
1049 pr_debug("software_%scc = %lld, added cc_uah = %lld\n",
1050 cc_type == SHDW_CC ? "sw_" : "",
1051 *software_counter, cc_uah);
1052 *software_counter += cc_uah;
1053 reset_cc(chip, cc_type == SHDW_CC ? CLEAR_SHDW_CC : CLEAR_CC);
1054 return (int)*software_counter;
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07001055 } else {
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001056 pr_debug("software_%scc = %lld, cc_uah = %lld, total = %lld\n",
1057 cc_type == SHDW_CC ? "shdw_" : "",
1058 *software_counter, cc_uah,
1059 *software_counter + cc_uah);
1060 return *software_counter + cc_uah;
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07001061 }
Xiaozhe Shie118c692012-09-24 15:17:43 -07001062}
1063
1064static int get_rbatt(struct qpnp_bms_chip *chip,
1065 int soc_rbatt_mohm, int batt_temp)
1066{
1067 int rbatt_mohm, scalefactor;
1068
1069 rbatt_mohm = chip->default_rbatt_mohm;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001070 if (chip->rbatt_sf_lut == NULL) {
1071 pr_debug("RBATT = %d\n", rbatt_mohm);
1072 return rbatt_mohm;
1073 }
1074 /* Convert the batt_temp to DegC from deciDegC */
1075 batt_temp = batt_temp / 10;
1076 scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
1077 batt_temp, soc_rbatt_mohm);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001078 rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
1079
1080 rbatt_mohm += chip->r_conn_mohm;
Xiaozhe Shi1a10aff2013-04-01 15:40:05 -07001081 rbatt_mohm += chip->rbatt_capacitive_mohm;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001082 return rbatt_mohm;
1083}
1084
Xiaozhe Shi06b67cc2013-03-29 12:07:40 -07001085#define IAVG_MINIMAL_TIME 2
Xiaozhe Shie118c692012-09-24 15:17:43 -07001086static void calculate_iavg(struct qpnp_bms_chip *chip, int cc_uah,
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001087 int *iavg_ua, int delta_time_s)
Xiaozhe Shie118c692012-09-24 15:17:43 -07001088{
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001089 int delta_cc_uah = 0;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001090
Xiaozhe Shi06b67cc2013-03-29 12:07:40 -07001091 /*
1092 * use the battery current if called too quickly
1093 */
1094 if (delta_time_s < IAVG_MINIMAL_TIME
1095 || chip->last_cc_uah == INT_MIN) {
Xiaozhe Shie118c692012-09-24 15:17:43 -07001096 get_battery_current(chip, iavg_ua);
1097 goto out;
1098 }
1099
Xiaozhe Shie118c692012-09-24 15:17:43 -07001100 delta_cc_uah = cc_uah - chip->last_cc_uah;
1101
1102 *iavg_ua = div_s64((s64)delta_cc_uah * 3600, delta_time_s);
1103
Xiaozhe Shie118c692012-09-24 15:17:43 -07001104out:
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001105 pr_debug("delta_cc = %d iavg_ua = %d\n", delta_cc_uah, (int)*iavg_ua);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001106
1107 /* remember cc_uah */
1108 chip->last_cc_uah = cc_uah;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001109}
1110
1111static int calculate_termination_uuc(struct qpnp_bms_chip *chip,
1112 struct soc_params *params,
1113 int batt_temp, int uuc_iavg_ma,
1114 int *ret_pc_unusable)
1115{
1116 int unusable_uv, pc_unusable, uuc_uah;
1117 int i = 0;
1118 int ocv_mv;
1119 int batt_temp_degc = batt_temp / 10;
1120 int rbatt_mohm;
1121 int delta_uv;
1122 int prev_delta_uv = 0;
1123 int prev_rbatt_mohm = 0;
1124 int uuc_rbatt_mohm;
1125
1126 for (i = 0; i <= 100; i++) {
1127 ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
1128 batt_temp_degc, i);
1129 rbatt_mohm = get_rbatt(chip, i, batt_temp);
1130 unusable_uv = (rbatt_mohm * uuc_iavg_ma)
1131 + (chip->v_cutoff_uv);
1132 delta_uv = ocv_mv * 1000 - unusable_uv;
1133
Xiaozhe Shie118c692012-09-24 15:17:43 -07001134 if (delta_uv > 0)
1135 break;
1136
1137 prev_delta_uv = delta_uv;
1138 prev_rbatt_mohm = rbatt_mohm;
1139 }
1140
1141 uuc_rbatt_mohm = linear_interpolate(rbatt_mohm, delta_uv,
1142 prev_rbatt_mohm, prev_delta_uv,
1143 0);
1144
1145 unusable_uv = (uuc_rbatt_mohm * uuc_iavg_ma) + (chip->v_cutoff_uv);
1146
1147 pc_unusable = calculate_pc(chip, unusable_uv, batt_temp);
1148 uuc_uah = (params->fcc_uah * pc_unusable) / 100;
Xiaozhe Shi794607c2013-02-19 10:25:59 -08001149 pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d rbatt_pc = %d uuc = %d\n",
Xiaozhe Shie118c692012-09-24 15:17:43 -07001150 uuc_iavg_ma,
1151 uuc_rbatt_mohm, unusable_uv,
Xiaozhe Shi794607c2013-02-19 10:25:59 -08001152 pc_unusable, i, uuc_uah);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001153 *ret_pc_unusable = pc_unusable;
1154 return uuc_uah;
1155}
1156
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001157#define TIME_PER_PERCENT_UUC 60
Xiaozhe Shie118c692012-09-24 15:17:43 -07001158static int adjust_uuc(struct qpnp_bms_chip *chip,
1159 struct soc_params *params,
1160 int new_pc_unusable,
1161 int new_uuc_uah,
1162 int batt_temp)
1163{
1164 int new_unusable_mv, new_iavg_ma;
1165 int batt_temp_degc = batt_temp / 10;
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001166 int max_percent_change;
1167
1168 max_percent_change = max(params->delta_time_s
1169 / TIME_PER_PERCENT_UUC, 1);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001170
1171 if (chip->prev_pc_unusable == -EINVAL
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001172 || abs(chip->prev_pc_unusable - new_pc_unusable)
1173 <= max_percent_change) {
Xiaozhe Shie118c692012-09-24 15:17:43 -07001174 chip->prev_pc_unusable = new_pc_unusable;
1175 return new_uuc_uah;
1176 }
1177
1178 /* the uuc is trying to change more than 1% restrict it */
1179 if (new_pc_unusable > chip->prev_pc_unusable)
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001180 chip->prev_pc_unusable += max_percent_change;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001181 else
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001182 chip->prev_pc_unusable -= max_percent_change;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001183
1184 new_uuc_uah = (params->fcc_uah * chip->prev_pc_unusable) / 100;
1185
1186 /* also find update the iavg_ma accordingly */
1187 new_unusable_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
1188 batt_temp_degc, chip->prev_pc_unusable);
1189 if (new_unusable_mv < chip->v_cutoff_uv/1000)
1190 new_unusable_mv = chip->v_cutoff_uv/1000;
1191
1192 new_iavg_ma = (new_unusable_mv * 1000 - chip->v_cutoff_uv)
Xiaozhe Shi904f1f72012-12-04 12:47:21 -08001193 / params->rbatt_mohm;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001194 if (new_iavg_ma == 0)
1195 new_iavg_ma = 1;
1196 chip->prev_uuc_iavg_ma = new_iavg_ma;
1197 pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
1198 new_uuc_uah, chip->prev_pc_unusable,
1199 new_unusable_mv, new_iavg_ma);
1200
1201 return new_uuc_uah;
1202}
1203
Abhijeet Dharmapurikarbdf8ba82012-12-20 18:33:56 -08001204#define MIN_IAVG_MA 250
Xiaozhe Shie118c692012-09-24 15:17:43 -07001205#define MIN_SECONDS_FOR_VALID_SAMPLE 20
1206static int calculate_unusable_charge_uah(struct qpnp_bms_chip *chip,
1207 struct soc_params *params,
1208 int batt_temp)
1209{
1210 int uuc_uah_iavg;
1211 int i;
1212 int uuc_iavg_ma = params->iavg_ua / 1000;
1213 int pc_unusable;
1214
1215 /*
1216 * if called first time, fill all the samples with
1217 * the shutdown_iavg_ma
1218 */
1219 if (chip->first_time_calc_uuc && chip->shutdown_iavg_ma != 0) {
1220 pr_debug("Using shutdown_iavg_ma = %d in all samples\n",
1221 chip->shutdown_iavg_ma);
1222 for (i = 0; i < IAVG_SAMPLES; i++)
1223 chip->iavg_samples_ma[i] = chip->shutdown_iavg_ma;
1224
1225 chip->iavg_index = 0;
1226 chip->iavg_num_samples = IAVG_SAMPLES;
1227 }
1228
1229 /*
1230 * if charging use a nominal avg current to keep
1231 * a reasonable UUC while charging
1232 */
Abhijeet Dharmapurikarbdf8ba82012-12-20 18:33:56 -08001233 if (uuc_iavg_ma < MIN_IAVG_MA)
1234 uuc_iavg_ma = MIN_IAVG_MA;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001235 chip->iavg_samples_ma[chip->iavg_index] = uuc_iavg_ma;
1236 chip->iavg_index = (chip->iavg_index + 1) % IAVG_SAMPLES;
1237 chip->iavg_num_samples++;
1238 if (chip->iavg_num_samples >= IAVG_SAMPLES)
1239 chip->iavg_num_samples = IAVG_SAMPLES;
1240
1241 /* now that this sample is added calcualte the average */
1242 uuc_iavg_ma = 0;
1243 if (chip->iavg_num_samples != 0) {
1244 for (i = 0; i < chip->iavg_num_samples; i++) {
1245 pr_debug("iavg_samples_ma[%d] = %d\n", i,
1246 chip->iavg_samples_ma[i]);
1247 uuc_iavg_ma += chip->iavg_samples_ma[i];
1248 }
1249
1250 uuc_iavg_ma = DIV_ROUND_CLOSEST(uuc_iavg_ma,
1251 chip->iavg_num_samples);
1252 }
1253
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001254 /*
1255 * if we're in bms reset mode, force uuc to be 3% of fcc
1256 */
1257 if (bms_reset)
1258 return (params->fcc_uah * 3) / 100;
1259
Xiaozhe Shi75e5efe2013-02-07 09:51:43 -08001260 uuc_uah_iavg = calculate_termination_uuc(chip, params, batt_temp,
1261 uuc_iavg_ma, &pc_unusable);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001262 pr_debug("uuc_iavg_ma = %d uuc with iavg = %d\n",
1263 uuc_iavg_ma, uuc_uah_iavg);
1264
1265 chip->prev_uuc_iavg_ma = uuc_iavg_ma;
1266 /* restrict the uuc such that it can increase only by one percent */
1267 uuc_uah_iavg = adjust_uuc(chip, params, pc_unusable,
1268 uuc_uah_iavg, batt_temp);
1269
1270 chip->first_time_calc_uuc = 0;
1271 return uuc_uah_iavg;
1272}
1273
1274static void find_ocv_for_soc(struct qpnp_bms_chip *chip,
1275 struct soc_params *params,
1276 int batt_temp,
1277 int shutdown_soc,
1278 int *ret_ocv_uv)
1279{
1280 s64 ocv_charge_uah;
1281 int pc, new_pc;
1282 int batt_temp_degc = batt_temp / 10;
1283 int ocv_uv;
1284
1285 ocv_charge_uah = (s64)shutdown_soc
1286 * (params->fcc_uah - params->uuc_uah);
1287 ocv_charge_uah = div_s64(ocv_charge_uah, 100)
1288 + params->cc_uah + params->uuc_uah;
1289 pc = DIV_ROUND_CLOSEST((int)ocv_charge_uah * 100, params->fcc_uah);
1290 pc = clamp(pc, 0, 100);
1291
1292 ocv_uv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
1293
1294 pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
1295 shutdown_soc, params->fcc_uah,
1296 params->uuc_uah, (int)ocv_charge_uah,
1297 pc, ocv_uv);
1298 new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_uv);
1299 pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_uv);
1300
1301 while (abs(new_pc - pc) > 1) {
1302 int delta_mv = 5;
1303
1304 if (new_pc > pc)
1305 delta_mv = -1 * delta_mv;
1306
1307 ocv_uv = ocv_uv + delta_mv;
1308 new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
1309 batt_temp_degc, ocv_uv);
1310 pr_debug("test revlookup pc = %d for ocv = %d\n",
1311 new_pc, ocv_uv);
1312 }
1313
1314 *ret_ocv_uv = ocv_uv * 1000;
1315 params->ocv_charge_uah = (int)ocv_charge_uah;
1316}
1317
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001318static int get_current_time(unsigned long *now_tm_sec)
1319{
1320 struct rtc_time tm;
1321 struct rtc_device *rtc;
1322 int rc;
1323
1324 rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
1325 if (rtc == NULL) {
1326 pr_err("%s: unable to open rtc device (%s)\n",
1327 __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
Xiaozhe Shi0e01af62013-05-06 12:56:08 -07001328 return -EINVAL;
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001329 }
1330
1331 rc = rtc_read_time(rtc, &tm);
1332 if (rc) {
1333 pr_err("Error reading rtc device (%s) : %d\n",
1334 CONFIG_RTC_HCTOSYS_DEVICE, rc);
1335 goto close_time;
1336 }
1337
1338 rc = rtc_valid_tm(&tm);
1339 if (rc) {
1340 pr_err("Invalid RTC time (%s): %d\n",
1341 CONFIG_RTC_HCTOSYS_DEVICE, rc);
1342 goto close_time;
1343 }
1344 rtc_tm_to_time(&tm, now_tm_sec);
1345
1346close_time:
1347 rtc_class_close(rtc);
1348 return rc;
1349}
1350
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08001351/* Returns estimated battery resistance */
1352static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
1353{
1354 return chip->rbatt_mohm * 1000;
1355}
1356
1357/* Returns instantaneous current in uA */
1358static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
1359{
1360 int rc, result_ua;
1361
1362 rc = get_battery_current(chip, &result_ua);
1363 if (rc) {
1364 pr_err("failed to get current: %d\n", rc);
1365 return rc;
1366 }
1367 return result_ua;
1368}
1369
1370/* Returns coulomb counter in uAh */
1371static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
1372{
1373 int64_t cc_raw;
1374
1375 mutex_lock(&chip->bms_output_lock);
1376 lock_output_data(chip);
1377 read_cc_raw(chip, &cc_raw, false);
1378 unlock_output_data(chip);
1379 mutex_unlock(&chip->bms_output_lock);
1380
1381 return calculate_cc(chip, cc_raw, CC, NORESET);
1382}
1383
1384/* Returns shadow coulomb counter in uAh */
1385static int get_prop_bms_charge_counter_shadow(struct qpnp_bms_chip *chip)
1386{
1387 int64_t cc_raw;
1388
1389 mutex_lock(&chip->bms_output_lock);
1390 lock_output_data(chip);
1391 read_cc_raw(chip, &cc_raw, true);
1392 unlock_output_data(chip);
1393 mutex_unlock(&chip->bms_output_lock);
1394
1395 return calculate_cc(chip, cc_raw, SHDW_CC, NORESET);
1396}
1397
1398/* Returns full charge design in uAh */
1399static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
1400{
1401 return chip->fcc_mah * 1000;
1402}
1403
Anirudh Ghayalc9d981a2013-06-24 09:50:33 +05301404/* Returns the current full charge in uAh */
1405static int get_prop_bms_charge_full(struct qpnp_bms_chip *chip)
1406{
1407 int rc;
1408 struct qpnp_vadc_result result;
1409
1410 rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
1411 if (rc) {
1412 pr_err("Unable to read battery temperature\n");
1413 return rc;
1414 }
1415
1416 return calculate_fcc(chip, (int)result.physical);
1417}
1418
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001419static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s)
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001420{
1421 unsigned long now_tm_sec = 0;
1422
1423 /* default to delta time = 0 if anything fails */
1424 *delta_time_s = 0;
1425
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001426 if (get_current_time(&now_tm_sec)) {
1427 pr_err("RTC read failed\n");
1428 return 0;
1429 }
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001430
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001431 *delta_time_s = (now_tm_sec - *time_stamp);
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001432
1433 /* remember this time */
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001434 *time_stamp = now_tm_sec;
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001435 return 0;
1436}
1437
Xiaozhe Shie118c692012-09-24 15:17:43 -07001438static void calculate_soc_params(struct qpnp_bms_chip *chip,
1439 struct raw_soc_params *raw,
1440 struct soc_params *params,
1441 int batt_temp)
1442{
Xiaozhe Shi219cb222013-06-10 15:49:59 -07001443 int soc_rbatt, shdw_cc_uah;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001444
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001445 calculate_delta_time(&chip->tm_sec, &params->delta_time_s);
1446 pr_debug("tm_sec = %ld, delta_s = %d\n",
1447 chip->tm_sec, params->delta_time_s);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001448 params->fcc_uah = calculate_fcc(chip, batt_temp);
1449 pr_debug("FCC = %uuAh batt_temp = %d\n", params->fcc_uah, batt_temp);
1450
1451 /* calculate remainging charge */
1452 params->ocv_charge_uah = calculate_ocv_charge(
1453 chip, raw,
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -08001454 params->fcc_uah);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001455 pr_debug("ocv_charge_uah = %uuAh\n", params->ocv_charge_uah);
1456
1457 /* calculate cc micro_volt_hour */
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001458 params->cc_uah = calculate_cc(chip, raw->cc, CC, RESET);
Xiaozhe Shi219cb222013-06-10 15:49:59 -07001459 shdw_cc_uah = calculate_cc(chip, raw->shdw_cc, SHDW_CC, RESET);
1460 pr_debug("cc_uah = %duAh raw->cc = %llx, shdw_cc_uah = %duAh raw->shdw_cc = %llx\n",
1461 params->cc_uah, raw->cc,
1462 shdw_cc_uah, raw->shdw_cc);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001463
1464 soc_rbatt = ((params->ocv_charge_uah - params->cc_uah) * 100)
1465 / params->fcc_uah;
1466 if (soc_rbatt < 0)
1467 soc_rbatt = 0;
Xiaozhe Shi904f1f72012-12-04 12:47:21 -08001468 params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
Xiaozhe Shi794607c2013-02-19 10:25:59 -08001469 pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001470
Xiaozhe Shi1e87cda2013-05-17 10:18:56 -07001471 if (params->rbatt_mohm != chip->rbatt_mohm) {
Xiaozhe Shi6dc56f12013-05-02 15:56:55 -07001472 chip->rbatt_mohm = params->rbatt_mohm;
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -07001473 if (chip->bms_psy_registered)
Xiaozhe Shi1e87cda2013-05-17 10:18:56 -07001474 power_supply_changed(&chip->bms_psy);
Xiaozhe Shi6dc56f12013-05-02 15:56:55 -07001475 }
1476
Xiaozhe Shif36d2862013-01-04 10:17:35 -08001477 calculate_iavg(chip, params->cc_uah, &params->iavg_ua,
1478 params->delta_time_s);
Xiaozhe Shie118c692012-09-24 15:17:43 -07001479
1480 params->uuc_uah = calculate_unusable_charge_uah(chip, params,
1481 batt_temp);
1482 pr_debug("UUC = %uuAh\n", params->uuc_uah);
1483}
1484
1485static bool is_shutdown_soc_within_limits(struct qpnp_bms_chip *chip, int soc)
1486{
1487 if (chip->shutdown_soc_invalid) {
1488 pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
1489 return 0;
1490 }
1491
1492 if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
1493 pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
1494 chip->shutdown_soc, soc,
1495 chip->shutdown_soc_valid_limit);
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08001496 chip->shutdown_soc_invalid = true;
Xiaozhe Shie118c692012-09-24 15:17:43 -07001497 return 0;
1498 }
1499
1500 return 1;
1501}
1502
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001503static int bound_soc(int soc)
1504{
1505 soc = max(0, soc);
1506 soc = min(100, soc);
1507 return soc;
1508}
1509
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001510#define IBAT_TOL_MASK 0x0F
1511#define OCV_TOL_MASK 0xF0
1512#define IBAT_TOL_DEFAULT 0x03
1513#define IBAT_TOL_NOCHG 0x0F
1514#define OCV_TOL_DEFAULT 0x20
1515#define OCV_TOL_NO_OCV 0x00
1516static int stop_ocv_updates(struct qpnp_bms_chip *chip)
1517{
1518 pr_debug("stopping ocv updates\n");
1519 return qpnp_masked_write(chip, BMS1_TOL_CTL,
1520 OCV_TOL_MASK, OCV_TOL_NO_OCV);
1521}
1522
1523static int reset_bms_for_test(struct qpnp_bms_chip *chip)
1524{
Xiaozhe Shi95da77f2013-02-20 13:40:06 -08001525 int ibat_ua = 0, vbat_uv = 0, rc;
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001526 int ocv_est_uv;
1527
1528 if (!chip) {
1529 pr_err("BMS driver has not been initialized yet!\n");
1530 return -EINVAL;
1531 }
1532
1533 rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
1534
Xiaozhe Shi1a10aff2013-04-01 15:40:05 -07001535 /*
1536 * Don't include rbatt and rbatt_capacitative since we expect this to
1537 * be used with a fake battery which does not have internal resistances
1538 */
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001539 ocv_est_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
1540 pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
1541 chip->last_ocv_uv = ocv_est_uv;
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001542 mutex_lock(&chip->last_soc_mutex);
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001543 chip->last_soc = -EINVAL;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08001544 chip->last_soc_invalid = true;
Xiaozhe Shi04da0992013-04-26 16:32:14 -07001545 mutex_unlock(&chip->last_soc_mutex);
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001546 reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07001547 chip->software_cc_uah = 0;
Xiaozhe Shif3da8622013-06-10 14:50:56 -07001548 chip->software_shdw_cc_uah = 0;
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001549 chip->last_cc_uah = INT_MIN;
1550 stop_ocv_updates(chip);
1551
1552 pr_debug("bms reset to ocv = %duv vbat_ua = %d ibat_ua = %d\n",
1553 chip->last_ocv_uv, vbat_uv, ibat_ua);
1554
1555 return rc;
1556}
1557
1558static int bms_reset_set(const char *val, const struct kernel_param *kp)
1559{
1560 int rc;
1561
1562 rc = param_set_bool(val, kp);
1563 if (rc) {
1564 pr_err("Unable to set bms_reset: %d\n", rc);
1565 return rc;
1566 }
1567
1568 if (*(bool *)kp->arg) {
1569 struct power_supply *bms_psy = power_supply_get_by_name("bms");
1570 struct qpnp_bms_chip *chip = container_of(bms_psy,
1571 struct qpnp_bms_chip, bms_psy);
1572
1573 rc = reset_bms_for_test(chip);
1574 if (rc) {
1575 pr_err("Unable to modify bms_reset: %d\n", rc);
1576 return rc;
1577 }
1578 }
1579 return 0;
1580}
1581
1582static struct kernel_param_ops bms_reset_ops = {
1583 .set = bms_reset_set,
1584 .get = param_get_bool,
1585};
1586
1587module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
1588
Xiaozhe Shi83484e32013-05-16 10:59:59 -07001589static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
1590 int soc)
1591{
1592 u8 temp;
1593 int rc;
1594 int iavg_ma = chip->prev_uuc_iavg_ma;
1595
1596 if (iavg_ma > IAVG_START)
1597 temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
1598 else
1599 temp = 0;
1600
1601 rc = qpnp_write_wrapper(chip, &temp,
1602 chip->base + IAVG_STORAGE_REG, 1);
1603
1604 temp = soc;
1605
1606 /* don't store soc if temperature is below 5degC */
1607 if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
1608 rc = qpnp_write_wrapper(chip, &temp,
1609 chip->base + SOC_STORAGE_REG, 1);
1610}
1611
1612static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
1613 int catch_up_sec, int new_soc, int prev_soc)
1614{
1615 int scaled_soc;
1616 int numerator;
1617
1618 /*
1619 * Don't report a high value immediately slowly scale the
1620 * value from prev_soc to the new soc based on a charge time
1621 * weighted average
1622 */
1623 pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
1624 if (catch_up_sec == 0)
1625 return new_soc;
1626
1627 if (chg_time_sec > catch_up_sec)
1628 return new_soc;
1629
1630 numerator = (catch_up_sec - chg_time_sec) * prev_soc
1631 + chg_time_sec * new_soc;
1632 scaled_soc = numerator / catch_up_sec;
1633
1634 pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
1635 chg_time_sec, new_soc, prev_soc, scaled_soc);
1636
1637 return scaled_soc;
1638}
1639
1640/*
1641 * bms_fake_battery is set in setups where a battery emulator is used instead
1642 * of a real battery. This makes the bms driver report a different/fake value
1643 * regardless of the calculated state of charge.
1644 */
1645static int bms_fake_battery = -EINVAL;
1646module_param(bms_fake_battery, int, 0644);
1647
1648static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
1649{
1650 pr_debug("Reported voltage based soc = %d\n",
1651 chip->prev_voltage_based_soc);
1652 return chip->prev_voltage_based_soc;
1653}
1654
1655#define SOC_CATCHUP_SEC_MAX 600
1656#define SOC_CATCHUP_SEC_PER_PERCENT 60
1657#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT)
Xiaozhe Shie7fafe62013-06-05 15:25:16 -07001658#define SOC_CHANGE_PER_SEC 5
Xiaozhe Shi83484e32013-05-16 10:59:59 -07001659static int report_cc_based_soc(struct qpnp_bms_chip *chip)
1660{
1661 int soc, soc_change;
1662 int time_since_last_change_sec, charge_time_sec = 0;
1663 unsigned long last_change_sec;
1664 struct timespec now;
1665 struct qpnp_vadc_result result;
1666 int batt_temp;
1667 int rc;
1668 bool charging, charging_since_last_report;
1669
Xiaozhe Shi83484e32013-05-16 10:59:59 -07001670 rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
1671
1672 if (rc) {
1673 pr_err("error reading adc channel = %d, rc = %d\n",
1674 LR_MUX1_BATT_THERM, rc);
1675 return rc;
1676 }
1677 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1678 result.measurement);
1679 batt_temp = (int)result.physical;
1680
1681 mutex_lock(&chip->last_soc_mutex);
Xiaozhe Shifa6ea692013-05-31 11:15:13 -07001682 soc = chip->calculated_soc;
1683
Xiaozhe Shi83484e32013-05-16 10:59:59 -07001684 last_change_sec = chip->last_soc_change_sec;
1685 calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
1686
1687 charging = is_battery_charging(chip);
1688 charging_since_last_report = charging || (chip->last_soc_unbound
1689 && chip->was_charging_at_sleep);
1690 /*
1691 * account for charge time - limit it to SOC_CATCHUP_SEC to
1692 * avoid overflows when charging continues for extended periods
1693 */
1694 if (charging) {
1695 if (chip->charge_start_tm_sec == 0) {
1696 /*
1697 * calculating soc for the first time
1698 * after start of chg. Initialize catchup time
1699 */
1700 if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
1701 chip->catch_up_time_sec =
1702 (soc - chip->last_soc)
1703 * SOC_CATCHUP_SEC_PER_PERCENT;
1704 else
1705 chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
1706
1707 if (chip->catch_up_time_sec < 0)
1708 chip->catch_up_time_sec = 0;
1709 chip->charge_start_tm_sec = last_change_sec;
1710 }
1711
1712 charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
1713 - chip->charge_start_tm_sec);
1714
1715 /* end catchup if calculated soc and last soc are same */
1716 if (chip->last_soc == soc)
1717 chip->catch_up_time_sec = 0;
1718 }
1719
1720 if (chip->last_soc != -EINVAL) {
1721 /*
1722 * last_soc < soc ... if we have not been charging at all
1723 * since the last time this was called, report previous SoC.
1724 * Otherwise, scale and catch up.
1725 */
1726 if (chip->last_soc < soc && !charging_since_last_report)
1727 soc = chip->last_soc;
1728 else if (chip->last_soc < soc && soc != 100)
1729 soc = scale_soc_while_chg(chip, charge_time_sec,
1730 chip->catch_up_time_sec,
1731 soc, chip->last_soc);
1732
1733 soc_change = min((int)abs(chip->last_soc - soc),
1734 time_since_last_change_sec / SOC_CHANGE_PER_SEC);
1735 if (chip->last_soc_unbound) {
1736 chip->last_soc_unbound = false;
1737 } else {
1738 /*
1739 * if soc have not been unbound by resume,
1740 * only change reported SoC by 1.
1741 */
1742 soc_change = min(1, soc_change);
1743 }
1744
1745 if (soc < chip->last_soc && soc != 0)
1746 soc = chip->last_soc - soc_change;
1747 if (soc > chip->last_soc && soc != 100)
1748 soc = chip->last_soc + soc_change;
1749 }
1750
Xiaozhe Shi208b8e52013-05-28 10:16:32 -07001751 if (chip->last_soc != soc && !chip->last_soc_unbound)
Xiaozhe Shi83484e32013-05-16 10:59:59 -07001752 chip->last_soc_change_sec = last_change_sec;
1753
1754 pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
1755 chip->last_soc, chip->calculated_soc,
1756 soc, time_since_last_change_sec);
1757 chip->last_soc = bound_soc(soc);
1758 backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
1759 pr_debug("Reported SOC = %d\n", chip->last_soc);
1760 chip->t_soc_queried = now;
1761 mutex_unlock(&chip->last_soc_mutex);
1762
1763 return soc;
1764}
1765
1766static int report_state_of_charge(struct qpnp_bms_chip *chip)
1767{
1768 if (bms_fake_battery != -EINVAL) {
1769 pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
1770 return bms_fake_battery;
1771 } else if (chip->use_voltage_soc)
1772 return report_voltage_based_soc(chip);
1773 else
1774 return report_cc_based_soc(chip);
1775}
1776
Xiaozhe Shieabcebf2013-05-28 10:41:09 -07001777#define VDD_MAX_ERR 5000
1778#define VDD_STEP_SIZE 10000
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001779static int charging_adjustments(struct qpnp_bms_chip *chip,
1780 struct soc_params *params, int soc,
1781 int vbat_uv, int ibat_ua, int batt_temp)
1782{
Xiaozhe Shifd98ddf2013-05-20 15:20:19 -07001783 int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
Xiaozhe Shia6618a22013-03-27 10:26:29 -07001784
Xiaozhe Shieabcebf2013-05-28 10:41:09 -07001785 batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001786
1787 if (chip->soc_at_cv == -EINVAL) {
Xiaozhe Shieabcebf2013-05-28 10:41:09 -07001788 if (batt_terminal_uv >= chip->max_voltage_uv - VDD_MAX_ERR) {
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001789 chip->soc_at_cv = soc;
1790 chip->prev_chg_soc = soc;
1791 chip->ibat_at_cv_ua = ibat_ua;
1792 pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
1793 ibat_ua, soc);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07001794 } else {
1795 /* In constant current charging return the calc soc */
1796 pr_debug("CC CHG SOC %d\n", soc);
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001797 }
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -08001798
1799 chip->prev_batt_terminal_uv = batt_terminal_uv;
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001800 return soc;
1801 }
1802
1803 /*
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -08001804 * battery is in CV phase - begin linear interpolation of soc based on
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001805 * battery charge current
1806 */
1807
1808 /*
1809 * if voltage lessened (possibly because of a system load)
1810 * keep reporting the prev chg soc
1811 */
Xiaozhe Shieabcebf2013-05-28 10:41:09 -07001812 if (batt_terminal_uv <= chip->prev_batt_terminal_uv - VDD_STEP_SIZE) {
Abhijeet Dharmapurikareef88662012-11-08 17:26:29 -08001813 pr_debug("batt_terminal_uv %d < (max = %d - 10000); CC CHG SOC %d\n",
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -08001814 batt_terminal_uv, chip->prev_batt_terminal_uv,
1815 chip->prev_chg_soc);
1816 chip->prev_batt_terminal_uv = batt_terminal_uv;
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001817 return chip->prev_chg_soc;
1818 }
1819
Xiaozhe Shifd98ddf2013-05-20 15:20:19 -07001820 soc_ibat = bound_soc(linear_interpolate(chip->soc_at_cv,
1821 chip->ibat_at_cv_ua,
Abhijeet Dharmapurikareef88662012-11-08 17:26:29 -08001822 100, -1 * chip->chg_term_ua,
Xiaozhe Shifd98ddf2013-05-20 15:20:19 -07001823 ibat_ua));
1824 weight_ibat = bound_soc(linear_interpolate(1, chip->soc_at_cv,
1825 100, 100, chip->prev_chg_soc));
1826 weight_cc = 100 - weight_ibat;
Xiaozhe Shieabcebf2013-05-28 10:41:09 -07001827 chg_soc = bound_soc(DIV_ROUND_CLOSEST(soc_ibat * weight_ibat
1828 + weight_cc * soc, 100));
1829
Xiaozhe Shifd98ddf2013-05-20 15:20:19 -07001830 pr_debug("weight_ibat = %d, weight_cc = %d, soc_ibat = %d, soc_cc = %d\n",
1831 weight_ibat, weight_cc, soc_ibat, soc);
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001832
1833 /* always report a higher soc */
1834 if (chg_soc > chip->prev_chg_soc) {
1835 int new_ocv_uv;
1836
1837 chip->prev_chg_soc = chg_soc;
1838
1839 find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
Xiaozhe Shicc48e992013-05-28 16:42:24 -07001840 chip->charging_adjusted_ocv = new_ocv_uv;
1841 pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n", new_ocv_uv,
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001842 chip->prev_chg_soc);
1843 }
1844
1845 pr_debug("Reporting CHG SOC %d\n", chip->prev_chg_soc);
Xiaozhe Shifc2f5a02013-01-28 15:09:04 -08001846 chip->prev_batt_terminal_uv = batt_terminal_uv;
Xiaozhe Shi41bc1f12012-09-26 16:55:22 -07001847 return chip->prev_chg_soc;
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001848}
1849
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001850static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
1851{
1852 /*
1853 * if battery is very low (v_cutoff voltage + 20mv) hold
1854 * a wakelock untill soc = 0%
1855 */
1856 if (vbat_uv <= chip->low_voltage_threshold
Xiaozhe Shia6618a22013-03-27 10:26:29 -07001857 && !wake_lock_active(&chip->low_voltage_wake_lock)) {
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001858 pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
1859 wake_lock(&chip->low_voltage_wake_lock);
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001860 } else if (vbat_uv > chip->low_voltage_threshold
Xiaozhe Shia6618a22013-03-27 10:26:29 -07001861 && wake_lock_active(&chip->low_voltage_wake_lock)) {
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001862 pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001863 wake_unlock(&chip->low_voltage_wake_lock);
1864 }
1865}
1866
Xiaozhe Shia6618a22013-03-27 10:26:29 -07001867#define VBATT_ERROR_MARGIN 20000
1868static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
1869{
1870 /*
1871 * if battery is very low (v_cutoff voltage + 20mv) hold
1872 * a wakelock untill soc = 0%
1873 */
1874 if (wake_lock_active(&chip->cv_wake_lock)) {
1875 if (chip->soc_at_cv != -EINVAL) {
1876 pr_debug("hit CV, releasing cv wakelock\n");
1877 wake_unlock(&chip->cv_wake_lock);
1878 } else if (!is_battery_charging(chip)) {
1879 pr_debug("charging stopped, releasing cv wakelock\n");
1880 wake_unlock(&chip->cv_wake_lock);
1881 }
1882 } else if (vbat_uv > chip->max_voltage_uv - VBATT_ERROR_MARGIN
1883 && chip->soc_at_cv == -EINVAL
1884 && is_battery_charging(chip)
1885 && !wake_lock_active(&chip->cv_wake_lock)) {
1886 pr_debug("voltage = %d holding cv wakelock\n", vbat_uv);
1887 wake_lock(&chip->cv_wake_lock);
1888 }
1889}
1890
Xiaozhe Shi561ebf72013-03-25 13:51:27 -07001891#define NO_ADJUST_HIGH_SOC_THRESHOLD 90
Xiaozhe Shie118c692012-09-24 15:17:43 -07001892static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
1893 int soc, int batt_temp)
1894{
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001895 int ibat_ua = 0, vbat_uv = 0;
1896 int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
1897 int delta_ocv_uv = 0;
1898 int n = 0;
1899 int rc_new_uah = 0;
1900 int pc_new = 0;
1901 int soc_new = 0;
1902 int slope = 0;
1903 int rc = 0;
1904 int delta_ocv_uv_limit = 0;
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -07001905 int correction_limit_uv = 0;
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001906
1907 rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
1908 if (rc < 0) {
1909 pr_err("simultaneous vbat ibat failed err = %d\n", rc);
1910 goto out;
1911 }
1912
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001913 very_low_voltage_check(chip, vbat_uv);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07001914 cv_voltage_check(chip, vbat_uv);
Xiaozhe Shi4be85782013-02-22 17:33:40 -08001915
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001916 delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
1917
Xiaozhe Shi904f1f72012-12-04 12:47:21 -08001918 ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
1919
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001920 pc_est = calculate_pc(chip, ocv_est_uv, batt_temp);
1921 soc_est = div_s64((s64)params->fcc_uah * pc_est - params->uuc_uah*100,
1922 (s64)params->fcc_uah - params->uuc_uah);
1923 soc_est = bound_soc(soc_est);
1924
Xiaozhe Shi20640b52013-01-03 11:49:30 -08001925 /* never adjust during bms reset mode */
1926 if (bms_reset) {
1927 pr_debug("bms reset mode, SOC adjustment skipped\n");
1928 goto out;
1929 }
1930
Xiaozhe Shi8658c982013-04-30 11:33:07 -07001931 if (ibat_ua < 0 && !is_battery_full(chip)) {
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001932 soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
1933 batt_temp);
1934 goto out;
1935 }
1936
1937 /*
1938 * do not adjust
Xiaozhe Shi561ebf72013-03-25 13:51:27 -07001939 * if soc_est is same as what bms calculated
1940 * OR if soc_est > adjust_soc_low_threshold
1941 * OR if soc is above 90
1942 * because we might pull it low
1943 * and cause a bad user experience
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001944 */
1945 if (soc_est == soc
Xiaozhe Shi561ebf72013-03-25 13:51:27 -07001946 || soc_est > chip->adjust_soc_low_threshold
1947 || soc >= NO_ADJUST_HIGH_SOC_THRESHOLD)
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001948 goto out;
1949
1950 if (chip->last_soc_est == -EINVAL)
1951 chip->last_soc_est = soc;
1952
1953 n = min(200, max(1 , soc + soc_est + chip->last_soc_est));
1954 chip->last_soc_est = soc_est;
1955
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -08001956 pc = calculate_pc(chip, chip->last_ocv_uv, chip->last_ocv_temp);
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001957 if (pc > 0) {
1958 pc_new = calculate_pc(chip,
1959 chip->last_ocv_uv - (++slope * 1000),
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -08001960 chip->last_ocv_temp);
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001961 while (pc_new == pc) {
1962 /* start taking 10mV steps */
1963 slope = slope + 10;
1964 pc_new = calculate_pc(chip,
1965 chip->last_ocv_uv - (slope * 1000),
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -08001966 chip->last_ocv_temp);
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07001967 }
1968 } else {
1969 /*
1970 * pc is already at the lowest point,
1971 * assume 1 millivolt translates to 1% pc
1972 */
1973 pc = 1;
1974 pc_new = 0;
1975 slope = 1;
1976 }
1977
1978 delta_ocv_uv = div_s64((soc - soc_est) * (s64)slope * 1000,
1979 n * (pc - pc_new));
1980
1981 if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
1982 pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
1983 delta_ocv_uv_limit);
1984
1985 if (delta_ocv_uv > 0)
1986 delta_ocv_uv = delta_ocv_uv_limit;
1987 else
1988 delta_ocv_uv = -1 * delta_ocv_uv_limit;
1989 pr_debug("new delta ocv = %d\n", delta_ocv_uv);
1990 }
1991
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -07001992 if (chip->last_ocv_uv > chip->flat_ocv_threshold_uv)
1993 correction_limit_uv = chip->high_ocv_correction_limit_uv;
1994 else
1995 correction_limit_uv = chip->low_ocv_correction_limit_uv;
1996
1997 if (abs(delta_ocv_uv) > correction_limit_uv) {
1998 pr_debug("limiting delta ocv %d limit = %d\n",
1999 delta_ocv_uv, correction_limit_uv);
2000 if (delta_ocv_uv > 0)
2001 delta_ocv_uv = correction_limit_uv;
2002 else
2003 delta_ocv_uv = -correction_limit_uv;
2004 pr_debug("new delta ocv = %d\n", delta_ocv_uv);
2005 }
2006
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07002007 chip->last_ocv_uv -= delta_ocv_uv;
2008
2009 if (chip->last_ocv_uv >= chip->max_voltage_uv)
2010 chip->last_ocv_uv = chip->max_voltage_uv;
2011
2012 /* calculate the soc based on this new ocv */
Abhijeet Dharmapurikar4b97cdd2012-12-26 21:10:53 -08002013 pc_new = calculate_pc(chip, chip->last_ocv_uv, chip->last_ocv_temp);
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07002014 rc_new_uah = (params->fcc_uah * pc_new) / 100;
2015 soc_new = (rc_new_uah - params->cc_uah - params->uuc_uah)*100
2016 / (params->fcc_uah - params->uuc_uah);
2017 soc_new = bound_soc(soc_new);
2018
2019 /*
2020 * if soc_new is ZERO force it higher so that phone doesnt report soc=0
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -07002021 * soc = 0 should happen only when soc_est is above a set value
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07002022 */
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -07002023 if (soc_new == 0 && soc_est >= chip->hold_soc_est)
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07002024 soc_new = 1;
2025
2026 soc = soc_new;
2027
2028out:
2029 pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, pc_new = %d, soc_new = %d, rbatt = %d, slope = %d\n",
2030 ibat_ua, vbat_uv, ocv_est_uv, pc_est,
2031 soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
Xiaozhe Shi904f1f72012-12-04 12:47:21 -08002032 pc_new, soc_new, params->rbatt_mohm, slope);
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07002033
Xiaozhe Shie118c692012-09-24 15:17:43 -07002034 return soc;
2035}
2036
Xiaozhe Shi2542c602012-11-28 10:08:07 -08002037static int clamp_soc_based_on_voltage(struct qpnp_bms_chip *chip, int soc)
2038{
2039 int rc, vbat_uv;
Xiaozhe Shi2542c602012-11-28 10:08:07 -08002040
Xiaozhe Shi36458962013-02-06 16:19:57 -08002041 rc = get_battery_voltage(&vbat_uv);
2042 if (rc < 0) {
2043 pr_err("adc vbat failed err = %d\n", rc);
2044 return soc;
Xiaozhe Shi2542c602012-11-28 10:08:07 -08002045 }
Xiaozhe Shi2542c602012-11-28 10:08:07 -08002046 if (soc == 0 && vbat_uv > chip->v_cutoff_uv) {
2047 pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
2048 vbat_uv, chip->v_cutoff_uv);
2049 return 1;
Xiaozhe Shi2542c602012-11-28 10:08:07 -08002050 } else {
2051 pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n",
2052 soc, vbat_uv, chip->v_cutoff_uv);
2053 return soc;
2054 }
2055}
2056
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08002057static int64_t convert_cc_uah_to_raw(struct qpnp_bms_chip *chip, int64_t cc_uah)
2058{
2059 int64_t cc_uv, cc_pvh, cc_raw;
2060
2061 cc_pvh = cc_uah * chip->r_sense_uohm;
2062 cc_uv = div_s64(cc_pvh * SLEEP_CLK_HZ * SECONDS_PER_HOUR,
2063 CC_READING_TICKS * 1000000LL);
2064 cc_raw = div_s64(cc_uv * CC_READING_RESOLUTION_D,
2065 CC_READING_RESOLUTION_N);
2066 return cc_raw;
2067}
2068
2069#define CC_STEP_INCREMENT_UAH 1500
2070#define OCV_STEP_INCREMENT 0x10
2071static void configure_soc_wakeup(struct qpnp_bms_chip *chip,
2072 struct soc_params *params,
2073 int batt_temp, int target_soc)
2074{
2075 int target_ocv_uv;
2076 int64_t target_cc_uah, cc_raw_64, current_shdw_cc_raw_64;
2077 int64_t current_shdw_cc_uah, iadc_comp_factor;
2078 uint64_t cc_raw, current_shdw_cc_raw;
2079 int16_t ocv_raw, current_ocv_raw;
2080
2081 current_shdw_cc_raw = 0;
2082 mutex_lock(&chip->bms_output_lock);
2083 lock_output_data(chip);
2084 qpnp_read_wrapper(chip, (u8 *)&current_ocv_raw,
2085 chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
2086 unlock_output_data(chip);
2087 mutex_unlock(&chip->bms_output_lock);
2088 current_shdw_cc_uah = get_prop_bms_charge_counter_shadow(chip);
2089 current_shdw_cc_raw_64 = convert_cc_uah_to_raw(chip,
2090 current_shdw_cc_uah);
2091
2092 /*
2093 * Calculate the target shadow coulomb counter threshold for when
2094 * the SoC changes.
2095 *
2096 * Since the BMS driver resets the shadow coulomb counter every
2097 * 20 seconds when the device is awake, calculate the threshold as
2098 * a delta from the current shadow coulomb count.
2099 */
2100 target_cc_uah = (100 - target_soc)
2101 * (params->fcc_uah - params->uuc_uah)
2102 / 100 - current_shdw_cc_uah;
2103 if (target_cc_uah < 0) {
2104 /*
2105 * If the target cc is below 0, that means we have already
2106 * passed the point where SoC should have fallen.
2107 * Set a wakeup in a few more mAh and check back again
2108 */
2109 target_cc_uah = CC_STEP_INCREMENT_UAH;
2110 }
2111 iadc_comp_factor = 100000;
2112 qpnp_iadc_comp_result(&iadc_comp_factor);
2113 target_cc_uah = div64_s64(target_cc_uah * 100000, iadc_comp_factor);
2114 target_cc_uah = cc_reverse_adjust_for_gain(target_cc_uah);
2115 cc_raw_64 = convert_cc_uah_to_raw(chip, target_cc_uah);
2116 cc_raw = convert_s64_to_s36(cc_raw_64);
2117
2118 find_ocv_for_soc(chip, params, batt_temp, target_soc, &target_ocv_uv);
2119 ocv_raw = convert_vbatt_uv_to_raw(chip, target_ocv_uv);
2120
2121 /*
2122 * If the current_ocv_raw was updated since reaching 100% and is lower
2123 * than the calculated target ocv threshold, set the new target
2124 * threshold 1.5mAh lower in order to check if the SoC changed yet.
2125 */
2126 if (current_ocv_raw != chip->ocv_reading_at_100
2127 && current_ocv_raw < ocv_raw)
2128 ocv_raw = current_ocv_raw - OCV_STEP_INCREMENT;
2129
2130 qpnp_write_wrapper(chip, (u8 *)&cc_raw,
2131 chip->base + BMS1_SW_CC_THR0, 5);
2132 qpnp_write_wrapper(chip, (u8 *)&ocv_raw,
2133 chip->base + BMS1_OCV_THR0, 2);
2134
2135 pr_debug("current sw_cc_raw = 0x%llx, current ocv = 0x%hx\n",
2136 current_shdw_cc_raw, (uint16_t)current_ocv_raw);
2137 pr_debug("target_cc_uah = %lld, raw64 = 0x%llx, raw 36 = 0x%llx, ocv_raw = 0x%hx\n",
2138 target_cc_uah,
2139 (uint64_t)cc_raw_64, cc_raw,
2140 (uint16_t)ocv_raw);
2141}
2142
Xiaozhe Shi04da0992013-04-26 16:32:14 -07002143#define SLEEP_RECALC_INTERVAL 3
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002144static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
2145 struct raw_soc_params *raw,
2146 int batt_temp)
2147{
Xiaozhe Shie7fafe62013-06-05 15:25:16 -07002148 int soc, new_ocv_uv, previous_soc;
Xiaozhe Shie118c692012-09-24 15:17:43 -07002149 int shutdown_soc, new_calculated_soc, remaining_usable_charge_uah;
2150 struct soc_params params;
2151
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002152 if (!is_battery_present(chip)) {
Xiaozhe Shi026fa9b2013-03-22 17:00:50 -07002153 pr_debug("battery gone, reporting 100\n");
2154 new_calculated_soc = 100;
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08002155 goto done_calculating;
2156 }
Xiaozhe Shie118c692012-09-24 15:17:43 -07002157 calculate_soc_params(chip, raw, &params, batt_temp);
2158 /* calculate remaining usable charge */
2159 remaining_usable_charge_uah = params.ocv_charge_uah
2160 - params.cc_uah
2161 - params.uuc_uah;
2162
2163 pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
2164 if (params.fcc_uah - params.uuc_uah <= 0) {
Xiaozhe Shicb386a22012-11-29 12:11:42 -08002165 pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
Xiaozhe Shie118c692012-09-24 15:17:43 -07002166 params.fcc_uah,
2167 params.uuc_uah);
Xiaozhe Shifd8cd482013-02-12 10:00:38 -08002168 new_calculated_soc = 0;
2169 goto done_calculating;
Xiaozhe Shie118c692012-09-24 15:17:43 -07002170 }
2171
Xiaozhe Shifd8cd482013-02-12 10:00:38 -08002172 soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
2173 (params.fcc_uah - params.uuc_uah));
2174
Xiaozhe Shie118c692012-09-24 15:17:43 -07002175 if (chip->first_time_calc_soc && soc < 0) {
2176 /*
2177 * first time calcualtion and the pon ocv is too low resulting
2178 * in a bad soc. Adjust ocv to get 0 soc
2179 */
2180 pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
2181 find_ocv_for_soc(chip, &params, batt_temp, 0, &new_ocv_uv);
2182 chip->last_ocv_uv = new_ocv_uv;
2183
2184 remaining_usable_charge_uah = params.ocv_charge_uah
2185 - params.cc_uah
2186 - params.uuc_uah;
2187
2188 soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
2189 (params.fcc_uah
2190 - params.uuc_uah));
2191 pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
2192 soc, chip->last_ocv_uv);
2193 }
2194
2195 if (soc > 100)
2196 soc = 100;
2197
2198 if (soc < 0) {
Xiaozhe Shicb386a22012-11-29 12:11:42 -08002199 pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
Xiaozhe Shie118c692012-09-24 15:17:43 -07002200 remaining_usable_charge_uah,
2201 params.ocv_charge_uah,
2202 params.cc_uah, params.uuc_uah);
2203
Xiaozhe Shicb386a22012-11-29 12:11:42 -08002204 pr_debug("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
Xiaozhe Shie118c692012-09-24 15:17:43 -07002205 chip->last_ocv_uv, batt_temp,
2206 params.fcc_uah, soc);
2207 soc = 0;
2208 }
2209
2210 mutex_lock(&chip->soc_invalidation_mutex);
2211 shutdown_soc = chip->shutdown_soc;
2212
2213 if (chip->first_time_calc_soc && soc != shutdown_soc
2214 && is_shutdown_soc_within_limits(chip, soc)) {
2215 /*
2216 * soc for the first time - use shutdown soc
2217 * to adjust pon ocv since it is a small percent away from
2218 * the real soc
2219 */
2220 pr_debug("soc = %d before forcing shutdown_soc = %d\n",
2221 soc, shutdown_soc);
2222 find_ocv_for_soc(chip, &params, batt_temp,
2223 shutdown_soc, &new_ocv_uv);
Xiaozhe Shie118c692012-09-24 15:17:43 -07002224 chip->last_ocv_uv = new_ocv_uv;
2225
2226 remaining_usable_charge_uah = params.ocv_charge_uah
2227 - params.cc_uah
2228 - params.uuc_uah;
2229
2230 soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
2231 (params.fcc_uah
2232 - params.uuc_uah));
2233
2234 pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
2235 shutdown_soc, soc, chip->last_ocv_uv);
2236 }
2237 mutex_unlock(&chip->soc_invalidation_mutex);
2238
2239 pr_debug("SOC before adjustment = %d\n", soc);
2240 new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
2241
Xiaozhe Shi445d2492013-03-27 18:10:18 -07002242 /* always clamp soc due to BMS hw/sw immaturities */
2243 new_calculated_soc = clamp_soc_based_on_voltage(chip,
2244 new_calculated_soc);
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08002245 /*
2246 * If the battery is full, configure the cc threshold so the system
2247 * wakes up after SoC changes
2248 */
2249 if (is_battery_full(chip))
2250 configure_soc_wakeup(chip, &params,
2251 batt_temp, bound_soc(new_calculated_soc - 1));
Xiaozhe Shifd8cd482013-02-12 10:00:38 -08002252done_calculating:
Xiaozhe Shifa6ea692013-05-31 11:15:13 -07002253 mutex_lock(&chip->last_soc_mutex);
Xiaozhe Shie7fafe62013-06-05 15:25:16 -07002254 previous_soc = chip->calculated_soc;
Xiaozhe Shie118c692012-09-24 15:17:43 -07002255 chip->calculated_soc = new_calculated_soc;
Xiaozhe Shi04da0992013-04-26 16:32:14 -07002256 pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08002257 if (chip->last_soc_invalid) {
2258 chip->last_soc_invalid = false;
2259 chip->last_soc = -EINVAL;
2260 }
Xiaozhe Shi04da0992013-04-26 16:32:14 -07002261 /*
2262 * Check if more than a long time has passed since the last
2263 * calculation (more than n times compared to the soc recalculation
2264 * rate, where n is defined by SLEEP_RECALC_INTERVAL). If this is true,
2265 * then the system must have gone through a long sleep, and SoC can be
2266 * allowed to become unbounded by the last reported SoC
2267 */
2268 if (params.delta_time_s * 1000 >
2269 chip->calculate_soc_ms * SLEEP_RECALC_INTERVAL
2270 && !chip->first_time_calc_soc) {
2271 chip->last_soc_unbound = true;
2272 chip->last_soc_change_sec = chip->last_recalc_time;
2273 pr_debug("last_soc unbound because elapsed time = %d\n",
2274 params.delta_time_s);
2275 }
2276 mutex_unlock(&chip->last_soc_mutex);
Xiaozhe Shi83484e32013-05-16 10:59:59 -07002277
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -07002278 if (new_calculated_soc != previous_soc && chip->bms_psy_registered) {
Xiaozhe Shi83484e32013-05-16 10:59:59 -07002279 power_supply_changed(&chip->bms_psy);
2280 pr_debug("power supply changed\n");
2281 } else {
2282 /*
2283 * Call report state of charge anyways to periodically update
2284 * reported SoC. This prevents reported SoC from being stuck
2285 * when calculated soc doesn't change.
2286 */
2287 report_state_of_charge(chip);
2288 }
2289
Xiaozhe Shicdeee312012-12-18 15:10:18 -08002290 get_current_time(&chip->last_recalc_time);
Xiaozhe Shi04da0992013-04-26 16:32:14 -07002291 chip->first_time_calc_soc = 0;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002292 return chip->calculated_soc;
2293}
2294
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002295static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
2296{
2297 int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
Xiaozhe Shi36458962013-02-06 16:19:57 -08002298 int rc, vbat_uv;
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002299
Xiaozhe Shi36458962013-02-06 16:19:57 -08002300 rc = get_battery_voltage(&vbat_uv);
2301 if (rc < 0) {
2302 pr_err("adc vbat failed err = %d\n", rc);
2303 return rc;
2304 }
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002305 voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
2306 voltage_remaining_uv = vbat_uv - chip->v_cutoff_uv;
2307 voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
2308
2309 voltage_based_soc = clamp(voltage_based_soc, 0, 100);
2310
2311 if (chip->prev_voltage_based_soc != voltage_based_soc
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -07002312 && chip->bms_psy_registered) {
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002313 power_supply_changed(&chip->bms_psy);
2314 pr_debug("power supply changed\n");
2315 }
2316 chip->prev_voltage_based_soc = voltage_based_soc;
2317
2318 pr_debug("vbat used = %duv\n", vbat_uv);
2319 pr_debug("Calculated voltage based soc = %d\n", voltage_based_soc);
2320 return voltage_based_soc;
Xiaozhe Shi781b0a22012-11-05 17:18:27 -08002321}
2322
Xiaozhe Shicdeee312012-12-18 15:10:18 -08002323static int recalculate_soc(struct qpnp_bms_chip *chip)
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002324{
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002325 int batt_temp, rc, soc;
2326 struct qpnp_vadc_result result;
2327 struct raw_soc_params raw;
2328
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08002329 bms_stay_awake(&chip->soc_wake_source);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002330 mutex_lock(&chip->vbat_monitor_mutex);
Xiaozhe Shib5689fb2013-07-15 17:20:49 -07002331 if (chip->vbat_monitor_params.state_request !=
2332 ADC_TM_HIGH_LOW_THR_DISABLE)
2333 qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002334 mutex_unlock(&chip->vbat_monitor_mutex);
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002335 if (chip->use_voltage_soc) {
2336 soc = calculate_soc_from_voltage(chip);
2337 } else {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -07002338 qpnp_iadc_calibrate_for_trim(true);
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002339 rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
2340 if (rc) {
2341 pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
2342 LR_MUX1_BATT_THERM, rc);
Abhijeet Dharmapurikar713b60a2012-12-26 21:30:05 -08002343 soc = chip->calculated_soc;
2344 } else {
2345 pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
2346 result.physical,
2347 result.measurement);
2348 batt_temp = (int)result.physical;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002349
Abhijeet Dharmapurikar713b60a2012-12-26 21:30:05 -08002350 mutex_lock(&chip->last_ocv_uv_mutex);
2351 read_soc_params_raw(chip, &raw, batt_temp);
2352 soc = calculate_state_of_charge(chip, &raw, batt_temp);
2353 mutex_unlock(&chip->last_ocv_uv_mutex);
2354 }
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08002355 }
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08002356 bms_relax(&chip->soc_wake_source);
Xiaozhe Shicdeee312012-12-18 15:10:18 -08002357 return soc;
2358}
2359
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08002360static void recalculate_work(struct work_struct *work)
2361{
2362 struct qpnp_bms_chip *chip = container_of(work,
2363 struct qpnp_bms_chip,
2364 recalc_work);
2365
2366 recalculate_soc(chip);
2367}
2368
Xiaozhe Shicdeee312012-12-18 15:10:18 -08002369static void calculate_soc_work(struct work_struct *work)
2370{
2371 struct qpnp_bms_chip *chip = container_of(work,
2372 struct qpnp_bms_chip,
2373 calculate_soc_delayed_work.work);
2374 int soc = recalculate_soc(chip);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002375
Xiaozhe Shi4be85782013-02-22 17:33:40 -08002376 if (soc < chip->low_soc_calc_threshold
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002377 || wake_lock_active(&chip->low_voltage_wake_lock))
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07002378 schedule_delayed_work(&chip->calculate_soc_delayed_work,
2379 round_jiffies_relative(msecs_to_jiffies
2380 (chip->low_soc_calculate_soc_ms)));
2381 else
2382 schedule_delayed_work(&chip->calculate_soc_delayed_work,
2383 round_jiffies_relative(msecs_to_jiffies
2384 (chip->calculate_soc_ms)));
2385}
2386
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002387static void configure_vbat_monitor_low(struct qpnp_bms_chip *chip)
2388{
2389 mutex_lock(&chip->vbat_monitor_mutex);
2390 if (chip->vbat_monitor_params.state_request
2391 == ADC_TM_HIGH_LOW_THR_ENABLE) {
2392 /*
2393 * Battery is now around or below v_cutoff
2394 */
2395 pr_debug("battery entered cutoff range\n");
2396 if (!wake_lock_active(&chip->low_voltage_wake_lock)) {
2397 pr_debug("voltage low, holding wakelock\n");
2398 wake_lock(&chip->low_voltage_wake_lock);
2399 cancel_delayed_work_sync(
2400 &chip->calculate_soc_delayed_work);
2401 schedule_delayed_work(
2402 &chip->calculate_soc_delayed_work, 0);
2403 }
2404 chip->vbat_monitor_params.state_request =
2405 ADC_TM_HIGH_THR_ENABLE;
2406 chip->vbat_monitor_params.high_thr =
2407 (chip->low_voltage_threshold + VBATT_ERROR_MARGIN);
2408 pr_debug("set low thr to %d and high to %d\n",
2409 chip->vbat_monitor_params.low_thr,
2410 chip->vbat_monitor_params.high_thr);
2411 chip->vbat_monitor_params.low_thr = 0;
2412 } else if (chip->vbat_monitor_params.state_request
2413 == ADC_TM_LOW_THR_ENABLE) {
2414 /*
2415 * Battery is in normal operation range.
2416 */
2417 pr_debug("battery entered normal range\n");
2418 if (wake_lock_active(&chip->cv_wake_lock)) {
2419 wake_unlock(&chip->cv_wake_lock);
2420 pr_debug("releasing cv wake lock\n");
2421 }
2422 chip->in_cv_range = false;
2423 chip->vbat_monitor_params.state_request =
2424 ADC_TM_HIGH_LOW_THR_ENABLE;
2425 chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
2426 - VBATT_ERROR_MARGIN;
2427 chip->vbat_monitor_params.low_thr =
2428 chip->low_voltage_threshold;
2429 pr_debug("set low thr to %d and high to %d\n",
2430 chip->vbat_monitor_params.low_thr,
2431 chip->vbat_monitor_params.high_thr);
2432 }
2433 qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
2434 mutex_unlock(&chip->vbat_monitor_mutex);
2435}
2436
2437#define CV_LOW_THRESHOLD_HYST_UV 100000
2438static void configure_vbat_monitor_high(struct qpnp_bms_chip *chip)
2439{
2440 mutex_lock(&chip->vbat_monitor_mutex);
2441 if (chip->vbat_monitor_params.state_request
2442 == ADC_TM_HIGH_LOW_THR_ENABLE) {
2443 /*
2444 * Battery is around vddmax
2445 */
2446 pr_debug("battery entered vddmax range\n");
2447 chip->in_cv_range = true;
2448 if (!wake_lock_active(&chip->cv_wake_lock)) {
2449 wake_lock(&chip->cv_wake_lock);
2450 pr_debug("holding cv wake lock\n");
2451 }
2452 schedule_work(&chip->recalc_work);
2453 chip->vbat_monitor_params.state_request =
2454 ADC_TM_LOW_THR_ENABLE;
2455 chip->vbat_monitor_params.low_thr =
2456 (chip->max_voltage_uv - CV_LOW_THRESHOLD_HYST_UV);
2457 chip->vbat_monitor_params.high_thr = chip->max_voltage_uv * 2;
2458 pr_debug("set low thr to %d and high to %d\n",
2459 chip->vbat_monitor_params.low_thr,
2460 chip->vbat_monitor_params.high_thr);
2461 } else if (chip->vbat_monitor_params.state_request
2462 == ADC_TM_HIGH_THR_ENABLE) {
2463 /*
2464 * Battery is in normal operation range.
2465 */
2466 pr_debug("battery entered normal range\n");
2467 if (wake_lock_active(&chip->low_voltage_wake_lock)) {
2468 pr_debug("voltage high, releasing wakelock\n");
2469 wake_unlock(&chip->low_voltage_wake_lock);
2470 }
2471 chip->vbat_monitor_params.state_request =
2472 ADC_TM_HIGH_LOW_THR_ENABLE;
2473 chip->vbat_monitor_params.high_thr =
2474 chip->max_voltage_uv - VBATT_ERROR_MARGIN;
2475 chip->vbat_monitor_params.low_thr =
2476 chip->low_voltage_threshold;
2477 pr_debug("set low thr to %d and high to %d\n",
2478 chip->vbat_monitor_params.low_thr,
2479 chip->vbat_monitor_params.high_thr);
2480 }
2481 qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
2482 mutex_unlock(&chip->vbat_monitor_mutex);
2483}
2484
2485static void btm_notify_vbat(enum qpnp_tm_state state, void *ctx)
2486{
2487 struct qpnp_bms_chip *chip = ctx;
2488 int vbat_uv;
2489 struct qpnp_vadc_result result;
2490 int rc;
2491
2492 rc = qpnp_vadc_read(VBAT_SNS, &result);
2493 pr_debug("vbat = %lld, raw = 0x%x\n", result.physical, result.adc_code);
2494
2495 get_battery_voltage(&vbat_uv);
2496 pr_debug("vbat is at %d, state is at %d\n", vbat_uv, state);
2497
2498 if (state == ADC_TM_LOW_STATE) {
2499 pr_debug("low voltage btm notification triggered\n");
2500 if (vbat_uv - VBATT_ERROR_MARGIN
2501 < chip->vbat_monitor_params.low_thr) {
2502 configure_vbat_monitor_low(chip);
2503 } else {
2504 pr_debug("faulty btm trigger, discarding\n");
2505 qpnp_adc_tm_channel_measure(
2506 &chip->vbat_monitor_params);
2507 }
2508 } else if (state == ADC_TM_HIGH_STATE) {
2509 pr_debug("high voltage btm notification triggered\n");
2510 if (vbat_uv + VBATT_ERROR_MARGIN
2511 > chip->vbat_monitor_params.high_thr) {
2512 configure_vbat_monitor_high(chip);
2513 } else {
2514 pr_debug("faulty btm trigger, discarding\n");
2515 qpnp_adc_tm_channel_measure(
2516 &chip->vbat_monitor_params);
2517 }
2518 } else {
2519 pr_debug("unknown voltage notification state: %d\n", state);
2520 }
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -07002521 if (chip->bms_psy_registered)
Xiaozhe Shifa120db2013-06-06 15:57:19 -07002522 power_supply_changed(&chip->bms_psy);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002523}
2524
2525static int reset_vbat_monitoring(struct qpnp_bms_chip *chip)
2526{
2527 int rc;
2528
2529 chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE;
Xiaozhe Shib5689fb2013-07-15 17:20:49 -07002530
2531 rc = qpnp_adc_tm_disable_chan_meas(&chip->vbat_monitor_params);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002532 if (rc) {
Xiaozhe Shib5689fb2013-07-15 17:20:49 -07002533 pr_err("tm disable failed: %d\n", rc);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002534 return rc;
2535 }
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002536 if (wake_lock_active(&chip->low_voltage_wake_lock)) {
2537 pr_debug("battery removed, releasing wakelock\n");
2538 wake_unlock(&chip->low_voltage_wake_lock);
2539 }
2540 if (chip->in_cv_range) {
2541 pr_debug("battery removed, removing in_cv_range state\n");
2542 chip->in_cv_range = false;
2543 }
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002544 return 0;
2545}
2546
2547static int setup_vbat_monitoring(struct qpnp_bms_chip *chip)
2548{
2549 int rc;
2550
2551 rc = qpnp_adc_tm_is_ready();
2552 if (rc) {
2553 pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
2554 return -EPROBE_DEFER;
2555 }
2556
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002557 chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold;
2558 chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
2559 - VBATT_ERROR_MARGIN;
2560 chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
2561 chip->vbat_monitor_params.channel = VBAT_SNS;
2562 chip->vbat_monitor_params.btm_ctx = (void *)chip;
2563 chip->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
2564 chip->vbat_monitor_params.threshold_notification = &btm_notify_vbat;
2565 pr_debug("set low thr to %d and high to %d\n",
2566 chip->vbat_monitor_params.low_thr,
2567 chip->vbat_monitor_params.high_thr);
Xiaozhe Shib5689fb2013-07-15 17:20:49 -07002568
2569 if (!is_battery_present(chip)) {
2570 pr_debug("no battery inserted, do not enable vbat monitoring\n");
2571 chip->vbat_monitor_params.state_request =
2572 ADC_TM_HIGH_LOW_THR_DISABLE;
2573 } else {
2574 rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
2575 if (rc) {
2576 pr_err("tm setup failed: %d\n", rc);
2577 return rc;
2578 }
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002579 }
2580 pr_debug("setup complete\n");
2581 return 0;
2582}
2583
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302584static void readjust_fcc_table(struct qpnp_bms_chip *chip)
2585{
2586 struct single_row_lut *temp, *old;
2587 int i, fcc, ratio;
2588
2589 if (!chip->enable_fcc_learning)
2590 return;
2591
2592 if (!chip->fcc_temp_lut) {
2593 pr_err("The static fcc lut table is NULL\n");
2594 return;
2595 }
2596
2597 temp = kzalloc(sizeof(struct single_row_lut), GFP_KERNEL);
2598 if (!temp) {
2599 pr_err("Cannot allocate memory for adjusted fcc table\n");
2600 return;
2601 }
2602
2603 fcc = interpolate_fcc(chip->fcc_temp_lut, chip->fcc_new_batt_temp);
2604
2605 temp->cols = chip->fcc_temp_lut->cols;
2606 for (i = 0; i < chip->fcc_temp_lut->cols; i++) {
2607 temp->x[i] = chip->fcc_temp_lut->x[i];
2608 ratio = div_u64(chip->fcc_temp_lut->y[i] * 1000, fcc);
2609 temp->y[i] = (ratio * chip->fcc_new_mah);
2610 temp->y[i] /= 1000;
2611 }
2612
2613 old = chip->adjusted_fcc_temp_lut;
2614 chip->adjusted_fcc_temp_lut = temp;
2615 kfree(old);
2616}
2617
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302618static int read_fcc_data_from_backup(struct qpnp_bms_chip *chip)
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302619{
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302620 int rc, i;
2621 u8 fcc = 0, chgcyl = 0;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302622
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302623 for (i = 0; i < chip->min_fcc_learning_samples; i++) {
2624 rc = qpnp_read_wrapper(chip, &fcc,
2625 chip->base + BMS_FCC_BASE_REG + i, 1);
2626 rc |= qpnp_read_wrapper(chip, &chgcyl,
2627 chip->base + BMS_CHGCYL_BASE_REG + i, 1);
2628 if (rc) {
2629 pr_err("Unable to read FCC data\n");
2630 return rc;
2631 }
2632 if (fcc == 0 || (fcc == 0xFF && chgcyl == 0xFF)) {
2633 /* FCC invalid/not present */
2634 chip->fcc_learning_samples[i].fcc_new = 0;
2635 chip->fcc_learning_samples[i].chargecycles = 0;
2636 } else {
2637 /* valid FCC data */
2638 chip->fcc_sample_count++;
2639 chip->fcc_learning_samples[i].fcc_new =
2640 fcc * chip->fcc_resolution;
2641 chip->fcc_learning_samples[i].chargecycles =
2642 chgcyl * CHGCYL_RESOLUTION;
2643 }
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302644 }
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302645
2646 return 0;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302647}
2648
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302649static int discard_backup_fcc_data(struct qpnp_bms_chip *chip)
2650{
2651 int rc = 0, i;
2652 u8 temp_u8 = 0;
2653
2654 chip->fcc_sample_count = 0;
2655 for (i = 0; i < chip->min_fcc_learning_samples; i++) {
2656 rc = qpnp_write_wrapper(chip, &temp_u8,
2657 chip->base + BMS_FCC_BASE_REG + i, 1);
2658 rc |= qpnp_write_wrapper(chip, &temp_u8,
2659 chip->base + BMS_CHGCYL_BASE_REG + i, 1);
2660 if (rc) {
2661 pr_err("Unable to clear FCC data\n");
2662 return rc;
2663 }
2664 }
2665
2666 return 0;
2667}
2668
2669static void
2670average_fcc_samples_and_readjust_fcc_table(struct qpnp_bms_chip *chip)
2671{
2672 int i, temp_fcc_avg = 0, temp_fcc_delta = 0, new_fcc_avg = 0;
2673 struct fcc_sample *ft;
2674
2675 for (i = 0; i < chip->min_fcc_learning_samples; i++)
2676 temp_fcc_avg += chip->fcc_learning_samples[i].fcc_new;
2677
2678 temp_fcc_avg /= chip->min_fcc_learning_samples;
2679 temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
2680
2681 /* fix the fcc if its an outlier i.e. > 5% of the average */
2682 for (i = 0; i < chip->min_fcc_learning_samples; i++) {
2683 ft = &chip->fcc_learning_samples[i];
2684 if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
2685 new_fcc_avg += temp_fcc_avg;
2686 else
2687 new_fcc_avg += ft->fcc_new;
2688 }
2689 new_fcc_avg /= chip->min_fcc_learning_samples;
2690
2691 chip->fcc_new_mah = new_fcc_avg;
2692 chip->fcc_new_batt_temp = FCC_DEFAULT_TEMP;
2693 pr_info("FCC update: New fcc_mah=%d, fcc_batt_temp=%d\n",
2694 new_fcc_avg, FCC_DEFAULT_TEMP);
2695 readjust_fcc_table(chip);
2696}
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302697
2698static void backup_charge_cycle(struct qpnp_bms_chip *chip)
2699{
2700 int rc = 0;
2701
2702 if (chip->charge_increase >= 0) {
2703 rc = qpnp_write_wrapper(chip, &chip->charge_increase,
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302704 chip->base + CHARGE_INCREASE_STORAGE, 1);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302705 if (rc)
2706 pr_err("Unable to backup charge_increase\n");
2707 }
2708
2709 if (chip->charge_cycles >= 0) {
2710 rc = qpnp_write_wrapper(chip, (u8 *)&chip->charge_cycles,
2711 chip->base + CHARGE_CYCLE_STORAGE_LSB, 2);
2712 if (rc)
2713 pr_err("Unable to backup charge_cycles\n");
2714 }
2715}
2716
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302717static bool chargecycles_in_range(struct qpnp_bms_chip *chip)
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302718{
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302719 int i, min_cycle, max_cycle, valid_range;
2720
2721 /* find the smallest and largest charge cycle */
2722 max_cycle = min_cycle = chip->fcc_learning_samples[0].chargecycles;
2723 for (i = 1; i < chip->min_fcc_learning_samples; i++) {
2724 if (min_cycle > chip->fcc_learning_samples[i].chargecycles)
2725 min_cycle = chip->fcc_learning_samples[i].chargecycles;
2726 if (max_cycle < chip->fcc_learning_samples[i].chargecycles)
2727 max_cycle = chip->fcc_learning_samples[i].chargecycles;
2728 }
2729
2730 /* check if chargecyles are in range to continue with FCC update */
2731 valid_range = DIV_ROUND_UP(VALID_FCC_CHGCYL_RANGE,
2732 CHGCYL_RESOLUTION) * CHGCYL_RESOLUTION;
2733 if (abs(max_cycle - min_cycle) > valid_range)
2734 return false;
2735
2736 return true;
2737}
2738
2739static int read_chgcycle_data_from_backup(struct qpnp_bms_chip *chip)
2740{
2741 int rc;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302742 uint16_t temp_u16 = 0;
2743 u8 temp_u8 = 0;
2744
2745 rc = qpnp_read_wrapper(chip, &temp_u8,
2746 chip->base + CHARGE_INCREASE_STORAGE, 1);
2747 if (!rc && temp_u8 != 0xFF)
2748 chip->charge_increase = temp_u8;
2749
2750 rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16,
2751 chip->base + CHARGE_CYCLE_STORAGE_LSB, 2);
2752 if (!rc && temp_u16 != 0xFFFF)
2753 chip->charge_cycles = temp_u16;
2754
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302755 return rc;
2756}
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302757
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302758static void
2759attempt_learning_new_fcc(struct qpnp_bms_chip *chip)
2760{
2761 pr_debug("Total FCC sample count=%d\n", chip->fcc_sample_count);
2762
2763 /* update FCC if we have the required samples */
2764 if ((chip->fcc_sample_count == chip->min_fcc_learning_samples) &&
2765 chargecycles_in_range(chip))
2766 average_fcc_samples_and_readjust_fcc_table(chip);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302767}
2768
2769static int calculate_real_soc(struct qpnp_bms_chip *chip,
2770 int batt_temp, struct raw_soc_params *raw, int cc_uah)
2771{
2772 int fcc_uah, rc_uah;
2773
2774 fcc_uah = calculate_fcc(chip, batt_temp);
2775 rc_uah = calculate_ocv_charge(chip, raw, fcc_uah);
2776
2777 return ((rc_uah - cc_uah) * 100) / fcc_uah;
2778}
2779
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302780#define MAX_U8_VALUE ((u8)(~0U))
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302781
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302782static int backup_new_fcc(struct qpnp_bms_chip *chip, int fcc_mah,
2783 int chargecycles)
2784{
2785 int rc, min_cycle, i;
2786 u8 fcc_new, chgcyl, pos = 0;
2787 struct fcc_sample *ft;
2788
2789 if ((fcc_mah > (chip->fcc_resolution * MAX_U8_VALUE)) ||
2790 (chargecycles > (CHGCYL_RESOLUTION * MAX_U8_VALUE))) {
2791 pr_warn("FCC/Chgcyl beyond storage limit. FCC=%d, chgcyl=%d\n",
2792 fcc_mah, chargecycles);
2793 return -EINVAL;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302794 }
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302795
2796 if (chip->fcc_sample_count == chip->min_fcc_learning_samples) {
2797 /* search best location - oldest entry */
2798 min_cycle = chip->fcc_learning_samples[0].chargecycles;
2799 for (i = 1; i < chip->min_fcc_learning_samples; i++) {
2800 if (min_cycle >
2801 chip->fcc_learning_samples[i].chargecycles)
2802 pos = i;
2803 }
2804 } else {
2805 /* find an empty location */
2806 for (i = 0; i < chip->min_fcc_learning_samples; i++) {
2807 ft = &chip->fcc_learning_samples[i];
2808 if (ft->fcc_new == 0 || (ft->fcc_new == 0xFF &&
2809 ft->chargecycles == 0xFF)) {
2810 pos = i;
2811 break;
2812 }
2813 }
2814 chip->fcc_sample_count++;
2815 }
2816 chip->fcc_learning_samples[pos].fcc_new = fcc_mah;
2817 chip->fcc_learning_samples[pos].chargecycles = chargecycles;
2818
2819 fcc_new = DIV_ROUND_UP(fcc_mah, chip->fcc_resolution);
2820 rc = qpnp_write_wrapper(chip, (u8 *)&fcc_new,
2821 chip->base + BMS_FCC_BASE_REG + pos, 1);
2822 if (rc)
2823 return rc;
2824
2825 chgcyl = DIV_ROUND_UP(chargecycles, CHGCYL_RESOLUTION);
2826 rc = qpnp_write_wrapper(chip, (u8 *)&chgcyl,
2827 chip->base + BMS_CHGCYL_BASE_REG + pos, 1);
2828 if (rc)
2829 return rc;
2830
2831 pr_debug("Backup new FCC: fcc_new=%d, chargecycle=%d, pos=%d\n",
2832 fcc_new, chgcyl, pos);
2833
2834 return rc;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302835}
2836
2837static void update_fcc_learning_table(struct qpnp_bms_chip *chip,
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302838 int new_fcc_uah, int chargecycles, int batt_temp)
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302839{
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302840 int rc, fcc_default, fcc_temp;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302841
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302842 /* convert the fcc at batt_temp to new fcc at FCC_DEFAULT_TEMP */
2843 fcc_default = calculate_fcc(chip, FCC_DEFAULT_TEMP) / 1000;
2844 fcc_temp = calculate_fcc(chip, batt_temp) / 1000;
2845 new_fcc_uah = (new_fcc_uah / fcc_temp) * fcc_default;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302846
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302847 rc = backup_new_fcc(chip, new_fcc_uah / 1000, chargecycles);
2848 if (rc) {
2849 pr_err("Unable to backup new FCC\n");
2850 return;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302851 }
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302852 /* check if FCC can be updated */
2853 attempt_learning_new_fcc(chip);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302854}
2855
2856static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
2857{
2858 if ((new_fcc_uah >= (fcc_uah / 2)) &&
2859 ((new_fcc_uah * 100) <= (fcc_uah * 105)))
2860 return true;
2861
2862 pr_debug("FCC rejected - not within valid limit\n");
2863 return false;
2864}
2865
2866static void fcc_learning_config(struct qpnp_bms_chip *chip, bool start)
2867{
2868 int rc, batt_temp;
2869 struct raw_soc_params raw;
2870 struct qpnp_vadc_result result;
2871 int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
2872
2873 rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
2874 if (rc) {
2875 pr_err("Unable to read batt_temp\n");
2876 return;
2877 } else {
2878 batt_temp = (int)result.physical;
2879 }
2880
2881 rc = read_soc_params_raw(chip, &raw, batt_temp);
2882 if (rc) {
2883 pr_err("Unable to read CC, cannot update FCC\n");
2884 return;
2885 }
2886
2887 if (start) {
2888 chip->start_pc = interpolate_pc(chip->pc_temp_ocv_lut,
2889 batt_temp / 10, raw.last_good_ocv_uv / 1000);
Xiaozhe Shif3da8622013-06-10 14:50:56 -07002890 chip->start_cc_uah = calculate_cc(chip, raw.cc, CC, NORESET);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302891 chip->start_real_soc = calculate_real_soc(chip,
2892 batt_temp, &raw, chip->start_cc_uah);
2893 pr_debug("start_pc=%d, start_cc=%d, start_soc=%d real_soc=%d\n",
2894 chip->start_pc, chip->start_cc_uah,
2895 chip->start_soc, chip->start_real_soc);
2896 } else {
Xiaozhe Shif3da8622013-06-10 14:50:56 -07002897 chip->end_cc_uah = calculate_cc(chip, raw.cc, CC, NORESET);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302898 delta_soc = 100 - chip->start_real_soc;
2899 delta_cc_uah = abs(chip->end_cc_uah - chip->start_cc_uah);
2900 new_fcc_uah = div_u64(delta_cc_uah * 100, delta_soc);
2901 fcc_uah = calculate_fcc(chip, batt_temp);
2902 pr_debug("start_soc=%d, start_pc=%d, start_real_soc=%d, start_cc=%d, end_cc=%d, new_fcc=%d\n",
2903 chip->start_soc, chip->start_pc, chip->start_real_soc,
2904 chip->start_cc_uah, chip->end_cc_uah, new_fcc_uah);
2905
2906 if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
Anirudh Ghayale0c02932013-07-08 16:26:35 +05302907 update_fcc_learning_table(chip, new_fcc_uah,
2908 chip->charge_cycles, batt_temp);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302909 }
2910}
2911
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002912static void charging_began(struct qpnp_bms_chip *chip)
Xiaozhe Shia6618a22013-03-27 10:26:29 -07002913{
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302914
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002915 mutex_lock(&chip->last_soc_mutex);
2916 chip->charge_start_tm_sec = 0;
2917 chip->catch_up_time_sec = 0;
2918 mutex_unlock(&chip->last_soc_mutex);
2919
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302920 chip->start_soc = report_state_of_charge(chip);
2921
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002922 mutex_lock(&chip->last_ocv_uv_mutex);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302923 if (chip->enable_fcc_learning)
2924 fcc_learning_config(chip, true);
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002925 chip->soc_at_cv = -EINVAL;
2926 chip->prev_chg_soc = -EINVAL;
2927 mutex_unlock(&chip->last_ocv_uv_mutex);
2928}
2929
2930static void charging_ended(struct qpnp_bms_chip *chip)
2931{
2932 mutex_lock(&chip->last_soc_mutex);
2933 chip->charge_start_tm_sec = 0;
2934 chip->catch_up_time_sec = 0;
2935 mutex_unlock(&chip->last_soc_mutex);
2936
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302937 chip->end_soc = report_state_of_charge(chip);
2938
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002939 mutex_lock(&chip->last_ocv_uv_mutex);
2940 chip->soc_at_cv = -EINVAL;
2941 chip->prev_chg_soc = -EINVAL;
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302942
2943 /* update the chargecycles */
2944 if (chip->end_soc > chip->start_soc) {
2945 chip->charge_increase += (chip->end_soc - chip->start_soc);
2946 if (chip->charge_increase > 100) {
2947 chip->charge_cycles++;
2948 chip->charge_increase = chip->charge_increase % 100;
2949 }
2950 if (chip->enable_fcc_learning)
2951 backup_charge_cycle(chip);
2952 }
2953
Xiaozhe Shi83484e32013-05-16 10:59:59 -07002954 if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302955 if (chip->enable_fcc_learning &&
2956 (chip->start_soc <= chip->min_fcc_learning_soc) &&
2957 (chip->start_pc <= chip->min_fcc_ocv_pc))
2958 fcc_learning_config(chip, false);
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002959 chip->done_charging = true;
Xiaozhe Shi83484e32013-05-16 10:59:59 -07002960 chip->last_soc_invalid = true;
Xiaozhe Shicc48e992013-05-28 16:42:24 -07002961 } else if (chip->charging_adjusted_ocv > 0) {
2962 pr_debug("Charging stopped before full, adjusted OCV = %d\n",
2963 chip->charging_adjusted_ocv);
2964 chip->last_ocv_uv = chip->charging_adjusted_ocv;
Xiaozhe Shi83484e32013-05-16 10:59:59 -07002965 }
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05302966
Xiaozhe Shicc48e992013-05-28 16:42:24 -07002967 chip->charging_adjusted_ocv = -EINVAL;
2968
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002969 mutex_unlock(&chip->last_ocv_uv_mutex);
2970}
2971
2972static void battery_status_check(struct qpnp_bms_chip *chip)
2973{
2974 int status = get_battery_status(chip);
2975
2976 if (chip->battery_status != status) {
2977 if (status == POWER_SUPPLY_STATUS_CHARGING) {
2978 pr_debug("charging started\n");
2979 charging_began(chip);
2980 } else if (chip->battery_status
2981 == POWER_SUPPLY_STATUS_CHARGING) {
2982 pr_debug("charging ended\n");
2983 charging_ended(chip);
2984 }
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08002985
2986 if (status == POWER_SUPPLY_STATUS_FULL) {
2987 pr_debug("battery full\n");
2988 enable_bms_irq(&chip->ocv_thr_irq);
2989 enable_bms_irq(&chip->sw_cc_thr_irq);
2990 } else if (chip->battery_status
2991 == POWER_SUPPLY_STATUS_FULL) {
2992 pr_debug("battery not full any more\n");
2993 disable_bms_irq(&chip->ocv_thr_irq);
2994 disable_bms_irq(&chip->sw_cc_thr_irq);
2995 }
2996
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002997 chip->battery_status = status;
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08002998 /* battery charge status has changed, so force a soc
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07002999 * recalculation to update the SoC */
3000 schedule_work(&chip->recalc_work);
3001 }
3002}
3003
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -07003004#define CALIB_WRKARND_DIG_MAJOR_MAX 0x03
3005
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07003006static void battery_insertion_check(struct qpnp_bms_chip *chip)
3007{
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003008 bool present = is_battery_present(chip);
3009
3010 mutex_lock(&chip->vbat_monitor_mutex);
3011 if (chip->battery_present != present) {
3012 if (chip->battery_present != -EINVAL) {
3013 if (present) {
3014 setup_vbat_monitoring(chip);
3015 chip->new_battery = true;
3016 } else {
3017 reset_vbat_monitoring(chip);
3018 }
3019 }
3020 chip->battery_present = present;
3021 /* a new battery was inserted or removed, so force a soc
3022 * recalculation to update the SoC */
3023 schedule_work(&chip->recalc_work);
3024 }
3025 mutex_unlock(&chip->vbat_monitor_mutex);
3026}
3027
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003028/* Returns capacity as a SoC percentage between 0 and 100 */
3029static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
3030{
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08003031 return report_state_of_charge(chip);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003032}
3033
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003034static void qpnp_bms_external_power_changed(struct power_supply *psy)
3035{
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07003036 struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
3037 bms_psy);
3038
3039 battery_insertion_check(chip);
3040 battery_status_check(chip);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003041}
3042
3043static int qpnp_bms_power_get_property(struct power_supply *psy,
3044 enum power_supply_property psp,
3045 union power_supply_propval *val)
3046{
3047 struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
3048 bms_psy);
3049
3050 switch (psp) {
3051 case POWER_SUPPLY_PROP_CAPACITY:
3052 val->intval = get_prop_bms_capacity(chip);
3053 break;
3054 case POWER_SUPPLY_PROP_CURRENT_NOW:
3055 val->intval = get_prop_bms_current_now(chip);
3056 break;
Xiaozhe Shi6dc56f12013-05-02 15:56:55 -07003057 case POWER_SUPPLY_PROP_RESISTANCE:
3058 val->intval = get_prop_bms_batt_resistance(chip);
3059 break;
Xiaozhe Shifb37f3b2013-05-20 16:56:19 -07003060 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
3061 val->intval = get_prop_bms_charge_counter(chip);
3062 break;
Xiaozhe Shif3da8622013-06-10 14:50:56 -07003063 case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
3064 val->intval = get_prop_bms_charge_counter_shadow(chip);
3065 break;
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003066 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
3067 val->intval = get_prop_bms_charge_full_design(chip);
3068 break;
Anirudh Ghayalc9d981a2013-06-24 09:50:33 +05303069 case POWER_SUPPLY_PROP_CHARGE_FULL:
3070 val->intval = get_prop_bms_charge_full(chip);
3071 break;
Anirudh Ghayal9dd582d2013-06-07 17:48:58 +05303072 case POWER_SUPPLY_PROP_CYCLE_COUNT:
3073 val->intval = chip->charge_cycles;
3074 break;
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003075 default:
3076 return -EINVAL;
3077 }
3078 return 0;
3079}
3080
Xiaozhe Shibdf14742012-12-05 12:41:48 -08003081#define OCV_USE_LIMIT_EN BIT(7)
3082static int set_ocv_voltage_thresholds(struct qpnp_bms_chip *chip,
3083 int low_voltage_threshold,
3084 int high_voltage_threshold)
3085{
3086 uint16_t low_voltage_raw, high_voltage_raw;
3087 int rc;
3088
3089 low_voltage_raw = convert_vbatt_uv_to_raw(chip,
3090 low_voltage_threshold);
3091 high_voltage_raw = convert_vbatt_uv_to_raw(chip,
3092 high_voltage_threshold);
3093 rc = qpnp_write_wrapper(chip, (u8 *)&low_voltage_raw,
3094 chip->base + BMS1_OCV_USE_LOW_LIMIT_THR0, 2);
3095 if (rc) {
3096 pr_err("Failed to set ocv low voltage threshold: %d\n", rc);
3097 return rc;
3098 }
3099 rc = qpnp_write_wrapper(chip, (u8 *)&high_voltage_raw,
3100 chip->base + BMS1_OCV_USE_HIGH_LIMIT_THR0, 2);
3101 if (rc) {
3102 pr_err("Failed to set ocv high voltage threshold: %d\n", rc);
3103 return rc;
3104 }
3105 rc = qpnp_masked_write(chip, BMS1_OCV_USE_LIMIT_CTL,
3106 OCV_USE_LIMIT_EN, OCV_USE_LIMIT_EN);
3107 if (rc) {
3108 pr_err("Failed to enabled ocv voltage thresholds: %d\n", rc);
3109 return rc;
3110 }
3111 pr_debug("ocv low threshold set to %d uv or 0x%x raw\n",
3112 low_voltage_threshold, low_voltage_raw);
3113 pr_debug("ocv high threshold set to %d uv or 0x%x raw\n",
3114 high_voltage_threshold, high_voltage_raw);
3115 return 0;
3116}
3117
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003118static void read_shutdown_soc_and_iavg(struct qpnp_bms_chip *chip)
3119{
3120 int rc;
3121 u8 temp;
3122
3123 if (chip->ignore_shutdown_soc) {
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08003124 chip->shutdown_soc_invalid = true;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003125 chip->shutdown_soc = 0;
3126 chip->shutdown_iavg_ma = 0;
3127 } else {
3128 rc = qpnp_read_wrapper(chip, &temp,
3129 chip->base + IAVG_STORAGE_REG, 1);
3130 if (rc) {
3131 pr_err("failed to read addr = %d %d assuming %d\n",
3132 chip->base + IAVG_STORAGE_REG, rc,
3133 IAVG_START);
3134 chip->shutdown_iavg_ma = IAVG_START;
Xiaozhe Shif5f966d2013-02-19 14:23:11 -08003135 } else if (temp == IAVG_INVALID) {
3136 pr_err("invalid iavg read from BMS1_DATA_REG_1, using %d\n",
3137 IAVG_START);
3138 chip->shutdown_iavg_ma = IAVG_START;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003139 } else {
3140 if (temp == 0) {
3141 chip->shutdown_iavg_ma = IAVG_START;
3142 } else {
3143 chip->shutdown_iavg_ma = IAVG_START
3144 + IAVG_STEP_SIZE_MA * (temp + 1);
3145 }
3146 }
3147
3148 rc = qpnp_read_wrapper(chip, &temp,
3149 chip->base + SOC_STORAGE_REG, 1);
3150 if (rc) {
3151 pr_err("failed to read addr = %d %d\n",
3152 chip->base + SOC_STORAGE_REG, rc);
3153 } else {
3154 chip->shutdown_soc = temp;
3155
Xiaozhe Shic7cbd052013-03-29 12:03:11 -07003156 if (chip->shutdown_soc == SOC_INVALID) {
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003157 pr_debug("No shutdown soc available\n");
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08003158 chip->shutdown_soc_invalid = true;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003159 chip->shutdown_iavg_ma = 0;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003160 }
3161 }
3162 }
3163
Anirudh Ghayale0c02932013-07-08 16:26:35 +05303164 /* read the SOC storage to determine if there was a battery removal */
3165 rc = qpnp_read_wrapper(chip, &temp, chip->base + SOC_STORAGE_REG, 1);
3166 if (!rc) {
3167 if (temp == SOC_INVALID)
3168 chip->battery_removed = true;
3169 }
3170
3171
3172 pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d, battery_removed = %d\n",
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003173 chip->shutdown_soc,
3174 chip->shutdown_iavg_ma,
Anirudh Ghayale0c02932013-07-08 16:26:35 +05303175 chip->shutdown_soc_invalid,
3176 chip->battery_removed);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003177}
3178
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003179static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *_chip)
3180{
3181 struct qpnp_bms_chip *chip = _chip;
3182
3183 pr_debug("ocv_thr irq triggered\n");
3184 bms_stay_awake(&chip->soc_wake_source);
3185 schedule_work(&chip->recalc_work);
3186 return IRQ_HANDLED;
3187}
3188
3189static irqreturn_t bms_sw_cc_thr_irq_handler(int irq, void *_chip)
3190{
3191 struct qpnp_bms_chip *chip = _chip;
3192
3193 pr_debug("sw_cc_thr irq triggered\n");
3194 bms_stay_awake(&chip->soc_wake_source);
3195 schedule_work(&chip->recalc_work);
3196 return IRQ_HANDLED;
3197}
3198
Xiaozhe Shiaf203c22013-06-19 12:01:38 -07003199static int64_t read_battery_id(struct qpnp_bms_chip *chip)
Xiaozhe Shi73a65692012-09-18 17:51:57 -07003200{
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003201 int rc;
3202 struct qpnp_vadc_result result;
3203
3204 rc = qpnp_vadc_read(LR_MUX2_BAT_ID, &result);
3205 if (rc) {
3206 pr_err("error reading batt id channel = %d, rc = %d\n",
3207 LR_MUX2_BAT_ID, rc);
3208 return rc;
3209 }
Xiaozhe Shiaf203c22013-06-19 12:01:38 -07003210
3211 return result.physical;
Xiaozhe Shi73a65692012-09-18 17:51:57 -07003212}
3213
3214static int set_battery_data(struct qpnp_bms_chip *chip)
3215{
3216 int64_t battery_id;
Xiaozhe Shiaf203c22013-06-19 12:01:38 -07003217 int rc;
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003218 struct bms_battery_data *batt_data;
Xiaozhe Shiaf203c22013-06-19 12:01:38 -07003219 struct device_node *node;
Xiaozhe Shi73a65692012-09-18 17:51:57 -07003220
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003221 if (chip->batt_type == BATT_DESAY) {
3222 batt_data = &desay_5200_data;
3223 } else if (chip->batt_type == BATT_PALLADIUM) {
3224 batt_data = &palladium_1500_data;
3225 } else if (chip->batt_type == BATT_OEM) {
3226 batt_data = &oem_batt_data;
Wu Fenglin2ac88aa2013-04-25 12:43:40 +08003227 } else if (chip->batt_type == BATT_QRD_4V35_2000MAH) {
3228 batt_data = &QRD_4v35_2000mAh_data;
tingtingf50326f2013-06-05 15:07:24 +08003229 } else if (chip->batt_type == BATT_QRD_4V2_1300MAH) {
3230 batt_data = &qrd_4v2_1300mah_data;
Xiaozhe Shi73a65692012-09-18 17:51:57 -07003231 } else {
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003232 battery_id = read_battery_id(chip);
3233 if (battery_id < 0) {
3234 pr_err("cannot read battery id err = %lld\n",
3235 battery_id);
3236 return battery_id;
3237 }
3238
Xiaozhe Shiaf203c22013-06-19 12:01:38 -07003239 node = of_find_node_by_name(chip->spmi->dev.of_node,
3240 "qcom,battery-data");
3241 if (node) {
3242 batt_data = kzalloc(sizeof(struct bms_battery_data),
3243 GFP_KERNEL);
3244 batt_data->fcc_temp_lut = kzalloc(
3245 sizeof(struct single_row_lut),
3246 GFP_KERNEL);
3247 batt_data->pc_temp_ocv_lut = kzalloc(
3248 sizeof(struct pc_temp_ocv_lut),
3249 GFP_KERNEL);
3250 batt_data->rbatt_sf_lut = kzalloc(
3251 sizeof(struct sf_lut), GFP_KERNEL);
3252
3253 rc = of_batterydata_read_data(node,
3254 batt_data, battery_id);
3255 if (rc) {
3256 pr_err("battery data load failed, using palladium 1500\n");
3257 kfree(batt_data->fcc_temp_lut);
3258 kfree(batt_data->pc_temp_ocv_lut);
3259 kfree(batt_data->rbatt_sf_lut);
3260 kfree(batt_data);
3261 batt_data = &palladium_1500_data;
3262 }
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003263 } else {
3264 pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
3265 battery_id);
3266 batt_data = &palladium_1500_data;
3267 }
Xiaozhe Shi73a65692012-09-18 17:51:57 -07003268 }
3269
Xiaozhe Shi976618f2013-04-30 10:49:30 -07003270 chip->fcc_mah = batt_data->fcc;
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003271 chip->fcc_temp_lut = batt_data->fcc_temp_lut;
3272 chip->fcc_sf_lut = batt_data->fcc_sf_lut;
3273 chip->pc_temp_ocv_lut = batt_data->pc_temp_ocv_lut;
3274 chip->pc_sf_lut = batt_data->pc_sf_lut;
3275 chip->rbatt_sf_lut = batt_data->rbatt_sf_lut;
3276 chip->default_rbatt_mohm = batt_data->default_rbatt_mohm;
Xiaozhe Shi1a10aff2013-04-01 15:40:05 -07003277 chip->rbatt_capacitive_mohm = batt_data->rbatt_capacitive_mohm;
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -07003278 chip->flat_ocv_threshold_uv = batt_data->flat_ocv_threshold_uv;
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003279
Xiaozhe Shiaf203c22013-06-19 12:01:38 -07003280 /* Override battery properties if specified in the battery profile */
3281 if (batt_data->max_voltage_uv >= 0)
3282 chip->max_voltage_uv = batt_data->max_voltage_uv;
3283 if (batt_data->cutoff_uv >= 0)
3284 chip->v_cutoff_uv = batt_data->cutoff_uv;
3285 if (batt_data->iterm_ua >= 0)
3286 chip->chg_term_ua = batt_data->iterm_ua;
3287
Xiaozhe Shi77a5b052012-12-14 16:37:45 -08003288 if (chip->pc_temp_ocv_lut == NULL) {
3289 pr_err("temp ocv lut table is NULL\n");
3290 return -EINVAL;
3291 }
3292 return 0;
Xiaozhe Shi73a65692012-09-18 17:51:57 -07003293}
3294
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003295#define SPMI_PROP_READ(chip_prop, qpnp_spmi_property, retval) \
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003296do { \
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003297 retval = of_property_read_u32(chip->spmi->dev.of_node, \
Xiaozhe Shi9bd24622013-01-23 15:54:54 -08003298 "qcom," qpnp_spmi_property, \
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003299 &chip->chip_prop); \
3300 if (retval) { \
3301 pr_err("Error reading " #qpnp_spmi_property \
3302 " property %d\n", rc); \
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003303 return -EINVAL; \
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003304 } \
3305} while (0)
3306
Anirudh Ghayale0c02932013-07-08 16:26:35 +05303307#define SPMI_PROP_READ_BOOL(chip_prop, qpnp_spmi_property) \
3308do { \
3309 chip->chip_prop = of_property_read_bool(chip->spmi->dev.of_node,\
3310 "qcom," qpnp_spmi_property); \
3311} while (0)
3312
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003313static inline int bms_read_properties(struct qpnp_bms_chip *chip)
3314{
3315 int rc;
3316
Xiaozhe Shid0a79542012-11-06 10:00:38 -08003317 SPMI_PROP_READ(r_sense_uohm, "r-sense-uohm", rc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003318 SPMI_PROP_READ(v_cutoff_uv, "v-cutoff-uv", rc);
3319 SPMI_PROP_READ(max_voltage_uv, "max-voltage-uv", rc);
3320 SPMI_PROP_READ(r_conn_mohm, "r-conn-mohm", rc);
3321 SPMI_PROP_READ(chg_term_ua, "chg-term-ua", rc);
3322 SPMI_PROP_READ(shutdown_soc_valid_limit,
3323 "shutdown-soc-valid-limit", rc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003324 SPMI_PROP_READ(adjust_soc_low_threshold,
3325 "adjust-soc-low-threshold", rc);
3326 SPMI_PROP_READ(batt_type, "batt-type", rc);
3327 SPMI_PROP_READ(low_soc_calc_threshold,
3328 "low-soc-calculate-soc-threshold", rc);
3329 SPMI_PROP_READ(low_soc_calculate_soc_ms,
3330 "low-soc-calculate-soc-ms", rc);
3331 SPMI_PROP_READ(calculate_soc_ms, "calculate-soc-ms", rc);
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003332 chip->use_external_rsense = of_property_read_bool(
3333 chip->spmi->dev.of_node,
Xiaozhe Shi9bd24622013-01-23 15:54:54 -08003334 "qcom,use-external-rsense");
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003335 chip->ignore_shutdown_soc = of_property_read_bool(
3336 chip->spmi->dev.of_node,
Xiaozhe Shi9bd24622013-01-23 15:54:54 -08003337 "qcom,ignore-shutdown-soc");
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08003338 chip->use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
Xiaozhe Shi9bd24622013-01-23 15:54:54 -08003339 "qcom,use-voltage-soc");
Xiaozhe Shibdf14742012-12-05 12:41:48 -08003340 chip->use_ocv_thresholds = of_property_read_bool(
3341 chip->spmi->dev.of_node,
Xiaozhe Shi9bd24622013-01-23 15:54:54 -08003342 "qcom,use-ocv-thresholds");
Xiaozhe Shi0ac7a002013-03-26 13:14:03 -07003343 SPMI_PROP_READ(high_ocv_correction_limit_uv,
3344 "high-ocv-correction-limit-uv", rc);
3345 SPMI_PROP_READ(low_ocv_correction_limit_uv,
3346 "low-ocv-correction-limit-uv", rc);
3347 SPMI_PROP_READ(hold_soc_est,
3348 "hold-soc-est", rc);
3349 SPMI_PROP_READ(ocv_high_threshold_uv,
3350 "ocv-voltage-high-threshold-uv", rc);
Xiaozhe Shibdf14742012-12-05 12:41:48 -08003351 SPMI_PROP_READ(ocv_low_threshold_uv,
3352 "ocv-voltage-low-threshold-uv", rc);
Xiaozhe Shi4be85782013-02-22 17:33:40 -08003353 SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
Xiaozhe Shi535494d2013-04-05 12:27:51 -07003354 SPMI_PROP_READ(temperature_margin, "tm-temp-margin", rc);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003355
3356 if (chip->adjust_soc_low_threshold >= 45)
3357 chip->adjust_soc_low_threshold = 45;
3358
Anirudh Ghayale0c02932013-07-08 16:26:35 +05303359 SPMI_PROP_READ_BOOL(enable_fcc_learning, "enable-fcc-learning");
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05303360 if (chip->enable_fcc_learning) {
3361 SPMI_PROP_READ(min_fcc_learning_soc,
3362 "min-fcc-learning-soc", rc);
3363 SPMI_PROP_READ(min_fcc_ocv_pc,
3364 "min-fcc-ocv-pc", rc);
3365 SPMI_PROP_READ(min_fcc_learning_samples,
3366 "min-fcc-learning-samples", rc);
Anirudh Ghayale0c02932013-07-08 16:26:35 +05303367 SPMI_PROP_READ(fcc_resolution,
3368 "fcc-resolution", rc);
3369 if (chip->min_fcc_learning_samples > MAX_FCC_CYCLES)
3370 chip->min_fcc_learning_samples = MAX_FCC_CYCLES;
3371 chip->fcc_learning_samples = devm_kzalloc(&chip->spmi->dev,
3372 (sizeof(struct fcc_sample) *
3373 chip->min_fcc_learning_samples), GFP_KERNEL);
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05303374 pr_debug("min-fcc-soc=%d, min-fcc-pc=%d, min-fcc-cycles=%d\n",
3375 chip->min_fcc_learning_soc, chip->min_fcc_ocv_pc,
3376 chip->min_fcc_learning_samples);
3377 }
3378
Xiaozhe Shid0a79542012-11-06 10:00:38 -08003379 pr_debug("dts data: r_sense_uohm:%d, v_cutoff_uv:%d, max_v:%d\n",
3380 chip->r_sense_uohm, chip->v_cutoff_uv,
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003381 chip->max_voltage_uv);
3382 pr_debug("r_conn:%d, shutdown_soc: %d, adjust_soc_low:%d\n",
3383 chip->r_conn_mohm, chip->shutdown_soc_valid_limit,
3384 chip->adjust_soc_low_threshold);
Xiaozhe Shi561ebf72013-03-25 13:51:27 -07003385 pr_debug("chg_term_ua:%d, batt_type:%d\n",
3386 chip->chg_term_ua,
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003387 chip->batt_type);
Xiaozhe Shi781b0a22012-11-05 17:18:27 -08003388 pr_debug("ignore_shutdown_soc:%d, use_voltage_soc:%d\n",
Xiaozhe Shi79d6c1d2012-11-26 13:19:50 -08003389 chip->ignore_shutdown_soc, chip->use_voltage_soc);
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003390 pr_debug("use external rsense: %d\n", chip->use_external_rsense);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003391 return 0;
3392}
3393
3394static inline void bms_initialize_constants(struct qpnp_bms_chip *chip)
3395{
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003396 chip->prev_pc_unusable = -EINVAL;
3397 chip->soc_at_cv = -EINVAL;
3398 chip->calculated_soc = -EINVAL;
Xiaozhe Shie118c692012-09-24 15:17:43 -07003399 chip->last_soc = -EINVAL;
Xiaozhe Shi7edde5d2012-09-26 11:23:09 -07003400 chip->last_soc_est = -EINVAL;
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003401 chip->battery_present = -EINVAL;
Xiaozhe Shi890fbf42013-05-02 16:42:53 -07003402 chip->battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
Xiaozhe Shif36d2862013-01-04 10:17:35 -08003403 chip->last_cc_uah = INT_MIN;
Abhijeet Dharmapurikar15f30fb2012-12-27 17:20:29 -08003404 chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
3405 chip->prev_last_good_ocv_raw = OCV_RAW_UNINITIALIZED;
Xiaozhe Shie118c692012-09-24 15:17:43 -07003406 chip->first_time_calc_soc = 1;
3407 chip->first_time_calc_uuc = 1;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003408}
3409
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003410#define SPMI_FIND_IRQ(chip, irq_name) \
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003411do { \
3412 chip->irq_name##_irq.irq = spmi_get_irq_byname(chip->spmi, \
3413 resource, #irq_name); \
3414 if (chip->irq_name##_irq.irq < 0) { \
3415 pr_err("Unable to get " #irq_name " irq\n"); \
3416 return -ENXIO; \
3417 } \
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003418} while (0)
3419
3420static int bms_find_irqs(struct qpnp_bms_chip *chip,
3421 struct spmi_resource *resource)
3422{
3423 SPMI_FIND_IRQ(chip, sw_cc_thr);
3424 SPMI_FIND_IRQ(chip, ocv_thr);
3425 return 0;
3426}
3427
3428#define SPMI_REQUEST_IRQ(chip, rc, irq_name) \
3429do { \
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003430 rc = devm_request_irq(chip->dev, chip->irq_name##_irq.irq, \
3431 bms_##irq_name##_irq_handler, \
3432 IRQF_TRIGGER_RISING, #irq_name, chip); \
3433 if (rc < 0) { \
3434 pr_err("Unable to request " #irq_name " irq: %d\n", rc);\
3435 return -ENXIO; \
3436 } \
3437} while (0)
3438
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003439static int bms_request_irqs(struct qpnp_bms_chip *chip)
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003440{
3441 int rc;
3442
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003443 SPMI_REQUEST_IRQ(chip, rc, sw_cc_thr);
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003444 enable_irq_wake(chip->sw_cc_thr_irq.irq);
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003445 SPMI_REQUEST_IRQ(chip, rc, ocv_thr);
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003446 enable_irq_wake(chip->ocv_thr_irq.irq);
3447 return 0;
3448}
3449
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003450#define REG_OFFSET_PERP_TYPE 0x04
3451#define REG_OFFSET_PERP_SUBTYPE 0x05
3452#define BMS_BMS_TYPE 0xD
Xiaozhe Shief6274c2013-03-06 15:23:52 -08003453#define BMS_BMS1_SUBTYPE 0x1
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003454#define BMS_IADC_TYPE 0x8
Xiaozhe Shief6274c2013-03-06 15:23:52 -08003455#define BMS_IADC1_SUBTYPE 0x3
3456#define BMS_IADC2_SUBTYPE 0x5
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003457
3458static int register_spmi(struct qpnp_bms_chip *chip, struct spmi_device *spmi)
3459{
3460 struct spmi_resource *spmi_resource;
3461 struct resource *resource;
3462 int rc;
3463 u8 type, subtype;
3464
3465 chip->dev = &(spmi->dev);
3466 chip->spmi = spmi;
3467
3468 spmi_for_each_container_dev(spmi_resource, spmi) {
3469 if (!spmi_resource) {
3470 pr_err("qpnp_bms: spmi resource absent\n");
3471 return -ENXIO;
3472 }
3473
3474 resource = spmi_get_resource(spmi, spmi_resource,
3475 IORESOURCE_MEM, 0);
3476 if (!(resource && resource->start)) {
3477 pr_err("node %s IO resource absent!\n",
3478 spmi->dev.of_node->full_name);
3479 return -ENXIO;
3480 }
3481
3482 rc = qpnp_read_wrapper(chip, &type,
3483 resource->start + REG_OFFSET_PERP_TYPE, 1);
3484 if (rc) {
3485 pr_err("Peripheral type read failed rc=%d\n", rc);
3486 return rc;
3487 }
3488 rc = qpnp_read_wrapper(chip, &subtype,
3489 resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
3490 if (rc) {
3491 pr_err("Peripheral subtype read failed rc=%d\n", rc);
3492 return rc;
3493 }
3494
Xiaozhe Shief6274c2013-03-06 15:23:52 -08003495 if (type == BMS_BMS_TYPE && subtype == BMS_BMS1_SUBTYPE) {
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003496 chip->base = resource->start;
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003497 rc = bms_find_irqs(chip, spmi_resource);
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003498 if (rc) {
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003499 pr_err("Could not find irqs\n");
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003500 return rc;
3501 }
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003502 } else if (type == BMS_IADC_TYPE
Xiaozhe Shief6274c2013-03-06 15:23:52 -08003503 && (subtype == BMS_IADC1_SUBTYPE
3504 || subtype == BMS_IADC2_SUBTYPE)) {
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003505 chip->iadc_base = resource->start;
3506 } else {
3507 pr_err("Invalid peripheral start=0x%x type=0x%x, subtype=0x%x\n",
3508 resource->start, type, subtype);
3509 }
3510 }
3511
3512 if (chip->base == 0) {
3513 dev_err(&spmi->dev, "BMS peripheral was not registered\n");
3514 return -EINVAL;
3515 }
3516 if (chip->iadc_base == 0) {
3517 dev_err(&spmi->dev, "BMS_IADC peripheral was not registered\n");
3518 return -EINVAL;
3519 }
3520
3521 return 0;
3522}
3523
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -07003524#define ADC_CH_SEL_MASK 0x7
3525#define ADC_INT_RSNSN_CTL_MASK 0x3
3526#define ADC_INT_RSNSN_CTL_VALUE_EXT_RENSE 0x2
3527#define FAST_AVG_EN_MASK 0x80
3528#define FAST_AVG_EN_VALUE_EXT_RSENSE 0x80
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003529static int read_iadc_channel_select(struct qpnp_bms_chip *chip)
3530{
3531 u8 iadc_channel_select;
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08003532 int32_t rds_rsense_nohm;
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003533 int rc;
3534
3535 rc = qpnp_read_wrapper(chip, &iadc_channel_select,
3536 chip->iadc_base + IADC1_BMS_ADC_CH_SEL_CTL, 1);
3537 if (rc) {
3538 pr_err("Error reading bms_iadc channel register %d\n", rc);
3539 return rc;
3540 }
3541
3542 iadc_channel_select &= ADC_CH_SEL_MASK;
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08003543 if (iadc_channel_select != EXTERNAL_RSENSE
3544 && iadc_channel_select != INTERNAL_RSENSE) {
3545 pr_err("IADC1_BMS_IADC configured incorrectly. Selected channel = %d\n",
3546 iadc_channel_select);
3547 return -EINVAL;
3548 }
3549
3550 if (chip->use_external_rsense) {
3551 pr_debug("External rsense selected\n");
3552 if (iadc_channel_select == INTERNAL_RSENSE) {
3553 pr_debug("Internal rsense detected; Changing rsense to external\n");
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003554 rc = qpnp_masked_write_iadc(chip,
3555 IADC1_BMS_ADC_CH_SEL_CTL,
3556 ADC_CH_SEL_MASK,
3557 EXTERNAL_RSENSE);
3558 if (rc) {
3559 pr_err("Unable to set IADC1_BMS channel %x to %x: %d\n",
3560 IADC1_BMS_ADC_CH_SEL_CTL,
3561 EXTERNAL_RSENSE, rc);
3562 return rc;
3563 }
Xiaozhe Shif3da8622013-06-10 14:50:56 -07003564 reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
Xiaozhe Shi80ba88d2013-04-05 10:23:34 -07003565 chip->software_cc_uah = 0;
Xiaozhe Shif3da8622013-06-10 14:50:56 -07003566 chip->software_shdw_cc_uah = 0;
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003567 }
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08003568 } else {
3569 pr_debug("Internal rsense selected\n");
3570 if (iadc_channel_select == EXTERNAL_RSENSE) {
3571 pr_debug("External rsense detected; Changing rsense to internal\n");
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003572 rc = qpnp_masked_write_iadc(chip,
3573 IADC1_BMS_ADC_CH_SEL_CTL,
3574 ADC_CH_SEL_MASK,
3575 INTERNAL_RSENSE);
3576 if (rc) {
3577 pr_err("Unable to set IADC1_BMS channel %x to %x: %d\n",
3578 IADC1_BMS_ADC_CH_SEL_CTL,
3579 INTERNAL_RSENSE, rc);
3580 return rc;
3581 }
Xiaozhe Shif3da8622013-06-10 14:50:56 -07003582 reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
3583 chip->software_shdw_cc_uah = 0;
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003584 }
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08003585
3586 rc = qpnp_iadc_get_rsense(&rds_rsense_nohm);
3587 if (rc) {
3588 pr_err("Unable to read RDS resistance value from IADC; rc = %d\n",
3589 rc);
3590 return rc;
3591 }
Xiaozhe Shid0a79542012-11-06 10:00:38 -08003592 chip->r_sense_uohm = rds_rsense_nohm/1000;
3593 pr_debug("rds_rsense = %d nOhm, saved as %d uOhm\n",
3594 rds_rsense_nohm, chip->r_sense_uohm);
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003595 }
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -07003596 /* prevent shorting of leads by IADC_BMS when external Rsense is used */
3597 if (chip->use_external_rsense) {
3598 if (chip->iadc_bms_revision2 > CALIB_WRKARND_DIG_MAJOR_MAX) {
3599 rc = qpnp_masked_write_iadc(chip,
3600 IADC1_BMS_ADC_INT_RSNSN_CTL,
3601 ADC_INT_RSNSN_CTL_MASK,
3602 ADC_INT_RSNSN_CTL_VALUE_EXT_RENSE);
3603 if (rc) {
3604 pr_err("Unable to set batfet config %x to %x: %d\n",
3605 IADC1_BMS_ADC_INT_RSNSN_CTL,
3606 ADC_INT_RSNSN_CTL_VALUE_EXT_RENSE, rc);
3607 return rc;
3608 }
3609 } else {
3610 /* In older PMICS use FAST_AVG_EN register bit 7 */
3611 rc = qpnp_masked_write_iadc(chip,
3612 IADC1_BMS_FAST_AVG_EN,
3613 FAST_AVG_EN_MASK,
3614 FAST_AVG_EN_VALUE_EXT_RSENSE);
3615 if (rc) {
3616 pr_err("Unable to set batfet config %x to %x: %d\n",
3617 IADC1_BMS_FAST_AVG_EN,
3618 FAST_AVG_EN_VALUE_EXT_RSENSE, rc);
3619 return rc;
3620 }
3621 }
3622 }
3623
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003624 return 0;
3625}
3626
Xiaozhe Shi535494d2013-04-05 12:27:51 -07003627static int refresh_die_temp_monitor(struct qpnp_bms_chip *chip)
3628{
3629 struct qpnp_vadc_result result;
3630 int rc;
3631
3632 rc = qpnp_vadc_read(DIE_TEMP, &result);
3633
3634 pr_debug("low = %lld, high = %lld\n",
3635 result.physical - chip->temperature_margin,
3636 result.physical + chip->temperature_margin);
3637 chip->die_temp_monitor_params.high_temp = result.physical
3638 + chip->temperature_margin;
3639 chip->die_temp_monitor_params.low_temp = result.physical
3640 - chip->temperature_margin;
3641 chip->die_temp_monitor_params.state_request =
3642 ADC_TM_HIGH_LOW_THR_ENABLE;
3643 return qpnp_adc_tm_channel_measure(&chip->die_temp_monitor_params);
3644}
3645
3646static void btm_notify_die_temp(enum qpnp_tm_state state, void *ctx)
3647{
3648 struct qpnp_bms_chip *chip = ctx;
3649 struct qpnp_vadc_result result;
3650 int rc;
3651
3652 rc = qpnp_vadc_read(DIE_TEMP, &result);
3653
3654 if (state == ADC_TM_LOW_STATE)
3655 pr_debug("low state triggered\n");
3656 else if (state == ADC_TM_HIGH_STATE)
3657 pr_debug("high state triggered\n");
3658 pr_debug("die temp = %lld, raw = 0x%x\n",
3659 result.physical, result.adc_code);
3660 schedule_work(&chip->recalc_work);
3661 refresh_die_temp_monitor(chip);
3662}
3663
3664static int setup_die_temp_monitoring(struct qpnp_bms_chip *chip)
3665{
3666 int rc = qpnp_adc_tm_is_ready();
3667 if (rc) {
3668 pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
3669 return -EPROBE_DEFER;
3670 }
3671 chip->die_temp_monitor_params.channel = DIE_TEMP;
3672 chip->die_temp_monitor_params.btm_ctx = (void *)chip;
3673 chip->die_temp_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
3674 chip->die_temp_monitor_params.threshold_notification =
3675 &btm_notify_die_temp;
3676 refresh_die_temp_monitor(chip);
3677 if (rc) {
3678 pr_err("tm setup failed: %d\n", rc);
3679 return rc;
3680 }
3681 pr_debug("setup complete\n");
3682 return 0;
3683}
3684
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003685static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003686{
3687 struct qpnp_bms_chip *chip;
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -07003688 bool warm_reset;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003689 int rc, vbatt;
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003690
3691 chip = kzalloc(sizeof *chip, GFP_KERNEL);
3692
3693 if (chip == NULL) {
3694 pr_err("kzalloc() failed.\n");
3695 return -ENOMEM;
3696 }
3697
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003698 rc = qpnp_vadc_is_ready();
3699 if (rc) {
3700 pr_info("vadc not ready: %d, deferring probe\n", rc);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003701 rc = -EPROBE_DEFER;
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003702 goto error_read;
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003703 }
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003704
3705 rc = qpnp_iadc_is_ready();
3706 if (rc) {
3707 pr_info("iadc not ready: %d, deferring probe\n", rc);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003708 rc = -EPROBE_DEFER;
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003709 goto error_read;
3710 }
3711
Xiaozhe Shi3eaf0b62013-07-11 09:48:08 -07003712 mutex_init(&chip->bms_output_lock);
3713 mutex_init(&chip->last_ocv_uv_mutex);
3714 mutex_init(&chip->vbat_monitor_mutex);
3715 mutex_init(&chip->soc_invalidation_mutex);
3716 mutex_init(&chip->last_soc_mutex);
3717
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -07003718 warm_reset = qpnp_pon_is_warm_reset();
3719 rc = warm_reset;
3720 if (rc < 0)
3721 goto error_read;
3722
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003723 rc = register_spmi(chip, spmi);
3724 if (rc) {
3725 pr_err("error registering spmi resource %d\n", rc);
3726 goto error_resource;
3727 }
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003728
3729 rc = qpnp_read_wrapper(chip, &chip->revision1,
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -07003730 chip->base + REVISION1, 1);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003731 if (rc) {
3732 pr_err("error reading version register %d\n", rc);
3733 goto error_read;
3734 }
3735
3736 rc = qpnp_read_wrapper(chip, &chip->revision2,
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -07003737 chip->base + REVISION2, 1);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003738 if (rc) {
3739 pr_err("Error reading version register %d\n", rc);
3740 goto error_read;
3741 }
Xiaozhe Shia045a562012-11-28 16:55:39 -08003742 pr_debug("BMS version: %hhu.%hhu\n", chip->revision2, chip->revision1);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003743
Abhijeet Dharmapurikar604461d2013-07-09 13:34:33 -07003744 rc = qpnp_read_wrapper(chip, &chip->iadc_bms_revision2,
3745 chip->iadc_base + REVISION2, 1);
3746 if (rc) {
3747 pr_err("Error reading version register %d\n", rc);
3748 goto error_read;
3749 }
3750
3751 rc = qpnp_read_wrapper(chip, &chip->iadc_bms_revision1,
3752 chip->iadc_base + REVISION1, 1);
3753 if (rc) {
3754 pr_err("Error reading version register %d\n", rc);
3755 goto error_read;
3756 }
3757 pr_debug("IADC_BMS version: %hhu.%hhu\n",
3758 chip->iadc_bms_revision2, chip->iadc_bms_revision1);
3759
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003760 rc = bms_read_properties(chip);
3761 if (rc) {
3762 pr_err("Unable to read all bms properties, rc = %d\n", rc);
3763 goto error_read;
3764 }
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003765
Xiaozhe Shidffbe692012-12-11 15:35:46 -08003766 rc = read_iadc_channel_select(chip);
3767 if (rc) {
3768 pr_err("Unable to get iadc selected channel = %d\n", rc);
3769 goto error_read;
3770 }
3771
Xiaozhe Shibdf14742012-12-05 12:41:48 -08003772 if (chip->use_ocv_thresholds) {
3773 rc = set_ocv_voltage_thresholds(chip,
3774 chip->ocv_low_threshold_uv,
3775 chip->ocv_high_threshold_uv);
3776 if (rc) {
3777 pr_err("Could not set ocv voltage thresholds: %d\n",
3778 rc);
3779 goto error_read;
3780 }
3781 }
3782
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003783 rc = set_battery_data(chip);
3784 if (rc) {
3785 pr_err("Bad battery data %d\n", rc);
3786 goto error_read;
3787 }
3788
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003789 bms_initialize_constants(chip);
3790
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003791 wakeup_source_init(&chip->soc_wake_source.source, "qpnp_soc_wake");
Xiaozhe Shi4be85782013-02-22 17:33:40 -08003792 wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
3793 "qpnp_low_voltage_lock");
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003794 wake_lock_init(&chip->cv_wake_lock, WAKE_LOCK_SUSPEND,
3795 "qpnp_cv_lock");
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003796 INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
3797 calculate_soc_work);
Xiaozhe Shi5cf7a672013-02-06 17:18:05 -08003798 INIT_WORK(&chip->recalc_work, recalculate_work);
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003799
3800 read_shutdown_soc_and_iavg(chip);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003801
Anirudh Ghayal9dd582d2013-06-07 17:48:58 +05303802 if (chip->enable_fcc_learning) {
Anirudh Ghayale0c02932013-07-08 16:26:35 +05303803 if (chip->battery_removed) {
3804 rc = discard_backup_fcc_data(chip);
3805 if (rc)
3806 pr_err("Could not discard backed-up FCC data\n");
3807 } else {
3808 rc = read_chgcycle_data_from_backup(chip);
3809 if (rc)
3810 pr_err("Unable to restore charge-cycle data\n");
3811
3812 rc = read_fcc_data_from_backup(chip);
3813 if (rc)
3814 pr_err("Unable to restore FCC-learning data\n");
3815 else
3816 attempt_learning_new_fcc(chip);
Anirudh Ghayal9dd582d2013-06-07 17:48:58 +05303817 }
3818 }
Anirudh Ghayald71d9f82013-06-05 11:11:46 +05303819
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003820 dev_set_drvdata(&spmi->dev, chip);
3821 device_init_wakeup(&spmi->dev, 1);
3822
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003823 rc = setup_vbat_monitoring(chip);
3824 if (rc < 0) {
3825 pr_err("failed to set up voltage notifications: %d\n", rc);
3826 goto error_setup;
Xiaozhe Shid5d21412013-02-06 17:14:41 -08003827 }
3828
Xiaozhe Shi535494d2013-04-05 12:27:51 -07003829 rc = setup_die_temp_monitoring(chip);
3830 if (rc < 0) {
3831 pr_err("failed to set up die temp notifications: %d\n", rc);
3832 goto error_setup;
3833 }
3834
Xiaozhe Shie7fafe62013-06-05 15:25:16 -07003835 battery_insertion_check(chip);
3836 battery_status_check(chip);
3837
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003838 calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
3839
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003840 /* setup & register the battery power supply */
3841 chip->bms_psy.name = "bms";
3842 chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
3843 chip->bms_psy.properties = msm_bms_power_props;
3844 chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
3845 chip->bms_psy.get_property = qpnp_bms_power_get_property;
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003846 chip->bms_psy.external_power_changed =
3847 qpnp_bms_external_power_changed;
3848 chip->bms_psy.supplied_to = qpnp_bms_supplicants;
3849 chip->bms_psy.num_supplicants = ARRAY_SIZE(qpnp_bms_supplicants);
3850
3851 rc = power_supply_register(chip->dev, &chip->bms_psy);
3852
3853 if (rc < 0) {
3854 pr_err("power_supply_register bms failed rc = %d\n", rc);
3855 goto unregister_dc;
3856 }
3857
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -07003858 chip->bms_psy_registered = true;
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003859 vbatt = 0;
Xiaozhe Shi36458962013-02-06 16:19:57 -08003860 rc = get_battery_voltage(&vbatt);
3861 if (rc) {
3862 pr_err("error reading vbat_sns adc channel = %d, rc = %d\n",
3863 VBAT_SNS, rc);
3864 goto unregister_dc;
3865 }
Xiaozhe Shicd7e5302012-10-17 12:29:53 -07003866
Abhijeet Dharmapurikar3bd4bbf2013-07-01 12:06:37 -07003867 rc = bms_request_irqs(chip);
3868 if (rc) {
3869 pr_err("error requesting bms irqs, rc = %d\n", rc);
3870 goto unregister_dc;
3871 }
3872
Xiaozhe Shi77ec38d2013-04-29 16:41:58 -07003873 pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u warm_reset = %d\n",
3874 get_prop_bms_capacity(chip), vbatt, chip->last_ocv_uv,
3875 chip->r_sense_uohm, warm_reset);
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003876 return 0;
3877
3878unregister_dc:
Abhijeet Dharmapurikar8e322492013-06-25 19:48:18 -07003879 chip->bms_psy_registered = false;
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003880 power_supply_unregister(&chip->bms_psy);
3881error_setup:
3882 dev_set_drvdata(&spmi->dev, NULL);
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003883 wakeup_source_trash(&chip->soc_wake_source.source);
Xiaozhe Shi4be85782013-02-22 17:33:40 -08003884 wake_lock_destroy(&chip->low_voltage_wake_lock);
Xiaozhe Shia6618a22013-03-27 10:26:29 -07003885 wake_lock_destroy(&chip->cv_wake_lock);
Xiaozhe Shic40b3972012-11-30 14:11:16 -08003886error_resource:
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003887error_read:
3888 kfree(chip);
3889 return rc;
3890}
3891
3892static int __devexit
3893qpnp_bms_remove(struct spmi_device *spmi)
3894{
3895 struct qpnp_bms_chip *chip = dev_get_drvdata(&spmi->dev);
3896
3897 dev_set_drvdata(&spmi->dev, NULL);
3898 kfree(chip);
3899 return 0;
3900}
3901
Xiaozhe Shid6168d82013-04-18 16:06:17 -07003902static int bms_suspend(struct device *dev)
3903{
3904 struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
3905
3906 cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
Xiaozhe Shi04da0992013-04-26 16:32:14 -07003907 chip->was_charging_at_sleep = is_battery_charging(chip);
Xiaozhe Shid6168d82013-04-18 16:06:17 -07003908 return 0;
3909}
3910
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003911static int bms_resume(struct device *dev)
3912{
3913 int rc;
Xiaozhe Shid6168d82013-04-18 16:06:17 -07003914 int soc_calc_period;
Xiaozhe Shid921f9f72013-05-23 18:55:15 -07003915 int time_until_next_recalc = 0;
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003916 unsigned long time_since_last_recalc;
3917 unsigned long tm_now_sec;
3918 struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
3919
3920 rc = get_current_time(&tm_now_sec);
3921 if (rc) {
3922 pr_err("Could not read current time: %d\n", rc);
Xiaozhe Shid921f9f72013-05-23 18:55:15 -07003923 } else {
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003924 if (chip->calculated_soc < chip->low_soc_calc_threshold)
3925 soc_calc_period = chip->low_soc_calculate_soc_ms;
3926 else
3927 soc_calc_period = chip->calculate_soc_ms;
Xiaozhe Shid921f9f72013-05-23 18:55:15 -07003928 time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
3929 pr_debug("Time since last recalc: %lu\n",
3930 time_since_last_recalc);
Xiaozhe Shid6168d82013-04-18 16:06:17 -07003931 time_until_next_recalc = max(0, soc_calc_period
3932 - (int)(time_since_last_recalc * 1000));
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003933 }
Xiaozhe Shid921f9f72013-05-23 18:55:15 -07003934
Xiaozhe Shi1ae8a952013-02-14 12:23:31 -08003935 if (time_until_next_recalc == 0)
3936 bms_stay_awake(&chip->soc_wake_source);
Xiaozhe Shid921f9f72013-05-23 18:55:15 -07003937 schedule_delayed_work(&chip->calculate_soc_delayed_work,
3938 round_jiffies_relative(msecs_to_jiffies
3939 (time_until_next_recalc)));
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003940 return 0;
3941}
3942
3943static const struct dev_pm_ops qpnp_bms_pm_ops = {
3944 .resume = bms_resume,
Xiaozhe Shid6168d82013-04-18 16:06:17 -07003945 .suspend = bms_suspend,
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003946};
3947
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003948static struct spmi_driver qpnp_bms_driver = {
3949 .probe = qpnp_bms_probe,
3950 .remove = __devexit_p(qpnp_bms_remove),
3951 .driver = {
3952 .name = QPNP_BMS_DEV_NAME,
3953 .owner = THIS_MODULE,
3954 .of_match_table = qpnp_bms_match_table,
Xiaozhe Shicdeee312012-12-18 15:10:18 -08003955 .pm = &qpnp_bms_pm_ops,
Xiaozhe Shib19f7032012-08-16 12:14:16 -07003956 },
3957};
3958
3959static int __init qpnp_bms_init(void)
3960{
3961 pr_info("QPNP BMS INIT\n");
3962 return spmi_driver_register(&qpnp_bms_driver);
3963}
3964
3965static void __exit qpnp_bms_exit(void)
3966{
3967 pr_info("QPNP BMS EXIT\n");
3968 return spmi_driver_unregister(&qpnp_bms_driver);
3969}
3970
3971module_init(qpnp_bms_init);
3972module_exit(qpnp_bms_exit);
3973
3974MODULE_DESCRIPTION("QPNP BMS Driver");
3975MODULE_LICENSE("GPL v2");
3976MODULE_ALIAS("platform:" QPNP_BMS_DEV_NAME);