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

Commit 7d6a26f2 authored by David Collins's avatar David Collins
Browse files

regulator: cpr3-regulator: add support for aging voltage margin adjustment



Add support for increasing the closed-loop voltage margin over
time based upon the results of aging sensor measurements.  The
aging ring oscillators (ROs) are arranging in pairs such that
one is constantly stressed by the vdd-supply voltage and the
other is never stressed.  The difference between the quotients
measured by these ROs gives an indication of how much the silicon
has aged.

Change-Id: Ic48a353bd0216247a48b32f19c2c08b750387047
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent ccdbb6d7
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -250,6 +250,8 @@ apcc_cpr: cpr3-ctrl@99e8000 {
	qcom,cpr-hw-closed-loop;
	qcom,cpr-clock-throttling = <0x20>;

	qcom,cpr-aging-ref-voltage = <905000>;

	thread@0 {
		qcom,cpr-thread-id = <0>;
		qcom,cpr-consecutive-up = <0>;
@@ -311,6 +313,15 @@ apcc_cpr: cpr3-ctrl@99e8000 {
			qcom,allow-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;

			qcom,cpr-aging-max-voltage-adjustment = <25000>;
			qcom,cpr-aging-ref-corner = <11>;
			qcom,cpr-aging-ro-scaling-factor = <3200>;
			qcom,cpr-aging-derate =
				<1000 1000 1000 1000 1000 1000 1000 1000
				 1000 1000 1000 1000 1000 1000 1000 1000
				 1000 1000 1000>;
			qcom,allow-aging-voltage-adjustment = <1>;
		};

		apc0_cbf_vreg: regulator-cbf {
@@ -358,6 +369,14 @@ apcc_cpr: cpr3-ctrl@99e8000 {
			qcom,allow-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;

			qcom,cpr-aging-max-voltage-adjustment = <25000>;
			qcom,cpr-aging-ref-corner = <9>;
			qcom,cpr-aging-ro-scaling-factor = <3200>;
			qcom,cpr-aging-derate =
				<1000 1000 1000 1000 1000 1000 1000 1000
				 1000 1000>;
			qcom,allow-aging-voltage-adjustment = <1>;
		};
	};

@@ -422,6 +441,15 @@ apcc_cpr: cpr3-ctrl@99e8000 {
			qcom,allow-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;

			qcom,cpr-aging-max-voltage-adjustment = <25000>;
			qcom,cpr-aging-ref-corner = <11>;
			qcom,cpr-aging-ro-scaling-factor = <3200>;
			qcom,cpr-aging-derate =
				<1000 1000 1000 1000 1000 1000 1000 1000
				 1000 1000 1000 1000 1000 1000 1000 1000
				 1000 1000>;
			qcom,allow-aging-voltage-adjustment = <1>;
		};
	};
};
+9 −0
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ gfx_cpr: cpr3-ctrl@838000 {

	qcom,cpr-enable;

	qcom,cpr-aging-ref-voltage = <905000>;

	thread@0 {
		qcom,cpr-thread-id = <0>;
		qcom,cpr-consecutive-up = <0>;
@@ -194,6 +196,13 @@ gfx_cpr: cpr3-ctrl@838000 {

			qcom,allow-voltage-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;

			qcom,cpr-aging-max-voltage-adjustment = <25000>;
			qcom,cpr-aging-ref-corner = <3>;
			qcom,cpr-aging-ro-scaling-factor = <2950>;
			qcom,cpr-aging-derate =
				<1000 1000 1000 1000>;
			qcom,allow-aging-voltage-adjustment = <1>;
		};
	};
};
+86 −2
Original line number Diff line number Diff line
@@ -159,6 +159,14 @@ Platform independent properties:
		    enabled) as opposed to open-loop mode (i.e. CPR sensing loop
		    disabled) by default.

- qcom,cpr-aging-ref-voltage
	Usage:      required if qcom,allow-aging-voltage-adjustment is specified
		    for any third level nodes
	Value type: <u32>
	Definition: Specifies the CPR aging reference voltage in microvolts.
		    This is the voltage that vdd-supply must be set to when
		    performing an aging measurement.

=================================================
Second Level Nodes - CPR Threads for a Controller
=================================================
@@ -460,8 +468,9 @@ Platform independent properties:
		    order to utilize this property.

