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

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

Merge "power: power_supply: add property for FCC stepper"

parents b464b6bb 68736f19
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -382,6 +382,7 @@ static struct device_attribute power_supply_attrs[] = {
	POWER_SUPPLY_ATTR(esr_nominal),
	POWER_SUPPLY_ATTR(soh),
	POWER_SUPPLY_ATTR(force_recharge),
	POWER_SUPPLY_ATTR(fcc_stepper_enable),
	/* Local extensions of type int64_t */
	POWER_SUPPLY_ATTR(charge_counter_ext),
	/* Properties of type `const char *' */
+190 −44
Original line number Diff line number Diff line
@@ -44,10 +44,12 @@
#define PL_INDIRECT_VOTER		"PL_INDIRECT_VOTER"
#define USBIN_I_VOTER			"USBIN_I_VOTER"
#define PL_FCC_LOW_VOTER		"PL_FCC_LOW_VOTER"
#define ICL_LIMIT_VOTER			"ICL_LIMIT_VOTER"

struct pl_data {
	int			pl_mode;
	int			pl_batfet_mode;
	int			pl_min_icl_ua;
	int			slave_pct;
	int			slave_fcc_ua;
	int			restricted_current;
@@ -71,10 +73,13 @@ struct pl_data {
	int			charge_type;
	int			total_settled_ua;
	int			pl_settled_ua;
	int			pl_fcc_max;
	u32			wa_flags;
	struct class		qcom_batt_class;
	struct wakeup_source	*pl_ws;
	struct notifier_block	nb;
	bool			pl_disable;
	int			taper_entry_fv;
};

struct pl_data *the_chip;
@@ -85,6 +90,7 @@ enum print_reason {

enum {
	AICL_RERUN_WA_BIT	= BIT(0),
	FORCE_INOV_DISABLE_BIT	= BIT(1),
};

static int debug_mask;
@@ -98,6 +104,8 @@ module_param_named(debug_mask, debug_mask, int, 0600);
			pr_debug(fmt, ##__VA_ARGS__);		\
	} while (0)

#define IS_USBIN(mode)	((mode == POWER_SUPPLY_PL_USBIN_USBIN) \
			|| (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
enum {
	VER = 0,
	SLAVE_PCT,
@@ -108,19 +116,19 @@ enum {
/*******
 * ICL *
 ********/
static void split_settled(struct pl_data *chip)
static int get_settled_split(struct pl_data *chip, int *main_icl_ua,
				int *slave_icl_ua, int *total_settled_icl_ua)
{
	int slave_icl_pct, total_current_ua;
	int slave_ua = 0, main_settled_ua = 0;
	union power_supply_propval pval = {0, };
	int rc, total_settled_ua = 0;

	if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN)
		&& (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT))
		return;
	if (!IS_USBIN(chip->pl_mode))
		return -EINVAL;

	if (!chip->main_psy)
		return;
		return -EINVAL;

	if (!get_effective_result_locked(chip->pl_disable_votable)) {
		/* read the aicl settled value */
@@ -128,11 +136,10 @@ static void split_settled(struct pl_data *chip)
			       POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval);
		if (rc < 0) {
			pr_err("Couldn't get aicl settled value rc=%d\n", rc);
			return;
			return rc;
		}
		main_settled_ua = pval.intval;
		/* slave gets 10 percent points less for ICL */
		slave_icl_pct = max(0, chip->slave_pct - 10);
		slave_icl_pct = max(0, chip->slave_pct);
		slave_ua = ((main_settled_ua + chip->pl_settled_ua)
						* slave_icl_pct) / 100;
		total_settled_ua = main_settled_ua + chip->pl_settled_ua;
@@ -144,18 +151,63 @@ static void split_settled(struct pl_data *chip)
			chip->usb_psy = power_supply_get_by_name("usb");
		if (!chip->usb_psy) {
			pr_err("Couldn't get usbpsy while splitting settled\n");
			return;
			return -ENOENT;
		}
		/* no client is voting, so get the total current from charger */
		rc = power_supply_get_property(chip->usb_psy,
			POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval);
		if (rc < 0) {
			pr_err("Couldn't get max current rc=%d\n", rc);
			return;
			return rc;
		}
		total_current_ua = pval.intval;
	}

	*main_icl_ua = total_current_ua - slave_ua;
	*slave_icl_ua = slave_ua;
	*total_settled_icl_ua = total_settled_ua;

	pl_dbg(chip, PR_PARALLEL,
		"Split total_current_ua=%d total_settled_ua=%d main_settled_ua=%d slave_ua=%d\n",
		total_current_ua, total_settled_ua, main_settled_ua, slave_ua);

	return 0;
}

static int validate_parallel_icl(struct pl_data *chip, bool *disable)
{
	int rc = 0;
	int main_ua = 0, slave_ua = 0, total_settled_ua = 0;

	if (!IS_USBIN(chip->pl_mode)
		|| get_effective_result_locked(chip->pl_disable_votable))
		return 0;

	rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua);
	if (rc < 0) {
		pr_err("Couldn't  get split current rc=%d\n", rc);
		return rc;
	}

	if (slave_ua < chip->pl_min_icl_ua)
		*disable = true;
	else
		*disable = false;

	return 0;
}

static void split_settled(struct pl_data *chip)
{
	union power_supply_propval pval = {0, };
	int rc, main_ua, slave_ua, total_settled_ua;

	rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua);
	if (rc < 0) {
		pr_err("Couldn't  get split current rc=%d\n", rc);
		return;
	}

	/*
	 * If there is an increase in slave share
	 * (Also handles parallel enable case)
@@ -165,7 +217,7 @@ static void split_settled(struct pl_data *chip)
	 *	Set slave ICL then main ICL.
	 */
	if (slave_ua > chip->pl_settled_ua) {
		pval.intval = total_current_ua - slave_ua;
		pval.intval = main_ua;
		/* Set ICL on main charger */
		rc = power_supply_set_property(chip->main_psy,
				POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
@@ -193,7 +245,7 @@ static void split_settled(struct pl_data *chip)
			return;
		}

		pval.intval = total_current_ua - slave_ua;
		pval.intval = main_ua;
		/* Set ICL on main charger */
		rc = power_supply_set_property(chip->main_psy,
				POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
@@ -207,9 +259,6 @@ static void split_settled(struct pl_data *chip)
	chip->total_settled_ua = total_settled_ua;
	chip->pl_settled_ua = slave_ua;

	pl_dbg(chip, PR_PARALLEL,
		"Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n",
		total_current_ua, main_settled_ua, slave_ua);
}

static ssize_t version_show(struct class *c, struct class_attribute *attr,
@@ -235,14 +284,21 @@ static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr,
static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr,
			const char *ubuf, size_t count)
{
	struct pl_data *chip = container_of(c, struct pl_data,
			qcom_batt_class);
	struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class);
	int rc;
	unsigned long val;
	bool disable = false;

	if (kstrtoul(ubuf, 10, &val))
		return -EINVAL;

	chip->slave_pct = val;

	rc = validate_parallel_icl(chip, &disable);
	if (rc < 0)
		return rc;

	vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0);
	rerun_election(chip->fcc_votable);
	rerun_election(chip->fv_votable);
	split_settled(chip);
@@ -374,6 +430,7 @@ static void get_fcc_split(struct pl_data *chip, int total_ua,
	effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
	slave_limited_ua = min(effective_total_ua, bcl_ua);
	*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
	*slave_ua = min(*slave_ua, chip->pl_fcc_max);

	/*
	 * In stacked BATFET configuration charger's current goes
@@ -399,6 +456,7 @@ static void pl_taper_work(struct work_struct *work)
	int eff_fcc_ua;
	int total_fcc_ua, master_fcc_ua, slave_fcc_ua = 0;

	chip->taper_entry_fv = get_effective_result(chip->fv_votable);
	chip->taper_work_running = true;
	while (true) {
		if (get_effective_result(chip->pl_disable_votable)) {
@@ -444,9 +502,27 @@ static void pl_taper_work(struct work_struct *work)
					eff_fcc_ua);
			vote(chip->fcc_votable, TAPER_STEPPER_VOTER,
					true, eff_fcc_ua);
		} else {
			/*
			 * Due to reduction of float voltage in JEITA condition
			 * taper charging can be initiated at a lower FV. On
			 * removal of JEITA condition, FV readjusts itself.
			 * However, once taper charging is initiated, it doesn't
			 * exits until parallel chaging is disabled due to which
			 * FCC doesn't scale back to its original value, leading
			 * to slow charging thereafter.
			 * Check if FV increases in comparison to FV at which
			 * taper charging was initiated, and if yes, exit taper
			 * charging.
			 */
			if (get_effective_result(chip->fv_votable) >
						chip->taper_entry_fv) {
				pl_dbg(chip, PR_PARALLEL, "Float voltage increased. Exiting taper\n");
				goto done;
			} else {
				pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
			}
		}
		/* wait for the charger state to deglitch after FCC change */
		msleep(PL_TAPER_WORK_DELAY_MS);
	}
@@ -473,11 +549,9 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
				&slave_fcc_ua);

		if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) {
			chip->slave_fcc_ua = slave_fcc_ua;
			vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER,
							false, 0);
		} else {
			chip->slave_fcc_ua = 0;
			vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER,
							true, 0);
		}
