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

Commit 1fb043f1 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 c5a15452 238086f6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -199,6 +199,12 @@ Charger specific properties:
  Definition: Boolean flag which when present disables STAT pin default software
		override configuration.

- 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
=============================================
+6 −0
Original line number Diff line number Diff line
@@ -247,6 +247,12 @@ Charger specific properties:
	Definition: Boolean flag which when present enables mositure protection
		    feature.

- 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 - SMB5 Charger Peripherals
=============================================
+383 −86
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#define USBIN_I_VOTER			"USBIN_I_VOTER"
#define PL_FCC_LOW_VOTER		"PL_FCC_LOW_VOTER"
#define ICL_LIMIT_VOTER			"ICL_LIMIT_VOTER"
#define FCC_STEPPER_VOTER		"FCC_STEPPER_VOTER"

struct pl_data {
	int			pl_mode;
@@ -52,6 +53,7 @@ struct pl_data {
	int			pl_min_icl_ua;
	int			slave_pct;
	int			slave_fcc_ua;
	int			main_fcc_ua;
	int			restricted_current;
	bool			restricted_charging_enabled;
	struct votable		*fcc_votable;
@@ -65,15 +67,25 @@ struct pl_data {
	struct work_struct	pl_disable_forever_work;
	struct work_struct	pl_taper_work;
	struct delayed_work	pl_awake_work;
	struct delayed_work	fcc_stepper_work;
	bool			taper_work_running;
	struct power_supply	*main_psy;
	struct power_supply	*pl_psy;
	struct power_supply	*batt_psy;
	struct power_supply	*usb_psy;
	struct power_supply	*dc_psy;
	int			charge_type;
	int			total_settled_ua;
	int			pl_settled_ua;
	int			pl_fcc_max;
	int			fcc_stepper_enable;
	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;
	int			step_fcc;
	u32			wa_flags;
	struct class		qcom_batt_class;
	struct wakeup_source	*pl_ws;
@@ -258,7 +270,6 @@ static void split_settled(struct pl_data *chip)

	chip->total_settled_ua = total_settled_ua;
	chip->pl_settled_ua = slave_ua;

}

static ssize_t version_show(struct class *c, struct class_attribute *attr,
@@ -388,6 +399,10 @@ static struct class_attribute pl_attributes[] = {
 *  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)
{
@@ -440,6 +455,47 @@ static void get_fcc_split(struct pl_data *chip, int total_ua,
		*master_ua = max(0, total_ua - *slave_ua);
}

static void get_fcc_stepper_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;

	if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual
		|| chip->main_step_fcc_count || chip->main_step_fcc_residual)
		chip->step_fcc = 1;

	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);
}

#define MINIMUM_PARALLEL_FCC_UA		500000
#define PL_TAPER_WORK_DELAY_MS		500
#define TAPER_RESIDUAL_PCT		90
@@ -559,6 +615,195 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
	return 0;
}

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

	/* 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);

	charger_present = pval.intval;

	/*Check whether DC charger is present or not */
	if (!chip->dc_psy)
		chip->dc_psy = power_supply_get_by_name("dc");
	if (chip->dc_psy) {
		rc = power_supply_get_property(chip->dc_psy,
				POWER_SUPPLY_PROP_PRESENT, &pval);
		if (rc < 0)
			pr_err("Couldn't get DC Present status, rc=%d\n", rc);

		charger_present |= pval.intval;
	}

	/*
	 * If USB is not present, then set parallel FCC to min value and
	 * main FCC to the effective value of FCC votable and exit.
	 */
	if (!charger_present) {
		/* Disable parallel */
		parallel_fcc = 0;

		if (chip->pl_psy) {
			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);
				goto out;
			}

			chip->pl_disable = true;
			power_supply_changed(chip->pl_psy);
		}

		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);
			goto out;
		}

		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 (parallel_fcc < chip->slave_fcc_ua) {
		/* Set parallel FCC */
		if (chip->pl_psy && !chip->pl_disable) {
			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);
					goto out;
				}

				if (IS_USBIN(chip->pl_mode))
					split_settled(chip);

				parallel_fcc = 0;
				chip->parallel_step_fcc_count = 0;
				chip->parallel_step_fcc_residual = 0;
				chip->total_settled_ua = 0;
				chip->pl_settled_ua = 0;
				chip->pl_disable = true;
				power_supply_changed(chip->pl_psy);
			} else {
				/* 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);
					goto out;
				}
			}
		}

		/* 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);
			goto out;
		}
	} else {
		/* 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);
			goto out;
		}

		/* Set parallel FCC */
		if (chip->pl_psy) {
			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);
				goto out;
			}

			/*
			 * Enable parallel charger only if it was disabled
			 * earlier and configured slave fcc is greater than or
			 * equal to minimum parallel FCC value.
			 */
			if (chip->pl_disable && parallel_fcc
					>= MINIMUM_PARALLEL_FCC_UA) {
				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);
					goto out;
				}

				if (IS_USBIN(chip->pl_mode))
					split_settled(chip);

				chip->pl_disable = false;
				power_supply_changed(chip->pl_psy);
			}
		}
	}

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

	if (reschedule_ms) {
		schedule_delayed_work(&chip->fcc_stepper_work,
				msecs_to_jiffies(reschedule_ms));
		pr_debug("Rescheduling FCC_STEPPER work\n");
		return;
	}
out:
	chip->step_fcc = 0;
	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)
@@ -697,6 +942,17 @@ static bool is_main_available(struct pl_data *chip)
	return !!chip->main_psy;
}

static bool is_batt_available(struct pl_data *chip)
{
	if (!chip->batt_psy)
		chip->batt_psy = power_supply_get_by_name("battery");

	if (!chip->batt_psy)
		return false;

	return true;
}

