diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 3ab862b4f3a7..53931649e4d5 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -5,6 +5,8 @@ Optional properties: - regulator-min-microvolt: smallest voltage consumers may set - regulator-max-microvolt: largest voltage consumers may set - regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops +- regulator-early-min-microvolt: minimum voltage during system startup, make sure we + select a voltage that suits the needs of all regulator consumers - regulator-min-microamp: smallest current consumers may set - regulator-max-microamp: largest current consumers may set - regulator-input-current-limit-microamp: maximum input current regulator allows diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 15b8b9954b07..541f08d6f31b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -56,6 +56,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); +static LIST_HEAD(regulator_early_min_volt_list); static bool has_full_constraints; static struct dentry *debugfs_root; @@ -4224,6 +4225,26 @@ static inline void rdev_init_debugfs(struct regulator_dev *rdev) #endif +static void rdev_init_early_min_volt(struct regulator_dev *rdev) +{ + struct regulator *regulator; + + if (!rdev->constraints->early_min_uV) + return; + + regulator = regulator_get(NULL, rdev_get_name(rdev)); + if (IS_ERR(regulator)) { + rdev_err(rdev, "regulator get failed, ret=%ld\n", + PTR_ERR(regulator)); + return; + } + + regulator->min_uV = rdev->constraints->early_min_uV; + regulator->max_uV = rdev->constraints->max_uV; + + list_add(®ulator->early_min_list, ®ulator_early_min_volt_list); +} + static int regulator_register_resolve_supply(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); @@ -4391,6 +4412,7 @@ regulator_register(const struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); rdev_init_debugfs(rdev); + rdev_init_early_min_volt(rdev); /* try to resolve regulators supply since a new one was registered */ class_for_each_device(®ulator_class, NULL, NULL, @@ -4830,6 +4852,28 @@ unlock: return 0; } +static void __init regulator_release_early_min_volt(void) +{ + struct regulator *regulator, *n; + struct regulator_dev *rdev; + + if (list_empty(®ulator_early_min_volt_list)) + return; + + list_for_each_entry_safe(regulator, n, ®ulator_early_min_volt_list, + early_min_list) { + rdev = regulator->rdev; + regulator->min_uV = 0; + regulator->max_uV = 0; + if (regulator_set_voltage(regulator, regulator->min_uV, + regulator->max_uV)) + rdev_err(regulator->rdev, "set voltage(%d, %d) failed\n", + regulator->min_uV, regulator->max_uV); + list_del(®ulator->early_min_list); + regulator_put(regulator); + } +} + static int __init regulator_init_complete(void) { /* @@ -4849,6 +4893,8 @@ static int __init regulator_init_complete(void) class_for_each_device(®ulator_class, NULL, NULL, regulator_late_cleanup); + regulator_release_early_min_volt(); + return 0; } late_initcall_sync(regulator_init_complete); diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index c74ac8734023..eb15aec07fc7 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -24,6 +24,7 @@ struct regulator { struct device *dev; struct list_head list; + struct list_head early_min_list; unsigned int always_on:1; unsigned int bypass:1; int uA_load; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 8bc8d14fa703..01060076dd78 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -42,6 +42,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-max-microvolt", &pval)) constraints->max_uV = pval; + if (!of_property_read_u32(np, "regulator-early-min-microvolt", &pval)) + constraints->early_min_uV = pval; + /* Voltage change possible? */ if (constraints->min_uV != constraints->max_uV) constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 8ab67b6f0250..07e913c791aa 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -80,6 +80,9 @@ struct regulator_state { * @uV_offset: Offset applied to voltages from consumer to compensate for * voltage drops. * + * @early_min_uV: Minimum voltage during system startup, make sure we select + * a voltage that suits the needs of all regulator consumers. + * * @min_uA: Smallest current consumers may set. * @max_uA: Largest current consumers may set. * @ilim_uA: Maximum input current. @@ -126,6 +129,9 @@ struct regulation_constraints { int min_uV; int max_uV; + /* Minimum voltage during system startup */ + int early_min_uV; + int uV_offset; /* current output range (inclusive) - for current control */