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

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

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

parents a312a5a6 7d6a26f2
Loading
Loading
Loading
Loading
+28 −0
Original line number Original line Diff line number Diff line
@@ -250,6 +250,8 @@ apcc_cpr: cpr3-ctrl@99e8000 {
	qcom,cpr-hw-closed-loop;
	qcom,cpr-hw-closed-loop;
	qcom,cpr-clock-throttling = <0x20>;
	qcom,cpr-clock-throttling = <0x20>;


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

	thread@0 {
	thread@0 {
		qcom,cpr-thread-id = <0>;
		qcom,cpr-thread-id = <0>;
		qcom,cpr-consecutive-up = <0>;
		qcom,cpr-consecutive-up = <0>;
@@ -311,6 +313,15 @@ apcc_cpr: cpr3-ctrl@99e8000 {
			qcom,allow-voltage-interpolation;
			qcom,allow-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;
			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 {
		apc0_cbf_vreg: regulator-cbf {
@@ -358,6 +369,14 @@ apcc_cpr: cpr3-ctrl@99e8000 {
			qcom,allow-voltage-interpolation;
			qcom,allow-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;
			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-voltage-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,allow-quotient-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;
			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 Original line Diff line number Diff line
@@ -140,6 +140,8 @@ gfx_cpr: cpr3-ctrl@838000 {


	qcom,cpr-enable;
	qcom,cpr-enable;


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

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


			qcom,allow-voltage-interpolation;
			qcom,allow-voltage-interpolation;
			qcom,cpr-scaled-open-loop-voltage-as-ceiling;
			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 Original line Diff line number Diff line
@@ -159,6 +159,14 @@ Platform independent properties:
		    enabled) as opposed to open-loop mode (i.e. CPR sensing loop
		    enabled) as opposed to open-loop mode (i.e. CPR sensing loop
		    disabled) by default.
		    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
Second Level Nodes - CPR Threads for a Controller
=================================================
=================================================
@@ -460,8 +468,9 @@ Platform independent properties:
		    order to utilize this property.
		    order to utilize this property.


- qcom,cpr-ro-scaling-factor
- qcom,cpr-ro-scaling-factor
	Usage:      required if qcom,cpr-closed-loop-voltage-fuse-adjustment
	Usage:      required if qcom,cpr-closed-loop-voltage-fuse-adjustment,
		    or qcom,cpr-closed-loop-voltage-adjustment is specified
		    qcom,cpr-closed-loop-voltage-adjustment, or
		    qcom,allow-aging-voltage-adjustment is specified
	Value type: <prop-encoded-array>
	Value type: <prop-encoded-array>
	Definition: A grouping of integer tuple lists.  Each tuple defines the
	Definition: A grouping of integer tuple lists.  Each tuple defines the
		    CPR ring oscillator (RO) scaling factor with units of QUOT/V
		    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
		    qcom,cpr-closed-loop-voltage-adjustment by the relevant RO
		    scaling factor in this property.
		    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
All properties specified within the core regulator framework can also be used in
third level nodes.  These bindings can be found in:
third level nodes.  These bindings can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt.
Documentation/devicetree/bindings/regulator/regulator.txt.
+102 −1
Original line number Original line Diff line number Diff line
@@ -58,6 +58,8 @@
 *			limitations found on a given chip
 *			limitations found on a given chip
 * @vdd_mx_ret_fuse:	Defines the logic retention voltage of VDD_MX
 * @vdd_mx_ret_fuse:	Defines the logic retention voltage of VDD_MX
 * @vdd_apcc_ret_fuse:	Defines the logic retention voltage of VDD_APCC
 * @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
 * 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
 * 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	partial_binning;
	u64	vdd_mx_ret_fuse;
	u64	vdd_mx_ret_fuse;
	u64	vdd_apcc_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.
 * 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
 * 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_FUSE_STEP_VOLT		10000
#define MSM8996_HMSS_VOLTAGE_FUSE_SIZE		6
#define MSM8996_HMSS_VOLTAGE_FUSE_SIZE		6
#define MSM8996_HMSS_QUOT_OFFSET_SCALE		5
#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_CPR_SENSOR_COUNT		25
#define MSM8996_HMSS_THREAD0_SENSOR_MIN		0
#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_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
 * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values
 * @vreg:		Pointer to the CPR3 regulator
 * @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",
	cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n",
		  fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse);
		  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;
	id = vreg->thread->thread_id;


	for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) {
	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,
	if (!of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-adjustment", NULL)
			"qcom,cpr-closed-loop-voltage-adjustment", NULL)
	    && !of_find_property(vreg->of_node,
	    && !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. */
		/* No adjustment required. */
		return 0;
		return 0;
	} else if (!of_find_property(vreg->of_node,
	} 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++)
	for (i = 0; i < vreg->fuse_corner_count; i++)
		ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[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,
	if (of_find_property(vreg->of_node,
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) {
			"qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) {
		rc = cpr3_parse_array_property(vreg,
		rc = cpr3_parse_array_property(vreg,
@@ -1518,6 +1546,72 @@ static int cpr3_hmss_apm_init(struct cpr3_controller *ctrl)
	return 0;
	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
 * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific
 *		initializations
 *		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);
	platform_set_drvdata(pdev, ctrl);


	return cpr3_regulator_register(pdev, ctrl);
	return cpr3_regulator_register(pdev, ctrl);
+150 −38
Original line number Original line Diff line number Diff line
@@ -43,6 +43,8 @@
 *			for each fuse corner (raw, not converted to a voltage)
 *			for each fuse corner (raw, not converted to a voltage)
 * @cpr_fusing_rev:	CPR fusing revision fuse parameter value
 * @cpr_fusing_rev:	CPR fusing revision fuse parameter value
 * @limitation:		CPR limitation select 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.
 * 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	init_voltage[MSM8996_MMSS_FUSE_CORNERS];
	u64	cpr_fusing_rev;
	u64	cpr_fusing_rev;
	u64	limitation;
	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.
 * 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
 * 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_FUSE_STEP_VOLT		10000
#define MSM8996_MMSS_VOLTAGE_FUSE_SIZE		5
#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_SENSOR_COUNT		35


#define MSM8996_MMSS_CPR_CLOCK_RATE		19200000
#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
 * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values
 * @vreg:		Pointer to the CPR3 regulator
 * @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
			  == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION
		? "CPR disabled and no interpolation" : "none");
		? "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++) {
	for (i = 0; i < MSM8996_MMSS_FUSE_CORNERS; i++) {
		rc = cpr3_read_fuse_param(base,
		rc = cpr3_read_fuse_param(base,
			msm8996_mmss_init_voltage_param[i],
			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 i, j, rc, quot_adjust;
	int *volt_adjust, *ro_scale;
	int *volt_adjust, *ro_scale;
	bool explicit_adjustment;
	u32 prev_quot;
	u32 prev_quot;


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

	if (!explicit_adjustment && !vreg->aging_allowed) {
		/* No adjustment required. */
		/* No adjustment required. */
		return 0;
		return 0;
	} else if (!of_find_property(vreg->of_node,
	} 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;
		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",
	rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor",
			vreg->corner_count * CPR3_RO_COUNT,
			vreg->corner_count * CPR3_RO_COUNT,
			corner_sum * 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;
		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 (i = 0; i < vreg->corner_count; i++) {
			for (j = 0; j < CPR3_RO_COUNT; j++) {
			for (j = 0; j < CPR3_RO_COUNT; j++) {
				if (vreg->corner[i].target_quot[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],
						ro_scale[i * CPR3_RO_COUNT + j],
						volt_adjust[i]);
						volt_adjust[i]);
					if (quot_adjust) {
					if (quot_adjust) {
					prev_quot
						prev_quot = vreg->corner[i].
					     = vreg->corner[i].target_quot[j];
								target_quot[j];
						vreg->corner[i].target_quot[j]
						vreg->corner[i].target_quot[j]
						     += quot_adjust;
						     += quot_adjust;
						cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n",
						cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n",
						     i, j, prev_quot,
						     i, j, prev_quot,
					     vreg->corner[i].target_quot[j],
						     vreg->corner[i].
							     target_quot[j],
						     volt_adjust[i]);
						     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 (i = 1; i < vreg->corner_count; i++) {
			for (j = 0; j < CPR3_RO_COUNT; j++) {
			for (j = 0; j < CPR3_RO_COUNT; j++) {
				if (vreg->corner[i].target_quot[j]
				if (vreg->corner[i].target_quot[j]
				    && vreg->corner[i].target_quot[j]
				    && vreg->corner[i].target_quot[j]
					 < vreg->corner[i - 1].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",
					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,
						i - 1, j,
					vreg->corner[i - 1].target_quot[j], i,
						vreg->corner[i - 1].
					j, vreg->corner[i - 1].target_quot[j]);
							target_quot[j],
						i, j,
						vreg->corner[i - 1].
							target_quot[j]);
					vreg->corner[i].target_quot[j]
					vreg->corner[i].target_quot[j]
					   = vreg->corner[i - 1].target_quot[j];
					   = vreg->corner[i - 1].target_quot[j];
				}
				}
			}
			}
		}
		}
	}


done:
done:
	kfree(volt_adjust);
	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
 * cpr3_mmss_init_thread() - perform all steps necessary to initialize the
 *		configuration data for a CPR3 thread
 *		configuration data for a CPR3 thread
@@ -721,6 +826,13 @@ static int cpr3_mmss_regulator_probe(struct platform_device *pdev)
		return rc;
		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);
	platform_set_drvdata(pdev, ctrl);


	return cpr3_regulator_register(pdev, ctrl);
	return cpr3_regulator_register(pdev, ctrl);
Loading