devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] regulator: Add X-Powers AXP318W PMIC support
@ 2025-10-21 11:20 Andre Przywara
  2025-10-21 11:20 ` [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W Andre Przywara
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Andre Przywara @ 2025-10-21 11:20 UTC (permalink / raw)
  To: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
	devicetree, linux-sunxi, linux-kernel

This patch series adds support for the X-Powers AXP318W PMIC, which is
used recently on new boards with Allwinner SoCs (the A733).
Compared to the RFC post, this now has been tested on real hardware,
with the full regulator description for the Radxa Cubie A7A board.
This also adds the switched outputs (swout1/swout2), and fixes the DCDC
input supplies, which are combined in certain ways.
Rob, I dropped your tag on the binding tag, since there were quite some
changes.

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

Patch 1 adds the compatible string to the binding document, and adds
the additional input supply properties.
Patch 2 is the MFD part, describing the regmap and all the interrupts.
So far we support the regulator and power key devices, the ADC and
other pieces will follow later.
Patch 3 adds the voltage regulator rails, this part is crucial to enable
any board using this PMIC, as we depend on those rails even for basic
devices.

Based on v6.18-rc1.

Please have a look!

Changelog RFC ... v1:
- tested on hardware
- adding switch outputs (swout1/swout2) (to binding and code)
- fixing DC/DC input supplies (in binding and code)


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

 .../bindings/mfd/x-powers,axp152.yaml         |  28 ++-
 drivers/mfd/axp20x-i2c.c                      |   2 +
 drivers/mfd/axp20x.c                          |  84 +++++++++
 drivers/regulator/axp20x-regulator.c          | 170 +++++++++++++++++-
 include/linux/mfd/axp20x.h                    | 129 +++++++++++++
 5 files changed, 410 insertions(+), 3 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W
  2025-10-21 11:20 [PATCH 0/3] regulator: Add X-Powers AXP318W PMIC support Andre Przywara
@ 2025-10-21 11:20 ` Andre Przywara
  2025-10-22 17:38   ` Conor Dooley
  2025-11-03 15:31   ` Chen-Yu Tsai
  2025-10-21 11:20 ` [PATCH 2/3] mfd: axp20x: Add support for AXP318W PMIC Andre Przywara
  2025-10-21 11:20 ` [PATCH 3/3] regulator: axp20x: add support for the AXP318W Andre Przywara
  2 siblings, 2 replies; 14+ messages in thread
From: Andre Przywara @ 2025-10-21 11:20 UTC (permalink / raw)
  To: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
	devicetree, linux-sunxi, linux-kernel

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>
---
 .../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 45f015d63df16..1bed19fc91ec4 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-7a-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.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/3] mfd: axp20x: Add support for AXP318W PMIC
  2025-10-21 11:20 [PATCH 0/3] regulator: Add X-Powers AXP318W PMIC support Andre Przywara
  2025-10-21 11:20 ` [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W Andre Przywara
@ 2025-10-21 11:20 ` Andre Przywara
  2025-11-03 15:49   ` Chen-Yu Tsai
  2025-10-21 11:20 ` [PATCH 3/3] regulator: axp20x: add support for the AXP318W Andre Przywara
  2 siblings, 1 reply; 14+ messages in thread
From: Andre Przywara @ 2025-10-21 11:20 UTC (permalink / raw)
  To: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
	devicetree, linux-sunxi, linux-kernel

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 regulator, interrupts and power key
devices 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>
---
 drivers/mfd/axp20x-i2c.c   |  2 +
 drivers/mfd/axp20x.c       | 84 +++++++++++++++++++++++++++++++++++++
 include/linux/mfd/axp20x.h | 86 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 172 insertions(+)

diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index 5c93136f977e7..4e4ebfc78525c 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 c5f0ebae327f5..be9c59e3de071 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),
@@ -365,6 +391,11 @@ static const struct resource axp313a_pek_resources[] = {
 	DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
 };
 
