aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuosong Su <gssu@marvell.com>2015-06-17 20:31:31 +0800
committerTim Wang <wangtt@marvell.com>2015-07-06 17:28:47 +0800
commit47ebe8d0c2279eb7bdd3e15a2946ad705a3840ca (patch)
tree8e0eeca7ea287586a89bb8e882d500cf274068bf
parent800c75cde553e6de0bce3d351b23ba5eb65d05a0 (diff)
downloadpxa-v3.14-47ebe8d0c2279eb7bdd3e15a2946ad705a3840ca.tar.gz
power: 88pm88x_battery: save CC value before GPADC is enabled
when enable GPADC, the value of CC will be cleared, so we should save it for later use. Change-Id: I405ca4b3a709253ca8c4ba3bf046ab05a5df7588 Signed-off-by: Guosong Su <gssu@marvell.com>
-rw-r--r--drivers/mfd/88pm88x-core.c50
-rw-r--r--drivers/power/88pm88x_battery.c77
-rw-r--r--include/linux/mfd/88pm88x.h1
3 files changed, 92 insertions, 36 deletions
diff --git a/drivers/mfd/88pm88x-core.c b/drivers/mfd/88pm88x-core.c
index 81c21edd6f2..ba757b4f14d 100644
--- a/drivers/mfd/88pm88x-core.c
+++ b/drivers/mfd/88pm88x-core.c
@@ -344,6 +344,51 @@ static void pm88x_verify_is_trimmed(struct pm88x_chip *chip)
}
}
+/*
+ * fuel gauge initialization,
+ * stored CC for later use before GPADC enable.
+ */
+int pm88x_pre_fg_init(struct pm88x_chip *chip)
+{
+ int ret;
+ unsigned int val, mask;
+ u8 buf[5];
+
+ /*
+ * set SD_PWRUP to enable sigma-delta
+ * set CC_CLR_ON_RD to clear coulomb counter on read
+ * set CC_EN to enable coulomb counter
+ */
+ val = mask = PM88X_SD_PWRUP | PM88X_CC_CLR_ON_RD | PM88X_CC_EN;
+ ret = regmap_update_bits(chip->battery_regmap, PM88X_CC_CONFIG1,
+ mask, val);
+ /* read columb counter to get the original SoC value */
+ regmap_read(chip->battery_regmap, PM88X_CC_CONFIG2, &val);
+ /*
+ * set PM88X_CC_READ_REQ to read Qbat_cc,
+ * if it has been set, then it means the data not ready
+ */
+ if (!(val & PM88X_CC_READ_REQ))
+ regmap_update_bits(chip->battery_regmap, PM88X_CC_CONFIG2,
+ PM88X_CC_READ_REQ, PM88X_CC_READ_REQ);
+ /* wait until Qbat_cc is ready */
+ do {
+ regmap_read(chip->battery_regmap, PM88X_CC_CONFIG2,
+ &val);
+ } while ((val & PM88X_CC_READ_REQ));
+
+ ret = regmap_bulk_read(chip->battery_regmap, PM88X_CC_VAL1,
+ buf, 5);
+ if (ret < 0)
+ return ret;
+ chip->pre_ccnt_uc = (s64) (((s64)(buf[4]) << 32)
+ | (u64)(buf[3] << 24) | (u64)(buf[2] << 16)
+ | (u64)(buf[1] << 8) | (u64)buf[0]);
+ dev_info(chip->dev, "buf[0 ~ 4] = 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4]);
+ return 0;
+}
+
int pm88x_post_init_chip(struct pm88x_chip *chip)
{
int ret;
@@ -375,6 +420,11 @@ int pm88x_post_init_chip(struct pm88x_chip *chip)
}
chip->rtc_wakeup = !!(val & PM88X_ALARM_WAKEUP);
+ ret = pm88x_pre_fg_init(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to initial fuel gauge: %d\n", ret);
+ return ret;
+ }
parse_powerup_down_log(chip);
return 0;
diff --git a/drivers/power/88pm88x_battery.c b/drivers/power/88pm88x_battery.c
index 42f6a6a8ce5..464a47f9e54 100644
--- a/drivers/power/88pm88x_battery.c
+++ b/drivers/power/88pm88x_battery.c
@@ -41,21 +41,6 @@
#define PM88X_VBAT_LOW_TH (0x18)
-#define PM88X_CC_CONFIG1 (0x01)
-#define PM88X_CC_EN (1 << 0)
-#define PM88X_CC_CLR_ON_RD (1 << 2)
-#define PM88X_SD_PWRUP (1 << 3)
-
-#define PM88X_CC_CONFIG2 (0x02)
-#define PM88X_CC_READ_REQ (1 << 0)
-#define PM88X_OFFCOMP_EN (1 << 1)
-
-#define PM88X_CC_VAL1 (0x03)
-#define PM88X_CC_VAL2 (0x04)
-#define PM88X_CC_VAL3 (0x05)
-#define PM88X_CC_VAL4 (0x06)
-#define PM88X_CC_VAL5 (0x07)
-
#define PM88X_IBAT_VAL1 (0x08) /* LSB */
#define PM88X_IBAT_VAL2 (0x09)
#define PM88X_IBAT_VAL3 (0x0a)
@@ -1545,62 +1530,52 @@ static int pm88x_setup_fuelgauge(struct pm88x_battery_info *info)
return true;
}
- /* 0. set the CCNT_LOW_TH before the CC_EN is set 23.43mC/LSB */
+ /* set the CCNT_LOW_TH before the CC_EN is set 23.43mC/LSB */
tmp = ccnt_data.alart_cc * 100 / 2343;
buf[0] = (u8)(tmp & 0xff);
buf[1] = (u8)((tmp & 0xff00) >> 8);
regmap_bulk_write(info->chip->battery_regmap, PM88X_CC_LOW_TH1, buf, 2);
- /* 1. set the EOC battery current as 100mA, done in charger driver */
-
- /* 2. use battery current to decide the EOC */
+ /* use battery current to decide the EOC */
data = mask = PM88X_IBAT_MEAS_EN;
ret = regmap_update_bits(info->chip->battery_regmap,
PM88X_IBAT_EOC_CONFIG, mask, data);
- /*
- * 3. set SD_PWRUP to enable sigma-delta
- * set CC_CLR_ON_RD to clear coulomb counter on read
- * set CC_EN to enable coulomb counter
- */
- data = mask = PM88X_SD_PWRUP | PM88X_CC_CLR_ON_RD | PM88X_CC_EN;
- ret = regmap_update_bits(info->chip->battery_regmap, PM88X_CC_CONFIG1,
- mask, data);
- if (ret < 0)
- goto out;
+
+ /* enable CC by default */
pm88x_cc_enable_bootup(info);
- /* 5. enable VBAT measurement */
+ /* enable VBAT measurement */
data = mask = PM88X_VBAT_MEAS_EN;
ret = regmap_update_bits(info->chip->gpadc_regmap, PM88X_GPADC_CONFIG1,
mask, data);
if (ret < 0)
goto out;
- /* 6. hold the sleep counter until this bit is released or be reset */
+ /* hold the sleep counter until this bit is released or be reset */
data = mask = PM88X_SLP_CNT_HOLD;
ret = regmap_update_bits(info->chip->base_regmap,
PM88X_SLP_CNT2, mask, data);
if (ret < 0)
goto out;
- /* 7. set the VBAT threashold as 3000mV: 0x890 * 1.367mV/LSB = 2.996V */
+ /* set the VBAT threashold as 3000mV: 0x890 * 1.367mV/LSB = 2.996V */
ret = regmap_write(info->chip->gpadc_regmap, PM88X_VBAT_LOW_TH, 0x89);
if (ret < 0)
goto out;
- /* 8. disable battery detection by HW */
+ /* disable battery detection by HW */
ret = regmap_update_bits(info->chip->gpadc_regmap, PM88X_GPADC_CONFIG8,
PM88X_GPADC_BD_EN, 0);
if (ret < 0)
goto out;
- /* 9. disable battery temperature monitoring */
+ /* disable battery temperature monitoring */
ret = regmap_update_bits(info->chip->battery_regmap, PM88X_CHG_CONFIG1,
PM88X_BATTEMP_MON_EN, 0);
if (ret < 0)
goto out;
- /* 10. disable battery temperature monitoring2 for 88pm886-A1 and 88pm880-xx */
+ /* disable battery temperature monitoring2 for 88pm886-A1 and 88pm880-xx */
switch (info->chip->type) {
case PM886:
if (info->chip->chip_id == PM886_A1)
@@ -1622,6 +1597,36 @@ out:
return ret;
}
+/* add stored CC to soc from saved. */
+static int pm88x_battery_init_calc_ccnt(struct pm88x_battery_info *info,
+ struct ccnt *ccnt_val, int soc_from_save)
+{
+ int factor, last_cc, soc_to_save;
+ s64 ccnt_uc = 0, ccnt_mc = 0;
+
+ /* get the original SoC value */
+ ccnt_uc = info->chip->pre_ccnt_uc;
+ /* Factor is nC */
+ factor = (info->cc_fixup) * 715 / 100;
+ ccnt_uc = ccnt_uc * factor;
+ ccnt_uc = div_s64(ccnt_uc, 1000);
+ ccnt_mc = div_s64(ccnt_uc, 1000);
+ last_cc = (ccnt_val->max_cc / (1000 * PM88X_CAP_FAC100)) * soc_from_save;
+
+ /* add the value */
+ last_cc += ccnt_mc;
+ /* clap battery SoC for sanity check */
+ if (last_cc > ccnt_val->max_cc)
+ soc_to_save = 1000 * PM88X_CAP_FAC100;
+ if (last_cc < 0)
+ soc_to_save = 0;
+
+ soc_to_save = last_cc * 100 / (ccnt_val->max_cc / (10 * PM88X_CAP_FAC100));
+ dev_info(info->dev, "%s<-- ccnt_val->soc: %d%%, new->last_cc: %d mC\n",
+ __func__, soc_to_save, last_cc);
+ return soc_to_save;
+}
+
static void pm88x_init_soc_cycles(struct pm88x_battery_info *info,
struct ccnt *ccnt_val,
int *initial_soc, int *initial_cycles)
@@ -1669,6 +1674,7 @@ static void pm88x_init_soc_cycles(struct pm88x_battery_info *info,
dev_info(info->dev,
"---> %s: soc_from_saved = %d, reliable_from_saved = %d\n",
__func__, soc_from_saved, reliable_from_saved);
+ soc_from_saved = pm88x_battery_init_calc_ccnt(info, ccnt_val, soc_from_saved);
/* ---------------------------------------------------------------- */
/*
@@ -1811,7 +1817,6 @@ static void pm88x_init_soc_cycles(struct pm88x_battery_info *info,
end:
/* update ccnt_data timely */
init_ccnt_data(ccnt_val, *initial_soc);
- pm88x_battery_calc_ccnt(info, &ccnt_data);
dev_info(info->dev,
"<---- %s: initial soc = %d\n", __func__, *initial_soc);
diff --git a/include/linux/mfd/88pm88x.h b/include/linux/mfd/88pm88x.h
index f17a8632a7b..b6e64a79f83 100644
--- a/include/linux/mfd/88pm88x.h
+++ b/include/linux/mfd/88pm88x.h
@@ -190,6 +190,7 @@ struct pm88x_chip {
u8 powerdown1;
u8 powerdown2;
u8 powerup;
+ s64 pre_ccnt_uc;
bool trimming_status;
struct notifier_block reboot_notifier;