mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
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:
@@ -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
|
||||
|
||||
@@ -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(®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);
|
||||
@@ -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(®ulator_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(®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_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(®ulator->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(®ulator_class, NULL, NULL,
|
||||
regulator_register_fill_coupling_array);
|
||||
|
||||
regulator_release_early_min_volt();
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall_sync(regulator_init_complete);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user