+static const struct resource axp318_pek_resources[] = {
+	DEFINE_RES_IRQ_NAMED(AXP318_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
+	DEFINE_RES_IRQ_NAMED(AXP318_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
+};
+
 static const struct resource axp717_pek_resources[] = {
 	DEFINE_RES_IRQ_NAMED(AXP717_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
 	DEFINE_RES_IRQ_NAMED(AXP717_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
@@ -444,6 +475,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,
@@ -660,6 +700,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),
@@ -881,6 +943,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,
@@ -1058,6 +1131,11 @@ static struct mfd_cell axp313a_cells[] = {
 	MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
 };
 
+static struct mfd_cell axp318_cells[] = {
+	MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
+	MFD_CELL_RES("axp318w-pek", axp318_pek_resources),
+};
+
 static struct mfd_cell axp717_cells[] = {
 	MFD_CELL_NAME("axp20x-regulator"),
 	MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
@@ -1310,6 +1388,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 3c5aecf1d4b5b..a871789f6cfa9 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
@@ -816,6 +880,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.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-21 11:20 [PATCH 0/3] regulator: Add X-Powers AXP318W PMIC support Andre Przywara
  2025-10-21 11:20 ` [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W Andre Przywara
  2025-10-21 11:20 ` [PATCH 2/3] mfd: axp20x: Add support for AXP318W PMIC Andre Przywara
@ 2025-10-21 11:20 ` Andre Przywara
  2025-10-21 14:27   ` Mark Brown
                     ` (2 more replies)
  2 siblings, 3 replies; 14+ messages in thread
From: Andre Przywara @ 2025-10-21 11:20 UTC (permalink / raw)
  To: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
	devicetree, linux-sunxi, linux-kernel

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.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
 include/linux/mfd/axp20x.h           |  43 +++++++
 2 files changed, 211 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index da891415efc0b..1576bf4178f8f 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -138,6 +138,15 @@
 #define AXP313A_DCDC_V_OUT_MASK		GENMASK(6, 0)
 #define AXP313A_LDO_V_OUT_MASK		GENMASK(4, 0)
 
+#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_DCDC2_NUM_VOLTAGES	88
+#define AXP318_DCDC6_NUM_VOLTAGES	128
+#define AXP318_DCDC7_NUM_VOLTAGES	103
+#define AXP318_DCDC8_NUM_VOLTAGES	119
+
 #define AXP717_DCDC1_NUM_VOLTAGES	88
 #define AXP717_DCDC2_NUM_VOLTAGES	107
 #define AXP717_DCDC3_NUM_VOLTAGES	103
@@ -765,6 +774,155 @@ 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, AXP318_DCDC2_NUM_VOLTAGES,
+			AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)),
+	AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23",
+			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
+			AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)),
+	AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45",
+			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
+			AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)),
+	AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45",
+			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
+			AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)),
+	AXP_DESC_RANGES(AXP318, DCDC6, "dcdc6", "vin678",
+			axp318_dcdc6_ranges, AXP318_DCDC6_NUM_VOLTAGES,
+			AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)),
+	AXP_DESC_RANGES(AXP318, DCDC7, "dcdc7", "vin678",
+			axp318_dcdc7_ranges, AXP318_DCDC7_NUM_VOLTAGES,
+			AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)),
+	AXP_DESC_RANGES(AXP318, DCDC8, "dcdc8", "vin678",
+			axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
+			AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+			AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)),
+	AXP_DESC_RANGES(AXP318, DCDC9, "dcdc9", "vin19",
+			axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
+			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(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100,
+		 AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(0)),
+	AXP_DESC(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100,
+		 AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(1)),
+	AXP_DESC(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100,
+		 AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(2)),
+	AXP_DESC(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100,
+		 AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(3)),
+	AXP_DESC(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100,
+		 AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(4)),
+	AXP_DESC(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100,
+		 AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(5)),
+	AXP_DESC(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100,
+		 AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(6)),
+	AXP_DESC(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100,
+		 AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL1, BIT(7)),
+	AXP_DESC(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100,
+		 AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(0)),
+	AXP_DESC(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100,
+		 AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(1)),
+	AXP_DESC(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100,
+		 AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(2)),
+	AXP_DESC(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100,
+		 AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(3)),
+	AXP_DESC(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100,
+		 AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(4)),
+	AXP_DESC(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100,
+		 AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(5)),
+	AXP_DESC(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100,
+		 AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(6)),
+	AXP_DESC(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100,
+		 AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL2, BIT(7)),
+	AXP_DESC(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100,
+		 AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(0)),
+	AXP_DESC(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100,
+		 AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(1)),
+	AXP_DESC(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100,
+		 AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(2)),
+	AXP_DESC(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100,
+		 AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(3)),
+	AXP_DESC(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100,
+		 AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(4)),
+	AXP_DESC(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100,
+		 AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(5)),
+	AXP_DESC(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
+		 AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(6)),
+	AXP_DESC(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
+		 AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL3, BIT(7)),
+	AXP_DESC(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
+		 AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL4, BIT(0)),
+	AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
+		 AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
+	AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
+		 AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),
+	AXP_DESC(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
+		 AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
+		 AXP318_LDO_OUTPUT_CONTROL4, BIT(3)),
+};
+
 static const struct linear_range axp717_dcdc1_ranges[] = {
 	REGULATOR_LINEAR_RANGE(500000,   0, 70, 10000),
 	REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
@@ -1347,6 +1505,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:
@@ -1585,6 +1744,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 +1814,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 +1874,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 a871789f6cfa9..9957185458d63 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -559,6 +559,49 @@ 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_REG_ID_MAX,
+};
+
 enum {
 	AXP717_DCDC1 = 0,
 	AXP717_DCDC2,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-21 11:20 ` [PATCH 3/3] regulator: axp20x: add support for the AXP318W Andre Przywara
@ 2025-10-21 14:27   ` Mark Brown
  2025-10-22  0:14   ` Yixun Lan
  2025-11-03 16:54   ` Chen-Yu Tsai
  2 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2025-10-21 14:27 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Samuel Holland,
	Jernej Skrabec, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, devicetree, linux-sunxi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 236 bytes --]

On Tue, Oct 21, 2025 at 12:20:12PM +0100, Andre Przywara wrote:
> The X-Powers AXP318W is a typical PMIC from X-Powers, featuring nine
> DC/DC converters and 28 LDOs, on the regulator side.

Reviewed-by: Mark Brown <broonie@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-21 11:20 ` [PATCH 3/3] regulator: axp20x: add support for the AXP318W Andre Przywara
  2025-10-21 14:27   ` Mark Brown
@ 2025-10-22  0:14   ` Yixun Lan
  2025-10-22  0:47     ` Andre Przywara
  2025-11-03 16:28     ` Chen-Yu Tsai
  2025-11-03 16:54   ` Chen-Yu Tsai
  2 siblings, 2 replies; 14+ messages in thread
From: Yixun Lan @ 2025-10-22  0:14 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-sunxi, linux-kernel

Hi Andre,

On 12:20 Tue 21 Oct     , Andre Przywara wrote:
> 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.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
>  include/linux/mfd/axp20x.h           |  43 +++++++
>  2 files changed, 211 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
> index da891415efc0b..1576bf4178f8f 100644
> --- a/drivers/regulator/axp20x-regulator.c
> +++ b/drivers/regulator/axp20x-regulator.c
> @@ -138,6 +138,15 @@
>  #define AXP313A_DCDC_V_OUT_MASK		GENMASK(6, 0)
>  #define AXP313A_LDO_V_OUT_MASK		GENMASK(4, 0)
>  
> +#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_DCDC2_NUM_VOLTAGES	88
> +#define AXP318_DCDC6_NUM_VOLTAGES	128
> +#define AXP318_DCDC7_NUM_VOLTAGES	103
> +#define AXP318_DCDC8_NUM_VOLTAGES	119
> +
>  #define AXP717_DCDC1_NUM_VOLTAGES	88
>  #define AXP717_DCDC2_NUM_VOLTAGES	107
>  #define AXP717_DCDC3_NUM_VOLTAGES	103
> @@ -765,6 +774,155 @@ 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),
> +};

In the AXP318W datasheet, it says:
section 7.1 DCDC/LCO desgin
 8. DCDC6/7/8/9 only able to tune at two voltage ranges which are
 <1.54v and >1.54v, the tuning voltage should not step cross 1.54v
 (I translate the original doc into english)

so, with this restricition, should we split the range into two?
one is dcdc6_lo_range, another dcdc6_hi_range

or what do you think?

> +
> +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, AXP318_DCDC2_NUM_VOLTAGES,
> +			AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)),
> +	AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23",
> +			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> +			AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)),
> +	AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45",
> +			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> +			AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)),
> +	AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45",
> +			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> +			AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)),
> +	AXP_DESC_RANGES(AXP318, DCDC6, "dcdc6", "vin678",
> +			axp318_dcdc6_ranges, AXP318_DCDC6_NUM_VOLTAGES,
> +			AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)),
> +	AXP_DESC_RANGES(AXP318, DCDC7, "dcdc7", "vin678",
> +			axp318_dcdc7_ranges, AXP318_DCDC7_NUM_VOLTAGES,
> +			AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)),
> +	AXP_DESC_RANGES(AXP318, DCDC8, "dcdc8", "vin678",
> +			axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
> +			AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)),
> +	AXP_DESC_RANGES(AXP318, DCDC9, "dcdc9", "vin19",
> +			axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
> +			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(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100,
> +		 AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(0)),
> +	AXP_DESC(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100,
> +		 AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(1)),
> +	AXP_DESC(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100,
> +		 AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(2)),
> +	AXP_DESC(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100,
> +		 AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(3)),
> +	AXP_DESC(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100,
> +		 AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(4)),
> +	AXP_DESC(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100,
> +		 AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(5)),
> +	AXP_DESC(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100,
> +		 AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(6)),
> +	AXP_DESC(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100,
> +		 AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(7)),
> +	AXP_DESC(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100,
> +		 AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(0)),
> +	AXP_DESC(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100,
> +		 AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(1)),
> +	AXP_DESC(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100,
> +		 AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(2)),
> +	AXP_DESC(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100,
> +		 AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(3)),
> +	AXP_DESC(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100,
> +		 AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(4)),
> +	AXP_DESC(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100,
> +		 AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(5)),
> +	AXP_DESC(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100,
> +		 AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(6)),
> +	AXP_DESC(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100,
> +		 AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(7)),
> +	AXP_DESC(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100,
> +		 AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(0)),
> +	AXP_DESC(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100,
> +		 AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(1)),
> +	AXP_DESC(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100,
> +		 AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(2)),
> +	AXP_DESC(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100,
> +		 AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(3)),
> +	AXP_DESC(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100,
> +		 AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(4)),
> +	AXP_DESC(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100,
> +		 AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(5)),
..
> +	AXP_DESC(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
> +		 AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(6)),
> +	AXP_DESC(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
> +		 AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(7)),
> +	AXP_DESC(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
> +		 AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(0)),
> +	AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
> +		 AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
> +	AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
> +		 AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),
> +	AXP_DESC(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
> +		 AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(3)),

also, in section 7.1 DCDC/LCO desgin
 3. ELDOIN can use DCDC's output as the voltage input, once in this case,
 the LDO (output?) config voltage should lower than DCDC input voltage.

Note: ELDOIN can use PS(Power Supply, should be equal to DCIN) or DCDC as input

in case of Radxa A7A (A733) board, it use DCDC9 as ELDOIN,
Should we do something in the driver level? or leave up to user

> +};
> +
>  static const struct linear_range axp717_dcdc1_ranges[] = {
>  	REGULATOR_LINEAR_RANGE(500000,   0, 70, 10000),
>  	REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
> @@ -1347,6 +1505,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:
> @@ -1585,6 +1744,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 +1814,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 +1874,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 a871789f6cfa9..9957185458d63 100644
> --- a/include/linux/mfd/axp20x.h
> +++ b/include/linux/mfd/axp20x.h
> @@ -559,6 +559,49 @@ 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_REG_ID_MAX,
> +};
> +
>  enum {
>  	AXP717_DCDC1 = 0,
>  	AXP717_DCDC2,
> -- 
> 2.25.1
> 

-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-22  0:14   ` Yixun Lan
@ 2025-10-22  0:47     ` Andre Przywara
  2025-10-22  7:58       ` Yixun Lan
  2025-11-03 16:28     ` Chen-Yu Tsai
  1 sibling, 1 reply; 14+ messages in thread
From: Andre Przywara @ 2025-10-22  0:47 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-sunxi, linux-kernel

On Wed, 22 Oct 2025 08:14:20 +0800
Yixun Lan <dlan@gentoo.org> wrote:

Hi,

thanks for having a look!

> Hi Andre,
> 
> On 12:20 Tue 21 Oct     , Andre Przywara wrote:
> > 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.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
> >  include/linux/mfd/axp20x.h           |  43 +++++++
> >  2 files changed, 211 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
> > index da891415efc0b..1576bf4178f8f 100644
> > --- a/drivers/regulator/axp20x-regulator.c
> > +++ b/drivers/regulator/axp20x-regulator.c
> > @@ -138,6 +138,15 @@
> >  #define AXP313A_DCDC_V_OUT_MASK		GENMASK(6, 0)
> >  #define AXP313A_LDO_V_OUT_MASK		GENMASK(4, 0)
> >  
> > +#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_DCDC2_NUM_VOLTAGES	88
> > +#define AXP318_DCDC6_NUM_VOLTAGES	128
> > +#define AXP318_DCDC7_NUM_VOLTAGES	103
> > +#define AXP318_DCDC8_NUM_VOLTAGES	119
> > +
> >  #define AXP717_DCDC1_NUM_VOLTAGES	88
> >  #define AXP717_DCDC2_NUM_VOLTAGES	107
> >  #define AXP717_DCDC3_NUM_VOLTAGES	103
> > @@ -765,6 +774,155 @@ 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),
> > +};  
> 
> In the AXP318W datasheet, it says:
> section 7.1 DCDC/LCO desgin
>  8. DCDC6/7/8/9 only able to tune at two voltage ranges which are
>  <1.54v and >1.54v, the tuning voltage should not step cross 1.54v
>  (I translate the original doc into english)

Thanks, I now read something similar in my Google translated copy of the
datasheet. But I don't understand what this is supposed to mean? That
exactly 1.54V does not work, so the value of 87 is invalid? But any
other value can be set?

> 
> so, with this restricition, should we split the range into two?
> one is dcdc6_lo_range, another dcdc6_hi_range
> 
> or what do you think?
> 
> > +
> > +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, AXP318_DCDC2_NUM_VOLTAGES,
> > +			AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)),
> > +	AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23",
> > +			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> > +			AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)),
> > +	AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45",
> > +			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> > +			AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)),
> > +	AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45",
> > +			axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> > +			AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)),
> > +	AXP_DESC_RANGES(AXP318, DCDC6, "dcdc6", "vin678",
> > +			axp318_dcdc6_ranges, AXP318_DCDC6_NUM_VOLTAGES,
> > +			AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)),
> > +	AXP_DESC_RANGES(AXP318, DCDC7, "dcdc7", "vin678",
> > +			axp318_dcdc7_ranges, AXP318_DCDC7_NUM_VOLTAGES,
> > +			AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)),
> > +	AXP_DESC_RANGES(AXP318, DCDC8, "dcdc8", "vin678",
> > +			axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
> > +			AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +			AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)),
> > +	AXP_DESC_RANGES(AXP318, DCDC9, "dcdc9", "vin19",
> > +			axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
> > +			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(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100,
> > +		 AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(0)),
> > +	AXP_DESC(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100,
> > +		 AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(1)),
> > +	AXP_DESC(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100,
> > +		 AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(2)),
> > +	AXP_DESC(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100,
> > +		 AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(3)),
> > +	AXP_DESC(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100,
> > +		 AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(4)),
> > +	AXP_DESC(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100,
> > +		 AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(5)),
> > +	AXP_DESC(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100,
> > +		 AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(6)),
> > +	AXP_DESC(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100,
> > +		 AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL1, BIT(7)),
> > +	AXP_DESC(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100,
> > +		 AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(0)),
> > +	AXP_DESC(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100,
> > +		 AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(1)),
> > +	AXP_DESC(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100,
> > +		 AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(2)),
> > +	AXP_DESC(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100,
> > +		 AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(3)),
> > +	AXP_DESC(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100,
> > +		 AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(4)),
> > +	AXP_DESC(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100,
> > +		 AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(5)),
> > +	AXP_DESC(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100,
> > +		 AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(6)),
> > +	AXP_DESC(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100,
> > +		 AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL2, BIT(7)),
> > +	AXP_DESC(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100,
> > +		 AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(0)),
> > +	AXP_DESC(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100,
> > +		 AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(1)),
> > +	AXP_DESC(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100,
> > +		 AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(2)),
> > +	AXP_DESC(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100,
> > +		 AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(3)),
> > +	AXP_DESC(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100,
> > +		 AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(4)),
> > +	AXP_DESC(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100,
> > +		 AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(5)),  
> ..
> > +	AXP_DESC(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
> > +		 AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(6)),
> > +	AXP_DESC(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
> > +		 AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(7)),
> > +	AXP_DESC(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
> > +		 AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(0)),
> > +	AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
> > +		 AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
> > +	AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
> > +		 AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),
> > +	AXP_DESC(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
> > +		 AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(3)),  
> 
> also, in section 7.1 DCDC/LCO desgin
>  3. ELDOIN can use DCDC's output as the voltage input, once in this case,
>  the LDO (output?) config voltage should lower than DCDC input voltage.
> 
> Note: ELDOIN can use PS(Power Supply, should be equal to DCIN) or DCDC as input
> 
> in case of Radxa A7A (A733) board, it use DCDC9 as ELDOIN,
> Should we do something in the driver level? or leave up to user

"User" really means board vendor here, right? As the actual board
user is not meant to adjust those voltages anyway, and any range
limitations should be considered during the board design phase.
So yes, DCDC9 is at 1.24V on the Radxa, and ELDOIN is connected to
that, but only ELDO1 and ELDO6 are used, and they are fixed to 900mV
and 800mV, respectively, and connected to SoC pins that require exactly
those voltages. So there is no room for change or to adjust things
here, and the requirements are met.
If board designers/people ignore that, that it just won't work, and
they get to keep the pieces. Nothing the driver can do here.

Cheers,
Andre

> 
> > +};
> > +
> >  static const struct linear_range axp717_dcdc1_ranges[] = {
> >  	REGULATOR_LINEAR_RANGE(500000,   0, 70, 10000),
> >  	REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
> > @@ -1347,6 +1505,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:
> > @@ -1585,6 +1744,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 +1814,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 +1874,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 a871789f6cfa9..9957185458d63 100644
> > --- a/include/linux/mfd/axp20x.h
> > +++ b/include/linux/mfd/axp20x.h
> > @@ -559,6 +559,49 @@ 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_REG_ID_MAX,
> > +};
> > +
> >  enum {
> >  	AXP717_DCDC1 = 0,
> >  	AXP717_DCDC2,
> > -- 
> > 2.25.1
> >   
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-22  0:47     ` Andre Przywara
@ 2025-10-22  7:58       ` Yixun Lan
  2025-10-31  1:22         ` Andre Przywara
  0 siblings, 1 reply; 14+ messages in thread
From: Yixun Lan @ 2025-10-22  7:58 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-sunxi, linux-kernel

Hi Andre,

On 01:47 Wed 22 Oct     , Andre Przywara wrote:
> On Wed, 22 Oct 2025 08:14:20 +0800
> Yixun Lan <dlan@gentoo.org> wrote:
> 
> Hi,
> 
> thanks for having a look!
> 
> > Hi Andre,
> > 
> > On 12:20 Tue 21 Oct     , Andre Przywara wrote:
> > > 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.
> > > 
> > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > > ---
> > >  drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
> > >  include/linux/mfd/axp20x.h           |  43 +++++++
> > >  2 files changed, 211 insertions(+), 2 deletions(-)
> > > 
..
> > > +
> > > +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),
> > > +};  
> > 
> > In the AXP318W datasheet, it says:
> > section 7.1 DCDC/LCO desgin
> >  8. DCDC6/7/8/9 only able to tune at two voltage ranges which are
> >  <1.54v and >1.54v, the tuning voltage should not step cross 1.54v
> >  (I translate the original doc into english)
> 
> Thanks, I now read something similar in my Google translated copy of the
> datasheet. But I don't understand what this is supposed to mean? That
> exactly 1.54V does not work, so the value of 87 is invalid? But any
> other value can be set?
I did a hard chinese - english translation..

No, I think it's probably a mistake that if user interpret value 87 as invalid,
from my understanding, DCDC6-9 only able to tune the voltage in two ranges:
(if user need to adjust the voltage dynamically)

a) range 0.5v - 1.54v (probably include 1.54v)
b) range 1.54v - 1.9v (probably also include 1.54v)

but can not tune in this case, example from range 1.5v - 1.6v which will
cross 1.54v point

I don't understand the logic behind but guess it's up to the HW/SoC
restriction in the design perspective..
> 
> > 
> > so, with this restricition, should we split the range into two?
> > one is dcdc6_lo_range, another dcdc6_hi_range
> > 
> > or what do you think?
> > 
> > ..
> > > +	AXP_DESC(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
> > > +		 AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(6)),
> > > +	AXP_DESC(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
> > > +		 AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(7)),
> > > +	AXP_DESC(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
> > > +		 AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(0)),
> > > +	AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
> > > +		 AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
> > > +	AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
> > > +		 AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),
> > > +	AXP_DESC(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
> > > +		 AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(3)),  
> > 
> > also, in section 7.1 DCDC/LCO desgin
> >  3. ELDOIN can use DCDC's output as the voltage input, once in this case,
> >  the LDO (output?) config voltage should lower than DCDC input voltage.
> > 
> > Note: ELDOIN can use PS(Power Supply, should be equal to DCIN) or DCDC as input
> > 
> > in case of Radxa A7A (A733) board, it use DCDC9 as ELDOIN,
> > Should we do something in the driver level? or leave up to user
> 
> "User" really means board vendor here, right? As the actual board
could be user from software level perspective, who use or design this

