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

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

Merge "power: qpnp-fg-gen4: Fix parallel current summing configuration"

parents f3912da8 74b58593
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -419,6 +419,13 @@ First Level Node - FG Gen4 device
		    multiple battery profiles to be specified for a battery for
		    proper functionality.

- qcom,soc-hi-res
	Usage:      optional
	Value type: <empty>
	Definition: A boolean property that when specified shows high
		    resolution of monotonic SOC under CAPACITY_RAW property
		    during charging in the scale of 0-10000.

==========================================================
Second Level Nodes - Peripherals managed by FG Gen4 driver
==========================================================
+94 −24
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#define pr_fmt(fmt)	"FG: %s: " fmt, __func__

#include <linux/alarmtimer.h>
#include <linux/irq.h>
#include <linux/ktime.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -188,6 +189,7 @@ struct fg_dt_props {
	bool	five_pin_battery;
	bool	multi_profile_load;
	bool	esr_calib_dischg;
	bool	soc_hi_res;
	int	cutoff_volt_mv;
	int	empty_volt_mv;
	int	cutoff_curr_ma;
@@ -236,7 +238,7 @@ struct fg_gen4_chip {
	struct work_struct	esr_calib_work;
	struct alarm		esr_fast_cal_timer;
	struct delayed_work	pl_enable_work;
	struct delayed_work	pl_current_en_work;
	struct work_struct	pl_current_en_work;
	struct completion	mem_attn;
	char			batt_profile[PROFILE_LEN];
	enum slope_limit_status	slope_limit_sts;
@@ -851,6 +853,35 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val)
	return 0;
}

static int fg_gen4_get_prop_capacity_raw(struct fg_gen4_chip *chip, int *val)
{
	struct fg_dev *fg = &chip->fg;
	int rc;

	if (!chip->dt.soc_hi_res) {
		rc = fg_get_msoc_raw(fg, val);
		return rc;
	}

	if (!is_input_present(fg)) {
		rc = fg_gen4_get_prop_capacity(fg, val);
		if (!rc)
			*val = *val * 100;
		return rc;
	}

	rc = fg_get_sram_prop(&chip->fg, FG_SRAM_MONOTONIC_SOC, val);
	if (rc < 0) {
		pr_err("Error in getting MONOTONIC_SOC, rc=%d\n", rc);
		return rc;
	}

	/* Show it in centi-percentage */
	*val = (*val * 10000) / 0xFFFF;

	return 0;
}

static inline void get_esr_meas_current(int curr_ma, u8 *val)
{
	switch (curr_ma) {
@@ -874,6 +905,43 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val)
	*val <<= ESR_PULL_DOWN_IVAL_SHIFT;
}

static int fg_gen4_get_power(struct fg_gen4_chip *chip, int *val, bool average)
{
	struct fg_dev *fg = &chip->fg;
	int rc, v_min, v_pred, esr_uohms, rslow_uohms;
	s64 power;

	rc = fg_get_sram_prop(fg, FG_SRAM_VOLTAGE_PRED, &v_pred);
	if (rc < 0)
		return rc;

	v_min = chip->dt.cutoff_volt_mv * 1000;
	power = (s64)v_min * (v_pred - v_min);

	rc = fg_get_sram_prop(fg, FG_SRAM_ESR, &esr_uohms);
	if (rc < 0) {
		pr_err("failed to get ESR, rc=%d\n", rc);
		return rc;
	}

	rc = fg_get_sram_prop(fg, FG_SRAM_RSLOW, &rslow_uohms);
	if (rc < 0) {
		pr_err("failed to get Rslow, rc=%d\n", rc);
		return rc;
	}

	if (average)
		power = div_s64(power, esr_uohms + rslow_uohms);
	else
		power = div_s64(power, esr_uohms);

	pr_debug("V_min: %d V_pred: %d ESR: %d Rslow: %d power: %lld\n", v_min,
		v_pred, esr_uohms, rslow_uohms, power);

	*val = power;
	return 0;
}

/* ALG callback functions below */

static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val)
@@ -3221,31 +3289,16 @@ static void pl_current_en_work(struct work_struct *work)
{
	struct fg_gen4_chip *chip = container_of(work,
				struct fg_gen4_chip,
				pl_current_en_work.work);
				pl_current_en_work);
	struct fg_dev *fg = &chip->fg;
	bool input_present = is_input_present(fg), en;

	en = fg->charge_done ? false : input_present;

	/*
	 * If mem_attn_irq is disabled and parallel summing current
	 * configuration needs to be modified, then enable mem_attn_irq and
	 * wait for 1 second before doing it.
	 */
	if (get_effective_result(chip->parallel_current_en_votable) != en &&
		!get_effective_result(chip->mem_attn_irq_en_votable)) {
		vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER,
			true, 0);
		schedule_delayed_work(&chip->pl_current_en_work,
			msecs_to_jiffies(1000));
		return;
	}

	if (!get_effective_result(chip->mem_attn_irq_en_votable))
	if (get_effective_result(chip->parallel_current_en_votable) == en)
		return;

	vote(chip->parallel_current_en_votable, FG_PARALLEL_EN_VOTER, en, 0);
	vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0);
}

