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

Commit 3797ea57 authored by Sahil Chandna's avatar Sahil Chandna Committed by Subbaraman Narayanamurthy
Browse files

power: fg-alg: Add support for OCV based step charging in TTF algorithm



Currently TTF algorithm support Vbatt based step charging, but since
oscillation in Vbatt is high when the load changes abruptly, we have
moved to OCV based step charging. Add support for OCV based step
charging in TTF algorithm.

Change-Id: Iac2b6e694ef7b93cf7cedd237752d1eea0cb8ece
Signed-off-by: default avatarSahil Chandna <chandna@codeaurora.org>
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent 41191ad1
Loading
Loading
Loading
Loading
+71 −33
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2018 The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt)	"ALG: %s: " fmt, __func__
@@ -886,6 +886,62 @@ static int ttf_lerp(const struct ttf_pt *pts, size_t tablesize,
	return -EINVAL;
}

static int get_step_chg_current_window(struct ttf *ttf)
{
	struct range_data *step_chg_cfg = ttf->step_chg_cfg;
	int i, rc, curr_window, vbatt;

	if (ttf->mode == TTF_MODE_V_STEP_CHG) {
		rc =  ttf->get_ttf_param(ttf->data, TTF_VBAT, &vbatt);
		if (rc < 0) {
			pr_err("failed to get battery voltage, rc=%d\n", rc);
			return rc;
		}
	} else {
		rc = ttf->get_ttf_param(ttf->data, TTF_OCV, &vbatt);
		if (rc < 0) {
			pr_err("failed to get battery OCV, rc=%d\n", rc);
			return rc;
		}
	}

	curr_window = ttf->step_chg_num_params - 1;
	for (i = 0; i < ttf->step_chg_num_params; i++) {
		if (is_between(step_chg_cfg[i].low_threshold,
			       step_chg_cfg[i].high_threshold,
			       vbatt))
			curr_window = i;
	}

	return curr_window;
}

static int get_cc2cv_current(struct ttf *ttf, int ibatt_avg, int vbatt_avg,
				int float_volt_uv)
{
	int i_cc2cv = 0;

	switch (ttf->mode) {
	case TTF_MODE_NORMAL:
	case TTF_MODE_V_STEP_CHG:
	case TTF_MODE_OCV_STEP_CHG:
		i_cc2cv = ibatt_avg * vbatt_avg /
			max(MILLI_UNIT, float_volt_uv / MILLI_UNIT);
		break;
	case TTF_MODE_QNOVO:
		i_cc2cv = min(
			ttf->cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
			ibatt_avg * vbatt_avg /
			max(MILLI_UNIT, float_volt_uv / MILLI_UNIT));
		break;
	default:
		pr_err("TTF mode %d is not supported\n", ttf->mode);
		break;
	}

	return i_cc2cv;
}

static int get_time_to_full_locked(struct ttf *ttf, int *val)
{
	struct step_chg_data *step_chg_data = ttf->step_chg_data;
@@ -896,7 +952,7 @@ static int get_time_to_full_locked(struct ttf *ttf, int *val)
		ibatt_this_step, t_predicted_this_step, ttf_slope,
		t_predicted_cv, t_predicted = 0, charge_type = 0, i_step,
		float_volt_uv = 0;
	int vbatt_now, multiplier, curr_window = 0, pbatt_avg;
	int multiplier, curr_window = 0, pbatt_avg;
	bool power_approx = false;
	s64 delta_ms;

@@ -985,22 +1041,7 @@ static int get_time_to_full_locked(struct ttf *ttf, int *val)
	pr_debug("TTF: mode: %d\n", ttf->mode);

	/* estimated battery current at the CC to CV transition */
	switch (ttf->mode) {
	case TTF_MODE_NORMAL:
	case TTF_MODE_V_STEP_CHG:
		i_cc2cv = ibatt_avg * vbatt_avg /
			max(MILLI_UNIT, float_volt_uv / MILLI_UNIT);
		break;
	case TTF_MODE_QNOVO:
		i_cc2cv = min(
			ttf->cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
			ibatt_avg * vbatt_avg /
			max(MILLI_UNIT, float_volt_uv / MILLI_UNIT));
		break;
	default:
		pr_err("TTF mode %d is not supported\n", ttf->mode);
		break;
	}
	i_cc2cv = get_cc2cv_current(ttf, ibatt_avg, vbatt_avg, float_volt_uv);
	pr_debug("TTF: i_cc2cv=%d\n", i_cc2cv);

	/* if we are already in CV state then we can skip estimating CC */
@@ -1045,23 +1086,15 @@ static int get_time_to_full_locked(struct ttf *ttf, int *val)
		}
		break;
	case TTF_MODE_V_STEP_CHG:
	case TTF_MODE_OCV_STEP_CHG:
		if (!step_chg_data || !step_chg_cfg)
			break;

		pbatt_avg = vbatt_avg * ibatt_avg;

		rc =  ttf->get_ttf_param(ttf->data, TTF_VBAT, &vbatt_now);
		if (rc < 0) {
			pr_err("failed to get battery voltage, rc=%d\n", rc);
			return rc;
		}

		curr_window = ttf->step_chg_num_params - 1;
		for (i = 0; i < ttf->step_chg_num_params; i++) {
			if (is_between(step_chg_cfg[i].low_threshold,
					step_chg_cfg[i].high_threshold,
					vbatt_now))
				curr_window = i;
		curr_window = get_step_chg_current_window(ttf);
		if (curr_window < 0) {
			pr_err("Failed to get step charging window\n");
			return curr_window;
		}

		pr_debug("TTF: curr_window: %d pbatt_avg: %d\n", curr_window,
@@ -1093,8 +1126,13 @@ static int get_time_to_full_locked(struct ttf *ttf, int *val)
							MILLI_UNIT);
			}

			step_chg_data[i].ocv = step_chg_cfg[i].high_threshold -
			if (ttf->mode == TTF_MODE_V_STEP_CHG)
				step_chg_data[i].ocv =
					step_chg_cfg[i].high_threshold -
					(rbatt * i_step);
			else
				step_chg_data[i].ocv =
					step_chg_cfg[i].high_threshold;

			/* Calculate SOC for each window */
			step_chg_data[i].soc = (float_volt_uv -
+4 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 */

#ifndef __FG_ALG_H__
@@ -69,11 +69,13 @@ enum ttf_mode {
	TTF_MODE_NORMAL = 0,
	TTF_MODE_QNOVO,
	TTF_MODE_V_STEP_CHG,
	TTF_MODE_OCV_STEP_CHG,
};

enum ttf_param {
	TTF_MSOC = 0,
	TTF_VBAT,
	TTF_OCV,
	TTF_IBAT,
	TTF_FCC,
	TTF_MODE,
@@ -114,6 +116,7 @@ struct ttf {
	struct step_chg_data	*step_chg_data;
	struct range_data	*step_chg_cfg;
	bool			step_chg_cfg_valid;
	bool			ocv_step_chg_cfg_valid;
	int			step_chg_num_params;
	int			mode;
	int			last_ttf;