mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
msm: rpm-regulator-smd: Add support for voltage corner resource parameter
Add support in the rpm-regulator-smd driver for the "corn" voltage corner parameter. It can be used with some regulators in order to specify voltage performance corners instead of discrete voltages. Initial support is provided for MSM8974 SMPS 2 (VDD_Dig). Change-Id: Icac67a1e5594d0aa54f3f6bd8aa8ac1edacc36d9 Signed-off-by: David Collins <collinsd@codeaurora.org>
This commit is contained in:
parent
97ab0481b2
commit
c395e1b293
3 changed files with 131 additions and 1 deletions
Documentation/devicetree/bindings/arm/msm
arch/arm/mach-msm
|
@ -54,6 +54,14 @@ Optional properties:
|
|||
- parent-supply: phandle to the parent supply/regulator node
|
||||
- qcom,system-load: Load in uA present on regulator that is not
|
||||
captured by any consumer request
|
||||
- qcom,use-voltage-corner: Flag that signifies if regulator_set_voltage
|
||||
calls should modify the corner parameter instead
|
||||
of the voltage parameter. When used, voltages
|
||||
specified inside of the regulator framework
|
||||
represent corners that have been incremented by
|
||||
1. This value shift is necessary to work around
|
||||
limitations in the regulator framework which
|
||||
treat 0 uV as an error.
|
||||
The following properties specify initial values for parameters to be sent to the
|
||||
RPM in regulator requests.
|
||||
- qcom,init-enable: 0 = regulator disabled
|
||||
|
@ -120,6 +128,24 @@ RPM in regulator requests.
|
|||
2 = GPS
|
||||
4 = WLAN
|
||||
8 = WAN
|
||||
- qcom,init-voltage-corner: Performance corner to use in order to determine
|
||||
voltage set point. This value corresponds to
|
||||
the actual value that will be sent and is not
|
||||
incremented by 1 like the values used inside of
|
||||
the regulator framework. The meaning of corner
|
||||
values is set by the RPM. It is possible that
|
||||
different regulators on a given platform or
|
||||
similar regulators on different platforms will
|
||||
utilize different corner values. These are
|
||||
corner values supported on MSM8974 for PMIC
|
||||
PM8841 SMPS 2 (VDD_Dig); nominal voltages for
|
||||
these corners are also shown:
|
||||
0 = Retention (0.5000 V)
|
||||
1 = SVS Krait (0.7250 V)
|
||||
2 = SVS SOC (0.8125 V)
|
||||
3 = Normal (0.9000 V)
|
||||
4 = Turbo (0.9875 V)
|
||||
5 = Super Turbo (1.0500 V)
|
||||
|
||||
All properties specified within the core regulator framework can also be used in
|
||||
second level nodes. These bindings can be found in:
|
||||
|
@ -150,4 +176,13 @@ rpm-regulator-smpb1 {
|
|||
regulator-max-microvolt = <1150000>;
|
||||
compatible = "qcom,rpm-regulator-smd";
|
||||
};
|
||||
pm8841_s1_corner: regulator-s1-corner {
|
||||
regulator-name = "8841_s1_corner";
|
||||
qcom,set = <3>;
|
||||
regulator-min-microvolt = <1>;
|
||||
regulator-max-microvolt = <6>;
|
||||
qcom,init-voltage-corner = <3>;
|
||||
qcom,use-voltage-corner;
|
||||
compatible = "qcom,rpm-regulator-smd";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -17,6 +17,26 @@
|
|||
|
||||
struct rpm_regulator;
|
||||
|
||||
/**
|
||||
* enum rpm_regulator_voltage_corner - possible voltage corner values
|
||||
*
|
||||
* These should be used in regulator_set_voltage() and
|
||||
* rpm_regulator_set_voltage() calls for corner type regulators as if they had
|
||||
* units of uV.
|
||||
*
|
||||
* Note, the meaning of corner values is set by the RPM. It is possible that
|
||||
* future platforms will utilize different corner values. The values specified
|
||||
* in this enum correspond to MSM8974 for PMIC PM8841 SMPS 2 (VDD_Dig).
|
||||
*/
|
||||
enum rpm_regulator_voltage_corner {
|
||||
RPM_REGULATOR_CORNER_RETENTION = 1,
|
||||
RPM_REGULATOR_CORNER_SVS_KRAIT,
|
||||
RPM_REGULATOR_CORNER_SVS_SOC,
|
||||
RPM_REGULATOR_CORNER_NORMAL,
|
||||
RPM_REGULATOR_CORNER_TURBO,
|
||||
RPM_REGULATOR_CORNER_SUPER_TURBO,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MSM_RPM_REGULATOR_SMD) || defined(CONFIG_MSM_RPM_REGULATOR)
|
||||
|
||||
struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply);
|
||||
|
|
|
@ -67,6 +67,7 @@ enum rpm_regulator_param_index {
|
|||
RPM_REGULATOR_PARAM_HEAD_ROOM,
|
||||
RPM_REGULATOR_PARAM_QUIET_MODE,
|
||||
RPM_REGULATOR_PARAM_FREQ_REASON,
|
||||
RPM_REGULATOR_PARAM_CORNER,
|
||||
RPM_REGULATOR_PARAM_MAX,
|
||||
};
|
||||
|
||||
|
@ -110,6 +111,7 @@ static struct rpm_regulator_param params[RPM_REGULATOR_PARAM_MAX] = {
|
|||
PARAM(HEAD_ROOM, 1, 0, 0, 1, "hr", 0, 0x7FFFFFFF, "qcom,init-head-room"),
|
||||
PARAM(QUIET_MODE, 0, 1, 0, 0, "qm", 0, 2, "qcom,init-quiet-mode"),
|
||||
PARAM(FREQ_REASON, 0, 1, 0, 1, "resn", 0, 8, "qcom,init-freq-reason"),
|
||||
PARAM(CORNER, 0, 1, 0, 0, "corn", 0, 5, "qcom,init-voltage-corner"),
|
||||
};
|
||||
|
||||
struct rpm_vreg_request {
|
||||
|
@ -437,6 +439,7 @@ static void rpm_vreg_aggregate_params(u32 *param_aggr, const u32 *param_reg)
|
|||
RPM_VREG_AGGR_MAX(HEAD_ROOM, param_aggr, param_reg);
|
||||
RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg);
|
||||
RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg);
|
||||
RPM_VREG_AGGR_MAX(CORNER, param_aggr, param_reg);
|
||||
}
|
||||
|
||||
static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator)
|
||||
|
@ -666,6 +669,56 @@ static int rpm_vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
|
|||
return uV;
|
||||
}
|
||||
|
||||
static int rpm_vreg_set_voltage_corner(struct regulator_dev *rdev, int min_uV,
|
||||
int max_uV, unsigned *selector)
|
||||
{
|
||||
struct rpm_regulator *reg = rdev_get_drvdata(rdev);
|
||||
int rc = 0;
|
||||
int corner;
|
||||
u32 prev_corner;
|
||||
|
||||
/*
|
||||
* Translate from values which work as inputs in the
|
||||
* regulator_set_voltage function to the actual corner values
|
||||
* sent to the RPM.
|
||||
*/
|
||||
corner = min_uV - RPM_REGULATOR_CORNER_RETENTION;
|
||||
|
||||
if (corner < params[RPM_REGULATOR_PARAM_CORNER].min
|
||||
|| corner > params[RPM_REGULATOR_PARAM_CORNER].max) {
|
||||
vreg_err(reg, "corner=%d is not within allowed range: [%u, %u]\n",
|
||||
corner, params[RPM_REGULATOR_PARAM_CORNER].min,
|
||||
params[RPM_REGULATOR_PARAM_CORNER].max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rpm_vreg_lock(reg->rpm_vreg);
|
||||
|
||||
prev_corner = reg->req.param[RPM_REGULATOR_PARAM_CORNER];
|
||||
RPM_VREG_SET_PARAM(reg, CORNER, corner);
|
||||
|
||||
/* Only send a new voltage if the regulator is currently enabled. */
|
||||
if (rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
|
||||
rc = rpm_vreg_aggregate_requests(reg);
|
||||
|
||||
if (rc) {
|
||||
vreg_err(reg, "set voltage corner failed, rc=%d", rc);
|
||||
RPM_VREG_SET_PARAM(reg, CORNER, prev_corner);
|
||||
}
|
||||
|
||||
rpm_vreg_unlock(reg->rpm_vreg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rpm_vreg_get_voltage_corner(struct regulator_dev *rdev)
|
||||
{
|
||||
struct rpm_regulator *reg = rdev_get_drvdata(rdev);
|
||||
|
||||
return reg->req.param[RPM_REGULATOR_PARAM_CORNER]
|
||||
+ RPM_REGULATOR_CORNER_RETENTION;
|
||||
}
|
||||
|
||||
static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
||||
{
|
||||
struct rpm_regulator *reg = rdev_get_drvdata(rdev);
|
||||
|
@ -802,6 +855,7 @@ struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
|
|||
priv_reg->rdev->reg_data = priv_reg;
|
||||
priv_reg->rpm_vreg = rpm_vreg;
|
||||
priv_reg->rdesc.name = framework_reg->rdesc.name;
|
||||
priv_reg->rdesc.ops = framework_reg->rdesc.ops;
|
||||
priv_reg->set_active = framework_reg->set_active;
|
||||
priv_reg->set_sleep = framework_reg->set_sleep;
|
||||
priv_reg->min_uV = framework_reg->min_uV;
|
||||
|
@ -963,7 +1017,7 @@ int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rpm_vreg_set_voltage(regulator->rdev, uV, uV, NULL);
|
||||
return regulator->rdesc.ops->set_voltage(regulator->rdev, uV, uV, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpm_regulator_set_voltage);
|
||||
|
||||
|
@ -993,6 +1047,19 @@ static struct regulator_ops smps_ops = {
|
|||
.enable_time = rpm_vreg_enable_time,
|
||||
};
|
||||
|
||||
static struct regulator_ops smps_corner_ops = {
|
||||
.enable = rpm_vreg_enable,
|
||||
.disable = rpm_vreg_disable,
|
||||
.is_enabled = rpm_vreg_is_enabled,
|
||||
.set_voltage = rpm_vreg_set_voltage_corner,
|
||||
.get_voltage = rpm_vreg_get_voltage_corner,
|
||||
.list_voltage = rpm_vreg_list_voltage,
|
||||
.set_mode = rpm_vreg_set_mode,
|
||||
.get_mode = rpm_vreg_get_mode,
|
||||
.get_optimum_mode = rpm_vreg_get_optimum_mode,
|
||||
.enable_time = rpm_vreg_enable_time,
|
||||
};
|
||||
|
||||
static struct regulator_ops switch_ops = {
|
||||
.enable = rpm_vreg_enable,
|
||||
.disable = rpm_vreg_disable,
|
||||
|
@ -1122,6 +1189,14 @@ static int __devinit rpm_vreg_device_probe(struct platform_device *pdev)
|
|||
reg->rdesc.owner = THIS_MODULE;
|
||||
reg->rdesc.type = REGULATOR_VOLTAGE;
|
||||
|
||||
/*
|
||||
* Switch to voltage corner regulator ops if qcom,use-voltage-corner
|
||||
* is specified in the device node (SMPS only).
|
||||
*/
|
||||
if (of_find_property(node, "qcom,use-voltage-corner", NULL)
|
||||
&& regulator_type == RPM_REGULATOR_SMD_TYPE_SMPS)
|
||||
reg->rdesc.ops = &smps_corner_ops;
|
||||
|
||||
if (regulator_type == RPM_REGULATOR_SMD_TYPE_VS)
|
||||
reg->rdesc.n_voltages = 0;
|
||||
else
|
||||
|
|
Loading…
Reference in a new issue