OSDN Git Service

qpnp-fg-gen3: add support for configuring slope limit coefficients
authorSubbaraman Narayanamurthy <subbaram@codeaurora.org>
Fri, 10 Feb 2017 02:06:14 +0000 (18:06 -0800)
committerSubbaraman Narayanamurthy <subbaram@codeaurora.org>
Sat, 11 Feb 2017 02:20:07 +0000 (18:20 -0800)
Slope limit coefficient is used to define the maximum change in
battery SOC. There is a requirement to configure slope limit
coefficient based on charging status and battery temperature
threshold. Add support for it through the following properties.

- qcom,slope-limit-temp-threshold
- qcom,slope-limit-coeffs

Possibe values allowed for slope limit coefficient is 0 to 31.

Change-Id: I41eacb13734f1692a16c1b011c58a488e46515ec
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
drivers/power/supply/qcom/fg-core.h
drivers/power/supply/qcom/qpnp-fg-gen3.c

index 8adfeeb..dffacc7 100644 (file)
@@ -320,6 +320,27 @@ First Level Node - FG Gen3 device
                    to be configured in conjunction with the charger side
                    configuration for proper functionality.
 
+- qcom,slope-limit-temp-threshold
+       Usage:      optional
+       Value type: <u32>
+       Definition: Battery temperature threshold to decide when slope limit
+                   coefficients should be applied along with charging status.
+                   Unit is in decidegC.
+
+- qcom,slope-limit-coeffs
+       Usage:      optional
+       Value type: <prop-encoded-array>
+       Definition: A list of integers which holds the slope limit coefficients
+                   in the following order. Allowed size is 4. Possible values
+                   are from 0 to 31. Unit is in decipercentage.
+                   Element 0 - Low temperature discharging
+                   Element 1 - Low temperature charging
+                   Element 2 - High temperature discharging
+                   Element 3 - High temperature charging
+                   These coefficients have to be specified along with the
+                   property "qcom,slope-limit-temp-threshold" to make dynamic
+                   slope limit adjustment functional.
+
 ==========================================================
 Second Level Nodes - Peripherals managed by FG Gen3 driver
 ==========================================================
@@ -354,6 +375,8 @@ pmi8998_fg: qpnp,fg {
        qcom,ki-coeff-soc-dischg = <30 60 90>;
        qcom,ki-coeff-med-dischg = <800 1000 1400>;
        qcom,ki-coeff-hi-dischg = <1200 1500 2100>;
+       qcom,slope-limit-temp-threshold = <100>;
+       qcom,slope-limit-coeffs = <10 11 12 13>;
        status = "okay";
 
        qcom,fg-batt-soc@4000 {
index 0d3fcc2..936a3a0 100644 (file)
@@ -71,6 +71,8 @@
 #define KI_COEFF_MAX                   62200
 #define KI_COEFF_SOC_LEVELS            3
 
+#define SLOPE_LIMIT_COEFF_MAX          31
+
 /* Debug flag definitions */
 enum fg_debug_flag {
        FG_IRQ                  = BIT(0), /* Show interrupts */
@@ -164,6 +166,7 @@ enum fg_sram_param_id {
        FG_SRAM_KI_COEFF_HI_DISCHG,
        FG_SRAM_ESR_TIGHT_FILTER,
        FG_SRAM_ESR_BROAD_FILTER,
+       FG_SRAM_SLOPE_LIMIT,
        FG_SRAM_MAX,
 };
 
@@ -202,6 +205,14 @@ enum wa_flags {
        PMI8998_V1_REV_WA = BIT(0),
 };
 
+enum slope_limit_status {
+       LOW_TEMP_DISCHARGE = 0,
+       LOW_TEMP_CHARGE,
+       HIGH_TEMP_DISCHARGE,
+       HIGH_TEMP_CHARGE,
+       SLOPE_LIMIT_NUM_COEFFS,
+};
+
 /* DT parameters for FG device */
 struct fg_dt_props {
        bool    force_load_profile;
@@ -234,10 +245,12 @@ struct fg_dt_props {
        int     esr_broad_flt_upct;
        int     esr_tight_lt_flt_upct;
        int     esr_broad_lt_flt_upct;
+       int     slope_limit_temp;
        int     jeita_thresholds[NUM_JEITA_LEVELS];
        int     ki_coeff_soc[KI_COEFF_SOC_LEVELS];
        int     ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
        int     ki_coeff_hi_dischg[KI_COEFF_SOC_LEVELS];
+       int     slope_limit_coeffs[SLOPE_LIMIT_NUM_COEFFS];
 };
 
 /* parameters from battery profile */
@@ -341,6 +354,7 @@ struct fg_chip {
        int                     maint_soc;
        int                     delta_soc;
        int                     last_msoc;
+       enum slope_limit_status slope_limit_sts;
        bool                    profile_available;
        bool                    profile_loaded;
        bool                    battery_missing;
@@ -352,6 +366,7 @@ struct fg_chip {
        bool                    soc_reporting_ready;
        bool                    esr_flt_cold_temp_en;
        bool                    bsoc_delta_irq_en;
+       bool                    slope_limit_en;
        struct completion       soc_update;
        struct completion       soc_ready;
        struct delayed_work     profile_load_work;
index 6b7c6d2..4dd5edb 100644 (file)
@@ -31,6 +31,8 @@
 #define FG_MEM_INFO_PMI8998            0x0D
 
 /* SRAM address and offset in ascending order */
+#define SLOPE_LIMIT_WORD               3
+#define SLOPE_LIMIT_OFFSET             0
 #define CUTOFF_VOLT_WORD               5
 #define CUTOFF_VOLT_OFFSET             0
 #define SYS_TERM_CURR_WORD             6
@@ -220,6 +222,8 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = {
                1, 512, 1000000, 0, fg_encode_default, NULL),
        PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
                1, 512, 1000000, 0, fg_encode_default, NULL),
+       PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
+               0, fg_encode_default, NULL),
 };
 
 static struct fg_sram_param pmi8998_v2_sram_params[] = {
@@ -286,6 +290,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
                1, 512, 1000000, 0, fg_encode_default, NULL),
        PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
                1, 512, 1000000, 0, fg_encode_default, NULL),
+       PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
+               0, fg_encode_default, NULL),
 };
 
 static struct fg_alg_flag pmi8998_v1_alg_flags[] = {
@@ -1770,6 +1776,48 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip)
        return 0;
 }
 
