149 lines
4.8 KiB
Diff
149 lines
4.8 KiB
Diff
From git@z Thu Jan 1 00:00:00 1970
|
|
Subject: [PATCH RFC 2/5] mfd: axp20x: Refactor axp20x_is_polyphase_slave()
|
|
From: Andre Przywara <andre.przywara@arm.com>
|
|
Date: Fri, 19 Sep 2025 01:00:17 +0100
|
|
Message-Id: <20250919000020.16969-3-andre.przywara@arm.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset="utf-8"
|
|
Content-Transfer-Encoding: 7bit
|
|
|
|
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, but we detect the existing setup, and prevent the connected
|
|
regulators from being re-programmed or turned off. At the moment this is
|
|
done in a switch/case construct, listing the known regulator pairs for
|
|
those PMICs supported.
|
|
|
|
To get rid of this ever growing code section, create a data structure
|
|
that describes the relationship, and have generic code that iterates
|
|
over the entries and checks for matches.
|
|
|
|
This not only cleans that function up and makes extensions much simpler,
|
|
but also allows to reuse this information for the upcoming programming
|
|
of those poly-phase setups.
|
|
|
|
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
|
---
|
|
drivers/regulator/axp20x-regulator.c | 91 ++++++++++++++--------------
|
|
1 file changed, 45 insertions(+), 46 deletions(-)
|
|
|
|
--- a/drivers/regulator/axp20x-regulator.c
|
|
+++ b/drivers/regulator/axp20x-regulator.c
|
|
@@ -1481,70 +1481,69 @@ static int axp20x_set_dcdc_workmode(stru
|
|
return regmap_update_bits(rdev->regmap, reg, mask, workmode);
|
|
}
|
|
|
|
+struct dualphase_regulator {
|
|
+ int axp_id;
|
|
+ int reg1, reg2;
|
|
+ unsigned int polyphase_reg;
|
|
+ unsigned int bitmask;
|
|
+} dualphase_regulators[] = {
|
|
+ { AXP323_ID, AXP313A_DCDC1, AXP313A_DCDC2,
|
|
+ AXP323_DCDC_MODE_CTRL2, BIT(1), },
|
|
+ { AXP803_ID, AXP803_DCDC2, AXP803_DCDC3, AXP803_POLYPHASE_CTRL,
|
|
+ AXP803_DCDC23_POLYPHASE_DUAL, },
|
|
+ { AXP803_ID, AXP803_DCDC5, AXP803_DCDC6, AXP803_POLYPHASE_CTRL,
|
|
+ AXP803_DCDC56_POLYPHASE_DUAL, },
|
|
+ /* AXP806's DCDC-A/B/C is a tri-phase regulator */
|
|
+ { AXP806_ID, AXP806_DCDCD, AXP806_DCDCE, AXP806_DCDC_MODE_CTRL2,
|
|
+ AXP806_DCDCDE_POLYPHASE_DUAL, },
|
|
+ { AXP813_ID, AXP803_DCDC2, AXP803_DCDC3, AXP803_POLYPHASE_CTRL,
|
|
+ AXP803_DCDC23_POLYPHASE_DUAL, },
|
|
+ { AXP813_ID, AXP803_DCDC5, AXP803_DCDC6, AXP803_POLYPHASE_CTRL,
|
|
+ AXP803_DCDC56_POLYPHASE_DUAL, },
|
|
+ { AXP15060_ID, AXP15060_DCDC2, AXP15060_DCDC3, AXP15060_DCDC_MODE_CTRL1,
|
|
+ AXP15060_DCDC23_POLYPHASE_DUAL_MASK, },
|
|
+ { AXP15060_ID, AXP15060_DCDC4, AXP15060_DCDC6, AXP15060_DCDC_MODE_CTRL1,
|
|
+ AXP15060_DCDC46_POLYPHASE_DUAL_MASK, },
|
|
+};
|
|
+
|
|
/*
|
|
* This function checks whether a regulator is part of a poly-phase
|
|
* output setup based on the registers settings. Returns true if it is.
|
|
*/
|
|
static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
|
|
{
|
|
+ struct dualphase_regulator *dpreg;
|
|
u32 reg = 0;
|
|
+ int i;
|
|
|
|
- /*
|
|
- * Currently in our supported AXP variants, only AXP803, AXP806,
|
|
- * AXP813 and AXP15060 have polyphase regulators.
|
|
- */
|
|
- switch (axp20x->variant) {
|
|
- case AXP803_ID:
|
|
- case AXP813_ID:
|
|
- regmap_read(axp20x->regmap, AXP803_POLYPHASE_CTRL, ®);
|
|
-
|
|
- switch (id) {
|
|
- case AXP803_DCDC3:
|
|
- return !!(reg & AXP803_DCDC23_POLYPHASE_DUAL);
|
|
- case AXP803_DCDC6:
|
|
- return !!(reg & AXP803_DCDC56_POLYPHASE_DUAL);
|
|
+ for (i = 0; i < ARRAY_SIZE(dualphase_regulators); i++) {
|
|
+ dpreg = &dualphase_regulators[i];
|
|
+
|
|
+ if (axp20x->variant != dpreg->axp_id)
|
|
+ continue;
|
|
+ /* Is this the second regulator from a dual-phase pair? */
|
|
+ if (id == dpreg->reg2) {
|
|
+ regmap_read(axp20x->regmap, dpreg->polyphase_reg, ®);
|
|
+
|
|
+ return !!(reg & dpreg->bitmask);
|
|
}
|
|
- break;
|
|
+ }
|
|
|
|
- case AXP806_ID:
|
|
+ /*
|
|
+ * DCDC-A/B/C can be configured either as a dual-phase (A+B) or
|
|
+ * as a triple-phase regulator (A+B+C), but not in any other
|
|
+ * combination. Treat this as a special case here.
|
|
+ */
|
|
+ if (axp20x->variant == AXP806_ID) {
|
|
regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, ®);
|
|
-
|
|
- switch (id) {
|
|
- case AXP806_DCDCB:
|
|
+ if (id == AXP806_DCDCB)
|
|
return (((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
|
|
AXP806_DCDCAB_POLYPHASE_DUAL) ||
|
|
((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
|
|
AXP806_DCDCABC_POLYPHASE_TRI));
|
|
- case AXP806_DCDCC:
|
|
+ if (id == AXP806_DCDCC)
|
|
return ((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
|
|
AXP806_DCDCABC_POLYPHASE_TRI);
|
|
- case AXP806_DCDCE:
|
|
- return !!(reg & AXP806_DCDCDE_POLYPHASE_DUAL);
|
|
- }
|
|
- break;
|
|
-
|
|
- case AXP15060_ID:
|
|
- regmap_read(axp20x->regmap, AXP15060_DCDC_MODE_CTRL1, ®);
|
|
-
|
|
- switch (id) {
|
|
- case AXP15060_DCDC3:
|
|
- return !!(reg & AXP15060_DCDC23_POLYPHASE_DUAL_MASK);
|
|
- case AXP15060_DCDC6:
|
|
- return !!(reg & AXP15060_DCDC46_POLYPHASE_DUAL_MASK);
|
|
- }
|
|
- break;
|
|
-
|
|
- case AXP323_ID:
|
|
- regmap_read(axp20x->regmap, AXP323_DCDC_MODE_CTRL2, ®);
|
|
-
|
|
- switch (id) {
|
|
- case AXP313A_DCDC2:
|
|
- return !!(reg & BIT(1));
|
|
- }
|
|
- break;
|
|
-
|
|
- default:
|
|
- return false;
|
|
}
|
|
|
|
return false;
|