1
0
Fork 0
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:
David Collins 2012-06-15 13:33:13 -07:00 committed by Stephen Boyd
parent 97ab0481b2
commit c395e1b293
3 changed files with 131 additions and 1 deletions
Documentation/devicetree/bindings/arm/msm
arch/arm/mach-msm

View file

@ -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";
};
};

View file

@ -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);

View file

@ -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