From 62a1665784c487cecf56fb3f5efbc6d75db3825a Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 24 Jul 2020 18:03:49 +0530 Subject: [PATCH] regulator: rpm-smd: Add support for BOB on PMIC5 Add support to distinguish PMIC4 BOB from PMIC5 BOB using "qcom,regulator-hw-type" device tree property as the MODE_CTL settings of PMIC5 BOBs are different from PMIC4 BOBs. Change-Id: I5162e514487b255c33eb66e75a44a40fe92d50a6 Signed-off-by: Jishnu Prakash --- drivers/regulator/rpm-smd-regulator.c | 274 +++++++++++++++++++++----- 1 file changed, 225 insertions(+), 49 deletions(-) diff --git a/drivers/regulator/rpm-smd-regulator.c b/drivers/regulator/rpm-smd-regulator.c index 3eb6b59aefaf..376f98829669 100644 --- a/drivers/regulator/rpm-smd-regulator.c +++ b/drivers/regulator/rpm-smd-regulator.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include /* Debug Definitions */ @@ -47,11 +48,13 @@ enum rpm_regulator_type { RPM_REGULATOR_TYPE_MAX, }; -/* Supported PMIC regulator LDO types */ +/* Supported PMIC regulator LDO and BOB types */ enum rpm_regulator_hw_type { RPM_REGULATOR_HW_TYPE_UNKNOWN, RPM_REGULATOR_HW_TYPE_PMIC4_LDO, RPM_REGULATOR_HW_TYPE_PMIC5_LDO, + RPM_REGULATOR_HW_TYPE_PMIC4_BOB, + RPM_REGULATOR_HW_TYPE_PMIC5_BOB, RPM_REGULATOR_HW_TYPE_MAX, }; @@ -80,22 +83,18 @@ enum rpm_regulator_param_index { RPM_REGULATOR_PARAM_MAX, }; -enum rpm_regulator_smps_mode { - RPM_REGULATOR_SMPS_MODE_AUTO = 0, - RPM_REGULATOR_SMPS_MODE_IPEAK = 1, - RPM_REGULATOR_SMPS_MODE_PWM = 2, +enum rpm_regulator_bob_mode_pmic4 { + RPM_REGULATOR_PMIC4_BOB_MODE_PASS = 0, + RPM_REGULATOR_PMIC4_BOB_MODE_PFM = 1, + RPM_REGULATOR_PMIC4_BOB_MODE_AUTO = 2, + RPM_REGULATOR_PMIC4_BOB_MODE_PWM = 3, }; -enum rpm_regulator_ldo_mode { - RPM_REGULATOR_LDO_MODE_IPEAK = 0, - RPM_REGULATOR_LDO_MODE_HPM = 1, -}; - -enum rpm_regulator_bob_mode { - RPM_REGULATOR_BOB_MODE_PASS = 0, - RPM_REGULATOR_BOB_MODE_PFM = 1, - RPM_REGULATOR_BOB_MODE_AUTO = 2, - RPM_REGULATOR_BOB_MODE_PWM = 3, +enum rpm_regulator_bob_mode_pmic5 { + RPM_REGULATOR_PMIC5_BOB_MODE_PASS = 2, + RPM_REGULATOR_PMIC5_BOB_MODE_PFM = 4, + RPM_REGULATOR_PMIC5_BOB_MODE_AUTO = 6, + RPM_REGULATOR_PMIC5_BOB_MODE_PWM = 7, }; #define RPM_SET_CONFIG_ACTIVE BIT(0) @@ -161,6 +160,11 @@ struct rpm_vreg_request { u32 modified; }; +struct rpm_reg_mode_info { + u32 mode; + int min_load_ua; +}; + struct rpm_vreg { struct rpm_vreg_request aggr_req_active; struct rpm_vreg_request aggr_req_sleep; @@ -170,6 +174,8 @@ struct rpm_vreg { bool allow_atomic; int regulator_type; int hpm_min_load; + struct rpm_reg_mode_info *mode; + int mode_count; int enable_time; spinlock_t slock; struct mutex mlock; @@ -1041,31 +1047,60 @@ static int rpm_vreg_set_bob_mode(struct regulator_dev *rdev, unsigned int mode) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int rc; - u32 prev_mode; + u32 hw_mode, hw_type, prev_mode; rpm_vreg_lock(reg->rpm_vreg); prev_mode = reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]; + hw_type = reg->rpm_vreg->regulator_hw_type; - switch (mode) { - case REGULATOR_MODE_FAST: - RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PWM); - break; - case REGULATOR_MODE_NORMAL: - RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_AUTO); - break; - case REGULATOR_MODE_IDLE: - RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PFM); - break; - case REGULATOR_MODE_STANDBY: - RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PASS); - break; - default: - vreg_err(reg, "invalid mode: %u\n", mode); + if (hw_type == RPM_REGULATOR_HW_TYPE_PMIC4_BOB) { + switch (mode) { + case REGULATOR_MODE_FAST: + hw_mode = RPM_REGULATOR_PMIC4_BOB_MODE_PWM; + break; + case REGULATOR_MODE_NORMAL: + hw_mode = RPM_REGULATOR_PMIC4_BOB_MODE_AUTO; + break; + case REGULATOR_MODE_IDLE: + hw_mode = RPM_REGULATOR_PMIC4_BOB_MODE_PFM; + break; + case REGULATOR_MODE_STANDBY: + hw_mode = RPM_REGULATOR_PMIC4_BOB_MODE_PASS; + break; + default: + vreg_err(reg, "invalid mode: %u\n", mode); + rpm_vreg_unlock(reg->rpm_vreg); + return -EINVAL; + } + } else if (hw_type == RPM_REGULATOR_HW_TYPE_PMIC5_BOB) { + switch (mode) { + case REGULATOR_MODE_FAST: + hw_mode = RPM_REGULATOR_PMIC5_BOB_MODE_PWM; + break; + case REGULATOR_MODE_NORMAL: + hw_mode = RPM_REGULATOR_PMIC5_BOB_MODE_AUTO; + break; + case REGULATOR_MODE_IDLE: + hw_mode = RPM_REGULATOR_PMIC5_BOB_MODE_PFM; + break; + case REGULATOR_MODE_STANDBY: + hw_mode = RPM_REGULATOR_PMIC5_BOB_MODE_PASS; + break; + default: + vreg_err(reg, "invalid mode: %u\n", mode); + rpm_vreg_unlock(reg->rpm_vreg); + return -EINVAL; + } + } else { + vreg_err(reg, "unsupported bob hw type: %d\n", + reg->rpm_vreg->regulator_hw_type); rpm_vreg_unlock(reg->rpm_vreg); return -EINVAL; } + RPM_VREG_SET_PARAM(reg, MODE_BOB, hw_mode); + rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "set BoB mode failed, rc=%d\n", rc); @@ -1080,29 +1115,75 @@ static int rpm_vreg_set_bob_mode(struct regulator_dev *rdev, unsigned int mode) static unsigned int rpm_vreg_get_bob_mode(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); - unsigned int mode; + unsigned int mode = REGULATOR_MODE_NORMAL; + u32 hw_type = reg->rpm_vreg->regulator_hw_type; - switch (reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]) { - case RPM_REGULATOR_BOB_MODE_PWM: - mode = REGULATOR_MODE_FAST; - break; - case RPM_REGULATOR_BOB_MODE_AUTO: - mode = REGULATOR_MODE_NORMAL; - break; - case RPM_REGULATOR_BOB_MODE_PFM: - mode = REGULATOR_MODE_IDLE; - break; - case RPM_REGULATOR_BOB_MODE_PASS: - mode = REGULATOR_MODE_STANDBY; - break; - default: - vreg_err(reg, "BoB mode unknown\n"); - mode = REGULATOR_MODE_NORMAL; + if (hw_type == RPM_REGULATOR_HW_TYPE_PMIC4_BOB) { + switch (reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]) { + case RPM_REGULATOR_PMIC4_BOB_MODE_PWM: + mode = REGULATOR_MODE_FAST; + break; + case RPM_REGULATOR_PMIC4_BOB_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case RPM_REGULATOR_PMIC4_BOB_MODE_PFM: + mode = REGULATOR_MODE_IDLE; + break; + case RPM_REGULATOR_PMIC4_BOB_MODE_PASS: + mode = REGULATOR_MODE_STANDBY; + break; + default: + vreg_err(reg, "BoB mode unknown\n"); + } + } else if (hw_type == RPM_REGULATOR_HW_TYPE_PMIC4_BOB) { + switch (reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]) { + case RPM_REGULATOR_PMIC5_BOB_MODE_PWM: + mode = REGULATOR_MODE_FAST; + break; + case RPM_REGULATOR_PMIC5_BOB_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case RPM_REGULATOR_PMIC5_BOB_MODE_PFM: + mode = REGULATOR_MODE_IDLE; + break; + case RPM_REGULATOR_PMIC5_BOB_MODE_PASS: + mode = REGULATOR_MODE_STANDBY; + break; + default: + vreg_err(reg, "BoB mode unknown\n"); + } } return mode; } +#define RPM_SMD_REGULATOR_MAX_MODES 5 + +static const int bob_supported_modes[RPM_SMD_REGULATOR_MAX_MODES] = { + [RPM_SMD_REGULATOR_MODE_PASS] = REGULATOR_MODE_STANDBY, + [RPM_SMD_REGULATOR_MODE_RET] = REGULATOR_MODE_INVALID, + [RPM_SMD_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE, + [RPM_SMD_REGULATOR_MODE_AUTO] = REGULATOR_MODE_NORMAL, + [RPM_SMD_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST, +}; + +static int rpm_vreg_bob_set_load(struct regulator_dev *rdev, int load_ua) +{ + struct rpm_regulator *reg = rdev_get_drvdata(rdev); + int rc = 0, i; + unsigned int mode; + + for (i = reg->rpm_vreg->mode_count - 1; i > 0; i--) + if (reg->rpm_vreg->mode[i].min_load_ua <= load_ua) + break; + + mode = reg->rpm_vreg->mode[i].mode; + + rc = rpm_vreg_set_bob_mode(rdev, mode); + + return rc; +} + static int rpm_vreg_enable_time(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); @@ -1210,6 +1291,7 @@ static struct regulator_ops bob_ops = { .is_enabled = rpm_vreg_is_enabled, .set_voltage = rpm_vreg_set_voltage, .get_voltage = rpm_vreg_get_voltage, + .set_load = rpm_vreg_bob_set_load, .set_mode = rpm_vreg_set_bob_mode, .get_mode = rpm_vreg_get_bob_mode, .enable_time = rpm_vreg_enable_time, @@ -1582,6 +1664,71 @@ fail_free_reg: return rc; } +int init_thresholds(struct device_node *node, struct device *dev, + struct rpm_vreg *rpm_vreg, int len) +{ + int rc, i; + u32 *buf; + const char *prop = "qcom,supported-modes"; + + len /= sizeof(u32); + rpm_vreg->mode = devm_kcalloc(dev, len, + sizeof(*rpm_vreg->mode), GFP_KERNEL); + if (!rpm_vreg->mode) + return -ENOMEM; + rpm_vreg->mode_count = len; + + buf = kcalloc(len, sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = of_property_read_u32_array(node, prop, buf, len); + if (rc) { + pr_err("unable to read %s, rc=%d\n", + prop, rc); + return rc; + } + + for (i = 0; i < len; i++) { + if (buf[i] < RPM_SMD_REGULATOR_MODE_PASS || + buf[i] > RPM_SMD_REGULATOR_MODE_HPM) { + dev_err(dev, "element %d of %s = %u is invalid for BOB\n", + i, prop, buf[i]); + return -EINVAL; + } + + rpm_vreg->mode[i].mode = bob_supported_modes[buf[i]]; + + if (i > 0 && buf[i] <= buf[i - 1]) { + dev_err(dev, "%s elements are not in ascending order\n", + prop); + return -EINVAL; + } + } + + prop = "qcom,mode-threshold-currents"; + + rc = of_property_read_u32_array(node, prop, buf, len); + if (rc) { + dev_err(dev, "unable to read %s, rc=%d\n", + prop, rc); + return rc; + } + + for (i = 0; i < len; i++) { + rpm_vreg->mode[i].min_load_ua = buf[i]; + + if (i > 0 && rpm_vreg->mode[i].min_load_ua + <= rpm_vreg->mode[i - 1].min_load_ua) { + dev_err(dev, "%s elements are not in ascending order\n", + prop); + return -EINVAL; + } + } + + return 0; +} + /* * This probe is called for parent rpm-regulator devices which have * properties which are required to identify a given RPM resource. @@ -1595,7 +1742,7 @@ static int rpm_vreg_resource_probe(struct platform_device *pdev) const char *prop; int val = 0; u32 resource_type; - int rc; + int rc, len; /* Create new rpm_vreg entry. */ @@ -1660,6 +1807,29 @@ static int rpm_vreg_resource_probe(struct platform_device *pdev) } } + if (rpm_vreg->regulator_type == RPM_REGULATOR_TYPE_BOB) { + prop = "qcom,regulator-hw-type"; + rpm_vreg->regulator_hw_type = RPM_REGULATOR_HW_TYPE_UNKNOWN; + rc = of_property_read_string(node, prop, &type); + if (rc) { + dev_err(dev, "%s is missing in DT node rc=%d\n", + prop, rc); + goto fail_free_vreg; + } + + if (!strcmp(type, "pmic4-bob")) { + rpm_vreg->regulator_hw_type + = RPM_REGULATOR_HW_TYPE_PMIC4_BOB; + } else if (!strcmp(type, "pmic5-bob")) { + rpm_vreg->regulator_hw_type + = RPM_REGULATOR_HW_TYPE_PMIC5_BOB; + } else { + dev_err(dev, "unknown %s = %s\n", + prop, type); + goto fail_free_vreg; + } + } + /* Optional device tree properties: */ of_property_read_u32(node, "qcom,allow-atomic", &val); rpm_vreg->allow_atomic = !!val; @@ -1670,6 +1840,12 @@ static int rpm_vreg_resource_probe(struct platform_device *pdev) rpm_vreg->always_wait_for_ack = of_property_read_bool(node, "qcom,always-wait-for-ack"); + if (of_find_property(node, "qcom,supported-modes", &len)) { + rc = init_thresholds(node, dev, rpm_vreg, len); + if (rc < 0) + goto fail_free_vreg; + } + rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE, resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX); if (rpm_vreg->handle_active == NULL