@@ -631,11 +705,9 @@ static int pl_disable_vote_callback(struct votable *votable,
{
	struct pl_data *chip = data;
	union power_supply_propval pval = {0, };
	int master_fcc_ua, total_fcc_ua, slave_fcc_ua;
	int rc;

	chip->total_settled_ua = 0;
	chip->pl_settled_ua = 0;
	int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0;
	int rc = 0;
	bool disable = false;

	if (!is_main_available(chip))
		return -ENODEV;
@@ -647,6 +719,16 @@ static int pl_disable_vote_callback(struct votable *votable,
		cancel_delayed_work_sync(&chip->pl_awake_work);
		vote(chip->pl_awake_votable, PL_VOTER, true, 0);

		rc = validate_parallel_icl(chip, &disable);
		if (rc < 0)
			return rc;

		if (disable) {
			pr_info("Parallel ICL is less than min ICL(%d), skipping parallel enable\n",
					chip->pl_min_icl_ua);
			return 0;
		}

		 /* enable parallel charging */
		rc = power_supply_get_property(chip->pl_psy,
				POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
@@ -729,8 +811,7 @@ static int pl_disable_vote_callback(struct votable *votable,
			pr_err("Couldn't change slave suspend state rc=%d\n",
				rc);

		if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
			|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
		if (IS_USBIN(chip->pl_mode))
			split_settled(chip);
		/*
		 * we could have been enabled while in taper mode,
@@ -757,8 +838,7 @@ static int pl_disable_vote_callback(struct votable *votable,
			(master_fcc_ua * 100) / total_fcc_ua,
			(slave_fcc_ua * 100) / total_fcc_ua);
	} else {
		if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
			|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
		if (IS_USBIN(chip->pl_mode))
			split_settled(chip);

		/* pl_psy may be NULL while in the disable branch */
@@ -781,11 +861,22 @@ static int pl_disable_vote_callback(struct votable *votable,
			return rc;
		}

		/* reset parallel FCC */
		chip->slave_fcc_ua = 0;
		rerun_election(chip->fv_votable);

		cancel_delayed_work_sync(&chip->pl_awake_work);
		schedule_delayed_work(&chip->pl_awake_work,
						msecs_to_jiffies(5000));

		chip->total_settled_ua = 0;
		chip->pl_settled_ua = 0;
	}

	/* notify parallel state change */
	if (chip->pl_psy && (chip->pl_disable != pl_disable)) {
		power_supply_changed(chip->pl_psy);
		chip->pl_disable = (bool)pl_disable;
	}

	pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n",
@@ -856,8 +947,8 @@ static bool is_parallel_available(struct pl_data *chip)
	chip->pl_mode = pval.intval;

	/* Disable autonomous votage increments for USBIN-USBIN */
	if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
		|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) {
	if (IS_USBIN(chip->pl_mode)
			&& (chip->wa_flags & FORCE_INOV_DISABLE_BIT)) {
		if (!chip->hvdcp_hw_inov_dis_votable)
			chip->hvdcp_hw_inov_dis_votable =
					find_votable("HVDCP_HW_INOV_DIS");
@@ -878,6 +969,17 @@ static bool is_parallel_available(struct pl_data *chip)
	}
	chip->pl_batfet_mode = pval.intval;

	pval.intval = 0;
	power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_MIN_ICL,
					&pval);
	chip->pl_min_icl_ua = pval.intval;

	chip->pl_fcc_max = INT_MAX;
	rc = power_supply_get_property(chip->pl_psy,
			POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval);
	if (!rc)
		chip->pl_fcc_max = pval.intval;

	vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);

	return true;
@@ -899,9 +1001,6 @@ static void handle_main_charge_type(struct pl_data *chip)
	if ((pval.intval != POWER_SUPPLY_CHARGE_TYPE_FAST)
		&& (pval.intval != POWER_SUPPLY_CHARGE_TYPE_TAPER)) {
		vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0);
		vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
		vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
				false, 0);
		chip->charge_type = pval.intval;
		return;
	}
