summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Troast <ntroast@codeaurora.org>2016-08-04 14:30:02 -0700
committerHarry Yang <harryy@codeaurora.org>2016-08-18 13:31:22 -0700
commit36e5d56a0e96cdab20d3f0dcff019a7fc19cb1ee (patch)
treef3db4b8b0f7e8ffac19d056a906de2580cfa5fff
parent59e8c0d0d5555196abbda8c7d54afa841feb0b12 (diff)
qcom-charger: qpnp-fg-gen3: increase ESR timer during suspend
ESR pulses consume too much power during sleep states. Add device tree properties to allow configuration of the ESR timing during charging, discharging while awake, and discharging while asleep. Configure these new device tree properties to increase the ESR timer while in a sleep state to save power. Change-Id: I673ab1a5713023ac4ab0271fec8d9a053df1c046 Signed-off-by: Nicholas Troast <ntroast@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt19
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi2
-rw-r--r--drivers/power/qcom-charger/fg-core.h7
-rw-r--r--drivers/power/qcom-charger/qpnp-fg-gen3.c135
4 files changed, 163 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
index 9bf6d5b2bf8e..bd236df6c056 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
@@ -119,6 +119,25 @@ First Level Node - FG Gen3 device
If these parameters are not specified, then the default
values used will be 0, 5, 45, 50.
+- qcom,fg-esr-timer-charging
+ Usage: optional
+ Value type: <u32>
+ Definition: Number of cycles between ESR pulses while the battery is
+ charging.
+
+- qcom,fg-esr-timer-awake
+ Usage: optional
+ Value type: <u32>
+ Definition: Number of cycles between ESR pulses while the system is
+ awake and the battery is discharging.
+
+- qcom,fg-esr-timer-asleep
+ Usage: optional
+ Value type: <u32>
+ Definition: Number of cycles between ESR pulses while the system is
+ asleep and the battery is discharging. This option requires
+ qcom,fg-esr-timer-awake to be defined.
+
==========================================================
Second Level Nodes - Peripherals managed by FG Gen3 driver
==========================================================
diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
index 714bdf48da6c..1c48265e3456 100644
--- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
@@ -309,6 +309,8 @@
qcom,pmic-revid = <&pmicobalt_revid>;
io-channels = <&pmicobalt_rradc 0>;
io-channel-names = "rradc_batt_id";
+ qcom,fg-esr-timer-awake = <64>;
+ qcom,fg-esr-timer-asleep = <256>;
status = "okay";
qcom,fg-batt-soc@4000 {
diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h
index cdcbb8011df2..d176bbb7d872 100644
--- a/drivers/power/qcom-charger/fg-core.h
+++ b/drivers/power/qcom-charger/fg-core.h
@@ -118,6 +118,10 @@ enum fg_sram_param_id {
FG_SRAM_CUTOFF_VOLT,
FG_SRAM_EMPTY_VOLT,
FG_SRAM_VBATT_LOW,
+ FG_SRAM_ESR_TIMER_DISCHG_MAX,
+ FG_SRAM_ESR_TIMER_DISCHG_INIT,
+ FG_SRAM_ESR_TIMER_CHG_MAX,
+ FG_SRAM_ESR_TIMER_CHG_INIT,
FG_SRAM_SYS_TERM_CURR,
FG_SRAM_CHG_TERM_CURR,
FG_SRAM_DELTA_SOC_THR,
@@ -149,6 +153,9 @@ struct fg_dt_props {
int recharge_soc_thr;
int rsense_sel;
int jeita_thresholds[NUM_JEITA_LEVELS];
+ int esr_timer_charging;
+ int esr_timer_awake;
+ int esr_timer_asleep;
};
/* parameters from battery profile */
diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c
index b350e53237b7..fcd4545471cc 100644
--- a/drivers/power/qcom-charger/qpnp-fg-gen3.c
+++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c
@@ -45,6 +45,14 @@
#define EMPTY_VOLT_OFFSET 0
#define VBATT_LOW_WORD 15
#define VBATT_LOW_OFFSET 1
+#define ESR_TIMER_DISCHG_MAX_WORD 17
+#define ESR_TIMER_DISCHG_MAX_OFFSET 0
+#define ESR_TIMER_DISCHG_INIT_WORD 17
+#define ESR_TIMER_DISCHG_INIT_OFFSET 2
+#define ESR_TIMER_CHG_MAX_WORD 18
+#define ESR_TIMER_CHG_MAX_OFFSET 0
+#define ESR_TIMER_CHG_INIT_WORD 18
+#define ESR_TIMER_CHG_INIT_OFFSET 2
#define PROFILE_LOAD_WORD 24
#define PROFILE_LOAD_OFFSET 0
#define NOM_CAP_WORD 58
@@ -114,6 +122,15 @@ static struct fg_sram_param pmicobalt_v1_sram_params[] = {
100, fg_encode_default, NULL),
PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET,
1, 256, 100, fg_encode_default, NULL),
+ PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
+ ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, fg_encode_default, NULL),
+ PARAM(ESR_TIMER_DISCHG_INIT, ESR_TIMER_DISCHG_INIT_WORD,
+ ESR_TIMER_DISCHG_INIT_OFFSET, 2, 1, 1, fg_encode_default,
+ NULL),
+ PARAM(ESR_TIMER_CHG_MAX, ESR_TIMER_CHG_MAX_WORD,
+ ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, fg_encode_default, NULL),
+ PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
+ ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, fg_encode_default, NULL),
};
static int fg_gen3_debug_mask;
@@ -707,6 +724,45 @@ static inline void get_temp_setpoint(int threshold, u8 *val)
*val = DIV_ROUND_CLOSEST((threshold + 30) * 10, 5);
}
+static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
+ int flags)
+{
+ u8 buf[2];
+ int rc, timer_max, timer_init;
+
+ if (charging) {
+ timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
+ timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
+ } else {
+ timer_max = FG_SRAM_ESR_TIMER_DISCHG_MAX;
+ timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
+ }
+
+ fg_encode(chip->sp, timer_max, cycles, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[timer_max].address,
+ chip->sp[timer_max].offset, buf,
+ chip->sp[timer_max].len, flags);
+ if (rc < 0) {
+ pr_err("Error in writing esr_timer_dischg_max, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ fg_encode(chip->sp, timer_init, cycles, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[timer_init].address,
+ chip->sp[timer_init].offset, buf,
+ chip->sp[timer_init].len, flags);
+ if (rc < 0) {
+ pr_err("Error in writing esr_timer_dischg_init, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
/* PSY CALLBACKS STAY HERE */
static int fg_psy_get_property(struct power_supply *psy,
@@ -943,6 +999,24 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
+ if (chip->dt.esr_timer_charging > 0) {
+ rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging, true,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (chip->dt.esr_timer_awake > 0) {
+ rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
return 0;
}
@@ -1327,6 +1401,25 @@ static int fg_parse_dt(struct fg_chip *chip)
}
}
+ rc = of_property_read_u32(node, "qcom,fg-esr-timer-charging", &temp);
+ if (rc < 0)
+ chip->dt.esr_timer_charging = -EINVAL;
+ else
+ chip->dt.esr_timer_charging = temp;
+
+ rc = of_property_read_u32(node, "qcom,fg-esr-timer-awake", &temp);
+ if (rc < 0)
+ chip->dt.esr_timer_awake = -EINVAL;
+ else
+ chip->dt.esr_timer_awake = temp;
+
+ rc = of_property_read_u32(node, "qcom,fg-esr-timer-asleep", &temp);
+ if (rc < 0)
+ chip->dt.esr_timer_asleep = -EINVAL;
+ else
+ chip->dt.esr_timer_asleep = temp;
+
+
return 0;
}
@@ -1450,6 +1543,47 @@ exit:
return rc;
}
+static int fg_gen3_suspend(struct device *dev)
+{
+ struct fg_chip *chip = dev_get_drvdata(dev);
+ int rc;
+
+ if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) {
+ rc = fg_set_esr_timer(chip, chip->dt.esr_timer_asleep, false,
+ FG_IMA_NO_WLOCK);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer during suspend, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int fg_gen3_resume(struct device *dev)
+{
+ struct fg_chip *chip = dev_get_drvdata(dev);
+ int rc;
+
+ if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) {
+ rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer during resume, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops fg_gen3_pm_ops = {
+ .suspend = fg_gen3_suspend,
+ .resume = fg_gen3_resume,
+};
+
static int fg_gen3_remove(struct platform_device *pdev)
{
struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
@@ -1468,6 +1602,7 @@ static struct platform_driver fg_gen3_driver = {
.name = FG_GEN3_DEV_NAME,
.owner = THIS_MODULE,
.of_match_table = fg_gen3_match_table,
+ .pm = &fg_gen3_pm_ops,
},
.probe = fg_gen3_probe,
.remove = fg_gen3_remove,