linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD
@ 2025-07-15 11:57 AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators AngeloGioacchino Del Regno
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Changes in v4:
 - Rewritten all register definitions for both MT6363 and MT6373
   regulators to be register offsets instead
 - Added the appropriate supply_name to all vregs in 6363 and 6373
 - Simplified the macro parameters for all vregs in 6363 and 6373
   - Added common definitions pattern in macros to avoid plain writing
     register definitions in every macro call
 - Added registration of SPMI sub-device in MT6363/73 and setup of
   regmap reg_base based on `reg` parsed from devicetree
 - Removed interrupts parsing from devicetree
   - Moved (pmic-internal) IRQs to macros
 - mtk-spmi-pmic: Added parsing if irqspec with param_count=2 for
   easier irqs registration from regulator drivers

Changes in v3:
 - Added buck and ldo supplies to mt6363 and mt6373 drivers and bindings;
 - Removed interrupts from mt6363 and mt6373 bindings;
 - Added registering interrupts in mt6363/73 drivers instead:
   this avoids big arrays in the mfd driver, which will grow
   uncontrollably (as it already happened in multiple MediaTek
   drivers) and with each new(future) supported PMIC;
 - Removed "ldo-" and "buck-" prefixes from mt6363 regulators
   - Renamed "vbX" to "vbuckX", reflecting datasheet name
 - Changed all LDOs in MT6363 and MT6373 to add VOCAL usage, both
   increasing the number of voltage steps (2.5 or 10mV increments
   depending on the LDO) and the accuracy of the reported voltages
 - Tested again on MT8196 board

Changes in v2:
 - Merged MFD and regulator in one series
 - Split mediatek,mt6316-regulator.yaml in three files as
   suggested by krzk
 - Added interrupt-names list in MT6363/MT6373 bindings as
   suggested by krzk
 - Documented regulator modes in MT6363/73 as suggested by krzk
 - Fixed interrupt and interrupt-names maxItems in both 6363/73
   because, well... I miscounted them in v1 :-)
 - Removed keys from mt6363 binding: the compatible was not yet
   added to the keys binding and doing that will take quite a
   while, as I have to find a way to test the code before that
   as unfortunately my HW does not provide any way to test the
   PMIC keys (thought it did, but then turns out it doesn't...)
 - Completed the mt6363 MFD example with ADC as suggested by Rob
 - Avoided applying regulator schemas multiple times as pointed
   out by Rob (in mfd binding)
 - Fixed MT6363/73 issues pointed out by lkp (eh, sorry, that
   happened during a last minute cleanup... ugh!).
 - Brewed some more coffee :-)


This series adds support for three new MediaTek PMICs: MT6316, MT6363
and MT6373 and their variants - used in board designs featuring the
MediaTek MT8196 Chromebook SoC, or the MT6991 Dimensity 9400 Smartphone
SoC.

In particular, MT6316 is a regulator, but the MT6363 and MT6373 PMICs
are multi-function devices, as they have and expose multiple sub-devices;
moreover, some of those also contain an interrupt controller, managing
internal IPs interrupts: for those, a chained interrupt handler is
registered, which parent is the SPMI controller itself.

This series adds support for all of the MT6316 regulator variants and
for MT6363, MT6373 SPMI PMICs and their interrupt controller.
AngeloGioacchino Del Regno (8):
  dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators
  regulator: Add support for MediaTek MT6316 SPMI PMIC Regulators
  dt-bindings: regulator: Document MediaTek MT6363 PMIC Regulators
  regulator: Add support for MediaTek MT6363 SPMI PMIC Regulators
  dt-bindings: regulator: Document MediaTek MT6373 PMIC Regulators
  regulator: Add support for MediaTek MT6373 SPMI PMIC Regulators
  dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC
  drivers: mfd: Add support for MediaTek SPMI PMICs and MT6363/73

 .../bindings/mfd/mediatek,mt6363.yaml         | 110 +++
 .../regulator/mediatek,mt6316b-regulator.yaml |  46 +
 .../regulator/mediatek,mt6316c-regulator.yaml |  46 +
 .../regulator/mediatek,mt6316d-regulator.yaml |  41 +
 .../regulator/mediatek,mt6363-regulator.yaml  | 175 ++++
 .../regulator/mediatek,mt6373-regulator.yaml  | 175 ++++
 drivers/mfd/Kconfig                           |  17 +
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/mtk-spmi-pmic.c                   | 410 ++++++++
 drivers/regulator/Kconfig                     |  27 +
 drivers/regulator/Makefile                    |   3 +
 drivers/regulator/mt6316-regulator.c          | 345 +++++++
 drivers/regulator/mt6363-regulator.c          | 934 ++++++++++++++++++
 drivers/regulator/mt6373-regulator.c          | 762 ++++++++++++++
 include/linux/mfd/mt6363.h                    |  26 +
 include/linux/mfd/mt6373.h                    |  21 +
 include/linux/regulator/mt6363-regulator.h    | 331 +++++++
 include/linux/regulator/mt6373-regulator.h    | 162 +++
 18 files changed, 3632 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6363-regulator.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6373-regulator.yaml
 create mode 100644 drivers/mfd/mtk-spmi-pmic.c
 create mode 100644 drivers/regulator/mt6316-regulator.c
 create mode 100644 drivers/regulator/mt6363-regulator.c
 create mode 100644 drivers/regulator/mt6373-regulator.c
 create mode 100644 include/linux/mfd/mt6363.h
 create mode 100644 include/linux/mfd/mt6373.h
 create mode 100644 include/linux/regulator/mt6363-regulator.h
 create mode 100644 include/linux/regulator/mt6373-regulator.h

-- 
2.50.1


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

