* [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support
@ 2026-07-17 14:31 Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W Jerome Brunet
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 14:31 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Conor Dooley, Jerome Brunet, Sashiko
This patch series adds support for the X-Powers AXP318W PMIC, which is
used recently on new boards with Allwinner SoCs (the A733).
The PMIC features 9 DCDC buck converters and 28 LDOs, plus the usual ADC,
interrupts, and power key components.
A datasheet can be found linked in this Wiki table:
https://linux-sunxi.org/AXP_PMICs
There was an unclosed topic regarding the handling of LDOs output
voltage being limited to input voltage being provided by the supply.
Chen-Yu noted the min_dropout_uV would be a good fit for that but
the actual minimal dropout value was unknown. I've arbitrarily picked
1uV because it is the minimum the framework supports. Realistically a low
dropout regulator is bound to have some dropout. This choice does the
trick for now and is certain be less restrictive than what it is in
reality.
If anyone has problems because the dropout is actually higher
* it is arguably an HW design error
* it is a good time to let us know what the actual dropout is
Changes in v4:
- Capitalize patch 3 title
- regulator: add support for workmode and poly-phase.
- i2c: fix probe through i2c sysfs
- Link to v3: https://patch.msgid.link/20260717-axp318-regulator-v3-0-779dc1b97dd4@baylibre.com
Changes in v3:
- Correct mess up v2 errors regarding ops and ids.
- Correctly propagate errors when checking axp318 threshold.
- Fix DT binding regex regarding dcdc max ids
- Add missing RTCLDO.
- Remove axp318 PEK MFD cell:
As pointed out by sashiko, the driver name did not match anything in the
pek driver. While the device does support some handling of the power
button, it does not seem to match the existing driver. Register 0x36
relates to DLDO3, not the power key, as expected by the misc driver.
Leave this out for now.
- Constify axp313 and axp717 mfd_cells array for consistency.
- Link to v2: https://patch.msgid.link/20260710-axp318-regulator-v2-0-ee5f1c56b49f@baylibre.com
Changes in v2:
- Droped _NUM_VOLTAGES macros
- Use min_dropout_uV to limit LDO voltage to supplies
- Add bypass mode for EDLO4/5
- Prevent crossing 1.54V threshold for DCDC6/7/8/9
- Link to v1: https://lore.kernel.org/r/20251021112013.2710903-1-andre.przywara@arm.com
---
Andre Przywara (3):
dt-bindings: mfd: x-powers,axp152: Document AXP318W
mfd: axp20x: Add support for AXP318W PMIC
regulator: axp20x: add support for the AXP318W
Jerome Brunet (2):
mfd: axp20x: Constify axp313 and axp717 cells
mfd: axp20x-i2c: Fix i2c instantiation
.../devicetree/bindings/mfd/x-powers,axp152.yaml | 28 +-
drivers/mfd/axp20x-i2c.c | 26 +-
drivers/mfd/axp20x-rsb.c | 1 +
drivers/mfd/axp20x.c | 83 +++++-
drivers/regulator/axp20x-regulator.c | 326 ++++++++++++++++++++-
include/linux/mfd/axp20x.h | 131 +++++++++
6 files changed, 571 insertions(+), 24 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260710-axp318-regulator-43545ce3261f
Best regards,
--
Jerome
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W
2026-07-17 14:31 [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support Jerome Brunet
@ 2026-07-17 14:31 ` Jerome Brunet
2026-07-17 14:43 ` sashiko-bot
2026-07-17 14:31 ` [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC Jerome Brunet
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 14:31 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Conor Dooley, Jerome Brunet
From: Andre Przywara <andre.przywara@arm.com>
The X-Powers AXP318W is a PMIC used on some newer Allwinner devices.
Among a large number of both DCDC and LDO regulators it features the usual
ADC/IRQ/power key parts.
Like other recent PMICs, it lacks the DC/DC converter PWM frequency control
register, that rate is fixed here (1.5MHz on DCDC1, 3 MHz on the others).
Add the new compatible string, and add that to the list of PMICs without
the PWM frequency property.
Also add more input supply properties, for the split DCDC and ALDO
supplies.
The PMIC features *two* switched outputs, hanging of DCDC1, and the
manual calls them swout1 and swout2, so follow suit here and add those
names to the pattern for matching the node names.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
.../devicetree/bindings/mfd/x-powers,axp152.yaml | 28 +++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
index 45f015d63df1..95b3984fe0f9 100644
--- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
+++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
@@ -83,6 +83,7 @@ allOf:
contains:
enum:
- x-powers,axp313a
+ - x-powers,axp318w
- x-powers,axp323
- x-powers,axp15060
- x-powers,axp717
@@ -102,6 +103,7 @@ properties:
- x-powers,axp221
- x-powers,axp223
- x-powers,axp313a
+ - x-powers,axp318w
- x-powers,axp323
- x-powers,axp717
- x-powers,axp803
@@ -156,10 +158,18 @@ properties:
description: >
DCDC1 power supply node, if present.
+ vin19-supply:
+ description: >
+ Combined DCDC1/DCDC9 power supply node, if present.
+
vin2-supply:
description: >
DCDC2 power supply node, if present.
+ vin23-supply:
+ description: >
+ Combined DCDC2/DCDC3 power supply node, if present.
+
vin3-supply:
description: >
DCDC3 power supply node, if present.
@@ -168,6 +178,10 @@ properties:
description: >
DCDC4 power supply node, if present.
+ vin45-supply:
+ description: >
+ Combined DCDC4/DCDC5 power supply node, if present.
+
vin5-supply:
description: >
DCDC5 power supply node, if present.
@@ -176,6 +190,10 @@ properties:
description: >
DCDC6 power supply node, if present.
+ vin678-supply:
+ description: >
+ Combined DCDC6/DCDC7/DCDC8 power supply node, if present.
+
vin7-supply:
description: >
DCDC7 power supply node, if present.
@@ -220,6 +238,14 @@ properties:
description: >
ALDO* power supply node, if present.
+ aldo156in-supply:
+ description: >
+ ALDO* power supply node, if present.
+
+ aldo234in-supply:
+ description: >
+ ALDO* power supply node, if present.
+
bldoin-supply:
description: >
BLDO* power supply node, if present.
@@ -277,7 +303,7 @@ properties:
Defines the work frequency of DC-DC in kHz.
patternProperties:
- "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
+ "^(([a-f])?ldo[0-9]|dcdc[0-9a-e]|ldo(_|-)io(0|1)|(dc1)?sw|swout[1-9]|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
$ref: /schemas/regulator/regulator.yaml#
type: object
unevaluatedProperties: false
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC
2026-07-17 14:31 [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W Jerome Brunet
@ 2026-07-17 14:31 ` Jerome Brunet
2026-07-17 14:48 ` sashiko-bot
2026-07-17 14:31 ` [PATCH v4 3/5] mfd: axp20x: Constify axp313 and axp717 cells Jerome Brunet
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 14:31 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet
From: Andre Przywara <andre.przywara@arm.com>
The AXP318W is a PMIC chip produced by X-Powers, it can be connected to
an I2C bus.
It has a large number of regulators: 9(!) DCDC buck converters, and 28
LDOs, also some ADCs, interrupts, and a power key.
Describe the regmap and the MFD bits, along with the registers exposed
via I2C only. This covers the regulators and interrupts for now.
Advertise the device using the new compatible string.
We use just "318" for the internal identifiers, for easier typing and
less churn, but use "318W" for anything externally visible. If something
else other than the "AXP318W" shows up, that's an easy change then.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mfd/axp20x-i2c.c | 2 ++
drivers/mfd/axp20x.c | 78 +++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 166 insertions(+)
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index 5c93136f977e..4e4ebfc78525 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
{ .compatible = "x-powers,axp313a", .data = (void *)AXP313A_ID },
+ { .compatible = "x-powers,axp318w", .data = (void *)AXP318_ID },
{ .compatible = "x-powers,axp323", .data = (void *)AXP323_ID },
{ .compatible = "x-powers,axp717", .data = (void *)AXP717_ID },
{ .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
@@ -83,6 +84,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
{ "axp221" },
{ "axp223" },
{ "axp313a" },
+ { "axp318w" },
{ "axp717" },
{ "axp803" },
{ "axp806" },
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 679364189ea5..c8aeebd01bbc 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -42,6 +42,7 @@ static const char * const axp20x_model_names[] = {
[AXP223_ID] = "AXP223",
[AXP288_ID] = "AXP288",
[AXP313A_ID] = "AXP313a",
+ [AXP318_ID] = "AXP318W",
[AXP323_ID] = "AXP323",
[AXP717_ID] = "AXP717",
[AXP803_ID] = "AXP803",
@@ -218,6 +219,31 @@ static const struct regmap_access_table axp313a_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges),
};
+static const struct regmap_range axp318_writeable_ranges[] = {
+ regmap_reg_range(AXP318_DCDC_OUTPUT_CONTROL1, AXP318_IRQ_STATE4),
+ regmap_reg_range(AXP318_SHUTDOWN_CTRL, AXP318_TEMP_ADC_H_EN),
+ regmap_reg_range(AXP318_DIE_TEMP_ADC_H_EN, AXP318_DIE_TEMP_ADC_H_EN),
+ regmap_reg_range(AXP318_GPADC_H_EN, AXP318_GPADC_H_EN),
+ regmap_reg_range(AXP318_GPIO_CTRL, AXP318_WDOG_CTRL),
+};
+
+static const struct regmap_range axp318_volatile_ranges[] = {
+ regmap_reg_range(AXP318_IRQ_EN1, AXP318_IRQ_STATE4),
+ regmap_reg_range(AXP318_POWER_REASON, AXP318_SHUTDOWN_REASON),
+ regmap_reg_range(AXP318_TEMP_ADC_H_EN, AXP318_GPADC_L),
+ regmap_reg_range(AXP318_GPIO_INPUT, AXP318_GPIO_INPUT),
+};
+
+static const struct regmap_access_table axp318_writeable_table = {
+ .yes_ranges = axp318_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp318_writeable_ranges),
+};
+
+static const struct regmap_access_table axp318_volatile_table = {
+ .yes_ranges = axp318_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp318_volatile_ranges),
+};
+
static const struct regmap_range axp717_writeable_ranges[] = {
regmap_reg_range(AXP717_PMU_FAULT, AXP717_MODULE_EN_CONTROL_1),
regmap_reg_range(AXP717_MIN_SYS_V_CONTROL, AXP717_BOOST_CONTROL),
@@ -447,6 +473,15 @@ static const struct regmap_config axp313a_regmap_config = {
.cache_type = REGCACHE_MAPLE,
};
+static const struct regmap_config axp318_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp318_writeable_table,
+ .volatile_table = &axp318_volatile_table,
+ .max_register = AXP318_WDOG_CTRL,
+ .cache_type = REGCACHE_MAPLE,
+};
+
static const struct regmap_config axp323_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -663,6 +698,28 @@ static const struct regmap_irq axp313a_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP313A, DIE_TEMP_HIGH, 0, 0),
};
+static const struct regmap_irq axp318_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP318, DCDC8_V_LOW, 0, 7),
+ INIT_REGMAP_IRQ(AXP318, DCDC7_V_LOW, 0, 6),
+ INIT_REGMAP_IRQ(AXP318, DCDC6_V_LOW, 0, 5),
+ INIT_REGMAP_IRQ(AXP318, DCDC5_V_LOW, 0, 4),
+ INIT_REGMAP_IRQ(AXP318, DCDC4_V_LOW, 0, 3),
+ INIT_REGMAP_IRQ(AXP318, DCDC3_V_LOW, 0, 2),
+ INIT_REGMAP_IRQ(AXP318, DCDC2_V_LOW, 0, 1),
+ INIT_REGMAP_IRQ(AXP318, DCDC1_V_LOW, 0, 0),
+ INIT_REGMAP_IRQ(AXP318, PEK_RIS_EDGE, 1, 6),
+ INIT_REGMAP_IRQ(AXP318, PEK_FAL_EDGE, 1, 5),
+ INIT_REGMAP_IRQ(AXP318, PEK_LONG, 1, 4),
+ INIT_REGMAP_IRQ(AXP318, PEK_SHORT, 1, 3),
+ INIT_REGMAP_IRQ(AXP318, DIE_TEMP_HIGH_LV2, 1, 2),
+ INIT_REGMAP_IRQ(AXP318, DIE_TEMP_HIGH_LV1, 1, 1),
+ INIT_REGMAP_IRQ(AXP318, DCDC9_V_LOW, 1, 0),
+ INIT_REGMAP_IRQ(AXP318, GPIO3_INPUT, 2, 6),
+ INIT_REGMAP_IRQ(AXP318, GPIO2_INPUT, 2, 5),
+ INIT_REGMAP_IRQ(AXP318, GPIO1_INPUT, 2, 4),
+ INIT_REGMAP_IRQ(AXP318, WDOG_EXPIRE, 3, 0),
+};
+
static const struct regmap_irq axp717_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL2, 0, 7),
INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL1, 0, 6),
@@ -884,6 +941,17 @@ static const struct regmap_irq_chip axp313a_regmap_irq_chip = {
.num_regs = 1,
};
+static const struct regmap_irq_chip axp318_regmap_irq_chip = {
+ .name = "axp318w_irq_chip",
+ .status_base = AXP318_IRQ_STATE1,
+ .ack_base = AXP318_IRQ_STATE1,
+ .unmask_base = AXP318_IRQ_EN1,
+ .init_ack_masked = true,
+ .irqs = axp318_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp318_regmap_irqs),
+ .num_regs = 4,
+};
+
static const struct regmap_irq_chip axp717_regmap_irq_chip = {
.name = "axp717_irq_chip",
.status_base = AXP717_IRQ0_STATE,
@@ -1061,6 +1129,10 @@ static struct mfd_cell axp313a_cells[] = {
MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
};
+static const struct mfd_cell axp318_cells[] = {
+ MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
+};
+
static struct mfd_cell axp717_cells[] = {
MFD_CELL_NAME("axp20x-regulator"),
MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
@@ -1313,6 +1385,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_cfg = &axp313a_regmap_config;
axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip;
break;
+ case AXP318_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp318_cells);
+ axp20x->cells = axp318_cells;
+ axp20x->regmap_cfg = &axp318_regmap_config;
+ axp20x->regmap_irq_chip = &axp318_regmap_irq_chip;
+ break;
case AXP323_ID:
axp20x->nr_cells = ARRAY_SIZE(axp313a_cells);
axp20x->cells = axp313a_cells;
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index b352661d99a1..c1f9dc06387a 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -19,6 +19,7 @@ enum axp20x_variants {
AXP223_ID,
AXP288_ID,
AXP313A_ID,
+ AXP318_ID,
AXP323_ID,
AXP717_ID,
AXP803_ID,
@@ -116,6 +117,69 @@ enum axp20x_variants {
#define AXP313A_IRQ_STATE 0x21
#define AXP323_DCDC_MODE_CTRL2 0x22
+#define AXP318_DCDC_OUTPUT_CONTROL1 0x10
+#define AXP318_DCDC_OUTPUT_CONTROL2 0x11
+#define AXP318_DCDC1_CONTROL 0x12
+#define AXP318_DCDC2_CONTROL 0x13
+#define AXP318_DCDC3_CONTROL 0x14
+#define AXP318_DCDC4_CONTROL 0x15
+#define AXP318_DCDC5_CONTROL 0x16
+#define AXP318_DCDC6_CONTROL 0x17
+#define AXP318_DCDC7_CONTROL 0x18
+#define AXP318_DCDC8_CONTROL 0x19
+#define AXP318_DCDC9_CONTROL 0x1a
+#define AXP318_LDO_OUTPUT_CONTROL1 0x20
+#define AXP318_LDO_OUTPUT_CONTROL2 0x21
+#define AXP318_LDO_OUTPUT_CONTROL3 0x22
+#define AXP318_LDO_OUTPUT_CONTROL4 0x23
+#define AXP318_ALDO1_CONTROL 0x24
+#define AXP318_ALDO2_CONTROL 0x25
+#define AXP318_ALDO3_CONTROL 0x26
+#define AXP318_ALDO4_CONTROL 0x27
+#define AXP318_ALDO5_CONTROL 0x28
+#define AXP318_ALDO6_CONTROL 0x29
+#define AXP318_BLDO1_CONTROL 0x2a
+#define AXP318_BLDO2_CONTROL 0x2b
+#define AXP318_BLDO3_CONTROL 0x2c
+#define AXP318_BLDO4_CONTROL 0x2d
+#define AXP318_BLDO5_CONTROL 0x2e
+#define AXP318_CLDO1_CONTROL 0x2f
+#define AXP318_CLDO2_CONTROL 0x30
+#define AXP318_CLDO3_CONTROL 0x31
+#define AXP318_CLDO4_CONTROL 0x32
+#define AXP318_CLDO5_CONTROL 0x33
+#define AXP318_DLDO1_CONTROL 0x34
+#define AXP318_DLDO2_CONTROL 0x35
+#define AXP318_DLDO3_CONTROL 0x36
+#define AXP318_DLDO4_CONTROL 0x37
+#define AXP318_DLDO5_CONTROL 0x38
+#define AXP318_DLDO6_CONTROL 0x39
+#define AXP318_ELDO1_CONTROL 0x3a
+#define AXP318_ELDO2_CONTROL 0x3b
+#define AXP318_ELDO3_CONTROL 0x3c
+#define AXP318_ELDO4_CONTROL 0x3d
+#define AXP318_ELDO5_CONTROL 0x3e
+#define AXP318_ELDO6_CONTROL 0x3f
+#define AXP318_IRQ_EN1 0x40
+#define AXP318_IRQ_EN2 0x41
+#define AXP318_IRQ_EN3 0x42
+#define AXP318_IRQ_EN4 0x43
+#define AXP318_IRQ_STATE1 0x48
+#define AXP318_IRQ_STATE2 0x49
+#define AXP318_IRQ_STATE3 0x4a
+#define AXP318_IRQ_STATE4 0x4b
+#define AXP318_POWER_REASON 0x50
+#define AXP318_SHUTDOWN_REASON 0x51
+#define AXP318_SHUTDOWN_CTRL 0x52
+#define AXP318_TEMP_ADC_H_EN 0x65
+#define AXP318_TEMP_ADC_L 0x66
+#define AXP318_DIE_TEMP_ADC_H_EN 0x67
+#define AXP318_GPADC_H_EN 0x69
+#define AXP318_GPADC_L 0x6a
+#define AXP318_GPIO_CTRL 0x70
+#define AXP318_GPIO_INPUT 0x71
+#define AXP318_WDOG_CTRL 0x77
+
#define AXP717_ON_INDICATE 0x00
#define AXP717_PMU_STATUS_2 0x01
#define AXP717_BC_DETECT 0x05
@@ -819,6 +883,28 @@ enum axp313a_irqs {
AXP313A_IRQ_PEK_RIS_EDGE,
};
+enum axp318_irqs {
+ AXP318_IRQ_DCDC1_V_LOW,
+ AXP318_IRQ_DCDC2_V_LOW,
+ AXP318_IRQ_DCDC3_V_LOW,
+ AXP318_IRQ_DCDC4_V_LOW,
+ AXP318_IRQ_DCDC5_V_LOW,
+ AXP318_IRQ_DCDC6_V_LOW,
+ AXP318_IRQ_DCDC7_V_LOW,
+ AXP318_IRQ_DCDC8_V_LOW,
+ AXP318_IRQ_DCDC9_V_LOW,
+ AXP318_IRQ_DIE_TEMP_HIGH_LV1,
+ AXP318_IRQ_DIE_TEMP_HIGH_LV2,
+ AXP318_IRQ_PEK_SHORT,
+ AXP318_IRQ_PEK_LONG,
+ AXP318_IRQ_PEK_FAL_EDGE,
+ AXP318_IRQ_PEK_RIS_EDGE,
+ AXP318_IRQ_GPIO1_INPUT = 20,
+ AXP318_IRQ_GPIO2_INPUT,
+ AXP318_IRQ_GPIO3_INPUT,
+ AXP318_IRQ_WDOG_EXPIRE = 24,
+};
+
enum axp717_irqs {
AXP717_IRQ_VBUS_FAULT,
AXP717_IRQ_VBUS_OVER_V,
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 3/5] mfd: axp20x: Constify axp313 and axp717 cells
2026-07-17 14:31 [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC Jerome Brunet
@ 2026-07-17 14:31 ` Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 5/5] regulator: axp20x: add support for the AXP318W Jerome Brunet
4 siblings, 0 replies; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 14:31 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet
mfd_cells array should generally be const and there does not seem to be
anything against it for the axp313 and axp717.
Constify the mfd_cells array for the axp313 and axp717 to be consitent
with the other supported chips
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mfd/axp20x.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index c8aeebd01bbc..2bbe73afff43 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1123,7 +1123,7 @@ static const struct mfd_cell axp152_cells[] = {
},
};
-static struct mfd_cell axp313a_cells[] = {
+static const struct mfd_cell axp313a_cells[] = {
/* AXP323 is sometimes paired with AXP717 as sub-PMIC */
MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
@@ -1133,7 +1133,7 @@ static const struct mfd_cell axp318_cells[] = {
MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
};
-static struct mfd_cell axp717_cells[] = {
+static const struct mfd_cell axp717_cells[] = {
MFD_CELL_NAME("axp20x-regulator"),
MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
MFD_CELL_OF("axp717-adc",
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation
2026-07-17 14:31 [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support Jerome Brunet
` (2 preceding siblings ...)
2026-07-17 14:31 ` [PATCH v4 3/5] mfd: axp20x: Constify axp313 and axp717 cells Jerome Brunet
@ 2026-07-17 14:31 ` Jerome Brunet
2026-07-17 14:54 ` sashiko-bot
2026-07-17 14:31 ` [PATCH v4 5/5] regulator: axp20x: add support for the AXP318W Jerome Brunet
4 siblings, 1 reply; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 14:31 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Sashiko, Jerome Brunet
Apparently this device never really supported i2c instantiation via
sysfs, because the driver does not even look at the i2c driver, which are
not set. It would only probe if the device matched through DT.
Fix that for correctness, even-though it is probably useless.
Add the missing AXP323 while at it.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/r/20260717090209.2A09B1F000E9@smtp.kernel.org
Fixes: 41751b033aaa ("mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading")
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mfd/axp20x-i2c.c | 26 ++++++++++++++------------
drivers/mfd/axp20x-rsb.c | 1 +
drivers/mfd/axp20x.c | 1 -
3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index 4e4ebfc78525..64c212b76e5e 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -35,6 +35,7 @@ static int axp20x_i2c_probe(struct i2c_client *i2c)
axp20x->irq = i2c->irq;
dev_set_drvdata(axp20x->dev, axp20x);
+ axp20x->variant = (kernel_ulong_t)i2c_get_match_data(i2c);
ret = axp20x_match_device(axp20x);
if (ret)
return ret;
@@ -77,18 +78,19 @@ MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
#endif
static const struct i2c_device_id axp20x_i2c_id[] = {
- { "axp152" },
- { "axp192" },
- { "axp202" },
- { "axp209" },
- { "axp221" },
- { "axp223" },
- { "axp313a" },
- { "axp318w" },
- { "axp717" },
- { "axp803" },
- { "axp806" },
- { "axp15060" },
+ { .name = "axp152", .driver_data = AXP152_ID },
+ { .name = "axp192", .driver_data = AXP192_ID },
+ { .name = "axp202", .driver_data = AXP202_ID },
+ { .name = "axp209", .driver_data = AXP209_ID },
+ { .name = "axp221", .driver_data = AXP221_ID },
+ { .name = "axp223", .driver_data = AXP223_ID },
+ { .name = "axp313a", .driver_data = AXP313A_ID },
+ { .name = "axp318w", .driver_data = AXP318_ID },
+ { .name = "axp323", .driver_data = AXP323_ID },
+ { .name = "axp717", .driver_data = AXP717_ID },
+ { .name = "axp803", .driver_data = AXP803_ID },
+ { .name = "axp806", .driver_data = AXP806_ID },
+ { .name = "axp15060", .driver_data = AXP15060_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
index 059656f2a1bd..8fdc870c1fe4 100644
--- a/drivers/mfd/axp20x-rsb.c
+++ b/drivers/mfd/axp20x-rsb.c
@@ -35,6 +35,7 @@ static int axp20x_rsb_probe(struct sunxi_rsb_device *rdev)
axp20x->irq = rdev->irq;
dev_set_drvdata(&rdev->dev, axp20x);
+ axp20x->variant = (kernel_ulong_t)device_get_match_data(axp20x->dev);
ret = axp20x_match_device(axp20x);
if (ret)
return ret;
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 2bbe73afff43..25509e47bedc 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1339,7 +1339,6 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
const struct mfd_cell *cells_no_irq = NULL;
int nr_cells_no_irq = 0;
- axp20x->variant = (long)device_get_match_data(dev);
switch (axp20x->variant) {
case AXP152_ID:
axp20x->nr_cells = ARRAY_SIZE(axp152_cells);
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 5/5] regulator: axp20x: add support for the AXP318W
2026-07-17 14:31 [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support Jerome Brunet
` (3 preceding siblings ...)
2026-07-17 14:31 ` [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation Jerome Brunet
@ 2026-07-17 14:31 ` Jerome Brunet
4 siblings, 0 replies; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 14:31 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet
From: Andre Przywara <andre.przywara@arm.com>
The X-Powers AXP318W is a typical PMIC from X-Powers, featuring nine
DC/DC converters and 28 LDOs, on the regulator side.
Describe the chip's voltage settings and switch registers, how the
voltages are encoded, and connect this to the MFD device via its
regulator ID.
We use just "318" for the internal identifiers, for easier typing and
less churn. If something else other than the "AXP318W" shows up, that's
an easy change, externally visible strings carry the additional letter
already.
Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Co-developed-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/regulator/axp20x-regulator.c | 326 ++++++++++++++++++++++++++++++++++-
include/linux/mfd/axp20x.h | 45 +++++
2 files changed, 362 insertions(+), 9 deletions(-)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index da891415efc0..8f6d28a1f76f 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -138,6 +138,30 @@
#define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0)
#define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0)
+#define AXP318_DCDC1_PFM_PWM_CTRL BIT(7)
+#define AXP318_DCDC23_POLYPHASE_CTRL BIT(6)
+#define AXP318_DCDC45_POLYPHASE_CTRL BIT(7)
+#define AXP318_DCDC1_V_OUT_MASK GENMASK(4, 0)
+#define AXP318_DCDC2_V_OUT_MASK GENMASK(6, 0)
+#define AXP318_LDO_V_OUT_MASK GENMASK(4, 0)
+#define AXP318_ELDO_V_OUT_MASK GENMASK(5, 0)
+#define AXP318_THRESHOLD_VOLTAGE 1540000
+/*
+ * FIXME:
+ * Some LDOs of the AXP318 may be fed by different supplies and
+ * the documentation repeatedly warns that output voltage must
+ * be less than the supply, which is the case for any LDO really.
+ *
+ * The best way to let the framework handle this is to set the
+ * min_dropout_uV field. However the AXP318 documentation
+ * does not provide any information about this.
+ *
+ * Realistically, it can't be less than 1uV so use this
+ * for all LDOs until we know more.
+ */
+#define AXP318_LDO_MIN_DROPOUT 1 /* uV */
+
+
#define AXP717_DCDC1_NUM_VOLTAGES 88
#define AXP717_DCDC2_NUM_VOLTAGES 107
#define AXP717_DCDC3_NUM_VOLTAGES 103
@@ -371,8 +395,8 @@
.ops = &axp20x_ops, \
}
-#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask) \
+#define AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _ops, _bpreg, _bpmask, _dropout) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -384,13 +408,32 @@
.owner = THIS_MODULE, \
.min_uV = (_min) * 1000, \
.uV_step = (_step) * 1000, \
+ .min_dropout_uV = (_dropout), \
.vsel_reg = (_vreg), \
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
- .ops = &axp20x_ops, \
+ .bypass_reg = (_bpreg), \
+ .bypass_mask = (_bpmask), \
+ .ops = (_ops), \
}
+#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask) \
+ AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, &axp20x_ops, 0, 0, 0)
+
+#define AXP_DESC_DO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _dropout) \
+ AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, &axp20x_ops, 0, 0, _dropout)
+
+#define AXP_DESC_BYPASS(_family, _id, _match, _supply, _min, _max, _step, _vreg,\
+ _vmask, _ereg, _emask, _bpreg, _bpmask, _dropout) \
+ AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, &axp20x_bypass_ops, _bpreg, \
+ _bpmask, _dropout)
+
#define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \
[_family##_##_id] = { \
.name = (_match), \
@@ -419,8 +462,9 @@
.ops = &axp20x_ops_fixed \
}
-#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \
- _vreg, _vmask, _ereg, _emask, _ramp_delay) \
+#define AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ _ramp_delay, _ops) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -436,10 +480,23 @@
.enable_mask = (_emask), \
.linear_ranges = (_ranges), \
.n_linear_ranges = ARRAY_SIZE(_ranges), \
- .ramp_delay = (_ramp_delay), \
- .ops = &axp20x_ops_range, \
+ .ramp_delay = (_ramp_delay), \
+ .ops = (_ops), \
}
+#define AXP_DESC_RANGES_THRESHOLD(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask) \
+ AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ 0, &axp318_threshold_ops_range)
+
+#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ _ramp_delay) \
+ AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ _ramp_delay, &axp20x_ops_range)
+
#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
_vreg, _vmask, _ereg, _emask) \
AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \
@@ -567,6 +624,50 @@ static int axp20x_regulator_enable_regmap(struct regulator_dev *rdev)
return regulator_enable_regmap(rdev);
};
+static int axp318_threshold_check(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ int old_sel, old_uV, new_uV, enabled;
+
+ /* Only applicable if the regulator is enabled */
+ enabled = rdev->desc->ops->is_enabled(rdev);
+ if (enabled <= 0)
+ return enabled;
+
+ old_sel = rdev->desc->ops->get_voltage_sel(rdev);
+ if (old_sel < 0)
+ return old_sel;
+
+ old_uV = rdev->desc->ops->list_voltage(rdev, old_sel);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = rdev->desc->ops->list_voltage(rdev, sel);
+ if (new_uV < 0)
+ return new_uV;
+
+ /* Crossing the threshold ? */
+ if ((old_uV <= AXP318_THRESHOLD_VOLTAGE
+ && new_uV > AXP318_THRESHOLD_VOLTAGE) ||
+ (new_uV <= AXP318_THRESHOLD_VOLTAGE
+ && old_uV > AXP318_THRESHOLD_VOLTAGE))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int axp318_threshold_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ int ret;
+
+ ret = axp318_threshold_check(rdev, sel);
+ if (ret < 0)
+ return ret;
+
+ return regulator_set_voltage_sel_regmap(rdev, sel);
+}
+
static const struct regulator_ops axp20x_ops_fixed = {
.list_voltage = regulator_list_voltage_linear,
};
@@ -580,6 +681,15 @@ static const struct regulator_ops axp20x_ops_range = {
.is_enabled = regulator_is_enabled_regmap,
};
+static const struct regulator_ops axp318_threshold_ops_range = {
+ .set_voltage_sel = axp318_threshold_set_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
static const struct regulator_ops axp20x_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -590,6 +700,19 @@ static const struct regulator_ops axp20x_ops = {
.set_ramp_delay = axp20x_set_ramp_delay,
};
+static const struct regulator_ops axp20x_bypass_ops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = axp20x_regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_ramp_delay = axp20x_set_ramp_delay,
+ .get_bypass = regulator_get_bypass_regmap,
+ .set_bypass = regulator_set_bypass_regmap,
+};
+
+
static const struct regulator_ops axp20x_ops_sw = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -765,6 +888,158 @@ static const struct regulator_desc axp313a_regulators[] = {
AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800),
};
+static const struct linear_range axp318_dcdc2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
+};
+
+static const struct linear_range axp318_dcdc6_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
+ REGULATOR_LINEAR_RANGE(1800000, 88, 118, 20000),
+ REGULATOR_LINEAR_RANGE(2440000, 119, 127, 40000),
+};
+
+static const struct linear_range axp318_dcdc7_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000),
+};
+
+static const struct linear_range axp318_dcdc8_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000),
+ REGULATOR_LINEAR_RANGE(1900000, 103, 118, 100000),
+};
+
+static const struct regulator_desc axp318_regulators[] = {
+ AXP_DESC(AXP318, DCDC1, "dcdc1", "vin19", 1000, 3400, 100,
+ AXP318_DCDC1_CONTROL, AXP318_DCDC1_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(0)),
+ AXP_DESC_RANGES(AXP318, DCDC2, "dcdc2", "vin23",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)),
+ AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)),
+ AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)),
+ AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC6, "dcdc6", "vin678",
+ axp318_dcdc6_ranges, 128,
+ AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC7, "dcdc7", "vin678",
+ axp318_dcdc7_ranges, 103,
+ AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC8, "dcdc8", "vin678",
+ axp318_dcdc8_ranges, 119,
+ AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC9, "dcdc9", "vin19",
+ axp318_dcdc8_ranges, 119,
+ AXP318_DCDC9_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL2, BIT(0)),
+ AXP_DESC_SW(AXP318, SWOUT1, "swout1", NULL,
+ AXP318_DCDC_OUTPUT_CONTROL2, BIT(3)),
+ AXP_DESC_SW(AXP318, SWOUT2, "swout2", NULL,
+ AXP318_DCDC_OUTPUT_CONTROL2, BIT(4)),
+ AXP_DESC_DO(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100,
+ AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100,
+ AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(1), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100,
+ AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(2), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100,
+ AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100,
+ AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(4), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100,
+ AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(5), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100,
+ AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100,
+ AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(7), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100,
+ AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100,
+ AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(1), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100,
+ AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(2), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100,
+ AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100,
+ AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(4), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100,
+ AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(5), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100,
+ AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100,
+ AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(7), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100,
+ AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100,
+ AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(1), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100,
+ AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(2), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100,
+ AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100,
+ AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(4), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100,
+ AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(5), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
+ AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
+ AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(7), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
+ AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_BYPASS(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
+ AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(1),
+ AXP318_ELDO4_CONTROL, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_BYPASS(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
+ AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(2),
+ AXP318_ELDO5_CONTROL, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
+ AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_FIXED(AXP318, RTC_LDO, "rtc-ldo", "ips", 1800),
+};
+
static const struct linear_range axp717_dcdc1_ranges[] = {
REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
@@ -1347,6 +1622,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
step = 150;
break;
case AXP313A_ID:
+ case AXP318_ID:
case AXP323_ID:
case AXP717_ID:
case AXP15060_ID:
@@ -1430,6 +1706,20 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
workmode <<= ffs(mask) - 1;
break;
+ case AXP318_ID:
+ /*
+ * Only DCDC1 has PWM control on the AXP318
+ * The other DCDCs control DVM through bit 7 of the related
+ * registers. Work mode could possibly extended to deal with
+ * this but it is not how it is documented at the moment
+ */
+ if (id != AXP318_DCDC1)
+ return -EINVAL;
+ reg = AXP318_DCDC1_CONTROL;
+ mask = AXP318_DCDC1_PFM_PWM_CTRL;
+ workmode <<= ffs(mask) - 1;
+ break;
+
case AXP806_ID:
/*
* AXP806 DCDC regulator IDs have the same range as AXP22X.
@@ -1543,6 +1833,17 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
}
break;
+ case AXP318_ID:
+ regmap_read(axp20x->regmap, AXP318_DCDC_CONTROL1, ®);
+
+ switch (id) {
+ case AXP318_DCDC3:
+ return !!(reg & AXP318_DCDC23_POLYPHASE_CTRL);
+ case AXP318_DCDC5:
+ return !!(reg & AXP318_DCDC45_POLYPHASE_CTRL);
+ }
+ break;
+
default:
return false;
}
@@ -1585,6 +1886,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
regulators = axp313a_regulators;
nregulators = AXP313A_REG_ID_MAX;
break;
+ case AXP318_ID:
+ regulators = axp318_regulators;
+ nregulators = AXP318_REG_ID_MAX;
+ break;
case AXP717_ID:
regulators = axp717_regulators;
nregulators = AXP717_REG_ID_MAX;
@@ -1651,7 +1956,9 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) ||
(regulators == axp803_regulators && i == AXP803_DC1SW) ||
(regulators == axp809_regulators && i == AXP809_DC1SW) ||
- (regulators == axp15060_regulators && i == AXP15060_SW)) {
+ (regulators == axp15060_regulators && i == AXP15060_SW) ||
+ (regulators == axp318_regulators && i == AXP318_SWOUT1) ||
+ (regulators == axp318_regulators && i == AXP318_SWOUT2)) {
new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
GFP_KERNEL);
if (!new_desc)
@@ -1709,7 +2016,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
*/
if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) ||
(regulators == axp809_regulators && i == AXP809_DCDC1) ||
- (regulators == axp15060_regulators && i == AXP15060_DCDC1))
+ (regulators == axp15060_regulators && i == AXP15060_DCDC1) ||
+ (regulators == axp318_regulators && i == AXP318_DCDC1))
of_property_read_string(rdev->dev.of_node,
"regulator-name",
&dcdc1_name);
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index c1f9dc06387a..10a959f362d3 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -128,6 +128,7 @@ enum axp20x_variants {
#define AXP318_DCDC7_CONTROL 0x18
#define AXP318_DCDC8_CONTROL 0x19
#define AXP318_DCDC9_CONTROL 0x1a
+#define AXP318_DCDC_CONTROL1 0x1b
#define AXP318_LDO_OUTPUT_CONTROL1 0x20
#define AXP318_LDO_OUTPUT_CONTROL2 0x21
#define AXP318_LDO_OUTPUT_CONTROL3 0x22
@@ -562,6 +563,50 @@ enum {
AXP313A_REG_ID_MAX,
};
+enum {
+ AXP318_DCDC1 = 0,
+ AXP318_DCDC2,
+ AXP318_DCDC3,
+ AXP318_DCDC4,
+ AXP318_DCDC5,
+ AXP318_DCDC6,
+ AXP318_DCDC7,
+ AXP318_DCDC8,
+ AXP318_DCDC9,
+ AXP318_ALDO1,
+ AXP318_ALDO2,
+ AXP318_ALDO3,
+ AXP318_ALDO4,
+ AXP318_ALDO5,
+ AXP318_ALDO6,
+ AXP318_BLDO1,
+ AXP318_BLDO2,
+ AXP318_BLDO3,
+ AXP318_BLDO4,
+ AXP318_BLDO5,
+ AXP318_CLDO1,
+ AXP318_CLDO2,
+ AXP318_CLDO3,
+ AXP318_CLDO4,
+ AXP318_CLDO5,
+ AXP318_DLDO1,
+ AXP318_DLDO2,
+ AXP318_DLDO3,
+ AXP318_DLDO4,
+ AXP318_DLDO5,
+ AXP318_DLDO6,
+ AXP318_ELDO1,
+ AXP318_ELDO2,
+ AXP318_ELDO3,
+ AXP318_ELDO4,
+ AXP318_ELDO5,
+ AXP318_ELDO6,
+ AXP318_SWOUT1,
+ AXP318_SWOUT2,
+ AXP318_RTC_LDO,
+ AXP318_REG_ID_MAX,
+};
+
enum {
AXP717_DCDC1 = 0,
AXP717_DCDC2,
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W
2026-07-17 14:31 ` [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W Jerome Brunet
@ 2026-07-17 14:43 ` sashiko-bot
2026-07-17 15:36 ` Jerome Brunet
0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-07-17 14:43 UTC (permalink / raw)
To: Jerome Brunet; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The `x-powers,axp318w` compatible string was omitted from the conditional block that exempts similar PMIC generations from strictly requiring the `interrupts` property.
- [Medium] The regex pattern for regulator nodes allows non-existent switched output nodes (`swout3` through `swout9`) to silently pass validation.
--
--- Patch [1]: [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W ---
commit 08577b06937ca6f13b4a7f204e7f0abb6042c44d
Author: Andre Przywara <andre.przywara@arm.com>
dt-bindings: mfd: x-powers,axp152: Document AXP318W
The X-Powers AXP318W is a PMIC used on some newer Allwinner devices.
This patch adds the new compatible string, updates the PWM frequency
property list, adds input supply properties, and updates the pattern
for matching switched outputs.
> diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
> index 45f015d63df16..95b3984fe0f96 100644
> --- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
> +++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
> @@ -83,6 +83,7 @@ allOf:
> contains:
> enum:
> - x-powers,axp313a
> + - x-powers,axp318w
> - x-powers,axp323
[Severity: Medium]
Should x-powers,axp318w also be added to the earlier conditional block that
exempts PMICs from requiring the interrupts property?
There is another allOf block in this binding that forces interrupts to be
required for all devices except a few specific generations:
- if:
not:
properties:
compatible:
contains:
enum:
- x-powers,axp15060
- x-powers,axp305
- x-powers,axp313a
- x-powers,axp323
then:
required:
- interrupts
Since the AXP318W shares constraints with siblings like axp313a and axp323,
will omitting it from that exemption block cause valid device trees without
an interrupts property to erroneously fail validation?
[ ... ]
> @@ -277,7 +303,7 @@ properties:
> Defines the work frequency of DC-DC in kHz.
>
> patternProperties:
> - "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
> + "^(([a-f])?ldo[0-9]|dcdc[0-9a-e]|ldo(_|-)io(0|1)|(dc1)?sw|swout[1-9]|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
[Severity: Medium]
Could the swout[1-9] pattern allow invalid switched output nodes to silently
pass validation?
The commit message notes that the PMIC features exactly two switched outputs,
swout1 and swout2. Allowing swout[1-9] might let device trees with invalid
nodes or typos like swout3 pass schema validation incorrectly. Would a tighter
pattern like swout[1-2] be more appropriate here?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260717-axp318-regulator-v4-0-50aff97084dd@baylibre.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC
2026-07-17 14:31 ` [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC Jerome Brunet
@ 2026-07-17 14:48 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-07-17 14:48 UTC (permalink / raw)
To: Jerome Brunet; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The system power-off handler `axp20x_power_off()` is missing a switch case for `AXP318_ID`, causing it to write the power-off command to a regulator control register.
- [Medium] The newly added `axp318_cells` array uses a hardcoded cell ID instead of `PLATFORM_DEVID_AUTO`, violating MFD subsystem guidelines.
--
--- Patch [2]: [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC ---
commit ffbc50262db7d7fef4ebd802fb44cd11951bf0bc
Author: Andre Przywara <andre.przywara@arm.com>
mfd: axp20x: Add support for AXP318W PMIC
This commit adds MFD core support for the X-Powers AXP318W PMIC. It defines
the regmap configurations, IRQs, and child device cells for the regulator.
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> index 679364189ea58..c8aeebd01bbcd 100644
> --- a/drivers/mfd/axp20x.c
> +++ b/drivers/mfd/axp20x.c
[ ... ]
> @@ -1061,6 +1129,10 @@ static struct mfd_cell axp313a_cells[] = {
> MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
> };
>
> +static const struct mfd_cell axp318_cells[] = {
> + MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
[Severity: Medium]
Does this hardcoded cell ID of 1 violate the MFD subsystem guidelines?
If multiple AXP devices with hardcoded IDs of 1 (such as the AXP313a and
AXP318W) are instantiated on the same system, could they both attempt to
register a platform device named axp20x-regulator.1, resulting in a fatal
-EEXIST failure?
Should this use PLATFORM_DEVID_AUTO instead?
> +};
> +
> static struct mfd_cell axp717_cells[] = {
> MFD_CELL_NAME("axp20x-regulator"),
[ ... ]
> @@ -1313,6 +1385,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
> axp20x->regmap_cfg = &axp313a_regmap_config;
> axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip;
> break;
> + case AXP318_ID:
> + axp20x->nr_cells = ARRAY_SIZE(axp318_cells);
> + axp20x->cells = axp318_cells;
> + axp20x->regmap_cfg = &axp318_regmap_config;
> + axp20x->regmap_irq_chip = &axp318_regmap_irq_chip;
> + break;
[Severity: High]
Is AXP318_ID missing from the switch statement in axp20x_power_off()?
When the system attempts to power off, axp20x_power_off() is called. If
AXP318_ID is not handled in the switch statement there, will it fall through
to the default case and select AXP20X_OFF_CTRL (0x32) instead of the correct
AXP318_SHUTDOWN_CTRL (0x52)?
Could this failure to shut down the PMIC corrupt the state of the CLDO4
regulator by writing the power-off command to AXP318_CLDO4_CONTROL (which
is also 0x32)?
> case AXP323_ID:
> axp20x->nr_cells = ARRAY_SIZE(axp313a_cells);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260717-axp318-regulator-v4-0-50aff97084dd@baylibre.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation
2026-07-17 14:31 ` [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation Jerome Brunet
@ 2026-07-17 14:54 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-07-17 14:54 UTC (permalink / raw)
To: Jerome Brunet; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing Error Handling / API Ambiguity causing unmatched devices to probe as AXP152.
- [High] MFD subsystem guideline violation: Hard-coded IDs used in mfd_cell array instead of PLATFORM_DEVID_AUTO.
--
--- Patch [4]: [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation ---
commit df6eff33eb956b610bd8100dff8a5beb1887390f
Author: Jerome Brunet <jbrunet@baylibre.com>
mfd: axp20x-i2c: Fix i2c instantiation
This patch fixes I2C instantiation for the AXP20X driver by moving the
variant matching directly into the bus-specific probes. It also adds support
for the AXP323 device.
Link: https://lore.kernel.org/r/20260717090209.2A09B1F000E9@smtp.kernel.org
> diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
> index 4e4ebfc78525c..64c212b76e5e6 100644
> --- a/drivers/mfd/axp20x-i2c.c
> +++ b/drivers/mfd/axp20x-i2c.c
> @@ -35,6 +35,7 @@ static int axp20x_i2c_probe(struct i2c_client *i2c)
> axp20x->irq = i2c->irq;
> dev_set_drvdata(axp20x->dev, axp20x);
>
> + axp20x->variant = (kernel_ulong_t)i2c_get_match_data(i2c);
[Severity: High]
This isn't a bug introduced by this patch, but because AXP152_ID is defined
as 0, a match failure returning NULL is indistinguishable from a successful
AXP152 match.
Since the driver blindly defaults to AXP152_ID on NULL, it could configure
an unrelated device as an AXP152 PMIC if forced via a sysfs bind. Writing
PMIC configurations to an unrelated I2C device can result in hardware
damage or system crashes.
Should the variant IDs be updated to start from 1 to allow unambiguous
error checking?
> ret = axp20x_match_device(axp20x);
> if (ret)
> return ret;
[ ... ]
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> index 2bbe73afff435..25509e47bedc8 100644
> --- a/drivers/mfd/axp20x.c
> +++ b/drivers/mfd/axp20x.c
> @@ -1339,7 +1339,6 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
> const struct mfd_cell *cells_no_irq = NULL;
> int nr_cells_no_irq = 0;
>
> - axp20x->variant = (long)device_get_match_data(dev);
> switch (axp20x->variant) {
> case AXP152_ID:
> axp20x->nr_cells = ARRAY_SIZE(axp152_cells);
[Severity: High]
This is a pre-existing issue, but there are hard-coded IDs used in the
mfd_cell arrays defined in this file:
drivers/mfd/axp20x.c:axp806_cells[] = {
{
.id = 2,
.name = "axp20x-regulator",
},
};
Using hard-coded IDs in the mfd_cell array bypasses standard subsystem
indexing. This can lead to device naming collisions in sysfs and driver
load failures. A regulator driver load failure here could cause critical
power domains to remain uninitialized, leading to an unusable system.
Would it be possible to use PLATFORM_DEVID_AUTO in mfd_add_devices and
avoid hard-coded id fields in the mfd_cell arrays?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260717-axp318-regulator-v4-0-50aff97084dd@baylibre.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W
2026-07-17 14:43 ` sashiko-bot
@ 2026-07-17 15:36 ` Jerome Brunet
0 siblings, 0 replies; 10+ messages in thread
From: Jerome Brunet @ 2026-07-17 15:36 UTC (permalink / raw)
To: sashiko-bot; +Cc: sashiko-reviews, robh, conor+dt, devicetree
On ven. 17 juil. 2026 at 14:43, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] The `x-powers,axp318w` compatible string was omitted from the conditional block that exempts similar PMIC generations from strictly requiring the `interrupts` property.
> - [Medium] The regex pattern for regulator nodes allows non-existent switched output nodes (`swout3` through `swout9`) to silently pass validation.
> --
>
> --- Patch [1]: [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W ---
> commit 08577b06937ca6f13b4a7f204e7f0abb6042c44d
> Author: Andre Przywara <andre.przywara@arm.com>
>
> dt-bindings: mfd: x-powers,axp152: Document AXP318W
>
> The X-Powers AXP318W is a PMIC used on some newer Allwinner devices.
> This patch adds the new compatible string, updates the PWM frequency
> property list, adds input supply properties, and updates the pattern
> for matching switched outputs.
>
>> diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
>> index 45f015d63df16..95b3984fe0f96 100644
>> --- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
>> +++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
>> @@ -83,6 +83,7 @@ allOf:
>> contains:
>> enum:
>> - x-powers,axp313a
>> + - x-powers,axp318w
>> - x-powers,axp323
>
> [Severity: Medium]
> Should x-powers,axp318w also be added to the earlier conditional block that
> exempts PMICs from requiring the interrupts property?
>
> There is another allOf block in this binding that forces interrupts to be
> required for all devices except a few specific generations:
>
> - if:
> not:
> properties:
> compatible:
> contains:
> enum:
> - x-powers,axp15060
> - x-powers,axp305
> - x-powers,axp313a
> - x-powers,axp323
> then:
> required:
> - interrupts
>
> Since the AXP318W shares constraints with siblings like axp313a and axp323,
> will omitting it from that exemption block cause valid device trees without
> an interrupts property to erroneously fail validation?
No, irq should not be omitted
>
> [ ... ]
>
>> @@ -277,7 +303,7 @@ properties:
>> Defines the work frequency of DC-DC in kHz.
>>
>> patternProperties:
>> - "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
>> + "^(([a-f])?ldo[0-9]|dcdc[0-9a-e]|ldo(_|-)io(0|1)|(dc1)?sw|swout[1-9]|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
>
> [Severity: Medium]
> Could the swout[1-9] pattern allow invalid switched output nodes to silently
> pass validation?
>
> The commit message notes that the PMIC features exactly two switched outputs,
> swout1 and swout2. Allowing swout[1-9] might let device trees with invalid
> nodes or typos like swout3 pass schema validation incorrectly. Would a tighter
> pattern like swout[1-2] be more appropriate here?
It is like that since v1 and has been acked.
It has been loose since forever so if it is an issue, it is defenitely
nothing introduced by this change. Making it strict would require a
different (crazy) regex for each chip.
--
Jerome
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-17 15:36 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-17 14:31 [PATCH v4 0/5] regulator: Add X-Powers AXP318W PMIC support Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 1/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W Jerome Brunet
2026-07-17 14:43 ` sashiko-bot
2026-07-17 15:36 ` Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 2/5] mfd: axp20x: Add support for AXP318W PMIC Jerome Brunet
2026-07-17 14:48 ` sashiko-bot
2026-07-17 14:31 ` [PATCH v4 3/5] mfd: axp20x: Constify axp313 and axp717 cells Jerome Brunet
2026-07-17 14:31 ` [PATCH v4 4/5] mfd: axp20x-i2c: Fix i2c instantiation Jerome Brunet
2026-07-17 14:54 ` sashiko-bot
2026-07-17 14:31 ` [PATCH v4 5/5] regulator: axp20x: add support for the AXP318W Jerome Brunet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox