From 4367cfdc7c657ad8a797f51b9ffd3c64b31910e7 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 26 Feb 2009 11:48:36 -0800 Subject: regulator: enumerate voltages (v2) Add a basic mechanism for regulators to report the discrete voltages they support: list_voltage() enumerates them using selectors numbered from 0 to an upper bound. Use those methods to force machine-level constraints into bounds. (Example: regulator supports 1.8V, 2.4V, 2.6V, 3.3V, and board constraints for that rail are 2.0V to 3.6V ... so the range of voltages is then 2.4V to 3.3V on this board.) Export those voltages to the regulator consumer interface, so for example regulator hooked up to an MMC/SD/SDIO slot can report the actual voltage options available to cards connected there. Signed-off-by: David Brownell Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 75abcd85e51..da357a07c98 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -692,6 +692,69 @@ static int set_machine_constraints(struct regulator_dev *rdev, else name = "regulator"; + /* constrain machine-level voltage specs to fit + * the actual range supported by this regulator. + */ + if (ops->list_voltage && rdev->desc->n_voltages) { + int count = rdev->desc->n_voltages; + int i; + int min_uV = INT_MAX; + int max_uV = INT_MIN; + int cmin = constraints->min_uV; + int cmax = constraints->max_uV; + + /* it's safe to autoconfigure fixed-voltage supplies */ + if (count == 1 && !cmin) { + cmin = INT_MIN; + cmax = INT_MAX; + } + + /* else require explicit machine-level constraints */ + else if (cmin <= 0 || cmax <= 0 || cmax < cmin) { + pr_err("%s: %s '%s' voltage constraints\n", + __func__, "invalid", name); + ret = -EINVAL; + goto out; + } + + /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */ + for (i = 0; i < count; i++) { + int value; + + value = ops->list_voltage(rdev, i); + if (value <= 0) + continue; + + /* maybe adjust [min_uV..max_uV] */ + if (value >= cmin && value < min_uV) + min_uV = value; + if (value <= cmax && value > max_uV) + max_uV = value; + } + + /* final: [min_uV..max_uV] valid iff constraints valid */ + if (max_uV < min_uV) { + pr_err("%s: %s '%s' voltage constraints\n", + __func__, "unsupportable", name); + ret = -EINVAL; + goto out; + } + + /* use regulator's subset of machine constraints */ + if (constraints->min_uV < min_uV) { + pr_debug("%s: override '%s' %s, %d -> %d\n", + __func__, name, "min_uV", + constraints->min_uV, min_uV); + constraints->min_uV = min_uV; + } + if (constraints->max_uV > max_uV) { + pr_debug("%s: override '%s' %s, %d -> %d\n", + __func__, name, "max_uV", + constraints->max_uV, max_uV); + constraints->max_uV = max_uV; + } + } + rdev->constraints = constraints; /* do we need to apply the constraint voltage */ @@ -1250,6 +1313,56 @@ int regulator_is_enabled(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_is_enabled); +/** + * regulator_count_voltages - count regulator_list_voltage() selectors + * @regulator: regulator source + * + * Returns number of selectors, or negative errno. Selectors are + * numbered starting at zero, and typically correspond to bitfields + * in hardware registers. + */ +int regulator_count_voltages(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + + return rdev->desc->n_voltages ? : -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_count_voltages); + +/** + * regulator_list_voltage - enumerate supported voltages + * @regulator: regulator source + * @selector: identify voltage to list + * Context: can sleep + * + * Returns a voltage that can be passed to @regulator_set_voltage(), + * zero if this selector code can't be used on this sytem, or a + * negative errno. + */ +int regulator_list_voltage(struct regulator *regulator, unsigned selector) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + int ret; + + if (!ops->list_voltage || selector >= rdev->desc->n_voltages) + return -EINVAL; + + mutex_lock(&rdev->mutex); + ret = ops->list_voltage(rdev, selector); + mutex_unlock(&rdev->mutex); + + if (ret > 0) { + if (ret < rdev->constraints->min_uV) + ret = 0; + else if (ret > rdev->constraints->max_uV) + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage); + /** * regulator_set_voltage - set regulator output voltage * @regulator: regulator source -- cgit v1.2.3-18-g5258