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

Commit 8036198d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: vm_bms: Add a logic to manage SOC reporting after EOC"

parents dfc0210e 0411e48e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -116,6 +116,10 @@ Parent node Optional properties
			The possible values are 1 to 16.
- qcom,batt-aging-comp : A boolean that defines if battery aging compensation
			is enabled.
- qcom,use-reported-soc : Bool property to enable the reported_soc logic. To
			enable this feature, qcom,resume-soc must be defined as
			a proper value. The BMS is also required to control the
			charging, discharging and recharging.

qcom,batt-pres-status node required properties:
- reg : offset and length of the PMIC LBC battery interface BATT_PRES_STATUS
+159 −4
Original line number Diff line number Diff line
@@ -180,6 +180,7 @@ struct bms_dt_cfg {
	int				cfg_low_temp_threshold;
	int				cfg_ibat_avg_samples;
	int				cfg_battery_aging_comp;
	bool				cfg_use_reported_soc;
};

struct qpnp_bms_chip {
@@ -271,6 +272,13 @@ struct qpnp_bms_chip {
	struct power_supply		bms_psy;
	struct power_supply		*batt_psy;
	struct power_supply		*usb_psy;
	bool				reported_soc_in_use;
	bool				charger_removed_since_full;
	bool				charger_reinserted;
	bool				reported_soc_high_current;
	int				reported_soc;
	int				reported_soc_change_sec;
	int				reported_soc_delta;
};

static struct qpnp_bms_chip *the_chip;
@@ -1489,6 +1497,14 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip)
					chip->ocv_at_100 = -EINVAL;
				}
			}
			if (chip->dt.cfg_use_reported_soc) {
				/* begin reported_soc process */
				chip->reported_soc_in_use = true;
				chip->charger_removed_since_full = false;
				chip->charger_reinserted = false;
				chip->reported_soc = 100;
				pr_debug("Begin reported_soc process\n");
			}
		}
	} else {
		if (chip->last_ocv_uv >= chip->ocv_at_100) {
@@ -1502,10 +1518,15 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip)
			 * This gets called once when the SOC falls
			 * below 100.
			 */
			if (chip->reported_soc_in_use
					&& chip->reported_soc == 100) {
				pr_debug("reported_soc=100, last_soc=%d, do not send DISCHARING status\n",
						chip->last_soc);
			} else {
				ret.intval = POWER_SUPPLY_STATUS_DISCHARGING;
				chip->batt_psy->set_property(chip->batt_psy,
					POWER_SUPPLY_PROP_STATUS, &ret);

			}
			pr_debug("SOC dropped (%d) discarding ocv_at_100\n",
							chip->last_soc);
			chip->ocv_at_100 = -EINVAL;
@@ -1520,6 +1541,39 @@ static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
	return chip->prev_voltage_based_soc;
}

static int prepare_reported_soc(struct qpnp_bms_chip *chip)
{
	if (chip->charger_removed_since_full == false) {
		/*
		 * charger is not removed since full,
		 * keep reported_soc as 100 and calculate the delta soc
		 * between reported_soc and last_soc
		 */
		chip->reported_soc = 100;
		chip->reported_soc_delta = 100 - chip->last_soc;
		pr_debug("Keep at reported_soc 100, reported_soc_delta=%d, last_soc=%d\n",
						chip->reported_soc_delta,
						chip->last_soc);
	} else {
		/* charger is removed since full */
		if (chip->charger_reinserted) {
			/*
			 * charger reinserted, keep the reported_soc
			 * until it equals to last_soc.
			 */
			if (chip->reported_soc == chip->last_soc) {
				chip->reported_soc_in_use = false;
				chip->reported_soc_high_current = false;
				pr_debug("reported_soc equals to last_soc, stop reported_soc process\n");
			}
			chip->reported_soc_change_sec = 0;
		}
	}
	pr_debug("Reporting reported_soc=%d, last_soc=%d\n",
					chip->reported_soc, chip->last_soc);
	return chip->reported_soc;
}

#define SOC_CATCHUP_SEC_MAX		600
#define SOC_CATCHUP_SEC_PER_PERCENT	60
#define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT)
@@ -1648,6 +1702,9 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip)

	backup_ocv_soc(chip, chip->last_ocv_uv, chip->last_soc);

	if (chip->reported_soc_in_use)
		return prepare_reported_soc(chip);

	pr_debug("Reported SOC=%d\n", chip->last_soc);

	return chip->last_soc;
@@ -1894,6 +1951,45 @@ static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
	return 0;
}

static void calculate_reported_soc(struct qpnp_bms_chip *chip)
{
	union power_supply_propval ret = {0,};

	if (chip->reported_soc > chip->last_soc) {
		/*send DISCHARGING status if the reported_soc drops from 100 */
		if (chip->reported_soc == 100) {
			ret.intval = POWER_SUPPLY_STATUS_DISCHARGING;
			chip->batt_psy->set_property(chip->batt_psy,
				POWER_SUPPLY_PROP_STATUS, &ret);
			pr_debug("Report discharging status, reported_soc=%d, last_soc=%d\n",
					chip->reported_soc, chip->last_soc);
		}
		/*
		* reported_soc_delta is used to prevent
		* the big change in last_soc,
		* this is not used in high current mode
		*/
		if (chip->reported_soc_delta > 0)
			chip->reported_soc_delta--;

		if (chip->reported_soc_high_current)
			chip->reported_soc--;
		else
			chip->reported_soc = chip->last_soc
					+ chip->reported_soc_delta;

		pr_debug("New reported_soc=%d, last_soc is=%d\n",
					chip->reported_soc, chip->last_soc);
	} else {
		chip->reported_soc_in_use = false;
		chip->reported_soc_high_current = false;
		pr_debug("reported_soc equals last_soc,stop reported_soc process\n");
	}
	pr_debug("bms power_supply_changed\n");
	power_supply_changed(&chip->bms_psy);
}