> user is not meant to adjust those voltages anyway, and any range
> limitations should be considered during the board design phase.
I'd be fine if push these up to designer, and blame them for wrong usage

> So yes, DCDC9 is at 1.24V on the Radxa, and ELDOIN is connected to
> that, but only ELDO1 and ELDO6 are used, and they are fixed to 900mV
> and 800mV, respectively, and connected to SoC pins that require exactly
> those voltages. So there is no room for change or to adjust things
> here, and the requirements are met.
for this single case, right, we shouldn't worry about..

> If board designers/people ignore that, that it just won't work, and
> they get to keep the pieces. Nothing the driver can do here.
> 
from a driver level, at least we can emit an error message to alert 
user of the wrong voltage value set..

> Cheers,
> Andre
> 

-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W
  2025-10-21 11:20 ` [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W Andre Przywara
@ 2025-10-22 17:38   ` Conor Dooley
  2025-11-03 15:31   ` Chen-Yu Tsai
  1 sibling, 0 replies; 14+ messages in thread
From: Conor Dooley @ 2025-10-22 17:38 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Yixun Lan, devicetree, linux-sunxi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 932 bytes --]

On Tue, Oct 21, 2025 at 12:20:10PM +0100, Andre Przywara wrote:
> 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>

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-22  7:58       ` Yixun Lan
@ 2025-10-31  1:22         ` Andre Przywara
  0 siblings, 0 replies; 14+ messages in thread
From: Andre Przywara @ 2025-10-31  1:22 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Lee Jones, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-sunxi, linux-kernel

On Wed, 22 Oct 2025 15:58:16 +0800
Yixun Lan <dlan@gentoo.org> wrote:

Hi,

> Hi Andre,
> 
> On 01:47 Wed 22 Oct     , Andre Przywara wrote:
> > On Wed, 22 Oct 2025 08:14:20 +0800
> > Yixun Lan <dlan@gentoo.org> wrote:
> > 
> > Hi,
> > 
> > thanks for having a look!
> >   
> > > Hi Andre,
> > > 
> > > On 12:20 Tue 21 Oct     , Andre Przywara wrote:  
> > > > 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.
> > > > 
> > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > > > ---
> > > >  drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
> > > >  include/linux/mfd/axp20x.h           |  43 +++++++
> > > >  2 files changed, 211 insertions(+), 2 deletions(-)
> > > >   
> ..
> > > > +
> > > > +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),
> > > > +};    
> > > 
> > > In the AXP318W datasheet, it says:
> > > section 7.1 DCDC/LCO desgin
> > >  8. DCDC6/7/8/9 only able to tune at two voltage ranges which are
> > >  <1.54v and >1.54v, the tuning voltage should not step cross 1.54v
> > >  (I translate the original doc into english)  
> > 
> > Thanks, I now read something similar in my Google translated copy of the
> > datasheet. But I don't understand what this is supposed to mean? That
> > exactly 1.54V does not work, so the value of 87 is invalid? But any
> > other value can be set?  
> I did a hard chinese - english translation..
> 
> No, I think it's probably a mistake that if user interpret value 87 as invalid,
> from my understanding, DCDC6-9 only able to tune the voltage in two ranges:
> (if user need to adjust the voltage dynamically)
> 
> a) range 0.5v - 1.54v (probably include 1.54v)
> b) range 1.54v - 1.9v (probably also include 1.54v)
> 
> but can not tune in this case, example from range 1.5v - 1.6v which will
> cross 1.54v point.

I am not sure I fully understand: as far is this driver is concerned,
these are just translations from target voltages to register values,
there is no notion of some transition or slope. The upper layer is
free to program any value it wants. So I don't know what the
restriction is, really: is it that the first value programmed to this
register sets a limit? So if you set something below 1.54V, you
cannot program anything higher than that later? And how do you get out
of this, by disabling the output, and re-programming? And do we really
know that, or has someone verified that, or is that just what written
in the manual?

And if that's the case, I don't see how we can model this with the
current driver. It's highly irrelevant anyway, since most voltages
programmed are fixed anyways, and for instance on the Radxa A7E are all
well below 1.54V.

So long story short: I would ignore this until someone reports an
actual issue. For the boards at hand I don't expect any.

> I don't understand the logic behind but guess it's up to the HW/SoC
> restriction in the design perspective..
> >   
> > > 
> > > so, with this restricition, should we split the range into two?
> > > one is dcdc6_lo_range, another dcdc6_hi_range
> > > 
> > > or what do you think?
> > > 
> > > ..  
> > > > +	AXP_DESC(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
> > > > +		 AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(6)),
> > > > +	AXP_DESC(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
> > > > +		 AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > > +		 AXP318_LDO_OUTPUT_CONTROL3, BIT(7)),
> > > > +	AXP_DESC(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
> > > > +		 AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(0)),
> > > > +	AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
> > > > +		 AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
> > > > +	AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
> > > > +		 AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),
> > > > +	AXP_DESC(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
> > > > +		 AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > > > +		 AXP318_LDO_OUTPUT_CONTROL4, BIT(3)),    
> > > 
> > > also, in section 7.1 DCDC/LCO desgin
> > >  3. ELDOIN can use DCDC's output as the voltage input, once in this case,
> > >  the LDO (output?) config voltage should lower than DCDC input voltage.
> > > 
> > > Note: ELDOIN can use PS(Power Supply, should be equal to DCIN) or DCDC as input
> > > 
> > > in case of Radxa A7A (A733) board, it use DCDC9 as ELDOIN,
> > > Should we do something in the driver level? or leave up to user  
> > 
> > "User" really means board vendor here, right? As the actual board  
> could be user from software level perspective, who use or design this

No actual *user* on the software side would program those voltages,
those are all described in the DT. Again, if the board designer didn't
consider this, it's a major fault, and it just wouldn't work.

> > user is not meant to adjust those voltages anyway, and any range
> > limitations should be considered during the board design phase.  
> I'd be fine if push these up to designer, and blame them for wrong usage

Yes.

> > So yes, DCDC9 is at 1.24V on the Radxa, and ELDOIN is connected to
> > that, but only ELDO1 and ELDO6 are used, and they are fixed to 900mV
> > and 800mV, respectively, and connected to SoC pins that require exactly
> > those voltages. So there is no room for change or to adjust things
> > here, and the requirements are met.  
> for this single case, right, we shouldn't worry about..
> 
> > If board designers/people ignore that, that it just won't work, and
> > they get to keep the pieces. Nothing the driver can do here.
> >   
> from a driver level, at least we can emit an error message to alert 
> user of the wrong voltage value set..

But where would you do that? Is there a callback or hook, where we
could check this? I don't see any.

Cheers,
Andre

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W
  2025-10-21 11:20 ` [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W Andre Przywara
  2025-10-22 17:38   ` Conor Dooley
@ 2025-11-03 15:31   ` Chen-Yu Tsai
  1 sibling, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2025-11-03 15:31 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Liam Girdwood, Mark Brown, Samuel Holland,
	Jernej Skrabec, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, devicetree, linux-sunxi, linux-kernel

On Tue, Oct 21, 2025 at 7:20 PM Andre Przywara <andre.przywara@arm.com> wrote:
>
> 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>
> ---
>  .../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 45f015d63df16..1bed19fc91ec4 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-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|swout[1-9]|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":

This and the ever growing list of *-supply properties makes me wonder
whether we should expand the conditional blocks to enforce which names
are valid for whichever models. That could be done later though.

Reviewed-by: Chen-Yu Tsai <wens@kernel.org>

>          $ref: /schemas/regulator/regulator.yaml#
>          type: object
>          unevaluatedProperties: false
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] mfd: axp20x: Add support for AXP318W PMIC
  2025-10-21 11:20 ` [PATCH 2/3] mfd: axp20x: Add support for AXP318W PMIC Andre Przywara
@ 2025-11-03 15:49   ` Chen-Yu Tsai
  0 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2025-11-03 15:49 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Liam Girdwood, Mark Brown, Samuel Holland,
	Jernej Skrabec, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, devicetree, linux-sunxi, linux-kernel