- qcom,cpr-ro-scaling-factor
	Usage:      required if qcom,cpr-closed-loop-voltage-fuse-adjustment
		    or qcom,cpr-closed-loop-voltage-adjustment is specified
	Usage:      required if qcom,cpr-closed-loop-voltage-fuse-adjustment,
		    qcom,cpr-closed-loop-voltage-adjustment, or
		    qcom,allow-aging-voltage-adjustment is specified
	Value type: <prop-encoded-array>
	Definition: A grouping of integer tuple lists.  Each tuple defines the
		    CPR ring oscillator (RO) scaling factor with units of QUOT/V
@@ -488,6 +497,81 @@ Platform independent properties:
		    qcom,cpr-closed-loop-voltage-adjustment by the relevant RO
		    scaling factor in this property.

- qcom,allow-aging-voltage-adjustment
	Usage:      optional
	Value type: <prop-encoded-array>
	Definition: A list of integers which specifies if CPR aging adjustment
		    should be performed for each fuse combination.
		    Supported per-combo element values:
			0 - do not perform CPR aging adjustment
			1 - perform CPR aging adjustment

		    The list must contain either qcom,cpr-fuse-combos number of
		    elements in which case the elements are applied to fuse
		    combinations 1-to-1 or the list must contain exactly 1
		    element which is used regardless of the fuse combination
		    found on a given chip.

- qcom,cpr-aging-max-voltage-adjustment
	Usage:      required if qcom,allow-aging-voltage-adjustment is specified
	Value type: <prop-encoded-array>
	Definition: A list of integers which defines the maximum CPR aging
		    voltage margin adjustment in microvolts that may be added
		    for each fuse combination.  If this property is specified
		    and the adjustment specified is greater than 0, then aging
		    adjustments are required for this regulator.

		    The list must contain either qcom,cpr-fuse-combos number of
		    elements in which case the max adjustments are applied to
		    fuse combinations 1-to-1 or the list must contain exactly 1
		    element which is used regardless of the fuse combination
		    found on a given chip.

- qcom,cpr-aging-ref-corner
	Usage:      required if qcom,allow-aging-voltage-adjustment is specified
	Value type: <prop-encoded-array>
	Definition: A list of integers which defines the CPR reference corner
		    for this regulator to use during aging measurements for each
		    fuse combination.

		    The list must contain either qcom,cpr-fuse-combos number of
		    elements in which case the max adjustments are applied to
		    fuse combinations 1-to-1 or the list must contain exactly 1
		    element which is used regardless of the fuse combination
		    found on a given chip.

- qcom,cpr-aging-ro-scaling-factor
	Usage:      required if qcom,allow-aging-voltage-adjustment is specified
	Value type: <prop-encoded-array>
	Definition: A list of integers which defines the CPR aging ring
		    oscillator (RO) scaling factor with units of QUOT/V to use
		    during aging measurements for each fuse combination.

		    The list must contain either qcom,cpr-fuse-combos number of
		    elements in which case the scaling factors are applied to
		    fuse combinations 1-to-1 or the list must contain exactly 1
		    element which is used regardless of the fuse combination
		    found on a given chip.

- qcom,cpr-aging-derate
	Usage:      optional, though only meaningful if
		    qcom,allow-aging-voltage-adjustment is specified
	Value type: <prop-encoded-array>
	Definition: A list of integer tuples which each define the CPR aging
		    derating scaling factor to apply to the closed-loop voltage
		    margin adjustment for each corner.  The individual scaling
		    factors have units of uV/mV and are ordered from lowest to
		    highest corner per tuple.  For example, a value of 900
		    specifies that the voltage adjustment for the corner should
		    be 90% (900/1000) of that for the reference corner.

		    The list and tuples must meet the same size requirements as
		    those specified for qcom,cpr-voltage-ceiling above.

		    If this property is not specified, then it is assumed that
		    no corners require derating (i.e. the scaling factor would
		    be 1000).

All properties specified within the core regulator framework can also be used in
third level nodes.  These bindings can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt.
+102 −1
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@
 *			limitations found on a given chip
 * @vdd_mx_ret_fuse:	Defines the logic retention voltage of VDD_MX
 * @vdd_apcc_ret_fuse:	Defines the logic retention voltage of VDD_APCC
 * @aging_init_quot_diff:	Initial quotient difference between CPR aging
 *			min and max sensors measured at time of manufacturing
 *
 * This struct holds the values for all of the fuses read from memory.  The
 * values for ro_sel, init_voltage, target_quot, and quot_offset come from
@@ -76,6 +78,7 @@ struct cpr3_msm8996_hmss_fuses {
	u64	partial_binning;
	u64	vdd_mx_ret_fuse;
	u64	vdd_apcc_ret_fuse;
	u64	aging_init_quot_diff;
};

