Loading drivers/power/supply/qcom/fg-alg.c +107 −20 Original line number Original line Diff line number Diff line Loading @@ -362,17 +362,63 @@ static void cap_learning_post_process(struct cap_learning *cl) cl->final_cap_uah, old_cap, cl->learned_cap_uah); cl->final_cap_uah, old_cap, cl->learned_cap_uah); } } /** * cap_wt_learning_process_full_data - * @cl: Capacity learning object * @batt_soc_pct: Battery State of Charge in percent * @cc_soc_delta_pct: percentage change in cc_soc * @delta_batt_soc_pct: percentage change in battery State of Charge * * Calculates the final learnt capacity when * weighted capacity learning is enabled. * */ static int cap_wt_learning_process_full_data(struct cap_learning *cl, int batt_soc_pct, int cc_soc_delta_pct, int delta_batt_soc_pct) { int64_t delta_cap_uah, del_cap_uah, total_cap_uah, res_cap_uah, wt_learnt_cap_uah; /* If the delta is < 10%, then skip processing full data */ if (delta_batt_soc_pct < cl->dt.min_delta_batt_soc) { pr_debug("batt_soc_delta_pct: %d\n", delta_batt_soc_pct); return -ERANGE; } delta_cap_uah = div64_s64(cl->learned_cap_uah * cc_soc_delta_pct, 100); /* Learnt Capacity from end Battery SOC to 100 % */ res_cap_uah = div64_s64(cl->learned_cap_uah * (100 - batt_soc_pct), 100); total_cap_uah = cl->init_cap_uah + delta_cap_uah + res_cap_uah; /* * difference in capacity learnt in this * charge cycle and previous learnt capacity */ del_cap_uah = total_cap_uah - cl->learned_cap_uah; /* Applying weight based on change in battery SOC */ wt_learnt_cap_uah = div64_s64(del_cap_uah * delta_batt_soc_pct, 100); cl->final_cap_uah = cl->learned_cap_uah + wt_learnt_cap_uah; pr_debug("cc_soc_delta_pct=%d total_cap_uah=%lld\n", cc_soc_delta_pct, cl->final_cap_uah); return 0; } /** /** * cap_learning_process_full_data - * cap_learning_process_full_data - * @cl: Capacity learning object * @cl: Capacity learning object * @batt_soc_msb: Most significant byte of Battery State of Charge * * * Processes the coulomb counter during charge termination and calculates the * Processes the coulomb counter during charge termination and calculates the * delta w.r.to the coulomb counter obtained earlier when the learning begun. * delta w.r.to the coulomb counter obtained earlier when the learning begun. * * */ */ static int cap_learning_process_full_data(struct cap_learning *cl) static int cap_learning_process_full_data(struct cap_learning *cl, int batt_soc_msb) { { int rc, cc_soc_sw, cc_soc_delta_pct; int rc, cc_soc_sw, cc_soc_delta_pct, delta_batt_soc_pct, batt_soc_pct; int64_t delta_cap_uah; int64_t delta_cap_uah; rc = cl->get_cc_soc(cl->data, &cc_soc_sw); rc = cl->get_cc_soc(cl->data, &cc_soc_sw); Loading @@ -381,10 +427,19 @@ static int cap_learning_process_full_data(struct cap_learning *cl) return rc; return rc; } } batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); delta_batt_soc_pct = batt_soc_pct - cl->init_batt_soc; cc_soc_delta_pct = cc_soc_delta_pct = div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100, div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100, cl->cc_soc_max); cl->cc_soc_max); if (cl->dt.cl_wt_enable) { rc = cap_wt_learning_process_full_data(cl, batt_soc_pct, cc_soc_delta_pct, delta_batt_soc_pct); return rc; } /* If the delta is < 50%, then skip processing full data */ /* If the delta is < 50%, then skip processing full data */ if (cc_soc_delta_pct < 50) { if (cc_soc_delta_pct < 50) { pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct); pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct); Loading Loading @@ -415,12 +470,14 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) batt_soc_msb = batt_soc >> 24; batt_soc_msb = batt_soc >> 24; batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); if (!cl->dt.cl_wt_enable) { if (batt_soc_pct > cl->dt.max_start_soc || if (batt_soc_pct > cl->dt.max_start_soc || batt_soc_pct < cl->dt.min_start_soc) { batt_soc_pct < cl->dt.min_start_soc) { pr_debug("Battery SOC %d is high/low, not starting\n", pr_debug("Battery SOC %d is high/low, not starting\n", batt_soc_pct); batt_soc_pct); return -EINVAL; return -EINVAL; } } } cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb, cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb, FULL_SOC_RAW); FULL_SOC_RAW); Loading @@ -444,6 +501,7 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) } } cl->init_cc_soc_sw = cc_soc_sw; cl->init_cc_soc_sw = cc_soc_sw; cl->init_batt_soc = batt_soc_pct; pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", batt_soc_msb, cl->init_cc_soc_sw); batt_soc_msb, cl->init_cc_soc_sw); out: out: Loading @@ -453,18 +511,19 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) /** /** * cap_learning_done - * cap_learning_done - * @cl: Capacity learning object * @cl: Capacity learning object * @batt_soc_msb: Most significant byte of battery State of Charge * * * Top level function for getting coulomb counter and post processing the * Top level function for getting coulomb counter and post processing the * data once the capacity learning is complete after charge termination. * data once the capacity learning is complete after charge termination. * * */ */ static int cap_learning_done(struct cap_learning *cl) static int cap_learning_done(struct cap_learning *cl, int batt_soc_msb) { { int rc; int rc; rc = cap_learning_process_full_data(cl); rc = cap_learning_process_full_data(cl, batt_soc_msb); if (rc < 0) { if (rc < 0) { pr_err("Error in processing cap learning full data, rc=%d\n", pr_debug("Error in processing cap learning full data, rc=%d\n", rc); rc); goto out; goto out; } } Loading @@ -483,6 +542,30 @@ static int cap_learning_done(struct cap_learning *cl) return rc; return rc; } } /** * cap_wt_learning_update - * @cl: Capacity learning object * @batt_soc_msb: Most significant byte of battery State of Charge * @input_present: Indicator for input presence * * Called by cap_learning_update when weighted learning is enabled * */ static void cap_wt_learning_update(struct cap_learning *cl, int batt_soc_msb, bool input_present) { int rc; if (!input_present) { rc = cap_learning_done(cl, batt_soc_msb); if (rc < 0) pr_debug("Error in completing capacity learning, rc=%d\n", rc); cl->active = false; cl->init_cap_uah = 0; } } /** /** * cap_learning_update - * cap_learning_update - * @cl: Capacity learning object * @cl: Capacity learning object Loading Loading @@ -519,6 +602,10 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, pr_debug("Charge_status: %d active: %d batt_soc: %d\n", pr_debug("Charge_status: %d active: %d batt_soc: %d\n", charge_status, cl->active, batt_soc_msb); charge_status, cl->active, batt_soc_msb); if (cl->active && cl->dt.cl_wt_enable) cap_wt_learning_update(cl, batt_soc_msb, input_present); /* Initialize the starting point of learning capacity */ /* Initialize the starting point of learning capacity */ if (!cl->active) { if (!cl->active) { if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { Loading @@ -531,7 +618,7 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, } } } else { } else { if (charge_done) { if (charge_done) { rc = cap_learning_done(cl); rc = cap_learning_done(cl, batt_soc_msb); if (rc < 0) if (rc < 0) pr_err("Error in completing capacity learning, rc=%d\n", pr_err("Error in completing capacity learning, rc=%d\n", rc); rc); Loading @@ -540,17 +627,17 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, cl->init_cap_uah = 0; cl->init_cap_uah = 0; } } if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING) { if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING && if (!input_present) { !input_present) { pr_debug("Capacity learning aborted @ battery SOC %d\n", pr_debug("Capacity learning aborted @ battery SOC %d\n", batt_soc_msb); batt_soc_msb); cl->active = false; cl->active = false; cl->init_cap_uah = 0; cl->init_cap_uah = 0; prime_cc = true; prime_cc = true; } } } if (charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { if (charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING && !cl->dt.cl_wt_enable) { if (qnovo_en && input_present) { if (qnovo_en && input_present) { /* /* * Don't abort the capacity learning when qnovo * Don't abort the capacity learning when qnovo Loading drivers/power/supply/qcom/fg-alg.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -41,12 +41,15 @@ struct cl_params { int max_cap_limit; int max_cap_limit; int min_cap_limit; int min_cap_limit; int skew_decipct; int skew_decipct; int min_delta_batt_soc; bool cl_wt_enable; }; }; struct cap_learning { struct cap_learning { void *data; void *data; int init_cc_soc_sw; int init_cc_soc_sw; int cc_soc_max; int cc_soc_max; int init_batt_soc; int64_t nom_cap_uah; int64_t nom_cap_uah; int64_t init_cap_uah; int64_t init_cap_uah; int64_t final_cap_uah; int64_t final_cap_uah; Loading drivers/power/supply/qcom/fg-reg.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,8 @@ #define BATT_THERM_PULL_UP_400K 3 #define BATT_THERM_PULL_UP_400K 3 #define BATT_THERM_PULL_UP_MASK GENMASK(1, 0) #define BATT_THERM_PULL_UP_MASK GENMASK(1, 0) #define ADC_RR_BATT_THERM_FREQ(chip) (chip->rradc_base + 0x82) #define ADC_RR_BATT_TEMP_LSB(chip) (chip->rradc_base + 0x88) #define ADC_RR_BATT_TEMP_LSB(chip) (chip->rradc_base + 0x88) #define ADC_RR_BATT_TEMP_MSB(chip) (chip->rradc_base + 0x89) #define ADC_RR_BATT_TEMP_MSB(chip) (chip->rradc_base + 0x89) #define GEN4_BATT_TEMP_MSB_MASK GENMASK(1, 0) #define GEN4_BATT_TEMP_MSB_MASK GENMASK(1, 0) Loading drivers/power/supply/qcom/qpnp-fg-gen4.c +80 −52 Original line number Original line Diff line number Diff line Loading @@ -201,6 +201,7 @@ struct fg_dt_props { int batt_temp_hot_thresh; int batt_temp_hot_thresh; int batt_temp_hyst; int batt_temp_hyst; int batt_temp_delta; int batt_temp_delta; u32 batt_therm_freq; int esr_pulse_thresh_ma; int esr_pulse_thresh_ma; int esr_meas_curr_ma; int esr_meas_curr_ma; int slope_limit_temp; int slope_limit_temp; Loading Loading @@ -3931,6 +3932,76 @@ static int fg_alg_init(struct fg_gen4_chip *chip) #define BATT_TEMP_HYST_MASK GENMASK(3, 0) #define BATT_TEMP_HYST_MASK GENMASK(3, 0) #define BATT_TEMP_DELTA_MASK GENMASK(7, 4) #define BATT_TEMP_DELTA_MASK GENMASK(7, 4) #define BATT_TEMP_DELTA_SHIFT 4 #define BATT_TEMP_DELTA_SHIFT 4 static int fg_gen4_batt_temp_config(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; u8 buf, val, mask; if (chip->dt.batt_temp_cold_thresh != -EINVAL) { fg_encode(fg->sp, FG_SRAM_BATT_TEMP_COLD, chip->dt.batt_temp_cold_thresh, &buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_word, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_byte, &buf, fg->sp[FG_SRAM_BATT_TEMP_COLD].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_cold_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hot_thresh != -EINVAL) { fg_encode(fg->sp, FG_SRAM_BATT_TEMP_HOT, chip->dt.batt_temp_hot_thresh, &buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_word, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_byte, &buf, fg->sp[FG_SRAM_BATT_TEMP_HOT].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hot_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hyst != -EINVAL) { val = chip->dt.batt_temp_hyst & BATT_TEMP_HYST_MASK; mask = BATT_TEMP_HYST_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hyst, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_delta != -EINVAL) { val = (chip->dt.batt_temp_delta << BATT_TEMP_DELTA_SHIFT) & BATT_TEMP_DELTA_MASK; mask = BATT_TEMP_DELTA_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_delta, rc=%d\n", rc); return rc; } } val = (u8)chip->dt.batt_therm_freq; rc = fg_write(fg, ADC_RR_BATT_THERM_FREQ(fg), &val, 1); if (rc < 0) { pr_err("failed to write to 0x%04X, rc=%d\n", ADC_RR_BATT_THERM_FREQ(fg), rc); return rc; } return rc; } static int fg_gen4_hw_init(struct fg_gen4_chip *chip) static int fg_gen4_hw_init(struct fg_gen4_chip *chip) { { struct fg_dev *fg = &chip->fg; struct fg_dev *fg = &chip->fg; Loading Loading @@ -4012,58 +4083,9 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } } } if (chip->dt.batt_temp_cold_thresh != -EINVAL) { rc = fg_gen4_batt_temp_config(chip); fg_encode(fg->sp, FG_SRAM_BATT_TEMP_COLD, if (rc < 0) chip->dt.batt_temp_cold_thresh, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_word, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_byte, buf, fg->sp[FG_SRAM_BATT_TEMP_COLD].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_cold_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hot_thresh != -EINVAL) { fg_encode(fg->sp, FG_SRAM_BATT_TEMP_HOT, chip->dt.batt_temp_hot_thresh, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_word, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_byte, buf, fg->sp[FG_SRAM_BATT_TEMP_HOT].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hot_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hyst != -EINVAL) { val = chip->dt.batt_temp_hyst & BATT_TEMP_HYST_MASK; mask = BATT_TEMP_HYST_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hyst, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_delta != -EINVAL) { val = (chip->dt.batt_temp_delta << BATT_TEMP_DELTA_SHIFT) & BATT_TEMP_DELTA_MASK; mask = BATT_TEMP_DELTA_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_delta, rc=%d\n", rc); return rc; return rc; } } fg_encode(fg->sp, FG_SRAM_ESR_PULSE_THRESH, fg_encode(fg->sp, FG_SRAM_ESR_PULSE_THRESH, chip->dt.esr_pulse_thresh_ma, buf); chip->dt.esr_pulse_thresh_ma, buf); Loading Loading @@ -4451,6 +4473,12 @@ static void fg_gen4_parse_batt_temp_dt(struct fg_gen4_chip *chip) chip->dt.batt_temp_delta = -EINVAL; chip->dt.batt_temp_delta = -EINVAL; else if (temp >= BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) else if (temp >= BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) chip->dt.batt_temp_delta = temp; chip->dt.batt_temp_delta = temp; chip->dt.batt_therm_freq = 8; rc = of_property_read_u32(node, "qcom,fg-batt-therm-freq", &temp); if (temp > 0 && temp <= 255) chip->dt.batt_therm_freq = temp; } } #define DEFAULT_CUTOFF_VOLT_MV 3100 #define DEFAULT_CUTOFF_VOLT_MV 3100 Loading Loading
drivers/power/supply/qcom/fg-alg.c +107 −20 Original line number Original line Diff line number Diff line Loading @@ -362,17 +362,63 @@ static void cap_learning_post_process(struct cap_learning *cl) cl->final_cap_uah, old_cap, cl->learned_cap_uah); cl->final_cap_uah, old_cap, cl->learned_cap_uah); } } /** * cap_wt_learning_process_full_data - * @cl: Capacity learning object * @batt_soc_pct: Battery State of Charge in percent * @cc_soc_delta_pct: percentage change in cc_soc * @delta_batt_soc_pct: percentage change in battery State of Charge * * Calculates the final learnt capacity when * weighted capacity learning is enabled. * */ static int cap_wt_learning_process_full_data(struct cap_learning *cl, int batt_soc_pct, int cc_soc_delta_pct, int delta_batt_soc_pct) { int64_t delta_cap_uah, del_cap_uah, total_cap_uah, res_cap_uah, wt_learnt_cap_uah; /* If the delta is < 10%, then skip processing full data */ if (delta_batt_soc_pct < cl->dt.min_delta_batt_soc) { pr_debug("batt_soc_delta_pct: %d\n", delta_batt_soc_pct); return -ERANGE; } delta_cap_uah = div64_s64(cl->learned_cap_uah * cc_soc_delta_pct, 100); /* Learnt Capacity from end Battery SOC to 100 % */ res_cap_uah = div64_s64(cl->learned_cap_uah * (100 - batt_soc_pct), 100); total_cap_uah = cl->init_cap_uah + delta_cap_uah + res_cap_uah; /* * difference in capacity learnt in this * charge cycle and previous learnt capacity */ del_cap_uah = total_cap_uah - cl->learned_cap_uah; /* Applying weight based on change in battery SOC */ wt_learnt_cap_uah = div64_s64(del_cap_uah * delta_batt_soc_pct, 100); cl->final_cap_uah = cl->learned_cap_uah + wt_learnt_cap_uah; pr_debug("cc_soc_delta_pct=%d total_cap_uah=%lld\n", cc_soc_delta_pct, cl->final_cap_uah); return 0; } /** /** * cap_learning_process_full_data - * cap_learning_process_full_data - * @cl: Capacity learning object * @cl: Capacity learning object * @batt_soc_msb: Most significant byte of Battery State of Charge * * * Processes the coulomb counter during charge termination and calculates the * Processes the coulomb counter during charge termination and calculates the * delta w.r.to the coulomb counter obtained earlier when the learning begun. * delta w.r.to the coulomb counter obtained earlier when the learning begun. * * */ */ static int cap_learning_process_full_data(struct cap_learning *cl) static int cap_learning_process_full_data(struct cap_learning *cl, int batt_soc_msb) { { int rc, cc_soc_sw, cc_soc_delta_pct; int rc, cc_soc_sw, cc_soc_delta_pct, delta_batt_soc_pct, batt_soc_pct; int64_t delta_cap_uah; int64_t delta_cap_uah; rc = cl->get_cc_soc(cl->data, &cc_soc_sw); rc = cl->get_cc_soc(cl->data, &cc_soc_sw); Loading @@ -381,10 +427,19 @@ static int cap_learning_process_full_data(struct cap_learning *cl) return rc; return rc; } } batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); delta_batt_soc_pct = batt_soc_pct - cl->init_batt_soc; cc_soc_delta_pct = cc_soc_delta_pct = div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100, div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100, cl->cc_soc_max); cl->cc_soc_max); if (cl->dt.cl_wt_enable) { rc = cap_wt_learning_process_full_data(cl, batt_soc_pct, cc_soc_delta_pct, delta_batt_soc_pct); return rc; } /* If the delta is < 50%, then skip processing full data */ /* If the delta is < 50%, then skip processing full data */ if (cc_soc_delta_pct < 50) { if (cc_soc_delta_pct < 50) { pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct); pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct); Loading Loading @@ -415,12 +470,14 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) batt_soc_msb = batt_soc >> 24; batt_soc_msb = batt_soc >> 24; batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); if (!cl->dt.cl_wt_enable) { if (batt_soc_pct > cl->dt.max_start_soc || if (batt_soc_pct > cl->dt.max_start_soc || batt_soc_pct < cl->dt.min_start_soc) { batt_soc_pct < cl->dt.min_start_soc) { pr_debug("Battery SOC %d is high/low, not starting\n", pr_debug("Battery SOC %d is high/low, not starting\n", batt_soc_pct); batt_soc_pct); return -EINVAL; return -EINVAL; } } } cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb, cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb, FULL_SOC_RAW); FULL_SOC_RAW); Loading @@ -444,6 +501,7 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) } } cl->init_cc_soc_sw = cc_soc_sw; cl->init_cc_soc_sw = cc_soc_sw; cl->init_batt_soc = batt_soc_pct; pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", batt_soc_msb, cl->init_cc_soc_sw); batt_soc_msb, cl->init_cc_soc_sw); out: out: Loading @@ -453,18 +511,19 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) /** /** * cap_learning_done - * cap_learning_done - * @cl: Capacity learning object * @cl: Capacity learning object * @batt_soc_msb: Most significant byte of battery State of Charge * * * Top level function for getting coulomb counter and post processing the * Top level function for getting coulomb counter and post processing the * data once the capacity learning is complete after charge termination. * data once the capacity learning is complete after charge termination. * * */ */ static int cap_learning_done(struct cap_learning *cl) static int cap_learning_done(struct cap_learning *cl, int batt_soc_msb) { { int rc; int rc; rc = cap_learning_process_full_data(cl); rc = cap_learning_process_full_data(cl, batt_soc_msb); if (rc < 0) { if (rc < 0) { pr_err("Error in processing cap learning full data, rc=%d\n", pr_debug("Error in processing cap learning full data, rc=%d\n", rc); rc); goto out; goto out; } } Loading @@ -483,6 +542,30 @@ static int cap_learning_done(struct cap_learning *cl) return rc; return rc; } } /** * cap_wt_learning_update - * @cl: Capacity learning object * @batt_soc_msb: Most significant byte of battery State of Charge * @input_present: Indicator for input presence * * Called by cap_learning_update when weighted learning is enabled * */ static void cap_wt_learning_update(struct cap_learning *cl, int batt_soc_msb, bool input_present) { int rc; if (!input_present) { rc = cap_learning_done(cl, batt_soc_msb); if (rc < 0) pr_debug("Error in completing capacity learning, rc=%d\n", rc); cl->active = false; cl->init_cap_uah = 0; } } /** /** * cap_learning_update - * cap_learning_update - * @cl: Capacity learning object * @cl: Capacity learning object Loading Loading @@ -519,6 +602,10 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, pr_debug("Charge_status: %d active: %d batt_soc: %d\n", pr_debug("Charge_status: %d active: %d batt_soc: %d\n", charge_status, cl->active, batt_soc_msb); charge_status, cl->active, batt_soc_msb); if (cl->active && cl->dt.cl_wt_enable) cap_wt_learning_update(cl, batt_soc_msb, input_present); /* Initialize the starting point of learning capacity */ /* Initialize the starting point of learning capacity */ if (!cl->active) { if (!cl->active) { if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { Loading @@ -531,7 +618,7 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, } } } else { } else { if (charge_done) { if (charge_done) { rc = cap_learning_done(cl); rc = cap_learning_done(cl, batt_soc_msb); if (rc < 0) if (rc < 0) pr_err("Error in completing capacity learning, rc=%d\n", pr_err("Error in completing capacity learning, rc=%d\n", rc); rc); Loading @@ -540,17 +627,17 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, cl->init_cap_uah = 0; cl->init_cap_uah = 0; } } if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING) { if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING && if (!input_present) { !input_present) { pr_debug("Capacity learning aborted @ battery SOC %d\n", pr_debug("Capacity learning aborted @ battery SOC %d\n", batt_soc_msb); batt_soc_msb); cl->active = false; cl->active = false; cl->init_cap_uah = 0; cl->init_cap_uah = 0; prime_cc = true; prime_cc = true; } } } if (charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { if (charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING && !cl->dt.cl_wt_enable) { if (qnovo_en && input_present) { if (qnovo_en && input_present) { /* /* * Don't abort the capacity learning when qnovo * Don't abort the capacity learning when qnovo Loading
drivers/power/supply/qcom/fg-alg.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -41,12 +41,15 @@ struct cl_params { int max_cap_limit; int max_cap_limit; int min_cap_limit; int min_cap_limit; int skew_decipct; int skew_decipct; int min_delta_batt_soc; bool cl_wt_enable; }; }; struct cap_learning { struct cap_learning { void *data; void *data; int init_cc_soc_sw; int init_cc_soc_sw; int cc_soc_max; int cc_soc_max; int init_batt_soc; int64_t nom_cap_uah; int64_t nom_cap_uah; int64_t init_cap_uah; int64_t init_cap_uah; int64_t final_cap_uah; int64_t final_cap_uah; Loading
drivers/power/supply/qcom/fg-reg.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,8 @@ #define BATT_THERM_PULL_UP_400K 3 #define BATT_THERM_PULL_UP_400K 3 #define BATT_THERM_PULL_UP_MASK GENMASK(1, 0) #define BATT_THERM_PULL_UP_MASK GENMASK(1, 0) #define ADC_RR_BATT_THERM_FREQ(chip) (chip->rradc_base + 0x82) #define ADC_RR_BATT_TEMP_LSB(chip) (chip->rradc_base + 0x88) #define ADC_RR_BATT_TEMP_LSB(chip) (chip->rradc_base + 0x88) #define ADC_RR_BATT_TEMP_MSB(chip) (chip->rradc_base + 0x89) #define ADC_RR_BATT_TEMP_MSB(chip) (chip->rradc_base + 0x89) #define GEN4_BATT_TEMP_MSB_MASK GENMASK(1, 0) #define GEN4_BATT_TEMP_MSB_MASK GENMASK(1, 0) Loading
drivers/power/supply/qcom/qpnp-fg-gen4.c +80 −52 Original line number Original line Diff line number Diff line Loading @@ -201,6 +201,7 @@ struct fg_dt_props { int batt_temp_hot_thresh; int batt_temp_hot_thresh; int batt_temp_hyst; int batt_temp_hyst; int batt_temp_delta; int batt_temp_delta; u32 batt_therm_freq; int esr_pulse_thresh_ma; int esr_pulse_thresh_ma; int esr_meas_curr_ma; int esr_meas_curr_ma; int slope_limit_temp; int slope_limit_temp; Loading Loading @@ -3931,6 +3932,76 @@ static int fg_alg_init(struct fg_gen4_chip *chip) #define BATT_TEMP_HYST_MASK GENMASK(3, 0) #define BATT_TEMP_HYST_MASK GENMASK(3, 0) #define BATT_TEMP_DELTA_MASK GENMASK(7, 4) #define BATT_TEMP_DELTA_MASK GENMASK(7, 4) #define BATT_TEMP_DELTA_SHIFT 4 #define BATT_TEMP_DELTA_SHIFT 4 static int fg_gen4_batt_temp_config(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; u8 buf, val, mask; if (chip->dt.batt_temp_cold_thresh != -EINVAL) { fg_encode(fg->sp, FG_SRAM_BATT_TEMP_COLD, chip->dt.batt_temp_cold_thresh, &buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_word, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_byte, &buf, fg->sp[FG_SRAM_BATT_TEMP_COLD].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_cold_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hot_thresh != -EINVAL) { fg_encode(fg->sp, FG_SRAM_BATT_TEMP_HOT, chip->dt.batt_temp_hot_thresh, &buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_word, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_byte, &buf, fg->sp[FG_SRAM_BATT_TEMP_HOT].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hot_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hyst != -EINVAL) { val = chip->dt.batt_temp_hyst & BATT_TEMP_HYST_MASK; mask = BATT_TEMP_HYST_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hyst, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_delta != -EINVAL) { val = (chip->dt.batt_temp_delta << BATT_TEMP_DELTA_SHIFT) & BATT_TEMP_DELTA_MASK; mask = BATT_TEMP_DELTA_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_delta, rc=%d\n", rc); return rc; } } val = (u8)chip->dt.batt_therm_freq; rc = fg_write(fg, ADC_RR_BATT_THERM_FREQ(fg), &val, 1); if (rc < 0) { pr_err("failed to write to 0x%04X, rc=%d\n", ADC_RR_BATT_THERM_FREQ(fg), rc); return rc; } return rc; } static int fg_gen4_hw_init(struct fg_gen4_chip *chip) static int fg_gen4_hw_init(struct fg_gen4_chip *chip) { { struct fg_dev *fg = &chip->fg; struct fg_dev *fg = &chip->fg; Loading Loading @@ -4012,58 +4083,9 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } } } if (chip->dt.batt_temp_cold_thresh != -EINVAL) { rc = fg_gen4_batt_temp_config(chip); fg_encode(fg->sp, FG_SRAM_BATT_TEMP_COLD, if (rc < 0) chip->dt.batt_temp_cold_thresh, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_word, fg->sp[FG_SRAM_BATT_TEMP_COLD].addr_byte, buf, fg->sp[FG_SRAM_BATT_TEMP_COLD].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_cold_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hot_thresh != -EINVAL) { fg_encode(fg->sp, FG_SRAM_BATT_TEMP_HOT, chip->dt.batt_temp_hot_thresh, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_word, fg->sp[FG_SRAM_BATT_TEMP_HOT].addr_byte, buf, fg->sp[FG_SRAM_BATT_TEMP_HOT].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hot_thresh, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_hyst != -EINVAL) { val = chip->dt.batt_temp_hyst & BATT_TEMP_HYST_MASK; mask = BATT_TEMP_HYST_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_hyst, rc=%d\n", rc); return rc; } } if (chip->dt.batt_temp_delta != -EINVAL) { val = (chip->dt.batt_temp_delta << BATT_TEMP_DELTA_SHIFT) & BATT_TEMP_DELTA_MASK; mask = BATT_TEMP_DELTA_MASK; rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, BATT_TEMP_HYST_DELTA_OFFSET, mask, val, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing batt_temp_delta, rc=%d\n", rc); return rc; return rc; } } fg_encode(fg->sp, FG_SRAM_ESR_PULSE_THRESH, fg_encode(fg->sp, FG_SRAM_ESR_PULSE_THRESH, chip->dt.esr_pulse_thresh_ma, buf); chip->dt.esr_pulse_thresh_ma, buf); Loading Loading @@ -4451,6 +4473,12 @@ static void fg_gen4_parse_batt_temp_dt(struct fg_gen4_chip *chip) chip->dt.batt_temp_delta = -EINVAL; chip->dt.batt_temp_delta = -EINVAL; else if (temp >= BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) else if (temp >= BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) chip->dt.batt_temp_delta = temp; chip->dt.batt_temp_delta = temp; chip->dt.batt_therm_freq = 8; rc = of_property_read_u32(node, "qcom,fg-batt-therm-freq", &temp); if (temp > 0 && temp <= 255) chip->dt.batt_therm_freq = temp; } } #define DEFAULT_CUTOFF_VOLT_MV 3100 #define DEFAULT_CUTOFF_VOLT_MV 3100 Loading