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

Commit d99327ff authored by Abhijeet Dharmapurikar's avatar Abhijeet Dharmapurikar Committed by Anirudh Ghayal
Browse files

regulator: cpr-regulator: Add support for Voltage Sensors



Voltage sensor regulators need to be notified when the corner of apc
rail changes. Voltage Sensor regulator needs to be disabled prior
to changing the apc corner and needs to be notified of the ceiling
and floor voltage before enabling it again.

Change-Id: I0156480f6bfaf10397578caded2c15a298f20f95
Signed-off-by: default avatarAbhijeet Dharmapurikar <adharmap@codeaurora.org>
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
parent 718b9859
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -649,6 +649,12 @@ Optional properties:
				the RPM corner to the corresponding APC virtual
				corner. This property must be defined if
				'rpm-apc-supply' is present.
- qcom,vsens-corner-map:	Array of integers which define the mapping of the VSENS corner to the
				corresponding APC fuse corner. The qcom,vsens-corner-map and
				vdd-vsense-corner-supply properties must both be specified for a given
				cpr-regulator device or neither must be specified.
- vdd-vsens-corner-supply:	Regulator to specify the current operating fuse corner to the Voltage Sensor.
- vdd-vsens-voltage-supply:	Regulator to specify the corner floor/ceiling voltages to the Voltage Sensor.

