regulator: core: Add support to limit min_uV during system startup

Now a regulator device can supply multiple consumers at the same time,
if a consumer starts and set a low voltage, another consumer doesn't
start in kernel but has been set a high frequency in bootloader will
abort.

This patch Adds support to limit min_uV during kernel startup to make
sure the voltage can suit the needs of all consumers.

Change-Id: Ibd16a8e44916798021e2470c90a8e3488df206f4
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Finley Xiao
2018-04-18 10:01:01 +08:00
committed by Tao Huang
parent 66c1d6486a
commit d7e9e2622d
5 changed files with 77 additions and 0 deletions

View File

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

View File

@@ -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;
@@ -4430,6 +4431,27 @@ 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->voltage[PM_SUSPEND_ON].min_uV =
rdev->constraints->early_min_uV;
regulator->voltage[PM_SUSPEND_ON].max_uV = rdev->constraints->max_uV;
list_add(&regulator->early_min_list, &regulator_early_min_volt_list);
}
static int regulator_register_resolve_supply(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
@@ -4700,6 +4722,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
}
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(&regulator_class, NULL, NULL,
@@ -5135,6 +5158,46 @@ unlock:
return 0;
}
static void __init regulator_release_early_min_volt(void)
{
struct regulator *regulator, *n, *reg;
struct regulator_dev *rdev;
int min_uV = 0, max_uV = 0, ret = 0;
if (list_empty(&regulator_early_min_volt_list))
return;
list_for_each_entry_safe(regulator, n, &regulator_early_min_volt_list,
early_min_list) {
rdev = regulator->rdev;
regulator_lock_supply(rdev);
regulator->voltage[PM_SUSPEND_ON].min_uV = 0;
regulator->voltage[PM_SUSPEND_ON].max_uV = 0;
min_uV = rdev->constraints->min_uV;
max_uV = rdev->constraints->max_uV;
list_for_each_entry(reg, &rdev->consumer_list, list) {
if (!reg->voltage[PM_SUSPEND_ON].min_uV &&
!reg->voltage[PM_SUSPEND_ON].max_uV)
continue;
ret = regulator_set_voltage_unlocked(regulator, min_uV,
max_uV,
PM_SUSPEND_ON);
if (ret)
rdev_err(rdev, "set voltage(%d, %d) failed\n",
min_uV, max_uV);
break;
}
regulator_unlock_supply(rdev);
list_del(&regulator->early_min_list);
regulator_put(regulator);
}
}
static int __init regulator_init_complete(void)
{
/*
@@ -5167,6 +5230,8 @@ static int __init regulator_init_complete(void)
class_for_each_device(&regulator_class, NULL, NULL,
regulator_register_fill_coupling_array);
regulator_release_early_min_volt();
return 0;
}
late_initcall_sync(regulator_init_complete);

View File

@@ -39,6 +39,7 @@ struct regulator_voltage {
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;

View File

@@ -43,6 +43,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;

View File

@@ -98,6 +98,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.
@@ -146,6 +149,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 */