#define UI_SOC_CATCHUP_TIME	(60)
static void monitor_soc_work(struct work_struct *work)
{
	struct qpnp_bms_chip *chip = container_of(work,
@@ -1969,6 +2065,20 @@ static void monitor_soc_work(struct work_struct *work)
		schedule_delayed_work(&chip->monitor_soc_work,
			msecs_to_jiffies(get_calculation_delay_ms(chip)));

	if (chip->reported_soc_in_use && chip->charger_removed_since_full
				&& !chip->charger_reinserted) {
		/* record the elapsed time after last reported_soc change */
		chip->reported_soc_change_sec += chip->delta_time_s;
		pr_debug("reported_soc_change_sec=%d\n",
					chip->reported_soc_change_sec);

		/* above the catch up time, calculate new reported_soc */
		if (chip->reported_soc_change_sec > UI_SOC_CATCHUP_TIME) {
			calculate_reported_soc(chip);
			chip->reported_soc_change_sec = 0;
		}
	}

	mutex_unlock(&chip->last_soc_mutex);

	bms_relax(&chip->vbms_soc_wake_source);
@@ -2251,6 +2361,42 @@ static void battery_status_check(struct qpnp_bms_chip *chip)
	}
}

#define HIGH_CURRENT_TH 2
static void reported_soc_check_status(struct qpnp_bms_chip *chip)
{
	u8 present;

	present = is_charger_present(chip);
	pr_debug("usb_present=%d\n", present);

	if (!present && !chip->charger_removed_since_full) {
		chip->charger_removed_since_full = true;
		pr_debug("reported_soc: charger removed since full\n");
		return;
	}
	if (chip->reported_soc_high_current) {
		pr_debug("reported_soc in high current mode, return\n");
		return;
	}
	if ((chip->reported_soc - chip->last_soc) >
			(100 - chip->dt.cfg_soc_resume_limit
						+ HIGH_CURRENT_TH)) {
		chip->reported_soc_high_current = true;
		chip->charger_removed_since_full = true;
		chip->charger_reinserted = false;
		pr_debug("reported_soc enters high current mode\n");
		return;
	}
	if (present && chip->charger_removed_since_full) {
		chip->charger_reinserted = true;
		pr_debug("reported_soc: charger reinserted\n");
	}
	if (!present && chip->charger_removed_since_full) {
		chip->charger_reinserted = false;
		pr_debug("reported_soc: charger removed again\n");
	}
}

static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy)
{
	struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
@@ -2259,6 +2405,9 @@ static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy)
	pr_debug("Triggered!\n");
	battery_status_check(chip);
	battery_insertion_check(chip);

	if (chip->reported_soc_in_use)
		reported_soc_check_status(chip);
}


@@ -3083,6 +3232,7 @@ static int show_bms_config(struct seq_file *m, void *data)
			"force_s3_on_suspend\t=\t%d\n"
			"report_charger_eoc\t=\t%d\n"
			"aging_compensation\t=\t%d\n"
			"use_reported_soc\t=\t%d\n"
			"s1_sample_interval_ms\t=\t%d\n"
			"s2_sample_interval_ms\t=\t%d\n"
			"s1_sample_count\t=\t%d\n"
@@ -3104,6 +3254,7 @@ static int show_bms_config(struct seq_file *m, void *data)
			chip->dt.cfg_force_s3_on_suspend,
			chip->dt.cfg_report_charger_eoc,
			chip->dt.cfg_battery_aging_comp,
			chip->dt.cfg_use_reported_soc,
			s1_sample_interval,
			s2_sample_interval,
			s1_sample_count,
@@ -3447,6 +3598,8 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip)
			"qcom,force-bms-active-on-charger");
	chip->dt.cfg_battery_aging_comp = of_property_read_bool(
			chip->spmi->dev.of_node, "qcom,batt-aging-comp");
	chip->dt.cfg_use_reported_soc = of_property_read_bool(
			chip->spmi->dev.of_node, "qcom,use-reported-soc");
	pr_debug("v_cutoff_uv=%d, max_v=%d\n", chip->dt.cfg_v_cutoff_uv,
					chip->dt.cfg_max_voltage_uv);
	pr_debug("r_conn=%d shutdown_soc_valid_limit=%d low_temp_threshold=%d ibat_avg_samples=%d\n",
@@ -3464,6 +3617,8 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip)
			chip->dt.cfg_disable_bms,
			chip->dt.cfg_force_bms_active_on_charger,
			chip->dt.cfg_battery_aging_comp);
	pr_debug("use-reported-soc is %d\n",
			chip->dt.cfg_use_reported_soc);

	return 0;
}