@@ -921,6 +1020,16 @@ static void handle_main_charge_type(struct pl_data *chip)
	/* handle fast/taper charge entry */
	if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER
			|| pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST) {
		/*
		 * Undo parallel charging termination if entered taper in
		 * reduced float voltage condition due to jeita mitigation.
		 */
		if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST &&
			(chip->taper_entry_fv <
			get_effective_result(chip->fv_votable))) {
			vote(chip->pl_disable_votable, TAPER_END_VOTER,
				false, 0);
		}
		pl_dbg(chip, PR_PARALLEL, "chg_state enabling parallel\n");
		vote(chip->pl_disable_votable, CHG_STATE_VOTER, false, 0);
		chip->charge_type = pval.intval;
@@ -940,6 +1049,7 @@ static void handle_settled_icl_change(struct pl_data *chip)
	int main_settled_ua;
	int main_limited;
	int total_current_ua;
	bool disable = false;

	total_current_ua = get_effective_result_locked(chip->usb_icl_votable);

@@ -973,13 +1083,8 @@ static void handle_settled_icl_change(struct pl_data *chip)
	else
		vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0);

	rerun_election(chip->fcc_votable);

	if (get_effective_result(chip->pl_disable_votable))
		return;

	if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN
			|| chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) {
	if (IS_USBIN(chip->pl_mode)) {
		/*
		 * call aicl split only when USBIN_USBIN and enabled
		 * and if settled current has changed by more than 300mA
@@ -993,10 +1098,19 @@ static void handle_settled_icl_change(struct pl_data *chip)

		/* If ICL change is small skip splitting */
		if (abs(new_total_settled_ua - chip->total_settled_ua)
						> MIN_ICL_CHANGE_DELTA_UA)
						> MIN_ICL_CHANGE_DELTA_UA) {
			rc = validate_parallel_icl(chip, &disable);
			if (rc < 0)
				return;

			vote(chip->pl_disable_votable, ICL_LIMIT_VOTER,
						disable, 0);
			if (!get_effective_result_locked(
						chip->pl_disable_votable))
				split_settled(chip);
		}
	}
}

