mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
regulator: core: clamp voltage constraints before applying apply_uV
machine_constraints_voltage() currently applies apply_uV against the machine-supplied [min_uV, max_uV] range, and only afterwards clamps that range down to what the regulator can actually supply (via ops->list_voltage()). If the machine-supplied range is wider than the regulator's actual range, apply_uV's rounding can pick a selector outside the (correct) clamped range, so the regulator ends up programmed outside its clamped min/max. At bring-up this shows up as a voltage read-back outside the clamped range. Fix this by moving the clamping block ahead of the apply_uV block, so apply_uV always targets an already-clamped range. Whether apply_uV should run is decided from the unclamped constraints beforehand and stored in a local bool, since clamping must not itself change whether apply_uV fires. No functional change to the clamping logic itself, only its position relative to apply_uV. Its early return 0 exits become fallthroughs since the apply_uV logic now follows it. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Kamal Wadhwa <kamal.wadhwa@oss.qualcomm.com> Link: https://patch.msgid.link/20260720-b4-regulator-core-clamp-voltage-v1-1-8e5eec076a8e@oss.qualcomm.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
1d26f12550
commit
a45cc646a3
|
|
@ -1220,10 +1220,98 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
|
|||
{
|
||||
const struct regulator_ops *ops = rdev->desc->ops;
|
||||
int ret;
|
||||
bool apply_uV;
|
||||
|
||||
/*
|
||||
* Decide up front, from the constraints as handed to us, whether
|
||||
* apply_uV needs to run below. The clamping pass right after this
|
||||
* may rewrite constraints->min_uV/max_uV (e.g. the fixed-voltage
|
||||
* autoconfigure case), and we don't want that to change whether
|
||||
* apply_uV fires.
|
||||
*/
|
||||
apply_uV = rdev->constraints->apply_uV &&
|
||||
rdev->constraints->min_uV && rdev->constraints->max_uV;
|
||||
|
||||
/*
|
||||
* Constrain machine-level voltage specs to fit the actual range
|
||||
* supported by this regulator before apply_uV (below) tries to
|
||||
* force hardware to a value from that range: otherwise apply_uV
|
||||
* can target a constraint value that doesn't correspond to any
|
||||
* real voltage selector and fail registration outright, even
|
||||
* though the clamping pass would have narrowed it to a value
|
||||
* the regulator can actually hit.
|
||||
*/
|
||||
if (ops->list_voltage && rdev->desc->n_voltages) {
|
||||
int count = rdev->desc->n_voltages;
|
||||
int i;
|
||||
int min_uV = INT_MAX;
|
||||
int max_uV = INT_MIN;
|
||||
int cmin = constraints->min_uV;
|
||||
int cmax = constraints->max_uV;
|
||||
|
||||
/* it's safe to autoconfigure fixed-voltage supplies
|
||||
* and the constraints are used by list_voltage.
|
||||
*/
|
||||
if (count == 1 && !cmin) {
|
||||
cmin = 1;
|
||||
cmax = INT_MAX;
|
||||
constraints->min_uV = cmin;
|
||||
constraints->max_uV = cmax;
|
||||
}
|
||||
|
||||
/* voltage constraints are optional */
|
||||
if ((cmin == 0) && (cmax == 0)) {
|
||||
/* nothing more to do */
|
||||
|
||||
/* else require explicit machine-level constraints */
|
||||
} else if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
|
||||
rdev_err(rdev, "invalid voltage constraints\n");
|
||||
return -EINVAL;
|
||||
|
||||
/* no need to loop voltages if range is continuous */
|
||||
} else if (rdev->desc->continuous_voltage_range) {
|
||||
/* nothing more to do */
|
||||
|
||||
} else {
|
||||
/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
|
||||
for (i = 0; i < count; i++) {
|
||||
int value;
|
||||
|
||||
value = ops->list_voltage(rdev, i);
|
||||
if (value <= 0)
|
||||
continue;
|
||||
|
||||
/* maybe adjust [min_uV..max_uV] */
|
||||
if (value >= cmin && value < min_uV)
|
||||
min_uV = value;
|
||||
if (value <= cmax && value > max_uV)
|
||||
max_uV = value;
|
||||
}
|
||||
|
||||
/* final: [min_uV..max_uV] valid iff constraints valid */
|
||||
if (max_uV < min_uV) {
|
||||
rdev_err(rdev,
|
||||
"unsupportable voltage constraints %u-%uuV\n",
|
||||
min_uV, max_uV);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* use regulator's subset of machine constraints */
|
||||
if (constraints->min_uV < min_uV) {
|
||||
rdev_dbg(rdev, "override min_uV, %d -> %d\n",
|
||||
constraints->min_uV, min_uV);
|
||||
constraints->min_uV = min_uV;
|
||||
}
|
||||
if (constraints->max_uV > max_uV) {
|
||||
rdev_dbg(rdev, "override max_uV, %d -> %d\n",
|
||||
constraints->max_uV, max_uV);
|
||||
constraints->max_uV = max_uV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* do we need to apply the constraint voltage */
|
||||
if (rdev->constraints->apply_uV &&
|
||||
rdev->constraints->min_uV && rdev->constraints->max_uV) {
|
||||
if (apply_uV) {
|
||||
int target_min, target_max;
|
||||
int current_uV = regulator_get_voltage_rdev(rdev);
|
||||
|
||||
|
|
@ -1278,77 +1366,6 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
|
|||
}
|
||||
}
|
||||
|
||||
/* constrain machine-level voltage specs to fit
|
||||
* the actual range supported by this regulator.
|
||||
*/
|
||||
if (ops->list_voltage && rdev->desc->n_voltages) {
|
||||
int count = rdev->desc->n_voltages;
|
||||
int i;
|
||||
int min_uV = INT_MAX;
|
||||
int max_uV = INT_MIN;
|
||||
int cmin = constraints->min_uV;
|
||||
int cmax = constraints->max_uV;
|
||||
|
||||
/* it's safe to autoconfigure fixed-voltage supplies
|
||||
* and the constraints are used by list_voltage.
|
||||
*/
|
||||
if (count == 1 && !cmin) {
|
||||
cmin = 1;
|
||||
cmax = INT_MAX;
|
||||
constraints->min_uV = cmin;
|
||||
constraints->max_uV = cmax;
|
||||
}
|
||||
|
||||
/* voltage constraints are optional */
|
||||
if ((cmin == 0) && (cmax == 0))
|
||||
return 0;
|
||||
|
||||
/* else require explicit machine-level constraints */
|
||||
if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
|
||||
rdev_err(rdev, "invalid voltage constraints\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* no need to loop voltages if range is continuous */
|
||||
if (rdev->desc->continuous_voltage_range)
|
||||
return 0;
|
||||
|
||||
/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
|
||||
for (i = 0; i < count; i++) {
|
||||
int value;
|
||||
|
||||
value = ops->list_voltage(rdev, i);
|
||||
if (value <= 0)
|
||||
continue;
|
||||
|
||||
/* maybe adjust [min_uV..max_uV] */
|
||||
if (value >= cmin && value < min_uV)
|
||||
min_uV = value;
|
||||
if (value <= cmax && value > max_uV)
|
||||
max_uV = value;
|
||||
}
|
||||
|
||||
/* final: [min_uV..max_uV] valid iff constraints valid */
|
||||
if (max_uV < min_uV) {
|
||||
rdev_err(rdev,
|
||||
"unsupportable voltage constraints %u-%uuV\n",
|
||||
min_uV, max_uV);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* use regulator's subset of machine constraints */
|
||||
if (constraints->min_uV < min_uV) {
|
||||
rdev_dbg(rdev, "override min_uV, %d -> %d\n",
|
||||
constraints->min_uV, min_uV);
|
||||
constraints->min_uV = min_uV;
|
||||
}
|
||||
if (constraints->max_uV > max_uV) {
|
||||
rdev_dbg(rdev, "override max_uV, %d -> %d\n",
|
||||
constraints->max_uV, max_uV);
|
||||
constraints->max_uV = max_uV;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user