[RFC PATCH 3/5] mfd: axp20x: Allow programming dual-phase regulator pairs
From: Andre Przywara <andre.przywara@arm.com>
Date: 2025-09-19 00:01:25
Also in:
linux-devicetree, linux-sunxi, lkml
Subsystem:
the rest, voltage and current regulator framework · Maintainers:
Linus Torvalds, Liam Girdwood, Mark Brown
Some X-Powers AXP PMICs allow to combine certain DC/DC rails together in a multi-phase fashion. So far we don't actively program those connections, since the PMIC reset default for the multi-phasing setup was always correct for the existing boards. Now a new set of boards appeared where the reset default is not correct, so we need to actively program the multi-phase setup. Use the new data structure describing the dual-phased regulators, and the new "x-powers,polyphased" DT property to enable or disable the dual-phase setup on the PMICs that support it. This works by checking how many regulators this DT property list: - If it's none, this means any existing poly-phase setup should be broken up. - If the property references at least one other regulator, we can use our dual-phase regulator table to find the register and bitmask required to establish the dual-phase connection. This supports only dual-phased regulator pairs so far, but we will somewhat paper ov^W^W fix this in the next patch. Signed-off-by: Andre Przywara <andre.przywara@arm.com> --- drivers/regulator/axp20x-regulator.c | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 19c9a98d1835a..e3acc4635a0ed 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c@@ -1549,6 +1549,70 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) return false; } +static int axp20x_find_polyphased_reg(const struct regulator_desc *regs, + int nregulators, + const struct device_node *np, int index) +{ + struct of_phandle_args args; + int ret, i; + + ret = of_parse_phandle_with_fixed_args(np, "x-powers,polyphased", + 0, index, &args); + if (ret) + return ret; + + for (i = 0; i < nregulators; i++) { + if (!strcmp(regs[i].name, args.np->name)) + return i; + } + + return -ENODEV; +} + +static int axp20x_parse_polyphase(struct axp20x_dev *axp20x, int primary_reg_id, + const struct regulator_desc *regs, + int nregulators, const struct device_node *np) +{ + struct dualphase_regulator *dpreg; + int reg_id, i; + + if (!of_property_present(np, "x-powers,polyphased")) + return 0; + + reg_id = axp20x_find_polyphased_reg(regs, nregulators, np, 0); + if (reg_id < 0 && reg_id != -ENOENT) /* not just empty property */ + return reg_id; + + for (i = 0; i < ARRAY_SIZE(dualphase_regulators); i++) { + dpreg = &dualphase_regulators[i]; + + if (axp20x->variant != dpreg->axp_id) + continue; + + if (dpreg->reg1 != primary_reg_id && + dpreg->reg2 != primary_reg_id) + continue; + + /* Empty property means breaking any polyphase setup. */ + if (reg_id == -ENOENT) { + regmap_update_bits(axp20x->regmap, dpreg->polyphase_reg, + dpreg->bitmask, 0); + + return 0; + } + + if ((dpreg->reg1 == primary_reg_id && dpreg->reg2 == reg_id) || + (dpreg->reg2 == primary_reg_id && dpreg->reg1 == reg_id)) { + regmap_update_bits(axp20x->regmap, dpreg->polyphase_reg, + dpreg->bitmask, dpreg->bitmask); + + return 0; + } + } + + return 0; +} + static int axp20x_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev;
@@ -1703,6 +1767,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev) rdev->desc->name); } + if (rdev->dev.of_node) + axp20x_parse_polyphase(axp20x, i, regulators, + nregulators, rdev->dev.of_node); + /* * Save AXP22X DCDC1 / DCDC5 / AXP15060 ALDO1 regulator names for later. */
--
2.46.4