Example:
	apc_vreg_corner: regulator@f9018000 {
@@ -722,6 +728,10 @@ Example:
		qcom,cpr-clamp-timer-interval = <1>;
		qcom,cpr-apc-volt-step = <5000>;

		qcom,vsens-corner-map = <1 2 2>;
		vdd-vsens-corner-supply = <&vsens_apc0_corner>;
		vdd-vsens-voltage-supply = <&vsens_apc0_voltage>;

		rpm-apc-supply = <&rpm_apc_vreg>;
		qcom,rpm-apc-corner-map = <4 4 5 5 7 7 7 7 7 7 7 7>;

+103 −1
Original line number Diff line number Diff line
@@ -279,6 +279,13 @@ struct cpr_regulator {
	int		*save_ctl;
	int		*save_irq;

	int		*vsens_corner_map;
	/* vsens status */
	bool		vsens_enabled;
	/* vsens regulators */
	struct regulator	*vdd_vsens_corner;
	struct regulator	*vdd_vsens_voltage;

	/* Config parameters */
	bool		enable;
	u32		ref_clk_khz;
@@ -703,12 +710,20 @@ static int cpr_scale_voltage(struct cpr_regulator *cpr_vreg, int corner,
{
	int rc = 0, vdd_mx_vmin = 0;
	int mem_acc_corner = cpr_vreg->mem_acc_corner_map[corner];
	int apc_corner;
	int fuse_corner = cpr_vreg->corner_map[corner];
	int apc_corner, vsens_corner;

	/* Determine the vdd_mx voltage */
	if (dir != NO_CHANGE && cpr_vreg->vdd_mx != NULL)
		vdd_mx_vmin = cpr_mx_get(cpr_vreg, corner, new_apc_volt);


	if (cpr_vreg->vdd_vsens_voltage && cpr_vreg->vsens_enabled) {
		rc = regulator_disable(cpr_vreg->vdd_vsens_voltage);
		if (!rc)
			cpr_vreg->vsens_enabled = false;
	}

	if (dir == DOWN) {
		if (!rc && cpr_vreg->mem_acc_vreg)
			rc = regulator_set_voltage(cpr_vreg->mem_acc_vreg,
@@ -750,6 +765,22 @@ static int cpr_scale_voltage(struct cpr_regulator *cpr_vreg, int corner,
			rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
	}

	if (!rc && cpr_vreg->vdd_vsens_corner) {
		vsens_corner = cpr_vreg->vsens_corner_map[fuse_corner];
		rc = regulator_set_voltage(cpr_vreg->vdd_vsens_corner,
					vsens_corner, vsens_corner);
	}
	if (!rc && cpr_vreg->vdd_vsens_voltage) {
		rc = regulator_set_voltage(cpr_vreg->vdd_vsens_voltage,
					cpr_vreg->floor_volt[corner],
					cpr_vreg->ceiling_volt[corner]);
		if (!rc && !cpr_vreg->vsens_enabled) {
			rc = regulator_enable(cpr_vreg->vdd_vsens_voltage);
			if (!rc)
				cpr_vreg->vsens_enabled = true;
		}
	}

	return rc;
}

@@ -4208,6 +4239,70 @@ static int cpr_rpm_apc_init(struct platform_device *pdev,
	return rc;
}

static int cpr_vsens_init(struct platform_device *pdev,
			       struct cpr_regulator *cpr_vreg)
{
	int rc = 0, len = 0;
	struct device_node *of_node = pdev->dev.of_node;

	if (of_find_property(of_node, "vdd-vsens-voltage-supply", NULL)) {
		cpr_vreg->vdd_vsens_voltage = devm_regulator_get(&pdev->dev,
							"vdd-vsens-voltage");
		if (IS_ERR_OR_NULL(cpr_vreg->vdd_vsens_voltage)) {
			rc = PTR_ERR(cpr_vreg->vdd_vsens_voltage);
			cpr_vreg->vdd_vsens_voltage = NULL;
			if (rc == -EPROBE_DEFER)
				return rc;
			/* device not found */
			cpr_debug(cpr_vreg, "regulator_get: vdd-vsens-voltage: rc=%d\n",
					rc);
			return 0;
		}
	}

	if (of_find_property(of_node, "vdd-vsens-corner-supply", NULL)) {
		cpr_vreg->vdd_vsens_corner = devm_regulator_get(&pdev->dev,
							"vdd-vsens-corner");
		if (IS_ERR_OR_NULL(cpr_vreg->vdd_vsens_corner)) {
			rc = PTR_ERR(cpr_vreg->vdd_vsens_corner);
			cpr_vreg->vdd_vsens_corner = NULL;
			if (rc == -EPROBE_DEFER)
				return rc;
			/* device not found */
			cpr_debug(cpr_vreg, "regulator_get: vdd-vsens-corner: rc=%d\n",
					rc);
			return 0;
		}

		if (!of_find_property(of_node, "qcom,vsens-corner-map", &len)) {
			cpr_err(cpr_vreg, "qcom,vsens-corner-map missing\n");
			return -EINVAL;
		}

		if (len != cpr_vreg->num_fuse_corners * sizeof(u32)) {
			cpr_err(cpr_vreg, "qcom,vsens-corner-map length=%d is invalid: required:%d\n",
				len, cpr_vreg->num_fuse_corners);
			return -EINVAL;
		}

		cpr_vreg->vsens_corner_map = devm_kcalloc(&pdev->dev,
					(cpr_vreg->num_fuse_corners + 1),
			sizeof(*cpr_vreg->vsens_corner_map), GFP_KERNEL);
		if (!cpr_vreg->vsens_corner_map)
			return -ENOMEM;

		rc = of_property_read_u32_array(of_node,
					"qcom,vsens-corner-map",
					&cpr_vreg->vsens_corner_map[1],
					cpr_vreg->num_fuse_corners);
		if (rc)
			cpr_err(cpr_vreg, "read qcom,vsens-corner-map failed, rc = %d\n",
				rc);
	}

	return rc;
}

static int cpr_init_cpr(struct platform_device *pdev,
			       struct cpr_regulator *cpr_vreg)
{
@@ -5024,6 +5119,13 @@ static int cpr_regulator_probe(struct platform_device *pdev)
		goto err_out;
	}

	rc = cpr_vsens_init(pdev, cpr_vreg);
	if (rc) {
		cpr_err(cpr_vreg, "Initialize vsens configuration failed rc=%d\n",
			rc);
		return rc;
	}

	rc = cpr_apc_init(pdev, cpr_vreg);
	if (rc) {
		if (rc != -EPROBE_DEFER)