@@ -917,6 +917,15 @@ static ssize_t bypass_show(struct device *dev,
}
static DEVICE_ATTR_RO(bypass);
+static ssize_t power_budget_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", rdev->pw_available);
+}
+static DEVICE_ATTR_RO(power_budget);
+
#define REGULATOR_ERROR_ATTR(name, bit) \
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -1149,6 +1158,10 @@ static void print_constraints_debug(struct regulator_dev *rdev)
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
count += scnprintf(buf + count, len - count, "standby ");
+ if (constraints->pw_budget)
+ count += scnprintf(buf + count, len - count, "%d mW budget",
+ constraints->pw_budget);
+
if (!count)
count = scnprintf(buf, len, "no parameters");
else
@@ -1627,6 +1640,13 @@ static int set_machine_constraints(struct regulator_dev *rdev)
rdev->last_off = ktime_get();
}
+ if (rdev->constraints->pw_budget)
+ rdev->pw_available = rdev->constraints->pw_budget;
+ else if (rdev->supply)
+ rdev->pw_available = regulator_get_power_budget(rdev->supply);
+ else
+ rdev->pw_available = INT_MAX;
+
print_constraints(rdev);
return 0;
}
@@ -4641,6 +4661,71 @@ int regulator_get_current_limit(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(regulator_get_current_limit);
+/**
+ * regulator_get_power_budget - get regulator total power budget
+ * @regulator: regulator source
+ *
+ * Return: Power budget of the regulator in mW.
+ */
+int regulator_get_power_budget(struct regulator *regulator)
+{
+ return regulator->rdev->pw_available;
+}
+EXPORT_SYMBOL_GPL(regulator_get_power_budget);
+
+/**
+ * regulator_request_power_budget - request power budget on a regulator
+ * @regulator: regulator source
+ * @pw_req: Power requested
+ *
+ * Return: 0 on success or a negative error number on failure.
+ */
+int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret = 0;
+
+ regulator_lock(rdev);
+ if (rdev->supply) {
+ ret = regulator_request_power_budget(rdev->supply, pw_req);
+ if (ret < 0)
+ goto out;
+ }
+ if (pw_req > rdev->pw_available) {
+ rdev_dbg(rdev, "power requested %d mW out of budget %d mW",
+ pw_req, rdev->pw_available);
+ ret = -ERANGE;
+ goto out;
+ }
+
+ rdev->pw_available -= pw_req;
+out:
+ regulator_unlock(rdev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_request_power_budget);
+
+/**
+ * regulator_free_power_budget - free power budget on a regulator
+ * @regulator: regulator source
+ * @pw: Power to be released.
+ *
+ * Return: Power budget of the regulator in mW.
+ */
+void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+
+ regulator_lock(rdev);
+ if (rdev->supply)
+ regulator_free_power_budget(rdev->supply, pw);
+ rdev->pw_available += pw;
+ regulator_unlock(rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_free_power_budget);
+
/**
* regulator_set_mode - set regulator operating mode
* @regulator: regulator source
@@ -5279,6 +5364,7 @@ static struct attribute *regulator_dev_attrs[] = {
&dev_attr_suspend_standby_mode.attr,
&dev_attr_suspend_mem_mode.attr,
&dev_attr_suspend_disk_mode.attr,
+ &dev_attr_power_budget.attr,
NULL
};
@@ -5360,6 +5446,9 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
attr == &dev_attr_suspend_disk_mode.attr)
return ops->set_suspend_mode ? mode : 0;
+ if (attr == &dev_attr_power_budget.attr)
+ return rdev->pw_available != INT_MAX ? mode : 0;
+
return mode;
}
@@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev,
if (constraints->min_uA != constraints->max_uA)
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
+ if (!of_property_read_u32(np, "regulator-power-budget", &pval))
+ constraints->pw_budget = pval;
+
constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
constraints->always_on = of_property_read_bool(np, "regulator-always-on");
if (!constraints->always_on) /* status change should be possible. */
@@ -235,6 +235,11 @@ int regulator_sync_voltage(struct regulator *regulator);
int regulator_set_current_limit(struct regulator *regulator,
int min_uA, int max_uA);
int regulator_get_current_limit(struct regulator *regulator);
+int regulator_get_power_budget(struct regulator *regulator);
+int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req);
+void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw);
int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator);
@@ -534,6 +539,22 @@ static inline int regulator_get_current_limit(struct regulator *regulator)
return 0;
}
+static inline int regulator_get_power_budget(struct regulator *regulator)
+{
+ return INT_MAX;
+}
+
+static inline int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw)
+{
+}
+
static inline int regulator_set_mode(struct regulator *regulator,
unsigned int mode)
{
@@ -649,6 +649,8 @@ struct regulator_dev {
int cached_err;
bool use_cached_err;
spinlock_t err_lock;
+
+ int pw_available;
};
/*
@@ -113,6 +113,7 @@ struct notification_limit {
* @min_uA: Smallest current consumers may set.
* @max_uA: Largest current consumers may set.
* @ilim_uA: Maximum input current.
+ * @pw_budget: Power budget for the regulator in mW.
* @system_load: Load that isn't captured by any consumer requests.
*
* @over_curr_limits: Limits for acting on over current.
@@ -185,6 +186,7 @@ struct regulation_constraints {
int max_uA;
int ilim_uA;
+ int pw_budget;
int system_load;
/* used for coupled regulators */