From: Bevan Weiss Date: Thu, 12 Feb 2026 06:05:12 +0000 (+1100) Subject: kernel: pse-pd: Fix missing regulator backport X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dfd15dc725a273cae3484fb9d487dc93ae5b6286;p=thirdparty%2Fopenwrt.git kernel: pse-pd: Fix missing regulator backport Fixes: 528c9259a70f Backport the PSE-PD... When the original backport bring-in was done, the regulator power budget portion was missed. This results in kernel build errors when trying to bring in PSE_CONTROLLER or PSE_REGULATOR configs. Which are required to bring in further PSE drivers. Bring in the backport to fix that up. Patch series naming is a bit wrong here, but keeps patches together in ordering, whilst reducing files touched in this commit. Without this patch, when adding config of CONFIG_PSE_CONTROLLER=y CONFIG_PSE_REGULATOR=y CONFIG_PSE_TPS23881=y CONFIG_REGULATOR=y The following errors occur: drivers/net/pse-pd/pse_core.c:446:9: error: implicit declaration of function 'regulator_free_power_budget' drivers/net/pse-pd/pse_core.c:559:16: error: implicit declaration of function 'regulator_request_power_budget' Signed-off-by: Bevan Weiss Link: https://github.com/openwrt/openwrt/pull/21996 Signed-off-by: Robert Marko --- diff --git a/target/linux/generic/backport-6.12/626-16b-v6.17-regulator-Add-support-for-power-budget.patch b/target/linux/generic/backport-6.12/626-16b-v6.17-regulator-Add-support-for-power-budget.patch new file mode 100644 index 00000000000..8f63044f77f --- /dev/null +++ b/target/linux/generic/backport-6.12/626-16b-v6.17-regulator-Add-support-for-power-budget.patch @@ -0,0 +1,257 @@ +From 42d7c87b4e1251f36eceac987e74623e7cda8577 Mon Sep 17 00:00:00 2001 +From: Kory Maincent +Date: Wed, 15 Jan 2025 15:41:57 +0100 +Subject: [PATCH] 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 +Link: https://patch.msgid.link/20250115-feature_regulator_pw_budget-v2-1-0a44b949e6bc@bootlin.com +Signed-off-by: Mark Brown +Signed-off-by: Bevan Weiss +--- + drivers/regulator/core.c | 114 +++++++++++++++++++++++++++++ + drivers/regulator/of_regulator.c | 3 + + include/linux/regulator/consumer.h | 21 ++++++ + include/linux/regulator/driver.h | 2 + + include/linux/regulator/machine.h | 2 + + 5 files changed, 142 insertions(+) + +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -916,6 +916,26 @@ static ssize_t bypass_show(struct device + } + static DEVICE_ATTR_RO(bypass); + ++static ssize_t power_budget_milliwatt_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct regulator_dev *rdev = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", rdev->constraints->pw_budget_mW); ++} ++static DEVICE_ATTR_RO(power_budget_milliwatt); ++ ++static ssize_t power_requested_milliwatt_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_requested_mW); ++} ++static DEVICE_ATTR_RO(power_requested_milliwatt); ++ + #define REGULATOR_ERROR_ATTR(name, bit) \ + static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +@@ -1148,6 +1168,10 @@ static void print_constraints_debug(stru + if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) + count += scnprintf(buf + count, len - count, "standby "); + ++ if (constraints->pw_budget_mW) ++ count += scnprintf(buf + count, len - count, "%d mW budget", ++ constraints->pw_budget_mW); ++ + if (!count) + count = scnprintf(buf, len, "no parameters"); + else +@@ -1631,6 +1655,9 @@ static int set_machine_constraints(struc + rdev->last_off = ktime_get(); + } + ++ if (!rdev->constraints->pw_budget_mW) ++ rdev->constraints->pw_budget_mW = INT_MAX; ++ + print_constraints(rdev); + return 0; + } +@@ -4646,6 +4673,87 @@ int regulator_get_current_limit(struct r + EXPORT_SYMBOL_GPL(regulator_get_current_limit); + + /** ++ * regulator_get_unclaimed_power_budget - get regulator unclaimed power budget ++ * @regulator: regulator source ++ * ++ * Return: Unclaimed power budget of the regulator in mW. ++ */ ++int regulator_get_unclaimed_power_budget(struct regulator *regulator) ++{ ++ return regulator->rdev->constraints->pw_budget_mW - ++ regulator->rdev->pw_requested_mW; ++} ++EXPORT_SYMBOL_GPL(regulator_get_unclaimed_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, pw_tot_req; ++ ++ regulator_lock(rdev); ++ if (rdev->supply) { ++ ret = regulator_request_power_budget(rdev->supply, pw_req); ++ if (ret < 0) ++ goto out; ++ } ++ ++ pw_tot_req = rdev->pw_requested_mW + pw_req; ++ if (pw_tot_req > rdev->constraints->pw_budget_mW) { ++ rdev_warn(rdev, "power requested %d mW out of budget %d mW", ++ pw_req, ++ rdev->constraints->pw_budget_mW - rdev->pw_requested_mW); ++ regulator_notifier_call_chain(rdev, ++ REGULATOR_EVENT_OVER_CURRENT_WARN, ++ NULL); ++ ret = -ERANGE; ++ goto out; ++ } ++ ++ rdev->pw_requested_mW = pw_tot_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; ++ int pw_tot_req; ++ ++ regulator_lock(rdev); ++ if (rdev->supply) ++ regulator_free_power_budget(rdev->supply, pw); ++ ++ pw_tot_req = rdev->pw_requested_mW - pw; ++ if (pw_tot_req >= 0) ++ rdev->pw_requested_mW = pw_tot_req; ++ else ++ rdev_warn(rdev, ++ "too much power freed %d mW (already requested %d mW)", ++ pw, rdev->pw_requested_mW); ++ ++ regulator_unlock(rdev); ++} ++EXPORT_SYMBOL_GPL(regulator_free_power_budget); ++ ++/** + * regulator_set_mode - set regulator operating mode + * @regulator: regulator source + * @mode: operating mode - one of the REGULATOR_MODE constants +@@ -5283,6 +5391,8 @@ static struct attribute *regulator_dev_a + &dev_attr_suspend_standby_mode.attr, + &dev_attr_suspend_mem_mode.attr, + &dev_attr_suspend_disk_mode.attr, ++ &dev_attr_power_budget_milliwatt.attr, ++ &dev_attr_power_requested_milliwatt.attr, + NULL + }; + +@@ -5364,6 +5474,10 @@ static umode_t regulator_attr_is_visible + attr == &dev_attr_suspend_disk_mode.attr) + return ops->set_suspend_mode ? mode : 0; + ++ if (attr == &dev_attr_power_budget_milliwatt.attr || ++ attr == &dev_attr_power_requested_milliwatt.attr) ++ return rdev->constraints->pw_budget_mW != INT_MAX ? mode : 0; ++ + return mode; + } + +--- a/drivers/regulator/of_regulator.c ++++ b/drivers/regulator/of_regulator.c +@@ -125,6 +125,9 @@ static int of_get_regulation_constraints + if (constraints->min_uA != constraints->max_uA) + constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; + ++ if (!of_property_read_u32(np, "regulator-power-budget-milliwatt", &pval)) ++ constraints->pw_budget_mW = 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. */ +--- a/include/linux/regulator/consumer.h ++++ b/include/linux/regulator/consumer.h +@@ -235,6 +235,11 @@ int regulator_sync_voltage(struct regula + 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_unclaimed_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_ + return 0; + } + ++static inline int regulator_get_unclaimed_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) + { +--- a/include/linux/regulator/driver.h ++++ b/include/linux/regulator/driver.h +@@ -649,6 +649,8 @@ struct regulator_dev { + int cached_err; + bool use_cached_err; + spinlock_t err_lock; ++ ++ int pw_requested_mW; + }; + + /* +--- a/include/linux/regulator/machine.h ++++ b/include/linux/regulator/machine.h +@@ -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_mW: 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_mW; + int system_load; + + /* used for coupled regulators */