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

Commit 99926237 authored by Osvaldo Banuelos's avatar Osvaldo Banuelos Committed by Gerrit - the friendly Code Review server
Browse files

regulator: cprh-kbss-regulator: add support for APM crossover corner



Add support for a corner whose open-loop voltage corresponds to the
VDD supply voltage required during an APM switch transition. This
corner is requested by OSM hardware to the CPRh controller when
the VDD supply must be set to a specific voltage to ensure a stable
APM switch procedure. Define a crossover corner of 880 mV for both
VDD_APC CPR devices.

CRs-Fixed: 1021656
Change-Id: Icf4b640ec2c330b0d9721d3494297e2d8445c9b6
Signed-off-by: default avatarOsvaldo Banuelos <osvaldob@codeaurora.org>
parent ef0049ee
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -42,10 +42,21 @@ KBSS specific properties:
- qcom,apm-threshold-voltage
	Usage:      optional
	Value type: <u32>
	Definition: Specifies the APM threshold voltage in microvolts.  If the
		    VDD_APCC supply voltage is above this level, then the APM is
		    switched to use VDD_APCC.  If VDD_APCC is below this level,
		    then the APM is switched to use VDD_MX.
	Definition: Specifies the APM threshold voltage in microvolts.  The
		    floor to ceiling range for every corner is adjusted to ensure
		    it does not intersect this voltage. The value of this property
		    must match with the APM threshold voltage defined in the OSM
		    device to ensure that if the VDD_APCC supply voltage is above
		    this level, then the APM is switched to use VDD_APCC and if
		    VDD_APCC is below this level, then the APM is switched to use
		    VDD_MX.

- qcom,apm-crossover-voltage
	Usage:      required if qcom,apm-threshold-voltage is specified
	Value type: <u32>
	Definition: Specifies the APM crossover voltage in microvolts which
		    corresponds to the voltage the VDD supply must be set at
		    during an APM switch transition.

- qcom,apm-hysteresis-voltage
	Usage:      optional
+2 −0
Original line number Diff line number Diff line
@@ -576,6 +576,7 @@
		qcom,cpr-voltage-settling-time = <1760>;

		qcom,apm-threshold-voltage = <832000>;
		qcom,apm-crossover-voltage = <880000>;
		qcom,apm-hysteresis-voltage = <32000>;
		qcom,voltage-step = <4000>;
		qcom,voltage-base = <352000>;
@@ -737,6 +738,7 @@
		qcom,cpr-voltage-settling-time = <1760>;

		qcom,apm-threshold-voltage = <832000>;
		qcom,apm-crossover-voltage = <880000>;
		qcom,apm-hysteresis-voltage = <32000>;
		qcom,voltage-step = <4000>;
		qcom,voltage-base = <352000>;
