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

Commit 312db073 authored by Anirudh Ghayal's avatar Anirudh Ghayal
Browse files

power: qpnp-qg: Add the filtered voltage based SOC scaling(FVSS)



FVSS scales the SOC to 0 at the programmed cutoff
voltage. It uses the filtered VBAT (fifo-average)
to scale the SOC. FVSS uses a weighted average of
VBAT based SOC and current system SOC.

Change-Id: I58214402b2d79feb25209f5a1451d3f41edf181b
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
parent 8e22f336
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct qg_dt {
	int			shutdown_soc_threshold;
	int			min_sleep_time_secs;
	int			sys_min_volt_mv;
	int			fvss_vbat_mv;
	bool			hold_soc_while_full;
	bool			linearize_soc;
	bool			cl_disable;
@@ -67,6 +68,7 @@ struct qg_dt {
	bool			use_s7_ocv;
	bool			qg_sleep_config;
	bool			qg_fast_chg_cfg;
	bool			fvss_enable;
};

struct qg_esr_data {
@@ -129,6 +131,7 @@ struct qpnp_qg {
	bool			dc_present;
	bool			charge_full;
	bool			force_soc;
	bool			fvss_active;
	int			charge_status;
	int			charge_type;
	int			chg_iterm_ma;
@@ -137,6 +140,8 @@ struct qpnp_qg {
	int			esr_nominal;
	int			soh;
	int			soc_reporting_ready;
	int			last_fifo_v_uv;
	int			last_fifo_i_ua;
	u32			fifo_done_count;
	u32			wa_flags;
	u32			seq_no;
@@ -145,6 +150,8 @@ struct qpnp_qg {
	u32			esr_last;
	u32			s2_state;
	u32			s2_state_mask;
	u32			soc_fvss_entry;
	u32			vbat_fvss_entry;
	ktime_t			last_user_update_time;
	ktime_t			last_fifo_update_time;
	unsigned long		last_maint_soc_update_time;
+91 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "qg-reg.h"
#include "qg-util.h"
#include "qg-defs.h"
#include "qg-profile-lib.h"
#include "qg-soc.h"

#define DEFAULT_UPDATE_TIME_MS			64000
@@ -45,6 +46,11 @@ static ssize_t soc_interval_ms_store(struct device *dev,
}
DEVICE_ATTR_RW(soc_interval_ms);

static int qg_fvss_delta_soc_interval_ms = 10000;
module_param_named(
	fvss_soc_interval_ms, qg_fvss_delta_soc_interval_ms, int, 0600
);

static int qg_delta_soc_cold_interval_ms = 4000;
static ssize_t soc_cold_interval_ms_show(struct device *dev,
		struct device_attribute *attr, char *buf)
@@ -87,6 +93,84 @@ static ssize_t maint_soc_update_ms_store(struct device *dev,
}
DEVICE_ATTR_RW(maint_soc_update_ms);

/* FVSS scaling only based on VBAT */
static int qg_fvss_vbat_scaling = 1;
module_param_named(
	fvss_vbat_scaling, qg_fvss_vbat_scaling, int, 0600
);

static int qg_process_fvss_soc(struct qpnp_qg *chip, int sys_soc)
{
	int rc, vbat_uv = 0, vbat_cutoff_uv = chip->dt.vbatt_cutoff_mv * 1000;
	int soc_vbat = 0, wt_vbat = 0, wt_sys = 0, soc_fvss = 0;

	if (!chip->dt.fvss_enable)
		return 0;

	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING)
		goto exit_soc_scale;

	rc = qg_get_battery_voltage(chip, &vbat_uv);
	if (rc < 0)
		goto exit_soc_scale;

	if (!chip->last_fifo_v_uv)
		chip->last_fifo_v_uv = vbat_uv;

	if (chip->last_fifo_v_uv > (chip->dt.fvss_vbat_mv * 1000)) {
		qg_dbg(chip, QG_DEBUG_SOC, "FVSS: last_fifo_v=%d fvss_entry_uv=%d - exit\n",
			chip->last_fifo_v_uv, chip->dt.fvss_vbat_mv * 1000);
		goto exit_soc_scale;
	}

	/* Enter FVSS */
	if (!chip->fvss_active) {
		chip->vbat_fvss_entry = CAP(vbat_cutoff_uv,
					chip->dt.fvss_vbat_mv * 1000,
					chip->last_fifo_v_uv);
		chip->soc_fvss_entry = sys_soc;
		chip->fvss_active = true;
	} else if (chip->last_fifo_v_uv > chip->vbat_fvss_entry) {
		/* VBAT has gone beyond the entry voltage */
		chip->vbat_fvss_entry = chip->last_fifo_v_uv;
		chip->soc_fvss_entry = sys_soc;
	}

	soc_vbat = qg_linear_interpolate(chip->soc_fvss_entry,
					chip->vbat_fvss_entry,
					0,
					vbat_cutoff_uv,
					chip->last_fifo_v_uv);
	soc_vbat = CAP(0, 100, soc_vbat);

	if (qg_fvss_vbat_scaling) {
		wt_vbat = 100;
		wt_sys = 0;
	} else {
		wt_sys = qg_linear_interpolate(100,
					chip->soc_fvss_entry,
					0,
					0,
					sys_soc);
		wt_sys = CAP(0, 100, wt_sys);
		wt_vbat = 100 - wt_sys;
	}

	soc_fvss = ((soc_vbat * wt_vbat) + (sys_soc * wt_sys)) / 100;
	soc_fvss = CAP(0, 100, soc_fvss);

	qg_dbg(chip, QG_DEBUG_SOC, "FVSS: vbat_fvss_entry=%d soc_fvss_entry=%d cutoff_uv=%d vbat_uv=%d fifo_avg_v=%d soc_vbat=%d sys_soc=%d wt_vbat=%d wt_sys=%d soc_fvss=%d\n",
			chip->vbat_fvss_entry, chip->soc_fvss_entry,
			vbat_cutoff_uv, vbat_uv, chip->last_fifo_v_uv,
			soc_vbat, sys_soc, wt_vbat, wt_sys, soc_fvss);

	return soc_fvss;

exit_soc_scale:
	chip->fvss_active = false;
	return sys_soc;
}

int qg_adjust_sys_soc(struct qpnp_qg *chip)
{
	int soc, vbat_uv, rc;
@@ -113,8 +197,11 @@ int qg_adjust_sys_soc(struct qpnp_qg *chip)
		soc = DIV_ROUND_CLOSEST(chip->sys_soc, 100);
	}

	qg_dbg(chip, QG_DEBUG_SOC, "last_adj_sys_soc=%d  adj_sys_soc=%d\n",
					chip->last_adj_ssoc, soc);
	qg_dbg(chip, QG_DEBUG_SOC, "sys_soc=%d adjusted sys_soc=%d\n",
					chip->sys_soc, soc);

	soc = qg_process_fvss_soc(chip, soc);

	chip->last_adj_ssoc = soc;

	return soc;
@@ -144,6 +231,8 @@ static void get_next_update_time(struct qpnp_qg *chip)
	else if (chip->maint_soc > 0 && chip->maint_soc >= chip->recharge_soc)
		/* if in maintenance mode scale slower */
		min_delta_soc_interval_ms = qg_maint_soc_update_ms;
	else if (chip->fvss_active)
		min_delta_soc_interval_ms = qg_fvss_delta_soc_interval_ms;

	if (!min_delta_soc_interval_ms)
		min_delta_soc_interval_ms = 1000;	/* 1 second */
+23 −0
Original line number Diff line number Diff line
@@ -493,6 +493,9 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length)
		chip->kdata.fifo[j].interval = sample_interval;
		chip->kdata.fifo[j].count = sample_count;

		chip->last_fifo_v_uv = chip->kdata.fifo[j].v;
		chip->last_fifo_i_ua = chip->kdata.fifo[j].i;

		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n",
					j, fifo_v,
					chip->kdata.fifo[j].v,
@@ -557,6 +560,9 @@ static int qg_process_accumulator(struct qpnp_qg *chip)
	if (chip->kdata.fifo_length == MAX_FIFO_LENGTH)
		chip->kdata.fifo_length = MAX_FIFO_LENGTH - 1;

	chip->last_fifo_v_uv = chip->kdata.fifo[index].v;
	chip->last_fifo_i_ua = chip->kdata.fifo[index].i;

	if (chip->kdata.fifo_length == 1)	/* Only accumulator data */
		chip->kdata.seq_no = chip->seq_no++ % U32_MAX;

@@ -2101,6 +2107,9 @@ static int qg_psy_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_POWER_AVG:
		rc = qg_get_power(chip, &pval->intval, true);
		break;
	case POWER_SUPPLY_PROP_SCALE_MODE_EN:
		pval->intval = chip->fvss_active;
		break;
	default:
		pr_debug("Unsupported property %d\n", psp);
		break;
@@ -2159,6 +2168,7 @@ static enum power_supply_property qg_psy_props[] = {
	POWER_SUPPLY_PROP_VOLTAGE_AVG,
	POWER_SUPPLY_PROP_POWER_AVG,
	POWER_SUPPLY_PROP_POWER_NOW,
	POWER_SUPPLY_PROP_SCALE_MODE_EN,
};

static const struct power_supply_desc qg_psy_desc = {
@@ -3818,6 +3828,7 @@ static int qg_parse_cl_dt(struct qpnp_qg *chip)
#define ESR_CHG_MIN_IBAT_UA		(-450000)
#define DEFAULT_SLEEP_TIME_SECS		1800 /* 30 mins */
#define DEFAULT_SYS_MIN_VOLT_MV		2800
#define DEFAULT_FVSS_VBAT_MV		3500
static int qg_parse_dt(struct qpnp_qg *chip)
{
	int rc = 0;
@@ -4049,6 +4060,18 @@ static int qg_parse_dt(struct qpnp_qg *chip)
	else
		chip->dt.min_sleep_time_secs = temp;

	if (of_property_read_bool(node, "qcom,fvss-enable")) {

		chip->dt.fvss_enable = true;

		rc = of_property_read_u32(node,
				"qcom,fvss-vbatt-mv", &temp);
		if (rc < 0)
			chip->dt.fvss_vbat_mv = DEFAULT_FVSS_VBAT_MV;
		else
			chip->dt.fvss_vbat_mv = temp;
	}

	qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d\n",
			chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
			chip->dt.delta_soc, chip->dt.qg_ext_sense);