Merge "regulator: rpm-smd: Add support for BOB on PMIC5"

This commit is contained in:
qctecmdr 2020-07-29 06:36:28 -07:00 committed by Gerrit - the friendly Code Review server
commit 53e29d51ae
2 changed files with 231 additions and 49 deletions

View File

@ -18,6 +18,7 @@
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/rpm-smd-regulator.h>
#include <linux/regulator/proxy-consumer.h>
#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
#include <soc/qcom/rpm-smd.h>
#include <linux/debugfs.h>
/* 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,
@ -1587,6 +1669,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.
@ -1600,7 +1747,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. */
@ -1665,6 +1812,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;
@ -1675,6 +1845,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

View File

@ -17,4 +17,10 @@
#define RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR 416
#define RPM_SMD_REGULATOR_LEVEL_BINNING 512
#define RPM_SMD_REGULATOR_MODE_PASS 0
#define RPM_SMD_REGULATOR_MODE_RET 1
#define RPM_SMD_REGULATOR_MODE_LPM 2
#define RPM_SMD_REGULATOR_MODE_AUTO 3
#define RPM_SMD_REGULATOR_MODE_HPM 4
#endif