diff options
author | Guosong Su <gssu@marvell.com> | 2015-06-17 20:31:31 +0800 |
---|---|---|
committer | Tim Wang <wangtt@marvell.com> | 2015-07-06 17:28:47 +0800 |
commit | 47ebe8d0c2279eb7bdd3e15a2946ad705a3840ca (patch) | |
tree | 8e0eeca7ea287586a89bb8e882d500cf274068bf | |
parent | 800c75cde553e6de0bce3d351b23ba5eb65d05a0 (diff) | |
download | pxa-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.c | 50 | ||||
-rw-r--r-- | drivers/power/88pm88x_battery.c | 77 | ||||
-rw-r--r-- | include/linux/mfd/88pm88x.h | 1 |
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; |