+17 −7
Original line number Diff line number Diff line
@@ -1109,11 +1109,19 @@ static int cpr3_regulator_init_cprh_corners(struct cpr3_regulator *vreg)
		}

		if (ro_sel == INT_MAX) {
			if (!corner->proc_freq) {
				/*
				 * Corner is not used as active DCVS set point
				 * select RO 0 arbitrarily.
				 */
				ro_sel = 0;
			} else {
				cpr3_err(vreg, "corner=%d has invalid RO select value\n",
					 i);
				rc = -EINVAL;
				goto free_base_quots;
			}
		}

		open_loop_volt_steps = DIV_ROUND_UP(corner->open_loop_volt -
						    ctrl->base_volt,
@@ -1121,9 +1129,11 @@ static int cpr3_regulator_init_cprh_corners(struct cpr3_regulator *vreg)
		floor_volt_steps = DIV_ROUND_UP(corner->floor_volt -
						ctrl->base_volt,
						ctrl->step_volt);
		delta_quot_steps = DIV_ROUND_UP(corner->target_quot[ro_sel] -
		delta_quot_steps = corner->proc_freq ?
			DIV_ROUND_UP(corner->target_quot[ro_sel] -
				     base_quots[ro_sel],
						CPRH_DELTA_QUOT_STEP_FACTOR);
				     CPRH_DELTA_QUOT_STEP_FACTOR) :
			0;

		if (open_loop_volt_steps > CPRH_CORNER_INIT_VOLTAGE_MAX_VALUE ||
		    floor_volt_steps > CPRH_CORNER_FLOOR_VOLTAGE_MAX_VALUE ||
+8 −1
Original line number Diff line number Diff line
@@ -572,7 +572,13 @@ struct cpr3_panic_regs_info {
 *			when hardware closed-loop attempts to exceed the ceiling
 *			voltage
 * @apm:		Handle to the array power mux (APM)
 * @apm_threshold_volt:	APM threshold voltage in microvolts
 * @apm_threshold_volt:	Voltage in microvolts which defines the threshold
 *			voltage to determine the APM supply selection for
 *			each corner
 * @apm_crossover_volt:	Voltage in microvolts corresponding to the voltage that
 *			the VDD supply must be set to while an APM switch is in
 *			progress. This element must be initialized for CPRh
 *			controllers when an APM threshold voltage is defined
 * @apm_adj_volt:	Minimum difference between APM threshold voltage and
 *			open-loop voltage which allows the APM threshold voltage
 *			to be used as a ceiling
@@ -736,6 +742,7 @@ struct cpr3_controller {
	int			ceiling_irq;
	struct msm_apm_ctrl_dev *apm;
	int			apm_threshold_volt;
	int			apm_crossover_volt;
	int			apm_adj_volt;
	enum msm_apm_supply	apm_high_supply;
	enum msm_apm_supply	apm_low_supply;
+30 −43
Original line number Diff line number Diff line
@@ -697,61 +697,38 @@ free_temp:
}

/**
 * cprh_kbss_apm_threshold_as_corner() - introduce a corner whose floor, open-loop,
 *		and ceiling voltages correspond to the APM threshold voltage.
 * cprh_kbss_apm_crossover_as_corner() - introduce a corner whose floor,
 *		open-loop, and ceiling voltages correspond to the APM
 *		crossover voltage.
 * @vreg:		Pointer to the CPR3 regulator
 *
 * The APM corner is utilized as a crossover corner by OSM and CPRh
 * hardware to determine the correct APM supply selection for the
 * rest of the corners. This function must be called after all other
 * functions which load per-corner values.
 * hardware to set the VDD supply voltage during the APM switch
 * routine.
 *
 * Return: 0 on success, errno on failure
 */
static int cprh_kbss_apm_threshold_as_corner(struct cpr3_regulator *vreg)
static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
{
	struct cpr3_controller *ctrl = vreg->thread->ctrl;
	struct cpr3_corner *corner;
	struct cprh_corner_band *corner_band;
	int i, threshold, apm_corner = 0;

	if (!ctrl->apm_threshold_volt) {
		/* APM voltage threshold corner not required. */
	if (!ctrl->apm_crossover_volt) {
		/* APM voltage crossover corner not required. */
		return 0;
	}

	threshold = ctrl->apm_threshold_volt;
	vreg->corner_count++;

	for (i = vreg->corner_count - 1; i >= 1; i--) {
		corner = &vreg->corner[i];

		if (threshold >= vreg->corner[i - 1].open_loop_volt) {
			apm_corner = i;
			break;
		}

		memcpy(corner, &vreg->corner[i - 1], sizeof(*corner));
	}

	corner = &vreg->corner[apm_corner];
	corner->proc_freq = 0;
	corner->floor_volt = threshold;
	corner->ceiling_volt = threshold;
	corner->open_loop_volt = threshold;
	corner->use_open_loop = true;
	cpr3_info(vreg, "APM threshold corner=%d, open-loop=%d\n",
		  apm_corner, threshold);

	corner = &vreg->corner[vreg->corner_count];
	/*
	 * Update corner band mappings to account for the inserted
	 * APM crossover corner.
	 * 0 MHz indicates this corner is not to be
	 * used as active DCVS set point.
	 */
	for (i = 0; i < vreg->corner_band_count; i++) {
		corner_band = &vreg->corner_band[i];
		if (corner_band->corner >= apm_corner)
			corner_band->corner++;
	}
	corner->proc_freq = 0;
	corner->floor_volt = ctrl->apm_crossover_volt;
	corner->ceiling_volt = ctrl->apm_crossover_volt;
	corner->open_loop_volt = ctrl->apm_crossover_volt;
	corner->use_open_loop = true;
	vreg->corner_count++;

	return 0;
}
@@ -1203,9 +1180,9 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
		return -EINVAL;
	}

	rc = cprh_kbss_apm_threshold_as_corner(vreg);
	rc = cprh_kbss_apm_crossover_as_corner(vreg);
	if (rc) {
		cpr3_err(vreg, "unable to introduce APM voltage threshold corner\n, rc=%d\n",
		cpr3_err(vreg, "unable to introduce APM voltage crossover corner, rc=%d\n",
			rc);
		return rc;
	}
@@ -1288,8 +1265,18 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl)
	rc = of_property_read_u32(ctrl->dev->of_node,
				  "qcom,apm-threshold-voltage",
				  &ctrl->apm_threshold_volt);
	if (rc)
	if (rc) {
		cpr3_debug(ctrl, "qcom,apm-threshold-voltage not specified\n");
	} else {
		rc = of_property_read_u32(ctrl->dev->of_node,
					  "qcom,apm-crossover-voltage",
					  &ctrl->apm_crossover_volt);
		if (rc) {
			cpr3_err(ctrl, "error reading property qcom,apm-crossover-voltage, rc=%d\n",
				 rc);
			return rc;
		}
	}

	of_property_read_u32(ctrl->dev->of_node, "qcom,apm-hysteresis-voltage",
				&ctrl->apm_adj_volt);