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

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

Merge "regulator: cpr-regulator: Add minimum difference allowed for quotients"

parents f8c606e0 c9018aab
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -559,6 +559,25 @@ Optional properties:
				read in order to get the redundant quotient offset for a fuse corner. This
				property is the same as qcom,cpr-fuse-quot-offset except that it is only
				utilized if a chip is configured to use the redundant set of fuse values.
- qcom,cpr-fuse-min-quot-diff:	Array of values which define the minimum difference allowed between the adjusted
				quotients of the fuse corners. The length of the array should be equal to the value
				of the qcom,cpr-fuse-corners property. Where each element in the array maps to the
				fuse corners in increasing order.
- qcom,cpr-min-quot-diff-adjustment:	Array of integer tuples of target quotient offsets to be added to
				the adjusted target quotients of each fuse corner. When the quotient difference
				between two adjacent fuse corners is insufficient, the quotient for the higher fuse corner is
				replaced with that of the lower fuse corner plus the adjustment value.
				The elements in a tuple are ordered from lowest voltage corner to highest voltage corner.
				Each tuple must be of the length defined by qcom,cpr-fuse-corners.
				If the qcom,cpr-fuse-version-map property is specified, then qcom,cpr-min-quot-diff-adjustment
				must contain the same number of tuples as qcom,cpr-fuse-version-map.  These tuples are then mapped
				one-to-one in the order specified.  E.g. if the second qcom,cpr-fuse-version-map tuple matches
				for a given device, then the quotient adjustments defined in the
				second qcom,cpr-min-quot-diff-adjustment tuple will be applied.  If the
				qcom,cpr-fuse-version-map property is not specified, then
				qcom,cpr-min-quot-diff-adjustment must contain a single tuple which is then
				applied unconditionally. The qcom,cpr-min-quot-diff-adjustment property must be specified
				if the qcom,cpr-fuse-min-quot-diff property is specified.

Example:
	apc_vreg_corner: regulator@f9018000 {
@@ -720,6 +739,11 @@ Example:
				<0 0 (-100000)>,
				<0 0 (-100000)>,
				<0 0 (-45000)>;
		qcom,cpr-fuse-min-quot-diff = <0 0 40>;
		qcom,cpr-min-quot-diff-adjustment =
					<0 0 0>,
					<0 0 72>,
					<0 0 104>;
		qcom,cpr-virtual-corner-init-voltage-adjustment =
			<0 0 0 (-10000) 0 0 0 0 0 0 0 0>,
			<0 0 0 0 0 0 0 0 0 0 0 (-20000)>,
+100 −4
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -2721,6 +2721,87 @@ done:
	return rc;
}

static int cpr_minimum_quot_difference_adjustment(struct platform_device *pdev,
					struct cpr_regulator *cpr_vreg)
{
	struct device_node *of_node = pdev->dev.of_node;
	int tuple_count, tuple_match;
	int rc, i, len = 0;
	u32 index, adjust_quot = 0;
	u32 *min_diff_quot;

	if (!of_find_property(of_node, "qcom,cpr-fuse-min-quot-diff", NULL))
		/* No conditional adjustment needed on revised quotients. */
		return 0;

	if (!of_find_property(of_node, "qcom,cpr-min-quot-diff-adjustment",
						&len)) {
		cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment not specified\n");
		return -ENODEV;
	}

	if (cpr_vreg->cpr_fuse_map_count) {
		if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH)
			/* No matching index to use for quotient adjustment. */
			return 0;
		tuple_count = cpr_vreg->cpr_fuse_map_count;
		tuple_match = cpr_vreg->cpr_fuse_map_match;
	} else {
		tuple_count = 1;
		tuple_match = 0;
	}

	if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) {
		cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment length=%d is invalid\n",
					len);
		return -EINVAL;
	}

	min_diff_quot = kzalloc(cpr_vreg->num_fuse_corners * sizeof(u32),
							GFP_KERNEL);
	if (!min_diff_quot) {
		cpr_err(cpr_vreg, "memory alloc failed\n");
		return -ENOMEM;
	}

	rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-min-quot-diff",
						min_diff_quot,
						cpr_vreg->num_fuse_corners);
	if (rc < 0) {
		cpr_err(cpr_vreg, "qcom,cpr-fuse-min-quot-diff reading failed, rc = %d\n",
							rc);
		goto error;
	}

	for (i = CPR_FUSE_CORNER_MIN + 1;
				i <= cpr_vreg->num_fuse_corners; i++) {
		if ((cpr_vreg->cpr_fuse_target_quot[i]
			- cpr_vreg->cpr_fuse_target_quot[i - 1])
		    <= (int)min_diff_quot[i - CPR_FUSE_CORNER_MIN]) {
			index = tuple_match * cpr_vreg->num_fuse_corners
					+ i - CPR_FUSE_CORNER_MIN;
			rc = of_property_read_u32_index(of_node,
						"qcom,cpr-min-quot-diff-adjustment",
						index, &adjust_quot);
			if (rc) {
				cpr_err(cpr_vreg, "could not read qcom,cpr-min-quot-diff-adjustment index %u, rc=%d\n",
							index, rc);
				goto error;
			}

			cpr_vreg->cpr_fuse_target_quot[i]
				= cpr_vreg->cpr_fuse_target_quot[i - 1]
					+ adjust_quot;
			cpr_info(cpr_vreg, "Corner[%d]: revised adjusted quotient = %d\n",
					i, cpr_vreg->cpr_fuse_target_quot[i]);
		};
	}

error:
	kfree(min_diff_quot);
	return rc;
}

static int cpr_adjust_target_quots(struct platform_device *pdev,
					struct cpr_regulator *cpr_vreg)
{
@@ -2772,6 +2853,11 @@ static int cpr_adjust_target_quots(struct platform_device *pdev,
		}
	}

	rc = cpr_minimum_quot_difference_adjustment(pdev, cpr_vreg);
	if (rc)
		cpr_err(cpr_vreg, "failed to apply minimum quot difference rc=%d\n",
					rc);

	return rc;
}

@@ -2814,10 +2900,10 @@ static int cpr_check_allowed(struct platform_device *pdev,
		return rc;
	}

	if (!allow_status)
		cpr_vreg->cpr_fuse_disable = true;
	else
	if (allow_status && !cpr_vreg->cpr_fuse_disable)
		cpr_vreg->cpr_fuse_disable = false;
	else
		cpr_vreg->cpr_fuse_disable = true;

	cpr_info(cpr_vreg, "CPR closed loop is %s for fuse revision %d\n",
		cpr_vreg->cpr_fuse_disable ? "disabled" : "enabled",
@@ -3030,6 +3116,16 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev,
			cpr_vreg->cpr_fuse_target_quot[i]);
	}

	for (i = CPR_FUSE_CORNER_MIN + 1;
				i <= cpr_vreg->num_fuse_corners; i++) {
		if (cpr_vreg->cpr_fuse_target_quot[i]
				< cpr_vreg->cpr_fuse_target_quot[i - 1]) {
			cpr_vreg->cpr_fuse_disable = true;
			cpr_err(cpr_vreg, "invalid quotient values; permanently disabling CPR\n");
			goto error;
		}
	}

	rc = cpr_adjust_target_quots(pdev, cpr_vreg);
	if (rc)
		goto error;