static int pl_disable_vote_callback(struct votable *votable,
		void *data, int pl_disable, const char *client)
{
@@ -709,6 +965,30 @@ static int pl_disable_vote_callback(struct votable *votable,
	if (!is_main_available(chip))
		return -ENODEV;

	if (!is_batt_available(chip))
		return -ENODEV;

	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 -ENODEV;
	}

	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_stepper_enable = pval.intval;
	pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled");

	if (chip->fcc_stepper_enable) {
		cancel_delayed_work_sync(&chip->fcc_stepper_work);
		vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0);
	}

	total_fcc_ua = get_effective_result_locked(chip->fcc_votable);

	if (chip->pl_mode != POWER_SUPPLY_PL_NONE && !pl_disable) {
@@ -744,6 +1024,16 @@ static int pl_disable_vote_callback(struct votable *votable,
		get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
				&slave_fcc_ua);

		if (chip->fcc_stepper_enable) {
			get_fcc_stepper_params(chip, master_fcc_ua,
					slave_fcc_ua);
			if (chip->step_fcc) {
				vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
					true, 0);
				schedule_delayed_work(&chip->fcc_stepper_work,
					0);
				}
		} else {
			/*
			 * If there is an increase in slave share
			 * (Also handles parallel enable case)
@@ -758,7 +1048,8 @@ static int pl_disable_vote_callback(struct votable *votable,
				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;
				}

@@ -791,7 +1082,8 @@ static int pl_disable_vote_callback(struct votable *votable,
				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;
				}
			}
@@ -810,6 +1102,8 @@ static int pl_disable_vote_callback(struct votable *votable,

			if (IS_USBIN(chip->pl_mode))
				split_settled(chip);
		}

		/*
		 * we could have been enabled while in taper mode,
		 *  start the taper work if so
@@ -835,6 +1129,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->fcc_stepper_enable) {
			if (IS_USBIN(chip->pl_mode))
				split_settled(chip);

@@ -860,18 +1155,28 @@ static int pl_disable_vote_callback(struct votable *votable,

			/* reset parallel FCC */
			chip->slave_fcc_ua = 0;
			chip->total_settled_ua = 0;
			chip->pl_settled_ua = 0;
		} else {
			get_fcc_stepper_params(chip, total_fcc_ua, 0);
			if (chip->step_fcc) {
				vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
					true, 0);
				schedule_delayed_work(&chip->fcc_stepper_work,
					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)) {
	if (chip->pl_psy && (chip->pl_disable != pl_disable)
				&& !chip->fcc_stepper_enable) {
		power_supply_changed(chip->pl_psy);
		chip->pl_disable = (bool)pl_disable;
	}
@@ -906,17 +1211,6 @@ static int pl_awake_vote_callback(struct votable *votable,
	return 0;
}

static bool is_batt_available(struct pl_data *chip)
{
	if (!chip->batt_psy)
		chip->batt_psy = power_supply_get_by_name("battery");

	if (!chip->batt_psy)
		return false;

	return true;
}

static bool is_parallel_available(struct pl_data *chip)
{
	union power_supply_propval pval = {0, };
@@ -1080,6 +1374,7 @@ 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 (IS_USBIN(chip->pl_mode)) {
		/*
@@ -1328,6 +1623,7 @@ int qcom_batt_init(int smb_version)
	INIT_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_stepper_work, fcc_stepper_work);

	rc = pl_register_notifier(chip);
	if (rc < 0) {
@@ -1383,6 +1679,7 @@ void qcom_batt_deinit(void)
	cancel_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_stepper_work);

	power_supply_unreg_notifier(&chip->nb);
	destroy_votable(chip->pl_enable_votable_indirect);
+7 −0
Original line number Diff line number Diff line
@@ -334,6 +334,9 @@ static int smb2_parse_dt(struct smb2 *chip)
	chg->disable_stat_sw_override = of_property_read_bool(node,
					"qcom,disable-stat-sw-override");

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

	return 0;
}

@@ -1001,6 +1004,7 @@ static enum power_supply_property smb2_batt_props[] = {
	POWER_SUPPLY_PROP_CHARGE_COUNTER,
	POWER_SUPPLY_PROP_CHARGE_FULL,
	POWER_SUPPLY_PROP_CYCLE_COUNT,
	POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
};

static int smb2_batt_get_prop(struct power_supply *psy,
@@ -1115,6 +1119,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_TEMP:
		rc = smblib_get_prop_from_bms(chg, psp, val);
		break;
	case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE:
		val->intval = chg->fcc_stepper_enable;
		break;
	default:
		pr_err("batt power supply prop %d not supported\n", psp);
		return -EINVAL;
+7 −0
Original line number Diff line number Diff line
@@ -504,6 +504,9 @@ static int smb5_parse_dt(struct smb5 *chip)
	chg->moisture_protection_enabled = of_property_read_bool(node,
					"qcom,moisture-protection-enable");

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

	return 0;
}

@@ -1258,6 +1261,7 @@ static enum power_supply_property smb5_batt_props[] = {
	POWER_SUPPLY_PROP_CYCLE_COUNT,
	POWER_SUPPLY_PROP_RECHARGE_SOC,
	POWER_SUPPLY_PROP_CHARGE_FULL,
	POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
};

#define ITERM_SCALING_FACTOR_PMI632	1525
@@ -1414,6 +1418,9 @@ static int smb5_batt_get_prop(struct power_supply *psy,
		rc = smblib_get_prop_from_bms(chg,
				POWER_SUPPLY_PROP_CHARGE_FULL, val);
		break;
	case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE:
		val->intval = chg->fcc_stepper_enable;
		break;
	default:
		pr_err("batt power supply prop %d not supported\n", psp);
		return -EINVAL;
Loading