Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35fe2f97 authored by David Collins's avatar David Collins Committed by Stephen Boyd
Browse files

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: default avatarDavid Collins <collinsd@codeaurora.org>
parent 17fe8aa0
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -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";
	};
};
+20 −0
Original line number Diff line number Diff line
@@ -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);
+76 −1
Original line number Diff line number Diff line
@@ -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,
@@ -1123,6 +1190,14 @@ static int 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