* [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 13:28   ` AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 2/8] regulator: Add support for MediaTek MT6316 SPMI " AngeloGioacchino Del Regno
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Add bindings for the regulators found in the MediaTek MT6316 PMIC,
usually found in board designs using the MT6991 Dimensity 9400 and
on MT8196 Kompanio SoC for Chromebooks.

This chip is fully controlled by SPMI and has multiple variants
providing different phase configurations.

Link: https://lore.kernel.org/r/20250624073548.29732-2-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-2-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 .../regulator/mediatek,mt6316b-regulator.yaml | 46 +++++++++++++++++++
 .../regulator/mediatek,mt6316c-regulator.yaml | 46 +++++++++++++++++++
 .../regulator/mediatek,mt6316d-regulator.yaml | 41 +++++++++++++++++
 3 files changed, 133 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml

diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
new file mode 100644
index 000000000000..e7a6b70cdab2
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6316b-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6316 BP/VP SPMI PMIC Regulators
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+  The MediaTek MT6316BP/VP PMICs are fully controlled by SPMI interface, both
+  feature four step-down DC/DC (buck) converters, and provides 2+2 Phases,
+  joining Buck 1+2 for the first phase, and Buck 3+4 for the second phase.
+
+properties:
+  compatible:
+    const: mediatek,mt6316b-regulator
+
+  vbuck12:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  vbuck34:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+examples:
+  - |
+    pmic {
+      regulators {
+        compatible = "mediatek,mt6316b-regulator";
+
+        vbuck12 {
+          regulator-min-microvolt = <450000>;
+          regulator-max-microvolt = <965000>;
+          regulator-always-on;
+        };
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
new file mode 100644
index 000000000000..0b9239a595ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6316c-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6316 CP/HP/KP SPMI PMIC Regulators
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+  The MediaTek MT6316CP/HP/KP PMICs are fully controlled by SPMI interface,
+  features four step-down DC/DC (buck) converters, and provides 3+1 Phases,
+  joining Buck 1+2+4 for the first phase, and uses Buck 3 for the second.
+
+properties:
+  compatible:
+    const: mediatek,mt6316c-regulator
+
+  vbuck124:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  vbuck3:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+examples:
+  - |
+    pmic {
+      regulators {
+        compatible = "mediatek,mt6316c-regulator";
+
+        vbuck124 {
+          regulator-min-microvolt = <450000>;
+          regulator-max-microvolt = <1277500>;
+          regulator-always-on;
+        };
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml
new file mode 100644
index 000000000000..460c02bf69de
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6316d-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6316 DP/TP SPMI PMIC Regulators
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+  The MediaTek MT6316DP/TP PMICs are fully controlled by SPMI interface, both
+  feature four step-down DC/DC (buck) converters, and provides a single Phase,
+  joining Buck 1+2+3+4.
+
+properties:
+  compatible:
+    const: mediatek,mt6316d-regulator
+
+  vbuck1234:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+examples:
+  - |
+    pmic {
+      regulators {
+        compatible = "mediatek,mt6316d-regulator";
+
+        vbuck1234 {
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1277500>;
+          regulator-always-on;
+        };
+      };
+    };
+...
-- 
2.50.1


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

* [PATCH v4 2/8] regulator: Add support for MediaTek MT6316 SPMI PMIC Regulators
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 3/8] dt-bindings: regulator: Document MediaTek MT6363 " AngeloGioacchino Del Regno
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Add a driver for the regulators found on all types of the MediaTek
MT6316 SPMI PMIC, fully controlled by SPMI interface and featuring
four step down DCDC (buck) converters.

In particular, this includes support for:
 - MT6316(BP/VP):    2+2 Phase (Phase 1: buck1+2, Phase 2: buck3+4)
 - MT6316(CP/HP/KP): 3+1 Phase (Phase 1: buck1+2+4, Phase 2: buck3)
 - MT6316(DP/TP):    4+0 Phase (Single phase, buck1+2+3+4)

Link: https://lore.kernel.org/r/20250624073548.29732-3-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-3-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/regulator/Kconfig            |   9 +
 drivers/regulator/Makefile           |   1 +
 drivers/regulator/mt6316-regulator.c | 345 +++++++++++++++++++++++++++
 3 files changed, 355 insertions(+)
 create mode 100644 drivers/regulator/mt6316-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 7423954153b0..81f2acd0f960 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -864,6 +864,15 @@ config REGULATOR_MT6315
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6316
+	tristate "MT6316 SPMI PMIC regulator driver"
+	depends on SPMI || COMPILE_TEST
+	help
+          Say Y here to enable support for 2+2, 3+1 and 4 phase regulators
+          found in the MediaTek MT6316 BP, CP, DP, HP, VP and TP SPMI PMICs.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6323
 	tristate "MediaTek MT6323 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index be98b29d6675..46c0e75f6107 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -103,6 +103,7 @@ obj-$(CONFIG_REGULATOR_MP886X) += mp886x.o
 obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o
+obj-$(CONFIG_REGULATOR_MT6315)  += mt6316-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6331)	+= mt6331-regulator.o
 obj-$(CONFIG_REGULATOR_MT6332)	+= mt6332-regulator.o
diff --git a/drivers/regulator/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c
new file mode 100644
index 000000000000..952852bbe923
--- /dev/null
+++ b/drivers/regulator/mt6316-regulator.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+// Copyright (c) 2025 Collabora Ltd
+//                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6316_BUCK_MODE_AUTO			0
+#define MT6316_BUCK_MODE_FORCE_PWM		1
+#define MT6316_BUCK_MODE_LP			2
+
+#define MT6316_CHIP_ID				0x20b
+#define MT6316_BUCK_TOP_CON0			0x1440
+#define EN_SET_OFFSET				0x1
+#define EN_CLR_OFFSET				0x2
+
+#define MT6316_BUCK_TOP_CON1			0x1443
+
+#define MT6316_BUCK_TOP_ELR0			0x1448
+#define MT6316_BUCK_TOP_ELR2			0x144a
+#define MT6316_BUCK_TOP_ELR4			0x144c
+#define MT6316_BUCK_TOP_ELR6			0x144e
+#define MT6316_VSEL_MASK			GENMASK(8, 0)
+
+#define MT6316_VBUCK1_DBG			0x14a8
+#define MT6316_VBUCK2_DBG			0x1528
+#define MT6316_VBUCK3_DBG			0x15a8
+#define MT6316_VBUCK4_DBG			0x1628
+#define MT6316_BUCK_QI				BIT(0)
+
+#define MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0	0x1688
+#define MT6316_BUCK_TOP_4PHASE_TOP_ELR_0	0x1690
+
+enum mt6316_type {
+	MT6316_TYPE_2PHASE,
+	MT6316_TYPE_3PHASE,
+	MT6316_TYPE_4PHASE
+};
+
+/**
+ * struct mt6316_regulator_info - MT6316 regulators information
+ * @desc: Regulator description structure
+ * @debug_reg: Debug register for regulator status
+ * @lp_mode_reg: Low Power mode register (normal/idle)
+ * @lp_mode_mask: Low Power mode regulator mask
+ * @modeset_reg: AUTO/PWM mode register
+ * @modeset_mask: AUTO/PWM regulator mask
+ */
+struct mt6316_regulator_info {
+	struct regulator_desc desc;
+	u16 debug_reg;
+	u16 lp_mode_reg;
+	u16 lp_mode_mask;
+	u16 modeset_reg;
+	u16 modeset_mask;
+};
+
+#define MT6316_BUCK(match, vreg_id, min, max, step, vs_reg)		\
+{									\
+	.desc = {							\
+		.name = match,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6316_vreg_setclr_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min) / step + 1,			\
+		.min_uV = min,						\
+		.uV_step = step,					\
+		.enable_reg = MT6316_BUCK_TOP_CON0,			\
+		.enable_mask = BIT(vreg_id - 1),			\
+		.vsel_reg = vs_reg,					\
+		.vsel_mask = MT6316_VSEL_MASK,				\
+		.of_map_mode = mt6316_map_mode,				\
+	},								\
+	.lp_mode_reg = MT6316_BUCK_TOP_CON1,				\
+	.lp_mode_mask = BIT(vreg_id - 1),				\
+	.modeset_reg = MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0,		\
+	.modeset_mask = BIT(vreg_id - 1),				\
+	.debug_reg = MT6316_VBUCK##vreg_id##_DBG,			\
+}
+
+/* Values in some MT6316 registers are big endian, 9 bits long... */
+static inline u16 mt6316_be9_to_cpu(u16 val)
+{
+	return ((val >> 8) & BIT(0)) | ((val & GENMASK(7, 0)) << 1);
+}
+
+static inline u16 mt6316_cpu_to_be9(u16 val)
+{
+	return ((val & BIT(0)) << 8) | (val >> 1);
+}
+
+static unsigned int mt6316_map_mode(u32 mode)
+{
+	switch (mode) {
+	case MT6316_BUCK_MODE_AUTO:
+		return REGULATOR_MODE_NORMAL;
+	case MT6316_BUCK_MODE_FORCE_PWM:
+		return REGULATOR_MODE_FAST;
+	case MT6316_BUCK_MODE_LP:
+		return REGULATOR_MODE_IDLE;
+	default:
+		return REGULATOR_MODE_INVALID;
+	}
+}
+
+static int mt6316_vreg_enable_setclr(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6316_vreg_disable_setclr(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_CLR_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6316_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+	u16 val = mt6316_cpu_to_be9(selector);
+
+	return regmap_bulk_write(rdev->regmap, rdev->desc->vsel_reg, &val, sizeof(val));
+}
+
+static int mt6316_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+	u16 val;
+	int ret;
+
+	ret = regmap_bulk_read(rdev->regmap, rdev->desc->vsel_reg, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	return mt6316_be9_to_cpu(val & rdev->desc->vsel_mask);
+}
+
+static int mt6316_regulator_get_status(struct regulator_dev *rdev)
+{
+	struct mt6316_regulator_info *info = rdev_get_drvdata(rdev);
+	u32 val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, info->debug_reg, &val);
+	if (ret)
+		return ret;
+
+	return val & MT6316_BUCK_QI ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static unsigned int mt6316_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6316_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to get mode: %d\n", ret);
+		return ret;
+	}
+
+	if ((val & info->modeset_mask) == info->modeset_mask)
+		return REGULATOR_MODE_FAST;
+
+	ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+	val &= info->lp_mode_mask;
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+		return ret;
+	}
+
+	return val ? REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL;
+}
+
+static int mt6316_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6316_regulator_info *info = rdev_get_drvdata(rdev);
+	struct regmap *regmap = rdev->regmap;
+	int cur_mode, ret;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = regmap_set_bits(regmap, info->modeset_reg, info->modeset_mask);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		cur_mode = mt6316_regulator_get_mode(rdev);
+		if (cur_mode < 0) {
+			ret = cur_mode;
+			break;
+		}
+
+		if (cur_mode == REGULATOR_MODE_FAST) {
+			ret = regmap_clear_bits(regmap, info->modeset_reg, info->modeset_mask);
+			break;
+		} else if (cur_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_clear_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+			if (ret == 0)
+				usleep_range(100, 200);
+		} else {
+			ret = 0;
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_set_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to set mode %u: %d\n", mode, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct regulator_ops mt6316_vreg_setclr_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.set_voltage_sel = mt6316_regulator_set_voltage_sel,
+	.get_voltage_sel = mt6316_regulator_get_voltage_sel,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = mt6316_vreg_enable_setclr,
+	.disable = mt6316_vreg_disable_setclr,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6316_regulator_get_status,
+	.set_mode = mt6316_regulator_set_mode,
+	.get_mode = mt6316_regulator_get_mode,
+};
+
+/* MT6316BP/VP - 2+2 phase buck */
+static struct mt6316_regulator_info mt6316bv_regulators[] = {
+	MT6316_BUCK("vbuck12", 1, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR0),
+	MT6316_BUCK("vbuck34", 3, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR4),
+};
+
+/* MT6316CP/HP/KP - 3+1 phase buck */
+static struct mt6316_regulator_info mt6316chk_regulators[] = {
+	MT6316_BUCK("vbuck124", 1, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR0),
+	MT6316_BUCK("vbuck3", 3, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR4),
+};
+
+/* MT6316DP/TP - 4 phase buck */
+static struct mt6316_regulator_info mt6316dt_regulators[] = {
+	MT6316_BUCK("vbuck1234", 1, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR0),
+};
+
+static const struct regmap_config mt6316_spmi_regmap_config = {
+	.reg_bits	= 16,
+	.val_bits	= 8,
+	.max_register	= 0x1700,
+	.fast_io	= true,
+};
+
+static int mt6316_regulator_probe(struct spmi_device *sdev)
+{
+	struct regulator_config config = {};
+	struct mt6316_regulator_info *info;
+	struct regulator_dev *rdev;
+	enum mt6316_type type;
+	int num_vregs, ret;
+	unsigned int i;
+	u32 chip_id;
+
+	config.regmap = devm_regmap_init_spmi_ext(sdev, &mt6316_spmi_regmap_config);
+	if (IS_ERR(config.regmap))
+		return PTR_ERR(config.regmap);
+
+	/*
+	 * The first read is expected to fail: this PMIC needs to be woken up
+	 * and that can be done with any activity over the SPMI bus.
+	 */
+	regmap_read(config.regmap, MT6316_CHIP_ID, &chip_id);
+
+	/* The second read, instead, shall not fail! */
+	ret = regmap_read(config.regmap, MT6316_CHIP_ID, &chip_id);
+	if (ret) {
+		dev_err(&sdev->dev, "Cannot read Chip ID!\n");
+		return ret;
+	}
+	dev_dbg(&sdev->dev, "Chip ID: 0x%x\n", chip_id);
+
+	config.dev = &sdev->dev;
+
+	type = (uintptr_t)device_get_match_data(&sdev->dev);
+	switch (type) {
+	case MT6316_TYPE_2PHASE:
+		info = mt6316bv_regulators;
+		num_vregs = ARRAY_SIZE(mt6316bv_regulators);
+		break;
+	case MT6316_TYPE_3PHASE:
+		info = mt6316chk_regulators;
+		num_vregs = ARRAY_SIZE(mt6316chk_regulators);
+		break;
+	case MT6316_TYPE_4PHASE:
+		info = mt6316dt_regulators;
+		num_vregs = ARRAY_SIZE(mt6316dt_regulators);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_vregs; i++) {
+		config.driver_data = &info[i];
+
+		rdev = devm_regulator_register(&sdev->dev, &info[i].desc, &config);
+		if (IS_ERR(rdev))
+			return dev_err_probe(&sdev->dev, PTR_ERR(rdev),
+					     "failed to register %s\n", info[i].desc.name);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6316_regulator_match[] = {
+	{ .compatible = "mediatek,mt6316b-regulator", .data = (void *)MT6316_TYPE_2PHASE },
+	{ .compatible = "mediatek,mt6316c-regulator", .data = (void *)MT6316_TYPE_3PHASE },
+	{ .compatible = "mediatek,mt6316d-regulator", .data = (void *)MT6316_TYPE_4PHASE },
+	{ /* sentinel */ }
+};
+
+static struct spmi_driver mt6316_regulator_driver = {
+	.driver = {
+		.name = "mt6316-regulator",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+		.of_match_table = mt6316_regulator_match,
+	},
+	.probe = mt6316_regulator_probe,
+};
+module_spmi_driver(mt6316_regulator_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6316 PMIC");
+MODULE_LICENSE("GPL");
-- 
2.50.1


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

* [PATCH v4 3/8] dt-bindings: regulator: Document MediaTek MT6363 PMIC Regulators
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 2/8] regulator: Add support for MediaTek MT6316 SPMI " AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 4/8] regulator: Add support for MediaTek MT6363 SPMI " AngeloGioacchino Del Regno
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Add bindings for the regulators found in the MediaTek MT6363 PMIC,
usually found in board designs using the MT6991 Dimensity 9400 and
on MT8196 Kompanio SoC for Chromebooks, along with the MT6316 and
MT6373 PMICs.

Link: https://lore.kernel.org/r/20250624073548.29732-4-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-4-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 .../regulator/mediatek,mt6363-regulator.yaml  | 175 ++++++++++++++++++
 1 file changed, 175 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6363-regulator.yaml

diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6363-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6363-regulator.yaml
new file mode 100644
index 000000000000..9df57b803edb
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6363-regulator.yaml
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6363-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6363 PMIC Regulators
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+  The MT6363 SPMI PMIC provides 13 BUCK and 25 LDO (Low Dropout) regulators
+  and can optionally provide overcurrent warnings with one ocp interrupt
+  for each voltage regulator.
+
+properties:
+  compatible:
+    const: mediatek,mt6363-regulator
+
+  interrupts:
+    description: Overcurrent warning interrupts
+    minItems: 1
+    maxItems: 38
+
+  interrupt-names:
+    description:
+      Names for the overcurrent interrupts are the same as the name
+      of a regulator (hence the same as each regulator's node name).
+      For example, the interrupt name for regulator ldo-vemc will
+      be "ldo-vemc".
+    minItems: 1
+    maxItems: 38
+    contains:
+      enum:
+        - buck-sshub1
+        - buck-sshub2
+        - buck-sshub4
+        - buck-vb1
+        - buck-vb2
+        - buck-vb3
+        - buck-vb4
+        - buck-vb5
+        - buck-vb6
+        - buck-vb7
+        - buck-vs1
+        - buck-vs2
+        - buck-vs3
+        - ldo-va12-1
+        - ldo-va12-2
+        - ldo-va15
+        - ldo-vaux18
+        - ldo-vcn13
+        - ldo-vcn15
+        - ldo-vemc
+        - ldo-vio0p75
+        - ldo-vio18
+        - ldo-vm18
+        - ldo-vrf0p9
+        - ldo-vrf12
+        - ldo-vrf13
+        - ldo-vrf18
+        - ldo-vrf-io18
+        - ldo-vsram-apu
+        - ldo-vsram-cpub
+        - ldo-vsram-cpum
+        - ldo-vsram-cpul
+        - ldo-vsram-digrf
+        - ldo-vsram-mdfe
+        - ldo-vsram-modem
+        - ldo-vtref18
+        - ldo-vufs12
+        - ldo-vufs18
+
+  isink-load:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  ldo-vemc:
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+patternProperties:
+  "^buck-(sshub[124]|vb[1-7]|vs[1-3])$":
+    description: Buck regulators
+    type: object
+    $ref: regulator.yaml#
+    properties:
+      regulator-allowed-modes:
+        description: |
+          Allowed Buck regulator operating modes allowed. Valid values below.
+            0 - Normal mode with automatic power saving, reducing the switching
+                frequency when light load conditions are detected
+            1 - Forced Continuous Conduction mode (FCCM) for improved voltage
+                regulation accuracy with constant switching frequency but lower
+                regulator efficiency
+            2 - Forced Low Power mode for improved regulator efficiency, used
+                when no heavy load is expected, does not limit the maximum out
+                current but unless only a light load is applied, there will be
+                regulation accuracy and efficiency losses.
+            3 - Forced Ultra Low Power mode for ultra low load, this greatly
+                reduces the maximum output power, makes the regulator to be
+                efficient only for ultra light load, and greatly reduces the
+                quiescent current (Iq) of the buck.
+        maxItems: 3
+        items:
+          enum: [ 0, 1, 2, 3 ]
+    unevaluatedProperties: false
+
+  "^ldo-va(12-1|12-2|15)$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^ldo-v(aux|m|rf-io|tref)18$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^ldo-vcn(13|15)$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^ldo-vio(0p75|18)$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^ldo-vrf(0p9|12|13|18)$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^ldo-vsram-(apu|cpub|cpum|cpul|digrf|mdfe|modem)$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^ldo-vufs(12|18)$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    pmic {
+      interrupt-controller;
+      #interrupt-cells = <3>;
+
+      regulators {
+        compatible = "mediatek,mt6363-regulator";
+        interrupts = <4 16 IRQ_TYPE_LEVEL_HIGH>, <4 17 IRQ_TYPE_LEVEL_HIGH>,
+                     <4 18 IRQ_TYPE_LEVEL_HIGH>, <4 19 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "ldo-vcn15", "ldo-vcn13", "ldo-vrf0p9", "ldo-vrf12";
+
+        ldo-vio18 {
+          regulator-name = "pp1800-vio18-s3";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <1800000>;
+          regulator-allowed-modes = <0 2>;
+          regulator-allow-set-load;
+        };
+      };
+    };
+...
-- 
2.50.1


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

* [PATCH v4 4/8] regulator: Add support for MediaTek MT6363 SPMI PMIC Regulators
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
                   ` (2 preceding siblings ...)
  2025-07-15 11:57 ` [PATCH v4 3/8] dt-bindings: regulator: Document MediaTek MT6363 " AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 5/8] dt-bindings: regulator: Document MediaTek MT6373 " AngeloGioacchino Del Regno
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Add a driver for the regulators found on the MT6363 PMIC, fully
controlled by SPMI interface.
This PMIC regulates voltage with an input range of 2.6-5.0V, and
features 10 buck converters and 26 LDOs.

Link: https://lore.kernel.org/r/20250624073548.29732-5-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-5-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/regulator/Kconfig                  |   9 +
 drivers/regulator/Makefile                 |   1 +
 drivers/regulator/mt6363-regulator.c       | 934 +++++++++++++++++++++
 include/linux/regulator/mt6363-regulator.h | 331 ++++++++
 4 files changed, 1275 insertions(+)
 create mode 100644 drivers/regulator/mt6363-regulator.c
 create mode 100644 include/linux/regulator/mt6363-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 81f2acd0f960..d770e51f7ad1 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -936,6 +936,15 @@ config REGULATOR_MT6360
 	  2-channel buck with Thermal Shutdown and Overload Protection
 	  6-channel High PSRR and Low Dropout LDO.
 
+config REGULATOR_MT6363
+	tristate "MT6363 SPMI PMIC regulator driver"
+	depends on SPMI || COMPILE_TEST
+	help
+          Say Y here to enable support for regulators found in the MediaTek
+          MT6363 SPMI PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6370
 	tristate "MT6370 SubPMIC Regulator"
 	depends on MFD_MT6370
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 46c0e75f6107..41eaeac5547d 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -111,6 +111,7 @@ obj-$(CONFIG_REGULATOR_MT6357)	+= mt6357-regulator.o
 obj-$(CONFIG_REGULATOR_MT6358)	+= mt6358-regulator.o
 obj-$(CONFIG_REGULATOR_MT6359)	+= mt6359-regulator.o
 obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
+obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o
 obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380)	+= mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
new file mode 100644
index 000000000000..e2376ca8cadf
--- /dev/null
+++ b/drivers/regulator/mt6363-regulator.c
@@ -0,0 +1,934 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+// Copyright (c) 2025 Collabora Ltd
+//                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6363-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6363_REGULATOR_MODE_NORMAL	0
+#define MT6363_REGULATOR_MODE_FCCM	1
+#define MT6363_REGULATOR_MODE_LP	2
+#define MT6363_REGULATOR_MODE_ULP	3
+
+#define EN_SET_OFFSET	0x1
+#define EN_CLR_OFFSET	0x2
+#define OP_CFG_OFFSET	0x5
+
+#define NORMAL_OP_CFG	0x10
+#define NORMAL_OP_EN	0x800000
+
+#define OC_IRQ_ENABLE_DELAY_MS		10
+
+/* Unlock keys for TMA and BUCK_TOP */
+#define MT6363_TMA_UNLOCK_VALUE		0x9c9c
+#define MT6363_BUCK_TOP_UNLOCK_VALUE	0x5543
+
+enum {
+	MT6363_ID_VBUCK1,
+	MT6363_ID_VBUCK2,
+	MT6363_ID_VBUCK3,
+	MT6363_ID_VBUCK4,
+	MT6363_ID_VBUCK5,
+	MT6363_ID_VBUCK6,
+	MT6363_ID_VBUCK7,
+	MT6363_ID_VS1,
+	MT6363_ID_VS2,
+	MT6363_ID_VS3,
+	MT6363_ID_VA12_1,
+	MT6363_ID_VA12_2,
+	MT6363_ID_VA15,
+	MT6363_ID_VAUX18,
+	MT6363_ID_VCN13,
+	MT6363_ID_VCN15,
+	MT6363_ID_VEMC,
+	MT6363_ID_VIO075,
+	MT6363_ID_VIO18,
+	MT6363_ID_VM18,
+	MT6363_ID_VSRAM_APU,
+	MT6363_ID_VSRAM_CPUB,
+	MT6363_ID_VSRAM_CPUM,
+	MT6363_ID_VSRAM_CPUL,
+	MT6363_ID_VSRAM_DIGRF,
+	MT6363_ID_VSRAM_MDFE,
+	MT6363_ID_VSRAM_MODEM,
+	MT6363_ID_VRF09,
+	MT6363_ID_VRF12,
+	MT6363_ID_VRF13,
+	MT6363_ID_VRF18,
+	MT6363_ID_VRFIO18,
+	MT6363_ID_VTREF18,
+	MT6363_ID_VUFS12,
+	MT6363_ID_VUFS18,
+};
+
+/**
+ * struct mt6363_regulator_info - MT6363 regulators information
+ * @desc: Regulator description structure
+ * @lp_mode_reg: Low Power mode register (normal/idle)
+ * @lp_mode_mask: Low Power mode regulator mask
+ * @hw_lp_mode_reg: Hardware voted Low Power mode register (normal/idle)
+ * @hw_lp_mode_mask: Hardware voted Low Power mode regulator mask
+ * @modeset_reg: AUTO/PWM mode register
+ * @modeset_mask: AUTO/PWM regulator mask
+ * @lp_imax_uA: Maximum load current (microamps), for Low Power mode only
+ * @op_en_reg: Operation mode enablement register
+ * @orig_op_en: Backup of a regulator's operation mode enablement register
+ * @orig_op_cfg: Backup of a regulator's operation mode configuration register
+ * @oc_work: Delayed work for enabling overcurrent IRQ
+ * @hwirq: PMIC-Internal HW Interrupt for overcurrent event
+ * @virq: Mapped Interrupt for overcurrent event
+ */
+struct mt6363_regulator_info {
+	struct regulator_desc desc;
+	u16 lp_mode_reg;
+	u16 lp_mode_mask;
+	u16 hw_lp_mode_reg;
+	u16 hw_lp_mode_mask;
+	u16 modeset_reg;
+	u16 modeset_mask;
+	int lp_imax_uA;
+	u16 op_en_reg;
+	u32 orig_op_en;
+	u8 orig_op_cfg;
+	struct delayed_work oc_work;
+	u8 hwirq;
+	int virq;
+};
+
+#define MT6363_BUCK(match, vreg, min, max, step, en_reg, lp_reg,	\
+		    mset_reg, ocp_intn)					\
+[MT6363_ID_##vreg] = {							\
+	.desc = {							\
+		.name = match,						\
+		.supply_name = "vsys-"match,				\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6363_vreg_setclr_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6363_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min) / step + 1,			\
+		.min_uV = min,						\
+		.uV_step = step,					\
+		.enable_reg = en_reg,					\
+		.enable_mask = BIT(MT6363_RG_BUCK_##vreg##_EN_BIT),	\
+		.vsel_reg = MT6363_RG_BUCK_##vreg##_VOSEL_ADDR,		\
+		.vsel_mask = MT6363_RG_BUCK_##vreg##_VOSEL_MASK,	\
+		.of_map_mode = mt6363_map_mode,				\
+	},								\
+	.lp_mode_reg = lp_reg,						\
+	.lp_mode_mask = BIT(MT6363_RG_BUCK_##vreg##_LP_BIT),		\
+	.hw_lp_mode_reg = MT6363_BUCK_##vreg##_HW_LP_MODE,		\
+	.hw_lp_mode_mask = 0xc,						\
+	.modeset_reg = mset_reg,					\
+	.modeset_mask = BIT(MT6363_RG_##vreg##_FCCM_BIT),		\
+	.lp_imax_uA = 100000,						\
+	.op_en_reg = MT6363_BUCK_##vreg##_OP_EN_0,			\
+	.hwirq = ocp_intn,						\
+}
+
+#define MT6363_LDO_LINEAR_OPS(match, vreg, in_sup, vops, min, max,	\
+			      step, buck_reg, ocp_intn)			\
+[MT6363_ID_##vreg] = {							\
+	.desc = {							\
+		.name = match,						\
+		.supply_name = in_sup,					\
+		.of_match = of_match_ptr(match),			\
+		.ops = &vops,						\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6363_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min) / step + 1,			\
+		.min_uV = min,						\
+		.uV_step = step,					\
+		.enable_reg = MT6363_RG_##buck_reg##_EN_ADDR,		\
+		.enable_mask = BIT(MT6363_RG_LDO_##vreg##_EN_BIT),	\
+		.vsel_reg = MT6363_RG_LDO_##vreg##_VOSEL_ADDR,		\
+		.vsel_mask = MT6363_RG_LDO_##vreg##_VOSEL_MASK,		\
+		.of_map_mode = mt6363_map_mode,				\
+	},								\
+	.lp_mode_reg = MT6363_RG_##buck_reg##_LP_ADDR,			\
+	.lp_mode_mask = BIT(MT6363_RG_LDO_##vreg##_LP_BIT),		\
+	.hw_lp_mode_reg = MT6363_LDO_##vreg##_HW_LP_MODE,		\
+	.hw_lp_mode_mask = 0x4,						\
+	.hwirq = ocp_intn,						\
+}
+
+#define MT6363_LDO_L_SC(match, vreg, inp, min, max, step, buck_reg,	\
+			ocp_intn)					\
+	MT6363_LDO_LINEAR_OPS(match, vreg, inp, mt6363_vreg_setclr_ops,	\
+			      min, max, step, buck_reg, ocp_intn)
+
+#define MT6363_LDO_L(match, vreg, inp, min, max, step, buck_reg,	\
+		     ocp_intn)						\
+	MT6363_LDO_LINEAR_OPS(match, vreg, inp, mt6363_ldo_linear_ops,	\
+			      min, max, step, buck_reg, ocp_intn)
+
+#define MT6363_LDO_LINEAR_CAL_OPS(match, vreg, in_sup, vops, vrnum,	\
+				  ocp_intn)				\
+[MT6363_ID_##vreg] = {							\
+	.desc = {							\
+		.name = match,						\
+		.supply_name = in_sup,					\
+		.of_match = of_match_ptr(match),			\
+		.ops = &vops,						\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6363_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_ranges##vrnum) * 11,	\
+		.linear_ranges = ldo_volt_ranges##vrnum,		\
+		.n_linear_ranges = ARRAY_SIZE(ldo_volt_ranges##vrnum),	\
+		.linear_range_selectors_bitfield = ldos_cal_selectors,	\
+		.enable_reg = MT6363_RG_LDO_##vreg##_ADDR,		\
+		.enable_mask = BIT(MT6363_RG_LDO_##vreg##_EN_BIT),	\
+		.vsel_reg = MT6363_RG_##vreg##_VOCAL_ADDR,		\
+		.vsel_mask = MT6363_RG_##vreg##_VOCAL_MASK,		\
+		.vsel_range_reg = MT6363_RG_##vreg##_VOSEL_ADDR,	\
+		.vsel_range_mask = MT6363_RG_##vreg##_VOSEL_MASK,	\
+		.of_map_mode = mt6363_map_mode,				\
+	},								\
+	.lp_mode_reg = MT6363_RG_LDO_##vreg##_ADDR,			\
+	.lp_mode_mask = BIT(MT6363_RG_LDO_##vreg##_LP_BIT),		\
+	.hw_lp_mode_reg = MT6363_LDO_##vreg##_HW_LP_MODE,		\
+	.hw_lp_mode_mask = 0x4,						\
+	.lp_imax_uA = 10000,						\
+	.op_en_reg = MT6363_LDO_##vreg##_OP_EN0,			\
+	.hwirq = ocp_intn,						\
+}
+
+#define MT6363_LDO_VT(match, vreg, inp, vranges_num, ocp_intn)		\
+	MT6363_LDO_LINEAR_CAL_OPS(match, vreg, inp, mt6363_ldo_vtable_ops,\
+				  vranges_num, ocp_intn)
+
+static const unsigned int ldos_cal_selectors[] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const struct linear_range ldo_volt_ranges0[] = {
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3500000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges1[] = {
+	REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1810000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges2[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges3[] = {
+	REGULATOR_LINEAR_RANGE(600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges4[] = {
+	REGULATOR_LINEAR_RANGE(550000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(600000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(650000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(700000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(750000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(800000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(900000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(950000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1000000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1050000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1100000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1150000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1750000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(1850000, 0, 10, 5000)
+};
+
+static const struct linear_range ldo_volt_ranges5[] = {
+	REGULATOR_LINEAR_RANGE(600000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(650000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(700000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(750000, 0, 10, 5000),
+	REGULATOR_LINEAR_RANGE(800000, 0, 10, 5000)
+};
+
+static int mt6363_vreg_enable_setclr(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6363_vreg_disable_setclr(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_CLR_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static inline unsigned int mt6363_map_mode(unsigned int mode)
+{
+	switch (mode) {
+	case MT6363_REGULATOR_MODE_NORMAL:
+		return REGULATOR_MODE_NORMAL;
+	case MT6363_REGULATOR_MODE_FCCM:
+		return REGULATOR_MODE_FAST;
+	case MT6363_REGULATOR_MODE_LP:
+		return REGULATOR_MODE_IDLE;
+	case MT6363_REGULATOR_MODE_ULP:
+		return REGULATOR_MODE_STANDBY;
+	default:
+		return REGULATOR_MODE_INVALID;
+	}
+}
+
+static unsigned int mt6363_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret;
+
+	if (info->modeset_reg) {
+		ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+		if (ret) {
+			dev_err(&rdev->dev, "Failed to get mt6363 mode: %d\n", ret);
+			return ret;
+		}
+
+		if (val & info->modeset_mask)
+			return REGULATOR_MODE_FAST;
+	} else {
+		val = 0;
+	};
+
+	ret = regmap_read(rdev->regmap, info->hw_lp_mode_reg, &val);
+	val &= info->hw_lp_mode_mask;
+
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+		return ret;
+	}
+
+	if (val)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6363_buck_unlock(struct regmap *map, bool unlock)
+{
+	u16 buf = unlock ? MT6363_BUCK_TOP_UNLOCK_VALUE : 0;
+
+	return regmap_bulk_write(map, MT6363_BUCK_TOP_KEY_PROT_LO, &buf, sizeof(buf));
+}
+
+static int mt6363_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+	struct regmap *regmap = rdev->regmap;
+	int cur_mode, ret;
+
+	if (!info->modeset_reg && mode == REGULATOR_MODE_FAST)
+		return -EOPNOTSUPP;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = mt6363_buck_unlock(regmap, true);
+		if (ret)
+			break;
+
+		ret = regmap_set_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+		mt6363_buck_unlock(regmap, false);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		cur_mode = mt6363_regulator_get_mode(rdev);
+		if (cur_mode < 0) {
+			ret = cur_mode;
+			break;
+		}
+
+		if (cur_mode == REGULATOR_MODE_FAST) {
+			ret = mt6363_buck_unlock(regmap, true);
+			if (ret)
+				break;
+
+			ret = regmap_clear_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+			mt6363_buck_unlock(regmap, false);
+			break;
+		} else if (cur_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_clear_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+			if (ret == 0)
+				usleep_range(100, 200);
+		} else {
+			ret = 0;
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_set_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to set mode %u: %d\n", mode, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt6363_regulator_set_load(struct regulator_dev *rdev, int load_uA)
+{
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int opmode_cfg, opmode_en;
+	int i, ret;
+
+	if (!info->lp_imax_uA)
+		return -EINVAL;
+
+	if (load_uA >= info->lp_imax_uA) {
+		ret = mt6363_regulator_set_mode(rdev, REGULATOR_MODE_NORMAL);
+		if (ret)
+			return ret;
+
+		opmode_cfg = NORMAL_OP_CFG;
+		opmode_en = NORMAL_OP_EN;
+	} else {
+		opmode_cfg = info->orig_op_cfg;
+		opmode_en = info->orig_op_en;
+	}
+
+	ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET, opmode_cfg);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 3; i++) {
+		ret = regmap_write(rdev->regmap, info->op_en_reg + i,
+				   (opmode_en >> (i * 8)) & GENMASK(7, 0));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mt6363_vemc_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	const u16 tma_unlock_key = MT6363_TMA_UNLOCK_VALUE;
+	const struct regulator_desc *rdesc = rdev->desc;
+	struct regmap *regmap = rdev->regmap;
+	unsigned int range, val;
+	int i, ret;
+	u16 mask;
+
+	for (i = 0; i < rdesc->n_linear_ranges; i++) {
+		const struct linear_range *r = &rdesc->linear_ranges[i];
+		unsigned int voltages_in_range = linear_range_values_in_range(r);
+
+		if (sel < voltages_in_range)
+			break;
+		sel -= voltages_in_range;
+	}
+
+	if (i == rdesc->n_linear_ranges)
+		return -EINVAL;
+
+	ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val);
+	if (ret)
+		return ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	/* Unlock TMA for writing */
+	ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L,
+				&tma_unlock_key, sizeof(tma_unlock_key));
+	if (ret)
+		return ret;
+
+	/* If HW trapping value is 1, use VEMC_VOSEL_1 instead of VEMC_VOSEL_0 */
+	if (val == 1) {
+		mask = MT6363_RG_VEMC_VOSEL_1_MASK;
+		sel = FIELD_PREP(MT6363_RG_VEMC_VOSEL_1_MASK, sel);
+	} else {
+		mask = rdesc->vsel_mask;
+	}
+
+	sel <<= ffs(rdesc->vsel_mask) - 1;
+	sel += rdesc->linear_ranges[i].min_sel;
+
+	range = rdesc->linear_range_selectors_bitfield[i];
+	range <<= ffs(rdesc->vsel_range_mask) - 1;
+
+	/* Write to the vreg calibration register for voltage finetuning */
+	ret = regmap_update_bits(regmap, rdesc->vsel_range_reg,
+				 rdesc->vsel_range_mask, range);
+	if (ret)
+		goto lock_tma;
+
+	/* Function must return the result of this write operation */
+	ret = regmap_update_bits(regmap, rdesc->vsel_reg, mask, sel);
+
+lock_tma:
+	/* Unconditionally re-lock TMA */
+	val = 0;
+	regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &val, 2);
+
+	return ret;
+}
+
+static int mt6363_vemc_get_voltage_sel(struct regulator_dev *rdev)
+{
+	const struct regulator_desc *rdesc = rdev->desc;
+	unsigned int vosel, trap, calsel;
+	int vcal, vsel, range, ret;
+
+	ret = regmap_read(rdev->regmap, rdesc->vsel_reg, &vosel);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(rdev->regmap, rdesc->vsel_range_reg, &calsel);
+	if (ret)
+		return ret;
+
+	calsel &= rdesc->vsel_range_mask;
+	for (range = 0; range < rdesc->n_linear_ranges; range++)
+		if (rdesc->linear_range_selectors_bitfield[range] != calsel)
+			break;
+
+	if (range == rdesc->n_linear_ranges)
+		return -EINVAL;
+
+	ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &trap);
+	if (ret)
+		return ret;
+
+	/* If HW trapping value is 1, use VEMC_VOSEL_1 instead of VEMC_VOSEL_0 */
+	if (trap > 1)
+		return -EINVAL;
+	else if (trap == 1)
+		vsel = FIELD_GET(MT6363_RG_VEMC_VOSEL_1_MASK, vosel);
+	else
+		vsel = vosel & rdesc->vsel_mask;
+
+	vcal = linear_range_values_in_range_array(rdesc->linear_ranges, range);
+
+	return vsel + vcal;
+}
+
+static int mt6363_va15_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	struct regmap *regmap = rdev->regmap;
+	int ret;
+
+	ret = mt6363_buck_unlock(regmap, true);
+	if (ret)
+		return ret;
+
+	ret = regulator_set_voltage_sel_pickable_regmap(rdev, sel);
+	if (ret)
+		goto va15_unlock;
+
+	ret = regmap_update_bits(regmap, MT6363_RG_BUCK_EFUSE_RSV1,
+				 MT6363_RG_BUCK_EFUSE_RSV1_MASK, sel);
+	if (ret)
+		goto va15_unlock;
+
+va15_unlock:
+	mt6363_buck_unlock(rdev->regmap, false);
+	return ret;
+}
+
+static void mt6363_oc_irq_enable_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct mt6363_regulator_info *info =
+		container_of(dwork, struct mt6363_regulator_info, oc_work);
+
+	enable_irq(info->virq);
+}
+
+static irqreturn_t mt6363_oc_isr(int irq, void *data)
+{
+	struct regulator_dev *rdev = (struct regulator_dev *)data;
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+
+	disable_irq_nosync(info->virq);
+
+	if (regulator_is_enabled_regmap(rdev))
+		regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
+
+	schedule_delayed_work(&info->oc_work, msecs_to_jiffies(OC_IRQ_ENABLE_DELAY_MS));
+
+	return IRQ_HANDLED;
+}
+
+static int mt6363_set_ocp(struct regulator_dev *rdev, int lim, int severity, bool enable)
+{
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+
+	/* MT6363 supports only enabling protection and does not support limits */
+	if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+		return -EOPNOTSUPP;
+
+	/* If there is no OCP interrupt, there's nothing to set */
+	if (info->virq <= 0)
+		return -EOPNOTSUPP;
+
+	return devm_request_threaded_irq(&rdev->dev, info->virq, NULL,
+					 mt6363_oc_isr, IRQF_ONESHOT,
+					 info->desc.name, rdev);
+}
+
+static const struct regulator_ops mt6363_vreg_setclr_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = mt6363_vreg_enable_setclr,
+	.disable = mt6363_vreg_disable_setclr,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_load = mt6363_regulator_set_load,
+	.set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_linear_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_vtable_ops = {
+	.list_voltage = regulator_list_voltage_pickable_linear_range,
+	.map_voltage = regulator_map_voltage_pickable_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_load = mt6363_regulator_set_load,
+	.set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_vemc_ops = {
+	.list_voltage = regulator_list_voltage_pickable_linear_range,
+	.map_voltage = regulator_map_voltage_pickable_linear_range,
+	.set_voltage_sel = mt6363_vemc_set_voltage_sel,
+	.get_voltage_sel = mt6363_vemc_get_voltage_sel,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_load = mt6363_regulator_set_load,
+	.set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_va15_ops = {
+	.list_voltage = regulator_list_voltage_pickable_linear_range,
+	.map_voltage = regulator_map_voltage_pickable_linear_range,
+	.set_voltage_sel = mt6363_va15_set_voltage_sel,
+	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_load = mt6363_regulator_set_load,
+	.set_over_current_protection = mt6363_set_ocp,
+};
+
+/* The array is indexed by id(MT6363_ID_XXX) */
+static struct mt6363_regulator_info mt6363_regulators[] = {
+	MT6363_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 1),
+	MT6363_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 2),
+	MT6363_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 3),
+	MT6363_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 4),
+	MT6363_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 5),
+	MT6363_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 6),
+	MT6363_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 7),
+	MT6363_BUCK("vs1", VS1, 0, 2200000, 12500, MT6363_RG_BUCK1_EN_ADDR,
+		    MT6363_RG_BUCK1_LP_ADDR, MT6363_RG_VS1_FCCM_ADDR, 8),
+	MT6363_BUCK("vs2", VS2, 0, 1600000, 12500, MT6363_RG_BUCK0_EN_ADDR,
+		    MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 0),
+	MT6363_BUCK("vs3", VS3, 0, 1193750, 6250, MT6363_RG_BUCK1_EN_ADDR,
+		    MT6363_RG_BUCK1_LP_ADDR, MT6363_RG_VS3_FCCM_ADDR, 9),
+	MT6363_LDO_VT("va12-1", VA12_1, "vs2-ldo2", 3, 37),
+	MT6363_LDO_VT("va12-2", VA12_2, "vs2-ldo2", 3, 38),
+	MT6363_LDO_LINEAR_CAL_OPS("va15", VA15, "vs1-ldo1", mt6363_ldo_va15_ops, 3, 39),
+	MT6363_LDO_VT("vaux18", VAUX18, "vsys-ldo1", 2, 31),
+	MT6363_LDO_VT("vcn13", VCN13, "vs2-ldo2", 1, 17),
+	MT6363_LDO_VT("vcn15", VCN15, "vs1-ldo2", 3, 16),
+	MT6363_LDO_LINEAR_CAL_OPS("vemc", VEMC, "vsys-ldo1", mt6363_ldo_vemc_ops, 0, 32),
+	MT6363_LDO_VT("vio0p75", VIO075, "vs1-ldo1", 5, 36),
+	MT6363_LDO_VT("vio18", VIO18, "vs1-ldo2", 3, 35),
+	MT6363_LDO_VT("vm18", VM18, "vs1-ldo1", 4, 40),
+	MT6363_LDO_L("vsram-apu", VSRAM_APU, "vs3-ldo1", 400000, 1193750, 6250, BUCK1, 30),
+	MT6363_LDO_L("vsram-cpub", VSRAM_CPUB, "vs2-ldo1", 400000, 1193750, 6250, BUCK1, 27),
+	MT6363_LDO_L("vsram-cpum", VSRAM_CPUM, "vs2-ldo1", 400000, 1193750, 6250, BUCK1, 28),
+	MT6363_LDO_L("vsram-cpul", VSRAM_CPUL, "vs2-ldo2", 400000, 1193750, 6250, BUCK1, 29),
+	MT6363_LDO_L_SC("vsram-digrf", VSRAM_DIGRF, "vs3-ldo1", 400000, 1193750, 6250, BUCK1, 23),
+	MT6363_LDO_L_SC("vsram-mdfe", VSRAM_MDFE, "vs3-ldo1", 400000, 1193750, 6250, BUCK1, 24),
+	MT6363_LDO_L_SC("vsram-modem", VSRAM_MODEM, "vs3-ldo2", 400000, 1193750, 6250, BUCK1, 25),
+	MT6363_LDO_VT("vrf0p9", VRF09, "vs3-ldo2", 1, 18),
+	MT6363_LDO_VT("vrf12", VRF12, "vs2-ldo1", 3, 19),
+	MT6363_LDO_VT("vrf13", VRF13, "vs2-ldo1", 1, 20),
+	MT6363_LDO_VT("vrf18", VRF18, "vs1-ldo1", 3, 21),
+	MT6363_LDO_VT("vrf-io18", VRFIO18, "vs1-ldo1", 3, 22),
+	MT6363_LDO_VT("vtref18", VTREF18, "vsys-ldo1", 2, 26),
+	MT6363_LDO_VT("vufs12", VUFS12, "vs2-ldo1", 4, 33),
+	MT6363_LDO_VT("vufs18", VUFS18, "vs1-ldo2", 3, 34),
+};
+
+static int mt6363_backup_op_setting(struct regmap *map, struct mt6363_regulator_info *info)
+{
+	unsigned int i, val;
+	int ret;
+
+	ret = regmap_read(map, info->op_en_reg + OP_CFG_OFFSET, &val);
+	if (ret)
+		return ret;
+
+	info->orig_op_cfg = val;
+
+	for (i = 0; i < 3; i++) {
+		ret = regmap_read(map, info->op_en_reg + i, &val);
+		if (ret)
+			return ret;
+
+		info->orig_op_en |= val << (i * 8);
+	}
+
+	return 0;
+}
+
+static void mt6363_irq_remove(void *data)
+{
+	int *virq = data;
+
+	irq_dispose_mapping(*virq);
+}
+
+static void mt6363_spmi_remove(void *data)
+{
+	struct spmi_device *sdev = data;
+
+	spmi_device_remove(sdev);
+};
+
+static struct regmap *mt6363_spmi_register_regmap(struct device *dev)
+{
+	struct regmap_config mt6363_regmap_config = {
+		.reg_bits = 16,
+		.val_bits = 16,
+		.max_register = 0x1f90,
+		.fast_io = true,
+	};
+	struct spmi_device *sdev, *sparent;
+	u32 base;
+	int ret;
+
+	if (!dev->parent)
+		return ERR_PTR(-ENODEV);
+
+	ret = device_property_read_u32(dev, "reg", &base);
+	if (ret)
+		return ERR_PTR(ret);
+
+	sparent = to_spmi_device(dev->parent);
+	if (!sparent)
+		return ERR_PTR(-ENODEV);
+
+	sdev = spmi_device_alloc(sparent->ctrl);
+	if (!sdev)
+		return ERR_PTR(-ENODEV);
+
+	sdev->usid = sparent->usid;
+	dev_set_name(&sdev->dev, "%d-%02x-regulator", sdev->ctrl->nr, sdev->usid);
+	ret = device_add(&sdev->dev);
+	if (ret) {
+		put_device(&sdev->dev);
+		return ERR_PTR(ret);
+	};
+
+	ret = devm_add_action_or_reset(dev, mt6363_spmi_remove, sdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mt6363_regmap_config.reg_base = base;
+
+	return devm_regmap_init_spmi_ext(sdev, &mt6363_regmap_config);
+}
+
+static int mt6363_regulator_probe(struct platform_device *pdev)
+{
+	struct irq_fwspec fwspec = {
+		.param_count = 2,
+		.param = { 0, IRQ_TYPE_LEVEL_HIGH },
+	};
+	struct device_node *interrupt_parent;
+	struct regulator_config config = {};
+	struct mt6363_regulator_info *info;
+	struct device *dev = &pdev->dev;
+	struct regulator_dev *rdev;
+	struct irq_domain *domain;
+	int i, ret;
+
+	config.regmap = mt6363_spmi_register_regmap(dev);
+	if (!config.regmap)
+		return dev_err_probe(dev, PTR_ERR(config.regmap),
+				     "Cannot get regmap\n");
+	config.dev = dev;
+
+	interrupt_parent = of_irq_find_parent(dev->of_node);
+	if (!interrupt_parent)
+		return dev_err_probe(dev, -EINVAL, "Cannot find IRQ parent\n");
+
+	domain = irq_find_host(interrupt_parent);
+	of_node_put(interrupt_parent);
+	fwspec.fwnode = domain->fwnode;
+
+	for (i = 0; i < ARRAY_SIZE(mt6363_regulators); i++) {
+		info = &mt6363_regulators[i];
+
+		fwspec.param[0] = info->hwirq;
+		info->virq = irq_create_fwspec_mapping(&fwspec);
+		if (!info->virq)
+			return dev_err_probe(dev, -EINVAL,
+					     "Failed to map IRQ%d\n", info->hwirq);
+
+		ret = devm_add_action_or_reset(dev, mt6363_irq_remove, &info->virq);
+		if (ret) {
+			irq_dispose_mapping(info->hwirq);
+			return ret;
+		}
+
+		config.driver_data = info;
+		INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work);
+
+		rdev = devm_regulator_register(dev, &info->desc, &config);
+		if (IS_ERR(rdev))
+			return dev_err_probe(dev, PTR_ERR(rdev),
+					     "failed to register %s\n", info->desc.name);
+
+		if (info->lp_imax_uA) {
+			ret = mt6363_backup_op_setting(config.regmap, info);
+			if (ret) {
+				dev_warn(dev, "Failed to backup op_setting for %s\n",
+					 info->desc.name);
+				info->lp_imax_uA = 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6363_regulator_match[] = {
+	{ .compatible = "mediatek,mt6363-regulator" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver mt6363_regulator_driver = {
+	.driver = {
+		.name = "mt6363-regulator",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+		.of_match_table = mt6363_regulator_match,
+	},
+	.probe = mt6363_regulator_probe,
+};
+module_platform_driver(mt6363_regulator_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6363 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6363-regulator.h b/include/linux/regulator/mt6363-regulator.h
new file mode 100644
index 000000000000..5df2bf21469c
--- /dev/null
+++ b/include/linux/regulator/mt6363-regulator.h
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ */
+
+#include <linux/bits.h>
+
+#ifndef __LINUX_REGULATOR_MT6363_H
+#define __LINUX_REGULATOR_MT6363_H
+
+/* Register */
+#define MT6363_TOP_TRAP				0x6
+#define MT6363_TOP_TMA_KEY_L			0x36e
+#define MT6363_RG_BUCK0_EN_ADDR			0x210
+#define MT6363_RG_BUCK_VS2_EN_BIT		0
+#define MT6363_RG_BUCK_VBUCK1_EN_BIT		1
+#define MT6363_RG_BUCK_VBUCK2_EN_BIT		2
+#define MT6363_RG_BUCK_VBUCK3_EN_BIT		3
+#define MT6363_RG_BUCK_VBUCK4_EN_BIT		4
+#define MT6363_RG_BUCK_VBUCK5_EN_BIT		5
+#define MT6363_RG_BUCK_VBUCK6_EN_BIT		6
+#define MT6363_RG_BUCK_VBUCK7_EN_BIT		7
+#define MT6363_RG_BUCK1_EN_ADDR			0x213
+#define MT6363_RG_BUCK_VS1_EN_BIT		0
+#define MT6363_RG_BUCK_VS3_EN_BIT		1
+#define MT6363_RG_LDO_VSRAM_DIGRF_EN_BIT	4
+#define MT6363_RG_LDO_VSRAM_MDFE_EN_BIT		5
+#define MT6363_RG_LDO_VSRAM_MODEM_EN_BIT	6
+#define MT6363_RG_BUCK0_LP_ADDR			0x216
+#define MT6363_RG_BUCK_VS2_LP_BIT		0
+#define MT6363_RG_BUCK_VBUCK1_LP_BIT		1
+#define MT6363_RG_BUCK_VBUCK2_LP_BIT		2
+#define MT6363_RG_BUCK_VBUCK3_LP_BIT		3
+#define MT6363_RG_BUCK_VBUCK4_LP_BIT		4
+#define MT6363_RG_BUCK_VBUCK5_LP_BIT		5
+#define MT6363_RG_BUCK_VBUCK6_LP_BIT		6
+#define MT6363_RG_BUCK_VBUCK7_LP_BIT		7
+#define MT6363_RG_BUCK1_LP_ADDR			0x219
+#define MT6363_RG_BUCK_VS1_LP_BIT		0
+#define MT6363_RG_BUCK_VS3_LP_BIT		1
+#define MT6363_RG_LDO_VSRAM_DIGRF_LP_BIT	4
+#define MT6363_RG_LDO_VSRAM_MDFE_LP_BIT		5
+#define MT6363_RG_LDO_VSRAM_MODEM_LP_BIT	6
+#define MT6363_RG_BUCK_VS2_VOSEL_ADDR		0x21c
+#define MT6363_RG_BUCK_VS2_VOSEL_MASK		GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR	0x21d
+#define MT6363_RG_BUCK_VBUCK1_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR	0x21e
+#define MT6363_RG_BUCK_VBUCK2_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR	0x21f
+#define MT6363_RG_BUCK_VBUCK3_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR	0x220
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR	0x221
+#define MT6363_RG_BUCK_VBUCK5_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR	0x222
+#define MT6363_RG_BUCK_VBUCK6_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR	0x223
+#define MT6363_RG_BUCK_VBUCK7_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_RG_BUCK_VS1_VOSEL_ADDR		0x224
+#define MT6363_RG_BUCK_VS1_VOSEL_MASK		GENMASK(7, 0)
+#define MT6363_RG_BUCK_VS3_VOSEL_ADDR		0x225
+#define MT6363_RG_BUCK_VS3_VOSEL_MASK		GENMASK(7, 0)
+#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR	0x228
+#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR	0x229
+#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR	0x22a
+#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_BUCK_TOP_KEY_PROT_LO		0x13fa
+#define MT6363_BUCK_VS2_WDTDBG_VOSEL_ADDR	0x13fc
+#define MT6363_BUCK_VBUCK1_WDTDBG_VOSEL_ADDR	0x13fd
+#define MT6363_BUCK_VBUCK2_WDTDBG_VOSEL_ADDR	0x13fe
+#define MT6363_BUCK_VBUCK3_WDTDBG_VOSEL_ADDR	0x13ff
+#define MT6363_BUCK_VBUCK4_WDTDBG_VOSEL_ADDR	0x1400
+#define MT6363_BUCK_VBUCK5_WDTDBG_VOSEL_ADDR	0x1401
+#define MT6363_BUCK_VBUCK6_WDTDBG_VOSEL_ADDR	0x1402
+#define MT6363_BUCK_VBUCK7_WDTDBG_VOSEL_ADDR	0x1403
+#define MT6363_BUCK_VS1_WDTDBG_VOSEL_ADDR	0x1404
+#define MT6363_BUCK_VS3_WDTDBG_VOSEL_ADDR	0x1405
+#define MT6363_RG_BUCK_EFUSE_RSV1		0x1417
+#define MT6363_RG_BUCK_EFUSE_RSV1_MASK		GENMASK(7, 4)
+#define MT6363_BUCK_VS2_OP_EN_0			0x145d
+#define MT6363_BUCK_VS2_HW_LP_MODE		0x1468
+#define MT6363_BUCK_VBUCK1_OP_EN_0		0x14dd
+#define MT6363_BUCK_VBUCK1_HW_LP_MODE		0x14e8
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR	0x14ea
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR	0x14eb
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_BUCK_VBUCK2_OP_EN_0		0x155d
+#define MT6363_BUCK_VBUCK2_HW_LP_MODE		0x1568
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR	0x156a
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR	0x156b
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_BUCK_VBUCK3_OP_EN_0		0x15dd
+#define MT6363_BUCK_VBUCK3_HW_LP_MODE		0x15e8
+#define MT6363_BUCK_VBUCK4_OP_EN_0		0x165d
+#define MT6363_BUCK_VBUCK4_HW_LP_MODE		0x1668
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR	0x166a
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR	0x166b
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK	GENMASK(7, 0)
+#define MT6363_BUCK_VBUCK5_OP_EN_0		0x16dd
+#define MT6363_BUCK_VBUCK5_HW_LP_MODE		0x16e8
+#define MT6363_BUCK_VBUCK6_OP_EN_0		0x175d
+#define MT6363_BUCK_VBUCK6_HW_LP_MODE		0x1768
+#define MT6363_BUCK_VBUCK7_OP_EN_0		0x17dd
+#define MT6363_BUCK_VBUCK7_HW_LP_MODE		0x17e8
+#define MT6363_BUCK_VS1_OP_EN_0			0x185d
+#define MT6363_BUCK_VS1_HW_LP_MODE		0x1868
+#define MT6363_BUCK_VS3_OP_EN_0			0x18dd
+#define MT6363_BUCK_VS3_HW_LP_MODE		0x18e8
+#define MT6363_RG_VS1_FCCM_ADDR			0x1964
+#define MT6363_RG_VS1_FCCM_BIT			0
+#define MT6363_RG_VS3_FCCM_ADDR			0x1973
+#define MT6363_RG_VS3_FCCM_BIT			0
+#define MT6363_RG_BUCK0_FCCM_ADDR		0x1a02
+#define MT6363_RG_VBUCK1_FCCM_BIT		0
+#define MT6363_RG_VBUCK2_FCCM_BIT		1
+#define MT6363_RG_VBUCK3_FCCM_BIT		2
+#define MT6363_RG_VS2_FCCM_BIT			3
+#define MT6363_RG_BUCK0_1_FCCM_ADDR		0x1a82
+#define MT6363_RG_VBUCK4_FCCM_BIT		0
+#define MT6363_RG_VBUCK5_FCCM_BIT		1
+#define MT6363_RG_VBUCK6_FCCM_BIT		2
+#define MT6363_RG_VBUCK7_FCCM_BIT		3
+#define MT6363_RG_VCN13_VOSEL_ADDR		0x1b0f
+#define MT6363_RG_VCN13_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VEMC_VOSEL_ADDR		0x1b10
+#define MT6363_RG_VEMC_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VEMC_VOSEL_1_MASK		GENMASK(7, 4)
+#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR	0x1b14
+#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR	0x1b15
+#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR	0x1b16
+#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR	0x1b17
+#define MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK	GENMASK(6, 0)
+#define MT6363_RG_VEMC_VOCAL_ADDR		0x1b1b
+#define MT6363_RG_VEMC_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_LDO_VCN15_ADDR		0x1b57
+#define MT6363_RG_LDO_VCN15_EN_BIT		0
+#define MT6363_RG_LDO_VCN15_LP_BIT		1
+#define MT6363_LDO_VCN15_HW_LP_MODE		0x1b5b
+#define MT6363_LDO_VCN15_OP_EN0			0x1b5c
+#define MT6363_RG_LDO_VRF09_ADDR		0x1b65
+#define MT6363_RG_LDO_VRF09_EN_BIT		0
+#define MT6363_RG_LDO_VRF09_LP_BIT		1
+#define MT6363_LDO_VRF09_HW_LP_MODE		0x1b69
+#define MT6363_LDO_VRF09_OP_EN0			0x1b6a
+#define MT6363_RG_LDO_VRF12_ADDR		0x1b73
+#define MT6363_RG_LDO_VRF12_EN_BIT		0
+#define MT6363_RG_LDO_VRF12_LP_BIT		1
+#define MT6363_LDO_VRF12_HW_LP_MODE		0x1b77
+#define MT6363_LDO_VRF12_OP_EN0			0x1b78
+#define MT6363_RG_LDO_VRF13_ADDR		0x1b81
+#define MT6363_RG_LDO_VRF13_EN_BIT		0
+#define MT6363_RG_LDO_VRF13_LP_BIT		1
+#define MT6363_LDO_VRF13_HW_LP_MODE		0x1b85
+#define MT6363_LDO_VRF13_OP_EN0			0x1b86
+#define MT6363_RG_LDO_VRF18_ADDR		0x1b8f
+#define MT6363_RG_LDO_VRF18_EN_BIT		0
+#define MT6363_RG_LDO_VRF18_LP_BIT		1
+#define MT6363_LDO_VRF18_HW_LP_MODE		0x1b93
+#define MT6363_LDO_VRF18_OP_EN0			0x1b94
+#define MT6363_RG_LDO_VRFIO18_ADDR		0x1b9d
+#define MT6363_RG_LDO_VRFIO18_EN_BIT		0
+#define MT6363_RG_LDO_VRFIO18_LP_BIT		1
+#define MT6363_LDO_VRFIO18_HW_LP_MODE		0x1ba1
+#define MT6363_LDO_VRFIO18_OP_EN0		0x1ba2
+#define MT6363_RG_LDO_VTREF18_ADDR		0x1bd7
+#define MT6363_RG_LDO_VTREF18_EN_BIT		0
+#define MT6363_RG_LDO_VTREF18_LP_BIT		1
+#define MT6363_LDO_VTREF18_HW_LP_MODE		0x1bdb
+#define MT6363_LDO_VTREF18_OP_EN0		0x1bdc
+#define MT6363_RG_LDO_VAUX18_ADDR		0x1be5
+#define MT6363_RG_LDO_VAUX18_EN_BIT		0
+#define MT6363_RG_LDO_VAUX18_LP_BIT		1
+#define MT6363_LDO_VAUX18_HW_LP_MODE		0x1be9
+#define MT6363_LDO_VAUX18_OP_EN0		0x1bea
+#define MT6363_RG_LDO_VEMC_ADDR			0x1bf3
+#define MT6363_RG_LDO_VEMC_EN_BIT		0
+#define MT6363_RG_LDO_VEMC_LP_BIT		1
+#define MT6363_LDO_VEMC_HW_LP_MODE		0x1bf7
+#define MT6363_LDO_VEMC_OP_EN0			0x1bf8
+#define MT6363_RG_LDO_VUFS12_ADDR		0x1c01
+#define MT6363_RG_LDO_VUFS12_EN_BIT		0
+#define MT6363_RG_LDO_VUFS12_LP_BIT		1
+#define MT6363_LDO_VUFS12_HW_LP_MODE		0x1c05
+#define MT6363_LDO_VUFS12_OP_EN0		0x1c06
+#define MT6363_RG_LDO_VUFS18_ADDR		0x1c0f
+#define MT6363_RG_LDO_VUFS18_EN_BIT		0
+#define MT6363_RG_LDO_VUFS18_LP_BIT		1
+#define MT6363_LDO_VUFS18_HW_LP_MODE		0x1c13
+#define MT6363_LDO_VUFS18_OP_EN0		0x1c14
+#define MT6363_RG_LDO_VIO18_ADDR		0x1c1d
+#define MT6363_RG_LDO_VIO18_EN_BIT		0
+#define MT6363_RG_LDO_VIO18_LP_BIT		1
+#define MT6363_LDO_VIO18_HW_LP_MODE		0x1c21
+#define MT6363_LDO_VIO18_OP_EN0			0x1c22
+#define MT6363_RG_LDO_VIO075_ADDR		0x1c57
+#define MT6363_RG_LDO_VIO075_EN_BIT		0
+#define MT6363_RG_LDO_VIO075_LP_BIT		1
+#define MT6363_LDO_VIO075_HW_LP_MODE		0x1c5b
+#define MT6363_LDO_VIO075_OP_EN0		0x1c5c
+#define MT6363_RG_LDO_VA12_1_ADDR		0x1c65
+#define MT6363_RG_LDO_VA12_1_EN_BIT		0
+#define MT6363_RG_LDO_VA12_1_LP_BIT		1
+#define MT6363_LDO_VA12_1_HW_LP_MODE		0x1c69
+#define MT6363_LDO_VA12_1_OP_EN0		0x1c6a
+#define MT6363_RG_LDO_VA12_2_ADDR		0x1c73
+#define MT6363_RG_LDO_VA12_2_EN_BIT		0
+#define MT6363_RG_LDO_VA12_2_LP_BIT		1
+#define MT6363_LDO_VA12_2_HW_LP_MODE		0x1c77
+#define MT6363_LDO_VA12_2_OP_EN0		0x1c78
+#define MT6363_RG_LDO_VA15_ADDR			0x1c81
+#define MT6363_RG_LDO_VA15_EN_BIT		0
+#define MT6363_RG_LDO_VA15_LP_BIT		1
+#define MT6363_LDO_VA15_HW_LP_MODE		0x1c85
+#define MT6363_LDO_VA15_OP_EN0			0x1c86
+#define MT6363_RG_LDO_VM18_ADDR			0x1c8f
+#define MT6363_RG_LDO_VM18_EN_BIT		0
+#define MT6363_RG_LDO_VM18_LP_BIT		1
+#define MT6363_LDO_VM18_HW_LP_MODE		0x1c93
+#define MT6363_LDO_VM18_OP_EN0			0x1c94
+#define MT6363_RG_LDO_VCN13_ADDR		0x1cd7
+#define MT6363_RG_LDO_VCN13_EN_BIT		0
+#define MT6363_RG_LDO_VCN13_LP_BIT		1
+#define MT6363_LDO_VCN13_HW_LP_MODE		0x1cdb
+#define MT6363_LDO_VCN13_OP_EN0			0x1ce4
+#define MT6363_LDO_VSRAM_DIGRF_HW_LP_MODE	0x1cf1
+#define MT6363_LDO_VSRAM_DIGRF_OP_EN0		0x1cfa
+#define MT6363_LDO_VSRAM_MDFE_HW_LP_MODE	0x1d5b
+#define MT6363_LDO_VSRAM_MDFE_OP_EN0		0x1d64
+#define MT6363_LDO_VSRAM_MODEM_HW_LP_MODE	0x1d76
+#define MT6363_LDO_VSRAM_MODEM_OP_EN0		0x1d7f
+#define MT6363_RG_LDO_VSRAM_CPUB_ADDR		0x1dd7
+#define MT6363_RG_LDO_VSRAM_CPUB_EN_BIT		0
+#define MT6363_RG_LDO_VSRAM_CPUB_LP_BIT		1
+#define MT6363_LDO_VSRAM_CPUB_HW_LP_MODE	0x1ddb
+#define MT6363_LDO_VSRAM_CPUB_OP_EN0		0x1de4
+#define MT6363_RG_LDO_VSRAM_CPUM_ADDR		0x1ded
+#define MT6363_RG_LDO_VSRAM_CPUM_EN_BIT		0
+#define MT6363_RG_LDO_VSRAM_CPUM_LP_BIT		1
+#define MT6363_LDO_VSRAM_CPUM_HW_LP_MODE	0x1df1
+#define MT6363_LDO_VSRAM_CPUM_OP_EN0		0x1dfa
+#define MT6363_RG_LDO_VSRAM_CPUL_ADDR		0x1e57
+#define MT6363_RG_LDO_VSRAM_CPUL_EN_BIT		0
+#define MT6363_RG_LDO_VSRAM_CPUL_LP_BIT		1
+#define MT6363_LDO_VSRAM_CPUL_HW_LP_MODE	0x1e5b
+#define MT6363_LDO_VSRAM_CPUL_OP_EN0		0x1e64
+#define MT6363_RG_LDO_VSRAM_APU_ADDR		0x1e6d
+#define MT6363_RG_LDO_VSRAM_APU_EN_BIT		0
+#define MT6363_RG_LDO_VSRAM_APU_LP_BIT		1
+#define MT6363_LDO_VSRAM_APU_HW_LP_MODE		0x1e71
+#define MT6363_LDO_VSRAM_APU_OP_EN0		0x1e7a
+#define MT6363_RG_VTREF18_VOCAL_ADDR		0x1ed8
+#define MT6363_RG_VTREF18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VTREF18_VOSEL_ADDR		0x1ed9
+#define MT6363_RG_VTREF18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VAUX18_VOCAL_ADDR		0x1edc
+#define MT6363_RG_VAUX18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VAUX18_VOSEL_ADDR		0x1edd
+#define MT6363_RG_VAUX18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VCN15_VOCAL_ADDR		0x1ee3
+#define MT6363_RG_VCN15_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VCN15_VOSEL_ADDR		0x1ee4
+#define MT6363_RG_VCN15_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VUFS18_VOCAL_ADDR		0x1ee7
+#define MT6363_RG_VUFS18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VUFS18_VOSEL_ADDR		0x1ee8
+#define MT6363_RG_VUFS18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VIO18_VOCAL_ADDR		0x1eeb
+#define MT6363_RG_VIO18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VIO18_VOSEL_ADDR		0x1eec
+#define MT6363_RG_VIO18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VM18_VOCAL_ADDR		0x1eef
+#define MT6363_RG_VM18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VM18_VOSEL_ADDR		0x1ef0
+#define MT6363_RG_VM18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VA15_VOCAL_ADDR		0x1ef3
+#define MT6363_RG_VA15_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VA15_VOSEL_ADDR		0x1ef4
+#define MT6363_RG_VA15_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF18_VOCAL_ADDR		0x1ef7
+#define MT6363_RG_VRF18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF18_VOSEL_ADDR		0x1ef8
+#define MT6363_RG_VRF18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRFIO18_VOCAL_ADDR		0x1efb
+#define MT6363_RG_VRFIO18_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRFIO18_VOSEL_ADDR		0x1efc
+#define MT6363_RG_VRFIO18_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VIO075_VOCFG_ADDR		0x1f01
+#define MT6363_RG_VIO075_VOCAL_ADDR		MT6363_RG_VIO075_VOCFG_ADDR
+#define MT6363_RG_VIO075_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VIO075_VOSEL_ADDR		MT6363_RG_VIO075_VOCFG_ADDR
+#define MT6363_RG_VIO075_VOSEL_MASK		GENMASK(6, 4)
+#define MT6363_RG_VCN13_VOCAL_ADDR		0x1f58
+#define MT6363_RG_VCN13_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VUFS12_VOCAL_ADDR		0x1f61
+#define MT6363_RG_VUFS12_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VUFS12_VOSEL_ADDR		0x1f62
+#define MT6363_RG_VUFS12_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VA12_1_VOCAL_ADDR		0x1f65
+#define MT6363_RG_VA12_1_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VA12_1_VOSEL_ADDR		0x1f66
+#define MT6363_RG_VA12_1_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VA12_2_VOCAL_ADDR		0x1f69
+#define MT6363_RG_VA12_2_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VA12_2_VOSEL_ADDR		0x1f6a
+#define MT6363_RG_VA12_2_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF12_VOCAL_ADDR		0x1f6d
+#define MT6363_RG_VRF12_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF12_VOSEL_ADDR		0x1f6e
+#define MT6363_RG_VRF12_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF13_VOCAL_ADDR		0x1f71
+#define MT6363_RG_VRF13_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF13_VOSEL_ADDR		0x1f72
+#define MT6363_RG_VRF13_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF09_VOCAL_ADDR		0x1f78
+#define MT6363_RG_VRF09_VOCAL_MASK		GENMASK(3, 0)
+#define MT6363_RG_VRF09_VOSEL_ADDR		0x1f79
+#define MT6363_RG_VRF09_VOSEL_MASK		GENMASK(3, 0)
+#define MT6363_ISINK_EN_CTRL0			0x21db
+#define MT6363_ISINK_CTRL0_MASK			GENMASK(7, 0)
+#define MT6363_ISINK_EN_CTRL1			0x21dc
+#define MT6363_ISINK_CTRL1_MASK			GENMASK(7, 4)
+
+#endif /* __LINUX_REGULATOR_MT6363_H */
+
-- 
2.50.1


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

* [PATCH v4 5/8] dt-bindings: regulator: Document MediaTek MT6373 PMIC Regulators
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
                   ` (3 preceding siblings ...)
  2025-07-15 11:57 ` [PATCH v4 4/8] regulator: Add support for MediaTek MT6363 SPMI " AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 6/8] regulator: Add support for MediaTek MT6373 SPMI " AngeloGioacchino Del Regno
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Add bindings for the regulators found in the MediaTek MT6363 PMIC,
usually found in board designs using the MT6991 Dimensity 9400 and
on MT8196 Kompanio SoC for Chromebooks, along with the MT6316 and
MT6363 PMICs.

Link: https://lore.kernel.org/r/20250624073548.29732-6-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-6-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 .../regulator/mediatek,mt6373-regulator.yaml  | 175 ++++++++++++++++++
 1 file changed, 175 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6373-regulator.yaml

diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6373-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6373-regulator.yaml
new file mode 100644
index 000000000000..dec4bf90e892
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6373-regulator.yaml
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6373-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6373 PMIC Regulators
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+  The MT6373 SPMI PMIC provides 11 BUCK and 23 LDO (Low Dropout) regulators
+  and can optionally provide overcurrent warnings with one ocp interrupt
+  for each voltage regulator.
+
+properties:
+  compatible:
+    const: mediatek,mt6373-regulator
+
+  interrupts:
+    description: Overcurrent warning interrupts
+    minItems: 1
+    maxItems: 34
+
+  interrupt-names:
+    description:
+      Names for the overcurrent interrupts are the same as the name
+      of a regulator (hence the same as each regulator's node name).
+      For example, the interrupt name for regulator vfp will be "vfp".
+    minItems: 1
+    maxItems: 34
+    contains:
+      enum:
+        - vbuck0
+        - vbuck1
+        - vbuck2
+        - vbuck3
+        - vbuck4
+        - vbuck4-ufs
+        - vbuck5
+        - vbuck6
+        - vbuck7
+        - vbuck8
+        - vbuck9
+        - vant18
+        - vaud18
+        - vaux18
+        - vcn33-1
+        - vcn33-2
+        - vcn33-3
+        - vcn18io
+        - vefuse
+        - vfp
+        - vibr
+        - vio28
+        - vmc
+        - vmch
+        - vrfio18-aif
+        - vrf09-aif
+        - vrf12-aif
+        - vrf13-aif
+        - vrf18-aif
+        - vsim1
+        - vsim2
+        - vsram-digrf-aif
+        - vtp
+        - vusb
+
+patternProperties:
+  "^v(ant|aud|aux)18$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^vbuck([0123456789]|4-ufs)$":
+    type: object
+    $ref: regulator.yaml#
+    properties:
+      regulator-allowed-modes:
+        description: |
+          Allowed Buck regulator operating modes allowed. Valid values below.
+            0 - Normal mode with automatic power saving, reducing the switching
+                frequency when light load conditions are detected
+            1 - Forced Continuous Conduction mode (FCCM) for improved voltage
+                regulation accuracy with constant switching frequency but lower
+                regulator efficiency
+            2 - Forced Low Power mode for improved regulator efficiency, used
+                when no heavy load is expected, does not limit the maximum out
+                current but unless only a light load is applied, there will be
+                regulation accuracy and efficiency losses.
+            3 - Forced Ultra Low Power mode for ultra low load, this greatly
+                reduces the maximum output power, makes the regulator to be
+                efficient only for ultra light load, and greatly reduces the
+                quiescent current (Iq) of the buck.
+        maxItems: 3
+        items:
+          enum: [ 0, 1, 2, 3 ]
+    unevaluatedProperties: false
+
+  "^vbuck4(-ufs)?$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^vcn33-[123]$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^v(f|t)p":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^v(cn18io|efuse|ibr|io28|sram-digrf-aif|usb)":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^vmc(h)?$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^vmch-(eint-low|eint-high)?$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^vrf(09|12|13|18|io18)-aif$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+  "^vsim[12]$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    pmic {
+      interrupt-controller;
+      #interrupt-cells = <3>;
+
+      regulators {
+        compatible = "mediatek,mt6373-regulator";
+        interrupts = <5 17 IRQ_TYPE_LEVEL_HIGH>, <5 18 IRQ_TYPE_LEVEL_HIGH>,
+                     <5 19 IRQ_TYPE_LEVEL_HIGH>, <5 20 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "vusb", "vaux18", "vrf13-aif", "vrf18-aif";
+
+        vaux18 {
+          regulator-name = "avss18-auxadc-mt6373";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <1800000>;
+          regulator-allowed-modes = <0 1 2>;
+        };
+
+        vmc {
+          regulator-name = "pp1800-2900-vmc";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <2900000>;
+          regulator-allowed-modes = <0 2>;
+        };
+      };
+    };
+...
-- 
2.50.1


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

* [PATCH v4 6/8] regulator: Add support for MediaTek MT6373 SPMI PMIC Regulators
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
                   ` (4 preceding siblings ...)
  2025-07-15 11:57 ` [PATCH v4 5/8] dt-bindings: regulator: Document MediaTek MT6373 " AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC AngeloGioacchino Del Regno
  2025-07-15 11:57 ` [PATCH v4 8/8] drivers: mfd: Add support for MediaTek SPMI PMICs and MT6363/73 AngeloGioacchino Del Regno
  7 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst

Add a driver for the regulators found on the MediaTek MT6373 PMIC,
fully controlled by SPMI interface.
Similarly to MT6363, this PMIC regulates voltage with input range
of 2.6-5.0V, and features 10 buck converters and 25 LDOs.

This PMIC is usually found on board designs using the MT6991 or
MT8196 SoC, in combination with the MT6363 PMIC.

Link: https://lore.kernel.org/r/20250624073548.29732-7-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-7-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/regulator/Kconfig                  |   9 +
 drivers/regulator/Makefile                 |   1 +
 drivers/regulator/mt6373-regulator.c       | 762 +++++++++++++++++++++
 include/linux/regulator/mt6373-regulator.h | 162 +++++
 4 files changed, 934 insertions(+)
 create mode 100644 drivers/regulator/mt6373-regulator.c
 create mode 100644 include/linux/regulator/mt6373-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d770e51f7ad1..ae1441c32881 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -953,6 +953,15 @@ config REGULATOR_MT6370
 	  This driver supports the control for DisplayBias voltages and one
 	  general purpose LDO which is commonly used to drive the vibrator.
 
+config REGULATOR_MT6373
+	tristate "MT6373 SPMI PMIC regulator driver"
+	depends on SPMI || COMPILE_TEST
+	help
+          Say Y here to enable support for buck and LDO regulators found in
+          the MediaTek MT6373 SPMI PMIC and its variants.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6380
 	tristate "MediaTek MT6380 PMIC"
 	depends on MTK_PMIC_WRAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 41eaeac5547d..d5124ea3c8c2 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_REGULATOR_MT6359)	+= mt6359-regulator.o
 obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
 obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o
 obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