static void pl_enable_work(struct work_struct *work)
@@ -3339,9 +3392,10 @@ static void status_change_work(struct work_struct *work)
	if (rc < 0)
		pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);

	if (is_parallel_charger_available(fg) &&
		!delayed_work_pending(&chip->pl_current_en_work))
		schedule_delayed_work(&chip->pl_current_en_work, 0);
	if (is_parallel_charger_available(fg)) {
		cancel_work_sync(&chip->pl_current_en_work);
		schedule_work(&chip->pl_current_en_work);
	}

	ttf_update(chip->ttf, input_present);
	fg->prev_charge_status = fg->charge_status;
@@ -3556,7 +3610,7 @@ static int fg_psy_get_property(struct power_supply *psy,
		rc = fg_gen4_get_prop_capacity(fg, &pval->intval);
		break;
	case POWER_SUPPLY_PROP_CAPACITY_RAW:
		rc = fg_get_msoc_raw(fg, &pval->intval);
		rc = fg_gen4_get_prop_capacity_raw(chip, &pval->intval);
		break;
	case POWER_SUPPLY_PROP_CC_SOC:
		rc = fg_get_sram_prop(&chip->fg, FG_SRAM_CC_SOC, &val);
@@ -3668,6 +3722,12 @@ static int fg_psy_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_BATT_AGE_LEVEL:
		pval->intval = chip->batt_age_level;
		break;
	case POWER_SUPPLY_PROP_POWER_NOW:
		rc = fg_gen4_get_power(chip, &pval->intval, false);
		break;
	case POWER_SUPPLY_PROP_POWER_AVG:
		rc = fg_gen4_get_power(chip, &pval->intval, true);
		break;
	default:
		pr_err("unsupported property %d\n", psp);
		rc = -EINVAL;
@@ -3815,6 +3875,8 @@ static enum power_supply_property fg_psy_props[] = {
	POWER_SUPPLY_PROP_CC_STEP,
	POWER_SUPPLY_PROP_CC_STEP_SEL,
	POWER_SUPPLY_PROP_BATT_AGE_LEVEL,
	POWER_SUPPLY_PROP_POWER_NOW,
	POWER_SUPPLY_PROP_POWER_AVG,
};

static const struct power_supply_desc fg_psy_desc = {
@@ -3923,6 +3985,8 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data,
	int rc;
	u8 val, mask;

	vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, true, 0);

	/* Wait for MEM_ATTN interrupt */
	rc = fg_wait_for_mem_attn(chip);
	if (rc < 0)
@@ -3935,6 +3999,7 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data,
		pr_err("Error in writing to 0x%04x, rc=%d\n",
			BATT_INFO_FG_CNV_CHAR_CFG(fg), rc);

	vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0);
	fg_dbg(fg, FG_STATUS, "Parallel current summing: %d\n", enable);

	return rc;
@@ -4956,6 +5021,7 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip)
					"qcom,five-pin-battery");
	chip->dt.multi_profile_load = of_property_read_bool(node,
					"qcom,multi-profile-load");
	chip->dt.soc_hi_res = of_property_read_bool(node, "qcom,soc-hi-res");
	return 0;
}

@@ -4968,7 +5034,7 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip)
	cancel_work_sync(&fg->status_change_work);
	cancel_delayed_work_sync(&fg->profile_load_work);
	cancel_delayed_work_sync(&fg->sram_dump_work);
	cancel_delayed_work_sync(&chip->pl_current_en_work);
	cancel_work_sync(&chip->pl_current_en_work);

	power_supply_unreg_notifier(&fg->nb);
	debugfs_remove_recursive(fg->dfs_root);
@@ -5031,7 +5097,7 @@ static int fg_gen4_probe(struct platform_device *pdev)
	INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work);
	INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work);
	INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work);
	INIT_DELAYED_WORK(&chip->pl_current_en_work, pl_current_en_work);
	INIT_WORK(&chip->pl_current_en_work, pl_current_en_work);

	fg->awake_votable = create_votable("FG_WS", VOTE_SET_ANY,
					fg_awake_cb, fg);
@@ -5145,6 +5211,10 @@ static int fg_gen4_probe(struct platform_device *pdev)
		goto exit;
	}

	if (fg->irqs[MEM_ATTN_IRQ].irq)
		irq_set_status_flags(fg->irqs[MEM_ATTN_IRQ].irq,
					IRQ_DISABLE_UNLAZY);

	/* Keep SOC_UPDATE irq disabled until we require it */
	if (fg->irqs[SOC_UPDATE_IRQ].irq)
		disable_irq_nosync(fg->irqs[SOC_UPDATE_IRQ].irq);