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

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

Merge "power: battery: Add support for FCC stepping"

parents f9a1c821 491b7aff
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -183,6 +183,12 @@ Charger specific properties:
  Value type: bool
  Definition: Boolean flag which when present enables sw compensation for jeita

- qcom,fcc-stepping-enable
  Usage:      optional
  Value type: bool
  Definition: Boolean flag which when present enables stepwise change in FCC.
	      The default stepping rate is 100mA/sec.

=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ static struct device_attribute power_supply_attrs[] = {
	POWER_SUPPLY_ATTR(pd_voltage_max),
	POWER_SUPPLY_ATTR(pd_voltage_min),
	POWER_SUPPLY_ATTR(sdp_current_max),
	POWER_SUPPLY_ATTR(fcc_stepper_enable),
	/* Local extensions of type int64_t */
	POWER_SUPPLY_ATTR(charge_counter_ext),
	/* Properties of type `const char *' */
+337 −50
Original line number Diff line number Diff line
@@ -40,12 +40,14 @@
#define ICL_CHANGE_VOTER		"ICL_CHANGE_VOTER"
#define PL_INDIRECT_VOTER		"PL_INDIRECT_VOTER"
#define USBIN_I_VOTER			"USBIN_I_VOTER"
#define FCC_STEPPER_VOTER		"FCC_STEPPER_VOTER"

struct pl_data {
	int			pl_mode;
	int			slave_pct;
	int			taper_pct;
	int			slave_fcc_ua;
	int			main_fcc_ua;
	int			restricted_current;
	bool			restricted_charging_enabled;
	struct votable		*fcc_votable;
@@ -59,6 +61,7 @@ struct pl_data {
	struct work_struct	pl_disable_forever_work;
	struct delayed_work	pl_taper_work;
	struct delayed_work	pl_awake_work;
	struct delayed_work	fcc_step_update_work;
	struct power_supply	*main_psy;
	struct power_supply	*pl_psy;
	struct power_supply	*batt_psy;
@@ -66,6 +69,13 @@ struct pl_data {
	int			charge_type;
	int			total_settled_ua;
	int			pl_settled_ua;
	int			fcc_step_update;
	int			main_step_fcc_dir;
	int			main_step_fcc_count;
	int			main_step_fcc_residual;
	int			parallel_step_fcc_dir;
	int			parallel_step_fcc_count;
	int			parallel_step_fcc_residual;
	struct class		qcom_batt_class;
	struct wakeup_source	*pl_ws;
	struct notifier_block	nb;
@@ -380,6 +390,10 @@ done:
 *  FCC  *
**********/
#define EFFICIENCY_PCT	80
#define FCC_STEP_SIZE_UA 100000
#define FCC_STEP_UPDATE_DELAY_MS 1000
#define STEP_UP 1
#define STEP_DOWN -1
static void get_fcc_split(struct pl_data *chip, int total_ua,
			int *master_ua, int *slave_ua)
{
@@ -432,6 +446,43 @@ static void get_fcc_split(struct pl_data *chip, int total_ua,
	*slave_ua = (*slave_ua * chip->taper_pct) / 100;
}

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

	/* Read current FCC of main charger */
	rc = power_supply_get_property(chip->main_psy,
		POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
	if (rc < 0) {
		pr_err("Couldn't get main charger current fcc, rc=%d\n", rc);
		return;
	}
	chip->main_fcc_ua = pval.intval;

	chip->main_step_fcc_dir = (main_fcc_ua > pval.intval) ?
				STEP_UP : STEP_DOWN;
	chip->main_step_fcc_count = abs((main_fcc_ua - pval.intval) /
				FCC_STEP_SIZE_UA);
	chip->main_step_fcc_residual = (main_fcc_ua - pval.intval) %
				FCC_STEP_SIZE_UA;

	chip->parallel_step_fcc_dir = (parallel_fcc_ua > chip->slave_fcc_ua) ?
				STEP_UP : STEP_DOWN;
	chip->parallel_step_fcc_count = abs((parallel_fcc_ua -
				chip->slave_fcc_ua) / FCC_STEP_SIZE_UA);
	chip->parallel_step_fcc_residual = (parallel_fcc_ua -
				chip->slave_fcc_ua) % FCC_STEP_SIZE_UA;

	pr_debug("Main FCC Stepper parameters: main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d\n",
		chip->main_step_fcc_dir, chip->main_step_fcc_count,
		chip->main_step_fcc_residual);
	pr_debug("Parallel FCC Stepper parameters: parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n",
		chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count,
		chip->parallel_step_fcc_residual);
}

static int pl_fcc_vote_callback(struct votable *votable, void *data,
			int total_fcc_ua, const char *client)
{
@@ -445,21 +496,57 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
	if (!chip->main_psy)
		return 0;

	if (!chip->batt_psy) {
		chip->batt_psy = power_supply_get_by_name("battery");
		if (!chip->batt_psy)
			return 0;

		rc = power_supply_get_property(chip->batt_psy,
				POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, &pval);
		if (rc < 0) {
			pr_err("Couldn't read FCC step update status, rc=%d\n",
				rc);
			return rc;
		}
		chip->fcc_step_update = pval.intval;
		pr_debug("FCC Stepper %s\n",
				pval.intval ? "enabled" : "disabled");
	}

	if (chip->fcc_step_update)
		cancel_delayed_work_sync(&chip->fcc_step_update_work);


	if (chip->pl_mode == POWER_SUPPLY_PL_NONE
	    || get_effective_result_locked(chip->pl_disable_votable)) {
		if (chip->fcc_step_update) {
			vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
					true, 0);
			get_fcc_step_update_params(chip, total_fcc_ua, 0);
			schedule_delayed_work(&chip->fcc_step_update_work, 0);

			return 0;
		}
		pval.intval = total_fcc_ua;
		rc = power_supply_set_property(chip->main_psy,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
		if (rc < 0)
			pr_err("Couldn't set main fcc, rc=%d\n", rc);

		return rc;
	}

	if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
		get_fcc_split(chip, total_fcc_ua,
			&master_fcc_ua, &slave_fcc_ua);

		if (chip->fcc_step_update) {
			vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
					true, 0);
			get_fcc_step_update_params(chip, master_fcc_ua,
					slave_fcc_ua);
			schedule_delayed_work(&chip->fcc_step_update_work, 0);
		} else {
			/*
			 * If there is an increase in slave share
			 * (Also handles parallel enable case)
@@ -474,7 +561,8 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
				if (rc < 0) {
				pr_err("Could not set main fcc, rc=%d\n", rc);
					pr_err("Could not set main fcc, rc=%d\n",
						rc);
					return rc;
				}

@@ -507,11 +595,13 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
				if (rc < 0) {
				pr_err("Could not set main fcc, rc=%d\n", rc);
					pr_err("Could not set main fcc, rc=%d\n",
						rc);
					return rc;
				}
			}
		}
	}

	pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
		   master_fcc_ua, slave_fcc_ua,
@@ -521,6 +611,192 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
	return 0;
}

static void fcc_step_update_work(struct work_struct *work)
{
	struct pl_data *chip = container_of(work,
			struct pl_data, fcc_step_update_work.work);
	union power_supply_propval pval = {0, };
	int reschedule_ms = 0, rc = 0;
	int main_fcc = chip->main_fcc_ua;
	int parallel_fcc = chip->slave_fcc_ua;

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

	/* Check whether USB is present or not */
	rc = power_supply_get_property(chip->usb_psy,
				POWER_SUPPLY_PROP_PRESENT, &pval);
	if (rc < 0) {
		pr_err("Couldn't get USB Present status, rc=%d\n", rc);
		return;
	}

	/*
	 * If USB is not present, then disable parallel and
	 * Main FCC to the effective value of FCC votable and exit.
	 */
	if (!pval.intval) {
		/* Disable parallel */
		parallel_fcc = 0;
		pval.intval = 1;
		rc = power_supply_set_property(chip->pl_psy,
			POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
		if (rc < 0)
			pr_err("Couldn't change slave suspend state rc=%d\n",
				rc);

		main_fcc = get_effective_result_locked(chip->fcc_votable);
		pval.intval = main_fcc;
		rc = power_supply_set_property(chip->main_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
		if (rc < 0) {
			pr_err("Couldn't set main charger fcc, rc=%d\n", rc);
			return;
		}

		goto stepper_exit;
	}

	if (chip->main_step_fcc_count) {
		main_fcc += (FCC_STEP_SIZE_UA * chip->main_step_fcc_dir);
		chip->main_step_fcc_count--;
		reschedule_ms = FCC_STEP_UPDATE_DELAY_MS;
	} else if (chip->main_step_fcc_residual) {
		main_fcc += chip->main_step_fcc_residual;
		chip->main_step_fcc_residual = 0;
	}

	if (chip->parallel_step_fcc_count) {
		parallel_fcc += (FCC_STEP_SIZE_UA *
			chip->parallel_step_fcc_dir);
		chip->parallel_step_fcc_count--;
		reschedule_ms = FCC_STEP_UPDATE_DELAY_MS;
	} else if (chip->parallel_step_fcc_residual) {
		parallel_fcc += chip->parallel_step_fcc_residual;
		chip->parallel_step_fcc_residual = 0;
	}

	if (chip->pl_mode == POWER_SUPPLY_PL_NONE ||
		get_effective_result_locked(chip->pl_disable_votable)) {
		/* Set Parallel FCC */
		pval.intval = parallel_fcc;
		rc = power_supply_set_property(chip->pl_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
		if (rc < 0) {
			pr_err("Couldn't set parallel charger fcc, rc=%d\n",
				rc);
			return;
		}

		/* Set main FCC */
		pval.intval = main_fcc;
		rc = power_supply_set_property(chip->main_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
		if (rc < 0) {
			pr_err("Couldn't set main charger fcc, rc=%d\n", rc);
			return;
		}

		if (parallel_fcc < MINIMUM_PARALLEL_FCC_UA) {
			pval.intval = 1;
			rc = power_supply_set_property(chip->pl_psy,
				POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
			if (rc < 0) {
				pr_err("Couldn't change slave suspend state rc=%d\n",
					rc);
				return;
			}
		}
	} else {
		if (parallel_fcc < chip->slave_fcc_ua) {
			pval.intval = parallel_fcc;
			rc = power_supply_set_property(chip->pl_psy,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
			if (rc < 0) {
				pr_err("Couldn't set parallel charger fcc, rc=%d\n",
					rc);
				return;
			}

			pval.intval = main_fcc;
			rc = power_supply_set_property(chip->main_psy,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
			if (rc < 0) {
				pr_err("Couldn't set main charger fcc, rc=%d\n",
					rc);
				return;
			}
		} else {
			pval.intval = main_fcc;
			rc = power_supply_set_property(chip->main_psy,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
			if (rc < 0) {
				pr_err("Couldn't set main charger fcc, rc=%d\n",
					rc);
				return;
			}

			pval.intval = parallel_fcc;
			rc = power_supply_set_property(chip->pl_psy,
				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
				&pval);
			if (rc < 0) {
				pr_err("Couldn't set parallel charger fcc, rc=%d\n",
					rc);
				return;
			}
		}

		rc = power_supply_get_property(chip->pl_psy,
				POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
		if (rc < 0) {
			pr_err("Couldn't get slave suspend status, rc=%d\n",
					rc);
			return;
		}

		/*
		 * Enable parallel charger only if it was disabled earlier and
		 * configured slave fcc is greater than or equal to 100mA.
		 */
		if (pval.intval == 1 && parallel_fcc >= 100000) {
			pval.intval = 0;
			rc = power_supply_set_property(chip->pl_psy,
				POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
			if (rc < 0) {
				pr_err("Couldn't change slave suspend state rc=%d\n",
						rc);
				return;
			}

			if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) ||
				(chip->pl_mode ==
				POWER_SUPPLY_PL_USBIN_USBIN_EXT))
				split_settled(chip);
		}
	}

stepper_exit:
	chip->main_fcc_ua = main_fcc;
	chip->slave_fcc_ua = parallel_fcc;

	if (reschedule_ms) {
		schedule_delayed_work(&chip->fcc_step_update_work,
				msecs_to_jiffies(reschedule_ms));
		pr_debug("Rescheduling FCC_STEPPER work\n");
	} else {
		vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0);
	}
}

#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
static int pl_fv_vote_callback(struct votable *votable, void *data,
			int fv_uv, const char *client)
@@ -660,6 +936,9 @@ static int pl_disable_vote_callback(struct votable *votable,
	chip->total_settled_ua = 0;
	chip->pl_settled_ua = 0;

	/* Cancel FCC step change work */
	cancel_delayed_work_sync(&chip->fcc_step_update_work);

	if (!pl_disable) { /* enable */
		/* keep system awake to talk to slave charger through i2c */
		cancel_delayed_work_sync(&chip->pl_awake_work);
@@ -685,6 +964,7 @@ static int pl_disable_vote_callback(struct votable *votable,
		 * PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy
		 * is seen.
		 */
		if (!chip->fcc_step_update) {
			pval.intval = 0;
			rc = power_supply_set_property(chip->pl_psy,
				POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
@@ -692,9 +972,11 @@ 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 ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) ||
				(chip->pl_mode ==
				POWER_SUPPLY_PL_USBIN_USBIN_EXT))
				split_settled(chip);
		}
		/*
		 * we could have been enabled while in taper mode,
		 *  start the taper work if so
@@ -715,6 +997,7 @@ static int pl_disable_vote_callback(struct votable *votable,
			|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
			split_settled(chip);

		if (!chip->fcc_step_update) {
			/* pl_psy may be NULL while in the disable branch */
			if (chip->pl_psy) {
				pval.intval = 1;
@@ -724,6 +1007,8 @@ static int pl_disable_vote_callback(struct votable *votable,
					pr_err("Couldn't change slave suspend state rc=%d\n",
						rc);
			}
		}

		rerun_election(chip->fcc_votable);
		rerun_election(chip->fv_votable);

@@ -1118,6 +1403,7 @@ int qcom_batt_init(void)
	INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
	INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
	INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work);
	INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work);

	rc = pl_register_notifier(chip);
	if (rc < 0) {
@@ -1172,6 +1458,7 @@ void qcom_batt_deinit(void)
	cancel_delayed_work_sync(&chip->pl_taper_work);
	cancel_work_sync(&chip->pl_disable_forever_work);
	cancel_delayed_work_sync(&chip->pl_awake_work);
	cancel_delayed_work_sync(&chip->fcc_step_update_work);

	power_supply_unreg_notifier(&chip->nb);
	destroy_votable(chip->pl_enable_votable_indirect);
+7 −0
Original line number Diff line number Diff line
@@ -325,6 +325,9 @@ static int smb2_parse_dt(struct smb2 *chip)
	if (rc < 0)
		chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;

	chg->fcc_stepper_mode = of_property_read_bool(node,
					"qcom,fcc-stepping-enable");

	return 0;
}

@@ -941,6 +944,7 @@ static enum power_supply_property smb2_batt_props[] = {
	POWER_SUPPLY_PROP_RERUN_AICL,
	POWER_SUPPLY_PROP_DP_DM,
	POWER_SUPPLY_PROP_CHARGE_COUNTER,
	POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
};

static int smb2_batt_get_prop(struct power_supply *psy,
@@ -1049,6 +1053,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
		rc = smblib_get_prop_batt_charge_counter(chg, val);
		break;
	case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE:
		val->intval = chg->fcc_stepper_mode;
		break;
	default:
		pr_err("batt power supply prop %d not supported\n", psp);
		return -EINVAL;
+7 −1
Original line number Diff line number Diff line
@@ -3360,7 +3360,8 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
		rc = smblib_request_dpdm(chg, true);
		if (rc < 0)
			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);

		if (chg->fcc_stepper_mode)
			vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0);
		/* Schedule work to enable parallel charger */
		vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
		schedule_delayed_work(&chg->pl_enable_work,
@@ -3379,6 +3380,11 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
			}
		}

		/* Force 1500mA FCC on removal */
		if (chg->fcc_stepper_mode)
			vote(chg->fcc_votable, FCC_STEPPER_VOTER,
						true, 1500000);

		rc = smblib_request_dpdm(chg, false);
		if (rc < 0)
			smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Loading