Skip to content

Commit 42d7c87

Browse files
kmaincentbroonie
authored andcommitted
regulator: Add support for power budget
Introduce power budget management for the regulator device. Enable tracking of available power capacity by providing helpers to request and release power budget allocations. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> Link: https://patch.msgid.link/20250115-feature_regulator_pw_budget-v2-1-0a44b949e6bc@bootlin.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent c3ad22a commit 42d7c87

File tree

5 files changed

+142
-0
lines changed

5 files changed

+142
-0
lines changed

drivers/regulator/core.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,26 @@ static ssize_t bypass_show(struct device *dev,
917917
}
918918
static DEVICE_ATTR_RO(bypass);
919919

920+
static ssize_t power_budget_milliwatt_show(struct device *dev,
921+
struct device_attribute *attr,
922+
char *buf)
923+
{
924+
struct regulator_dev *rdev = dev_get_drvdata(dev);
925+
926+
return sprintf(buf, "%d\n", rdev->constraints->pw_budget_mW);
927+
}
928+
static DEVICE_ATTR_RO(power_budget_milliwatt);
929+
930+
static ssize_t power_requested_milliwatt_show(struct device *dev,
931+
struct device_attribute *attr,
932+
char *buf)
933+
{
934+
struct regulator_dev *rdev = dev_get_drvdata(dev);
935+
936+
return sprintf(buf, "%d\n", rdev->pw_requested_mW);
937+
}
938+
static DEVICE_ATTR_RO(power_requested_milliwatt);
939+
920940
#define REGULATOR_ERROR_ATTR(name, bit) \
921941
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
922942
char *buf) \
@@ -1149,6 +1169,10 @@ static void print_constraints_debug(struct regulator_dev *rdev)
11491169
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
11501170
count += scnprintf(buf + count, len - count, "standby ");
11511171

1172+
if (constraints->pw_budget_mW)
1173+
count += scnprintf(buf + count, len - count, "%d mW budget",
1174+
constraints->pw_budget_mW);
1175+
11521176
if (!count)
11531177
count = scnprintf(buf, len, "no parameters");
11541178
else
@@ -1627,6 +1651,9 @@ static int set_machine_constraints(struct regulator_dev *rdev)
16271651
rdev->last_off = ktime_get();
16281652
}
16291653

1654+
if (!rdev->constraints->pw_budget_mW)
1655+
rdev->constraints->pw_budget_mW = INT_MAX;
1656+
16301657
print_constraints(rdev);
16311658
return 0;
16321659
}
@@ -4601,6 +4628,87 @@ int regulator_get_current_limit(struct regulator *regulator)
46014628
}
46024629
EXPORT_SYMBOL_GPL(regulator_get_current_limit);
46034630

