Merge changes Ifb5e9c26,I3ba91f8b,I82022aa4,Idc141e6b,I4f2ab278,Ie0a8dc51,I213b3618,Ie57d474f into msm-3.4
* changes:
power: pm8921-charger: round up vddmax adjustments
power: pm8921-bms: use termination battery resistance
power: pm8921-bms: increase/decrease UUC 1% at a time
power: pm8921-bms: limit voltage correction
power: pm8921-bms: backup average current along with shutdown soc
power: pm8921-bms: use rtc to get average current
power: pm8921-bms: fix ccadc accuracy
power: pm8921-bms: provide option to ignore shutdown soc
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 518579a..1f39d3f 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -394,6 +394,7 @@
.v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 384b1cf..c16f55d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -345,6 +345,7 @@
.v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 98140b4..46d317b 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -426,6 +426,7 @@
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.rconn_mohm = 18,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b69ad11..88e0948 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/rtc.h>
#define BMS_CONTROL 0x224
#define BMS_S1_DELAY 0x225
@@ -50,6 +51,9 @@
#define TEMP_SOC_STORAGE 0x107
+#define TEMP_IAVG_STORAGE 0x105
+#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
+
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
PM8921_BMS_CC_THR,
@@ -126,14 +130,20 @@
int last_ocv_uv;
int pon_ocv_uv;
int last_cc_uah;
- struct timeval t;
+ unsigned long tm_sec;
int enable_fcc_learning;
int shutdown_soc;
+ int shutdown_iavg_ua;
int shutdown_soc_timer_expired;
struct delayed_work shutdown_soc_work;
struct delayed_work calculate_soc_delayed_work;
struct timespec t_soc_queried;
int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int prev_iavg_ua;
+ int prev_uuc_iavg_ma;
+ int prev_pc_unusable;
+ int adjust_soc_low_threshold;
};
/*
@@ -475,8 +485,8 @@
return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
}
-#define CC_READING_TICKS 55
-#define SLEEP_CLK_HZ 32768
+#define CC_READING_TICKS 56
+#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
/**
* ccmicrovolt_to_nvh -
@@ -1148,59 +1158,168 @@
*val = cc_uah;
}
-static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles,
- int rbatt, int fcc_uah, int i_ma)
+ int fcc_uah, int i_ma,
+ int *ret_pc_unusable)
{
int unusable_uv, pc_unusable, uuc;
+ int i = 0;
+ int ocv_mv;
+ int batt_temp_degc = batt_temp / 10;
+ int rbatt_mohm;
+ int delta_uv;
+ int prev_delta_uv = 0;
+ int prev_rbatt_mohm = 0;
+ int prev_ocv_mv = 0;
+ int uuc_rbatt_uv;
- /* calculate unusable charge with itest */
- unusable_uv = (rbatt * i_ma) + (chip->v_cutoff * 1000);
+ for (i = 0; i <= 100; i++) {
+ ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+ rbatt_mohm = get_rbatt(chip, i, batt_temp);
+ unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
+ delta_uv = ocv_mv * 1000 - unusable_uv;
+
+ pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
+ i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
+
+ if (delta_uv > 0)
+ break;
+
+ prev_delta_uv = delta_uv;
+ prev_rbatt_mohm = rbatt_mohm;
+ prev_ocv_mv = ocv_mv;
+ }
+
+ uuc_rbatt_uv = linear_interpolate(rbatt_mohm, delta_uv,
+ prev_rbatt_mohm, prev_delta_uv,
+ 0);
+
+ unusable_uv = (uuc_rbatt_uv * i_ma) + (chip->v_cutoff * 1000);
+
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
uuc = (fcc_uah * pc_unusable) / 100;
- pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
- i_ma, unusable_uv, pc_unusable, uuc);
+ pr_debug("For i_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ i_ma, uuc_rbatt_uv, unusable_uv,
+ pc_unusable, uuc);
+ *ret_pc_unusable = pc_unusable;
return uuc;
}
-static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
- int *iavg_ua, int *delta_time_us)
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+ int new_pc_unusable,
+ int new_uuc,
+ int batt_temp,
+ int rbatt,
+ int *iavg_ma)
{
- int delta_cc_uah;
- struct timeval now;
+ int new_unusable_mv;
+ int batt_temp_degc = batt_temp / 10;
- delta_cc_uah = cc_uah - chip->last_cc_uah;
- do_gettimeofday(&now);
- if (chip->t.tv_sec != 0) {
- *delta_time_us = (now.tv_sec - chip->t.tv_sec) * USEC_PER_SEC
- + now.tv_usec - chip->t.tv_usec;
- } else {
- /* calculation for the first time */
- *delta_time_us = 0;
+ if (chip->prev_pc_unusable == -EINVAL
+ || abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+ chip->prev_pc_unusable = new_pc_unusable;
+ return new_uuc;
}
- if (*delta_time_us != 0)
- *iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
- *delta_time_us);
+ /* the uuc is trying to change more than 1% restrict it */
+ if (new_pc_unusable > chip->prev_pc_unusable)
+ chip->prev_pc_unusable++;
else
- *iavg_ua = 0;
+ chip->prev_pc_unusable--;
- pr_debug("t.tv_sec = %d, now.tv_sec = %d delta_us = %d iavg_ua = %d\n",
- (int)chip->t.tv_sec, (int)now.tv_sec,
- *delta_time_us, (int)*iavg_ua);
+ new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+ /* also find update the iavg_ma accordingly */
+ new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+ chip->prev_pc_unusable);
+ if (new_unusable_mv < chip->v_cutoff)
+ new_unusable_mv = chip->v_cutoff;
+
+ *iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+ if (*iavg_ma == 0)
+ *iavg_ma = 1;
+ pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+ new_uuc, chip->prev_pc_unusable,
+ new_unusable_mv, *iavg_ma);
+
+ return new_uuc;
+}
+
+static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
+ int *iavg_ua, int *delta_time_s)
+{
+ int delta_cc_uah;
+ struct rtc_time tm;
+ struct rtc_device *rtc;
+ unsigned long now_tm_sec = 0;
+ int rc = 0;
+
+ /* if anything fails report the previous iavg_ua */
+ *iavg_ua = chip->prev_iavg_ua;
+
+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+ if (rtc == NULL) {
+ pr_err("%s: unable to open rtc device (%s)\n",
+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+ goto out;
+ }
+
+ rc = rtc_read_time(rtc, &tm);
+ if (rc) {
+ pr_err("Error reading rtc device (%s) : %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
+
+ rc = rtc_valid_tm(&tm);
+ if (rc) {
+ pr_err("Invalid RTC time (%s): %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
+ rtc_tm_to_time(&tm, &now_tm_sec);
+
+ if (chip->tm_sec == 0) {
+ *delta_time_s = 0;
+ pm8921_bms_get_battery_current(iavg_ua);
+ goto out;
+ }
+
+ *delta_time_s = (now_tm_sec - chip->tm_sec);
+
+ /* use the previous iavg if called within 15 seconds */
+ if (*delta_time_s < 15) {
+ *iavg_ua = chip->prev_iavg_ua;
+ goto out;
+ }
+
+ delta_cc_uah = cc_uah - chip->last_cc_uah;
+
+ *iavg_ua = div_s64((s64)delta_cc_uah * 3600, *delta_time_s);
+
+ pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d delta_cc = %d iavg_ua = %d\n",
+ chip->tm_sec, now_tm_sec,
+ *delta_time_s, delta_cc_uah, (int)*iavg_ua);
+
+out:
+ /* remember the iavg */
+ chip->prev_iavg_ua = *iavg_ua;
+
/* remember cc_uah */
chip->last_cc_uah = cc_uah;
/* remember this time */
- chip->t = now;
+ chip->tm_sec = now_tm_sec;
}
#define IAVG_SAMPLES 16
-#define CHARGING_IAVG_MA 300
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE 20
static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
int rbatt, int fcc_uah, int cc_uah,
int soc_rbatt, int batt_temp, int chargecycles,
- int iavg_ua, int delta_time_us)
+ int iavg_ua, int delta_time_s)
{
int uuc_uah_iavg;
int i;
@@ -1208,32 +1327,34 @@
static int iavg_samples[IAVG_SAMPLES];
static int iavg_index;
static int iavg_num_samples;
+ static int firsttime = 1;
+ int pc_unusable;
- if (delta_time_us == 0) {
- /*
- * this means uuc is being for the first time,
- * iavg_ua will be 0 which will lead to unreasonably low uuc
- * hence use the instantenous current instead of iavg_ua
- * value for the first time
- */
- pm8921_bms_get_battery_current(&iavg_ua);
- iavg_ma = iavg_ua / 1000;
+ /*
+ * if we are called first time fill all the
+ * samples with the the shutdown_iavg_ua
+ */
+ if (firsttime && chip->shutdown_iavg_ua != 0) {
+ pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+ chip->shutdown_iavg_ua);
+ for (i = 0; i < IAVG_SAMPLES; i++)
+ iavg_samples[i] = chip->shutdown_iavg_ua;
+
+ iavg_index = 0;
+ iavg_num_samples = IAVG_SAMPLES;
}
- /* if the time since last sample is small ignore it */
- if (delta_time_us == 0 || delta_time_us > USEC_PER_SEC) {
- /*
- * if we are charging use a nominal avg current so that we keep
- * a reasonable UUC while charging
- */
- if (iavg_ma < 0)
- iavg_ma = CHARGING_IAVG_MA;
- iavg_samples[iavg_index] = iavg_ma;
- iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
- iavg_num_samples++;
- if (iavg_num_samples >= IAVG_SAMPLES)
- iavg_num_samples = IAVG_SAMPLES;
- }
+ /*
+ * if we are charging use a nominal avg current so that we keep
+ * a reasonable UUC while charging
+ */
+ if (iavg_ma < 0)
+ iavg_ma = CHARGING_IAVG_MA;
+ iavg_samples[iavg_index] = iavg_ma;
+ iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
+ iavg_num_samples++;
+ if (iavg_num_samples >= IAVG_SAMPLES)
+ iavg_num_samples = IAVG_SAMPLES;
/* now that this sample is added calcualte the average */
iavg_ma = 0;
@@ -1246,11 +1367,20 @@
iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
}
- uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
+ uuc_uah_iavg = calculate_termination_uuc(chip,
batt_temp, chargecycles,
- rbatt, fcc_uah, iavg_ma);
+ fcc_uah, iavg_ma,
+ &pc_unusable);
pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
+ /* restrict the uuc such that it can increase only by one percent */
+ uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+ batt_temp, rbatt, &iavg_ma);
+
+ /* find out what the avg current should be for this uuc */
+ chip->prev_uuc_iavg_ma = iavg_ma;
+
+ firsttime = 0;
return uuc_uah_iavg;
}
@@ -1277,7 +1407,7 @@
int *cc_uah,
int *rbatt,
int *iavg_ua,
- int *delta_time_us)
+ int *delta_time_s)
{
int soc_rbatt;
@@ -1303,12 +1433,12 @@
soc_rbatt = 0;
*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_us);
+ calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_s);
*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
*fcc_uah, *cc_uah, soc_rbatt,
batt_temp, chargecycles, *iavg_ua,
- *delta_time_us);
+ *delta_time_s);
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
@@ -1323,7 +1453,7 @@
int real_fcc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1332,7 +1462,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
real_fcc_uah = remaining_charge_uah - cc_uah;
*ret_fcc_uah = fcc_uah;
@@ -1393,6 +1523,7 @@
int soc_new = 0;
int m = 0;
int rc = 0;
+ int delta_ocv_uv_limit = 0;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -1405,6 +1536,9 @@
if (ibat_ua < 0)
goto out;
+
+ delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
@@ -1422,7 +1556,8 @@
* and cause a bad user experience
*/
if (soc_est == soc
- || (is_between(45, 25, soc_est) && is_between(50, 20, soc))
+ || (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+ && is_between(50, chip->adjust_soc_low_threshold - 5, soc))
|| soc >= 90)
goto out;
@@ -1457,6 +1592,18 @@
delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
n * (pc - pc_new));
+
+ if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+ pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+ delta_ocv_uv_limit);
+
+ if (delta_ocv_uv > 0)
+ delta_ocv_uv = delta_ocv_uv_limit;
+ else
+ delta_ocv_uv = -1 * delta_ocv_uv_limit;
+ pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+ }
+
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1490,29 +1637,80 @@
}
#define IGNORE_SOC_TEMP_DECIDEG 50
-static void backup_soc(struct pm8921_bms_chip *chip, int batt_temp, int soc)
+#define IAVG_STEP_SIZE_MA 50
+#define IAVG_START 600
+#define SOC_ZERO 0xFF
+static void backup_soc_and_iavg(struct pm8921_bms_chip *chip, int batt_temp,
+ int soc)
{
+ u8 temp;
+ int iavg_ma = chip->prev_uuc_iavg_ma;
+
+ if (iavg_ma > IAVG_START)
+ temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+ else
+ temp = 0;
+
+ pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+ TEMP_IAVG_STORAGE_USE_MASK, temp);
+
+ /* since only 6 bits are available for SOC, we store half the soc */
if (soc == 0)
- soc = 0xFF;
+ temp = SOC_ZERO;
+ else
+ temp = soc;
- if (batt_temp < IGNORE_SOC_TEMP_DECIDEG)
- soc = 0;
-
- pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, soc);
+ /* don't store soc if temperature is below 5degC */
+ if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+ pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, temp);
}
-static void read_shutdown_soc(struct pm8921_bms_chip *chip)
+static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
{
int rc;
u8 temp;
+ rc = pm8xxx_readb(chip->dev->parent, TEMP_IAVG_STORAGE, &temp);
+ if (rc) {
+ pr_err("failed to read addr = %d %d assuming %d\n",
+ TEMP_IAVG_STORAGE, rc, IAVG_START);
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ temp &= TEMP_IAVG_STORAGE_USE_MASK;
+
+ if (temp == 0) {
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ chip->shutdown_iavg_ua = IAVG_START
+ + IAVG_STEP_SIZE_MA * (temp + 1);
+ }
+ }
+
rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
- if (rc)
+ if (rc) {
pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
- else
+ } else {
chip->shutdown_soc = temp;
- pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
+ if (chip->shutdown_soc == 0) {
+ pr_debug("No shutdown soc available\n");
+ shutdown_soc_invalid = 1;
+ chip->shutdown_iavg_ua = 0;
+ } else if (chip->shutdown_soc == SOC_ZERO) {
+ chip->shutdown_soc = 0;
+ }
+ }
+
+ if (chip->ignore_shutdown_soc) {
+ shutdown_soc_invalid = 1;
+ chip->shutdown_soc = 0;
+ chip->shutdown_iavg_ua = 0;
+ }
+
+ pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+ chip->shutdown_soc,
+ chip->shutdown_iavg_ua,
+ shutdown_soc_invalid);
}
static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
@@ -1572,42 +1770,13 @@
int *ret_uuc,
int *ret_rbatt)
{
- int new_rbatt;
int ocv_uv;
- int soc_rbatt;
- int iavg_ua, iavg_ma;
- int num_tries = 0;
-
- pm8921_bms_get_battery_current(&iavg_ua);
- iavg_ma = iavg_ua / 1000;
- if (iavg_ma < 0)
- iavg_ma = CHARGING_IAVG_MA;
-
-recalculate_ocv:
find_ocv_for_soc(chip, batt_temp, chargecycles,
fcc_uah, uuc_uah, cc_uah,
soc,
&rc_uah, &ocv_uv);
- soc_rbatt = div_s64((rc_uah - cc_uah) * 100, fcc_uah);
- new_rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- pr_debug("for f_soc = %d rc_uah = %d ocv_uv = %d, soc_rbatt = %d rbatt = %d\n",
- soc, rc_uah, ocv_uv, soc_rbatt, new_rbatt);
- if (abs(new_rbatt - rbatt) > 20 && num_tries < 10) {
- rbatt = new_rbatt;
- uuc_uah = calculate_uuc_uah_at_given_current(chip,
- batt_temp, chargecycles,
- new_rbatt, fcc_uah, iavg_ma);
-
- pr_debug("rbatt not settled uuc = %d for rbatt = %d iavg_ma = %d num_tries = %d\n",
- uuc_uah, rbatt, iavg_ma, num_tries);
- num_tries++;
- goto recalculate_ocv;
- }
- pr_debug("DONE for s_soc = %d rc_uah = %d ocv_uv = %d, rbatt = %d\n",
- soc, rc_uah, ocv_uv, new_rbatt);
-
*ret_ocv = ocv_uv;
*ret_rbatt = rbatt;
*ret_rc = rc_uah;
@@ -1675,20 +1844,15 @@
static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
{
- int shutdown_soc;
-
- if (chip->shutdown_soc == 0 || shutdown_soc_invalid) {
+ if (shutdown_soc_invalid) {
pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
return 0;
}
- shutdown_soc = chip->shutdown_soc;
- if (shutdown_soc == 0xFF)
- shutdown_soc = 0;
-
- if (abs(shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
- pr_debug("rejecting shutdown soc = %d, soc = %d, limit = %d\n",
- shutdown_soc, soc, chip->shutdown_soc_valid_limit);
+ if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+ pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
+ chip->shutdown_soc, soc,
+ chip->shutdown_soc_valid_limit);
shutdown_soc_invalid = 1;
return 0;
}
@@ -1710,12 +1874,13 @@
int cc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
int new_ocv;
int new_rc_uah;
int new_ucc_uah;
int new_rbatt;
int shutdown_soc;
+ static int firsttime = 1;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1724,7 +1889,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
/* calculate remaining usable charge */
remaining_usable_charge_uah = remaining_charge_uah
@@ -1741,7 +1906,7 @@
(fcc_uah - unusable_charge_uah));
}
- if (delta_time_us == 0 && soc < 0) {
+ if (firsttime && soc < 0) {
/*
* first time calcualtion and the pon ocv is too low resulting
* in a bad soc. Adjust ocv such that we get 0 soc
@@ -1797,11 +1962,8 @@
mutex_lock(&soc_invalidation_mutex);
shutdown_soc = chip->shutdown_soc;
- /* value of 0xFF means shutdown soc was 0% */
- if (shutdown_soc == 0xFF)
- shutdown_soc = 0;
- if (delta_time_us == 0 && soc != shutdown_soc
+ if (firsttime && soc != shutdown_soc
&& is_shutdown_soc_within_limits(chip, soc)) {
/*
* soc for the first time - use shutdown soc
@@ -1843,6 +2005,7 @@
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
pr_debug("calculated SOC = %d\n", calculated_soc);
+ firsttime = 0;
return calculated_soc;
}
@@ -1951,16 +2114,13 @@
* force shutdown soc if it is valid and the shutdown soc show
* timer has not expired
*/
- if (chip->shutdown_soc != 0xFF)
- soc = chip->shutdown_soc;
- else
- soc = 0;
+ soc = chip->shutdown_soc;
pr_debug("Forcing SHUTDOWN_SOC = %d\n", soc);
}
last_soc = soc;
- backup_soc(chip, batt_temp, last_soc);
+ backup_soc_and_iavg(chip, batt_temp, last_soc);
pr_debug("Reported SOC = %d\n", last_soc);
chip->t_soc_queried = now;
@@ -1977,6 +2137,9 @@
int soc;
pr_debug("Invalidating shutdown soc - the battery was removed\n");
+ if (shutdown_soc_invalid)
+ return;
+
mutex_lock(&soc_invalidation_mutex);
shutdown_soc_invalid = 1;
last_soc = -EINVAL;
@@ -2011,6 +2174,7 @@
mutex_unlock(&chip->last_ocv_uv_mutex);
}
EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+
#define MIN_DELTA_625_UV 1000
static void calib_hkadc(struct pm8921_bms_chip *chip)
{
@@ -2157,7 +2321,7 @@
int cc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
if (!the_chip) {
pr_err("called before initialization\n");
@@ -2185,7 +2349,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
return rbatt;
@@ -2302,7 +2466,6 @@
last_real_fcc_mah = new_fcc_uah/1000;
last_real_fcc_batt_temp = batt_temp;
readjust_fcc_table();
-
}
if (is_battery_full) {
@@ -2316,7 +2479,7 @@
* forget the old cc value
*/
the_chip->last_cc_uah = 0;
- pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
+ pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
the_chip->ocv_reading_at_100,
the_chip->cc_reading_at_100);
}
@@ -2949,6 +3112,13 @@
chip->start_percent = -EINVAL;
chip->end_percent = -EINVAL;
chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+ chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+ if (chip->adjust_soc_low_threshold >= 45)
+ chip->adjust_soc_low_threshold = 45;
+
+ chip->prev_pc_unusable = -EINVAL;
+
+ chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
rc = set_battery_data(chip);
if (rc) {
pr_err("%s bad battery data %d\n", __func__, rc);
@@ -2993,7 +3163,7 @@
goto free_irqs;
}
- read_shutdown_soc(chip);
+ read_shutdown_soc_and_iavg(chip);
platform_set_drvdata(pdev, chip);
the_chip = chip;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 4e15e77..6330883 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -2808,6 +2808,8 @@
static int ichg_threshold_ua = -400000;
module_param(ichg_threshold_ua, int, 0644);
+
+#define PM8921_CHG_VDDMAX_RES_MV 10
static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
{
int ichg_meas_ua, vbat_uv;
@@ -2867,9 +2869,11 @@
return;
}
+ adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
+ * PM8921_CHG_VDDMAX_RES_MV;
+
if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
-
pr_debug("adjusting vdd_max_mv to %d to make "
"vbat_batt_termial_uv = %d to %d\n",
adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index d17125a..d1438d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -131,6 +131,8 @@
unsigned int rconn_mohm;
int enable_fcc_learning;
int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int adjust_soc_low_threshold;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)