summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-06-08 05:13:49 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-06-08 05:13:48 -0700
commit019955f7cdb8122aa8aac0f49d66ffefcac0d6a3 (patch)
tree49659a1d27a224fce118ccf890c9c025b87a3ab4
parent2bf7a89b5a885316f1c697e982f8f6be03e46b8b (diff)
parent26efcc23eb8274e3f2bef3e28f630b3710a194a8 (diff)
Merge "regulator: spm: check min/max voltages against HW configuration"
-rw-r--r--drivers/regulator/spm-regulator.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/regulator/spm-regulator.c b/drivers/regulator/spm-regulator.c
index be59947ba6f2..d469463a0b00 100644
--- a/drivers/regulator/spm-regulator.c
+++ b/drivers/regulator/spm-regulator.c
@@ -95,6 +95,7 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
#define QPNP_SMPS_REG_VOLTAGE_SETPOINT 0x41
#define QPNP_SMPS_REG_MODE 0x45
#define QPNP_SMPS_REG_STEP_CTRL 0x61
+#define QPNP_SMPS_REG_UL_LL_CTRL 0x68
/* FTS426 voltage control registers */
#define QPNP_FTS426_REG_VOLTAGE_LB 0x40
@@ -102,6 +103,22 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
#define QPNP_FTS426_REG_VOLTAGE_VALID_LB 0x42
#define QPNP_FTS426_REG_VOLTAGE_VALID_UB 0x43
+/* HF voltage limit registers */
+#define QPNP_HF_REG_VOLTAGE_ULS 0x69
+#define QPNP_HF_REG_VOLTAGE_LLS 0x6B
+
+/* FTS voltage limit registers */
+#define QPNP_FTS_REG_VOLTAGE_ULS_VALID 0x6A
+#define QPNP_FTS_REG_VOLTAGE_LLS_VALID 0x6C
+
+/* FTS426 voltage limit registers */
+#define QPNP_FTS426_REG_VOLTAGE_ULS_LB 0x68
+#define QPNP_FTS426_REG_VOLTAGE_ULS_UB 0x69
+
+/* Common regulator UL & LL limits control register layout */
+#define QPNP_COMMON_UL_EN_MASK 0x80
+#define QPNP_COMMON_LL_EN_MASK 0x40
+
#define QPNP_SMPS_MODE_PWM 0x80
#define QPNP_SMPS_MODE_AUTO 0x40
#define QPNP_FTS426_MODE_PWM 0x07
@@ -924,6 +941,88 @@ static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
return rc;
}
+static int qpnp_smps_check_constraints(struct spm_vreg *vreg,
+ struct regulator_init_data *init_data)
+{
+ int rc = 0, limit_min_uV, limit_max_uV;
+ u16 ul_reg, ll_reg;
+ u8 reg[2];
+
+ limit_min_uV = 0;
+ limit_max_uV = INT_MAX;
+
+ ul_reg = QPNP_FTS_REG_VOLTAGE_ULS_VALID;
+ ll_reg = QPNP_FTS_REG_VOLTAGE_LLS_VALID;
+
+ switch (vreg->regulator_type) {
+ case QPNP_TYPE_HF:
+ ul_reg = QPNP_HF_REG_VOLTAGE_ULS;
+ ll_reg = QPNP_HF_REG_VOLTAGE_LLS;
+ case QPNP_TYPE_FTS2:
+ case QPNP_TYPE_FTS2p5:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_SMPS_REG_UL_LL_CTRL, reg, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: UL_LL register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg[0] & QPNP_COMMON_UL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ul_reg, &reg[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: ULS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ if (reg[0] & QPNP_COMMON_LL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ll_reg, &reg[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: LLS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_min_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ break;
+ case QPNP_TYPE_FTS426:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_FTS426_REG_VOLTAGE_ULS_LB,
+ reg, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage limit registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg,
+ ((unsigned)reg[1] << 8) | reg[0]);
+ break;
+ case QPNP_TYPE_ULT_HF:
+ /* no HW voltage limit configuration */
+ break;
+ }
+
+ if (init_data->constraints.min_uV < limit_min_uV
+ || init_data->constraints.max_uV > limit_max_uV) {
+ dev_err(&vreg->pdev->dev, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n",
+ init_data->constraints.min_uV,
+ init_data->constraints.max_uV, limit_min_uV,
+ limit_max_uV);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
static bool spm_regulator_using_range0(struct spm_vreg *vreg)
{
return vreg->range == &fts2_range0 || vreg->range == &fts2p5_range0
@@ -1105,6 +1204,13 @@ static int spm_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
+ rc = qpnp_smps_check_constraints(vreg, init_data);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: regulator constraints check failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
vreg->rdesc.name = init_data->constraints.name;
vreg->rdesc.type = REGULATOR_VOLTAGE;
vreg->rdesc.owner = THIS_MODULE;