4631+
/**
4632+
* regulator_get_unclaimed_power_budget - get regulator unclaimed power budget
4633+
* @regulator: regulator source
4634+
*
4635+
* Return: Unclaimed power budget of the regulator in mW.
4636+
*/
4637+
int regulator_get_unclaimed_power_budget(struct regulator *regulator)
4638+
{
4639+
return regulator->rdev->constraints->pw_budget_mW -
4640+
regulator->rdev->pw_requested_mW;
4641+
}
4642+
EXPORT_SYMBOL_GPL(regulator_get_unclaimed_power_budget);
4643+
4644+
/**
4645+
* regulator_request_power_budget - request power budget on a regulator
4646+
* @regulator: regulator source
4647+
* @pw_req: Power requested
4648+
*
4649+
* Return: 0 on success or a negative error number on failure.
4650+
*/
4651+
int regulator_request_power_budget(struct regulator *regulator,
4652+
unsigned int pw_req)
4653+
{
4654+
struct regulator_dev *rdev = regulator->rdev;
4655+
int ret = 0, pw_tot_req;
4656+
4657+
regulator_lock(rdev);
4658+
if (rdev->supply) {
4659+
ret = regulator_request_power_budget(rdev->supply, pw_req);
4660+
if (ret < 0)
4661+
goto out;
4662+
}
4663+
4664+
pw_tot_req = rdev->pw_requested_mW + pw_req;
4665+
if (pw_tot_req > rdev->constraints->pw_budget_mW) {
4666+
rdev_warn(rdev, "power requested %d mW out of budget %d mW",
4667+
pw_req,
4668+
rdev->constraints->pw_budget_mW - rdev->pw_requested_mW);
4669+
regulator_notifier_call_chain(rdev,
4670+
REGULATOR_EVENT_OVER_CURRENT_WARN,
4671+
NULL);
4672+
ret = -ERANGE;
4673+
goto out;
4674+
}
4675+
4676+
rdev->pw_requested_mW = pw_tot_req;
4677+
out:
4678+
regulator_unlock(rdev);
4679+
return ret;
4680+
}
4681+
EXPORT_SYMBOL_GPL(regulator_request_power_budget);
4682+
4683+
/**
4684+
* regulator_free_power_budget - free power budget on a regulator
4685+
* @regulator: regulator source
4686+
* @pw: Power to be released.
4687+
*
4688+
* Return: Power budget of the regulator in mW.
4689+
*/
4690+
void regulator_free_power_budget(struct regulator *regulator,
4691+
unsigned int pw)
4692+
{
4693+
struct regulator_dev *rdev = regulator->rdev;
4694+
int pw_tot_req;
4695+
4696+
regulator_lock(rdev);
4697+
if (rdev->supply)
4698+
regulator_free_power_budget(rdev->supply, pw);
4699+
4700+
pw_tot_req = rdev->pw_requested_mW - pw;
4701+
if (pw_tot_req >= 0)
4702+
rdev->pw_requested_mW = pw_tot_req;
4703+
else
4704+
rdev_warn(rdev,
4705+
"too much power freed %d mW (already requested %d mW)",
4706+
pw, rdev->pw_requested_mW);
4707+
4708+
regulator_unlock(rdev);
4709+
}
4710+
EXPORT_SYMBOL_GPL(regulator_free_power_budget);
4711+
46044712
/**
46054713
* regulator_set_mode - set regulator operating mode
46064714
* @regulator: regulator source
@@ -5239,6 +5347,8 @@ static struct attribute *regulator_dev_attrs[] = {
52395347
&dev_attr_suspend_standby_mode.attr,
52405348
&dev_attr_suspend_mem_mode.attr,
52415349
&dev_attr_suspend_disk_mode.attr,
5350+
&dev_attr_power_budget_milliwatt.attr,
5351+
&dev_attr_power_requested_milliwatt.attr,
52425352
NULL
52435353
};
52445354

@@ -5320,6 +5430,10 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
53205430
attr == &dev_attr_suspend_disk_mode.attr)
53215431
return ops->set_suspend_mode ? mode : 0;
53225432

5433+
if (attr == &dev_attr_power_budget_milliwatt.attr ||
5434+
attr == &dev_attr_power_requested_milliwatt.attr)
5435+
return rdev->constraints->pw_budget_mW != INT_MAX ? mode : 0;
5436+
53235437
return mode;
53245438
}
53255439

drivers/regulator/of_regulator.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev,
125125
if (constraints->min_uA != constraints->max_uA)
126126
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
127127

128+
if (!of_property_read_u32(np, "regulator-power-budget-milliwatt", &pval))
129+
constraints->pw_budget_mW = pval;
130+
128131
constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
129132
constraints->always_on = of_property_read_bool(np, "regulator-always-on");
130133
if (!constraints->always_on) /* status change should be possible. */

include/linux/regulator/consumer.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ int regulator_sync_voltage(struct regulator *regulator);
258258
int regulator_set_current_limit(struct regulator *regulator,
259259
int min_uA, int max_uA);
260260
int regulator_get_current_limit(struct regulator *regulator);
261+
int regulator_get_unclaimed_power_budget(struct regulator *regulator);
262+
int regulator_request_power_budget(struct regulator *regulator,
263+
unsigned int pw_req);
264+
void regulator_free_power_budget(struct regulator *regulator,
265+
unsigned int pw);
261266

262267
int regulator_set_mode(struct regulator *regulator, unsigned int mode);
263268
unsigned int regulator_get_mode(struct regulator *regulator);
@@ -571,6 +576,22 @@ static inline int regulator_get_current_limit(struct regulator *regulator)
571576
return 0;
572577
}
573578

579+
static inline int regulator_get_unclaimed_power_budget(struct regulator *regulator)
580+
{
581+
return INT_MAX;
582+
}
583+
584+
static inline int regulator_request_power_budget(struct regulator *regulator,
585+
unsigned int pw_req)
586+
{
587+
return -EOPNOTSUPP;
588+
}
589+
590+
static inline void regulator_free_power_budget(struct regulator *regulator,
591+
unsigned int pw)
592+
{
593+
}
594+
574595
static inline int regulator_set_mode(struct regulator *regulator,
575596
unsigned int mode)
576597
{

include/linux/regulator/driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,8 @@ struct regulator_dev {
656656
int cached_err;
657657
bool use_cached_err;
658658
spinlock_t err_lock;
659+
660+
int pw_requested_mW;
659661
};
660662

661663
/*

include/linux/regulator/machine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct notification_limit {
113113
* @min_uA: Smallest current consumers may set.
114114
* @max_uA: Largest current consumers may set.
115115
* @ilim_uA: Maximum input current.
116+
* @pw_budget_mW: Power budget for the regulator in mW.
116117
* @system_load: Load that isn't captured by any consumer requests.
117118
*
118119
* @over_curr_limits: Limits for acting on over current.
@@ -185,6 +186,7 @@ struct regulation_constraints {
185186
int max_uA;
186187
int ilim_uA;
187188

189+
int pw_budget_mW;
188190
int system_load;
189191

190192
/* used for coupled regulators */

0 commit comments

Comments
 (0)