+static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
+{
+       enum slope_limit_status status;
+       int rc;
+       u8 buf;
+
+       if (!chip->slope_limit_en)
+               return 0;
+
+       if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
+               chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
+               if (batt_temp < chip->dt.slope_limit_temp)
+                       status = LOW_TEMP_CHARGE;
+               else
+                       status = HIGH_TEMP_CHARGE;
+       } else {
+               if (batt_temp < chip->dt.slope_limit_temp)
+                       status = LOW_TEMP_DISCHARGE;
+               else
+                       status = HIGH_TEMP_DISCHARGE;
+       }
+
+       if (chip->slope_limit_sts == status)
+               return 0;
+
+       fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
+               chip->dt.slope_limit_coeffs[status], &buf);
+       rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
+                       chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
+                       chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
+       if (rc < 0) {
+               pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
+                       rc);
+               return rc;
+       }
+
+       chip->slope_limit_sts = status;
+       fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
+               buf);
+       return 0;
+}
+
 static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
 {
        u8 esr_tight_lt_flt, esr_broad_lt_flt;
@@ -1918,7 +1966,7 @@ static void status_change_work(struct work_struct *work)
        struct fg_chip *chip = container_of(work,
                        struct fg_chip, status_change_work);
        union power_supply_propval prop = {0, };
-       int rc;
+       int rc, batt_temp;
 
        if (!batt_psy_initialized(chip)) {
                fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
@@ -1971,6 +2019,14 @@ static void status_change_work(struct work_struct *work)
        if (rc < 0)
                pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
 
+       rc = fg_get_battery_temp(chip, &batt_temp);
+       if (!rc) {
+               rc = fg_slope_limit_config(chip, batt_temp);
+               if (rc < 0)
+                       pr_err("Error in configuring slope limiter rc:%d\n",
+                               rc);
+       }
+
        fg_batt_avg_update(chip);
 
 out:
@@ -3214,6 +3270,10 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
        if (rc < 0)
                pr_err("Error in configuring ESR filter rc:%d\n", rc);
 
+       rc = fg_slope_limit_config(chip, batt_temp);
+       if (rc < 0)
+               pr_err("Error in configuring slope limiter rc:%d\n", rc);
+
        if (!batt_psy_initialized(chip)) {
                chip->last_batt_temp = batt_temp;
                return IRQ_HANDLED;
@@ -3451,6 +3511,40 @@ static int fg_register_interrupts(struct fg_chip *chip)
        return 0;
 }
 
+static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
+{
+       struct device_node *node = chip->dev->of_node;
+       int rc, i;
+
+       rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
+                       &chip->dt.slope_limit_temp);
+       if (rc < 0)
+               return 0;
+
+       rc = of_property_count_elems_of_size(node, "qcom,slope-limit-coeffs",
+                       sizeof(u32));
+       if (rc != SLOPE_LIMIT_NUM_COEFFS)
+               return -EINVAL;
+
+       rc = of_property_read_u32_array(node, "qcom,slope-limit-coeffs",
+                       chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
+       if (rc < 0) {
+               pr_err("Error in reading qcom,slope-limit-coeffs, rc=%d\n", rc);
+               return rc;
+       }
+
+       for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
+               if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
+                       chip->dt.slope_limit_coeffs[i] < 0) {
+                       pr_err("Incorrect slope limit coefficient\n");
+                       return -EINVAL;
+               }
+       }
+
+       chip->slope_limit_en = true;
+       return 0;
+}
+
 static int fg_parse_ki_coefficients(struct fg_chip *chip)
 {
        struct device_node *node = chip->dev->of_node;
@@ -3839,6 +3933,11 @@ static int fg_parse_dt(struct fg_chip *chip)
                chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
        else
                chip->dt.esr_broad_lt_flt_upct = temp;
+
+       rc = fg_parse_slope_limit_coefficients(chip);
+       if (rc < 0)
+               pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
+
        return 0;
 }