/**
@@ -337,6 +340,12 @@ static const struct cpr3_fuse_param msm8996_cpr_partial_binning_param[] = {
	{},
};

static const struct cpr3_fuse_param
msm8996_hmss_aging_init_quot_diff_param[] = {
	{68, 14, 19},
	{},
};

/*
 * Some initial msm8996 parts cannot be used in a meaningful way by software.
 * Other parts can only be used when operating with CPR disabled (i.e. at the
@@ -390,6 +399,8 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = {
#define MSM8996_HMSS_FUSE_STEP_VOLT		10000
#define MSM8996_HMSS_VOLTAGE_FUSE_SIZE		6
#define MSM8996_HMSS_QUOT_OFFSET_SCALE		5
#define MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE	2
#define MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE	6

#define MSM8996_HMSS_CPR_SENSOR_COUNT		25
#define MSM8996_HMSS_THREAD0_SENSOR_MIN		0
@@ -399,6 +410,9 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = {

#define MSM8996_HMSS_CPR_CLOCK_RATE		19200000

#define MSM8996_HMSS_AGING_SENSOR_ID		11
#define MSM8996_HMSS_AGING_BYPASS_MASK0		(GENMASK(7, 0) & ~BIT(3))

/**
 * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values
 * @vreg:		Pointer to the CPR3 regulator
@@ -495,6 +509,14 @@ static int cpr3_msm8996_hmss_read_fuse_data(struct cpr3_regulator *vreg)
	cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n",
		  fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse);

	rc = cpr3_read_fuse_param(base, msm8996_hmss_aging_init_quot_diff_param,
				&fuse->aging_init_quot_diff);
	if (rc) {
		cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
			rc);
		return rc;
	}

	id = vreg->thread->thread_id;

	for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) {
@@ -845,7 +867,8 @@ static int cpr3_hmss_parse_closed_loop_voltage_adjustments(
	if (!of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-adjustment", NULL)
	    && !of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) {
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)
	    && !vreg->aging_allowed) {
		/* No adjustment required. */
		return 0;
	} else if (!of_find_property(vreg->of_node,
@@ -874,6 +897,11 @@ static int cpr3_hmss_parse_closed_loop_voltage_adjustments(
	for (i = 0; i < vreg->fuse_corner_count; i++)
		ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[i]];

	for (i = 0; i < vreg->corner_count; i++)
		memcpy(vreg->corner[i].ro_scale,
		 &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT],
		 sizeof(*ro_all_scale) * CPR3_RO_COUNT);

	if (of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) {
		rc = cpr3_parse_array_property(vreg,
@@ -1518,6 +1546,72 @@ static int cpr3_hmss_apm_init(struct cpr3_controller *ctrl)
	return 0;
}

/**
 * cpr3_hmss_init_aging() - perform HMSS CPR3 controller specific
 *		aging initializations
 * @ctrl:		Pointer to the CPR3 controller
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_hmss_init_aging(struct cpr3_controller *ctrl)
{
	struct cpr3_msm8996_hmss_fuses *fuse = NULL;
	struct cpr3_regulator *vreg;
	u32 aging_ro_scale;
	int i, j, rc;

	for (i = 0; i < ctrl->thread_count; i++) {
		for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
			if (ctrl->thread[i].vreg[j].aging_allowed) {
				ctrl->aging_required = true;
				vreg = &ctrl->thread[i].vreg[j];
				fuse = vreg->platform_fuses;
				break;
			}
		}
	}

	if (!ctrl->aging_required || !fuse)
		return 0;

	rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor",
					1, vreg->fuse_combos_supported,
					vreg->fuse_combo, &aging_ro_scale);
	if (rc)
		return rc;

	if (aging_ro_scale == 0) {
		cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n",
			aging_ro_scale);
		return -EINVAL;
	}

	ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL;
	ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE;

	ctrl->aging_sensor_count = 1;
	ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL);
	if (!ctrl->aging_sensor)
		return -ENOMEM;

	ctrl->aging_sensor->sensor_id = MSM8996_HMSS_AGING_SENSOR_ID;
	ctrl->aging_sensor->bypass_mask[0] = MSM8996_HMSS_AGING_BYPASS_MASK0;
	ctrl->aging_sensor->ro_scale = aging_ro_scale;

	ctrl->aging_sensor->init_quot_diff
		= cpr3_convert_open_loop_voltage_fuse(0,
			MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE,
			fuse->aging_init_quot_diff,
			MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE);

	cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n",
		ctrl->aging_sensor->sensor_id,
		ctrl->aging_sensor->init_quot_diff,
		ctrl->aging_sensor->ro_scale);

	return 0;
}

/**
 * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific
 *		initializations
@@ -1708,6 +1802,13 @@ static int cpr3_hmss_regulator_probe(struct platform_device *pdev)
		}
	}

	rc = cpr3_hmss_init_aging(ctrl);
	if (rc) {
		cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n",
			rc);
		return rc;
	}

	platform_set_drvdata(pdev, ctrl);

	return cpr3_regulator_register(pdev, ctrl);
+150 −38
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@
 *			for each fuse corner (raw, not converted to a voltage)
 * @cpr_fusing_rev:	CPR fusing revision fuse parameter value
 * @limitation:		CPR limitation select fuse parameter value
 * @aging_init_quot_diff:	Initial quotient difference between CPR aging
 *			min and max sensors measured at time of manufacturing
 *
 * This struct holds the values for all of the fuses read from memory.
 */
@@ -50,6 +52,7 @@ struct cpr3_msm8996_mmss_fuses {
	u64	init_voltage[MSM8996_MMSS_FUSE_CORNERS];
	u64	cpr_fusing_rev;
	u64	limitation;
	u64	aging_init_quot_diff;
};

/**
@@ -110,6 +113,12 @@ static const struct cpr3_fuse_param msm8996_cpr_limitation_param[] = {
	{},
};

static const struct cpr3_fuse_param
msm8996_mmss_aging_init_quot_diff_param[] = {
	{68, 26, 31},
	{},
};

/*
 * Some initial msm8996 parts cannot be used in a meaningful way by software.
 * Other parts can only be used when operating with CPR disabled (i.e. at the
@@ -134,11 +143,16 @@ static const int msm8996_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = {

#define MSM8996_MMSS_FUSE_STEP_VOLT		10000
#define MSM8996_MMSS_VOLTAGE_FUSE_SIZE		5
#define MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SCALE	2
#define MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SIZE	6

#define MSM8996_MMSS_CPR_SENSOR_COUNT		35

#define MSM8996_MMSS_CPR_CLOCK_RATE		19200000

#define MSM8996_MMSS_AGING_SENSOR_ID		29
#define MSM8996_MMSS_AGING_BYPASS_MASK0		(GENMASK(23, 0))

/**
 * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values
 * @vreg:		Pointer to the CPR3 regulator
@@ -181,6 +195,14 @@ static int cpr3_msm8996_mmss_read_fuse_data(struct cpr3_regulator *vreg)
			  == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION
		? "CPR disabled and no interpolation" : "none");

	rc = cpr3_read_fuse_param(base, msm8996_mmss_aging_init_quot_diff_param,
				&fuse->aging_init_quot_diff);
	if (rc) {
		cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
			rc);
		return rc;
	}

	for (i = 0; i < MSM8996_MMSS_FUSE_CORNERS; i++) {
		rc = cpr3_read_fuse_param(base,
			msm8996_mmss_init_voltage_param[i],
@@ -267,10 +289,13 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg,
{
	int i, j, rc, quot_adjust;
	int *volt_adjust, *ro_scale;
	bool explicit_adjustment;
	u32 prev_quot;

	if (!of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-adjustment", NULL)) {
	explicit_adjustment = of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-adjustment", NULL);

	if (!explicit_adjustment && !vreg->aging_allowed) {
		/* No adjustment required. */
		return 0;
	} else if (!of_find_property(vreg->of_node,
@@ -288,15 +313,6 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg,
		goto done;
	}

	rc = cpr3_parse_array_property(vreg,
		"qcom,cpr-closed-loop-voltage-adjustment",
		vreg->corner_count, corner_sum, combo_offset, volt_adjust);
	if (rc) {
		cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
			rc);
		goto done;
	}

	rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor",
			vreg->corner_count * CPR3_RO_COUNT,
			corner_sum * CPR3_RO_COUNT,
@@ -308,6 +324,25 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg,
		goto done;
	}

	for (i = 0; i < vreg->corner_count; i++)
		memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT],
			sizeof(*ro_scale) * CPR3_RO_COUNT);

	if (explicit_adjustment) {
		rc = cpr3_parse_array_property(vreg,
			"qcom,cpr-closed-loop-voltage-adjustment",
			vreg->corner_count, corner_sum, combo_offset,
			volt_adjust);
		if (rc) {
			cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
				rc);
			goto done;
		}

		/*
		 * Adjust the target quotients for each corner according to
		 * device tree adjustment values.
		 */
		for (i = 0; i < vreg->corner_count; i++) {
			for (j = 0; j < CPR3_RO_COUNT; j++) {
				if (vreg->corner[i].target_quot[j]) {
@@ -315,35 +350,45 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg,
						ro_scale[i * CPR3_RO_COUNT + j],
						volt_adjust[i]);
					if (quot_adjust) {
					prev_quot
					     = vreg->corner[i].target_quot[j];
						prev_quot = vreg->corner[i].
								target_quot[j];
						vreg->corner[i].target_quot[j]
						     += quot_adjust;
						cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n",
						     i, j, prev_quot,
					     vreg->corner[i].target_quot[j],
						     vreg->corner[i].
							     target_quot[j],
						     volt_adjust[i]);
					}
				}
			}
		}

	/* Ensure that target quotients increase monotonically */
		/*
		 * Ensure that target quotients increase monotonically from
		 * lower to higher corners after being adjusted based upon
		 * device tree adjustment values.
		 */
		for (i = 1; i < vreg->corner_count; i++) {
			for (j = 0; j < CPR3_RO_COUNT; j++) {
				if (vreg->corner[i].target_quot[j]
				    && vreg->corner[i].target_quot[j]
					 < vreg->corner[i - 1].target_quot[j]) {
					cpr3_info(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n",
					i, j, vreg->corner[i].target_quot[j],
						i, j,
						vreg->corner[i].target_quot[j],
						i - 1, j,
					vreg->corner[i - 1].target_quot[j], i,
					j, vreg->corner[i - 1].target_quot[j]);
						vreg->corner[i - 1].
							target_quot[j],
						i, j,
						vreg->corner[i - 1].
							target_quot[j]);
					vreg->corner[i].target_quot[j]
					   = vreg->corner[i - 1].target_quot[j];
				}
			}
		}
	}