+obj-$(CONFIG_REGULATOR_MT6373) += mt6373-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380)	+= mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
diff --git a/drivers/regulator/mt6373-regulator.c b/drivers/regulator/mt6373-regulator.c
new file mode 100644
index 000000000000..ed2141ca3bac
--- /dev/null
+++ b/drivers/regulator/mt6373-regulator.c
@@ -0,0 +1,762 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+// Copyright (c) 2025 Collabora Ltd
+//                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6373-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6373_REGULATOR_MODE_NORMAL	0
+#define MT6373_REGULATOR_MODE_FCCM	1
+#define MT6373_REGULATOR_MODE_LP	2
+#define MT6373_REGULATOR_MODE_ULP	3
+
+#define EN_SET_OFFSET			0x1
+#define EN_CLR_OFFSET			0x2
+
+#define OC_IRQ_ENABLE_DELAY_MS		10
+
+/* Unlock key for mode setting */
+#define MT6373_BUCK_TOP_UNLOCK_VALUE	0x5543
+
+enum {
+	MT6373_ID_VBUCK0,
+	MT6373_ID_VBUCK1,
+	MT6373_ID_VBUCK2,
+	MT6373_ID_VBUCK3,
+	MT6373_ID_VBUCK4,
+	MT6373_ID_VBUCK5,
+	MT6373_ID_VBUCK6,
+	MT6373_ID_VBUCK7,
+	MT6373_ID_VBUCK8,
+	MT6373_ID_VBUCK9,
+	MT6373_ID_VANT18,
+	MT6373_ID_VAUD18,
+	MT6373_ID_VAUX18,
+	MT6373_ID_VCN18IO,
+	MT6373_ID_VCN33_1,
+	MT6373_ID_VCN33_2,
+	MT6373_ID_VCN33_3,
+	MT6373_ID_VEFUSE,
+	MT6373_ID_VFP,
+	MT6373_ID_VIBR,
+	MT6373_ID_VIO28,
+	MT6373_ID_VMC,
+	MT6373_ID_VMCH,
+	MT6373_ID_VMCH_EINT_HIGH,
+	MT6373_ID_VMCH_EINT_LOW,
+	MT6373_ID_VRF09_AIF,
+	MT6373_ID_VRF12_AIF,
+	MT6373_ID_VRF13_AIF,
+	MT6373_ID_VRF18_AIF,
+	MT6373_ID_VRFIO18_AIF,
+	MT6373_ID_VSRAM_DIGRF_AIF,
+	MT6373_ID_VTP,
+	MT6373_ID_VUSB,
+};
+
+/**
+ * struct mt6373_regulator_info - MT6373 regulators information
+ * @desc: Regulator description structure
+ * @lp_mode_reg: Low Power mode register (normal/idle)
+ * @lp_mode_mask: Low Power mode regulator mask
+ * @modeset_reg: AUTO/PWM mode register
+ * @modeset_mask: AUTO/PWM regulator mask
+ * @oc_work: Delayed work for enabling overcurrent IRQ
+ * @hwirq: PMIC-Internal HW Interrupt for overcurrent event
+ * @virq: Mapped Interrupt for overcurrent event
+ */
+struct mt6373_regulator_info {
+	struct regulator_desc desc;
+	u16 lp_mode_reg;
+	u16 lp_mode_mask;
+	u16 modeset_reg;
+	u16 modeset_mask;
+	struct delayed_work oc_work;
+	u8 hwirq;
+	int virq;
+};
+
+#define MT6373_BUCK(match, vreg, min, max, step, en_reg, lp_reg,	\
+		    mset_reg, ocp_intn)					\
+[MT6373_ID_##vreg] = {							\
+	.desc = {							\
+		.name = match,						\
+		.supply_name = "vsys-"match,				\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6373_vreg_setclr_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6373_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min) / step + 1,			\
+		.min_uV = min,						\
+		.uV_step = step,					\
+		.enable_reg = en_reg,					\
+		.enable_mask = BIT(MT6373_PMIC_RG_BUCK_##vreg##_EN_BIT),\
+		.vsel_reg = MT6373_PMIC_RG_BUCK_##vreg##_VOSEL_ADDR,	\
+		.vsel_mask = MT6373_PMIC_RG_BUCK_VOSEL_MASK,		\
+		.of_map_mode = mt6373_map_mode,				\
+	},								\
+	.lp_mode_reg = lp_reg,						\
+	.lp_mode_mask = BIT(MT6373_PMIC_RG_BUCK_##vreg##_LP_BIT),	\
+	.modeset_reg = mset_reg,					\
+	.modeset_mask = BIT(MT6373_PMIC_RG_##vreg##_FCCM_BIT),		\
+	.hwirq = ocp_intn,						\
+}
+
+
+#define MT6373_LDO_L(match, vreg, in_sup, min, max, step, ocp_intn)	\
+[MT6373_ID_##vreg] = {							\
+	.desc = {							\
+		.name = match,						\
+		.supply_name = in_sup,					\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6373_ldo_linear_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6373_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min) / step + 1,			\
+		.min_uV = min,						\
+		.uV_step = step,					\
+		.enable_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR,		\
+		.enable_mask = BIT(0),					\
+		.vsel_reg = MT6373_PMIC_RG_##vreg##_VOSEL_ADDR,		\
+		.vsel_mask = MT6373_PMIC_RG_##vreg##_VOSEL_MASK,	\
+		.of_map_mode = mt6373_map_mode,				\
+	},								\
+	.lp_mode_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR,		\
+	.lp_mode_mask = BIT(1),						\
+	.hwirq = ocp_intn,						\
+}
+
+#define MT6373_LDO_VT_OPS(match, vreg, in_sup, vops, vrnum, ocp_intn)	\
+[MT6373_ID_##vreg] = {							\
+	.desc = {							\
+		.name = match,						\
+		.supply_name = in_sup,					\
+		.of_match = of_match_ptr(match),			\
+		.ops = &vops,						\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6373_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_ranges##vrnum) * 11,	\
+		.linear_ranges = ldo_volt_ranges##vrnum,		\
+		.n_linear_ranges = ARRAY_SIZE(ldo_volt_ranges##vrnum),	\
+		.linear_range_selectors_bitfield = ldos_cal_selectors,	\
+		.enable_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR,		\
+		.enable_mask = BIT(0),					\
+		.vsel_reg = MT6373_PMIC_RG_##vreg##_VOCAL_ADDR,		\
+		.vsel_mask = MT6373_PMIC_RG_LDO_VT_VOCALSEL_MASK,	\
+		.vsel_range_reg = MT6373_PMIC_RG_##vreg##_VOSEL_ADDR,	\
+		.vsel_range_mask = MT6373_PMIC_RG_LDO_VT_VOCALSEL_MASK,	\
+		.of_map_mode = mt6373_map_mode,				\
+	},								\
+	.lp_mode_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR,		\
+	.lp_mode_mask = BIT(1),						\
+	.hwirq = ocp_intn,						\
+}
+
+#define MT6373_LDO_VT(match, vreg, inp, vrnum, ocp_intn)		\
+	MT6373_LDO_VT_OPS(match, vreg, inp, mt6373_ldo_vtable_ops,	\
+			  vrnum, ocp_intn)
+
+#define MT6373_LDO_EI(match, vreg, inp, vrnum, ocp_intn)		\
+	MT6373_LDO_VT_OPS(match, vreg, inp, mt6373_vmch_eint_ops,	\
+			  vrnum, ocp_intn)
+
+static const unsigned int ldos_cal_selectors[] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const struct linear_range ldo_volt_ranges1[] = {
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3500000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges2[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges3[] = {
+	REGULATOR_LINEAR_RANGE(600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges4[] = {
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3400000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(3500000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges5[] = {
+	REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+};
+
+static int mt6373_vreg_enable_setclr(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6373_vreg_disable_setclr(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_CLR_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static inline unsigned int mt6373_map_mode(unsigned int mode)
+{
+	switch (mode) {
+	case MT6373_REGULATOR_MODE_NORMAL:
+		return REGULATOR_MODE_NORMAL;
+	case MT6373_REGULATOR_MODE_FCCM:
+		return REGULATOR_MODE_FAST;
+	case MT6373_REGULATOR_MODE_LP:
+		return REGULATOR_MODE_IDLE;
+	case MT6373_REGULATOR_MODE_ULP:
+		return REGULATOR_MODE_STANDBY;
+	default:
+		return REGULATOR_MODE_INVALID;
+	}
+}
+
+static int mt6373_vmch_eint_enable(struct regulator_dev *rdev)
+{
+	const struct regulator_desc *rdesc = rdev->desc;
+	unsigned int val;
+	int ret;
+
+	if (rdesc->id == MT6373_ID_VMCH_EINT_HIGH)
+		val = MT6373_PMIC_RG_LDO_VMCH_EINT_POL_BIT;
+	else
+		val = 0;
+
+	ret = regmap_update_bits(rdev->regmap,
+				 MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR,
+				 MT6373_PMIC_RG_LDO_VMCH_EINT_POL_BIT, val);
+	if (ret)
+		return ret;
+
+	ret = regmap_set_bits(rdev->regmap,
+			      MT6373_PMIC_RG_LDO_VMCH_ADDR,
+			      rdesc->enable_mask);
+	if (ret)
+		return ret;
+
+	return regmap_set_bits(rdev->regmap, rdesc->enable_reg, rdesc->enable_mask);
+}
+
+static int mt6373_vmch_eint_disable(struct regulator_dev *rdev)
+{
+	const struct regulator_desc *rdesc = rdev->desc;
+	int ret;
+
+	ret = regmap_clear_bits(rdev->regmap,
+				MT6373_PMIC_RG_LDO_VMCH_ADDR,
+				rdesc->enable_mask);
+	if (ret)
+		return ret;
+
+	/* Wait for VMCH discharging */
+	usleep_range(1500, 1600);
+
+	return regmap_clear_bits(rdev->regmap, rdesc->enable_reg, rdesc->enable_mask);
+}
+
+static unsigned int mt6373_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret;
+
+	if (info->modeset_reg) {
+		ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+		if (ret) {
+			dev_err(&rdev->dev, "Failed to get mt6373 mode: %d\n", ret);
+			return ret;
+		}
+
+		if (val & info->modeset_mask)
+			return REGULATOR_MODE_FAST;
+	} else {
+		val = 0;
+	};
+
+	ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+	val &= info->lp_mode_mask;
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+		return ret;
+	}
+
+	if (val)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6373_buck_unlock(struct regmap *map, bool unlock)
+{
+	u16 buf = unlock ? MT6373_BUCK_TOP_UNLOCK_VALUE : 0;
+
+	return regmap_bulk_write(map, MT6373_BUCK_TOP_KEY_PROT_LO, &buf, sizeof(buf));
+}
+
+static int mt6373_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+	struct regmap *regmap = rdev->regmap;
+	int cur_mode, ret;
+
+	if (!info->modeset_reg && mode == REGULATOR_MODE_FAST)
+		return -EOPNOTSUPP;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = mt6373_buck_unlock(regmap, true);
+		if (ret)
+			break;
+
+		ret = regmap_set_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+		mt6373_buck_unlock(regmap, false);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		cur_mode = mt6373_regulator_get_mode(rdev);
+		if (cur_mode < 0) {
+			ret = cur_mode;
+			break;
+		}
+
+		if (cur_mode == REGULATOR_MODE_FAST) {
+			ret = mt6373_buck_unlock(regmap, true);
+			if (ret)
+				break;
+
+			ret = regmap_clear_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+			mt6373_buck_unlock(regmap, false);
+			break;
+		} else if (cur_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_clear_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+			if (ret == 0)
+				usleep_range(100, 200);
+		} else {
+			ret = 0;
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_set_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to set mode %u: %d\n", mode, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mt6373_oc_irq_enable_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct mt6373_regulator_info *info =
+		container_of(dwork, struct mt6373_regulator_info, oc_work);
+
+	enable_irq(info->virq);
+}
+
+static irqreturn_t mt6373_oc_isr(int irq, void *data)
+{
+	struct regulator_dev *rdev = (struct regulator_dev *)data;
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+
+	disable_irq_nosync(info->virq);
+
+	if (regulator_is_enabled_regmap(rdev))
+		regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
+
+	schedule_delayed_work(&info->oc_work, msecs_to_jiffies(OC_IRQ_ENABLE_DELAY_MS));
+
+	return IRQ_HANDLED;
+}
+
+static int mt6373_set_ocp(struct regulator_dev *rdev, int lim, int severity, bool enable)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+
+	/* MT6373 supports only enabling protection and does not support limits */
+	if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+		return -EINVAL;
+
+	/* If there is no OCP interrupt, there's nothing to set */
+	if (info->virq <= 0)
+		return -EINVAL;
+
+	return devm_request_threaded_irq(&rdev->dev, info->virq, NULL,
+					 mt6373_oc_isr, IRQF_ONESHOT,
+					 info->desc.name, rdev);
+}
+
+static const struct regulator_ops mt6373_vreg_setclr_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = mt6373_vreg_enable_setclr,
+	.disable = mt6373_vreg_disable_setclr,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6373_regulator_set_mode,
+	.get_mode = mt6373_regulator_get_mode,
+	.set_over_current_protection = mt6373_set_ocp,
+};
+
+static const struct regulator_ops mt6373_ldo_linear_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6373_regulator_set_mode,
+	.get_mode = mt6373_regulator_get_mode,
+	.set_over_current_protection = mt6373_set_ocp,
+};
+
+static const struct regulator_ops mt6373_ldo_vtable_ops = {
+	.list_voltage = regulator_list_voltage_pickable_linear_range,
+	.map_voltage = regulator_map_voltage_pickable_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6373_regulator_set_mode,
+	.get_mode = mt6373_regulator_get_mode,
+	.set_over_current_protection = mt6373_set_ocp,
+};
+
+static const struct regulator_ops mt6373_vmch_eint_ops = {
+	.list_voltage = regulator_list_voltage_pickable_linear_range,
+	.map_voltage = regulator_map_voltage_pickable_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = mt6373_vmch_eint_enable,
+	.disable = mt6373_vmch_eint_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6373_regulator_set_mode,
+	.get_mode = mt6373_regulator_get_mode,
+	.set_over_current_protection = mt6373_set_ocp,
+};
+
+/* The array is indexed by id(MT6373_ID_XXX) */
+static struct mt6373_regulator_info mt6373_regulators[] = {
+	MT6373_BUCK("vbuck0", VBUCK0, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 0),
+	MT6373_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 1),
+	MT6373_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 2),
+	MT6373_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 3),
+	MT6373_BUCK("vbuck4", VBUCK4, 0, 0, 1, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 4),
+	MT6373_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 5),
+	MT6373_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 6),
+	MT6373_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 7),
+	MT6373_BUCK("vbuck8", VBUCK8, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK1_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK1_LP_ADDR, MT6373_PMIC_RG_BUCK1_FCCM_ADDR, 8),
+	MT6373_BUCK("vbuck9", VBUCK9, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK1_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK1_LP_ADDR, MT6373_PMIC_RG_BUCK1_FCCM_ADDR, 9),
+	MT6373_LDO_VT("vant18", VANT18, "vs1-ldo1", 3, 28),
+	MT6373_LDO_VT("vaud18", VAUD18, "vs1-ldo1", 3, 16),
+	MT6373_LDO_VT("vaux18", VAUX18, "vsys-ldo2", 2, 18),
+	MT6373_LDO_VT("vcn18io", VCN18IO, "vs1-ldo1", 3, 25),
+	MT6373_LDO_VT("vcn33-1", VCN33_1, "vsys-ldo1", 4, 22),
+	MT6373_LDO_VT("vcn33-2", VCN33_2, "vsys-ldo1", 4, 23),
+	MT6373_LDO_VT("vcn33-3", VCN33_3, "vsys-ldo2", 4, 24),
+	MT6373_LDO_VT("vefuse", VEFUSE, "vsys-ldo2", 1, 31),
+	MT6373_LDO_VT("vfp", VFP, "vsys-ldo2", 1, 36),
+	MT6373_LDO_VT("vibr", VIBR, "vsys-ldo2", 1, 34),
+	MT6373_LDO_VT("vio28", VIO28, "vsys-ldo2", 1, 35),
+	MT6373_LDO_VT("vmc", VMC, "vsys-ldo1", 1, 33),
+	MT6373_LDO_VT("vmch", VMCH, "vsys-ldo3", 4, 32),
+	MT6373_LDO_EI("vmch-eint-high", VMCH_EINT_HIGH, "vsys-ldo3", 4, 0),
+	MT6373_LDO_EI("vmch-eint-low", VMCH_EINT_LOW, "vsys-ldo3", 4, 0),
+	MT6373_LDO_VT("vrf09-aif", VRF09_AIF, "vs3-ldo1", 3, 26),
+	MT6373_LDO_VT("vrf12-aif", VRF12_AIF, "vs2-ldo1", 5, 27),
+	MT6373_LDO_VT("vrf13-aif", VRF13_AIF, "vs2-ldo1", 3, 19),
+	MT6373_LDO_VT("vrf18-aif", VRF18_AIF, "vs1-ldo1", 3, 20),
+	MT6373_LDO_VT("vrfio18-aif", VRFIO18_AIF, "vs1-ldo1", 3, 25),
+	MT6373_LDO_L("vsram-digrf-aif", VSRAM_DIGRF_AIF, "vs3-ldo1", 400000, 1193750, 6250, 29),
+	MT6373_LDO_VT("vtp", VTP, "vsys-ldo2", 1, 37),
+	MT6373_LDO_VT("vusb", VUSB, "vsys-ldo2", 1, 17)
+};
+
+static void mt6373_irq_remove(void *data)
+{
+	int *virq = data;
+
+	irq_dispose_mapping(*virq);
+}
+
+static void mt6373_spmi_remove(void *data)
+{
+	struct spmi_device *sdev = data;
+
+	spmi_device_remove(sdev);
+};
+
+static struct regmap *mt6373_spmi_register_regmap(struct device *dev)
+{
+	struct regmap_config mt6373_regmap_config = {
+		.reg_bits = 16,
+		.val_bits = 16,
+		.max_register = 0x1f90,
+		.fast_io = true,
+	};
+	struct spmi_device *sdev, *sparent;
+	u32 base;
+	int ret;
+
+	if (!dev->parent)
+		return ERR_PTR(-ENODEV);
+
+	ret = device_property_read_u32(dev, "reg", &base);
+	if (ret)
+		return ERR_PTR(ret);
+
+	sparent = to_spmi_device(dev->parent);
+	if (!sparent)
+		return ERR_PTR(-ENODEV);
+
+	sdev = spmi_device_alloc(sparent->ctrl);
+	if (!sdev)
+		return ERR_PTR(-ENODEV);
+
+	sdev->usid = sparent->usid;
+	dev_set_name(&sdev->dev, "%d-%02x-regulator", sdev->ctrl->nr, sdev->usid);
+	ret = device_add(&sdev->dev);
+	if (ret) {
+		put_device(&sdev->dev);
+		return ERR_PTR(ret);
+	};
+
+	ret = devm_add_action_or_reset(dev, mt6373_spmi_remove, sdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mt6373_regmap_config.reg_base = base;
+
+	return devm_regmap_init_spmi_ext(sdev, &mt6373_regmap_config);
+}
+
+static int mt6373_regulator_probe(struct platform_device *pdev)
+{
+	struct irq_fwspec fwspec = {
+		.param_count = 2,
+		.param = { 0, IRQ_TYPE_LEVEL_HIGH },
+	};
+	struct device_node *interrupt_parent;
+	struct regulator_config config = {};
+	struct mt6373_regulator_info *info;
+	struct device *dev = &pdev->dev;
+	struct regulator_dev *rdev;
+	struct irq_domain *domain;
+	bool is_vbuck4_hw_ctrl;
+	bool is_cw_variant;
+	int i, ret;
+	u32 val;
+
+	config.regmap = mt6373_spmi_register_regmap(dev);
+	if (!config.regmap)
+		return dev_err_probe(dev, PTR_ERR(config.regmap),
+				     "Cannot get regmap\n");
+	config.dev = dev;
+
+	interrupt_parent = of_irq_find_parent(dev->of_node);
+	if (!interrupt_parent)
+		return -EINVAL;
+
+	domain = irq_find_host(interrupt_parent);
+	of_node_put(interrupt_parent);
+	fwspec.fwnode = domain->fwnode;
+
+	/* Read PMIC variant information */
+	ret = regmap_read(config.regmap, MT6373_PLG_CFG_ELR1, &val);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot read ID register\n");
+
+	val = FIELD_GET(MT6373_ELR_VARIANT_MASK, val);
+	is_cw_variant = (val == MT6373_ELR_VARIANT_MT6373CW);
+
+	/* Read Reserved-SW information */
+	ret = regmap_read(config.regmap, MT6373_RG_RSV_SWREG_H, &val);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot read RSV_SW register\n");
+
+	is_vbuck4_hw_ctrl = val & MT6373_RG_RSV_SWREG_VBUCK4_HW_CTRL;
+
+	for (i = 0; i < ARRAY_SIZE(mt6373_regulators); i++) {
+		info = &mt6373_regulators[i];
+
+		/* MT6373CW VBUCK4 constraints are different */
+		if (info->desc.id == MT6373_ID_VBUCK4) {
+			unsigned int vbuck4_max_uV;
+
+			/* VBUCK4 vreg software control not allowed in hw_ctrl mode */
+			if (is_vbuck4_hw_ctrl)
+				continue;
+
+			if (is_cw_variant) {
+				info->desc.uV_step = 6250;
+				vbuck4_max_uV = 1193750;
+			} else {
+				info->desc.uV_step = 13875;
+				vbuck4_max_uV = 2650125;
+			}
+			info->desc.n_voltages = vbuck4_max_uV / info->desc.uV_step + 1;
+		}
+
+		fwspec.param[0] = info->hwirq;
+		info->virq = irq_create_fwspec_mapping(&fwspec);
+		if (!info->virq)
+			return dev_err_probe(dev, -EINVAL,
+					     "Failed to map IRQ%d\n", info->hwirq);
+
+		ret = devm_add_action_or_reset(dev, mt6373_irq_remove, &info->virq);
+		if (ret) {
+			irq_dispose_mapping(info->virq);
+			return ret;
+		}
+
+		config.driver_data = info;
+		INIT_DELAYED_WORK(&info->oc_work, mt6373_oc_irq_enable_work);
+
+		rdev = devm_regulator_register(dev, &info->desc, &config);
+		if (IS_ERR(rdev))
+			return dev_err_probe(dev, PTR_ERR(rdev),
+					     "failed to register %s\n", info->desc.name);
+	}
+	dev_set_drvdata(dev, config.regmap);
+
+	return 0;
+}
+
+static void mt6373_regulator_shutdown(struct platform_device *pdev)
+{
+	struct regmap *regmap = dev_get_drvdata(&pdev->dev);
+
+	regmap_write(regmap, MT6373_TOP_CFG_ELR5, MT6373_TOP_CFG_ELR5_SHUTDOWN);
+}
+
+static const struct of_device_id mt6373_regulator_match[] = {
+	{ .compatible = "mediatek,mt6373-regulator" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver mt6373_regulator_driver = {
+	.driver = {
+		.name = "mt6373-regulator",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+		.of_match_table = mt6373_regulator_match,
+	},
+	.probe = mt6373_regulator_probe,
+	.shutdown = mt6373_regulator_shutdown
+};
+module_platform_driver(mt6373_regulator_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek MT6373 PMIC Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6373-regulator.h b/include/linux/regulator/mt6373-regulator.h
new file mode 100644
index 000000000000..0f6a7c4739c2
--- /dev/null
+++ b/include/linux/regulator/mt6373-regulator.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ */
+
+#include <linux/bits.h>
+
+#ifndef __LINUX_REGULATOR_MT6373_H
+#define __LINUX_REGULATOR_MT6373_H
+
+/* Register */
+#define MT6373_TOP_CFG_ELR5			0x117
+#define MT6373_TOP_CFG_ELR5_SHUTDOWN		BIT(0)
+
+#define MT6373_PMIC_RG_BUCK0_EN_ADDR		0x210
+#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_BIT	0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_BIT	1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_BIT	2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_BIT	3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_BIT	4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_BIT	5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_BIT	6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_BIT	7
+
+#define MT6373_PMIC_RG_BUCK1_EN_ADDR		0x213
+#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_BIT	0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_BIT	1
+
+#define MT6373_PMIC_RG_BUCK0_LP_ADDR		0x216
+#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_BIT	0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_BIT	1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_BIT	2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_BIT	3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_BIT	4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_BIT	5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_BIT	6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_BIT	7
+
+#define MT6373_PMIC_RG_BUCK1_LP_ADDR		0x219
+#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_BIT	0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_BIT	1
+
+#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR	0x21c
+#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR	0x21d
+#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR	0x21e
+#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR	0x21f
+#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR	0x220
+#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR	0x221
+#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR	0x222
+#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR	0x223
+#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR	0x224
+#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR	0x225
+#define MT6373_PMIC_RG_BUCK_VOSEL_MASK		GENMASK(8, 0)
+
+#define MT6373_PLG_CFG_ELR1			0x37b
+#define MT6373_ELR_VARIANT_MASK			GENMASK(3, 2)
+#define MT6373_ELR_VARIANT_MT6373CW		1
+#define MT6373_RG_RSV_SWREG_H			0x9d9
+#define MT6373_RG_RSV_SWREG_VBUCK4_HW_CTRL	BIT(0)
+
+#define MT6373_BUCK_TOP_KEY_PROT_LO		0x13fa
+
+#define MT6373_PMIC_RG_BUCK1_FCCM_ADDR		0x196d
+#define MT6373_PMIC_RG_VBUCK8_FCCM_BIT		6
+#define MT6373_PMIC_RG_VBUCK9_FCCM_BIT		7
+
+#define MT6373_PMIC_RG_BUCK0_FCCM_ADDR		0x1a02
+#define MT6373_PMIC_RG_VBUCK0_FCCM_BIT		0
+#define MT6373_PMIC_RG_VBUCK1_FCCM_BIT		1
+#define MT6373_PMIC_RG_VBUCK2_FCCM_BIT		2
+#define MT6373_PMIC_RG_VBUCK3_FCCM_BIT		3
+
+#define MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR	0x1a82
+#define MT6373_PMIC_RG_VBUCK4_FCCM_BIT		0
+#define MT6373_PMIC_RG_VBUCK5_FCCM_BIT		1
+#define MT6373_PMIC_RG_VBUCK6_FCCM_BIT		2
+#define MT6373_PMIC_RG_VBUCK7_FCCM_BIT		3
+
+#define MT6373_PMIC_RG_VSRAM_DIGRF_AIF_VOSEL_ADDR 0x1b09
+#define MT6373_PMIC_RG_VSRAM_DIGRF_AIF_VOSEL_MASK GENMASK(6, 0)
+
+#define MT6373_PMIC_RG_LDO_VAUD18_ADDR		0x1b57
+#define MT6373_PMIC_RG_LDO_VUSB_ADDR		0x1b65
+#define MT6373_PMIC_RG_LDO_VAUX18_ADDR		0x1b73
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_ADDR	0x1b81
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_ADDR	0x1b8f
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_ADDR	0x1b9d
+#define MT6373_PMIC_RG_LDO_VCN33_1_ADDR		0x1bd7
+#define MT6373_PMIC_RG_LDO_VCN33_2_ADDR		0x1be5
+#define MT6373_PMIC_RG_LDO_VCN33_3_ADDR		0x1bf3
+#define MT6373_PMIC_RG_LDO_VCN18IO_ADDR		0x1c01
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_ADDR	0x1c0f
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_ADDR	0x1c1d
+#define MT6373_PMIC_RG_LDO_VANT18_ADDR		0x1c57
+#define MT6373_PMIC_RG_LDO_VEFUSE_ADDR		0x1c73
+#define MT6373_PMIC_RG_LDO_VMCH_ADDR		0x1c81
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR	0x1c8f
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_HIGH_ADDR	MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_LOW_ADDR	MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_POL_BIT	BIT(2)
+#define MT6373_PMIC_RG_LDO_VMC_ADDR		0x1c90
+#define MT6373_PMIC_RG_LDO_VIBR_ADDR		0x1c9e
+#define MT6373_PMIC_RG_LDO_VIO28_ADDR		0x1cd7
+#define MT6373_PMIC_RG_LDO_VFP_ADDR		0x1ce5
+#define MT6373_PMIC_RG_LDO_VTP_ADDR		0x1cf3
+#define MT6373_PMIC_RG_LDO_VSIM1_ADDR		0x1d01
+#define MT6373_PMIC_RG_LDO_VSIM2_ADDR		0x1d10
+#define MT6373_PMIC_RG_LDO_VSIM2_LP_ADDR	0x1d10
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_ADDR	0x1d57
+#define MT6373_PMIC_RG_VAUX18_VOCAL_ADDR	0x1dd8
+#define MT6373_PMIC_RG_VAUX18_VOSEL_ADDR	0x1dd9
+#define MT6373_PMIC_RG_VUSB_VOCAL_ADDR		0x1ddc
+#define MT6373_PMIC_RG_VUSB_VOSEL_ADDR		0x1ddd
+#define MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR	0x1de0
+#define MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR	0x1de1
+#define MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR	0x1de4
+#define MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR	0x1de5
+#define MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR	0x1de8
+#define MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR	0x1de9
+#define MT6373_PMIC_RG_VMCH_VOCAL_ADDR		0x1dec
+#define MT6373_PMIC_RG_VMCH_VOSEL_ADDR		0x1ded
+#define MT6373_PMIC_RG_VMCH_EINT_HIGH_VOSEL_ADDR MT6373_PMIC_RG_VMCH_VOSEL_ADDR
+#define MT6373_PMIC_RG_VMCH_EINT_LOW_VOSEL_ADDR	MT6373_PMIC_RG_VMCH_VOSEL_ADDR
+#define MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR	0x1df0
+#define MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR	0x1df1
+#define MT6373_PMIC_RG_VMC_VOCAL_ADDR		0x1df4
+#define MT6373_PMIC_RG_VMCH_EINT_HIGH_VOCAL_ADDR MT6373_PMIC_RG_VMC_VOCAL_ADDR
+#define MT6373_PMIC_RG_VMCH_EINT_LOW_VOCAL_ADDR	MT6373_PMIC_RG_VMC_VOCAL_ADDR
+#define MT6373_PMIC_RG_VMC_VOSEL_ADDR		0x1df5
+#define MT6373_PMIC_RG_VIBR_VOCAL_ADDR		0x1df8
+#define MT6373_PMIC_RG_VIBR_VOSEL_ADDR		0x1df9
+#define MT6373_PMIC_RG_VIO28_VOCAL_ADDR		0x1dfc
+#define MT6373_PMIC_RG_VIO28_VOSEL_ADDR		0x1dfd
+#define MT6373_PMIC_RG_VFP_VOCAL_ADDR		0x1e00
+#define MT6373_PMIC_RG_VFP_VOSEL_ADDR		0x1e01
+#define MT6373_PMIC_RG_VTP_VOCAL_ADDR		0x1e04
+#define MT6373_PMIC_RG_VTP_VOSEL_ADDR		0x1e05
+#define MT6373_PMIC_RG_VSIM1_VOCAL_ADDR		0x1e08
+#define MT6373_PMIC_RG_VSIM1_VOSEL_ADDR		0x1e09
+#define MT6373_PMIC_RG_VSIM2_VOCAL_ADDR		0x1e0c
+#define MT6373_PMIC_RG_VSIM2_VOSEL_ADDR		0x1e0d
+#define MT6373_PMIC_RG_VAUD18_VOCAL_ADDR	0x1e58
+#define MT6373_PMIC_RG_VAUD18_VOSEL_ADDR	0x1e59
+#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR	0x1e5c
+#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR	0x1e5d
+#define MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR	0x1e60
+#define MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR	0x1e61
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR	0x1e64
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR	0x1e65
+#define MT6373_PMIC_RG_VANT18_VOCAL_ADDR	0x1e68
+#define MT6373_PMIC_RG_VANT18_VOSEL_ADDR	0x1e69
+#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR	0x1ed8
+#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR	0x1ed9
+#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR	0x1edc
+#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR	0x1edd
+#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR	0x1f58
+#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR	0x1f59
+#define MT6373_PMIC_RG_LDO_VT_VOCALSEL_MASK	GENMASK(7, 0)
+
+#endif /* __LINUX_REGULATOR_MT6363_H */
+
-- 
2.50.1


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

* [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
                   ` (5 preceding siblings ...)
  2025-07-15 11:57 ` [PATCH v4 6/8] regulator: Add support for MediaTek MT6373 SPMI " AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  2025-07-15 13:55   ` Rob Herring (Arm)
  2025-07-15 11:57 ` [PATCH v4 8/8] drivers: mfd: Add support for MediaTek SPMI PMICs and MT6363/73 AngeloGioacchino Del Regno
  7 siblings, 1 reply; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst,
	Nícolas F. R. A. Prado

Add a binding for the MediaTek MT6363/6373 (and similar) multi
function PMICs connected over SPMI.

These PMICs are found on board designs using newer MediaTek SoCs,
such as the Dimensity 9400 Smartphone chip, or the Chromebook
MT8196 chip.

Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Link: https://lore.kernel.org/r/20250623120038.108891-2-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-8-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 .../bindings/mfd/mediatek,mt6363.yaml         | 110 ++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml
new file mode 100644
index 000000000000..b19755b3104c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml
@@ -0,0 +1,110 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,mt6363.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6363 series SPMI PMICs multi-function device
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description: |
+  Some MediaTek Power Management ICs (PMICs) found in board designs with
+  the Helio, Dimensity and/or Kompanio series of SoCs are interfaced to
+  the chip via the System Power Management Interface (SPMI) bus.
+
+  These PMICs are multi-function devices with various sub modules.
+  For example, those may include one, or more of the following:
+  - Auxiliary ADC Controller
+  - Clock Controller
+  - eFuses
+  - GPIO Controller
+  - Interrupt Controller
+  - Keys
+  - LEDs Controller
+  - Regulators
+  - RTC
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6363
+      - mediatek,mt6373
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 3
+
+patternProperties:
+  "^adc@[0-9a-f]+$":
+    type: object
+    $ref: /schemas/iio/adc/mediatek,mt6359-auxadc.yaml#
+    properties:
+      reg:
+        maxItems: 1
+    unevaluatedProperties: false
+
+  "^regulators@[0-9a-f]+$":
+    type: object
+    properties:
+      compatible:
+        contains:
+          enum:
+            - mediatek,mt6363-regulator
+            - mediatek,mt6373-regulator
+    oneOf:
+      - $ref: /schemas/regulator/mediatek,mt6363-regulator.yaml#
+      - $ref: /schemas/regulator/mediatek,mt6373-regulator.yaml#
+    additionalProperties: true
+
+required:
+  - compatible
+  - reg
+  - '#address-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/spmi/spmi.h>
+
+    spmi {
+      #address-cells = <2>;
+      #size-cells = <0>;
+
+      pmic@4 {
+        compatible = "mediatek,mt6363";
+        reg = <0x4 SPMI_USID>;
+        interrupts = <4 64 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-controller;
+        #address-cells = <1>;
+        #interrupt-cells = <3>;
+        #size-cells = <0>;
+
+        regulators@30 {
+          compatible = "mediatek,mt6363-regulator";
+          reg = <0x30>;
+        };
+
+        adc@1000 {
+          compatible = "mediatek,mt6363-auxadc";
+          reg = <0x1000>;
+          #io-channel-cells = <1>;
+        };
+      };
+    };
-- 
2.50.1


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

* [PATCH v4 8/8] drivers: mfd: Add support for MediaTek SPMI PMICs and MT6363/73
  2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
                   ` (6 preceding siblings ...)
  2025-07-15 11:57 ` [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC AngeloGioacchino Del Regno
@ 2025-07-15 11:57 ` AngeloGioacchino Del Regno
  7 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 11:57 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, lgirdwood, broonie, devicetree,
	linux-kernel, linux-arm-kernel, kernel, wenst,
	Nícolas F. R. A. Prado

This driver adds support for the MediaTek SPMI PMICs and their
interrupt controller (which is present in 95% of the cases).

Other than probing all of the sub-devices of a SPMI PMIC, this
sets up a regmap from the relevant SPMI bus and initializes an
interrupt controller with its irq domain and irqchip to handle
chained interrupts, with the SPMI bus itself being its parent
irq controller, and the PMIC being the outmost device.

This driver hence holds all of the information about a specific
PMIC's interrupts and will properly handle them, calling the
ISR for any subdevice that requested an interrupt.

As for the interrupt spec, this driver wants 3 interrupt cells,
but ignores the first one: this is because of how this first
revision of the MediaTek SPMI 2.0 Controller works, which does
not hold irq number information in its register, but delegates
that to the SPMI device - it's possible that this will change
in the future with a newer revision of the controller IP, and
this is the main reason for that.

To make use of this implementation, this driver also adds the
required bits to support MediaTek MT6363 and MT6373 SPMI PMICs.

Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Link: https://lore.kernel.org/r/20250623120038.108891-3-angelogioacchino.delregno@collabora.com
Link: https://lore.kernel.org/r/20250707134451.154346-9-angelogioacchino.delregno@collabora.com
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/mfd/Kconfig         |  17 ++
 drivers/mfd/Makefile        |   1 +
 drivers/mfd/mtk-spmi-pmic.c | 410 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/mt6363.h  |  26 +++
 include/linux/mfd/mt6373.h  |  21 ++
 5 files changed, 475 insertions(+)
 create mode 100644 drivers/mfd/mtk-spmi-pmic.c
 create mode 100644 include/linux/mfd/mt6363.h
 create mode 100644 include/linux/mfd/mt6373.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6fb3768e3d71..5119f58ba175 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1063,6 +1063,23 @@ config MFD_MT6397
 	  accessing the device; additional drivers must be enabled in order
 	  to use the functionality of the device.
 
+config MFD_MTK_SPMI_PMIC
+	tristate "MediaTek SPMI PMICs"
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	depends on OF
+	depends on SPMI
+	select REGMAP_SPMI
+	default y if ARCH_MEDIATEK
+	help
+	  Say yes here to enable support for MediaTek's SPMI PMICs.
+	  These PMICs made their first appearance in board designs using the
+          MediaTek Dimensity 9400 series of SoCs.
+	  Note that this will only be useful paired with descriptions of the
+	  independent functions as children nodes in the device tree.
+
+	  Say M here if you want to include support for the MediaTek SPMI
+	  PMICs as a module. The module will be called "mtk-spmi-pmic".
+
 config MFD_MENF21BMC
 	tristate "MEN 14F021P00 Board Management Controller Support"
 	depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 79495f9f3457..6f5af4921d9d 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -183,6 +183,7 @@ obj-$(CONFIG_MFD_MT6360)	+= mt6360-core.o
 obj-$(CONFIG_MFD_MT6370)	+= mt6370.o
 mt6397-objs			:= mt6397-core.o mt6397-irq.o mt6358-irq.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397.o
+obj-$(CONFIG_MFD_MTK_SPMI_PMIC)	+= mtk-spmi-pmic.o
 
 obj-$(CONFIG_RZ_MTU3)		+= rz-mtu3.o
 obj-$(CONFIG_ABX500_CORE)	+= abx500-core.o
diff --git a/drivers/mfd/mtk-spmi-pmic.c b/drivers/mfd/mtk-spmi-pmic.c
new file mode 100644
index 000000000000..512b53bdb0d1
--- /dev/null
+++ b/drivers/mfd/mtk-spmi-pmic.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/spmi.h>
+#include <linux/types.h>
+#include <linux/regmap.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/mfd/mt6363.h>
+#include <linux/mfd/mt6373.h>
+
+#define MTK_SPMI_PMIC_VAL_BITS		8
+#define MTK_SPMI_PMIC_CHIP_ID_REG_M	0xb
+#define MTK_SPMI_PMIC_RCS_IRQ_DONE	0x41b
+
+/**
+ * mtk_spmi_pmic_irq_group - Group of interrupts in SPMI PMIC
+ * @num_int_regs: Number of registers for this group of interrupts
+ * @con_reg:      PMIC Interrupt Group Control 0 register
+ * @sta_reg:      PMIC Interrupt Group Status 0 register
+ * @group_num:    PMIC Interrupt Group number - also corresponds to the
+ *                status bit in the global IRQ Control register
+ */
+struct mtk_spmi_pmic_irq_grp {
+	u8 hwirq_base;
+	u8 num_int_regs;
+	u16 con_reg;
+	u16 sta_reg;
+	u8 group_num;
+};
+
+/**
+ * mtk_spmi_pmic_pdata - SPMI PMIC Platform Data
+ * @pmic_irq:    Group of interrupts in SPMI PMIC
+ * @num_groups:  Number of groups of interrupts
+ * @con_reg_sz:  Size of Control registers, depends on existence
+ *               of SET and CLR registers in the layout
+ * @top_irq_reg: Global interrupt status register, explains which
+ *               group needs attention because of a group irq
+ * @chip_id_reg: Chip ID Register
+ */
+struct mtk_spmi_pmic_pdata {
+	const struct mtk_spmi_pmic_irq_grp *pmic_irq;
+	u8 num_groups;
+	u8 con_reg_sz;
+	u8 top_irq_reg;
+	u8 chip_id_reg;
+};
+
+/**
+ * mtk_spmi_pmic - Main driver structure
+ * @pdata:    SPMI PMIC Platform data
+ * @dev:      Handle to SPMI Device
+ * @dom:      IRQ Domain of the PMIC's interrupt controller
+ * @regmap:   Handle to PMIC regmap
+ * @irq_lock: Lock for the PMIC's irqchip
+ * @irq:      PMIC chained interrupt
+ */
+struct mtk_spmi_pmic {
+	const struct mtk_spmi_pmic_pdata *pdata;
+	struct device *dev;
+	struct irq_domain *dom;
+	struct regmap *regmap;
+	struct mutex irq_lock;
+	int irq;
+};
+
+static void mtk_spmi_pmic_irq_set_unmasking(struct irq_data *d, bool unmask)
+{
+	struct mtk_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	const struct mtk_spmi_pmic_pdata *pdata = pmic->pdata;
+	struct regmap *regmap = pmic->regmap;
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	unsigned short i;
+
+	for (i = 0; i < pdata->num_groups; i++) {
+		const struct mtk_spmi_pmic_irq_grp *irq_grp = &pdata->pmic_irq[i];
+		u32 con_reg;
+		u8 irq_en_bit;
+
+		if (hwirq < irq_grp->hwirq_base)
+			continue;
+
+		con_reg = irq_grp->con_reg + (pdata->con_reg_sz * i);
+		irq_en_bit = hwirq - irq_grp->hwirq_base;
+
+		regmap_assign_bits(regmap, con_reg, BIT(irq_en_bit), unmask);
+
+		break;
+	}
+}
+
+static void mtk_spmi_pmic_irq_mask(struct irq_data *d)
+{
+	mtk_spmi_pmic_irq_set_unmasking(d, false);
+}
+
+static void mtk_spmi_pmic_irq_unmask(struct irq_data *d)
+{
+	mtk_spmi_pmic_irq_set_unmasking(d, true);
+}
+
+static void mtk_spmi_pmic_irq_lock(struct irq_data *d)
+{
+	struct mtk_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
+
+	mutex_lock(&pmic->irq_lock);
+}
+
+static void mtk_spmi_pmic_irq_sync_unlock(struct irq_data *d)
+{
+	struct mtk_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
+
+	mutex_unlock(&pmic->irq_lock);
+}
+
+static struct irq_chip mtk_spmi_pmic_irq_chip = {
+	.name = "mtk-spmi-pmic",
+	.irq_mask = mtk_spmi_pmic_irq_mask,
+	.irq_unmask = mtk_spmi_pmic_irq_unmask,
+	.irq_bus_lock = mtk_spmi_pmic_irq_lock,
+	.irq_bus_sync_unlock = mtk_spmi_pmic_irq_sync_unlock,
+	.flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static int mtk_spmi_pmic_irq_domain_map(struct irq_domain *d, unsigned int virq,
+					irq_hw_number_t hwirq)
+{
+	struct mtk_spmi_pmic *pmic = d->host_data;
+
+	irq_set_chip_data(virq, pmic);
+	irq_set_chip_and_handler(virq, &mtk_spmi_pmic_irq_chip, handle_level_irq);
+
+	return 0;
+}
+
+static int mtk_spmi_pmic_irq_xlate(struct irq_domain *d, struct device_node *ctrlr,
+				  const u32 *intspec, unsigned int intsize,
+				  unsigned long *out_hwirq, unsigned int *out_type)
+{
+	struct mtk_spmi_pmic *pmic = d->host_data;
+	struct device *dev = pmic->dev;
+	struct irq_fwspec fwspec;
+
+	of_phandle_args_to_fwspec(ctrlr, intspec, intsize, &fwspec);
+	if (WARN_ON(fwspec.param_count < 3))
+		return -EINVAL;
+
+	/*
+	 * The IRQ number in intspec[0] is ignored on purpose here!
+	 *
+	 * This is because of how at least the first revision of the SPMI 2.0
+	 * controller works in MediaTek SoCs: the controller will raise an
+	 * interrupt for each SID (but doesn't know the details!), and the
+	 * specific IRQ number that got raised must be read from the PMIC or
+	 * its sub-device driver.
+	 * It's possible that this will change in the future with a newer
+	 * revision of the SPMI controller, and this is why the devicetree
+	 * holds the full intspec.
+	 */
+	*out_hwirq = intspec[1];
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+
+	dev_dbg(dev, "Found device IRQ %u chained from SPMI IRQ %x (map: 0x%lx)\n",
+		intspec[1], intspec[0], *out_hwirq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops mtk_spmi_pmic_irq_domain_ops = {
+	.map = mtk_spmi_pmic_irq_domain_map,
+	.xlate = mtk_spmi_pmic_irq_xlate,
+};
+
+static int mtk_spmi_pmic_handle_group_irq(struct mtk_spmi_pmic *pmic, int group)
+{
+	const struct mtk_spmi_pmic_irq_grp *irq_grp = &pmic->pdata->pmic_irq[group];
+	struct regmap *regmap = pmic->regmap;
+	struct device *dev = pmic->dev;
+	int i, ret;
+
+	for (i = 0; i < irq_grp->num_int_regs; i++) {
+		u32 status, saved_status;
+
+		ret = regmap_read(regmap, irq_grp->sta_reg + i, &status);
+		if (ret) {
+			dev_err(dev, "Could not read IRQ status register: %d", ret);
+			return ret;
+		}
+
+		if (status == 0)
+			continue;
+
+		saved_status = status;
+		do {
+			irq_hw_number_t hwirq;
+			u8 bit = __ffs(status);
+
+			/* Each reg has 8 bits: this is the first irq of this group */
+			hwirq = MTK_SPMI_PMIC_VAL_BITS * i;
+
+			/* Offset by this group's start interrupt */
+			hwirq += irq_grp->hwirq_base;
+
+			/* Finally, offset by the fired irq's bit number */
+			hwirq += bit;
+
+			status &= ~BIT(bit);
+
+			generic_handle_domain_irq(pmic->dom, hwirq);
+		} while (status);
+
+		/* Clear the interrupts by writing the previous status */
+		regmap_write(regmap, irq_grp->sta_reg + i, saved_status);
+	}
+
+	return 0;
+}
+
+static void mtk_spmi_pmic_handle_chained_irq(struct irq_desc *desc)
+{
+	struct mtk_spmi_pmic *pmic = irq_desc_get_handler_data(desc);
+	const struct mtk_spmi_pmic_pdata *pdata = pmic->pdata;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct regmap *regmap = pmic->regmap;
+	bool irq_handled = false;
+	int i, ret;
+	u32 val;
+
+	chained_irq_enter(chip, desc);
+
+	ret = regmap_read(regmap, pdata->top_irq_reg, &val);
+	if (ret)
+		handle_bad_irq(desc);
+
+	dev_dbg(pmic->dev, "PMIC IRQ Status: %x\n", val);
+
+	/* This is very unlikely to happen */
+	if (val == 0) {
+		chained_irq_exit(chip, desc);
+		return;
+	}
+
+	for (i = 0; i < pdata->num_groups; i++) {
+		const struct mtk_spmi_pmic_irq_grp *irq_grp = &pdata->pmic_irq[i];
+		u8 group_bit = BIT(irq_grp[i].group_num);
+
+		if (val & group_bit) {
+			ret = mtk_spmi_pmic_handle_group_irq(pmic, i);
+			if (ret == 0)
+				irq_handled = true;
+		}
+	}
+
+	/* The RCS flag has to be cleared even if the IRQ was not handled. */
+	ret = regmap_write(regmap, MTK_SPMI_PMIC_RCS_IRQ_DONE, 1);
+	if (ret)
+		dev_warn(pmic->dev, "Could not clear RCS flag!\n");
+
+	if (!irq_handled)
+		handle_bad_irq(desc);
+
+	chained_irq_exit(chip, desc);
+}
+
+static void mtk_spmi_pmic_irq_remove(void *data)
+{
+	struct mtk_spmi_pmic *pmic = (struct mtk_spmi_pmic *)data;
+
+	irq_set_chained_handler_and_data(pmic->irq, NULL, NULL);
+	irq_domain_remove(pmic->dom);
+}
+
+static int mtk_spmi_pmic_irq_init(struct spmi_device *sdev, struct regmap *regmap,
+				  const struct mtk_spmi_pmic_pdata *pdata)
+{
+	struct mtk_spmi_pmic *pmic;
+	int ret;
+
+	pmic = devm_kzalloc(&sdev->dev, sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	pmic->irq = of_irq_get(sdev->dev.of_node, 0);
+	if (pmic->irq < 0)
+		return dev_err_probe(&sdev->dev, pmic->irq, "Cannot get IRQ\n");
+
+	pmic->dev = &sdev->dev;
+	pmic->regmap = regmap;
+	pmic->pdata = pdata;
+	mutex_init(&pmic->irq_lock);
+
+	pmic->dom = irq_domain_add_tree(sdev->dev.of_node,
+					&mtk_spmi_pmic_irq_domain_ops, pmic);
+	if (!pmic->dom)
+		return dev_err_probe(&sdev->dev, -ENOMEM, "Cannot create IRQ domain\n");
+
+	ret = devm_add_action_or_reset(&sdev->dev, mtk_spmi_pmic_irq_remove, pmic);
+	if (ret) {
+		irq_domain_remove(pmic->dom);
+		return ret;
+	}
+
+	irq_set_chained_handler_and_data(pmic->irq, mtk_spmi_pmic_handle_chained_irq, pmic);
+
+	return 0;
+}
+
+#define MTK_SPMI_PMIC_IRQ_GROUP(pmic, grp, gnum, first_irq, last_irq)	\
+{									\
+	.hwirq_base = first_irq,					\
+	.num_int_regs = ((last_irq - first_irq) /			\
+			 MTK_SPMI_PMIC_VAL_BITS) + 1,			\
+	.con_reg = pmic##_##grp##_TOP_INT_CON0,				\
+	.sta_reg = pmic##_##grp##_TOP_INT_STATUS0,			\
+	.group_num = gnum,						\
+}
+
+static const struct mtk_spmi_pmic_irq_grp mt6363_irq_groups[] = {
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6363, BUCK, 0, 0, 9),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6363, LDO, 1, 16, 40),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6363, PSC, 2, 48, 57),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6363, MISC, 3, 64, 79),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6363, HK, 4, 80, 87),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6363, BM, 6, 88, 107)
+};
+
+static const struct mtk_spmi_pmic_irq_grp mt6373_irq_groups[] = {
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6373, BUCK, 0, 0, 9),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6373, LDO, 1, 16, 39),
+	MTK_SPMI_PMIC_IRQ_GROUP(MT6373, MISC, 3, 56, 71),
+};
+
+static const struct mtk_spmi_pmic_pdata mt6363_pdata = {
+	.pmic_irq = mt6363_irq_groups,
+	.num_groups = ARRAY_SIZE(mt6363_irq_groups),
+	.con_reg_sz = 3,
+	.top_irq_reg = MT6363_TOP_INT_STATUS1,
+	.chip_id_reg = MTK_SPMI_PMIC_CHIP_ID_REG_M,
+};
+
+static const struct mtk_spmi_pmic_pdata mt6373_pdata = {
+	.pmic_irq = mt6373_irq_groups,
+	.num_groups = ARRAY_SIZE(mt6373_irq_groups),
+	.con_reg_sz = 3,
+	.top_irq_reg = MT6373_TOP_INT_STATUS1,
+	.chip_id_reg = MTK_SPMI_PMIC_CHIP_ID_REG_M,
+};
+
+static const struct regmap_config mtk_spmi_regmap_config = {
+	.reg_bits	= 16,
+	.val_bits	= MTK_SPMI_PMIC_VAL_BITS,
+	.max_register	= 0xffff,
+	.fast_io	= true,
+};
+
+static int mtk_spmi_pmic_probe(struct spmi_device *sdev)
+{
+	const struct mtk_spmi_pmic_pdata *pdata;
+	struct device *dev = &sdev->dev;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_spmi_ext(sdev, &mtk_spmi_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	pdata = (const struct mtk_spmi_pmic_pdata *)device_get_match_data(&sdev->dev);
+	if (pdata && pdata->num_groups) {
+		ret = mtk_spmi_pmic_irq_init(sdev, regmap, pdata);
+		if (ret)
+			return ret;
+	}
+
+	return devm_of_platform_populate(dev);
+}
+
+static const struct of_device_id mtk_pmic_spmi_id_table[] = {
+	{ .compatible = "mediatek,mt6363", .data = &mt6363_pdata },
+	{ .compatible = "mediatek,mt6373", .data = &mt6373_pdata },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_pmic_spmi_id_table);
+
+static struct spmi_driver mtk_spmi_pmic_driver = {
+	.probe = mtk_spmi_pmic_probe,
+	.driver = {
+		.name = "mtk-spmi-pmic",
+		.of_match_table = mtk_pmic_spmi_id_table,
+	},
+};
+module_spmi_driver(mtk_spmi_pmic_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek SPMI PMIC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/mt6363.h b/include/linux/mfd/mt6363.h
new file mode 100644
index 000000000000..2e13398f5af5
--- /dev/null
+++ b/include/linux/mfd/mt6363.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#ifndef __MFD_MT6363_H__
+#define __MFD_MT6363_H__
+
+/* PMIC Registers */
+#define MT6363_MISC_TOP_INT_CON0	0x37
+#define MT6363_MISC_TOP_INT_STATUS0	0x43
+#define MT6363_TOP_INT_STATUS1		0x4e
+#define MT6363_PSC_TOP_INT_CON0		0x90f
+#define MT6363_PSC_TOP_INT_STATUS0	0x91b
+#define MT6363_BM_TOP_INT_CON0		0xc24
+#define MT6363_BM_TOP_INT_STATUS0	0xc36
+#define MT6363_HK_TOP_INT_CON0		0xf92
+#define MT6363_HK_TOP_INT_STATUS0	0xf9e
+#define MT6363_BUCK_TOP_INT_CON0	0x1411
+#define MT6363_BUCK_TOP_INT_STATUS0	0x141d
+#define MT6363_LDO_TOP_INT_CON0		0x1b11
+#define MT6363_LDO_TOP_INT_STATUS0	0x1b29
+
+#endif /* __MFD_MT6363_H__ */
diff --git a/include/linux/mfd/mt6373.h b/include/linux/mfd/mt6373.h
new file mode 100644
index 000000000000..3509e46447bd
--- /dev/null
+++ b/include/linux/mfd/mt6373.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#ifndef __MFD_MT6373_H__
+#define __MFD_MT6373_H__
+
+/* PMIC Registers */
+#define MT6373_MISC_TOP_INT_CON0	0x3c
+#define MT6373_MISC_TOP_INT_STATUS0	0x48
+#define MT6373_TOP_INT_MASK_CON0	0x4c
+#define MT6373_TOP_INT_STATUS1		0x53
+#define MT6373_BUCK_TOP_INT_CON0	0x1411
+#define MT6373_BUCK_TOP_INT_STATUS0	0x141d
+#define MT6373_LDO_TOP_INT_CON0		0x1b10
+#define MT6373_LDO_TOP_INT_STATUS0	0x1b22
+
+#endif /* __MFD_MT6373_H__ */
-- 
2.50.1


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

* Re: [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators
  2025-07-15 11:57 ` [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators AngeloGioacchino Del Regno
@ 2025-07-15 13:28   ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 13:28 UTC (permalink / raw)
  To: linux-mediatek
  Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg, lgirdwood, broonie,
	devicetree, linux-kernel, linux-arm-kernel, kernel, wenst

Il 15/07/25 13:57, AngeloGioacchino Del Regno ha scritto:
> Add bindings for the regulators found in the MediaTek MT6316 PMIC,
> usually found in board designs using the MT6991 Dimensity 9400 and
> on MT8196 Kompanio SoC for Chromebooks.
> 
> This chip is fully controlled by SPMI and has multiple variants
> providing different phase configurations.
> 
> Link: https://lore.kernel.org/r/20250624073548.29732-2-angelogioacchino.delregno@collabora.com
> Link: https://lore.kernel.org/r/20250707134451.154346-2-angelogioacchino.delregno@collabora.com

Btw, sorry about those Link: tags, those were completely unwanted... they
slipped through while using b4 and I forgot to remove them.

I'll wait for any feedback or tags and will resend the series with those
tags removed.

Thanks,
Angelo

> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
>   .../regulator/mediatek,mt6316b-regulator.yaml | 46 +++++++++++++++++++
>   .../regulator/mediatek,mt6316c-regulator.yaml | 46 +++++++++++++++++++
>   .../regulator/mediatek,mt6316d-regulator.yaml | 41 +++++++++++++++++
>   3 files changed, 133 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
>   create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
>   create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml
> 
> diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
> new file mode 100644
> index 000000000000..e7a6b70cdab2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6316b-regulator.yaml
> @@ -0,0 +1,46 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/mediatek,mt6316b-regulator.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT6316 BP/VP SPMI PMIC Regulators
> +
> +maintainers:
> +  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> +
> +description:
> +  The MediaTek MT6316BP/VP PMICs are fully controlled by SPMI interface, both
> +  feature four step-down DC/DC (buck) converters, and provides 2+2 Phases,
> +  joining Buck 1+2 for the first phase, and Buck 3+4 for the second phase.
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt6316b-regulator
> +
> +  vbuck12:
> +    type: object
> +    $ref: regulator.yaml#
> +    unevaluatedProperties: false
> +
> +  vbuck34:
> +    type: object
> +    $ref: regulator.yaml#
> +    unevaluatedProperties: false
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    pmic {
> +      regulators {
> +        compatible = "mediatek,mt6316b-regulator";
> +
> +        vbuck12 {
> +          regulator-min-microvolt = <450000>;
> +          regulator-max-microvolt = <965000>;
> +          regulator-always-on;
> +        };
> +      };
> +    };
> +...
> diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
> new file mode 100644
> index 000000000000..0b9239a595ed
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6316c-regulator.yaml
> @@ -0,0 +1,46 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/mediatek,mt6316c-regulator.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT6316 CP/HP/KP SPMI PMIC Regulators
> +
> +maintainers:
> +  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> +
> +description:
> +  The MediaTek MT6316CP/HP/KP PMICs are fully controlled by SPMI interface,
> +  features four step-down DC/DC (buck) converters, and provides 3+1 Phases,
> +  joining Buck 1+2+4 for the first phase, and uses Buck 3 for the second.
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt6316c-regulator
> +
> +  vbuck124:
> +    type: object
> +    $ref: regulator.yaml#
> +    unevaluatedProperties: false
> +
> +  vbuck3:
> +    type: object
> +    $ref: regulator.yaml#
> +    unevaluatedProperties: false
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    pmic {
> +      regulators {
> +        compatible = "mediatek,mt6316c-regulator";
> +
> +        vbuck124 {
> +          regulator-min-microvolt = <450000>;
> +          regulator-max-microvolt = <1277500>;
> +          regulator-always-on;
> +        };
> +      };
> +    };
> +...
> diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml
> new file mode 100644
> index 000000000000..460c02bf69de
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6316d-regulator.yaml
> @@ -0,0 +1,41 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/mediatek,mt6316d-regulator.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT6316 DP/TP SPMI PMIC Regulators
> +
> +maintainers:
> +  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> +
> +description:
> +  The MediaTek MT6316DP/TP PMICs are fully controlled by SPMI interface, both
> +  feature four step-down DC/DC (buck) converters, and provides a single Phase,
> +  joining Buck 1+2+3+4.
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt6316d-regulator
> +
> +  vbuck1234:
> +    type: object
> +    $ref: regulator.yaml#
> +    unevaluatedProperties: false
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    pmic {
> +      regulators {
> +        compatible = "mediatek,mt6316d-regulator";
> +
> +        vbuck1234 {
> +          regulator-min-microvolt = <400000>;
> +          regulator-max-microvolt = <1277500>;
> +          regulator-always-on;
> +        };
> +      };
> +    };
> +...


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

* Re: [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC
  2025-07-15 11:57 ` [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC AngeloGioacchino Del Regno
@ 2025-07-15 13:55   ` Rob Herring (Arm)
  2025-07-15 13:57     ` AngeloGioacchino Del Regno
  0 siblings, 1 reply; 12+ messages in thread
From: Rob Herring (Arm) @ 2025-07-15 13:55 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno
  Cc: broonie, lee, linux-arm-kernel, matthias.bgg, conor+dt, wenst,
	devicetree, linux-mediatek, linux-kernel, kernel,
	Nícolas F. R. A. Prado, krzk+dt, lgirdwood


On Tue, 15 Jul 2025 13:57:17 +0200, AngeloGioacchino Del Regno wrote:
> Add a binding for the MediaTek MT6363/6373 (and similar) multi
> function PMICs connected over SPMI.
> 
> These PMICs are found on board designs using newer MediaTek SoCs,
> such as the Dimensity 9400 Smartphone chip, or the Chromebook
> MT8196 chip.
> 
> Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
> Link: https://lore.kernel.org/r/20250623120038.108891-2-angelogioacchino.delregno@collabora.com
> Link: https://lore.kernel.org/r/20250707134451.154346-8-angelogioacchino.delregno@collabora.com
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
>  .../bindings/mfd/mediatek,mt6363.yaml         | 110 ++++++++++++++++++
>  1 file changed, 110 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: pmic@4 (mediatek,mt6363): adc@1000: 'reg' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6363.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: pmic@4 (mediatek,mt6363): regulators@30: 'oneOf' conditional failed, one must be fixed:
	'reg' does not match any of the regexes: '^buck-(sshub[124]|vb[1-7]|vs[1-3])$', '^ldo-v(aux|m|rf-io|tref)18$', '^ldo-va(12-1|12-2|15)$', '^ldo-vcn(13|15)$', '^ldo-vio(0p75|18)$', '^ldo-vrf(0p9|12|13|18)$', '^ldo-vsram-(apu|cpub|cpum|cpul|digrf|mdfe|modem)$', '^ldo-vufs(12|18)$', '^pinctrl-[0-9]+$'
	'reg' does not match any of the regexes: '^pinctrl-[0-9]+$', '^v(ant|aud|aux)18$', '^v(cn18io|efuse|ibr|io28|sram-digrf-aif|usb)', '^v(f|t)p', '^vbuck([0123456789]|4-ufs)$', '^vbuck4(-ufs)?$', '^vcn33-[123]$', '^vmc(h)?$', '^vmch-(eint-low|eint-high)?$', '^vrf(09|12|13|18|io18)-aif$', '^vsim[12]$'
	'mediatek,mt6373-regulator' was expected
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6363.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: regulators@30 (mediatek,mt6363-regulator): 'reg' does not match any of the regexes: '^buck-(sshub[124]|vb[1-7]|vs[1-3])$', '^ldo-v(aux|m|rf-io|tref)18$', '^ldo-va(12-1|12-2|15)$', '^ldo-vcn(13|15)$', '^ldo-vio(0p75|18)$', '^ldo-vrf(0p9|12|13|18)$', '^ldo-vsram-(apu|cpub|cpum|cpul|digrf|mdfe|modem)$', '^ldo-vufs(12|18)$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/regulator/mediatek,mt6363-regulator.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: adc@1000 (mediatek,mt6363-auxadc): 'reg' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250715115718.176495-8-angelogioacchino.delregno@collabora.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


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

* Re: [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC
  2025-07-15 13:55   ` Rob Herring (Arm)
@ 2025-07-15 13:57     ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 12+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-07-15 13:57 UTC (permalink / raw)
  To: Rob Herring (Arm)
  Cc: broonie, lee, linux-arm-kernel, matthias.bgg, conor+dt, wenst,
	devicetree, linux-mediatek, linux-kernel, kernel,
	Nícolas F. R. A. Prado, krzk+dt, lgirdwood

Il 15/07/25 15:55, Rob Herring (Arm) ha scritto:
> 
> On Tue, 15 Jul 2025 13:57:17 +0200, AngeloGioacchino Del Regno wrote:
>> Add a binding for the MediaTek MT6363/6373 (and similar) multi
>> function PMICs connected over SPMI.
>>
>> These PMICs are found on board designs using newer MediaTek SoCs,
>> such as the Dimensity 9400 Smartphone chip, or the Chromebook
>> MT8196 chip.
>>
>> Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
>> Link: https://lore.kernel.org/r/20250623120038.108891-2-angelogioacchino.delregno@collabora.com
>> Link: https://lore.kernel.org/r/20250707134451.154346-8-angelogioacchino.delregno@collabora.com
>> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>> ---
>>   .../bindings/mfd/mediatek,mt6363.yaml         | 110 ++++++++++++++++++
>>   1 file changed, 110 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6363.yaml
>>
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> yamllint warnings/errors:
> 
> dtschema/dtc warnings/errors:
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: pmic@4 (mediatek,mt6363): adc@1000: 'reg' does not match any of the regexes: '^pinctrl-[0-9]+$'
> 	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6363.yaml#
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: pmic@4 (mediatek,mt6363): regulators@30: 'oneOf' conditional failed, one must be fixed:
> 	'reg' does not match any of the regexes: '^buck-(sshub[124]|vb[1-7]|vs[1-3])$', '^ldo-v(aux|m|rf-io|tref)18$', '^ldo-va(12-1|12-2|15)$', '^ldo-vcn(13|15)$', '^ldo-vio(0p75|18)$', '^ldo-vrf(0p9|12|13|18)$', '^ldo-vsram-(apu|cpub|cpum|cpul|digrf|mdfe|modem)$', '^ldo-vufs(12|18)$', '^pinctrl-[0-9]+$'
> 	'reg' does not match any of the regexes: '^pinctrl-[0-9]+$', '^v(ant|aud|aux)18$', '^v(cn18io|efuse|ibr|io28|sram-digrf-aif|usb)', '^v(f|t)p', '^vbuck([0123456789]|4-ufs)$', '^vbuck4(-ufs)?$', '^vcn33-[123]$', '^vmc(h)?$', '^vmch-(eint-low|eint-high)?$', '^vrf(09|12|13|18|io18)-aif$', '^vsim[12]$'
> 	'mediatek,mt6373-regulator' was expected
> 	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6363.yaml#
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: regulators@30 (mediatek,mt6363-regulator): 'reg' does not match any of the regexes: '^buck-(sshub[124]|vb[1-7]|vs[1-3])$', '^ldo-v(aux|m|rf-io|tref)18$', '^ldo-va(12-1|12-2|15)$', '^ldo-vcn(13|15)$', '^ldo-vio(0p75|18)$', '^ldo-vrf(0p9|12|13|18)$', '^ldo-vsram-(apu|cpub|cpum|cpul|digrf|mdfe|modem)$', '^ldo-vufs(12|18)$', '^pinctrl-[0-9]+$'
> 	from schema $id: http://devicetree.org/schemas/regulator/mediatek,mt6363-regulator.yaml#
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6363.example.dtb: adc@1000 (mediatek,mt6363-auxadc): 'reg' does not match any of the regexes: '^pinctrl-[0-9]+$'
> 	from schema $id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml#
> 
> doc reference errors (make refcheckdocs):
> 
> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250715115718.176495-8-angelogioacchino.delregno@collabora.com
> 
> The base for the series is generally the latest rc1. A different dependency
> should be noted in *this* patch.
> 
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
> 
> pip3 install dtschema --upgrade
> 
> Please check and re-submit after running the above command yourself. Note
> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> your schema. However, it must be unset to test all examples with your schema.
> 

Uff. I've sent the wrong series. Sorry for the noise.

Sending v5 asap.

Sorry again,
Angelo

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

end of thread, other threads:[~2025-07-15 13:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-15 11:57 [PATCH v4 0/8] Add support MT6316/6363/MT6373 PMICs regulators and MFD AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 1/8] dt-bindings: regulator: Document MediaTek MT6316 PMIC Regulators AngeloGioacchino Del Regno
2025-07-15 13:28   ` AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 2/8] regulator: Add support for MediaTek MT6316 SPMI " AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 3/8] dt-bindings: regulator: Document MediaTek MT6363 " AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 4/8] regulator: Add support for MediaTek MT6363 SPMI " AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 5/8] dt-bindings: regulator: Document MediaTek MT6373 " AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 6/8] regulator: Add support for MediaTek MT6373 SPMI " AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 7/8] dt-bindings: mfd: Add binding for MediaTek MT6363 series SPMI PMIC AngeloGioacchino Del Regno
2025-07-15 13:55   ` Rob Herring (Arm)
2025-07-15 13:57     ` AngeloGioacchino Del Regno
2025-07-15 11:57 ` [PATCH v4 8/8] drivers: mfd: Add support for MediaTek SPMI PMICs and MT6363/73 AngeloGioacchino Del Regno

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).