On Tue, Oct 21, 2025 at 7:20 PM Andre Przywara <andre.przywara@arm.com> wrote:
>
> 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 regulator, interrupts and power key
> devices 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>
> ---
>  drivers/mfd/axp20x-i2c.c   |  2 +
>  drivers/mfd/axp20x.c       | 84 +++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/axp20x.h | 86 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 172 insertions(+)
>
> diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
> index 5c93136f977e7..4e4ebfc78525c 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 c5f0ebae327f5..be9c59e3de071 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),
> +};

I'd probably add a .no_ranges for both readable and writeable tables
for the various holes in the register range:

  - 0x00 ~ 0x03
  - 0x08 ~ 0x0f
  - 0x1c
  - 0x44 ~ 0x47
  - 0x4c ~ 0x4f
  - 0x58 ~ 0x5c
  - 0x5e ~ 0x5f
  - 0x61 ~ 0x64
  - 0x6b ~ 0x6f

> +
> +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),
> @@ -365,6 +391,11 @@ static const struct resource axp313a_pek_resources[] = {
>         DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
>  };
>
> +static const struct resource axp318_pek_resources[] = {
> +       DEFINE_RES_IRQ_NAMED(AXP318_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
> +       DEFINE_RES_IRQ_NAMED(AXP318_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
> +};
> +
>  static const struct resource axp717_pek_resources[] = {
>         DEFINE_RES_IRQ_NAMED(AXP717_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
>         DEFINE_RES_IRQ_NAMED(AXP717_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
> @@ -444,6 +475,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,
> @@ -660,6 +700,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),

The datasheet I have (0.1 draft in Chinese) says bit 3 is long press
and bit 4 is short press.


> +       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),
> @@ -881,6 +943,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,
> @@ -1058,6 +1131,11 @@ static struct mfd_cell axp313a_cells[] = {
>         MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
>  };
>
> +static struct mfd_cell axp318_cells[] = {
> +       MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
> +       MFD_CELL_RES("axp318w-pek", axp318_pek_resources),
> +};
> +
>  static struct mfd_cell axp717_cells[] = {
>         MFD_CELL_NAME("axp20x-regulator"),
>         MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
> @@ -1310,6 +1388,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 3c5aecf1d4b5b..a871789f6cfa9 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
>

registers 0x04 ~ 0x07 are data registers. Shall we use them for NVMEM?

> +#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

0x1b and 0x1d control DCDC modes. Or are you leaving out registers that
aren't used?

> +#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
> @@ -816,6 +880,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,

The datasheet I have (0.1 draft in Chinese) says long press comes before
short press.

> +       AXP318_IRQ_PEK_FAL_EDGE,
> +       AXP318_IRQ_PEK_RIS_EDGE,
> +       AXP318_IRQ_GPIO1_INPUT = 20,

AFAICT the interrupt numbers don't have to align with the bit offsets,
even though we've been doing it for past models.

ChenYu

> +       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.25.1
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-22  0:14   ` Yixun Lan
  2025-10-22  0:47     ` Andre Przywara
@ 2025-11-03 16:28     ` Chen-Yu Tsai
  1 sibling, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2025-11-03 16:28 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Andre Przywara, Lee Jones, Liam Girdwood, Mark Brown,
	Samuel Holland, Jernej Skrabec, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, linux-sunxi, linux-kernel

On Wed, Oct 22, 2025 at 8:14 AM Yixun Lan <dlan@gentoo.org> wrote:
>
> Hi Andre,
>
> On 12:20 Tue 21 Oct     , Andre Przywara wrote:
> > 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.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
> >  include/linux/mfd/axp20x.h           |  43 +++++++
> >  2 files changed, 211 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
> > index da891415efc0b..1576bf4178f8f 100644
> > --- a/drivers/regulator/axp20x-regulator.c
> > +++ b/drivers/regulator/axp20x-regulator.c
> > @@ -138,6 +138,15 @@
> >  #define AXP313A_DCDC_V_OUT_MASK              GENMASK(6, 0)
> >  #define AXP313A_LDO_V_OUT_MASK               GENMASK(4, 0)
> >
> > +#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_DCDC2_NUM_VOLTAGES    88
> > +#define AXP318_DCDC6_NUM_VOLTAGES    128
> > +#define AXP318_DCDC7_NUM_VOLTAGES    103
> > +#define AXP318_DCDC8_NUM_VOLTAGES    119
> > +
> >  #define AXP717_DCDC1_NUM_VOLTAGES    88
> >  #define AXP717_DCDC2_NUM_VOLTAGES    107
> >  #define AXP717_DCDC3_NUM_VOLTAGES    103
> > @@ -765,6 +774,155 @@ 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),
> > +};
>
> In the AXP318W datasheet, it says:
> section 7.1 DCDC/LCO desgin
>  8. DCDC6/7/8/9 only able to tune at two voltage ranges which are
>  <1.54v and >1.54v, the tuning voltage should not step cross 1.54v
>  (I translate the original doc into english)
>
> so, with this restricition, should we split the range into two?
> one is dcdc6_lo_range, another dcdc6_hi_range
>
> or what do you think?

I understand it like this:

DCDC2~9 support DVM or dynamic voltage scaling management. Not sure
what the actual thing is, but it at least it provides controlled
ramp rate. So the change of the voltage while the regulator is on
shall not cross the 1.54v boundary; however it is fine to set any
voltage when the regulator is off.

Maybe without DVM the voltage would just jump over and even potentially
overshoot. We would need an oscilloscope to check the actual behavior
though.

So perhaps it would be better to enable DVM by default for all capable
ones, and model in the ramp delay as well? Andre?

As for not crossing 1.54v, I think you can just wrap the current
.set_voltage helper with a check that fails when the regulator is
on and it is crossing?

> > +
> > +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, AXP318_DCDC2_NUM_VOLTAGES,
> > +                     AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)),
> > +     AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23",
> > +                     axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> > +                     AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)),
> > +     AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45",
> > +                     axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> > +                     AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)),
> > +     AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45",
> > +                     axp318_dcdc2_ranges, AXP318_DCDC2_NUM_VOLTAGES,
> > +                     AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)),
> > +     AXP_DESC_RANGES(AXP318, DCDC6, "dcdc6", "vin678",
> > +                     axp318_dcdc6_ranges, AXP318_DCDC6_NUM_VOLTAGES,
> > +                     AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)),
> > +     AXP_DESC_RANGES(AXP318, DCDC7, "dcdc7", "vin678",
> > +                     axp318_dcdc7_ranges, AXP318_DCDC7_NUM_VOLTAGES,
> > +                     AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)),
> > +     AXP_DESC_RANGES(AXP318, DCDC8, "dcdc8", "vin678",
> > +                     axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
> > +                     AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK,
> > +                     AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)),
> > +     AXP_DESC_RANGES(AXP318, DCDC9, "dcdc9", "vin19",
> > +                     axp318_dcdc8_ranges, AXP318_DCDC8_NUM_VOLTAGES,
> > +                     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(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100,
> > +              AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(0)),
> > +     AXP_DESC(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100,
> > +              AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(1)),
> > +     AXP_DESC(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100,
> > +              AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(2)),
> > +     AXP_DESC(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100,
> > +              AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(3)),
> > +     AXP_DESC(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100,
> > +              AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(4)),
> > +     AXP_DESC(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100,
> > +              AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(5)),
> > +     AXP_DESC(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100,
> > +              AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(6)),
> > +     AXP_DESC(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100,
> > +              AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL1, BIT(7)),
> > +     AXP_DESC(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100,
> > +              AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(0)),
> > +     AXP_DESC(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100,
> > +              AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(1)),
> > +     AXP_DESC(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100,
> > +              AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(2)),
> > +     AXP_DESC(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100,
> > +              AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(3)),
> > +     AXP_DESC(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100,
> > +              AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(4)),
> > +     AXP_DESC(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100,
> > +              AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(5)),
> > +     AXP_DESC(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100,
> > +              AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(6)),
> > +     AXP_DESC(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100,
> > +              AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL2, BIT(7)),
> > +     AXP_DESC(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100,
> > +              AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(0)),
> > +     AXP_DESC(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100,
> > +              AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(1)),
> > +     AXP_DESC(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100,
> > +              AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(2)),
> > +     AXP_DESC(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100,
> > +              AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(3)),
> > +     AXP_DESC(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100,
> > +              AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(4)),
> > +     AXP_DESC(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100,
> > +              AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(5)),
> ..
> > +     AXP_DESC(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
> > +              AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(6)),
> > +     AXP_DESC(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
> > +              AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL3, BIT(7)),
> > +     AXP_DESC(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
> > +              AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL4, BIT(0)),
> > +     AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
> > +              AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
> > +     AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
> > +              AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),
> > +     AXP_DESC(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
> > +              AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
> > +              AXP318_LDO_OUTPUT_CONTROL4, BIT(3)),
>
> also, in section 7.1 DCDC/LCO desgin
>  3. ELDOIN can use DCDC's output as the voltage input, once in this case,
>  the LDO (output?) config voltage should lower than DCDC input voltage.
>
> Note: ELDOIN can use PS(Power Supply, should be equal to DCIN) or DCDC as input
>
> in case of Radxa A7A (A733) board, it use DCDC9 as ELDOIN,
> Should we do something in the driver level? or leave up to user

That's up to the designer. They should be aware of any restrictions.
Like, it doesn't make sense to set a voltage higher than the supply
for an LDO...

There's two options here. First, a wrapper for the .set_voltage callback
(again) that checks the requested voltage against the supply voltage,
and returns something like -EINVAL if that check fails.

Second, we could set the .min_dropout_uV field. That would make the core
try to raise the supply voltage to satisfy the minimum dropout voltage
constraint.

Both require knowing the actual minimum dropout value, which doesn't seem
to be provided in the datasheet.


ChenYu

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] regulator: axp20x: add support for the AXP318W
  2025-10-21 11:20 ` [PATCH 3/3] regulator: axp20x: add support for the AXP318W Andre Przywara
  2025-10-21 14:27   ` Mark Brown
  2025-10-22  0:14   ` Yixun Lan
@ 2025-11-03 16:54   ` Chen-Yu Tsai
  2 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2025-11-03 16:54 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Lee Jones, Liam Girdwood, Mark Brown, Samuel Holland,
	Jernej Skrabec, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, devicetree, linux-sunxi, linux-kernel

On Tue, Oct 21, 2025 at 7:20 PM Andre Przywara <andre.przywara@arm.com> wrote:
>
> 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.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  drivers/regulator/axp20x-regulator.c | 170 ++++++++++++++++++++++++++-
>  include/linux/mfd/axp20x.h           |  43 +++++++
>  2 files changed, 211 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
> index da891415efc0b..1576bf4178f8f 100644
> --- a/drivers/regulator/axp20x-regulator.c
> +++ b/drivers/regulator/axp20x-regulator.c
> @@ -138,6 +138,15 @@
>  #define AXP313A_DCDC_V_OUT_MASK                GENMASK(6, 0)
>  #define AXP313A_LDO_V_OUT_MASK         GENMASK(4, 0)
>
> +#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_DCDC2_NUM_VOLTAGES      88
> +#define AXP318_DCDC6_NUM_VOLTAGES      128
> +#define AXP318_DCDC7_NUM_VOLTAGES      103
> +#define AXP318_DCDC8_NUM_VOLTAGES      119

Upon closer inspection of the helper code, these aren't actually needed.
My bad for introducing this unused field in the first place.

[...]

> +       AXP_DESC(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
> +                AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +                AXP318_LDO_OUTPUT_CONTROL4, BIT(1)),
> +       AXP_DESC(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
> +                AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
> +                AXP318_LDO_OUTPUT_CONTROL4, BIT(2)),

eldo4 and eldo5 support operating in switch mode. We can model that as
a bypass mode control. See the *bypass* fields in regulator_desc and
regulator_set_bypass_regmap() / regulator_get_bypass_regmap().

The rest check out. But also see my other reply regarding the 1.54v
threshold.


Thanks
ChenYu

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2025-11-03 16:55 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-21 11:20 [PATCH 0/3] regulator: Add X-Powers AXP318W PMIC support Andre Przywara
2025-10-21 11:20 ` [PATCH 1/3] dt-bindings: mfd: x-powers,axp152: Document AXP318W Andre Przywara
2025-10-22 17:38   ` Conor Dooley
2025-11-03 15:31   ` Chen-Yu Tsai
2025-10-21 11:20 ` [PATCH 2/3] mfd: axp20x: Add support for AXP318W PMIC Andre Przywara
2025-11-03 15:49   ` Chen-Yu Tsai
2025-10-21 11:20 ` [PATCH 3/3] regulator: axp20x: add support for the AXP318W Andre Przywara
2025-10-21 14:27   ` Mark Brown
2025-10-22  0:14   ` Yixun Lan
2025-10-22  0:47     ` Andre Przywara
2025-10-22  7:58       ` Yixun Lan
2025-10-31  1:22         ` Andre Przywara
2025-11-03 16:28     ` Chen-Yu Tsai
2025-11-03 16:54   ` Chen-Yu Tsai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).