done:
	kfree(volt_adjust);
@@ -504,6 +549,66 @@ static void cpr3_mmss_print_settings(struct cpr3_regulator *vreg)
	}
}

/**
 * cpr3_mmss_init_aging() - perform MMSS CPR3 controller specific
 *		aging initializations
 * @ctrl:		Pointer to the CPR3 controller
 *
 * Return: 0 on success, errno on failure
 */
static int cpr3_mmss_init_aging(struct cpr3_controller *ctrl)
{
	struct cpr3_msm8996_mmss_fuses *fuse;
	struct cpr3_regulator *vreg;
	u32 aging_ro_scale;
	int rc;

	vreg = &ctrl->thread[0].vreg[0];

	ctrl->aging_required = vreg->aging_allowed;
	fuse = vreg->platform_fuses;

	if (!ctrl->aging_required || !fuse)
		return 0;

	rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor",
					1, vreg->fuse_combos_supported,
					vreg->fuse_combo, &aging_ro_scale);
	if (rc)
		return rc;

	if (aging_ro_scale == 0) {
		cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n",
			aging_ro_scale);
		return -EINVAL;
	}

	ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL;
	ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE;

	ctrl->aging_sensor_count = 1;
	ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL);
	if (!ctrl->aging_sensor)
		return -ENOMEM;

	ctrl->aging_sensor->sensor_id = MSM8996_MMSS_AGING_SENSOR_ID;
	ctrl->aging_sensor->bypass_mask[0] = MSM8996_MMSS_AGING_BYPASS_MASK0;
	ctrl->aging_sensor->ro_scale = aging_ro_scale;

	ctrl->aging_sensor->init_quot_diff
		= cpr3_convert_open_loop_voltage_fuse(0,
			MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SCALE,
			fuse->aging_init_quot_diff,
			MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SIZE);

	cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n",
		ctrl->aging_sensor->sensor_id,
		ctrl->aging_sensor->init_quot_diff,
		ctrl->aging_sensor->ro_scale);

	return 0;
}

/**
 * cpr3_mmss_init_thread() - perform all steps necessary to initialize the
 *		configuration data for a CPR3 thread
@@ -721,6 +826,13 @@ static int cpr3_mmss_regulator_probe(struct platform_device *pdev)
		return rc;
	}

	rc = cpr3_mmss_init_aging(ctrl);
	if (rc) {
		cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n",
			rc);
		return rc;
	}

	platform_set_drvdata(pdev, ctrl);

	return cpr3_regulator_register(pdev, ctrl);
Loading