static void handle_parallel_in_taper(struct pl_data *chip)
{
@@ -1027,6 +1141,34 @@ static void handle_parallel_in_taper(struct pl_data *chip)
	}
}

static void handle_usb_change(struct pl_data *chip)
{
	int rc;
	union power_supply_propval pval = {0, };

	if (!chip->usb_psy)
		chip->usb_psy = power_supply_get_by_name("usb");
	if (!chip->usb_psy) {
		pr_err("Couldn't get usbpsy\n");
		return;
	}

	rc = power_supply_get_property(chip->usb_psy,
			POWER_SUPPLY_PROP_PRESENT, &pval);
	if (rc < 0) {
		pr_err("Couldn't get present from USB rc=%d\n", rc);
		return;
	}

	if (!pval.intval) {
		/* USB removed: remove all stale votes */
		vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
		vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
				false, 0);
		vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0);
	}
}

static void status_change_work(struct work_struct *work)
{
	struct pl_data *chip = container_of(work,
@@ -1051,6 +1193,7 @@ static void status_change_work(struct work_struct *work)

	is_parallel_available(chip);

	handle_usb_change(chip);
	handle_main_charge_type(chip);
	handle_settled_icl_change(chip);
	handle_parallel_in_taper(chip);
@@ -1098,7 +1241,9 @@ static void pl_config_init(struct pl_data *chip, int smb_version)
	switch (smb_version) {
	case PMI8998_SUBTYPE:
	case PM660_SUBTYPE:
		chip->wa_flags = AICL_RERUN_WA_BIT;
		chip->wa_flags = AICL_RERUN_WA_BIT | FORCE_INOV_DISABLE_BIT;
		break;
	case PMI632_SUBTYPE:
		break;
	default:
		break;
@@ -1199,6 +1344,7 @@ int qcom_batt_init(int smb_version)
		goto unreg_notifier;
	}

	chip->pl_disable = true;
	chip->qcom_batt_class.name = "qcom-battery",
	chip->qcom_batt_class.owner = THIS_MODULE,
	chip->qcom_batt_class.class_groups = batt_class_groups;
+1 −0
Original line number Diff line number Diff line
@@ -308,6 +308,7 @@ enum power_supply_property {
	POWER_SUPPLY_PROP_ESR_NOMINAL,
	POWER_SUPPLY_PROP_SOH,
	POWER_SUPPLY_PROP_FORCE_RECHARGE,
	POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
	/* Local extensions of type int64_t */
	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
	/* Properties of type `const char *' */