summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTirupathi Reddy <tirupath@codeaurora.org>2016-02-11 18:00:22 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-25 16:02:44 -0700
commit0dc93b15a84a8350081acd29592ef873be1918c9 (patch)
tree8f400e5b811a3e3e1fb996c22f7c6e207bf18882
parent7f3712ee81e1acc1e34def428cf621aec6a7a651 (diff)
regulator: cpr4: Add miscellaneous fuse based voltage adjustments
Apply voltage adjustments for required voltage corners based on different values of selected miscellaneous fuse bits. Apply the adjustments to both open-loop voltages and closed-loop target quotients. CRs-Fixed: 982984 Change-Id: Ic45949afc8445d35c245434a7f51e4859a5978ad Signed-off-by: Tirupathi Reddy <tirupath@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt28
-rw-r--r--drivers/regulator/cpr4-apss-regulator.c151
2 files changed, 178 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
index 61382b562676..4864bef72962 100644
--- a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt
@@ -348,6 +348,27 @@ APSS specific properties:
regardless of the fuse combination and speed bin found
on a given chip.
+- qcom,cpr-misc-fuse-voltage-adjustment
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: A grouping of integer tuple lists where each tuple defines
+ the voltage adjustments in microvolts for each voltage
+ corner in order from lowest to highest. This adjustment is
+ applied to both open-loop and closed-loop voltages.
+
+ Each tuple list must contain a number of tuples equal to
+ 2 to the power of the number of bits selected for misc
+ voltage adj fuse definition. For MSMTITANIUM the tuple
+ list must contain 2 tuples for the 1-bit misc fuse.
+ Tuples in a list should be specified in ascending order
+ according to the misc fuse value assuming that the fuse
+ is treated like an unsigned integer.
+
+ The tuple list grouping must contain qcom,cpr-speed-bins
+ number of tuple lists in which case the lists are matched to
+ speed bins 1-to-1 or exactly 1 list which is used regardless
+ of the speed bin found on a given chip.
+
=======
Example
=======
@@ -422,6 +443,13 @@ apc_cpr: cpr4-ctrl@b018000 {
1689600000 1843200000 1958400000
2150400000 2208000000>;
+ qcom,cpr-misc-fuse-voltage-adjustment =
+ /* Speed bin 0; misc fuse 0..1 */
+ < 0 0 0 0
+ 0 0 0 0>,
+ < 0 0 30000 0
+ 0 0 0 0>;
+
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
diff --git a/drivers/regulator/cpr4-apss-regulator.c b/drivers/regulator/cpr4-apss-regulator.c
index c5b66718a7dd..5fd6d0ba1824 100644
--- a/drivers/regulator/cpr4-apss-regulator.c
+++ b/drivers/regulator/cpr4-apss-regulator.c
@@ -66,6 +66,7 @@ struct cpr4_msmtitanium_apss_fuses {
u64 cpr_fusing_rev;
u64 boost_cfg;
u64 boost_voltage;
+ u64 misc;
};
/*
@@ -155,6 +156,17 @@ static const struct cpr3_fuse_param msmtitanium_apss_boost_fuse_volt_param[] = {
{},
};
+static const struct cpr3_fuse_param msmtitanium_misc_fuse_volt_adj_param[] = {
+ {36, 54, 54},
+ {},
+};
+
+/*
+ * The number of possible values for misc fuse is
+ * 2^(#bits defined for misc fuse)
+ */
+#define MSMTITANIUM_MISC_FUSE_VAL_COUNT BIT(1)
+
/*
* Open loop voltage fuse reference voltages in microvolts for MSMTITANIUM
*/
@@ -231,6 +243,20 @@ static int cpr4_msmtitanium_apss_read_fuse_data(struct cpr3_regulator *vreg)
}
cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
+ rc = cpr3_read_fuse_param(base, msmtitanium_misc_fuse_volt_adj_param,
+ &fuse->misc);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read misc voltage adjustment fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+ cpr3_info(vreg, "CPR misc fuse value = %llu\n", fuse->misc);
+ if (fuse->misc >= MSMTITANIUM_MISC_FUSE_VAL_COUNT) {
+ cpr3_err(vreg, "CPR misc fuse value = %llu, should be < %lu\n",
+ fuse->misc, MSMTITANIUM_MISC_FUSE_VAL_COUNT);
+ return -EINVAL;
+ }
+
for (i = 0; i < MSMTITANIUM_APSS_FUSE_CORNERS; i++) {
rc = cpr3_read_fuse_param(base,
msmtitanium_apss_init_voltage_param[i],
@@ -325,6 +351,78 @@ static int cpr4_apss_parse_corner_data(struct cpr3_regulator *vreg)
}
/**
+ * cpr4_apss_parse_misc_fuse_voltage_adjustments() - fill an array from a
+ * portion of the voltage adjustments specified based on
+ * miscellaneous fuse bits.
+ * @vreg: Pointer to the CPR3 regulator
+ * @volt_adjust: Voltage adjustment output data array which must be
+ * of size vreg->corner_count
+ *
+ * cpr3_parse_common_corner_data() must be called for vreg before this function
+ * is called so that speed bin size elements are initialized.
+ *
+ * Two formats are supported for the device tree property:
+ * 1. Length == tuple_list_size * vreg->corner_count
+ * (reading begins at index 0)
+ * 2. Length == tuple_list_size * vreg->speed_bin_corner_sum
+ * (reading begins at index tuple_list_size * vreg->speed_bin_offset)
+ *
+ * Here, tuple_list_size is the number of possible values for misc fuse.
+ * All other property lengths are treated as errors.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_apss_parse_misc_fuse_voltage_adjustments(
+ struct cpr3_regulator *vreg, u32 *volt_adjust)
+{
+ struct device_node *node = vreg->of_node;
+ struct cpr4_msmtitanium_apss_fuses *fuse = vreg->platform_fuses;
+ int tuple_list_size = MSMTITANIUM_MISC_FUSE_VAL_COUNT;
+ int i, offset, rc, len = 0;
+ const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment";
+
+ if (!of_find_property(node, prop_name, &len)) {
+ cpr3_err(vreg, "property %s is missing\n", prop_name);
+ return -EINVAL;
+ }
+
+ if (len == tuple_list_size * vreg->corner_count * sizeof(u32)) {
+ offset = 0;
+ } else if (vreg->speed_bin_corner_sum > 0 &&
+ len == tuple_list_size * vreg->speed_bin_corner_sum
+ * sizeof(u32)) {
+ offset = tuple_list_size * vreg->speed_bin_offset
+ + fuse->misc * vreg->corner_count;
+ } else {
+ if (vreg->speed_bin_corner_sum > 0)
+ cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n",
+ prop_name, len,
+ tuple_list_size * vreg->corner_count
+ * sizeof(u32),
+ tuple_list_size * vreg->speed_bin_corner_sum
+ * sizeof(u32));
+ else
+ cpr3_err(vreg, "property %s has invalid length=%d, should be %zu\n",
+ prop_name, len,
+ tuple_list_size * vreg->corner_count
+ * sizeof(u32));
+ return -EINVAL;
+ }
+
+ for (i = 0; i < vreg->corner_count; i++) {
+ rc = of_property_read_u32_index(node, prop_name, offset + i,
+ &volt_adjust[i]);
+ if (rc) {
+ cpr3_err(vreg, "error reading property %s, rc=%d\n",
+ prop_name, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/**
* cpr4_msmtitanium_apss_calculate_open_loop_voltages() - calculate the open-loop
* voltage for each corner of a CPR3 regulator
* @vreg: Pointer to the CPR3 regulator
@@ -349,7 +447,7 @@ static int cpr4_msmtitanium_apss_calculate_open_loop_voltages(
int i, j, rc = 0;
bool allow_interpolation;
u64 freq_low, volt_low, freq_high, volt_high;
- int *fuse_volt;
+ int *fuse_volt, *misc_adj_volt;
int *fmax_corner;
fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt),
@@ -445,8 +543,34 @@ done:
if (rc)
cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n",
rc);
+
+ if (of_find_property(node,
+ "qcom,cpr-misc-fuse-voltage-adjustment",
+ NULL)) {
+ misc_adj_volt = kcalloc(vreg->corner_count,
+ sizeof(*misc_adj_volt), GFP_KERNEL);
+ if (!misc_adj_volt) {
+ rc = -ENOMEM;
+ goto _exit;
+ }
+
+ rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
+ misc_adj_volt);
+ if (rc) {
+ cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
+ rc);
+ kfree(misc_adj_volt);
+ goto _exit;
+ }
+
+ for (i = 0; i < vreg->corner_count; i++)
+ vreg->corner[i].open_loop_volt
+ += misc_adj_volt[i];
+ kfree(misc_adj_volt);
+ }
}
+_exit:
kfree(fuse_volt);
kfree(fmax_corner);
return rc;
@@ -525,6 +649,7 @@ static int cpr4_msmtitanium_apss_calculate_target_quotients(
int i, j, fuse_corner, quot_adjust;
int *fmax_corner;
int *volt_adjust, *volt_adjust_fuse, *ro_scale;
+ int *voltage_adj_misc;
/* Log fused quotient values for debugging purposes. */
cpr3_info(vreg, "fused LowSVS: quot[%2llu]=%4llu\n",
@@ -567,6 +692,30 @@ static int cpr4_msmtitanium_apss_calculate_target_quotients(
goto done;
}
+ if (of_find_property(vreg->of_node,
+ "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) {
+ voltage_adj_misc = kcalloc(vreg->corner_count,
+ sizeof(*voltage_adj_misc), GFP_KERNEL);
+ if (!voltage_adj_misc) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg,
+ voltage_adj_misc);
+ if (rc) {
+ cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n",
+ rc);
+ kfree(voltage_adj_misc);
+ goto done;
+ }
+
+ for (i = 0; i < vreg->corner_count; i++)
+ volt_adjust[i] += voltage_adj_misc[i];
+
+ kfree(voltage_adj_misc);
+ }
+
if (!allow_interpolation) {
/* Use fused target quotients for lower frequencies. */
return cpr4_msmtitanium_apss_set_no_interpolation_quotients(