Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f43149e6 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: fg-alg: Loosen capacity learning qualification criterion"

parents 016bf866 9919bd8f
Loading
Loading
Loading
Loading
+107 −20
Original line number Original line Diff line number Diff line
@@ -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);
@@ -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);
@@ -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);
@@ -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:
@@ -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;
	}
	}
@@ -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
@@ -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) {
@@ -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);
@@ -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
+3 −0
Original line number Original line Diff line number Diff line
@@ -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;
+2 −0
Original line number Original line Diff line number Diff line
@@ -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)
+80 −52
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
@@ -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