diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-08-19 05:29:26 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-08-19 05:29:25 -0700 |
commit | c8066779721d557225c4107717ff94098d02e99c (patch) | |
tree | d2666083d9b66c0c2ab333dc65d797547500c1b3 | |
parent | a76f4330d86184de18fabb4ce6ca7c8fbb1f5929 (diff) | |
parent | 36e5d56a0e96cdab20d3f0dcff019a7fc19cb1ee (diff) |
Merge "qcom-charger: qpnp-fg-gen3: increase ESR timer during suspend"
-rw-r--r-- | Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt | 19 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi | 2 | ||||
-rw-r--r-- | drivers/power/qcom-charger/fg-core.h | 12 | ||||
-rw-r--r-- | drivers/power/qcom-charger/fg-util.c | 12 | ||||
-rw-r--r-- | drivers/power/qcom-charger/qpnp-fg-gen3.c | 135 |
5 files changed, 174 insertions, 6 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 ac68f19e01ab..d99749a01f6c 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 ef4ea8172035..d176bbb7d872 100644 --- a/drivers/power/qcom-charger/fg-core.h +++ b/drivers/power/qcom-charger/fg-core.h @@ -68,8 +68,9 @@ enum fg_debug_flag { /* SRAM access */ enum sram_access_flags { - FG_IMA_DEFAULT = 0, - FG_IMA_ATOMIC, + FG_IMA_DEFAULT = 0, + FG_IMA_ATOMIC = BIT(0), + FG_IMA_NO_WLOCK = BIT(1), }; /* JEITA */ @@ -117,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, @@ -148,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/fg-util.c b/drivers/power/qcom-charger/fg-util.c index 9f2d9973e04b..5f133d6f39c1 100644 --- a/drivers/power/qcom-charger/fg-util.c +++ b/drivers/power/qcom-charger/fg-util.c @@ -66,7 +66,8 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, if (!fg_sram_address_valid(address, len)) return -EFAULT; - vote(chip->awake_votable, SRAM_WRITE, true, 0); + if (!(flags & FG_IMA_NO_WLOCK)) + vote(chip->awake_votable, SRAM_WRITE, true, 0); mutex_lock(&chip->sram_rw_lock); if ((flags & FG_IMA_ATOMIC) && chip->irqs[SOC_UPDATE_IRQ].irq) { @@ -113,7 +114,8 @@ out: disable_irq_nosync(chip->irqs[SOC_UPDATE_IRQ].irq); mutex_unlock(&chip->sram_rw_lock); - vote(chip->awake_votable, SRAM_WRITE, false, 0); + if (!(flags & FG_IMA_NO_WLOCK)) + vote(chip->awake_votable, SRAM_WRITE, false, 0); return rc; } @@ -128,7 +130,8 @@ int fg_sram_read(struct fg_chip *chip, u16 address, u8 offset, if (!fg_sram_address_valid(address, len)) return -EFAULT; - vote(chip->awake_votable, SRAM_READ, true, 0); + if (!(flags & FG_IMA_NO_WLOCK)) + vote(chip->awake_votable, SRAM_READ, true, 0); mutex_lock(&chip->sram_rw_lock); rc = fg_interleaved_mem_read(chip, address, offset, val, len); @@ -137,7 +140,8 @@ int fg_sram_read(struct fg_chip *chip, u16 address, u8 offset, address, offset, rc); mutex_unlock(&chip->sram_rw_lock); - vote(chip->awake_votable, SRAM_READ, false, 0); + if (!(flags & FG_IMA_NO_WLOCK)) + vote(chip->awake_votable, SRAM_READ, false, 0); return rc; } 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, |