summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-01-30 07:04:56 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-01-30 07:04:56 -0800
commit49d53355928478930d4aeae0ba7bddef9520be8d (patch)
tree0ff36c046563abfba5558b08fa09c22043c7909a /drivers
parent510fc66816808fc4381ef68f0dcf2bf38a15347d (diff)
parentfcc7c6c794e675cd559502ec07281a83890d07d3 (diff)
Merge "regulator: cpr4: Support MMSS closed-loop voltage adjustments"
Diffstat (limited to 'drivers')
-rw-r--r--drivers/regulator/cpr3-mmss-regulator.c257
-rw-r--r--drivers/regulator/cpr3-regulator.h10
-rw-r--r--drivers/regulator/cpr3-util.c256
-rw-r--r--drivers/regulator/cpr4-mmss-ldo-regulator.c48
4 files changed, 324 insertions, 247 deletions
diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c
index 1ac9791b467b..1070a34073e4 100644
--- a/drivers/regulator/cpr3-mmss-regulator.c
+++ b/drivers/regulator/cpr3-mmss-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, 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
@@ -453,45 +453,24 @@ done:
}
/**
- * cpr3_msm8996_mmss_apply_closed_loop_offset_voltages() - modify the
- * closed-loop voltage adjustments by the amounts that are needed
- * for this fuse combo
+ * cpr3_msm8996_mmss_adjust_target_quotients() - adjust the target quotients
+ * for each corner according to device tree values and fuse values
* @vreg: Pointer to the CPR3 regulator
- * @volt_adjust: Array of closed-loop voltage adjustment values of length
- * vreg->corner_count which is further adjusted based upon
- * offset voltage fuse values.
*
* Return: 0 on success, errno on failure
*/
-static int cpr3_msm8996_mmss_apply_closed_loop_offset_voltages(
- struct cpr3_regulator *vreg, int *volt_adjust)
+static int cpr3_msm8996_mmss_adjust_target_quotients(
+ struct cpr3_regulator *vreg)
{
struct cpr3_msm8996_mmss_fuses *fuse = vreg->platform_fuses;
const struct cpr3_fuse_param (*offset_param)[2];
- u32 *corner_map;
int *volt_offset;
- int rc = 0, i, fuse_len;
-
- if (!of_find_property(vreg->of_node,
- "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) {
- /* No closed-loop offset required. */
- return 0;
- }
+ int i, fuse_len, rc = 0;
- corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map),
- GFP_KERNEL);
volt_offset = kcalloc(vreg->fuse_corner_count, sizeof(*volt_offset),
GFP_KERNEL);
- if (!corner_map || !volt_offset) {
- rc = -ENOMEM;
- goto done;
- }
-
- rc = cpr3_parse_corner_array_property(vreg,
- "qcom,cpr-fused-closed-loop-voltage-adjustment-map",
- 1, corner_map);
- if (rc)
- goto done;
+ if (!volt_offset)
+ return -ENOMEM;
offset_param = cpr3_ctrl_is_msm8998(vreg->thread->ctrl)
? msm8998_mmss_offset_voltage_param
@@ -507,223 +486,11 @@ static int cpr3_msm8996_mmss_apply_closed_loop_offset_voltages(
i, volt_offset[i]);
}
- for (i = 0; i < vreg->corner_count; i++) {
- if (corner_map[i] == 0) {
- continue;
- } else if (corner_map[i] > vreg->fuse_corner_count) {
- cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n",
- i, corner_map[i]);
- rc = -EINVAL;
- goto done;
- }
-
- volt_adjust[i] += volt_offset[corner_map[i] - 1];
- }
+ rc = cpr3_adjust_target_quotients(vreg, volt_offset);
+ if (rc)
+ cpr3_err(vreg, "adjust target quotients failed, rc=%d\n", rc);
-done:
- kfree(corner_map);
kfree(volt_offset);
-
- return rc;
-}
-
-/**
- * cpr3_mmss_enforce_inc_quotient_monotonicity() - Ensure that target quotients
- * increase monotonically from lower to higher corners
- * @vreg: Pointer to the CPR3 regulator
- *
- * Return: 0 on success, errno on failure
- */
-static void cpr3_mmss_enforce_inc_quotient_monotonicity(
- struct cpr3_regulator *vreg)
-{
- int i, j;
-
- for (i = 1; i < vreg->corner_count; i++) {
- for (j = 0; j < CPR3_RO_COUNT; j++) {
- if (vreg->corner[i].target_quot[j]
- && vreg->corner[i].target_quot[j]
- < vreg->corner[i - 1].target_quot[j]) {
- cpr3_debug(vreg, "corner %d RO%u target quot=%u < 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 - 1, j,
- vreg->corner[i - 1].target_quot[j],
- i, j,
- vreg->corner[i - 1].target_quot[j]);
- vreg->corner[i].target_quot[j]
- = vreg->corner[i - 1].target_quot[j];
- }
- }
- }
-}
-
-/**
- * cpr3_mmss_enforce_dec_quotient_monotonicity() - Ensure that target quotients
- * decrease monotonically from higher to lower corners
- * @vreg: Pointer to the CPR3 regulator
- *
- * Return: 0 on success, errno on failure
- */
-static void cpr3_mmss_enforce_dec_quotient_monotonicity(
- struct cpr3_regulator *vreg)
-{
- int i, j;
-
- for (i = vreg->corner_count - 2; i >= 0; i--) {
- for (j = 0; j < CPR3_RO_COUNT; j++) {
- if (vreg->corner[i + 1].target_quot[j]
- && vreg->corner[i].target_quot[j]
- > vreg->corner[i + 1].target_quot[j]) {
- cpr3_debug(vreg, "corner %d RO%u target quot=%u > 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 + 1, j,
- vreg->corner[i + 1].target_quot[j],
- i, j,
- vreg->corner[i + 1].target_quot[j]);
- vreg->corner[i].target_quot[j]
- = vreg->corner[i + 1].target_quot[j];
- }
- }
- }
-}
-
-/**
- * _cpr3_mmss_adjust_target_quotients() - adjust the target quotients for each
- * corner of the regulator according to input adjustment and
- * scaling arrays
- * @vreg: Pointer to the CPR3 regulator
- * @volt_adjust: Pointer to an array of closed-loop voltage adjustments
- * with units of microvolts. The array must have
- * vreg->corner_count number of elements.
- * @ro_scale: Pointer to a flattened 2D array of RO scaling factors.
- * The array must have an inner dimension of CPR3_RO_COUNT
- * and an outer dimension of vreg->corner_count
- * @label: Null terminated string providing a label for the type
- * of adjustment.
- *
- * Return: true if any corners received a positive voltage adjustment (> 0),
- * else false
- */
-static bool _cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg,
- const int *volt_adjust, const int *ro_scale, const char *label)
-{
- int i, j, quot_adjust;
- bool is_increasing = false;
- u32 prev_quot;
-
- for (i = 0; i < vreg->corner_count; i++) {
- for (j = 0; j < CPR3_RO_COUNT; j++) {
- if (vreg->corner[i].target_quot[j]) {
- quot_adjust = cpr3_quot_adjustment(
- ro_scale[i * CPR3_RO_COUNT + j],
- volt_adjust[i]);
- if (quot_adjust) {
- prev_quot = vreg->corner[i].
- target_quot[j];
- vreg->corner[i].target_quot[j]
- += quot_adjust;
- cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n",
- i, j, label, prev_quot,
- vreg->corner[i].target_quot[j],
- volt_adjust[i]);
- }
- }
- }
- if (volt_adjust[i] > 0)
- is_increasing = true;
- }
-
- return is_increasing;
-}
-
-/**
- * cpr3_mmss_adjust_target_quotients() - adjust the target quotients for each
- * corner according to device tree values and fuse values
- * @vreg: Pointer to the CPR3 regulator
- *
- * Return: 0 on success, errno on failure
- */
-static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg)
-{
- int i, rc;
- int *volt_adjust, *ro_scale;
- bool explicit_adjustment, fused_adjustment, is_increasing;
-
- explicit_adjustment = of_find_property(vreg->of_node,
- "qcom,cpr-closed-loop-voltage-adjustment", NULL);
- fused_adjustment = of_find_property(vreg->of_node,
- "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL);
-
- if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
- /* No adjustment required. */
- return 0;
- } else if (!of_find_property(vreg->of_node,
- "qcom,cpr-ro-scaling-factor", NULL)) {
- cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
- return -EINVAL;
- }
-
- volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
- GFP_KERNEL);
- ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT,
- sizeof(*ro_scale), GFP_KERNEL);
- if (!volt_adjust || !ro_scale) {
- rc = -ENOMEM;
- goto done;
- }
-
- rc = cpr3_parse_corner_array_property(vreg,
- "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale);
- if (rc) {
- cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
- rc);
- 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_corner_array_property(vreg,
- "qcom,cpr-closed-loop-voltage-adjustment",
- 1, volt_adjust);
- if (rc) {
- cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
- rc);
- goto done;
- }
-
- _cpr3_mmss_adjust_target_quotients(vreg, volt_adjust, ro_scale,
- "from DT");
- cpr3_mmss_enforce_inc_quotient_monotonicity(vreg);
- }
-
- if (fused_adjustment) {
- memset(volt_adjust, 0,
- sizeof(*volt_adjust) * vreg->corner_count);
-
- rc = cpr3_msm8996_mmss_apply_closed_loop_offset_voltages(vreg,
- volt_adjust);
- if (rc) {
- cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n",
- rc);
- goto done;
- }
-
- is_increasing = _cpr3_mmss_adjust_target_quotients(vreg,
- volt_adjust, ro_scale, "from fuse");
- if (is_increasing)
- cpr3_mmss_enforce_inc_quotient_monotonicity(vreg);
- else
- cpr3_mmss_enforce_dec_quotient_monotonicity(vreg);
- }
-
-done:
- kfree(volt_adjust);
- kfree(ro_scale);
return rc;
}
@@ -1112,7 +879,7 @@ static int cpr3_mmss_init_thread(struct cpr3_thread *thread)
return rc;
}
- rc = cpr3_mmss_adjust_target_quotients(vreg);
+ rc = cpr3_msm8996_mmss_adjust_target_quotients(vreg);
if (rc) {
cpr3_err(vreg, "unable to adjust target quotients, rc=%d\n",
rc);
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 2e997b526b90..f0230b8ae2e5 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, 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
@@ -904,6 +904,8 @@ int cpr3_apm_init(struct cpr3_controller *ctrl);
int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg);
void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg);
+int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
+ int *fuse_volt_adjust);
#else
@@ -1084,6 +1086,12 @@ static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
{
}
+static inline int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
+ int *fuse_volt_adjust)
+{
+ return 0;
+}
+
#endif /* CONFIG_REGULATOR_CPR3 */
#endif /* __REGULATOR_CPR_REGULATOR_H__ */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 7f712d4f6ee4..0a1a1c56bd16 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -2147,3 +2147,259 @@ void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
corner->ceiling_volt, corner->open_loop_volt);
}
}
+
+/**
+ * cpr3_apply_closed_loop_offset_voltages() - modify the closed-loop voltage
+ * adjustments by the amounts that are needed for this
+ * fuse combo
+ * @vreg: Pointer to the CPR3 regulator
+ * @volt_adjust: Array of closed-loop voltage adjustment values of length
+ * vreg->corner_count which is further adjusted based upon
+ * offset voltage fuse values.
+ * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
+ * vreg->fuse_corner_count.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr3_apply_closed_loop_offset_voltages(struct cpr3_regulator *vreg,
+ int *volt_adjust, int *fuse_volt_adjust)
+{
+ u32 *corner_map;
+ int rc = 0, i;
+
+ if (!of_find_property(vreg->of_node,
+ "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL)) {
+ /* No closed-loop offset required. */
+ return 0;
+ }
+
+ corner_map = kcalloc(vreg->corner_count, sizeof(*corner_map),
+ GFP_KERNEL);
+ if (!corner_map)
+ return -ENOMEM;
+
+ rc = cpr3_parse_corner_array_property(vreg,
+ "qcom,cpr-fused-closed-loop-voltage-adjustment-map",
+ 1, corner_map);
+ if (rc)
+ goto done;
+
+ for (i = 0; i < vreg->corner_count; i++) {
+ if (corner_map[i] == 0) {
+ continue;
+ } else if (corner_map[i] > vreg->fuse_corner_count) {
+ cpr3_err(vreg, "corner %d mapped to invalid fuse corner: %u\n",
+ i, corner_map[i]);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ volt_adjust[i] += fuse_volt_adjust[corner_map[i] - 1];
+ }
+
+done:
+ kfree(corner_map);
+ return rc;
+}
+
+/**
+ * cpr3_enforce_inc_quotient_monotonicity() - Ensure that target quotients
+ * increase monotonically from lower to higher corners
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * Return: 0 on success, errno on failure
+ */
+static void cpr3_enforce_inc_quotient_monotonicity(struct cpr3_regulator *vreg)
+{
+ int i, j;
+
+ for (i = 1; i < vreg->corner_count; i++) {
+ for (j = 0; j < CPR3_RO_COUNT; j++) {
+ if (vreg->corner[i].target_quot[j]
+ && vreg->corner[i].target_quot[j]
+ < vreg->corner[i - 1].target_quot[j]) {
+ cpr3_debug(vreg, "corner %d RO%u target quot=%u < 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 - 1, j,
+ vreg->corner[i - 1].target_quot[j],
+ i, j,
+ vreg->corner[i - 1].target_quot[j]);
+ vreg->corner[i].target_quot[j]
+ = vreg->corner[i - 1].target_quot[j];
+ }
+ }
+ }
+}
+
+/**
+ * cpr3_enforce_dec_quotient_monotonicity() - Ensure that target quotients
+ * decrease monotonically from higher to lower corners
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * Return: 0 on success, errno on failure
+ */
+static void cpr3_enforce_dec_quotient_monotonicity(struct cpr3_regulator *vreg)
+{
+ int i, j;
+
+ for (i = vreg->corner_count - 2; i >= 0; i--) {
+ for (j = 0; j < CPR3_RO_COUNT; j++) {
+ if (vreg->corner[i + 1].target_quot[j]
+ && vreg->corner[i].target_quot[j]
+ > vreg->corner[i + 1].target_quot[j]) {
+ cpr3_debug(vreg, "corner %d RO%u target quot=%u > 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 + 1, j,
+ vreg->corner[i + 1].target_quot[j],
+ i, j,
+ vreg->corner[i + 1].target_quot[j]);
+ vreg->corner[i].target_quot[j]
+ = vreg->corner[i + 1].target_quot[j];
+ }
+ }
+ }
+}
+
+/**
+ * _cpr3_adjust_target_quotients() - adjust the target quotients for each
+ * corner of the regulator according to input adjustment and
+ * scaling arrays
+ * @vreg: Pointer to the CPR3 regulator
+ * @volt_adjust: Pointer to an array of closed-loop voltage adjustments
+ * with units of microvolts. The array must have
+ * vreg->corner_count number of elements.
+ * @ro_scale: Pointer to a flattened 2D array of RO scaling factors.
+ * The array must have an inner dimension of CPR3_RO_COUNT
+ * and an outer dimension of vreg->corner_count
+ * @label: Null terminated string providing a label for the type
+ * of adjustment.
+ *
+ * Return: true if any corners received a positive voltage adjustment (> 0),
+ * else false
+ */
+static bool _cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
+ const int *volt_adjust, const int *ro_scale, const char *label)
+{
+ int i, j, quot_adjust;
+ bool is_increasing = false;
+ u32 prev_quot;
+
+ for (i = 0; i < vreg->corner_count; i++) {
+ for (j = 0; j < CPR3_RO_COUNT; j++) {
+ if (vreg->corner[i].target_quot[j]) {
+ quot_adjust = cpr3_quot_adjustment(
+ ro_scale[i * CPR3_RO_COUNT + j],
+ volt_adjust[i]);
+ if (quot_adjust) {
+ prev_quot = vreg->corner[i].
+ target_quot[j];
+ vreg->corner[i].target_quot[j]
+ += quot_adjust;
+ cpr3_debug(vreg, "adjusted corner %d RO%d target quot %s: %u --> %u (%d uV)\n",
+ i, j, label, prev_quot,
+ vreg->corner[i].target_quot[j],
+ volt_adjust[i]);
+ }
+ }
+ }
+ if (volt_adjust[i] > 0)
+ is_increasing = true;
+ }
+
+ return is_increasing;
+}
+
+/**
+ * cpr3_adjust_target_quotients() - adjust the target quotients for each
+ * corner according to device tree values and fuse values
+ * @vreg: Pointer to the CPR3 regulator
+ * @fuse_volt_adjust: Fused closed-loop voltage adjustment values of length
+ * vreg->fuse_corner_count. This parameter could be null
+ * pointer when no fused adjustments are needed.
+ *
+ * Return: 0 on success, errno on failure
+ */
+int cpr3_adjust_target_quotients(struct cpr3_regulator *vreg,
+ int *fuse_volt_adjust)
+{
+ int i, rc;
+ int *volt_adjust, *ro_scale;
+ bool explicit_adjustment, fused_adjustment, is_increasing;
+
+ explicit_adjustment = of_find_property(vreg->of_node,
+ "qcom,cpr-closed-loop-voltage-adjustment", NULL);
+ fused_adjustment = of_find_property(vreg->of_node,
+ "qcom,cpr-fused-closed-loop-voltage-adjustment-map", NULL);
+
+ if (!explicit_adjustment && !fused_adjustment && !vreg->aging_allowed) {
+ /* No adjustment required. */
+ return 0;
+ } else if (!of_find_property(vreg->of_node,
+ "qcom,cpr-ro-scaling-factor", NULL)) {
+ cpr3_err(vreg, "qcom,cpr-ro-scaling-factor is required for closed-loop voltage adjustment, but is missing\n");
+ return -EINVAL;
+ }
+
+ volt_adjust = kcalloc(vreg->corner_count, sizeof(*volt_adjust),
+ GFP_KERNEL);
+ ro_scale = kcalloc(vreg->corner_count * CPR3_RO_COUNT,
+ sizeof(*ro_scale), GFP_KERNEL);
+ if (!volt_adjust || !ro_scale) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ rc = cpr3_parse_corner_array_property(vreg,
+ "qcom,cpr-ro-scaling-factor", CPR3_RO_COUNT, ro_scale);
+ if (rc) {
+ cpr3_err(vreg, "could not load RO scaling factors, rc=%d\n",
+ rc);
+ 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_corner_array_property(vreg,
+ "qcom,cpr-closed-loop-voltage-adjustment",
+ 1, volt_adjust);
+ if (rc) {
+ cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n",
+ rc);
+ goto done;
+ }
+
+ _cpr3_adjust_target_quotients(vreg, volt_adjust, ro_scale,
+ "from DT");
+ cpr3_enforce_inc_quotient_monotonicity(vreg);
+ }
+
+ if (fused_adjustment && fuse_volt_adjust) {
+ memset(volt_adjust, 0,
+ sizeof(*volt_adjust) * vreg->corner_count);
+
+ rc = cpr3_apply_closed_loop_offset_voltages(vreg, volt_adjust,
+ fuse_volt_adjust);
+ if (rc) {
+ cpr3_err(vreg, "could not apply fused closed-loop voltage reductions, rc=%d\n",
+ rc);
+ goto done;
+ }
+
+ is_increasing = _cpr3_adjust_target_quotients(vreg, volt_adjust,
+ ro_scale, "from fuse");
+ if (is_increasing)
+ cpr3_enforce_inc_quotient_monotonicity(vreg);
+ else
+ cpr3_enforce_dec_quotient_monotonicity(vreg);
+ }
+
+done:
+ kfree(volt_adjust);
+ kfree(ro_scale);
+ return rc;
+}
diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c
index 2843f71745fc..f8e3ea40ddac 100644
--- a/drivers/regulator/cpr4-mmss-ldo-regulator.c
+++ b/drivers/regulator/cpr4-mmss-ldo-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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
@@ -417,6 +417,45 @@ done:
}
/**
+ * cpr4_sdm660_mmss_adjust_target_quotients() - adjust the target quotients for
+ * each corner according to device tree values and fuse values
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cpr4_sdm660_mmss_adjust_target_quotients(struct cpr3_regulator *vreg)
+{
+ struct cpr4_sdm660_mmss_fuses *fuse = vreg->platform_fuses;
+ const struct cpr3_fuse_param (*offset_param)[2];
+ int *volt_offset;
+ int i, fuse_len, rc = 0;
+
+ volt_offset = kcalloc(vreg->fuse_corner_count, sizeof(*volt_offset),
+ GFP_KERNEL);
+ if (!volt_offset)
+ return -ENOMEM;
+
+ offset_param = sdm660_mmss_offset_voltage_param;
+ for (i = 0; i < vreg->fuse_corner_count; i++) {
+ fuse_len = offset_param[i][0].bit_end + 1
+ - offset_param[i][0].bit_start;
+ volt_offset[i] = cpr3_convert_open_loop_voltage_fuse(
+ 0, SDM660_MMSS_OFFSET_FUSE_STEP_VOLT,
+ fuse->offset_voltage[i], fuse_len);
+ if (volt_offset[i])
+ cpr3_info(vreg, "fuse_corner[%d] offset=%7d uV\n",
+ i, volt_offset[i]);
+ }
+
+ rc = cpr3_adjust_target_quotients(vreg, volt_offset);
+ if (rc)
+ cpr3_err(vreg, "adjust target quotients failed, rc=%d\n", rc);
+
+ kfree(volt_offset);
+ return rc;
+}
+
+/**
* cpr4_mmss_print_settings() - print out MMSS CPR configuration settings into
* the kernel log for debugging purposes
* @vreg: Pointer to the CPR3 regulator
@@ -489,6 +528,13 @@ static int cpr4_mmss_init_thread(struct cpr3_thread *thread)
return rc;
}
+ rc = cpr4_sdm660_mmss_adjust_target_quotients(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to adjust target quotients, rc=%d\n",
+ rc);
+ return rc;
+ }
+
rc = cpr4_sdm660_mmss_calculate_open_loop_voltages(vreg);
if (rc) {
cpr3_err(vreg, "unable to calculate open-loop voltages, rc=%d\n",