devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Add PMIC and SPMI driver for mt8196
@ 2025-03-14  7:32 Lu.Tang
  2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
                   ` (6 more replies)
  0 siblings, 7 replies; 24+ messages in thread
From: Lu.Tang @ 2025-03-14  7:32 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group, Lu.Tang

This series is based on linux-next.

Changes in v0:
- Modify SPMI driver for mt8196
- Add SPMI PMIC mfd driver
- Add PMIC regulator driver for mt8196

*** BLURB HERE ***

Lu.Tang (5):
  pmic: mediatek: Add pmic auxadc driver
  pmic: mediatek: Add pmic regulator driver
  pmic: mediatek: Add spmi pmic mfd driver
  spmi: mediatek: modify spmi dirver for mt8196
  dt-bindings: pmic: mediatek: Add pmic documents

 .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |   31 +
 .../bindings/input/mediatek,pmic-keys.yaml    |    1 +
 .../bindings/mfd/mediatek,mt6685.yaml         |   50 +
 .../bindings/mfd/mediatek,spmi-pmic.yaml      |  173 +++
 .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |    1 +
 drivers/iio/adc/Kconfig                       |   10 +
 drivers/iio/adc/Makefile                      |    1 +
 drivers/iio/adc/mtk-spmi-pmic-adc.c           |  576 +++++++++
 drivers/mfd/Kconfig                           |   26 +
 drivers/mfd/Makefile                          |    2 +
 drivers/mfd/mt6685-core.c                     |   83 ++
 drivers/mfd/mtk-spmi-pmic.c                   |  518 ++++++++
 drivers/regulator/Kconfig                     |   34 +
 drivers/regulator/Makefile                    |    3 +
 drivers/regulator/mt6316-regulator.c          |  381 ++++++
 drivers/regulator/mt6363-regulator.c          | 1106 +++++++++++++++++
 drivers/regulator/mt6373-regulator.c          |  826 ++++++++++++
 drivers/spmi/spmi-mtk-pmif.c                  | 1040 +++++++++++++++-
 include/linux/mfd/mt6363/core.h               |  134 ++
 include/linux/mfd/mt6363/registers.h          |  168 +++
 include/linux/mfd/mt6373/core.h               |   94 ++
 include/linux/mfd/mt6373/registers.h          |   53 +
 include/linux/regulator/mt6316-regulator.h    |   48 +
 include/linux/regulator/mt6363-regulator.h    |  424 +++++++
 include/linux/regulator/mt6373-regulator.h    |  318 +++++
 25 files changed, 6037 insertions(+), 64 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
 create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c
 create mode 100644 drivers/mfd/mt6685-core.c
 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/core.h
 create mode 100644 include/linux/mfd/mt6363/registers.h
 create mode 100644 include/linux/mfd/mt6373/core.h
 create mode 100644 include/linux/mfd/mt6373/registers.h
 create mode 100644 include/linux/regulator/mt6316-regulator.h
 create mode 100644 include/linux/regulator/mt6363-regulator.h
 create mode 100644 include/linux/regulator/mt6373-regulator.h

-- 
2.46.0


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

* [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
@ 2025-03-14  7:32 ` Lu.Tang
  2025-03-14  8:53   ` AngeloGioacchino Del Regno
                     ` (2 more replies)
  2025-03-14  7:32 ` [PATCH 2/5] pmic: mediatek: Add pmic regulator driver Lu.Tang
                   ` (5 subsequent siblings)
  6 siblings, 3 replies; 24+ messages in thread
From: Lu.Tang @ 2025-03-14  7:32 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group, Lu.Tang

From: "Lu.Tang" <lu.tang@mediatek.com>

Add pmic mt6363 and mt6373 auxadc driver

Signed-off-by: Lu Tang <lu.tang@mediatek.com>
---
 drivers/iio/adc/Kconfig             |  10 +
 drivers/iio/adc/Makefile            |   1 +
 drivers/iio/adc/mtk-spmi-pmic-adc.c | 576 ++++++++++++++++++++++++++++
 3 files changed, 587 insertions(+)
 create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 27413516216c..7c4b5f8f7209 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1039,6 +1039,16 @@ config MEDIATEK_MT6577_AUXADC
 	  This driver can also be built as a module. If so, the module will be
 	  called mt6577_auxadc.
 
+config MEDIATEK_SPMI_PMIC_ADC
+	tristate "MediaTek SPMI PMIC ADC Support"
+	depends on MFD_MTK_SPMI_PMIC
+	help
+	  Say yes here to enable support for MediaTek SPMI PMIC ADC.
+	  The driver supports multiple channels read.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called mtk-spmi-pmic-adc.
+
 config MEN_Z188_ADC
 	tristate "MEN 16z188 ADC IP Core support"
 	depends on MCB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 9f26d5eca822..b3224abea040 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
 obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
 obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
+obj-$(CONFIG_MEDIATEK_SPMI_PMIC_ADC) += mtk-spmi-pmic-adc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
 obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
diff --git a/drivers/iio/adc/mtk-spmi-pmic-adc.c b/drivers/iio/adc/mtk-spmi-pmic-adc.c
new file mode 100644
index 000000000000..61e062bc8cf5
--- /dev/null
+++ b/drivers/iio/adc/mtk-spmi-pmic-adc.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/mt6363/registers.h>
+#include <linux/mfd/mt6373/registers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/iio/mt635x-auxadc.h>
+
+#define AUXADC_RDY_BIT			BIT(15)
+
+#define AUXADC_DEF_R_RATIO		1
+#define AUXADC_DEF_AVG_NUM		32
+
+#define AUXADC_AVG_TIME_US		10
+#define AUXADC_POLL_DELAY_US		100
+#define AUXADC_TIMEOUT_US		32000
+#define VOLT_FULL			1840
+
+#define IMP_VOLT_FULL			18400
+#define IMIX_R_MIN_MOHM			100
+#define IMIX_R_CALI_CNT			2
+
+#define EXT_THR_PURES_SHIFT		3
+#define EXT_THR_SEL_MASK		0x1F
+
+#define DT_CHANNEL_CONVERT(val)		((val) & 0xFF)
+#define DT_PURES_CONVERT(val)		(((val) & 0xFF00) >> 8)
+
+struct pmic_adc_device {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex lock;
+	struct iio_chan_spec *iio_chans;
+	unsigned int nchannels;
+	const struct auxadc_info *info;
+	struct regulator *isink_load;
+	int imix_r;
+	int imp_curr;
+	int pre_uisoc;
+};
+
+static struct pmic_adc_device *imix_r_dev;
+
+/*
+ * @ch_name:	HW channel name
+ * @res:	ADC resolution
+ * @r_ratio:	resistance ratio, represented by r_ratio[0] / r_ratio[1]
+ * @avg_num:	sampling times of AUXADC measurements then average it
+ * @regs:	request and data output registers for this channel
+ */
+struct auxadc_channels {
+	enum iio_chan_type type;
+	long info_mask;
+	/* AUXADC channel attribute */
+	const char *ch_name;
+	unsigned char res;
+	unsigned char r_ratio[2];
+	unsigned short avg_num;
+	const struct auxadc_regs *regs;
+};
+
+#define AUXADC_CHANNEL(_ch_name, _res)	\
+	[AUXADC_##_ch_name] = {				\
+		.type = IIO_VOLTAGE,			\
+		.info_mask = BIT(IIO_CHAN_INFO_RAW) |		\
+			     BIT(IIO_CHAN_INFO_PROCESSED),	\
+		.ch_name = __stringify(_ch_name),	\
+		.res = _res,				\
+	}
+
+/*
+ * The array represents all possible AUXADC channels found
+ * in the supported PMICs.
+ */
+static struct auxadc_channels auxadc_chans[] = {
+	AUXADC_CHANNEL(BATADC, 15),
+	AUXADC_CHANNEL(VCDT, 12),
+	AUXADC_CHANNEL(BAT_TEMP, 12),
+	AUXADC_CHANNEL(CHIP_TEMP, 12),
+	AUXADC_CHANNEL(VCORE_TEMP, 12),
+	AUXADC_CHANNEL(VPROC_TEMP, 12),
+	AUXADC_CHANNEL(VGPU_TEMP, 12),
+	AUXADC_CHANNEL(ACCDET, 12),
+	AUXADC_CHANNEL(HPOFS_CAL, 15),
+	AUXADC_CHANNEL(VTREF, 12),
+	AUXADC_CHANNEL(VBIF, 12),
+	AUXADC_CHANNEL(IMP, 15),
+	[AUXADC_IMIX_R] = {
+		.type = IIO_RESISTANCE,
+		.info_mask = BIT(IIO_CHAN_INFO_RAW),
+		.ch_name = "IMIX_R",
+	},
+	AUXADC_CHANNEL(VSYSSNS, 15),
+	AUXADC_CHANNEL(VIN1, 15),
+	AUXADC_CHANNEL(VIN2, 15),
+	AUXADC_CHANNEL(VIN3, 15),
+	AUXADC_CHANNEL(VIN4, 15),
+	AUXADC_CHANNEL(VIN5, 15),
+	AUXADC_CHANNEL(VIN6, 15),
+	AUXADC_CHANNEL(VIN7, 15),
+};
+
+struct auxadc_regs {
+	unsigned int enable_reg;
+	unsigned int enable_mask;
+	unsigned int ready_reg;
+	unsigned int ready_mask;
+	unsigned int value_reg;
+	unsigned int ext_thr_sel;
+	u8 src_sel;
+};
+
+#define AUXADC_REG(_ch_name, _chip, _enable_reg, _enable_mask, _value_reg) \
+	[AUXADC_##_ch_name] = {				\
+		.enable_reg = _chip##_##_enable_reg,	\
+		.enable_mask = _enable_mask,		\
+		.ready_reg = _chip##_##_value_reg,	\
+		.ready_mask = AUXADC_RDY_BIT,		\
+		.value_reg = _chip##_##_value_reg,	\
+	}						\
+
+#define TIA_ADC_REG(_src_sel, _chip)	\
+	[AUXADC_VIN##_src_sel] = {			\
+		.enable_reg = _chip##_AUXADC_RQST1,	\
+		.enable_mask = BIT(4),			\
+		.ready_reg = _chip##_AUXADC_ADC_CH12_L,	\
+		.ready_mask = AUXADC_RDY_BIT,		\
+		.value_reg = _chip##_AUXADC_ADC_CH12_L,	\
+		.ext_thr_sel = _chip##_SDMADC_CON0,	\
+		.src_sel = _src_sel,			\
+	}						\
+
+static const struct auxadc_regs mt6363_auxadc_regs_tbl[] = {
+	AUXADC_REG(BATADC, MT6363, AUXADC_RQST0, BIT(0), AUXADC_ADC0_L),
+	AUXADC_REG(BAT_TEMP, MT6363, AUXADC_RQST0, BIT(3), AUXADC_ADC3_L),
+	AUXADC_REG(CHIP_TEMP, MT6363, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L),
+	AUXADC_REG(VCORE_TEMP, MT6363, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L),
+	AUXADC_REG(VPROC_TEMP, MT6363, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L),
+	AUXADC_REG(VGPU_TEMP, MT6363, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L),
+	AUXADC_REG(VTREF, MT6363, AUXADC_RQST1, BIT(3), AUXADC_ADC11_L),
+	[AUXADC_IMP] = {
+		.enable_reg = MT6363_AUXADC_IMP0,
+		.enable_mask = BIT(0),
+		.ready_reg = MT6363_AUXADC_IMP1,
+		.ready_mask = BIT(7),
+		.value_reg = MT6363_AUXADC_ADC42_L,
+	},
+	AUXADC_REG(VSYSSNS, MT6363, AUXADC_RQST1, BIT(6), AUXADC_ADC_CH14_L),
+	TIA_ADC_REG(1, MT6363),
+	TIA_ADC_REG(2, MT6363),
+	TIA_ADC_REG(3, MT6363),
+	TIA_ADC_REG(4, MT6363),
+	TIA_ADC_REG(5, MT6363),
+	TIA_ADC_REG(6, MT6363),
+	TIA_ADC_REG(7, MT6363),
+};
+
+static const struct auxadc_regs mt6373_auxadc_regs_tbl[] = {
+	AUXADC_REG(CHIP_TEMP, MT6373, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L),
+	AUXADC_REG(VCORE_TEMP, MT6373, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L),
+	AUXADC_REG(VPROC_TEMP, MT6373, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L),
+	AUXADC_REG(VGPU_TEMP, MT6373, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L),
+	TIA_ADC_REG(1, MT6373),
+	TIA_ADC_REG(2, MT6373),
+	TIA_ADC_REG(3, MT6373),
+	TIA_ADC_REG(4, MT6373),
+	TIA_ADC_REG(5, MT6373),
+};
+
+struct auxadc_info {
+	const struct auxadc_regs *regs_tbl;
+};
+
+static const struct auxadc_info mt6363_info = {
+	.regs_tbl = mt6363_auxadc_regs_tbl,
+};
+
+static const struct auxadc_info mt6373_info = {
+	.regs_tbl = mt6373_auxadc_regs_tbl,
+};
+
+#define regmap_bulk_read_poll_timeout(map, addr, val, val_count, cond, sleep_us, timeout_us) \
+({ \
+	u64 __timeout_us = (timeout_us); \
+	unsigned long __sleep_us = (sleep_us); \
+	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
+	int __ret; \
+	might_sleep_if(__sleep_us); \
+	for (;;) { \
+		__ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \
+		if (__ret) \
+			break; \
+		if (cond) \
+			break; \
+		if ((__timeout_us) && \
+		    ktime_compare(ktime_get(), __timeout) > 0) { \
+			__ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \
+			break; \
+		} \
+		if (__sleep_us) \
+			usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
+	} \
+	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
+/*
+ * @adc_dev:	 pointer to the struct pmic_adc_device
+ * @auxadc_chan: pointer to the struct auxadc_channels, it represents specific
+		 auxadc channel
+ * @val:	 pointer to output value
+ */
+static int get_auxadc_out(struct pmic_adc_device *adc_dev,
+			  int channel, int channel2, int *val)
+{
+	int ret;
+	u16 buf = 0;
+	const struct auxadc_channels *auxadc_chan = &auxadc_chans[channel];
+
+	if (!auxadc_chan->regs)
+		return -EINVAL;
+
+	if (auxadc_chan->regs->ext_thr_sel) {
+		buf = (channel2 << EXT_THR_PURES_SHIFT)
+			| auxadc_chan->regs->src_sel;
+		ret = regmap_update_bits(adc_dev->regmap,
+					 auxadc_chan->regs->ext_thr_sel,
+					 EXT_THR_SEL_MASK, buf);
+		if (ret < 0)
+			return ret;
+	}
+	regmap_write(adc_dev->regmap,
+		     auxadc_chan->regs->enable_reg,
+		     auxadc_chan->regs->enable_mask);
+	usleep_range(auxadc_chan->avg_num * AUXADC_AVG_TIME_US,
+		     (auxadc_chan->avg_num + 1) * AUXADC_AVG_TIME_US);
+
+	ret = regmap_bulk_read_poll_timeout(adc_dev->regmap,
+					    auxadc_chan->regs->value_reg,
+					    buf, 2,
+					    (buf & AUXADC_RDY_BIT),
+					    AUXADC_POLL_DELAY_US,
+					    AUXADC_TIMEOUT_US);
+	*val = buf & (BIT(auxadc_chan->res) - 1);
+	if (ret)
+		dev_err(adc_dev->dev, "%s ret error code:%d!\n", auxadc_chan->ch_name, ret);
+
+	/* set PURES to OPEN after measuring done */
+	if (auxadc_chan->regs->ext_thr_sel) {
+		buf = (ADC_PURES_OPEN << EXT_THR_PURES_SHIFT)
+			| auxadc_chan->regs->src_sel;
+		ret = regmap_update_bits(adc_dev->regmap,
+					 auxadc_chan->regs->ext_thr_sel,
+					 EXT_THR_SEL_MASK, buf);
+	}
+
+	return ret;
+}
+
+static int gauge_get_imp_ibat(void)
+{
+	struct power_supply *psy;
+	union power_supply_propval prop;
+	int ret;
+
+	psy = power_supply_get_by_name("mtk-gauge");
+	if (!psy)
+		return 0;
+
+	ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop);
+	if (ret)
+		return ret;
+
+	power_supply_put(psy);
+	return prop.intval;
+}
+
+static int get_imp_out(struct pmic_adc_device *adc_dev, int *val)
+{
+	int ret;
+	unsigned int buf = 0;
+	const struct auxadc_channels *auxadc_chan = &auxadc_chans[AUXADC_IMP];
+
+	if (!auxadc_chan->regs)
+		return -EINVAL;
+
+	regmap_write(adc_dev->regmap,
+		     auxadc_chan->regs->enable_reg,
+		     auxadc_chan->regs->enable_mask);
+	ret = regmap_read_poll_timeout(adc_dev->regmap, auxadc_chan->regs->ready_reg,
+					   buf, buf & auxadc_chan->regs->ready_mask,
+					   AUXADC_POLL_DELAY_US,
+					   AUXADC_TIMEOUT_US);
+	if (ret) {
+		dev_err(adc_dev->dev, "%s %s ret error code:%d!\n",
+			__func__, auxadc_chan->ch_name, ret);
+		return ret;
+	}
+
+	ret = regmap_bulk_read(adc_dev->regmap, auxadc_chan->regs->value_reg, (u8 *) &buf, 2);
+	if (ret)
+		return ret;
+	*val = buf & (BIT(auxadc_chan->res) - 1);
+	adc_dev->imp_curr = gauge_get_imp_ibat();
+
+	regmap_write(adc_dev->regmap,
+		     auxadc_chan->regs->enable_reg, 0);
+
+	return 0;
+}
+
+static int pmic_adc_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct pmic_adc_device *adc_dev = iio_priv(indio_dev);
+	const struct auxadc_channels *auxadc_chan;
+	int auxadc_out = 0;
+	int ret = 0;
+
+	mutex_lock(&adc_dev->lock);
+	switch (chan->channel) {
+	case AUXADC_IMP:
+		ret = get_imp_out(adc_dev, &auxadc_out);
+		break;
+	case AUXADC_IMIX_R:
+		auxadc_out = adc_dev->imix_r;
+		break;
+	default:
+		ret = get_auxadc_out(adc_dev,
+				     chan->channel, chan->channel2,
+				     &auxadc_out);
+		break;
+	}
+	mutex_unlock(&adc_dev->lock);
+
+	if (ret && ret != -ETIMEDOUT)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		auxadc_chan = &auxadc_chans[chan->channel];
+		*val = auxadc_out * auxadc_chan->r_ratio[0] * VOLT_FULL;
+		*val = (*val / auxadc_chan->r_ratio[1]) >> auxadc_chan->res;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_RAW:
+		*val = auxadc_out;
+		ret = IIO_VAL_INT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (chan->channel == AUXADC_IMP) {
+		*val2 = adc_dev->imp_curr;
+		ret = IIO_VAL_INT_MULTIPLE;
+	}
+
+	return ret;
+}
+
+static int pmic_adc_fwnode_xlate(struct iio_dev *indio_dev,
+			     const struct fwnode_reference_args *iiospec)
+{
+	int i;
+	int channel = DT_CHANNEL_CONVERT(iiospec->args[0]);
+	int channel2 = DT_PURES_CONVERT(iiospec->args[0]);
+
+	for (i = 0; i < indio_dev->num_channels; i++) {
+		if (indio_dev->channels[i].channel == channel &&
+		    indio_dev->channels[i].channel2 == channel2)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info pmic_adc_info = {
+	.read_raw = &pmic_adc_read_raw,
+	.fwnode_xlate = &pmic_adc_fwnode_xlate,
+};
+
+static int auxadc_init_imix_r(struct pmic_adc_device *adc_dev,
+			      struct device_node *imix_r_node)
+{
+	unsigned int val = 0;
+	int ret;
+
+	if (!adc_dev)
+		return -EINVAL;
+
+	adc_dev->isink_load = devm_regulator_get_exclusive(adc_dev->dev, "isink_load");
+	if (IS_ERR(adc_dev->isink_load)) {
+		dev_err(adc_dev->dev, "Failed to get isink_load regulator, ret=%d\n",
+			(int)PTR_ERR(adc_dev->isink_load));
+		return PTR_ERR(adc_dev->isink_load);
+	}
+
+	imix_r_dev = adc_dev;
+	if (imix_r_dev->imix_r)
+		return 0;
+
+	ret = of_property_read_u32(imix_r_node, "val", &val);
+	if (ret)
+		dev_notice(imix_r_dev->dev, "no imix_r, ret=%d\n", ret);
+	imix_r_dev->imix_r = (int)val;
+	imix_r_dev->pre_uisoc = 101;
+	return 0;
+}
+
+static int auxadc_get_data_from_dt(struct pmic_adc_device *adc_dev,
+				   struct iio_chan_spec *iio_chan,
+				   struct device_node *node)
+{
+	struct auxadc_channels *auxadc_chan;
+	unsigned int channel = 0;
+	unsigned int value = 0;
+	unsigned int val_arr[2] = {0};
+	int ret;
+
+	ret = of_property_read_u32(node, "channel", &channel);
+	if (ret) {
+		dev_err(adc_dev->dev, "invalid channel in node:%s\n",
+			   node->name);
+		return ret;
+	}
+	if (channel > AUXADC_CHAN_MAX) {
+		dev_err(adc_dev->dev, "invalid channel number %d in node:%s\n",
+			   channel, node->name);
+		return -EINVAL;
+	}
+	if (channel >= ARRAY_SIZE(auxadc_chans)) {
+		dev_err(adc_dev->dev, "channel number %d in node:%s not exists\n",
+			   channel, node->name);
+		return -EINVAL;
+	}
+	iio_chan->channel = channel;
+	iio_chan->datasheet_name = auxadc_chans[channel].ch_name;
+	iio_chan->info_mask_separate = auxadc_chans[channel].info_mask;
+	iio_chan->type = auxadc_chans[channel].type;
+	iio_chan->extend_name = node->name;
+	ret = of_property_read_u32(node, "pures", &value);
+	if (!ret)
+		iio_chan->channel2 = value;
+
+	if (channel == AUXADC_IMIX_R)
+		return auxadc_init_imix_r(adc_dev, node);
+
+	auxadc_chan = &auxadc_chans[channel];
+	auxadc_chan->regs = &adc_dev->info->regs_tbl[channel];
+
+	ret = of_property_read_u32_array(node, "resistance-ratio", val_arr, 2);
+	if (!ret) {
+		auxadc_chan->r_ratio[0] = val_arr[0];
+		auxadc_chan->r_ratio[1] = val_arr[1];
+	} else {
+		auxadc_chan->r_ratio[0] = AUXADC_DEF_R_RATIO;
+		auxadc_chan->r_ratio[1] = 1;
+	}
+
+	ret = of_property_read_u32(node, "avg-num", &value);
+	if (!ret)
+		auxadc_chan->avg_num = value;
+	else
+		auxadc_chan->avg_num = AUXADC_DEF_AVG_NUM;
+
+	return 0;
+}
+
+static int auxadc_parse_dt(struct pmic_adc_device *adc_dev,
+			   struct device_node *node)
+{
+	struct iio_chan_spec *iio_chan;
+	struct device_node *child;
+	unsigned int index = 0;
+	int ret;
+
+	adc_dev->nchannels = of_get_available_child_count(node);
+	if (!adc_dev->nchannels)
+		return -EINVAL;
+
+	adc_dev->iio_chans = devm_kcalloc(adc_dev->dev, adc_dev->nchannels,
+		sizeof(*adc_dev->iio_chans), GFP_KERNEL);
+	if (!adc_dev->iio_chans)
+		return -ENOMEM;
+	iio_chan = adc_dev->iio_chans;
+
+	for_each_available_child_of_node(node, child) {
+		ret = auxadc_get_data_from_dt(adc_dev, iio_chan, child);
+		if (ret < 0) {
+			of_node_put(child);
+			return ret;
+		}
+		iio_chan->indexed = 1;
+		iio_chan->address = index++;
+		iio_chan++;
+	}
+
+	return 0;
+}
+
+static int pmic_adc_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct pmic_adc_device *adc_dev;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+	adc_dev->dev = &pdev->dev;
+	adc_dev->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	mutex_init(&adc_dev->lock);
+	adc_dev->info = of_device_get_match_data(&pdev->dev);
+
+	ret = auxadc_parse_dt(adc_dev, node);
+	if (ret) {
+		dev_notice(&pdev->dev, "auxadc_parse_dt fail, ret=%d\n", ret);
+		return ret;
+	}
+
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &pmic_adc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = adc_dev->iio_chans;
+	indio_dev->num_channels = adc_dev->nchannels;
+
+	ret = devm_iio_device_register(&pdev->dev, indio_dev);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "failed to register iio device!\n");
+		return ret;
+	}
+
+	dev_dbg(&pdev->dev, "probe done\n");
+
+	return 0;
+}
+
+static const struct of_device_id pmic_adc_of_match[] = {
+	{ .compatible = "mediatek,mt6363-auxadc", .data = &mt6363_info, },
+	{ .compatible = "mediatek,mt6373-auxadc", .data = &mt6373_info, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pmic_adc_of_match);
+
+static struct platform_driver pmic_adc_driver = {
+	.driver = {
+		.name = "mtk-spmi-pmic-adc",
+		.of_match_table = pmic_adc_of_match,
+	},
+	.probe	= pmic_adc_probe,
+};
+module_platform_driver(pmic_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SPMI PMIC ADC Driver");
-- 
2.46.0


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

* [PATCH 2/5] pmic: mediatek: Add pmic regulator driver
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
  2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
@ 2025-03-14  7:32 ` Lu.Tang
  2025-03-14  8:26   ` Chen-Yu Tsai
  2025-03-14  9:02   ` 回复: " Lu Tang (汤璐)
  2025-03-14  7:32 ` [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver Lu.Tang
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 24+ messages in thread
From: Lu.Tang @ 2025-03-14  7:32 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group, Lu.Tang

From: "Lu.Tang" <lu.tang@mediatek.com>

Add pmic mt6316/mt6373/mt6363 regulator driver

Signed-off-by: Lu Tang <lu.tang@mediatek.com>
---
 drivers/regulator/Kconfig                  |   34 +
 drivers/regulator/Makefile                 |    3 +
 drivers/regulator/mt6316-regulator.c       |  381 +++++++
 drivers/regulator/mt6363-regulator.c       | 1106 ++++++++++++++++++++
 drivers/regulator/mt6373-regulator.c       |  826 +++++++++++++++
 include/linux/regulator/mt6316-regulator.h |   48 +
 include/linux/regulator/mt6363-regulator.h |  424 ++++++++
 include/linux/regulator/mt6373-regulator.h |  318 ++++++
 8 files changed, 3140 insertions(+)
 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/regulator/mt6316-regulator.h
 create mode 100644 include/linux/regulator/mt6363-regulator.h
 create mode 100644 include/linux/regulator/mt6373-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 39297f7d8177..7b2d47fee535 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -853,6 +853,16 @@ config REGULATOR_MT6315
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6316
+	tristate "MediaTek MT6316 PMIC"
+	depends on SPMI
+	select REGMAP_SPMI
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6316 PMIC.
+	  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
@@ -916,6 +926,18 @@ 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 Regulator driver"
+	depends on MFD_MTK_SPMI_PMIC
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6363 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
+	  The driver can also be build as a module.
+	  If so, the module will be called mt6363_regulator
+
 config REGULATOR_MT6370
 	tristate "MT6370 SubPMIC Regulator"
 	depends on MFD_MT6370
@@ -924,6 +946,18 @@ 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 Regulator driver"
+	depends on MFD_MTK_SPMI_PMIC
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6373 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
+	  The driver can also be build as a module.
+	  If so, the module will be called mt6373_regulator
+
 config REGULATOR_MT6380
 	tristate "MediaTek MT6380 PMIC"
 	depends on MTK_PMIC_WRAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3d5a803dce8a..b54a64522499 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -102,6 +102,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_MT6316) += mt6316-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6331)	+= mt6331-regulator.o
 obj-$(CONFIG_REGULATOR_MT6332)	+= mt6332-regulator.o
@@ -109,7 +110,9 @@ 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_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/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c
new file mode 100644
index 000000000000..1c069a0d4cff
--- /dev/null
+++ b/drivers/regulator/mt6316-regulator.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6316-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SET_OFFSET	0x1
+#define CLR_OFFSET	0x2
+
+#define MT6316_REG_WIDTH	8
+
+#define MT6316_BUCK_MODE_AUTO		0
+#define MT6316_BUCK_MODE_FORCE_PWM	1
+#define MT6316_BUCK_MODE_NORMAL		0
+#define MT6316_BUCK_MODE_LP		2
+
+#define BUCK_PHASE_3			3
+#define BUCK_PHASE_4			4
+
+struct mt6316_regulator_info {
+	struct regulator_desc desc;
+	u32 da_reg;
+	u32 qi;
+	u32 modeset_reg;
+	u32 modeset_mask;
+	u32 lp_mode_reg;
+	u32 lp_mode_mask;
+	u32 lp_mode_shift;
+};
+
+struct mt6316_init_data {
+	u32 id;
+	u32 size;
+};
+
+struct mt6316_chip {
+	struct device *dev;
+	struct regmap *regmap;
+	u32 slave_id;
+};
+
+#define MT_BUCK(match, _name, volt_ranges, _bid, _vsel)	\
+[MT6316_ID_##_name] = {					\
+	.desc = {					\
+		.name = #_name,				\
+		.of_match = of_match_ptr(match),	\
+		.ops = &mt6316_volt_range_ops,		\
+		.type = REGULATOR_VOLTAGE,		\
+		.id = MT6316_ID_##_name,		\
+		.owner = THIS_MODULE,			\
+		.n_voltages = 0x1ff,			\
+		.linear_ranges = volt_ranges,		\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),\
+		.vsel_reg = _vsel,			\
+		.vsel_mask = 0xff,			\
+		.enable_reg = MT6316_BUCK_TOP_CON0,	\
+		.enable_mask = BIT(_bid - 1),		\
+		.of_map_mode = mt6316_map_mode,		\
+	},						\
+	.da_reg = MT6316_VBUCK##_bid##_DBG8,		\
+	.qi = BIT(0),					\
+	.lp_mode_reg = MT6316_BUCK_TOP_CON1,		\
+	.lp_mode_mask = BIT(_bid - 1),			\
+	.lp_mode_shift = _bid - 1,			\
+	.modeset_reg = MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0,\
+	.modeset_mask = BIT(_bid - 1),			\
+}
+
+static const struct linear_range mt_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(0, 0, 0x1fe, 2500),
+};
+
+static int mt6316_regulator_enable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6316_regulator_disable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + CLR_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+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_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+	unsigned short reg_val = 0;
+	int ret = 0;
+
+	reg_val = ((selector & 0x1) << 8) | (selector >> 1);
+	ret = regmap_bulk_write(rdev->regmap, rdev->desc->vsel_reg, (u8 *) &reg_val, 2);
+
+	return ret;
+}
+
+static int mt6316_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	unsigned int reg_val = 0;
+
+	ret = regmap_bulk_read(rdev->regmap, rdev->desc->vsel_reg, (u8 *) &reg_val, 2);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get mt6316 regulator voltage: %d\n", ret);
+		return ret;
+	}
+	ret = ((reg_val >> 8) & 0x1) + ((reg_val & rdev->desc->vsel_mask) << 1);
+
+	return ret;
+}
+
+static unsigned int mt6316_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6316_regulator_info *info;
+	int ret = 0, regval = 0;
+	u32 modeset_mask;
+
+	info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get mt6316 buck mode: %d\n", ret);
+		return ret;
+	}
+
+	modeset_mask = info->modeset_mask;
+
+	if ((regval & modeset_mask) == modeset_mask)
+		return REGULATOR_MODE_FAST;
+
+	ret = regmap_read(rdev->regmap, info->lp_mode_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get mt6316 buck lp mode: %d\n", ret);
+		return ret;
+	}
+
+	if (regval & info->lp_mode_mask)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6316_regulator_set_mode(struct regulator_dev *rdev, u32 mode)
+{
+	struct mt6316_regulator_info *info;
+	int ret = 0, val, curr_mode;
+	u32 modeset_mask;
+
+	info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
+	modeset_mask = info->modeset_mask;
+
+	curr_mode = mt6316_regulator_get_mode(rdev);
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+					 modeset_mask, modeset_mask);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		if (curr_mode == REGULATOR_MODE_FAST) {
+			ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+						 modeset_mask, 0);
+		} else if (curr_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg,
+						 info->lp_mode_mask, 0);
+			usleep_range(100, 110);
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		val = MT6316_BUCK_MODE_LP >> 1;
+		val <<= info->lp_mode_shift;
+		ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, info->lp_mode_mask, val);
+		break;
+	default:
+		ret = -EINVAL;
+		goto err_mode;
+	}
+
+err_mode:
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to set mt6316 buck mode: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt6316_get_status(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	u32 regval = 0;
+	struct mt6316_regulator_info *info;
+
+	info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
+	ret = regmap_read(rdev->regmap, info->da_reg, &regval);
+	if (ret != 0) {
+		dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static void mt6316_buck_phase_init(struct mt6316_chip *chip, unsigned int *s6_buck_phase)
+{
+	int ret = 0;
+	u32 val = 0;
+
+	ret = regmap_read(chip->regmap, MT6316_BUCK_TOP_4PHASE_TOP_ELR_0, &val);
+	if (ret) {
+		dev_err(chip->dev, "Failed to get mt6316 buck phase: %d\n", ret);
+		return;
+	}
+
+	dev_info(chip->dev, "S%d RG_4PH_CONFIG:%d\n", chip->slave_id, val);
+	if (chip->slave_id == MT6316_SLAVE_ID_6)
+		*s6_buck_phase = val;
+}
+
+static const struct regulator_ops mt6316_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.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_regulator_enable,
+	.disable = mt6316_regulator_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6316_get_status,
+	.set_mode = mt6316_regulator_set_mode,
+	.get_mode = mt6316_regulator_get_mode,
+};
+
+static struct mt6316_regulator_info mt6316_regulators[] = {
+	MT_BUCK("vbuck1", VBUCK1, mt_volt_range1, 1, MT6316_BUCK_TOP_ELR0),
+	MT_BUCK("vbuck2", VBUCK2, mt_volt_range1, 2, MT6316_BUCK_TOP_ELR2),
+	MT_BUCK("vbuck3", VBUCK3, mt_volt_range1, 3, MT6316_BUCK_TOP_ELR4),
+	MT_BUCK("vbuck4", VBUCK4, mt_volt_range1, 4, MT6316_BUCK_TOP_ELR6),
+};
+
+static struct mt6316_init_data mt6316_3_init_data = {
+	.id = MT6316_SLAVE_ID_3,
+	.size = MT6316_ID_3_MAX,
+};
+
+static struct mt6316_init_data mt6316_6_init_data = {
+	.id = MT6316_SLAVE_ID_6,
+	.size = MT6316_ID_6_MAX,
+};
+
+static struct mt6316_init_data mt6316_7_init_data = {
+	.id = MT6316_SLAVE_ID_7,
+	.size = MT6316_ID_7_MAX,
+};
+
+static struct mt6316_init_data mt6316_8_init_data = {
+	.id = MT6316_SLAVE_ID_8,
+	.size = MT6316_ID_8_MAX,
+};
+
+static struct mt6316_init_data mt6316_15_init_data = {
+	.id = MT6316_SLAVE_ID_15,
+	.size = MT6316_ID_15_MAX,
+};
+
+static const struct of_device_id mt6316_of_match[] = {
+	{
+		.compatible = "mediatek,mt6316-3-regulator",
+		.data = &mt6316_3_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-6-regulator",
+		.data = &mt6316_6_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-7-regulator",
+		.data = &mt6316_7_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-8-regulator",
+		.data = &mt6316_8_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-15-regulator",
+		.data = &mt6316_15_init_data,
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, mt6316_of_match);
+
+static int mt6316_regulator_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+	struct mt6316_init_data *pdata;
+	struct mt6316_chip *chip;
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	struct device_node *node = pdev->dev.of_node;
+	u32 val = 0;
+	int i;
+	unsigned int s6_buck_phase;
+
+	regmap = dev_get_regmap(dev->parent, NULL);
+	if (!regmap)
+		return -ENODEV;
+
+	chip = devm_kzalloc(dev, sizeof(struct mt6316_chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	of_id = of_match_device(mt6316_of_match, dev);
+	if (!of_id || !of_id->data)
+		return -ENODEV;
+
+	pdata = (struct mt6316_init_data *)of_id->data;
+	chip->slave_id = pdata->id;
+	if (!of_property_read_u32(node, "buck-size", &val))
+		pdata->size = val;
+	chip->dev = dev;
+	chip->regmap = regmap;
+	dev_set_drvdata(dev, chip);
+
+	dev->fwnode = &(dev->of_node->fwnode);
+	if (dev->fwnode && !dev->fwnode->dev)
+		dev->fwnode->dev = dev;
+
+	config.dev = dev;
+	config.driver_data = pdata;
+	config.regmap = regmap;
+
+	mt6316_buck_phase_init(chip, &s6_buck_phase);
+	for (i = 0; i < pdata->size; i++) {
+		if (pdata->id == MT6316_SLAVE_ID_6 &&
+		    s6_buck_phase == BUCK_PHASE_4 &&
+		    (mt6316_regulators + i)->desc.id == MT6316_ID_VBUCK3) {
+			dev_info(dev, "skip registering %s.\n", (mt6316_regulators + i)->desc.name);
+			continue;
+		}
+
+		rdev = devm_regulator_register(dev, &(mt6316_regulators + i)->desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(dev, "failed to register %s\n", (mt6316_regulators + i)->desc.name);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver mt6316_regulator_driver = {
+	.driver		= {
+		.name	= "mt6316-regulator",
+		.of_match_table = mt6316_of_match,
+	},
+	.probe = mt6316_regulator_probe,
+};
+
+module_platform_driver(mt6316_regulator_driver);
+
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6316 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
new file mode 100644
index 000000000000..cdb280110a9a
--- /dev/null
+++ b/drivers/regulator/mt6363-regulator.c
@@ -0,0 +1,1106 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/mt6363/registers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6363-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SET_OFFSET	0x1
+#define CLR_OFFSET	0x2
+#define OP_CFG_OFFSET	0x5
+#define NORMAL_OP_CFG	0x10
+#define NORMAL_OP_EN	0x800000
+
+#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 DEFAULT_DELAY_MS		10
+
+/*
+ * MT6363 regulator lock register
+ */
+#define MT6363_TMA_UNLOCK_VALUE		0x9c9c
+#define MT6363_BUCK_TOP_UNLOCK_VALUE	0x5543
+
+#define MT6363_RG_BUCK_EFUSE_RSV1	0x1447
+#define MT6363_RG_BUCK_EFUSE_RSV1_MASK	0xf0
+
+/*
+ * MT6363 regulators' information
+ *
+ * @irq: Interrupt request number of the regulator.
+ * @oc_irq_enable_delay_ms: delay in milliseconds before enabling overcurrent interrupt.
+ * @oc_work: Delayed work fields of overcurrent events.
+ * @desc: standard fields of regulator description.
+ * @lp_mode_reg: for operating NORMAL/IDLE mode register.
+ * @lp_mode_mask: MASK for operating lp_mode register.
+ * @hw_lp_mode_reg: hardware NORMAL/IDLE mode status register.
+ * @hw_lp_mode_mask: MASK for hardware NORMAL/IDLE mode status register.
+ * @modeset_reg: for operating AUTO/PWM mode register.
+ * @modeset_mask: MASK for operating modeset register.
+ * @vocal_reg: Calibrates output voltage register.
+ * @vocal_mask: MASK of Calibrates output voltage register.
+ * @lp_imax_uA: Maximum load current in Low power mode.
+ * @op_en_reg: for HW control operating mode register.
+ * @orig_op_en: for HW control original mode register.
+ * @orig_op_cfg: for HW control original mode register.
+ */
+struct mt6363_regulator_info {
+	int irq;
+	int oc_irq_enable_delay_ms;
+	struct delayed_work oc_work;
+	struct regulator_desc desc;
+	u32 lp_mode_reg;
+	u32 lp_mode_mask;
+	u32 hw_lp_mode_reg;
+	u32 hw_lp_mode_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+	u32 vocal_reg;
+	u32 vocal_mask;
+	u32 lp_imax_uA;
+	u32 op_en_reg;
+	u32 orig_op_en;
+	u32 orig_op_cfg;
+};
+
+#define MT6363_BUCK(match, _name, min, max, step, _enable_reg, en_bit, \
+		    _vsel_reg, _vsel_mask, _lp_mode_reg, lp_bit,			\
+		    _modeset_reg, modeset_bit, _en_delay)			\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_buck_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_BUCK_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0xc,					\
+	.modeset_reg = _modeset_reg,				\
+	.modeset_mask = BIT(modeset_bit),			\
+	.lp_imax_uA = 100000,					\
+	.op_en_reg = MT6363_BUCK_##_name##_OP_EN_0,		\
+}
+
+#define MT6363_SSHUB(match, _name, min, max, step, \
+		     _enable_reg, _vsel_reg, _vsel_mask)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_sshub_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(0),				\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+	},							\
+}
+
+#define MT6363_LDO_LINEAR1(match, _name, min, max, step, \
+			   _enable_reg, en_bit, _vsel_reg,	\
+			   _vsel_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_buck_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+}
+
+#define MT6363_LDO_LINEAR2(match, _name, min, max, step,	\
+			   _enable_reg, en_bit, _vsel_reg,	\
+			   _vsel_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_volt_range_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+}
+
+#define MT6363_LDO(match, _name, _volt_table, _enable_reg, en_bit,	\
+		   _vsel_reg, _vsel_mask, _vocal_reg,		\
+		   _vocal_mask, _lp_mode_reg, lp_bit, _en_delay)		\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_volt_table_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.vocal_reg = _vocal_reg,				\
+	.vocal_mask = _vocal_mask,				\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+	.lp_imax_uA = 10000,					\
+	.op_en_reg = MT6363_LDO_##_name##_OP_EN0,		\
+}
+
+#define MT6363_LDO_OPS(match, _name, _ops, _volt_table, _enable_reg, en_bit,	\
+		       _vsel_reg, _vsel_mask, _vocal_reg,	\
+		       _vocal_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &_ops,					\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.vocal_reg = _vocal_reg,				\
+	.vocal_mask = _vocal_mask,				\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+	.lp_imax_uA = 10000,					\
+	.op_en_reg = MT6363_LDO_##_name##_OP_EN0,		\
+}
+
+static const unsigned int ldo_volt_table0[] = {
+	1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2500000, 2600000,
+	2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int ldo_volt_table1[] = {
+	900000, 1000000, 1100000, 1200000, 1300000, 1700000, 1800000, 1810000,
+};
+
+static const unsigned int ldo_volt_table2[] = {
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static const unsigned int ldo_volt_table3[] = {
+	600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000,
+	1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000,
+};
+
+static const unsigned int ldo_volt_table4[] = {
+	550000, 600000, 650000, 700000, 750000, 800000, 900000, 950000,
+	1000000, 1050000, 1100000, 1150000, 1700000, 1750000, 1800000, 1850000,
+};
+
+static const unsigned int ldo_volt_table5[] = {
+	600000, 650000, 700000, 750000, 800000,
+};
+
+static int mt6363_buck_enable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6363_buck_disable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + 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 = 0;
+	int ret;
+
+	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;
+
+	if (info->hw_lp_mode_reg) {
+		ret = regmap_read(rdev->regmap, info->hw_lp_mode_reg, &val);
+		val &= info->hw_lp_mode_mask;
+	} else {
+		ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+		val &= info->lp_mode_mask;
+	}
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to get mt6363 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, 2);
+}
+
+static int mt6363_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret = 0;
+	int curr_mode;
+
+	curr_mode = mt6363_regulator_get_mode(rdev);
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = mt6363_buck_unlock(rdev->regmap, true);
+		if (ret)
+			return ret;
+		ret = regmap_update_bits(rdev->regmap,
+					 info->modeset_reg,
+					 info->modeset_mask,
+					 info->modeset_mask);
+		ret |= mt6363_buck_unlock(rdev->regmap, false);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		if (curr_mode == REGULATOR_MODE_FAST) {
+			ret = mt6363_buck_unlock(rdev->regmap, true);
+			if (ret)
+				return ret;
+			ret = regmap_update_bits(rdev->regmap,
+						 info->modeset_reg,
+						 info->modeset_mask,
+						 0);
+			ret |= mt6363_buck_unlock(rdev->regmap, false);
+			break;
+		} else if (curr_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_update_bits(rdev->regmap,
+						 info->lp_mode_reg,
+						 info->lp_mode_mask,
+						 0);
+			udelay(100);
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_update_bits(rdev->regmap,
+					 info->lp_mode_reg,
+					 info->lp_mode_mask,
+					 info->lp_mode_mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to set mt6363 mode(%d): %d\n", mode, ret);
+	}
+	return ret;
+}
+
+static int mt6363_regulator_set_load(struct regulator_dev *rdev, int load_uA)
+{
+	int i, ret;
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+
+	/* not support */
+	if (!info->lp_imax_uA)
+		return 0;
+
+	if (load_uA >= info->lp_imax_uA) {
+		ret = mt6363_regulator_set_mode(rdev, REGULATOR_MODE_NORMAL);
+		if (ret)
+			return ret;
+		ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET, NORMAL_OP_CFG);
+		for (i = 0; i < 3; i++) {
+			ret |= regmap_write(rdev->regmap, info->op_en_reg + i,
+					    (NORMAL_OP_EN >> (i * 8)) & 0xff);
+		}
+	} else {
+		ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET,
+				   info->orig_op_cfg);
+		for (i = 0; i < 3; i++) {
+			ret |= regmap_write(rdev->regmap, info->op_en_reg + i,
+					    (info->orig_op_en >> (i * 8)) & 0xff);
+		}
+	}
+
+	return ret;
+}
+
+static int mt6363_vemc_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	int ret;
+	u16 buf = MT6363_TMA_UNLOCK_VALUE;
+	unsigned int val = 0;
+
+	ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &buf, 2);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val);
+	if (ret)
+		return ret;
+	switch (val) {
+	case 0:
+		/* If HW trapping is 0, use VEMC_VOSEL_0 */
+		ret = regmap_update_bits(rdev->regmap,
+					 rdev->desc->vsel_reg,
+					 rdev->desc->vsel_mask, sel);
+		break;
+	case 1:
+		/* If HW trapping is 1, use VEMC_VOSEL_1 */
+		ret = regmap_update_bits(rdev->regmap,
+					 rdev->desc->vsel_reg,
+					 rdev->desc->vsel_mask << 4, sel << 4);
+		break;
+	default:
+		break;
+	}
+	if (ret)
+		return ret;
+
+	buf = 0;
+	ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &buf, 2);
+	return ret;
+}
+
+static int mt6363_vemc_get_voltage_sel(struct regulator_dev *rdev)
+{
+	int ret;
+	unsigned int val = 0, sel = 0;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &sel);
+	if (ret)
+		return ret;
+	ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val);
+	if (ret)
+		return ret;
+	switch (val) {
+	case 0:
+		/* If HW trapping is 0, use VEMC_VOSEL_0 */
+		sel &= rdev->desc->vsel_mask;
+		break;
+	case 1:
+		/* If HW trapping is 1, use VEMC_VOSEL_1 */
+		sel = (sel >> 4) & rdev->desc->vsel_mask;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return sel;
+}
+
+static int mt6363_va15_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	int ret;
+
+	ret = mt6363_buck_unlock(rdev->regmap, true);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel);
+	if (ret)
+		goto va15_unlock;
+	ret = regmap_update_bits(rdev->regmap, MT6363_RG_BUCK_EFUSE_RSV1,
+				 MT6363_RG_BUCK_EFUSE_RSV1_MASK, sel);
+	if (ret)
+		goto va15_unlock;
+
+va15_unlock:
+	ret |= mt6363_buck_unlock(rdev->regmap, false);
+	return ret;
+}
+
+static const struct regulator_ops mt6363_buck_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_buck_enable,
+	.disable = mt6363_buck_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_load = mt6363_regulator_set_load,
+};
+
+/* for sshub */
+static const struct regulator_ops mt6363_sshub_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,
+};
+
+static const struct regulator_ops mt6363_volt_range_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,
+};
+
+static const struct regulator_ops mt6363_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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_load = mt6363_regulator_set_load,
+};
+
+static const struct regulator_ops mt6363_vemc_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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,
+};
+
+static const struct regulator_ops mt6363_va15_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = mt6363_va15_set_voltage_sel,
+	.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_load = mt6363_regulator_set_load,
+};
+
+static int _isink_load_control(struct regulator_dev *rdev, bool enable)
+{
+	const struct {
+		unsigned int reg;
+		unsigned int mask;
+		unsigned int val;
+	} en_settings[] = {
+		{ MT6363_ISINK_EN_CTRL0, 0xFF, 0xFF },
+		{ MT6363_ISINK_EN_CTRL1, 0xF0, 0xF0 },
+	}, dis_settings[] = {
+		{ MT6363_ISINK_EN_CTRL1, 0xF0, 0 },
+		{ MT6363_ISINK_EN_CTRL0, 0xFF, 0 },
+	}, *settings;
+	int i, setting_size, ret;
+
+	if (enable) {
+		settings = en_settings;
+		setting_size = ARRAY_SIZE(en_settings);
+	} else {
+		settings = dis_settings;
+		setting_size = ARRAY_SIZE(dis_settings);
+	}
+
+	for (i = 0; i < setting_size; i++) {
+		ret = regmap_update_bits(rdev->regmap,
+					 settings[i].reg, settings[i].mask,
+					 settings[i].val);
+		if (ret) {
+			dev_err(&rdev->dev,
+				"Failed to %s isink settings[%d], ret=%d\n",
+				enable ? "enable" : "disable",
+				i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int isink_load_enable(struct regulator_dev *rdev)
+{
+	return _isink_load_control(rdev, true);
+}
+
+static int isink_load_disable(struct regulator_dev *rdev)
+{
+	return _isink_load_control(rdev, false);
+}
+
+static int isink_load_is_enabled(struct regulator_dev *rdev)
+{
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, MT6363_ISINK_EN_CTRL1, &val);
+	if (ret)
+		return ret;
+
+	val &= 0xF0;
+	return (val == 0xF0);
+}
+
+static const struct regulator_ops isink_load_ops = {
+	.enable = isink_load_enable,
+	.disable = isink_load_disable,
+	.is_enabled = isink_load_is_enabled,
+};
+
+static int mt6363_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config);
+
+/* The array is indexed by id(MT6363_ID_XXX) */
+static struct mt6363_regulator_info mt6363_regulators[] = {
+	MT6363_BUCK("vs2", VS2, 0, 1600000, 12500,
+		    MT6363_RG_BUCK_VS2_EN_ADDR,
+		    MT6363_RG_BUCK_VS2_EN_SHIFT,
+		    MT6363_RG_BUCK_VS2_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VS2_VOSEL_MASK,
+		    MT6363_RG_BUCK_VS2_LP_ADDR,
+		    MT6363_RG_BUCK_VS2_LP_SHIFT,
+		    MT6363_RG_VS2_FCCM_ADDR,
+		    MT6363_RG_VS2_FCCM_SHIFT, 180),
+	MT6363_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK1_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK1_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK1_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK1_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK1_LP_SHIFT,
+		    MT6363_RG_VBUCK1_FCCM_ADDR,
+		    MT6363_RG_VBUCK1_FCCM_SHIFT, 180),
+	MT6363_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK2_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK2_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK2_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK2_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK2_LP_SHIFT,
+		    MT6363_RG_VBUCK2_FCCM_ADDR,
+		    MT6363_RG_VBUCK2_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK3_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK3_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK3_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK3_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK3_LP_SHIFT,
+		    MT6363_RG_VBUCK3_FCCM_ADDR,
+		    MT6363_RG_VBUCK3_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK4_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK4_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK4_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK4_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK4_LP_SHIFT,
+		    MT6363_RG_VBUCK4_FCCM_ADDR,
+		    MT6363_RG_VBUCK4_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK5_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK5_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK5_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK5_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK5_LP_SHIFT,
+		    MT6363_RG_VBUCK5_FCCM_ADDR,
+		    MT6363_RG_VBUCK5_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK6_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK6_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK6_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK6_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK6_LP_SHIFT,
+		    MT6363_RG_VBUCK6_FCCM_ADDR,
+		    MT6363_RG_VBUCK6_FCCM_SHIFT, 300),
+	MT6363_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK7_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK7_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK7_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK7_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK7_LP_SHIFT,
+		    MT6363_RG_VBUCK7_FCCM_ADDR,
+		    MT6363_RG_VBUCK7_FCCM_SHIFT, 300),
+	MT6363_BUCK("vs1", VS1, 0, 2200000, 12500,
+		    MT6363_RG_BUCK_VS1_EN_ADDR,
+		    MT6363_RG_BUCK_VS1_EN_SHIFT,
+		    MT6363_RG_BUCK_VS1_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VS1_VOSEL_MASK,
+		    MT6363_RG_BUCK_VS1_LP_ADDR,
+		    MT6363_RG_BUCK_VS1_LP_SHIFT,
+		    MT6363_RG_VS1_FCCM_ADDR,
+		    MT6363_RG_VS1_FCCM_SHIFT, 180),
+	MT6363_BUCK("vs3", VS3, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VS3_EN_ADDR,
+		    MT6363_RG_BUCK_VS3_EN_SHIFT,
+		    MT6363_RG_BUCK_VS3_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VS3_VOSEL_MASK,
+		    MT6363_RG_BUCK_VS3_LP_ADDR,
+		    MT6363_RG_BUCK_VS3_LP_SHIFT,
+		    MT6363_RG_VS3_FCCM_ADDR,
+		    MT6363_RG_VS3_FCCM_SHIFT, 180),
+	MT6363_SSHUB("vbuck1-sshub", VBUCK1_SSHUB, 0, 1193750, 6250,
+		     MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR,
+		     MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR,
+		     MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK),
+	MT6363_SSHUB("vbuck2-sshub", VBUCK2_SSHUB, 0, 1193750, 6250,
+		     MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR,
+		     MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR,
+		     MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK),
+	MT6363_SSHUB("vbuck4-sshub", VBUCK4_SSHUB, 0, 1193750, 6250,
+		     MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR,
+		     MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR,
+		     MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK),
+	MT6363_LDO_LINEAR1("vsram-digrf", VSRAM_DIGRF, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_DIGRF_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_DIGRF_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_DIGRF_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_DIGRF_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR1("vsram-mdfe", VSRAM_MDFE, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_MDFE_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_MDFE_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_MDFE_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_MDFE_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR1("vsram-modem", VSRAM_MODEM, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_MODEM_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_MODEM_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_MODEM_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_MODEM_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-cpub", VSRAM_CPUB, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_CPUB_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUB_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_CPUB_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUB_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-cpum", VSRAM_CPUM, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_CPUM_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUM_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_CPUM_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUM_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-cpul", VSRAM_CPUL, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_CPUL_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUL_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_CPUL_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUL_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-apu", VSRAM_APU, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_APU_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_APU_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_APU_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_APU_LP_SHIFT, 180),
+	MT6363_LDO_OPS("vemc", VEMC, mt6363_vemc_ops, ldo_volt_table0,
+		       MT6363_RG_LDO_VEMC_EN_ADDR, MT6363_RG_LDO_VEMC_EN_SHIFT,
+		       MT6363_RG_VEMC_VOSEL_0_ADDR,
+		       MT6363_RG_VEMC_VOSEL_0_MASK,
+		       MT6363_RG_VEMC_VOCAL_0_ADDR,
+		       MT6363_RG_VEMC_VOCAL_0_MASK,
+		       MT6363_RG_LDO_VEMC_LP_ADDR,
+		       MT6363_RG_LDO_VEMC_LP_SHIFT, 680),
+	MT6363_LDO("vcn13", VCN13, ldo_volt_table1,
+		   MT6363_RG_LDO_VCN13_EN_ADDR, MT6363_RG_LDO_VCN13_EN_SHIFT,
+		   MT6363_RG_VCN13_VOSEL_ADDR,
+		   MT6363_RG_VCN13_VOSEL_MASK,
+		   MT6363_RG_VCN13_VOCAL_ADDR,
+		   MT6363_RG_VCN13_VOCAL_MASK,
+		   MT6363_RG_LDO_VCN13_LP_ADDR,
+		   MT6363_RG_LDO_VCN13_LP_SHIFT, 180),
+	MT6363_LDO("vtref18", VTREF18, ldo_volt_table2,
+		   MT6363_RG_LDO_VTREF18_EN_ADDR, MT6363_RG_LDO_VTREF18_EN_SHIFT,
+		   MT6363_RG_VTREF18_VOSEL_ADDR,
+		   MT6363_RG_VTREF18_VOSEL_MASK,
+		   MT6363_RG_VTREF18_VOCAL_ADDR,
+		   MT6363_RG_VTREF18_VOCAL_MASK,
+		   MT6363_RG_LDO_VTREF18_LP_ADDR,
+		   MT6363_RG_LDO_VTREF18_LP_SHIFT, 240),
+	MT6363_LDO("vaux18", VAUX18, ldo_volt_table2,
+		   MT6363_RG_LDO_VAUX18_EN_ADDR, MT6363_RG_LDO_VAUX18_EN_SHIFT,
+		   MT6363_RG_VAUX18_VOSEL_ADDR,
+		   MT6363_RG_VAUX18_VOSEL_MASK,
+		   MT6363_RG_VAUX18_VOCAL_ADDR,
+		   MT6363_RG_VAUX18_VOCAL_MASK,
+		   MT6363_RG_LDO_VAUX18_LP_ADDR,
+		   MT6363_RG_LDO_VAUX18_LP_SHIFT, 240),
+	MT6363_LDO("vcn15", VCN15, ldo_volt_table3,
+		   MT6363_RG_LDO_VCN15_EN_ADDR, MT6363_RG_LDO_VCN15_EN_SHIFT,
+		   MT6363_RG_VCN15_VOSEL_ADDR,
+		   MT6363_RG_VCN15_VOSEL_MASK,
+		   MT6363_RG_VCN15_VOCAL_ADDR,
+		   MT6363_RG_VCN15_VOCAL_MASK,
+		   MT6363_RG_LDO_VCN15_LP_ADDR,
+		   MT6363_RG_LDO_VCN15_LP_SHIFT, 180),
+	MT6363_LDO("vufs18", VUFS18, ldo_volt_table3,
+		   MT6363_RG_LDO_VUFS18_EN_ADDR, MT6363_RG_LDO_VUFS18_EN_SHIFT,
+		   MT6363_RG_VUFS18_VOSEL_ADDR,
+		   MT6363_RG_VUFS18_VOSEL_MASK,
+		   MT6363_RG_VUFS18_VOCAL_ADDR,
+		   MT6363_RG_VUFS18_VOCAL_MASK,
+		   MT6363_RG_LDO_VUFS18_LP_ADDR,
+		   MT6363_RG_LDO_VUFS18_LP_SHIFT, 680),
+	MT6363_LDO("vio18", VIO18, ldo_volt_table3,
+		   MT6363_RG_LDO_VIO18_EN_ADDR, MT6363_RG_LDO_VIO18_EN_SHIFT,
+		   MT6363_RG_VIO18_VOSEL_ADDR,
+		   MT6363_RG_VIO18_VOSEL_MASK,
+		   MT6363_RG_VIO18_VOCAL_ADDR,
+		   MT6363_RG_VIO18_VOCAL_MASK,
+		   MT6363_RG_LDO_VIO18_LP_ADDR,
+		   MT6363_RG_LDO_VIO18_LP_SHIFT, 680),
+	MT6363_LDO("vm18", VM18, ldo_volt_table4,
+		   MT6363_RG_LDO_VM18_EN_ADDR, MT6363_RG_LDO_VM18_EN_SHIFT,
+		   MT6363_RG_VM18_VOSEL_ADDR,
+		   MT6363_RG_VM18_VOSEL_MASK,
+		   MT6363_RG_VM18_VOCAL_ADDR,
+		   MT6363_RG_VM18_VOCAL_MASK,
+		   MT6363_RG_LDO_VM18_LP_ADDR,
+		   MT6363_RG_LDO_VM18_LP_SHIFT, 280),
+	MT6363_LDO_OPS("va15", VA15, mt6363_va15_ops, ldo_volt_table3,
+		       MT6363_RG_LDO_VA15_EN_ADDR, MT6363_RG_LDO_VA15_EN_SHIFT,
+		       MT6363_RG_VA15_VOSEL_ADDR,
+		       MT6363_RG_VA15_VOSEL_MASK,
+		       MT6363_RG_VA15_VOCAL_ADDR,
+		       MT6363_RG_VA15_VOCAL_MASK,
+		       MT6363_RG_LDO_VA15_LP_ADDR,
+		       MT6363_RG_LDO_VA15_LP_SHIFT, 180),
+	MT6363_LDO("vrf18", VRF18, ldo_volt_table3,
+		   MT6363_RG_LDO_VRF18_EN_ADDR, MT6363_RG_LDO_VRF18_EN_SHIFT,
+		   MT6363_RG_VRF18_VOSEL_ADDR,
+		   MT6363_RG_VRF18_VOSEL_MASK,
+		   MT6363_RG_VRF18_VOCAL_ADDR,
+		   MT6363_RG_VRF18_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF18_LP_ADDR,
+		   MT6363_RG_LDO_VRF18_LP_SHIFT, 180),
+	MT6363_LDO("vrfio18", VRFIO18, ldo_volt_table3,
+		   MT6363_RG_LDO_VRFIO18_EN_ADDR, MT6363_RG_LDO_VRFIO18_EN_SHIFT,
+		   MT6363_RG_VRFIO18_VOSEL_ADDR,
+		   MT6363_RG_VRFIO18_VOSEL_MASK,
+		   MT6363_RG_VRFIO18_VOCAL_ADDR,
+		   MT6363_RG_VRFIO18_VOCAL_MASK,
+		   MT6363_RG_LDO_VRFIO18_LP_ADDR,
+		   MT6363_RG_LDO_VRFIO18_LP_SHIFT, 180),
+	MT6363_LDO("vio075", VIO075, ldo_volt_table5,
+		   MT6363_RG_LDO_VIO075_EN_ADDR, MT6363_RG_LDO_VIO075_EN_SHIFT,
+		   MT6363_RG_VIO075_VOSEL_ADDR,
+		   MT6363_RG_VIO075_VOSEL_MASK,
+		   MT6363_RG_VIO075_VOCAL_ADDR,
+		   MT6363_RG_VIO075_VOCAL_MASK,
+		   MT6363_RG_LDO_VIO075_LP_ADDR,
+		   MT6363_RG_LDO_VIO075_LP_SHIFT, 3000),
+	MT6363_LDO("vufs12", VUFS12, ldo_volt_table4,
+		   MT6363_RG_LDO_VUFS12_EN_ADDR, MT6363_RG_LDO_VUFS12_EN_SHIFT,
+		   MT6363_RG_VUFS12_VOSEL_ADDR,
+		   MT6363_RG_VUFS12_VOSEL_MASK,
+		   MT6363_RG_VUFS12_VOCAL_ADDR,
+		   MT6363_RG_VUFS12_VOCAL_MASK,
+		   MT6363_RG_LDO_VUFS12_LP_ADDR,
+		   MT6363_RG_LDO_VUFS12_LP_SHIFT, 280),
+	MT6363_LDO("va12-1", VA12_1, ldo_volt_table3,
+		   MT6363_RG_LDO_VA12_1_EN_ADDR, MT6363_RG_LDO_VA12_1_EN_SHIFT,
+		   MT6363_RG_VA12_1_VOSEL_ADDR,
+		   MT6363_RG_VA12_1_VOSEL_MASK,
+		   MT6363_RG_VA12_1_VOCAL_ADDR,
+		   MT6363_RG_VA12_1_VOCAL_MASK,
+		   MT6363_RG_LDO_VA12_1_LP_ADDR,
+		   MT6363_RG_LDO_VA12_1_LP_SHIFT, 180),
+	MT6363_LDO("va12-2", VA12_2, ldo_volt_table3,
+		   MT6363_RG_LDO_VA12_2_EN_ADDR, MT6363_RG_LDO_VA12_2_EN_SHIFT,
+		   MT6363_RG_VA12_2_VOSEL_ADDR,
+		   MT6363_RG_VA12_2_VOSEL_MASK,
+		   MT6363_RG_VA12_2_VOCAL_ADDR,
+		   MT6363_RG_VA12_2_VOCAL_MASK,
+		   MT6363_RG_LDO_VA12_2_LP_ADDR,
+		   MT6363_RG_LDO_VA12_2_LP_SHIFT, 180),
+	MT6363_LDO("vrf12", VRF12, ldo_volt_table3,
+		   MT6363_RG_LDO_VRF12_EN_ADDR, MT6363_RG_LDO_VRF12_EN_SHIFT,
+		   MT6363_RG_VRF12_VOSEL_ADDR,
+		   MT6363_RG_VRF12_VOSEL_MASK,
+		   MT6363_RG_VRF12_VOCAL_ADDR,
+		   MT6363_RG_VRF12_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF12_LP_ADDR,
+		   MT6363_RG_LDO_VRF12_LP_SHIFT, 180),
+	MT6363_LDO("vrf13", VRF13, ldo_volt_table1,
+		   MT6363_RG_LDO_VRF13_EN_ADDR, MT6363_RG_LDO_VRF13_EN_SHIFT,
+		   MT6363_RG_VRF13_VOSEL_ADDR,
+		   MT6363_RG_VRF13_VOSEL_MASK,
+		   MT6363_RG_VRF13_VOCAL_ADDR,
+		   MT6363_RG_VRF13_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF13_LP_ADDR,
+		   MT6363_RG_LDO_VRF13_LP_SHIFT, 180),
+	MT6363_LDO("vrf09", VRF09, ldo_volt_table1,
+		   MT6363_RG_LDO_VRF09_EN_ADDR, MT6363_RG_LDO_VRF09_EN_SHIFT,
+		   MT6363_RG_VRF09_VOSEL_ADDR,
+		   MT6363_RG_VRF09_VOSEL_MASK,
+		   MT6363_RG_VRF09_VOCAL_ADDR,
+		   MT6363_RG_VRF09_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF09_LP_ADDR,
+		   MT6363_RG_LDO_VRF09_LP_SHIFT, 180),
+	[MT6363_ID_ISINK_LOAD] = {
+		.desc = {
+			.name = "isink_load",
+			.of_match = of_match_ptr("isink-load"),
+			.regulators_node = "regulators",
+			.id = MT6363_ID_ISINK_LOAD,
+			.type = REGULATOR_CURRENT,
+			.ops = &isink_load_ops,
+			.owner = THIS_MODULE,
+		},
+	}
+};
+
+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->irq);
+}
+
+static irqreturn_t mt6363_oc_irq(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->irq);
+	if (!regulator_is_enabled_regmap(rdev))
+		goto delayed_enable;
+	regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT,
+				      NULL);
+delayed_enable:
+	schedule_delayed_work(&info->oc_work,
+			      msecs_to_jiffies(info->oc_irq_enable_delay_ms));
+	return IRQ_HANDLED;
+}
+
+static int mt6363_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config)
+{
+	int ret;
+	struct mt6363_regulator_info *info = config->driver_data;
+
+	if (info->irq > 0) {
+		ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms",
+					   &info->oc_irq_enable_delay_ms);
+		if (ret || !info->oc_irq_enable_delay_ms)
+			info->oc_irq_enable_delay_ms = DEFAULT_DELAY_MS;
+		INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work);
+	}
+	return 0;
+}
+
+static int mt6363_backup_op_setting(struct regmap *map, struct mt6363_regulator_info *info)
+{
+	int i, ret;
+	u32 val = 0;
+
+	ret = regmap_read(map, info->op_en_reg + OP_CFG_OFFSET, &info->orig_op_cfg);
+	for (i = 0; i < 3; i++) {
+		ret |= regmap_read(map, info->op_en_reg + i, &val);
+		info->orig_op_en |= val << (i * 8);
+	}
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mt6363_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	struct mt6363_regulator_info *info;
+	int i, ret;
+
+	config.dev = pdev->dev.parent;
+	config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	for (i = 0; i < MT6363_MAX_REGULATOR; i++) {
+		info = &mt6363_regulators[i];
+		info->irq = platform_get_irq_byname_optional(pdev, info->desc.name);
+		config.driver_data = info;
+
+		rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
+		if (IS_ERR(rdev)) {
+			ret = PTR_ERR(rdev);
+			dev_err(&pdev->dev, "failed to register %s, ret=%d\n",
+				info->desc.name, ret);
+			continue;
+		}
+		if (info->lp_imax_uA) {
+			ret = mt6363_backup_op_setting(config.regmap, info);
+			if (ret) {
+				dev_notice(&pdev->dev, "failed to backup op_setting (%s)\n",
+					   info->desc.name);
+				info->lp_imax_uA = 0;
+			}
+		}
+
+		if (info->irq <= 0)
+			continue;
+		ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+						mt6363_oc_irq,
+						IRQF_TRIGGER_HIGH,
+						info->desc.name,
+						rdev);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request IRQ:%s, ret=%d",
+				info->desc.name, ret);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id mt6363_regulator_ids[] = {
+	{ "mt6363-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6363_regulator_ids);
+
+static struct platform_driver mt6363_regulator_driver = {
+	.driver = {
+		.name = "mt6363-regulator",
+	},
+	.probe = mt6363_regulator_probe,
+	.id_table = mt6363_regulator_ids,
+};
+module_platform_driver(mt6363_regulator_driver);
+
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6363 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mt6373-regulator.c b/drivers/regulator/mt6373-regulator.c
new file mode 100644
index 000000000000..5a8a9f84d13a
--- /dev/null
+++ b/drivers/regulator/mt6373-regulator.c
@@ -0,0 +1,826 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/mt6373/registers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6373-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SET_OFFSET	0x1
+#define CLR_OFFSET	0x2
+
+#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 DEFAULT_DELAY_MS		10
+
+#define MT6373_RG_RSV_SWREG_H		0xa09
+#define MT6373_PLG_CFG_ELR1		0x3ab
+#define MT6373_ELR_MASK			0xc
+
+/*
+ * MT6373 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @lp_mode_reg: for operating NORMAL/IDLE mode register.
+ * @lp_mode_mask: MASK for operating lp_mode register.
+ * @modeset_reg: for operating AUTO/PWM mode register.
+ * @modeset_mask: MASK for operating modeset register.
+ * @modeset_reg: Calibrates output voltage register.
+ * @modeset_mask: MASK of Calibrates output voltage register.
+ */
+struct mt6373_regulator_info {
+	int irq;
+	int oc_irq_enable_delay_ms;
+	struct delayed_work oc_work;
+	struct regulator_desc desc;
+	u32 lp_mode_reg;
+	u32 lp_mode_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+	u32 vocal_reg;
+	u32 vocal_mask;
+};
+
+#define MT6373_BUCK(match, _name, min, max, step,		\
+		    _enable_reg, en_bit, _vsel_reg, _vsel_mask, \
+		    _lp_mode_reg, lp_bit,			\
+		    _modeset_reg, modeset_bit, _en_delay)			\
+[MT6373_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_buck_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.modeset_reg = _modeset_reg,				\
+	.modeset_mask = BIT(modeset_bit),			\
+}
+
+#define MT6373_LDO_LINEAR(match, _name, min, max, step,	\
+			  _enable_reg, en_bit, _vsel_reg,	\
+			  _vsel_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6373_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_volt_range_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+}
+
+#define MT6373_LDO(match, _name, _volt_table, _enable_reg, en_bit,	\
+		   _vsel_reg, _vsel_mask, _vocal_reg,		\
+		   _vocal_mask, _lp_mode_reg, lp_bit, _en_delay)		\
+[MT6373_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_volt_table_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.vocal_reg = _vocal_reg,				\
+	.vocal_mask = _vocal_mask,				\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+}
+
+#define MT6373_VMCH_EINT(match, _eint_pol, _volt_table, _en_delay)		\
+[MT6373_ID_VMCH_##_eint_pol] = {				\
+	.desc = {						\
+		.name = "VMCH_"#_eint_pol,			\
+		.of_match = of_match_ptr(match),	\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_vmch_eint_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_VMCH_##_eint_pol,		\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = MT6373_LDO_VMCH_EINT,	\
+		.enable_mask = MT6373_PMIC_RG_LDO_VMCH_EINT_EN_MASK,	\
+		.enable_time = _en_delay,			\
+		.vsel_reg = MT6373_PMIC_RG_VMCH_VOSEL_ADDR,	\
+		.vsel_mask = MT6373_PMIC_RG_VMCH_VOSEL_MASK,	\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.vocal_reg = MT6373_PMIC_RG_VMCH_VOCAL_ADDR,		\
+	.vocal_mask = MT6373_PMIC_RG_VMCH_VOCAL_MASK,		\
+	.lp_mode_reg = MT6373_PMIC_RG_LDO_VMCH_LP_ADDR,		\
+	.lp_mode_mask = BIT(MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT),	\
+}
+
+static const unsigned int ldo_volt_table1[] = {
+	1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2100000, 2200000,
+	2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int ldo_volt_table2[] = {
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static const unsigned int ldo_volt_table3[] = {
+	600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000,
+	1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000,
+};
+
+static const unsigned int ldo_volt_table4[] = {
+	1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2500000, 2600000,
+	2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int ldo_volt_table5[] = {
+	900000, 1000000, 1100000, 1200000, 1300000, 1700000, 1800000, 1810000,
+};
+
+static int mt6373_buck_enable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6373_buck_disable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + 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 unsigned int mt6373_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val = 0;
+	int ret;
+
+	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;
+
+	ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to get mt6373 lp mode: %d\n", ret);
+		return ret;
+	}
+
+	if (val & info->lp_mode_mask)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6373_buck_unlock(struct regmap *map, bool unlock)
+{
+	u8 buf[2];
+
+	if (unlock) {
+		buf[0] = 0x43;
+		buf[1] = 0x55;
+	} else
+		buf[0] = buf[1] = 0;
+	return regmap_bulk_write(map, MT6373_BUCK_TOP_KEY_PROT_LO, buf, 2);
+}
+
+static int mt6373_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret = 0;
+	int curr_mode;
+
+	curr_mode = mt6373_regulator_get_mode(rdev);
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = mt6373_buck_unlock(rdev->regmap, true);
+		if (ret)
+			return ret;
+		ret = regmap_update_bits(rdev->regmap,
+					 info->modeset_reg,
+					 info->modeset_mask,
+					 info->modeset_mask);
+		ret |= mt6373_buck_unlock(rdev->regmap, false);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		if (curr_mode == REGULATOR_MODE_FAST) {
+			ret = mt6373_buck_unlock(rdev->regmap, true);
+			if (ret)
+				return ret;
+			ret = regmap_update_bits(rdev->regmap,
+						 info->modeset_reg,
+						 info->modeset_mask,
+						 0);
+			ret |= mt6373_buck_unlock(rdev->regmap, false);
+		} else if (curr_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_update_bits(rdev->regmap,
+						 info->lp_mode_reg,
+						 info->lp_mode_mask,
+						 0);
+			udelay(100);
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_update_bits(rdev->regmap,
+					 info->lp_mode_reg,
+					 info->lp_mode_mask,
+					 info->lp_mode_mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to set mt6373 mode(%d): %d\n", mode, ret);
+	}
+	return ret;
+}
+
+static int mt6373_vmch_eint_enable(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	int ret;
+
+	if (rdev->desc->id == MT6373_ID_VMCH_EINT_HIGH)
+		val = MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK;
+	else
+		val = 0;
+	ret = regmap_update_bits(rdev->regmap, MT6373_LDO_VMCH_EINT,
+				 MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK, val);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rdev->regmap, MT6373_PMIC_RG_LDO_VMCH_EN_ADDR,
+				 BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT),
+				 BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				 rdev->desc->enable_mask, rdev->desc->enable_mask);
+	return ret;
+}
+
+static int mt6373_vmch_eint_disable(struct regulator_dev *rdev)
+{
+	int ret;
+
+	ret = regmap_update_bits(rdev->regmap, MT6373_PMIC_RG_LDO_VMCH_EN_ADDR,
+				 BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT), 0);
+	if (ret)
+		return ret;
+
+	udelay(1500); /* Must delay for VMCH discharging */
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				 rdev->desc->enable_mask, 0);
+	return ret;
+}
+
+static const struct regulator_ops mt6373_buck_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_buck_enable,
+	.disable = mt6373_buck_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6373_regulator_set_mode,
+	.get_mode = mt6373_regulator_get_mode,
+};
+
+static const struct regulator_ops mt6373_volt_range_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,
+};
+
+static const struct regulator_ops mt6373_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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,
+};
+
+static const struct regulator_ops mt6373_vmch_eint_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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_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,
+};
+
+static int mt6373_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config);
+
+/* 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_BUCK_VBUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK0_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK0_FCCM_SHIFT, 180),
+	MT6373_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK1_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK1_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK2_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK2_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK3_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK3_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT, 180),
+	MT6373_BUCK("vbuck4-ufs", VBUCK4_UFS, 0, 2650125, 13875,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT, 180),
+	MT6373_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK5_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK5_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK6_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK6_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK7_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK7_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck8", VBUCK8, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK8_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK8_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck9", VBUCK9, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK9_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK9_FCCM_SHIFT, 200),
+	MT6373_LDO_LINEAR("vsram-digrf-aif", VSRAM_DIGRF_AIF, 400000, 1193750, 6250,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_ADDR,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_SHIFT,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_ADDR,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_MASK,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_ADDR,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_SHIFT, 180),
+	MT6373_LDO("vusb", VUSB, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VUSB_EN_ADDR, MT6373_PMIC_RG_LDO_VUSB_EN_SHIFT,
+		   MT6373_PMIC_RG_VUSB_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VUSB_VOSEL_MASK,
+		   MT6373_PMIC_RG_VUSB_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VUSB_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VUSB_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VUSB_LP_SHIFT, 720),
+	MT6373_LDO("vaux18", VAUX18, ldo_volt_table2,
+		   MT6373_PMIC_RG_LDO_VAUX18_EN_ADDR, MT6373_PMIC_RG_LDO_VAUX18_EN_SHIFT,
+		   MT6373_PMIC_RG_VAUX18_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VAUX18_VOSEL_MASK,
+		   MT6373_PMIC_RG_VAUX18_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VAUX18_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VAUX18_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VAUX18_LP_SHIFT, 240),
+	MT6373_LDO("vrf13-aif", VRF13_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRF13_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF13_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF13_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF13_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF13_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF13_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrf18-aif", VRF18_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRF18_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF18_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF18_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF18_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF18_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF18_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrfio18-aif", VRFIO18_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrf09-aif", VRF09_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRF09_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF09_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF09_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF09_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF09_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF09_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrf12-aif", VRF12_AIF, ldo_volt_table5,
+		   MT6373_PMIC_RG_LDO_VRF12_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF12_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF12_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF12_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF12_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF12_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vant18", VANT18, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VANT18_EN_ADDR, MT6373_PMIC_RG_LDO_VANT18_EN_SHIFT,
+		   MT6373_PMIC_RG_VANT18_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VANT18_VOSEL_MASK,
+		   MT6373_PMIC_RG_VANT18_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VANT18_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VANT18_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VANT18_LP_SHIFT, 720),
+	MT6373_LDO("vibr", VIBR, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VIBR_EN_ADDR, MT6373_PMIC_RG_LDO_VIBR_EN_SHIFT,
+		   MT6373_PMIC_RG_VIBR_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VIBR_VOSEL_MASK,
+		   MT6373_PMIC_RG_VIBR_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VIBR_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VIBR_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VIBR_LP_SHIFT, 210),
+	MT6373_LDO("vio28", VIO28, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VIO28_EN_ADDR, MT6373_PMIC_RG_LDO_VIO28_EN_SHIFT,
+		   MT6373_PMIC_RG_VIO28_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VIO28_VOSEL_MASK,
+		   MT6373_PMIC_RG_VIO28_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VIO28_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VIO28_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VIO28_LP_SHIFT, 210),
+	MT6373_LDO("vfp", VFP, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VFP_EN_ADDR, MT6373_PMIC_RG_LDO_VFP_EN_SHIFT,
+		   MT6373_PMIC_RG_VFP_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VFP_VOSEL_MASK,
+		   MT6373_PMIC_RG_VFP_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VFP_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VFP_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VFP_LP_SHIFT, 210),
+	MT6373_LDO("vtp", VTP, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VTP_EN_ADDR, MT6373_PMIC_RG_LDO_VTP_EN_SHIFT,
+		   MT6373_PMIC_RG_VTP_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VTP_VOSEL_MASK,
+		   MT6373_PMIC_RG_VTP_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VTP_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VTP_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VTP_LP_SHIFT, 720),
+	MT6373_LDO("vmch", VMCH, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VMCH_EN_ADDR, MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT,
+		   MT6373_PMIC_RG_VMCH_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VMCH_VOSEL_MASK,
+		   MT6373_PMIC_RG_VMCH_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VMCH_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VMCH_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT, 720),
+	MT6373_LDO("vmc", VMC, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VMC_EN_ADDR, MT6373_PMIC_RG_LDO_VMC_EN_SHIFT,
+		   MT6373_PMIC_RG_VMC_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VMC_VOSEL_MASK,
+		   MT6373_PMIC_RG_VMC_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VMC_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VMC_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VMC_LP_SHIFT, 720),
+	MT6373_LDO("vaud18", VAUD18, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VAUD18_EN_ADDR, MT6373_PMIC_RG_LDO_VAUD18_EN_SHIFT,
+		   MT6373_PMIC_RG_VAUD18_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VAUD18_VOSEL_MASK,
+		   MT6373_PMIC_RG_VAUD18_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VAUD18_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VAUD18_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VAUD18_LP_SHIFT, 720),
+	MT6373_LDO("vcn33-1", VCN33_1, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VCN33_1_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_1_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN33_1_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN33_1_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN33_1_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN33_1_LP_SHIFT, 210),
+	MT6373_LDO("vcn33-2", VCN33_2, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VCN33_2_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_2_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN33_2_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN33_2_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN33_2_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN33_2_LP_SHIFT, 210),
+	MT6373_LDO("vcn33-3", VCN33_3, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VCN33_3_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_3_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN33_3_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN33_3_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN33_3_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN33_3_LP_SHIFT, 210),
+	MT6373_LDO("vcn18io", VCN18IO, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VCN18IO_EN_ADDR, MT6373_PMIC_RG_LDO_VCN18IO_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN18IO_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN18IO_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN18IO_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN18IO_LP_SHIFT, 720),
+	MT6373_LDO("vefuse", VEFUSE, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VEFUSE_EN_ADDR, MT6373_PMIC_RG_LDO_VEFUSE_EN_SHIFT,
+		   MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VEFUSE_VOSEL_MASK,
+		   MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VEFUSE_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VEFUSE_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VEFUSE_LP_SHIFT, 720),
+	MT6373_VMCH_EINT("vmch-eint-high", EINT_HIGH, ldo_volt_table4, 720),
+	MT6373_VMCH_EINT("vmch-eint-low", EINT_LOW, ldo_volt_table4, 720),
+};
+
+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->irq);
+}
+
+static irqreturn_t mt6373_oc_irq(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->irq);
+	if (!regulator_is_enabled_regmap(rdev))
+		goto delayed_enable;
+	regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT,
+				      NULL);
+delayed_enable:
+	schedule_delayed_work(&info->oc_work,
+			      msecs_to_jiffies(info->oc_irq_enable_delay_ms));
+	return IRQ_HANDLED;
+}
+
+static int mt6373_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config)
+{
+	int ret;
+	struct mt6373_regulator_info *info = config->driver_data;
+
+	if (info->irq > 0) {
+		ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms",
+					   &info->oc_irq_enable_delay_ms);
+		if (ret || !info->oc_irq_enable_delay_ms)
+			info->oc_irq_enable_delay_ms = DEFAULT_DELAY_MS;
+		INIT_DELAYED_WORK(&info->oc_work, mt6373_oc_irq_enable_work);
+	}
+	return 0;
+}
+
+static bool mt6373_bypass_register(struct mt6373_regulator_info *info)
+{
+	return info->desc.id == MT6373_ID_VBUCK4_UFS;
+}
+
+static int mt6373_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	struct mt6373_regulator_info *info;
+	int i, ret;
+	unsigned int val = 0;
+	bool is_mt6373_cw = false;
+
+	config.dev = pdev->dev.parent;
+	config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
+
+	if (!config.regmap) {
+		dev_err(&pdev->dev, "failed to get regmap\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_read(config.regmap, MT6373_PLG_CFG_ELR1, &val);
+	if (ret)
+		dev_notice(&pdev->dev, "failed to read ELR, ret=%d\n", ret);
+	else if ((val & MT6373_ELR_MASK) == 0x4)
+		is_mt6373_cw = true;
+
+	/* MT6373_RG_RSV_SWREG_H for checking 6989p */
+	ret = regmap_read(config.regmap, MT6373_RG_RSV_SWREG_H, &val);
+
+	for (i = 0; i < MT6373_MAX_REGULATOR; i++) {
+		info = &mt6373_regulators[i];
+		info->irq = platform_get_irq_byname_optional(pdev, info->desc.name);
+		config.driver_data = info;
+		if (is_mt6373_cw && mt6373_bypass_register(info))
+			continue;
+		if ((info->desc.id == MT6373_ID_VBUCK4) && (val & 0x1)) {
+			dev_info(&pdev->dev, "skip registering %s\n", info->desc.name);
+			continue;
+		}
+
+		rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
+		if (IS_ERR(rdev)) {
+			ret = PTR_ERR(rdev);
+			dev_err(&pdev->dev, "failed to register %s, ret=%d\n",
+				info->desc.name, ret);
+			continue;
+		}
+
+		if (info->irq <= 0)
+			continue;
+		ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+						mt6373_oc_irq,
+						IRQF_TRIGGER_HIGH,
+						info->desc.name,
+						rdev);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request IRQ:%s, ret=%d",
+				info->desc.name, ret);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static void mt6373_regulator_shutdown(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+	int ret = 0;
+
+	regmap = dev_get_regmap(dev->parent, NULL);
+	if (!regmap) {
+		dev_notice(&pdev->dev, "invalid regmap.\n");
+		return;
+	}
+
+	ret = regmap_write(regmap, MT6373_TOP_CFG_ELR5, 0x1);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "enable sequence off failed.\n");
+		return;
+	}
+}
+
+static const struct platform_device_id mt6373_regulator_ids[] = {
+	{ "mt6373-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6373_regulator_ids);
+
+static struct platform_driver mt6373_regulator_driver = {
+	.driver = {
+		.name = "mt6373-regulator",
+	},
+	.probe = mt6373_regulator_probe,
+	.shutdown = mt6373_regulator_shutdown,
+	.id_table = mt6373_regulator_ids,
+};
+module_platform_driver(mt6373_regulator_driver);
+
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6373 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6316-regulator.h b/include/linux/regulator/mt6316-regulator.h
new file mode 100644
index 000000000000..dd11b3d856fd
--- /dev/null
+++ b/include/linux/regulator/mt6316-regulator.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6316_H
+#define __LINUX_REGULATOR_MT6316_H
+
+#define MT6316_SLAVE_ID_3	3
+#define MT6316_SLAVE_ID_6	6
+#define MT6316_SLAVE_ID_7	7
+#define MT6316_SLAVE_ID_8	8
+#define MT6316_SLAVE_ID_15	15
+
+#define MT6316_ID_3_MAX		3
+#define MT6316_ID_6_MAX		3
+#define MT6316_ID_7_MAX		3
+#define MT6316_ID_8_MAX		3
+#define MT6316_ID_15_MAX	2
+
+enum {
+	MT6316_ID_VBUCK1 = 0,
+	MT6316_ID_VBUCK2,
+	MT6316_ID_VBUCK3,
+	MT6316_ID_VBUCK4,
+	MT6316_ID_MAX,
+};
+
+/* Register */
+#define MT6316_TOP_CFG_ELR4			0x143
+#define MT6316_BUCK_TOP_CON0			0x1440
+#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_VBUCK1_DBG4			0x14A4
+#define MT6316_VBUCK1_DBG8			0x14A8
+#define MT6316_VBUCK2_DBG4			0x1524
+#define MT6316_VBUCK2_DBG8			0x1528
+#define MT6316_VBUCK3_DBG4			0x15A4
+#define MT6316_VBUCK3_DBG8			0x15A8
+#define MT6316_VBUCK4_DBG4			0x1624
+#define MT6316_VBUCK4_DBG8			0x1628
+#define MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0     0x1688
+#define MT6316_BUCK_TOP_4PHASE_TOP_ELR_0	0x1690
+
+#endif /* __LINUX_REGULATOR_MT6316_H */
diff --git a/include/linux/regulator/mt6363-regulator.h b/include/linux/regulator/mt6363-regulator.h
new file mode 100644
index 000000000000..f9c2220ae18c
--- /dev/null
+++ b/include/linux/regulator/mt6363-regulator.h
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6363_H
+#define __LINUX_REGULATOR_MT6363_H
+
+enum {
+	MT6363_ID_VS2,
+	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_VS3,
+	MT6363_ID_VBUCK1_SSHUB,
+	MT6363_ID_VBUCK2_SSHUB,
+	MT6363_ID_VBUCK4_SSHUB,
+	MT6363_ID_VSRAM_DIGRF,
+	MT6363_ID_VSRAM_MDFE,
+	MT6363_ID_VSRAM_MODEM,
+	MT6363_ID_VSRAM_CPUB,
+	MT6363_ID_VSRAM_CPUM,
+	MT6363_ID_VSRAM_CPUL,
+	MT6363_ID_VSRAM_APU,
+	MT6363_ID_VEMC,
+	MT6363_ID_VCN13,
+	MT6363_ID_VTREF18,
+	MT6363_ID_VAUX18,
+	MT6363_ID_VCN15,
+	MT6363_ID_VUFS18,
+	MT6363_ID_VIO18,
+	MT6363_ID_VM18,
+	MT6363_ID_VA15,
+	MT6363_ID_VRF18,
+	MT6363_ID_VRFIO18,
+	MT6363_ID_VIO075,
+	MT6363_ID_VUFS12,
+	MT6363_ID_VA12_1,
+	MT6363_ID_VA12_2,
+	MT6363_ID_VRF12,
+	MT6363_ID_VRF13,
+	MT6363_ID_VRF09,
+	MT6363_ID_ISINK_LOAD,
+	MT6363_MAX_REGULATOR,
+};
+
+#define MTK_REGULATOR_MAX_NR MT6363_MAX_REGULATOR
+
+/* Register */
+#define MT6363_TOP_TRAP                             (0x36)
+#define MT6363_TOP_TMA_KEY_L                        (0x39e)
+#define MT6363_BUCK_TOP_KEY_PROT_LO                 (0x142a)
+#define MT6363_BUCK_VS2_OP_EN_0                     (0x148d)
+#define MT6363_BUCK_VS2_HW_LP_MODE                  (0x1498)
+#define MT6363_BUCK_VBUCK1_OP_EN_0                  (0x150d)
+#define MT6363_BUCK_VBUCK1_HW_LP_MODE               (0x1518)
+#define MT6363_BUCK_VBUCK2_OP_EN_0                  (0x158d)
+#define MT6363_BUCK_VBUCK2_HW_LP_MODE               (0x1598)
+#define MT6363_BUCK_VBUCK3_OP_EN_0                  (0x160d)
+#define MT6363_BUCK_VBUCK3_HW_LP_MODE               (0x1618)
+#define MT6363_BUCK_VBUCK4_OP_EN_0                  (0x168d)
+#define MT6363_BUCK_VBUCK4_HW_LP_MODE               (0x1698)
+#define MT6363_BUCK_VBUCK5_OP_EN_0                  (0x170d)
+#define MT6363_BUCK_VBUCK5_HW_LP_MODE               (0x1718)
+#define MT6363_BUCK_VBUCK6_OP_EN_0                  (0x178d)
+#define MT6363_BUCK_VBUCK6_HW_LP_MODE               (0x1798)
+#define MT6363_BUCK_VBUCK7_OP_EN_0                  (0x180d)
+#define MT6363_BUCK_VBUCK7_HW_LP_MODE               (0x1818)
+#define MT6363_BUCK_VS1_OP_EN_0                     (0x188d)
+#define MT6363_BUCK_VS1_HW_LP_MODE                  (0x1898)
+#define MT6363_BUCK_VS3_OP_EN_0                     (0x190d)
+#define MT6363_BUCK_VS3_HW_LP_MODE                  (0x1918)
+#define MT6363_LDO_VCN15_HW_LP_MODE                 (0x1b8b)
+#define MT6363_LDO_VCN15_OP_EN0                     (0x1b8c)
+#define MT6363_LDO_VRF09_HW_LP_MODE                 (0x1b99)
+#define MT6363_LDO_VRF09_OP_EN0                     (0x1b9a)
+#define MT6363_LDO_VRF12_HW_LP_MODE                 (0x1ba7)
+#define MT6363_LDO_VRF12_OP_EN0                     (0x1ba8)
+#define MT6363_LDO_VRF13_HW_LP_MODE                 (0x1bb5)
+#define MT6363_LDO_VRF13_OP_EN0                     (0x1bb6)
+#define MT6363_LDO_VRF18_HW_LP_MODE                 (0x1bc3)
+#define MT6363_LDO_VRF18_OP_EN0                     (0x1bc4)
+#define MT6363_LDO_VRFIO18_HW_LP_MODE               (0x1bd1)
+#define MT6363_LDO_VRFIO18_OP_EN0                   (0x1bd2)
+#define MT6363_LDO_VTREF18_HW_LP_MODE               (0x1c0b)
+#define MT6363_LDO_VTREF18_OP_EN0                   (0x1c0c)
+#define MT6363_LDO_VAUX18_HW_LP_MODE                (0x1c19)
+#define MT6363_LDO_VAUX18_OP_EN0                    (0x1c1a)
+#define MT6363_LDO_VEMC_HW_LP_MODE                  (0x1c27)
+#define MT6363_LDO_VEMC_OP_EN0                      (0x1c28)
+#define MT6363_LDO_VUFS12_HW_LP_MODE                (0x1c35)
+#define MT6363_LDO_VUFS12_OP_EN0                    (0x1c36)
+#define MT6363_LDO_VUFS18_HW_LP_MODE                (0x1c43)
+#define MT6363_LDO_VUFS18_OP_EN0                    (0x1c44)
+#define MT6363_LDO_VIO18_HW_LP_MODE                 (0x1c51)
+#define MT6363_LDO_VIO18_OP_EN0                     (0x1c52)
+#define MT6363_LDO_VIO075_HW_LP_MODE                (0x1c8b)
+#define MT6363_LDO_VIO075_OP_EN0                    (0x1c8c)
+#define MT6363_LDO_VA12_1_HW_LP_MODE                (0x1c99)
+#define MT6363_LDO_VA12_1_OP_EN0                    (0x1c9a)
+#define MT6363_LDO_VA12_2_HW_LP_MODE                (0x1ca7)
+#define MT6363_LDO_VA12_2_OP_EN0                    (0x1ca8)
+#define MT6363_LDO_VA15_HW_LP_MODE                  (0x1cb5)
+#define MT6363_LDO_VA15_OP_EN0                      (0x1cb6)
+#define MT6363_LDO_VM18_HW_LP_MODE                  (0x1cc3)
+#define MT6363_LDO_VM18_OP_EN0                      (0x1cc4)
+#define MT6363_LDO_VCN13_HW_LP_MODE                 (0x1d0b)
+#define MT6363_LDO_VCN13_OP_EN0                     (0x1d14)
+#define MT6363_LDO_VSRAM_DIGRF_HW_LP_MODE           (0x1d21)
+#define MT6363_LDO_VSRAM_DIGRF_OP_EN0               (0x1d2a)
+#define MT6363_LDO_VSRAM_MDFE_HW_LP_MODE            (0x1d8b)
+#define MT6363_LDO_VSRAM_MDFE_OP_EN0                (0x1d94)
+#define MT6363_LDO_VSRAM_MODEM_HW_LP_MODE           (0x1da6)
+#define MT6363_LDO_VSRAM_MODEM_OP_EN0               (0x1daf)
+#define MT6363_LDO_VSRAM_CPUB_HW_LP_MODE            (0x1e0b)
+#define MT6363_LDO_VSRAM_CPUB_OP_EN0                (0x1e14)
+#define MT6363_LDO_VSRAM_CPUM_HW_LP_MODE            (0x1e21)
+#define MT6363_LDO_VSRAM_CPUM_OP_EN0                (0x1e2a)
+#define MT6363_LDO_VSRAM_CPUL_HW_LP_MODE            (0x1e8b)
+#define MT6363_LDO_VSRAM_CPUL_OP_EN0                (0x1e94)
+#define MT6363_LDO_VSRAM_APU_HW_LP_MODE             (0x1ea1)
+#define MT6363_LDO_VSRAM_APU_OP_EN0                 (0x1eaa)
+#define MT6363_RG_BUCK_VS2_EN_ADDR                  (0x240)
+#define MT6363_RG_BUCK_VS2_EN_SHIFT                 (0)
+#define MT6363_RG_BUCK_VBUCK1_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK1_EN_SHIFT              (1)
+#define MT6363_RG_BUCK_VBUCK2_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK2_EN_SHIFT              (2)
+#define MT6363_RG_BUCK_VBUCK3_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK3_EN_SHIFT              (3)
+#define MT6363_RG_BUCK_VBUCK4_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK4_EN_SHIFT              (4)
+#define MT6363_RG_BUCK_VBUCK5_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK5_EN_SHIFT              (5)
+#define MT6363_RG_BUCK_VBUCK6_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK6_EN_SHIFT              (6)
+#define MT6363_RG_BUCK_VBUCK7_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK7_EN_SHIFT              (7)
+#define MT6363_RG_BUCK_VS1_EN_ADDR                  (0x243)
+#define MT6363_RG_BUCK_VS1_EN_SHIFT                 (0)
+#define MT6363_RG_BUCK_VS3_EN_ADDR                  (0x243)
+#define MT6363_RG_BUCK_VS3_EN_SHIFT                 (1)
+#define MT6363_RG_LDO_VSRAM_DIGRF_EN_ADDR           (0x243)
+#define MT6363_RG_LDO_VSRAM_DIGRF_EN_SHIFT          (4)
+#define MT6363_RG_LDO_VSRAM_MDFE_EN_ADDR            (0x243)
+#define MT6363_RG_LDO_VSRAM_MDFE_EN_SHIFT           (5)
+#define MT6363_RG_LDO_VSRAM_MODEM_EN_ADDR           (0x243)
+#define MT6363_RG_LDO_VSRAM_MODEM_EN_SHIFT          (6)
+#define MT6363_RG_BUCK_VS2_LP_ADDR                  (0x246)
+#define MT6363_RG_BUCK_VS2_LP_SHIFT                 (0)
+#define MT6363_RG_BUCK_VBUCK1_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK1_LP_SHIFT              (1)
+#define MT6363_RG_BUCK_VBUCK2_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK2_LP_SHIFT              (2)
+#define MT6363_RG_BUCK_VBUCK3_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK3_LP_SHIFT              (3)
+#define MT6363_RG_BUCK_VBUCK4_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK4_LP_SHIFT              (4)
+#define MT6363_RG_BUCK_VBUCK5_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK5_LP_SHIFT              (5)
+#define MT6363_RG_BUCK_VBUCK6_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK6_LP_SHIFT              (6)
+#define MT6363_RG_BUCK_VBUCK7_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK7_LP_SHIFT              (7)
+#define MT6363_RG_BUCK_VS1_LP_ADDR                  (0x249)
+#define MT6363_RG_BUCK_VS1_LP_SHIFT                 (0)
+#define MT6363_RG_BUCK_VS3_LP_ADDR                  (0x249)
+#define MT6363_RG_BUCK_VS3_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VSRAM_DIGRF_LP_ADDR           (0x249)
+#define MT6363_RG_LDO_VSRAM_DIGRF_LP_SHIFT          (4)
+#define MT6363_RG_LDO_VSRAM_MDFE_LP_ADDR            (0x249)
+#define MT6363_RG_LDO_VSRAM_MDFE_LP_SHIFT           (5)
+#define MT6363_RG_LDO_VSRAM_MODEM_LP_ADDR           (0x249)
+#define MT6363_RG_LDO_VSRAM_MODEM_LP_SHIFT          (6)
+#define MT6363_RG_BUCK_VS2_VOSEL_ADDR               (0x24c)
+#define MT6363_RG_BUCK_VS2_VOSEL_MASK               (0xff)
+#define MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR            (0x24d)
+#define MT6363_RG_BUCK_VBUCK1_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR            (0x24e)
+#define MT6363_RG_BUCK_VBUCK2_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR            (0x24f)
+#define MT6363_RG_BUCK_VBUCK3_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR            (0x250)
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR            (0x251)
+#define MT6363_RG_BUCK_VBUCK5_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR            (0x252)
+#define MT6363_RG_BUCK_VBUCK6_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR            (0x253)
+#define MT6363_RG_BUCK_VBUCK7_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VS1_VOSEL_ADDR               (0x254)
+#define MT6363_RG_BUCK_VS1_VOSEL_MASK               (0xff)
+#define MT6363_RG_BUCK_VS3_VOSEL_ADDR               (0x255)
+#define MT6363_RG_BUCK_VS3_VOSEL_MASK               (0xff)
+#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR        (0x258)
+#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK        (0x7f)
+#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR         (0x259)
+#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR        (0x25a)
+#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK        (0x7f)
+#define MT6363_BUCK_VS2_WDTDBG_VOSEL_ADDR           (0x142c)
+#define MT6363_BUCK_VBUCK1_WDTDBG_VOSEL_ADDR        (0x142d)
+#define MT6363_BUCK_VBUCK2_WDTDBG_VOSEL_ADDR        (0x142e)
+#define MT6363_BUCK_VBUCK3_WDTDBG_VOSEL_ADDR        (0x142f)
+#define MT6363_BUCK_VBUCK4_WDTDBG_VOSEL_ADDR        (0x1430)
+#define MT6363_BUCK_VBUCK5_WDTDBG_VOSEL_ADDR        (0x1431)
+#define MT6363_BUCK_VBUCK6_WDTDBG_VOSEL_ADDR        (0x1432)
+#define MT6363_BUCK_VBUCK7_WDTDBG_VOSEL_ADDR        (0x1433)
+#define MT6363_BUCK_VS1_WDTDBG_VOSEL_ADDR           (0x1434)
+#define MT6363_BUCK_VS3_WDTDBG_VOSEL_ADDR           (0x1435)
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR         (0x151a)
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR      (0x151b)
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK      (0xff)
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR         (0x159a)
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR      (0x159b)
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK      (0xff)
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR         (0x169a)
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR      (0x169b)
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK      (0xff)
+#define MT6363_RG_VS1_FCCM_ADDR                     (0x1994)
+#define MT6363_RG_VS1_FCCM_SHIFT                    (0)
+#define MT6363_RG_VS3_FCCM_ADDR                     (0x19a3)
+#define MT6363_RG_VS3_FCCM_SHIFT                    (0)
+#define MT6363_RG_VBUCK1_FCCM_ADDR                  (0x1a32)
+#define MT6363_RG_VBUCK1_FCCM_SHIFT                 (0)
+#define MT6363_RG_VBUCK2_FCCM_ADDR                  (0x1a32)
+#define MT6363_RG_VBUCK2_FCCM_SHIFT                 (1)
+#define MT6363_RG_VBUCK3_FCCM_ADDR                  (0x1a32)
+#define MT6363_RG_VBUCK3_FCCM_SHIFT                 (2)
+#define MT6363_RG_VS2_FCCM_ADDR                     (0x1a32)
+#define MT6363_RG_VS2_FCCM_SHIFT                    (3)
+#define MT6363_RG_VBUCK4_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK4_FCCM_SHIFT                 (0)
+#define MT6363_RG_VBUCK5_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK5_FCCM_SHIFT                 (1)
+#define MT6363_RG_VBUCK6_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK6_FCCM_SHIFT                 (2)
+#define MT6363_RG_VBUCK7_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK7_FCCM_SHIFT                 (3)
+#define MT6363_RG_VCN13_VOSEL_ADDR                  (0x1b3f)
+#define MT6363_RG_VCN13_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VEMC_VOSEL_0_ADDR                 (0x1b40)
+#define MT6363_RG_VEMC_VOSEL_0_MASK                 (0xf)
+#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR         (0x1b44)
+#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR         (0x1b45)
+#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR         (0x1b46)
+#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR          (0x1b47)
+#define MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK          (0x7f)
+#define MT6363_RG_VEMC_VOCAL_0_ADDR                 (0x1b4b)
+#define MT6363_RG_VEMC_VOCAL_0_MASK                 (0xf)
+#define MT6363_RG_LDO_VCN15_EN_ADDR                 (0x1b87)
+#define MT6363_RG_LDO_VCN15_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VCN15_LP_ADDR                 (0x1b87)
+#define MT6363_RG_LDO_VCN15_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF09_EN_ADDR                 (0x1b95)
+#define MT6363_RG_LDO_VRF09_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF09_LP_ADDR                 (0x1b95)
+#define MT6363_RG_LDO_VRF09_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF12_EN_ADDR                 (0x1ba3)
+#define MT6363_RG_LDO_VRF12_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF12_LP_ADDR                 (0x1ba3)
+#define MT6363_RG_LDO_VRF12_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF13_EN_ADDR                 (0x1bb1)
+#define MT6363_RG_LDO_VRF13_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF13_LP_ADDR                 (0x1bb1)
+#define MT6363_RG_LDO_VRF13_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF18_EN_ADDR                 (0x1bbf)
+#define MT6363_RG_LDO_VRF18_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF18_LP_ADDR                 (0x1bbf)
+#define MT6363_RG_LDO_VRF18_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRFIO18_EN_ADDR               (0x1bcd)
+#define MT6363_RG_LDO_VRFIO18_EN_SHIFT              (0)
+#define MT6363_RG_LDO_VRFIO18_LP_ADDR               (0x1bcd)
+#define MT6363_RG_LDO_VRFIO18_LP_SHIFT              (1)
+#define MT6363_RG_LDO_VTREF18_EN_ADDR               (0x1c07)
+#define MT6363_RG_LDO_VTREF18_EN_SHIFT              (0)
+#define MT6363_RG_LDO_VTREF18_LP_ADDR               (0x1c07)
+#define MT6363_RG_LDO_VTREF18_LP_SHIFT              (1)
+#define MT6363_RG_LDO_VAUX18_EN_ADDR                (0x1c15)
+#define MT6363_RG_LDO_VAUX18_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VAUX18_LP_ADDR                (0x1c15)
+#define MT6363_RG_LDO_VAUX18_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VEMC_EN_ADDR                  (0x1c23)
+#define MT6363_RG_LDO_VEMC_EN_SHIFT                 (0)
+#define MT6363_RG_LDO_VEMC_LP_ADDR                  (0x1c23)
+#define MT6363_RG_LDO_VEMC_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VUFS12_EN_ADDR                (0x1c31)
+#define MT6363_RG_LDO_VUFS12_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VUFS12_LP_ADDR                (0x1c31)
+#define MT6363_RG_LDO_VUFS12_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VUFS18_EN_ADDR                (0x1c3f)
+#define MT6363_RG_LDO_VUFS18_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VUFS18_LP_ADDR                (0x1c3f)
+#define MT6363_RG_LDO_VUFS18_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VIO18_EN_ADDR                 (0x1c4d)
+#define MT6363_RG_LDO_VIO18_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VIO18_LP_ADDR                 (0x1c4d)
+#define MT6363_RG_LDO_VIO18_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VIO075_EN_ADDR                (0x1c87)
+#define MT6363_RG_LDO_VIO075_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VIO075_LP_ADDR                (0x1c87)
+#define MT6363_RG_LDO_VIO075_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VA12_1_EN_ADDR                (0x1c95)
+#define MT6363_RG_LDO_VA12_1_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VA12_1_LP_ADDR                (0x1c95)
+#define MT6363_RG_LDO_VA12_1_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VA12_2_EN_ADDR                (0x1ca3)
+#define MT6363_RG_LDO_VA12_2_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VA12_2_LP_ADDR                (0x1ca3)
+#define MT6363_RG_LDO_VA12_2_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VA15_EN_ADDR                  (0x1cb1)
+#define MT6363_RG_LDO_VA15_EN_SHIFT                 (0)
+#define MT6363_RG_LDO_VA15_LP_ADDR                  (0x1cb1)
+#define MT6363_RG_LDO_VA15_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VM18_EN_ADDR                  (0x1cbf)
+#define MT6363_RG_LDO_VM18_EN_SHIFT                 (0)
+#define MT6363_RG_LDO_VM18_LP_ADDR                  (0x1cbf)
+#define MT6363_RG_LDO_VM18_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VCN13_EN_ADDR                 (0x1d07)
+#define MT6363_RG_LDO_VCN13_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VCN13_LP_ADDR                 (0x1d07)
+#define MT6363_RG_LDO_VCN13_LP_SHIFT                (1)
+#define MT6363_LDO_VSRAM_DIGRF_WDTDBG_VOSEL_ADDR    (0x1d24)
+#define MT6363_LDO_VSRAM_MDFE_WDTDBG_VOSEL_ADDR     (0x1d8e)
+#define MT6363_LDO_VSRAM_MODEM_WDTDBG_VOSEL_ADDR    (0x1da9)
+#define MT6363_RG_LDO_VSRAM_CPUB_EN_ADDR            (0x1e07)
+#define MT6363_RG_LDO_VSRAM_CPUB_EN_SHIFT           (0)
+#define MT6363_RG_LDO_VSRAM_CPUB_LP_ADDR            (0x1e07)
+#define MT6363_RG_LDO_VSRAM_CPUB_LP_SHIFT           (1)
+#define MT6363_LDO_VSRAM_CPUB_WDTDBG_VOSEL_ADDR     (0x1e0e)
+#define MT6363_RG_LDO_VSRAM_CPUM_EN_ADDR            (0x1e1d)
+#define MT6363_RG_LDO_VSRAM_CPUM_EN_SHIFT           (0)
+#define MT6363_RG_LDO_VSRAM_CPUM_LP_ADDR            (0x1e1d)
+#define MT6363_RG_LDO_VSRAM_CPUM_LP_SHIFT           (1)
+#define MT6363_LDO_VSRAM_CPUM_WDTDBG_VOSEL_ADDR     (0x1e24)
+#define MT6363_RG_LDO_VSRAM_CPUL_EN_ADDR            (0x1e87)
+#define MT6363_RG_LDO_VSRAM_CPUL_EN_SHIFT           (0)
+#define MT6363_RG_LDO_VSRAM_CPUL_LP_ADDR            (0x1e87)
+#define MT6363_RG_LDO_VSRAM_CPUL_LP_SHIFT           (1)
+#define MT6363_LDO_VSRAM_CPUL_WDTDBG_VOSEL_ADDR     (0x1e8e)
+#define MT6363_RG_LDO_VSRAM_APU_EN_ADDR             (0x1e9d)
+#define MT6363_RG_LDO_VSRAM_APU_EN_SHIFT            (0)
+#define MT6363_RG_LDO_VSRAM_APU_LP_ADDR             (0x1e9d)
+#define MT6363_RG_LDO_VSRAM_APU_LP_SHIFT            (1)
+#define MT6363_LDO_VSRAM_APU_WDTDBG_VOSEL_ADDR      (0x1ea4)
+#define MT6363_RG_VTREF18_VOCAL_ADDR                (0x1f08)
+#define MT6363_RG_VTREF18_VOCAL_MASK                (0xf)
+#define MT6363_RG_VTREF18_VOSEL_ADDR                (0x1f09)
+#define MT6363_RG_VTREF18_VOSEL_MASK                (0xf)
+#define MT6363_RG_VAUX18_VOCAL_ADDR                 (0x1f0c)
+#define MT6363_RG_VAUX18_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VAUX18_VOSEL_ADDR                 (0x1f0d)
+#define MT6363_RG_VAUX18_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VCN15_VOCAL_ADDR                  (0x1f13)
+#define MT6363_RG_VCN15_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VCN15_VOSEL_ADDR                  (0x1f14)
+#define MT6363_RG_VCN15_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VUFS18_VOCAL_ADDR                 (0x1f17)
+#define MT6363_RG_VUFS18_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VUFS18_VOSEL_ADDR                 (0x1f18)
+#define MT6363_RG_VUFS18_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VIO18_VOCAL_ADDR                  (0x1f1b)
+#define MT6363_RG_VIO18_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VIO18_VOSEL_ADDR                  (0x1f1c)
+#define MT6363_RG_VIO18_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VM18_VOCAL_ADDR                   (0x1f1f)
+#define MT6363_RG_VM18_VOCAL_MASK                   (0xf)
+#define MT6363_RG_VM18_VOSEL_ADDR                   (0x1f20)
+#define MT6363_RG_VM18_VOSEL_MASK                   (0xf)
+#define MT6363_RG_VA15_VOCAL_ADDR                   (0x1f23)
+#define MT6363_RG_VA15_VOCAL_MASK                   (0xf)
+#define MT6363_RG_VA15_VOSEL_ADDR                   (0x1f24)
+#define MT6363_RG_VA15_VOSEL_MASK                   (0xf)
+#define MT6363_RG_VRF18_VOCAL_ADDR                  (0x1f27)
+#define MT6363_RG_VRF18_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF18_VOSEL_ADDR                  (0x1f28)
+#define MT6363_RG_VRF18_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VRFIO18_VOCAL_ADDR                (0x1f2b)
+#define MT6363_RG_VRFIO18_VOCAL_MASK                (0xf)
+#define MT6363_RG_VRFIO18_VOSEL_ADDR                (0x1f2c)
+#define MT6363_RG_VRFIO18_VOSEL_MASK                (0xf)
+#define MT6363_RG_VIO075_VOCAL_ADDR                 (0x1f31)
+#define MT6363_RG_VIO075_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VIO075_VOSEL_ADDR                 (0x1f31)
+#define MT6363_RG_VIO075_VOSEL_MASK                 (0x70)
+#define MT6363_RG_VCN13_VOCAL_ADDR                  (0x1f88)
+#define MT6363_RG_VCN13_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VUFS12_VOCAL_ADDR                 (0x1f91)
+#define MT6363_RG_VUFS12_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VUFS12_VOSEL_ADDR                 (0x1f92)
+#define MT6363_RG_VUFS12_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VA12_1_VOCAL_ADDR                 (0x1f95)
+#define MT6363_RG_VA12_1_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VA12_1_VOSEL_ADDR                 (0x1f96)
+#define MT6363_RG_VA12_1_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VA12_2_VOCAL_ADDR                 (0x1f99)
+#define MT6363_RG_VA12_2_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VA12_2_VOSEL_ADDR                 (0x1f9a)
+#define MT6363_RG_VA12_2_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VRF12_VOCAL_ADDR                  (0x1f9d)
+#define MT6363_RG_VRF12_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF12_VOSEL_ADDR                  (0x1f9e)
+#define MT6363_RG_VRF12_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VRF13_VOCAL_ADDR                  (0x1fa1)
+#define MT6363_RG_VRF13_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF13_VOSEL_ADDR                  (0x1fa2)
+#define MT6363_RG_VRF13_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VRF09_VOCAL_ADDR                  (0x1fa8)
+#define MT6363_RG_VRF09_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF09_VOSEL_ADDR                  (0x1fa9)
+#define MT6363_RG_VRF09_VOSEL_MASK                  (0xf)
+#define MT6363_ISINK_EN_CTRL0                       (0x220b)
+#define MT6363_ISINK_EN_CTRL1                       (0x220c)
+
+
+#endif /* __LINUX_REGULATOR_MT6363_H */
diff --git a/include/linux/regulator/mt6373-regulator.h b/include/linux/regulator/mt6373-regulator.h
new file mode 100644
index 000000000000..9aa38741c31a
--- /dev/null
+++ b/include/linux/regulator/mt6373-regulator.h
@@ -0,0 +1,318 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6373_H
+#define __LINUX_REGULATOR_MT6373_H
+
+enum {
+	MT6373_ID_VBUCK0,
+	MT6373_ID_VBUCK1,
+	MT6373_ID_VBUCK2,
+	MT6373_ID_VBUCK3,
+	MT6373_ID_VBUCK4,
+	MT6373_ID_VBUCK4_UFS,
+	MT6373_ID_VBUCK5,
+	MT6373_ID_VBUCK6,
+	MT6373_ID_VBUCK7,
+	MT6373_ID_VBUCK8,
+	MT6373_ID_VBUCK9,
+	MT6373_ID_VUSB,
+	MT6373_ID_VAUX18,
+	MT6373_ID_VRF13_AIF,
+	MT6373_ID_VRF18_AIF,
+	MT6373_ID_VRFIO18_AIF,
+	MT6373_ID_VRF09_AIF,
+	MT6373_ID_VRF12_AIF,
+	MT6373_ID_VANT18,
+	MT6373_ID_VSRAM_DIGRF_AIF,
+	MT6373_ID_VIBR,
+	MT6373_ID_VIO28,
+	MT6373_ID_VFP,
+	MT6373_ID_VTP,
+	MT6373_ID_VMCH,
+	MT6373_ID_VMC,
+	MT6373_ID_VAUD18,
+	MT6373_ID_VCN33_1,
+	MT6373_ID_VCN33_2,
+	MT6373_ID_VCN33_3,
+	MT6373_ID_VCN18IO,
+	MT6373_ID_VEFUSE,
+	MT6373_ID_VMCH_EINT_HIGH,
+	MT6373_ID_VMCH_EINT_LOW,
+	MT6373_MAX_REGULATOR,
+};
+
+/* Register */
+#define MT6373_BUCK_TOP_KEY_PROT_LO                 0x142a
+#define MT6373_TOP_CFG_ELR5                         0x147
+#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_SHIFT         2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_SHIFT         3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT         4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_SHIFT         5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_SHIFT         6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_SHIFT         7
+#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_ADDR          0x243
+#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_ADDR          0x243
+#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_SHIFT         2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_SHIFT         3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT         4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_SHIFT         5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_SHIFT         6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_SHIFT         7
+#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_ADDR          0x249
+#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_ADDR          0x249
+#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR       0x24c
+#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR       0x24d
+#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR       0x24e
+#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR       0x24f
+#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR       0x250
+#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR       0x251
+#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR       0x252
+#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR       0x253
+#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR       0x254
+#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR       0x255
+#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_VBUCK8_FCCM_ADDR             0x199d
+#define MT6373_PMIC_RG_VBUCK8_FCCM_SHIFT            6
+#define MT6373_PMIC_RG_VBUCK9_FCCM_ADDR             0x199d
+#define MT6373_PMIC_RG_VBUCK9_FCCM_SHIFT            7
+#define MT6373_PMIC_RG_VBUCK0_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK0_FCCM_SHIFT            0
+#define MT6373_PMIC_RG_VBUCK1_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK1_FCCM_SHIFT            1
+#define MT6373_PMIC_RG_VBUCK2_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK2_FCCM_SHIFT            2
+#define MT6373_PMIC_RG_VBUCK3_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK3_FCCM_SHIFT            3
+#define MT6373_PMIC_RG_VBUCK4_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT            0
+#define MT6373_PMIC_RG_VBUCK5_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK5_FCCM_SHIFT            1
+#define MT6373_PMIC_RG_VBUCK6_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK6_FCCM_SHIFT            2
+#define MT6373_PMIC_RG_VBUCK7_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK7_FCCM_SHIFT            3
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_ADDR 0x1b39
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_MASK 0x7F
+#define MT6373_PMIC_RG_LDO_VAUD18_EN_ADDR           0x1b87
+#define MT6373_PMIC_RG_LDO_VAUD18_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VAUD18_LP_ADDR           0x1b87
+#define MT6373_PMIC_RG_LDO_VAUD18_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VUSB_EN_ADDR             0x1b95
+#define MT6373_PMIC_RG_LDO_VUSB_EN_SHIFT            0
+#define MT6373_PMIC_RG_LDO_VUSB_LP_ADDR             0x1b95
+#define MT6373_PMIC_RG_LDO_VUSB_LP_SHIFT            1
+#define MT6373_PMIC_RG_LDO_VAUX18_EN_ADDR           0x1ba3
+#define MT6373_PMIC_RG_LDO_VAUX18_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VAUX18_LP_ADDR           0x1ba3
+#define MT6373_PMIC_RG_LDO_VAUX18_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_EN_ADDR        0x1bb1
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_LP_ADDR        0x1bb1
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_EN_ADDR        0x1bbf
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_LP_ADDR        0x1bbf
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_ADDR      0x1bcd
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_SHIFT     0
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_ADDR      0x1bcd
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_SHIFT     1
+#define MT6373_PMIC_RG_LDO_VCN33_1_EN_ADDR          0x1c07
+#define MT6373_PMIC_RG_LDO_VCN33_1_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN33_1_LP_ADDR          0x1c07
+#define MT6373_PMIC_RG_LDO_VCN33_1_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VCN33_2_EN_ADDR          0x1c15
+#define MT6373_PMIC_RG_LDO_VCN33_2_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN33_2_LP_ADDR          0x1c15
+#define MT6373_PMIC_RG_LDO_VCN33_2_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VCN33_3_EN_ADDR          0x1c23
+#define MT6373_PMIC_RG_LDO_VCN33_3_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN33_3_LP_ADDR          0x1c23
+#define MT6373_PMIC_RG_LDO_VCN33_3_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VCN18IO_EN_ADDR          0x1c31
+#define MT6373_PMIC_RG_LDO_VCN18IO_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN18IO_LP_ADDR          0x1c31
+#define MT6373_PMIC_RG_LDO_VCN18IO_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_EN_ADDR        0x1c3f
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_LP_ADDR        0x1c3f
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_EN_ADDR        0x1c4d
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_LP_ADDR        0x1c4d
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VANT18_EN_ADDR           0x1c87
+#define MT6373_PMIC_RG_LDO_VANT18_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VANT18_LP_ADDR           0x1c87
+#define MT6373_PMIC_RG_LDO_VANT18_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VEFUSE_EN_ADDR           0x1ca3
+#define MT6373_PMIC_RG_LDO_VEFUSE_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VEFUSE_LP_ADDR           0x1ca3
+#define MT6373_PMIC_RG_LDO_VEFUSE_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VMCH_EN_ADDR             0x1cb1
+#define MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT            0
+#define MT6373_PMIC_RG_LDO_VMCH_LP_ADDR             0x1cb1
+#define MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT            1
+#define MT6373_PMIC_RG_LDO_VMC_EN_ADDR              0x1cc0
+#define MT6373_PMIC_RG_LDO_VMC_EN_SHIFT             0
+#define MT6373_PMIC_RG_LDO_VMC_LP_ADDR              0x1cc0
+#define MT6373_PMIC_RG_LDO_VMC_LP_SHIFT             1
+#define MT6373_PMIC_RG_LDO_VIBR_EN_ADDR             0x1cce
+#define MT6373_PMIC_RG_LDO_VIBR_EN_SHIFT            0
+#define MT6373_PMIC_RG_LDO_VIBR_LP_ADDR             0x1cce
+#define MT6373_PMIC_RG_LDO_VIBR_LP_SHIFT            1
+#define MT6373_PMIC_RG_LDO_VIO28_EN_ADDR            0x1d07
+#define MT6373_PMIC_RG_LDO_VIO28_EN_SHIFT           0
+#define MT6373_PMIC_RG_LDO_VIO28_LP_ADDR            0x1d07
+#define MT6373_PMIC_RG_LDO_VIO28_LP_SHIFT           1
+#define MT6373_PMIC_RG_LDO_VFP_EN_ADDR              0x1d15
+#define MT6373_PMIC_RG_LDO_VFP_EN_SHIFT             0
+#define MT6373_PMIC_RG_LDO_VFP_LP_ADDR              0x1d15
+#define MT6373_PMIC_RG_LDO_VFP_LP_SHIFT             1
+#define MT6373_PMIC_RG_LDO_VTP_EN_ADDR              0x1d23
+#define MT6373_PMIC_RG_LDO_VTP_EN_SHIFT             0
+#define MT6373_PMIC_RG_LDO_VTP_LP_ADDR              0x1d23
+#define MT6373_PMIC_RG_LDO_VTP_LP_SHIFT             1
+#define MT6373_PMIC_RG_LDO_VSIM1_EN_ADDR            0x1d31
+#define MT6373_PMIC_RG_LDO_VSIM1_EN_SHIFT           0
+#define MT6373_PMIC_RG_LDO_VSIM1_LP_ADDR            0x1d31
+#define MT6373_PMIC_RG_LDO_VSIM1_LP_SHIFT           1
+#define MT6373_PMIC_RG_LDO_VSIM2_EN_ADDR            0x1d40
+#define MT6373_PMIC_RG_LDO_VSIM2_EN_SHIFT           0
+#define MT6373_PMIC_RG_LDO_VSIM2_LP_ADDR            0x1d40
+#define MT6373_PMIC_RG_LDO_VSIM2_LP_SHIFT           1
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_ADDR  0x1d87
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_SHIFT 0
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_ADDR  0x1d87
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_SHIFT 1
+#define MT6373_PMIC_RG_VAUX18_VOCAL_ADDR            0x1e08
+#define MT6373_PMIC_RG_VAUX18_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VAUX18_VOSEL_ADDR            0x1e09
+#define MT6373_PMIC_RG_VAUX18_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VUSB_VOCAL_ADDR              0x1e0c
+#define MT6373_PMIC_RG_VUSB_VOCAL_MASK              0xF
+#define MT6373_PMIC_RG_VUSB_VOSEL_ADDR              0x1e0d
+#define MT6373_PMIC_RG_VUSB_VOSEL_MASK              0xF
+#define MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR           0x1e10
+#define MT6373_PMIC_RG_VCN33_1_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR           0x1e11
+#define MT6373_PMIC_RG_VCN33_1_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR           0x1e14
+#define MT6373_PMIC_RG_VCN33_2_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR           0x1e15
+#define MT6373_PMIC_RG_VCN33_2_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR           0x1e18
+#define MT6373_PMIC_RG_VCN33_3_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR           0x1e19
+#define MT6373_PMIC_RG_VCN33_3_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VMCH_VOCAL_ADDR              0x1e1c
+#define MT6373_PMIC_RG_VMCH_VOCAL_MASK              0xF
+#define MT6373_PMIC_RG_VMCH_VOSEL_ADDR              0x1e1d
+#define MT6373_PMIC_RG_VMCH_VOSEL_MASK              0xF
+#define MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR            0x1e20
+#define MT6373_PMIC_RG_VEFUSE_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR            0x1e21
+#define MT6373_PMIC_RG_VEFUSE_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VMC_VOCAL_ADDR               0x1e24
+#define MT6373_PMIC_RG_VMC_VOCAL_MASK               0xF
+#define MT6373_PMIC_RG_VMC_VOSEL_ADDR               0x1e25
+#define MT6373_PMIC_RG_VMC_VOSEL_MASK               0xF
+#define MT6373_PMIC_RG_VIBR_VOCAL_ADDR              0x1e28
+#define MT6373_PMIC_RG_VIBR_VOCAL_MASK              0xF
+#define MT6373_PMIC_RG_VIBR_VOSEL_ADDR              0x1e29
+#define MT6373_PMIC_RG_VIBR_VOSEL_MASK              0xF
+#define MT6373_PMIC_RG_VIO28_VOCAL_ADDR             0x1e2c
+#define MT6373_PMIC_RG_VIO28_VOCAL_MASK             0xF
+#define MT6373_PMIC_RG_VIO28_VOSEL_ADDR             0x1e2d
+#define MT6373_PMIC_RG_VIO28_VOSEL_MASK             0xF
+#define MT6373_PMIC_RG_VFP_VOCAL_ADDR               0x1e30
+#define MT6373_PMIC_RG_VFP_VOCAL_MASK               0xF
+#define MT6373_PMIC_RG_VFP_VOSEL_ADDR               0x1e31
+#define MT6373_PMIC_RG_VFP_VOSEL_MASK               0xF
+#define MT6373_PMIC_RG_VTP_VOCAL_ADDR               0x1e34
+#define MT6373_PMIC_RG_VTP_VOCAL_MASK               0xF
+#define MT6373_PMIC_RG_VTP_VOSEL_ADDR               0x1e35
+#define MT6373_PMIC_RG_VTP_VOSEL_MASK               0xF
+#define MT6373_PMIC_RG_VSIM1_VOCAL_ADDR             0x1e38
+#define MT6373_PMIC_RG_VSIM1_VOCAL_MASK             0xF
+#define MT6373_PMIC_RG_VSIM1_VOSEL_ADDR             0x1e39
+#define MT6373_PMIC_RG_VSIM1_VOSEL_MASK             0xF
+#define MT6373_PMIC_RG_VSIM2_VOCAL_ADDR             0x1e3c
+#define MT6373_PMIC_RG_VSIM2_VOCAL_MASK             0xF
+#define MT6373_PMIC_RG_VSIM2_VOSEL_ADDR             0x1e3d
+#define MT6373_PMIC_RG_VSIM2_VOSEL_MASK             0xF
+#define MT6373_PMIC_RG_VAUD18_VOCAL_ADDR            0x1e88
+#define MT6373_PMIC_RG_VAUD18_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VAUD18_VOSEL_ADDR            0x1e89
+#define MT6373_PMIC_RG_VAUD18_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR         0x1e8c
+#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR         0x1e8d
+#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_MASK         0xF
+#define MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR           0x1e90
+#define MT6373_PMIC_RG_VCN18IO_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR           0x1e91
+#define MT6373_PMIC_RG_VCN18IO_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR       0x1e94
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_MASK       0xF
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR       0x1e95
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_MASK       0xF
+#define MT6373_PMIC_RG_VANT18_VOCAL_ADDR            0x1e98
+#define MT6373_PMIC_RG_VANT18_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VANT18_VOSEL_ADDR            0x1e99
+#define MT6373_PMIC_RG_VANT18_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR         0x1f08
+#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR         0x1f09
+#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_MASK         0xF
+#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR         0x1f0c
+#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR         0x1f0d
+#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_MASK         0xF
+#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR         0x1f88
+#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR         0x1f89
+#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_MASK         0xF
+
+#define MT6373_LDO_VMCH_EINT                        0x1cbf
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_EN_MASK        0x1
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK       0x4
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_DB_MASK        0x10
+
+#endif /* __LINUX_REGULATOR_MT6373_H */
-- 
2.46.0


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

* [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
  2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
  2025-03-14  7:32 ` [PATCH 2/5] pmic: mediatek: Add pmic regulator driver Lu.Tang
@ 2025-03-14  7:32 ` Lu.Tang
  2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
  2025-03-14  7:32 ` [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196 Lu.Tang
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Lu.Tang @ 2025-03-14  7:32 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group, Lu.Tang

From: "Lu.Tang" <lu.tang@mediatek.com>

Add spmi pmic mfd driver for mt8196

Signed-off-by: Lu Tang <lu.tang@mediatek.com>
---
 drivers/mfd/Kconfig                  |  26 ++
 drivers/mfd/Makefile                 |   2 +
 drivers/mfd/mt6685-core.c            |  83 +++++
 drivers/mfd/mtk-spmi-pmic.c          | 518 +++++++++++++++++++++++++++
 include/linux/mfd/mt6363/core.h      | 134 +++++++
 include/linux/mfd/mt6363/registers.h | 168 +++++++++
 include/linux/mfd/mt6373/core.h      |  94 +++++
 include/linux/mfd/mt6373/registers.h |  53 +++
 8 files changed, 1078 insertions(+)
 create mode 100644 drivers/mfd/mt6685-core.c
 create mode 100644 drivers/mfd/mtk-spmi-pmic.c
 create mode 100644 include/linux/mfd/mt6363/core.h
 create mode 100644 include/linux/mfd/mt6363/registers.h
 create mode 100644 include/linux/mfd/mt6373/core.h
 create mode 100644 include/linux/mfd/mt6373/registers.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d44c69bb3dfd..a62625566893 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1030,6 +1030,32 @@ config MFD_MT6397
 	  accessing the device; additional drivers must be enabled in order
 	  to use the functionality of the device.
 
+config MFD_MT6685
+	tristate "MT6685 SPMI PMIC"
+	depends on OF
+	depends on SPMI
+	select REGMAP_SPMI
+	select REGMAP_IRQ
+	help
+	  This enables support for the Mediatek SPMI PMICs.
+	  These PMICs are currently used with the Mediatek series of
+	  SoCs.  Note, that this will only be useful paired with descriptions
+	  of the independent functions as children nodes in the device tree.
+
+config MFD_MTK_SPMI_PMIC
+	tristate "Mediatek SPMI PMICs"
+	depends on OF
+	depends on SPMI
+	select REGMAP_SPMI
+	help
+	  This enables support for the Mediatek SPMI PMICs.
+	  These PMICs are currently used with the MT63xx 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 SPMI PMIC
+	  series 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 9220eaf7cf12..b8cb34284e56 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -182,6 +182,8 @@ 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_MT6685)	+= mt6685-core.o
+obj-$(CONFIG_MFD_MTK_SPMI_PMIC)	+= mtk-spmi-pmic.o
 
 pcf50633-objs			:= pcf50633-core.o pcf50633-irq.o
 obj-$(CONFIG_MFD_PCF50633)	+= pcf50633.o
diff --git a/drivers/mfd/mt6685-core.c b/drivers/mfd/mt6685-core.c
new file mode 100644
index 000000000000..c71008184666
--- /dev/null
+++ b/drivers/mfd/mt6685-core.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 MediaTek Inc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+static const struct mfd_cell mt6685_devs[] = {
+	{
+		.name = "mt6685-clkbuf",
+		.of_compatible = "mediatek,mt6685-clkbuf",
+	}, {
+		.name = "mt6685-tb-clkbuf",
+		.of_compatible = "mediatek,mt6685-tb-clkbuf",
+	}, {
+		.name = "mt6685-rtc",
+		.of_compatible = "mediatek,mt6685-rtc",
+	}, {
+		.name = "mt6685-audclk",
+		.of_compatible = "mediatek,mt6685-audclk",
+	}, {
+		.name = "mt6685-consys",
+		.of_compatible = "mediatek,mt6685-consys",
+	}, {
+		.name = "mt6685-gps",
+		.of_compatible = "mediatek,mt6685-gps",
+	}
+};
+
+static const struct regmap_config spmi_regmap_config = {
+	.reg_bits	= 16,
+	.val_bits	= 8,
+	.max_register	= 0x2000,
+	.fast_io	= true,
+	.use_single_read = true,
+	.use_single_write = true
+};
+
+static int mt6685_spmi_probe(struct spmi_device *sdev)
+{
+	int ret;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&sdev->dev, "Failed to init mt6685 regmap: %ld\n", PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	ret = devm_mfd_add_devices(&sdev->dev, -1, mt6685_devs,
+				   ARRAY_SIZE(mt6685_devs), NULL, 0, NULL);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to add child devices: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6685_id_table[] = {
+	{ .compatible = "mediatek,mt6685", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6685_id_table);
+
+static struct spmi_driver mt6685_spmi_driver = {
+	.probe = mt6685_spmi_probe,
+	.driver = {
+		.name = "mt6685",
+		.of_match_table = mt6685_id_table,
+	},
+};
+module_spmi_driver(mt6685_spmi_driver);
+
+MODULE_DESCRIPTION("Mediatek SPMI MT6685 Clock IC driver");
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mtk-spmi-pmic.c b/drivers/mfd/mtk-spmi-pmic.c
new file mode 100644
index 000000000000..4c4bed5e991a
--- /dev/null
+++ b/drivers/mfd/mtk-spmi-pmic.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mt6363/core.h>
+#include <linux/mfd/mt6363/registers.h>
+#include <linux/mfd/mt6373/core.h>
+#include <linux/mfd/mt6373/registers.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#define MTK_SPMI_PMIC_REG_WIDTH	8
+#define PMIC_SWCID		0xB
+#define PMIC_MT6316_SWCID	0x20B
+#define RCS_INT_DONE		0x41B
+
+struct irq_top_t {
+	int hwirq_base;
+	unsigned int num_int_regs;
+	unsigned int en_reg;
+	unsigned int en_reg_shift;
+	unsigned int sta_reg;
+	unsigned int sta_reg_shift;
+	unsigned int top_offset;
+};
+
+struct mtk_spmi_pmic_data {
+	const struct mfd_cell *cells;
+	int cell_size;
+	unsigned int num_top;
+	unsigned int num_pmic_irqs;
+	unsigned short top_int_status_reg;
+	struct irq_top_t *pmic_ints;
+	unsigned int cid_addr;
+};
+
+struct pmic_core {
+	struct device *dev;
+	struct spmi_device *sdev;
+	struct regmap *regmap;
+	u16 chip_id;
+	int irq;
+	bool *enable_hwirq;
+	bool *cache_hwirq;
+	struct mutex irqlock;
+	struct irq_domain *irq_domain;
+	const struct mtk_spmi_pmic_data *chip_data;
+};
+
+static const struct resource mt6363_regulators_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN15_OC, "VCN15"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN13_OC, "VCN13"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF09_OC, "VRF09"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF12_OC, "VRF12"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF13_OC, "VRF13"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF18_OC, "VRF18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRFIO18_OC, "VRFIO18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_MDFE_OC, "VSRAM_MDFE"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VTREF18_OC, "VTREF18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_APU_OC, "VSRAM_APU"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VAUX18_OC, "VAUX18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VEMC_OC, "VEMC"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS12_OC, "VUFS12"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS18_OC, "VUFS18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO18_OC, "VIO18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO075_OC, "VIO075"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_1_OC, "VA12_1"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_2_OC, "VA12_2"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA15_OC, "VA15"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VM18_OC, "VM18"),
+};
+
+static const struct resource mt6363_keys_resources[] = {
+	DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY),
+	DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY),
+	DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY_R),
+	DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY_R),
+};
+
+static const struct resource mt6363_lvsys_notify_resources[] = {
+	/* MT6363 LVSYS interrupt name is contrary,
+	 * we name LVSYS_R to MT6363_IRQ_NI_LVSYS_INT_FALLING;
+	 * LVSYS_F to MT6363_IRQ_NI_LVSYS_INT_RISING
+	 */
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_FALLING, "LVSYS_R"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_RISING, "LVSYS_F"),
+};
+
+static const struct resource mt6373_regulators_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VUSB_OC, "VUSB"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VAUX18_OC, "VAUX18"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF13_AIF_OC, "VRF13_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF18_AIF_OC, "VRF18_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRFIO18_AIF_OC, "VRFIO18_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_1_OC, "VCN33_1"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_2_OC, "VCN33_2"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_3_OC, "VCN33_3"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN18IO_OC, "VCN18IO"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF09_AIF_OC, "VRF09_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF12_AIF_OC, "VRF12_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VANT18_OC, "VANT18"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VSRAM_DIGRF_AIF_OC, "VSRAM_DIGRF_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VEFUSE_OC, "VEFUSE"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMCH_OC, "VMCH"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMC_OC, "VMC"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIBR_OC, "VIBR"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIO28_OC, "VIO28"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VFP_OC, "VFP"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VTP_OC, "VTP"),
+};
+
+static const struct mfd_cell mt6363_devs[] = {
+	{
+		.name = "mt6363-auxadc",
+		.of_compatible = "mediatek,mt6363-auxadc",
+	}, {
+		.name = "mtk-dynamic-loading-throttling",
+		.of_compatible = "mediatek,mt6363-dynamic_loading_throttling",
+	}, {
+		.name = "mt6363-efuse",
+		.of_compatible = "mediatek,mt6363-efuse",
+	}, {
+		.name = "mt6363-regulator",
+		.num_resources = ARRAY_SIZE(mt6363_regulators_resources),
+		.resources = mt6363_regulators_resources,
+		.of_compatible = "mediatek,mt6363-regulator",
+	}, {
+		.name = "mtk-pmic-keys",
+		.num_resources = ARRAY_SIZE(mt6363_keys_resources),
+		.resources = mt6363_keys_resources,
+		.of_compatible = "mediatek,mt6363-keys"
+	}, {
+		.name = "mt6363-consys",
+		.of_compatible = "mediatek,mt6363-consys",
+	}, {
+		.name = "mt6363-lvsys-notify",
+		.num_resources = ARRAY_SIZE(mt6363_lvsys_notify_resources),
+		.resources = mt6363_lvsys_notify_resources,
+		.of_compatible = "mediatek,mt6363-lvsys-notify",
+	}, {
+		.name = "mt6363-pinctrl",
+		.of_compatible = "mediatek,mt6363-pinctrl",
+	},
+};
+
+static const struct mfd_cell mt6373_devs[] = {
+	{
+		.name = "mt6373-regulator",
+		.num_resources = ARRAY_SIZE(mt6373_regulators_resources),
+		.resources = mt6373_regulators_resources,
+		.of_compatible = "mediatek,mt6373-regulator",
+	}, {
+		.name = "mt6373-auxadc",
+		.of_compatible = "mediatek,mt6373-auxadc",
+	}, {
+		.name = "mt6373-efuse",
+		.of_compatible = "mediatek,mt6373-efuse",
+	}, {
+		.name = "mt6373-consys",
+		.of_compatible = "mediatek,mt6373-consys",
+	}, {
+		.name = "mt6373-pinctrl",
+		.of_compatible = "mediatek,mt6373-pinctrl",
+	},
+};
+
+static struct irq_top_t mt6363_ints[] = {
+	MT6363_TOP_GEN(BUCK),
+	MT6363_TOP_GEN(LDO),
+	MT6363_TOP_GEN(PSC),
+	MT6363_TOP_GEN(MISC),
+	MT6363_TOP_GEN(HK),
+	MT6363_TOP_GEN(BM),
+};
+
+
+static struct irq_top_t mt6373_ints[] = {
+	MT6373_TOP_GEN(BUCK),
+	MT6373_TOP_GEN(LDO),
+	MT6373_TOP_GEN(MISC),
+};
+
+static const struct mtk_spmi_pmic_data mt6316_data = {
+	.num_pmic_irqs = 0,
+	.cid_addr = PMIC_MT6316_SWCID,
+};
+
+static const struct mtk_spmi_pmic_data mt6363_data = {
+	.cells = mt6363_devs,
+	.cell_size = ARRAY_SIZE(mt6363_devs),
+	.num_top = ARRAY_SIZE(mt6363_ints),
+	.num_pmic_irqs = MT6363_IRQ_NR,
+	.top_int_status_reg = MT6363_TOP_INT_STATUS1,
+	.pmic_ints = mt6363_ints,
+};
+
+static const struct mtk_spmi_pmic_data mt6373_data = {
+	.cells = mt6373_devs,
+	.cell_size = ARRAY_SIZE(mt6373_devs),
+	.num_top = ARRAY_SIZE(mt6373_ints),
+	.num_pmic_irqs = MT6373_IRQ_NR,
+	.top_int_status_reg = MT6373_TOP_INT_STATUS1,
+	.pmic_ints = mt6373_ints,
+};
+
+static void mtk_spmi_pmic_irq_enable(struct irq_data *data)
+{
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+
+	core->enable_hwirq[hwirq] = true;
+}
+
+static void mtk_spmi_pmic_irq_disable(struct irq_data *data)
+{
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+
+	core->enable_hwirq[hwirq] = false;
+}
+
+static void mtk_spmi_pmic_irq_lock(struct irq_data *data)
+{
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&core->irqlock);
+}
+
+static void mtk_spmi_pmic_irq_sync_unlock(struct irq_data *data)
+{
+	unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift;
+	struct irq_top_t *pmic_int;
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	for (i = 0; i < chip_data->num_pmic_irqs; i++) {
+		if (core->enable_hwirq[i] == core->cache_hwirq[i])
+			continue;
+
+		/* Find out the IRQ group */
+		top_gp = 0;
+		while ((top_gp + 1) < chip_data->num_top &&
+			i >= chip_data->pmic_ints[top_gp + 1].hwirq_base)
+			top_gp++;
+
+		pmic_int = &(chip_data->pmic_ints[top_gp]);
+		/* Find the IRQ registers */
+		gp_offset = i - pmic_int->hwirq_base;
+		int_regs = gp_offset / MTK_SPMI_PMIC_REG_WIDTH;
+		shift = gp_offset % MTK_SPMI_PMIC_REG_WIDTH;
+		en_reg = pmic_int->en_reg + (pmic_int->en_reg_shift * int_regs);
+
+		regmap_update_bits(core->regmap, en_reg, BIT(shift),
+				   core->enable_hwirq[i] << shift);
+		core->cache_hwirq[i] = core->enable_hwirq[i];
+	}
+	mutex_unlock(&core->irqlock);
+}
+
+static struct irq_chip mtk_spmi_pmic_irq_chip = {
+	.name = "spmi-pmic-irq",
+	.flags = IRQCHIP_SKIP_SET_WAKE,
+	.irq_enable = mtk_spmi_pmic_irq_enable,
+	.irq_disable = mtk_spmi_pmic_irq_disable,
+	.irq_bus_lock = mtk_spmi_pmic_irq_lock,
+	.irq_bus_sync_unlock = mtk_spmi_pmic_irq_sync_unlock,
+};
+
+static void mtk_spmi_pmic_irq_sp_handler(struct pmic_core *core,
+					 unsigned int top_gp)
+{
+	unsigned int irq_status = 0, sta_reg, status;
+	unsigned int hwirq, virq;
+	int ret, i, j;
+	struct irq_top_t *pmic_int;
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	for (i = 0; i < chip_data->pmic_ints[top_gp].num_int_regs; i++) {
+		pmic_int = &(chip_data->pmic_ints[top_gp]);
+		sta_reg = pmic_int->sta_reg + (pmic_int->sta_reg_shift * i);
+
+		ret = regmap_read(core->regmap, sta_reg, &irq_status);
+		if (ret) {
+			dev_err(core->dev,
+				"Failed to read irq status: %d\n", ret);
+			return;
+		}
+
+		if (!irq_status)
+			continue;
+
+		status = irq_status;
+		do {
+			j = __ffs(status);
+
+			hwirq = pmic_int->hwirq_base + MTK_SPMI_PMIC_REG_WIDTH * i + j;
+
+			virq = irq_find_mapping(core->irq_domain, hwirq);
+			dev_info(core->dev, "[%x]Reg[0x%x]=0x%x,hwirq=%d\n",
+				 core->chip_id, sta_reg, irq_status, hwirq);
+			if (virq)
+				handle_nested_irq(virq);
+
+			status &= ~BIT(j);
+		} while (status);
+
+		regmap_write(core->regmap, sta_reg, irq_status);
+	}
+}
+
+static irqreturn_t mtk_spmi_pmic_irq_handler(int irq, void *data)
+{
+	int ret;
+	unsigned int bit, i, top_irq_status = 0;
+	struct pmic_core *core = data;
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	ret = regmap_read(core->regmap, chip_data->top_int_status_reg,
+			  &top_irq_status);
+	if (ret) {
+		dev_err(core->dev,
+			"Failed to read status from the device, ret=%d\n", ret);
+		return IRQ_NONE;
+	}
+
+	dev_info(core->dev, "top_irq_sts:0x%x\n", top_irq_status);
+	for (i = 0; i < chip_data->num_top; i++) {
+		bit = BIT(chip_data->pmic_ints[i].top_offset);
+		if (top_irq_status & bit)
+			mtk_spmi_pmic_irq_sp_handler(core, i);
+	}
+
+	ret = regmap_write(core->regmap, RCS_INT_DONE, 1);
+	if (ret) {
+		dev_err(core->dev,
+			"Failed to clear RCS flag, ret=%d\n", ret);
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mtk_spmi_pmic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+					irq_hw_number_t hw)
+{
+	struct pmic_core *core = d->host_data;
+
+	irq_set_chip_data(irq, core);
+	irq_set_chip_and_handler(irq, &mtk_spmi_pmic_irq_chip,
+				 handle_level_irq);
+	irq_set_nested_thread(irq, 1);
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops pmic_irq_domain_ops = {
+	.map = mtk_spmi_pmic_irq_domain_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
+static int mtk_spmi_pmic_irq_init(struct pmic_core *core)
+{
+	int i, j, ret;
+	unsigned int en_reg, sta_reg;
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	mutex_init(&core->irqlock);
+	core->enable_hwirq = devm_kcalloc(core->dev,
+					  chip_data->num_pmic_irqs,
+					  sizeof(bool), GFP_KERNEL);
+	if (!core->enable_hwirq)
+		return -ENOMEM;
+
+	core->cache_hwirq = devm_kcalloc(core->dev,
+					 chip_data->num_pmic_irqs,
+					 sizeof(bool), GFP_KERNEL);
+	if (!core->cache_hwirq)
+		return -ENOMEM;
+
+	/* Disable all interrupt for initializing */
+	for (i = 0; i < chip_data->num_top; i++) {
+		for (j = 0; j < chip_data->pmic_ints[i].num_int_regs; j++) {
+			en_reg = chip_data->pmic_ints[i].en_reg +
+				chip_data->pmic_ints[i].en_reg_shift * j;
+			regmap_write(core->regmap, en_reg, 0);
+			sta_reg = chip_data->pmic_ints[i].sta_reg +
+				chip_data->pmic_ints[i].sta_reg_shift * j;
+			regmap_write(core->regmap, sta_reg, 0xFF);
+		}
+	}
+	regmap_write(core->regmap, RCS_INT_DONE, 1);
+
+	core->irq_domain = irq_domain_add_linear(core->dev->of_node,
+						 chip_data->num_pmic_irqs,
+						 &pmic_irq_domain_ops,
+						 core);
+	if (!core->irq_domain) {
+		dev_err(core->dev, "Could not create IRQ domain\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_threaded_irq(core->dev, core->irq, NULL,
+					mtk_spmi_pmic_irq_handler, IRQF_ONESHOT,
+					mtk_spmi_pmic_irq_chip.name, core);
+	if (ret) {
+		dev_err(core->dev, "Failed to register IRQ=%d, ret=%d\n",
+			core->irq, ret);
+		return ret;
+	}
+
+	enable_irq_wake(core->irq);
+	return ret;
+}
+
+static const struct regmap_config spmi_regmap_config = {
+	.reg_bits	= 16,
+	.val_bits	= 8,
+	.max_register	= 0xffff,
+	.fast_io	= true,
+};
+
+static int mtk_spmi_pmic_probe(struct spmi_device *sdev)
+{
+	int ret;
+	unsigned int id;
+	struct device_node *np = sdev->dev.of_node;
+	struct pmic_core *core;
+	const struct mtk_spmi_pmic_data *chip_data;
+
+	core = devm_kzalloc(&sdev->dev, sizeof(*core), GFP_KERNEL);
+	if (!core)
+		return -ENOMEM;
+
+	core->sdev = sdev;
+	core->dev = &sdev->dev;
+	chip_data = (struct mtk_spmi_pmic_data *)of_device_get_match_data(&sdev->dev);
+	if (!chip_data)
+		return -ENODEV;
+
+	core->chip_data = chip_data;
+	core->regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
+	if (IS_ERR(core->regmap))
+		return PTR_ERR(core->regmap);
+	if (chip_data->cid_addr)
+		ret = regmap_read(core->regmap, chip_data->cid_addr, &id);
+	else
+		ret = regmap_read(core->regmap, PMIC_SWCID, &id);
+	if (ret || id == 0) {
+		dev_err(&sdev->dev, "Failed to read chip id: %d\n", ret);
+		return ret;
+	}
+
+	core->chip_id = id;
+
+	if (chip_data->num_pmic_irqs) {
+		core->irq = of_irq_get(np, 0);
+		if (core->irq < 0)
+			dev_err(&sdev->dev, "Failed to get irq(%d)\n", core->irq);
+
+		ret = mtk_spmi_pmic_irq_init(core);
+		if (ret)
+			dev_err(&sdev->dev, "IRQ_init failed(%d)\n", core->irq);
+
+		ret = devm_mfd_add_devices(&sdev->dev, -1, chip_data->cells,
+					   chip_data->cell_size, NULL, 0,
+					   core->irq_domain);
+		if (ret) {
+			irq_domain_remove(core->irq_domain);
+			dev_err(&sdev->dev, "Failed to add mfd devices: %d\n", ret);
+			return ret;
+		}
+	} else {
+		ret = devm_of_platform_populate(&sdev->dev);
+		if (ret) {
+			dev_err(&sdev->dev, "Failed to platform populate: %d\n", ret);
+			return ret;
+		}
+	}
+
+	device_init_wakeup(&sdev->dev, true);
+
+	dev_dbg(&sdev->dev, "probe chip id=0x%x done\n", core->chip_id);
+
+	return ret;
+}
+
+static const struct of_device_id mtk_spmi_pmic_of_match[] = {
+	{ .compatible = "mediatek,mt6316", .data = &mt6316_data, },
+	{ .compatible = "mediatek,mt6363", .data = &mt6363_data, },
+	{ .compatible = "mediatek,mt6373", .data = &mt6373_data, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mtk_spmi_pmic_of_match);
+
+static struct spmi_driver mtk_spmi_pmic_driver = {
+	.driver = {
+		.name = "mtk-spmi-pmic",
+		.of_match_table = of_match_ptr(mtk_spmi_pmic_of_match),
+	},
+	.probe = mtk_spmi_pmic_probe,
+};
+module_spmi_driver(mtk_spmi_pmic_driver);
+
+MODULE_DESCRIPTION("Mediatek SPMI PMIC driver");
+MODULE_ALIAS("spmi:spmi-pmic");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Argus Lin <argus.lin@mediatek.com>");
+MODULE_AUTHOR("Jeter Chen <jeter.chen@mediatek.com>");
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
diff --git a/include/linux/mfd/mt6363/core.h b/include/linux/mfd/mt6363/core.h
new file mode 100644
index 000000000000..3243a52da34d
--- /dev/null
+++ b/include/linux/mfd/mt6363/core.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6363_CORE_H__
+#define __MFD_MT6363_CORE_H__
+
+#define MT6363_REG_WIDTH 8
+
+enum mt6363_irq_top_status_shift {
+	MT6363_BUCK_TOP = 0,
+	MT6363_LDO_TOP,
+	MT6363_PSC_TOP,
+	MT6363_MISC_TOP,
+	MT6363_HK_TOP,
+	MT6363_SCK_TOP,
+	MT6363_BM_TOP,
+	MT6363_AUD_TOP,
+};
+
+enum mt6363_irq_numbers {
+	MT6363_IRQ_VS2_OC = 0,
+	MT6363_IRQ_VBUCK1_OC,
+	MT6363_IRQ_VBUCK2_OC,
+	MT6363_IRQ_VBUCK3_OC,
+	MT6363_IRQ_VBUCK4_OC,
+	MT6363_IRQ_VBUCK5_OC,
+	MT6363_IRQ_VBUCK6_OC,
+	MT6363_IRQ_VBUCK7_OC,
+	MT6363_IRQ_VS1_OC,
+	MT6363_IRQ_VS3_OC,
+	MT6363_IRQ_VCN15_OC = 16,
+	MT6363_IRQ_VCN13_OC,
+	MT6363_IRQ_VRF09_OC,
+	MT6363_IRQ_VRF12_OC,
+	MT6363_IRQ_VRF13_OC,
+	MT6363_IRQ_VRF18_OC,
+	MT6363_IRQ_VRFIO18_OC,
+	MT6363_IRQ_VSRAM_DIGRF_OC,
+	MT6363_IRQ_VSRAM_MDFE_OC,
+	MT6363_IRQ_VSRAM_MODEM_OC,
+	MT6363_IRQ_VTREF18_OC,
+	MT6363_IRQ_VSRAM_CPUB_OC,
+	MT6363_IRQ_VSRAM_CPUM_OC,
+	MT6363_IRQ_VSRAM_CPUL_OC,
+	MT6363_IRQ_VSRAM_APU_OC,
+	MT6363_IRQ_VAUX18_OC,
+	MT6363_IRQ_VEMC_OC,
+	MT6363_IRQ_VUFS12_OC,
+	MT6363_IRQ_VUFS18_OC,
+	MT6363_IRQ_VIO18_OC,
+	MT6363_IRQ_VIO075_OC,
+	MT6363_IRQ_VA12_1_OC,
+	MT6363_IRQ_VA12_2_OC,
+	MT6363_IRQ_VA15_OC,
+	MT6363_IRQ_VM18_OC,
+	MT6363_IRQ_PWRKEY = 48,
+	MT6363_IRQ_HOMEKEY,
+	MT6363_IRQ_HOMEKEY_2,
+	MT6363_IRQ_PWRKEY_R,
+	MT6363_IRQ_HOMEKEY_R,
+	MT6363_IRQ_HOMEKEY_2_R,
+	MT6363_IRQ_NI_LVSYS_INT_FALLING,
+	MT6363_IRQ_NI_LVSYS_INT_RISING,
+	MT6363_IRQ_CHRDET_LEVEL,
+	MT6363_IRQ_CHRDET_EDGE,
+	MT6363_IRQ_RCS0 = 64,
+	MT6363_IRQ_SPMI_CMD_ALERT,
+	MT6363_IRQ_BM_PROTREG = 70,
+	MT6363_IRQ_BUCK_PROTREG = 72,
+	MT6363_IRQ_LDO_PROTREG,
+	MT6363_IRQ_PSC_PROTREG,
+	MT6363_IRQ_PLT_PROTREG,
+	MT6363_IRQ_HK_PROTREG,
+	MT6363_IRQ_TOP_PROTREG = 79,
+	MT6363_IRQ_BAT_H,
+	MT6363_IRQ_BAT_L,
+	MT6363_IRQ_BAT2_H,
+	MT6363_IRQ_BAT2_L,
+	MT6363_IRQ_BAT_TEMP_H,
+	MT6363_IRQ_BAT_TEMP_L,
+	MT6363_IRQ_THR_H,
+	MT6363_IRQ_THR_L,
+	MT6363_IRQ_AUXADC_IMP,
+	MT6363_IRQ_NAG_C_DLTV,
+	MT6363_IRQ_FG_BAT_H = 88,
+	MT6363_IRQ_FG_BAT_L,
+	MT6363_IRQ_FG_CUR_H,
+	MT6363_IRQ_FG_CUR_L,
+	MT6363_IRQ_FG_ZCV,
+	MT6363_IRQ_FG_N_CHARGE_L = 95,
+	MT6363_IRQ_FG_IAVG_H,
+	MT6363_IRQ_FG_IAVG_L,
+	MT6363_IRQ_FG_DISCHARGE = 99,
+	MT6363_IRQ_FG_CHARGE,
+	MT6363_IRQ_BATON_LV = 104,
+	MT6363_IRQ_BATON_BAT_IN = 106,
+	MT6363_IRQ_BATON_BAT_OUT,
+	MT6363_IRQ_NR = 108,
+};
+
+#define MT6363_IRQ_BUCK_BASE MT6363_IRQ_VS2_OC
+#define MT6363_IRQ_LDO_BASE MT6363_IRQ_VCN15_OC
+#define MT6363_IRQ_PSC_BASE MT6363_IRQ_PWRKEY
+#define MT6363_IRQ_MISC_BASE MT6363_IRQ_RCS0
+#define MT6363_IRQ_HK_BASE MT6363_IRQ_BAT_H
+#define MT6363_IRQ_BM_BASE MT6363_IRQ_FG_BAT_H
+
+#define MT6363_IRQ_BUCK_BITS \
+	(MT6363_IRQ_VS3_OC - MT6363_IRQ_BUCK_BASE + 1)
+#define MT6363_IRQ_LDO_BITS \
+	(MT6363_IRQ_VM18_OC - MT6363_IRQ_LDO_BASE + 1)
+#define MT6363_IRQ_PSC_BITS \
+	(MT6363_IRQ_CHRDET_EDGE - MT6363_IRQ_PSC_BASE + 1)
+#define MT6363_IRQ_MISC_BITS \
+	(MT6363_IRQ_TOP_PROTREG - MT6363_IRQ_MISC_BASE + 1)
+#define MT6363_IRQ_HK_BITS \
+	(MT6363_IRQ_NAG_C_DLTV - MT6363_IRQ_HK_BASE + 1)
+#define MT6363_IRQ_BM_BITS \
+	(MT6363_IRQ_BATON_BAT_OUT - MT6363_IRQ_BM_BASE + 1)
+
+#define MT6363_TOP_GEN(sp) \
+{ \
+	.hwirq_base = MT6363_IRQ_##sp##_BASE, \
+	.num_int_regs =	((MT6363_IRQ_##sp##_BITS - 1) / MT6363_REG_WIDTH) + 1, \
+	.en_reg = MT6363_##sp##_TOP_INT_CON0, \
+	.en_reg_shift = 0x3, \
+	.sta_reg = MT6363_##sp##_TOP_INT_STATUS0, \
+	.sta_reg_shift = 0x1, \
+	.top_offset = MT6363_##sp##_TOP, \
+}
+
+#endif /* __MFD_MT6363_CORE_H__ */
diff --git a/include/linux/mfd/mt6363/registers.h b/include/linux/mfd/mt6363/registers.h
new file mode 100644
index 000000000000..e22ca686a7d0
--- /dev/null
+++ b/include/linux/mfd/mt6363/registers.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+
+#ifndef __MFD_MT6363_REGISTERS_H__
+#define __MFD_MT6363_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6363_TOPSTATUS		   (0x1e)
+#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_STRUP_CON11		   (0xa0e)
+#define MT6363_STRUP_CON12		   (0xa0f)
+#define MT6363_PCHR_VREF_ANA_CON1          (0xa89)
+#define MT6363_PCHR_VREF_ANA_CON2          (0xa8a)
+#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)
+
+/* voter */
+#define MT6363_BUCK_VS2_VOTER_CON0         (0x149a)
+#define MT6363_BUCK_VS2_VOTER_CON0_SET     (0x149b)
+#define MT6363_BUCK_VS2_VOTER_CON0_CLR     (0x149c)
+#define MT6363_BUCK_VS2_VOTER_CON1         (0x149d)
+#define MT6363_BUCK_VS2_VOTER_CON1_SET     (0x149e)
+#define MT6363_BUCK_VS2_VOTER_CON1_CLR     (0x149f)
+#define MT6363_BUCK_VS2_VOTER_CFG          (0x14a0)
+#define MT6363_BUCK_VS1_VOTER_CON0         (0x189a)
+#define MT6363_BUCK_VS1_VOTER_CON0_SET     (0x189b)
+#define MT6363_BUCK_VS1_VOTER_CON0_CLR     (0x189c)
+#define MT6363_BUCK_VS1_VOTER_CON1         (0x189d)
+#define MT6363_BUCK_VS1_VOTER_CON1_SET     (0x189e)
+#define MT6363_BUCK_VS1_VOTER_CON1_CLR     (0x189f)
+#define MT6363_BUCK_VS1_VOTER_CFG          (0x18a0)
+#define MT6363_BUCK_VS3_VOTER_CON0         (0x191a)
+#define MT6363_BUCK_VS3_VOTER_CON0_SET     (0x191b)
+#define MT6363_BUCK_VS3_VOTER_CON0_CLR     (0x191c)
+#define MT6363_BUCK_VS3_VOTER_CON1         (0x191d)
+#define MT6363_BUCK_VS3_VOTER_CON1_SET     (0x191e)
+#define MT6363_BUCK_VS3_VOTER_CON1_CLR     (0x191f)
+#define MT6363_BUCK_VS3_VOTER_CFG          (0x1920)
+
+#define MT6363_CHRDET_DEB_ADDR             MT6363_TOPSTATUS
+#define MT6363_CHRDET_DEB_MASK             (0x1)
+#define MT6363_CHRDET_DEB_SHIFT            (2)
+#define MT6363_RG_VBB_UVLO_VTHL_ADDR       MT6363_PCHR_VREF_ANA_CON1
+#define MT6363_RG_VBB_UVLO_VTHL_MASK       (0xF)
+#define MT6363_RG_VBB_UVLO_VTHL_SHIFT      (0)
+#define MT6363_RG_VSYS_UVLO_VTHL_ADDR      MT6363_PCHR_VREF_ANA_CON2
+#define MT6363_RG_VSYS_UVLO_VTHL_MASK      (0xF)
+#define MT6363_RG_VSYS_UVLO_VTHL_SHIFT     (0)
+
+#define MT6363_AUXADC_ADC0_L               (0x1088)
+#define MT6363_AUXADC_ADC3_L               (0x108e)
+#define MT6363_AUXADC_ADC4_L               (0x1090)
+#define MT6363_AUXADC_ADC11_L              (0x109e)
+#define MT6363_AUXADC_ADC38_L              (0x10c4)
+#define MT6363_AUXADC_ADC39_L              (0x10c6)
+#define MT6363_AUXADC_ADC40_L              (0x10c8)
+#define MT6363_AUXADC_ADC_CH12_L           (0x10d2)
+#define MT6363_AUXADC_ADC_CH14_L           (0x10d8)
+#define MT6363_AUXADC_ADC42_L              (0x10dc)
+#define MT6363_AUXADC_RQST0                (0x1108)
+#define MT6363_AUXADC_RQST1                (0x1109)
+#define MT6363_AUXADC_RQST3                (0x110c)
+#define MT6363_SDMADC_RQST0                (0x110e)
+#define MT6363_SDMADC_CON0                 (0x11c4)
+#define MT6363_AUXADC_IMP0                 (0x1208)
+#define MT6363_AUXADC_IMP1                 (0x1209)
+
+/* voter */
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_ADDR                 \
+	MT6363_BUCK_VS2_VOTER_CON0
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SHIFT                (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON0_SET
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON0_CLR
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_ADDR                 \
+	MT6363_BUCK_VS2_VOTER_CON1
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_MASK                 (0xF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SHIFT                (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON1_SET
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_MASK             (0xF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON1_CLR
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_MASK             (0xF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_ADDR                 \
+	MT6363_BUCK_VS2_VOTER_CFG
+#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_SHIFT                (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_ADDR                 \
+	MT6363_BUCK_VS1_VOTER_CON0
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SHIFT                (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON0_SET
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON0_CLR
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_ADDR                 \
+	MT6363_BUCK_VS1_VOTER_CON1
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_MASK                 (0xF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SHIFT                (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON1_SET
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_MASK             (0xF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON1_CLR
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_MASK             (0xF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_ADDR                 \
+	MT6363_BUCK_VS1_VOTER_CFG
+#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_SHIFT                (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_ADDR                 \
+	MT6363_BUCK_VS3_VOTER_CON0
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SHIFT                (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON0_SET
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON0_CLR
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_ADDR                 \
+	MT6363_BUCK_VS3_VOTER_CON1
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_MASK                 (0xF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SHIFT                (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON1_SET
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_MASK             (0xF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON1_CLR
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_MASK             (0xF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_ADDR                 \
+	MT6363_BUCK_VS3_VOTER_CFG
+#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_SHIFT                (0)
+
+#endif /* __MFD_MT6363_REGISTERS_H__ */
+
diff --git a/include/linux/mfd/mt6373/core.h b/include/linux/mfd/mt6373/core.h
new file mode 100644
index 000000000000..dd77d8cf29a2
--- /dev/null
+++ b/include/linux/mfd/mt6373/core.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6373_CORE_H__
+#define __MFD_MT6373_CORE_H__
+
+#define MT6373_REG_WIDTH 8
+
+enum mt6373_irq_top_status_shift {
+	MT6373_BUCK_TOP = 0,
+	MT6373_LDO_TOP,
+	MT6373_PSC_TOP,
+	MT6373_MISC_TOP,
+	MT6373_HK_TOP,
+	MT6373_SCK_TOP,
+	MT6373_BM_TOP,
+	MT6373_AUD_TOP,
+};
+
+enum mt6373_irq_numbers {
+	MT6373_IRQ_VBUCK0_OC,
+	MT6373_IRQ_VBUCK1_OC,
+	MT6373_IRQ_VBUCK2_OC,
+	MT6373_IRQ_VBUCK3_OC,
+	MT6373_IRQ_VBUCK4_OC,
+	MT6373_IRQ_VBUCK5_OC,
+	MT6373_IRQ_VBUCK6_OC,
+	MT6373_IRQ_VBUCK7_OC,
+	MT6373_IRQ_VBUCK8_OC,
+	MT6373_IRQ_VBUCK9_OC,
+	MT6373_IRQ_VAUD18_OC = 16,
+	MT6373_IRQ_VUSB_OC,
+	MT6373_IRQ_VAUX18_OC,
+	MT6373_IRQ_VRF13_AIF_OC,
+	MT6373_IRQ_VRF18_AIF_OC,
+	MT6373_IRQ_VRFIO18_AIF_OC,
+	MT6373_IRQ_VCN33_1_OC,
+	MT6373_IRQ_VCN33_2_OC,
+	MT6373_IRQ_VCN33_3_OC,
+	MT6373_IRQ_VCN18IO_OC,
+	MT6373_IRQ_VRF09_AIF_OC,
+	MT6373_IRQ_VRF12_AIF_OC,
+	MT6373_IRQ_VANT18_OC,
+	MT6373_IRQ_VSRAM_DIGRF_AIF_OC,
+	MT6373_IRQ_VMDDR_OC,
+	MT6373_IRQ_VEFUSE_OC,
+	MT6373_IRQ_VMCH_OC,
+	MT6373_IRQ_VMC_OC,
+	MT6373_IRQ_VIBR_OC,
+	MT6373_IRQ_VIO28_OC,
+	MT6373_IRQ_VFP_OC,
+	MT6373_IRQ_VTP_OC,
+	MT6373_IRQ_VSIM1_OC,
+	MT6373_IRQ_VSIM2_OC,
+	MT6373_IRQ_RCS0 = 56,
+	MT6373_IRQ_SPMI_CMD_ALERT,
+	MT6373_IRQ_BM_PROTREG = 62,
+	MT6373_IRQ_VRC_PROTREG,
+	MT6373_IRQ_BUCK_PROTREG = 64,
+	MT6373_IRQ_LDO_PROTREG,
+	MT6373_IRQ_PSC_PROTREG,
+	MT6373_IRQ_PLT_PROTREG,
+	MT6373_IRQ_HK_PROTREG,
+	MT6373_IRQ_SCK_PROTREG,
+	MT6373_IRQ_XPP_PROTREG,
+	MT6373_IRQ_TOP_PROTREG,
+	MT6373_IRQ_NR = 72,
+};
+
+#define MT6373_IRQ_BUCK_BASE MT6373_IRQ_VBUCK0_OC
+#define MT6373_IRQ_LDO_BASE MT6373_IRQ_VAUD18_OC
+#define MT6373_IRQ_MISC_BASE MT6373_IRQ_RCS0
+
+#define MT6373_IRQ_BUCK_BITS \
+	(MT6373_IRQ_VBUCK9_OC - MT6373_IRQ_BUCK_BASE + 1)
+#define MT6373_IRQ_LDO_BITS \
+	(MT6373_IRQ_VSIM2_OC - MT6373_IRQ_LDO_BASE + 1)
+#define MT6373_IRQ_MISC_BITS \
+	(MT6373_IRQ_TOP_PROTREG - MT6373_IRQ_MISC_BASE + 1)
+
+#define MT6373_TOP_GEN(sp) \
+{ \
+	.hwirq_base = MT6373_IRQ_##sp##_BASE, \
+	.num_int_regs =	((MT6373_IRQ_##sp##_BITS - 1) / MT6373_REG_WIDTH) + 1, \
+	.en_reg = MT6373_##sp##_TOP_INT_CON0, \
+	.en_reg_shift = 0x3, \
+	.sta_reg = MT6373_##sp##_TOP_INT_STATUS0, \
+	.sta_reg_shift = 0x1, \
+	.top_offset = MT6373_##sp##_TOP, \
+}
+
+#endif /* __MFD_MT6373_CORE_H__ */
diff --git a/include/linux/mfd/mt6373/registers.h b/include/linux/mfd/mt6373/registers.h
new file mode 100644
index 000000000000..05aef78abfdf
--- /dev/null
+++ b/include/linux/mfd/mt6373/registers.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+
+#ifndef __MFD_MT6373_REGISTERS_H__
+#define __MFD_MT6373_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6373_TOPSTATUS                       0x1e
+#define MT6373_MISC_TOP_INT_CON0               0x3c
+#define MT6373_MISC_TOP_INT_CON1               0x3f
+#define MT6373_MISC_TOP_INT_STATUS0            0x48
+#define MT6373_MISC_TOP_INT_STATUS1            0x49
+#define MT6373_TOP_INT_MASK_CON0               0x4c
+#define MT6373_TOP_INT_MASK_CON0_SET           0x4d
+#define MT6373_TOP_INT_MASK_CON0_CLR           0x4e
+#define MT6373_TOP_INT_MASK_CON1               0x4f
+#define MT6373_TOP_INT_MASK_CON1_SET           0x50
+#define MT6373_TOP_INT_MASK_CON1_CLR           0x51
+#define MT6373_TOP_INT_STATUS0                 0x52
+#define MT6373_TOP_INT_STATUS1                 0x53
+#define MT6373_HK_TOP_INT_CON0                 0xf92
+#define MT6373_HK_TOP_INT_CON1                 0xf95
+#define MT6373_HK_TOP_INT_STATUS0              0xf9e
+#define MT6373_HK_TOP_INT_STATUS1              0xf9f
+#define MT6373_AUXADC_ADC4_L                   0x1090
+#define MT6373_AUXADC_ADC38_L                  0x10c4
+#define MT6373_AUXADC_ADC39_L                  0x10c6
+#define MT6373_AUXADC_ADC40_L                  0x10c8
+#define MT6373_AUXADC_ADC_CH12_L               0x10d2
+#define MT6373_AUXADC_ADC_CH12_H               0x10d3
+#define MT6373_AUXADC_RQST0                    0x1108
+#define MT6373_AUXADC_RQST1                    0x1109
+#define MT6373_AUXADC_RQST3                    0x110c
+#define MT6373_SDMADC_RQST0                    0x110e
+#define MT6373_SDMADC_CON0                     0x11c4
+#define MT6373_BUCK_TOP_INT_CON0               0x1411
+#define MT6373_BUCK_TOP_INT_CON1               0x1414
+#define MT6373_BUCK_TOP_INT_STATUS0            0x141d
+#define MT6373_BUCK_TOP_INT_STATUS1            0x141e
+#define MT6373_LDO_TOP_INT_CON0                0x1b10
+#define MT6373_LDO_TOP_INT_CON1                0x1b13
+#define MT6373_LDO_TOP_INT_CON2                0x1b16
+#define MT6373_LDO_TOP_INT_STATUS0             0x1b22
+#define MT6373_LDO_TOP_INT_STATUS1             0x1b23
+#define MT6373_LDO_TOP_INT_STATUS2             0x1b24
+#define MT6373_LDO_VMCH_CON0                   0x1cb1
+#define MT6373_LDO_VMCH_CON1                   0x1cb2
+#define MT6373_LDO_VMCH_CON2                   0x1cb3
+
+#endif /* __MFD_MT6373_REGISTERS_H__ */
-- 
2.46.0


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

* [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
                   ` (2 preceding siblings ...)
  2025-03-14  7:32 ` [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver Lu.Tang
@ 2025-03-14  7:32 ` Lu.Tang
  2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
  2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Lu.Tang @ 2025-03-14  7:32 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group, Lu.Tang

From: "Lu.Tang" <lu.tang@mediatek.com>

Modify spmi driver for mt8196 pmic.
Add pmif_s/pmif_m controller and rcs irq handler.

Signed-off-by: Lu.Tang <lu.tang@mediatek.com>
---
 drivers/spmi/spmi-mtk-pmif.c | 1040 +++++++++++++++++++++++++++++++---
 1 file changed, 976 insertions(+), 64 deletions(-)

diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c
index 160d36f7d238..36f7ef80e7c4 100644
--- a/drivers/spmi/spmi-mtk-pmif.c
+++ b/drivers/spmi/spmi-mtk-pmif.c
@@ -1,14 +1,20 @@
 // SPDX-License-Identifier: GPL-2.0
 //
-// Copyright (c) 2021 MediaTek Inc.
+// Copyright (c) 2024 MediaTek Inc.
 
 #include <linux/clk.h>
 #include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/sched/clock.h>
+#include <linux/sched/mm.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/spmi.h>
+#include <linux/irq.h>
 
 #define SWINF_IDLE	0x00
 #define SWINF_WFVLDCLR	0x06
@@ -21,14 +27,21 @@
 #define PMIF_CMD_EXT_REG_LONG	3
 
 #define PMIF_DELAY_US   10
-#define PMIF_TIMEOUT_US (10 * 1000)
+#define PMIF_TIMEOUT_US (100 * 1000)
 
 #define PMIF_CHAN_OFFSET 0x5
 
+#define PMIF_CAPS_VER_1 1
+#define PMIF_CAPS_VER_2 2
+
 #define PMIF_MAX_CLKS	3
 
 #define SPMI_OP_ST_BUSY 1
 
+#define SPMI_SOC_CHANNEL 2
+
+#define PMIF_IRQDESC(name) { #name, pmif_##name##_irq_handler, -1}
+
 struct ch_reg {
 	u32 ch_sta;
 	u32 wdata;
@@ -41,25 +54,53 @@ struct pmif_data {
 	const u32	*regs;
 	const u32	*spmimst_regs;
 	u32	soc_chan;
+	u32 caps;
 };
 
 struct pmif {
-	void __iomem	*base;
-	void __iomem	*spmimst_base;
+	void __iomem	*pmif_base[2];
+	void __iomem	*spmimst_base[2];
 	struct ch_reg	chan;
 	struct clk_bulk_data clks[PMIF_MAX_CLKS];
 	size_t nclks;
 	const struct pmif_data *data;
-	raw_spinlock_t lock;
+	raw_spinlock_t	lock_m;
+	raw_spinlock_t	lock_p;
+	struct spmi_controller  *spmic;
+	struct wakeup_source *pmif_m_Thread_lock;
+	struct wakeup_source *pmif_p_Thread_lock;
+	struct mutex pmif_m_mutex;
+	struct mutex pmif_p_mutex;
+	int		irq;
+	int		irq_p;
+	struct irq_domain	*domain;
+	struct irq_chip		irq_chip;
+	struct irq_chip		irq_chip_p;
+	int			rcs_irq;
+	int			rcs_irq_p;
+	struct mutex		rcs_m_irqlock;
+	struct mutex		rcs_p_irqlock;
+	bool	   *rcs_enable_hwirq;
+	int spmi_nack_irq;
+	int spmi_p_nack_irq;
 };
 
 static const char * const pmif_clock_names[] = {
 	"pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux",
 };
 
+struct pmif_irq_desc {
+	const char *name;
+	irq_handler_t irq_handler;
+	int irq;
+};
+
 enum pmif_regs {
 	PMIF_INIT_DONE,
 	PMIF_INF_EN,
+	MD_AUXADC_RDATA_0_ADDR,
+	MD_AUXADC_RDATA_1_ADDR,
+	MD_AUXADC_RDATA_2_ADDR,
 	PMIF_ARB_EN,
 	PMIF_CMDISSUE_EN,
 	PMIF_TIMER_CTRL,
@@ -103,6 +144,11 @@ enum pmif_regs {
 	PMIF_SWINF_3_RDATA_31_0,
 	PMIF_SWINF_3_ACC,
 	PMIF_SWINF_3_VLD_CLR,
+	PMIF_PMIC_SWINF_0_PER,
+	PMIF_PMIC_SWINF_1_PER,
+	PMIF_ACC_VIO_INFO_0,
+	PMIF_ACC_VIO_INFO_1,
+	PMIF_ACC_VIO_INFO_2,
 };
 
 static const u32 mt6873_regs[] = {
@@ -201,6 +247,63 @@ static const u32 mt8195_regs[] = {
 	[PMIF_SWINF_3_STA] = 0x08E8,
 };
 
+static const u32 mt6xxx_regs[] = {
+	[PMIF_INIT_DONE] =			0x0000,
+	[PMIF_INF_EN] =				0x0024,
+	[MD_AUXADC_RDATA_0_ADDR] =		0x0080,
+	[MD_AUXADC_RDATA_1_ADDR] =		0x0084,
+	[MD_AUXADC_RDATA_2_ADDR] =		0x0088,
+	[PMIF_ARB_EN] =				0x0150,
+	[PMIF_CMDISSUE_EN] =			0x03B8,
+	[PMIF_TIMER_CTRL] =			0x03E4,
+	[PMIF_SPI_MODE_CTRL] =			0x0408,
+	[PMIF_IRQ_EVENT_EN_0] =			0x0420,
+	[PMIF_IRQ_FLAG_0] =			0x0428,
+	[PMIF_IRQ_CLR_0] =			0x042C,
+	[PMIF_IRQ_EVENT_EN_1] =			0x0430,
+	[PMIF_IRQ_FLAG_1] =			0x0438,
+	[PMIF_IRQ_CLR_1] =			0x043C,
+	[PMIF_IRQ_EVENT_EN_2] =			0x0440,
+	[PMIF_IRQ_FLAG_2] =			0x0448,
+	[PMIF_IRQ_CLR_2] =			0x044C,
+	[PMIF_IRQ_EVENT_EN_3] =			0x0450,
+	[PMIF_IRQ_FLAG_3] =			0x0458,
+	[PMIF_IRQ_CLR_3] =			0x045C,
+	[PMIF_IRQ_EVENT_EN_4] =			0x0460,
+	[PMIF_IRQ_FLAG_4] =			0x0468,
+	[PMIF_IRQ_CLR_4] =			0x046C,
+	[PMIF_WDT_EVENT_EN_0] =			0x0474,
+	[PMIF_WDT_FLAG_0] =			0x0478,
+	[PMIF_WDT_EVENT_EN_1] =			0x047C,
+	[PMIF_WDT_FLAG_1] =			0x0480,
+	[PMIF_SWINF_0_ACC] =			0x0800,
+	[PMIF_SWINF_0_WDATA_31_0] =		0x0804,
+	[PMIF_SWINF_0_RDATA_31_0] =		0x0814,
+	[PMIF_SWINF_0_VLD_CLR] =		0x0824,
+	[PMIF_SWINF_0_STA] =			0x0828,
+	[PMIF_SWINF_1_ACC] =			0x0840,
+	[PMIF_SWINF_1_WDATA_31_0] =		0x0844,
+	[PMIF_SWINF_1_RDATA_31_0] =		0x0854,
+	[PMIF_SWINF_1_VLD_CLR] =		0x0864,
+	[PMIF_SWINF_1_STA] =			0x0868,
+	[PMIF_SWINF_2_ACC] =			0x0880,
+	[PMIF_SWINF_2_WDATA_31_0] =		0x0884,
+	[PMIF_SWINF_2_RDATA_31_0] =		0x0894,
+	[PMIF_SWINF_2_VLD_CLR] =		0x08A4,
+	[PMIF_SWINF_2_STA] =			0x08A8,
+	[PMIF_SWINF_3_ACC] =			0x08C0,
+	[PMIF_SWINF_3_WDATA_31_0] =		0x08C4,
+	[PMIF_SWINF_3_RDATA_31_0] =		0x08D4,
+	[PMIF_SWINF_3_VLD_CLR] =		0x08E4,
+	[PMIF_SWINF_3_STA] =			0x08E8,
+	[PMIF_PMIC_SWINF_0_PER] =		0x093C,
+	[PMIF_PMIC_SWINF_1_PER] =		0x0940,
+	[PMIF_ACC_VIO_INFO_0] =			0x0980,
+	[PMIF_ACC_VIO_INFO_1] =			0x0984,
+	[PMIF_ACC_VIO_INFO_2] =			0x0988,
+
+};
+
 enum spmi_regs {
 	SPMI_OP_ST_CTRL,
 	SPMI_GRP_ID_EN,
@@ -262,26 +365,132 @@ static const u32 mt8195_spmi_regs[] = {
 	[SPMI_MST_DBG] = 0x00FC,
 };
 
-static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)
+static const u32 mt6853_spmi_regs[] = {
+	[SPMI_OP_ST_CTRL] =	0x0000,
+	[SPMI_GRP_ID_EN] =	0x0004,
+	[SPMI_OP_ST_STA] =	0x0008,
+	[SPMI_MST_SAMPL] =	0x000C,
+	[SPMI_MST_REQ_EN] =	0x0010,
+	[SPMI_MST_RCS_CTRL] =	0x0014,
+	[SPMI_SLV_3_0_EINT] =	0x0020,
+	[SPMI_SLV_7_4_EINT] =	0x0024,
+	[SPMI_SLV_B_8_EINT] =	0x0028,
+	[SPMI_SLV_F_C_EINT] =	0x002C,
+	[SPMI_REC_CTRL] =	0x0040,
+	[SPMI_REC0] =		0x0044,
+	[SPMI_REC1] =		0x0048,
+	[SPMI_REC2] =		0x004C,
+	[SPMI_REC3] =		0x0050,
+	[SPMI_REC4] =		0x0054,
+	[SPMI_REC_CMD_DEC] =	0x005C,
+	[SPMI_DEC_DBG] =	0x00F8,
+	[SPMI_MST_DBG] =	0x00FC,
+};
+
+enum {
+	IRQ_LAT_LIMIT_REACHED = 6,
+	IRQ_HW_MONITOR = 7,
+	IRQ_WDT = 8,
+	/* MT6833/MT6877 series */
+	IRQ_HW_MONITOR_V3 = 12,
+	IRQ_WDT_V3 = 13,
+	IRQ_ALL_PMIC_MPU_VIO_V3 = 14,
+	/* MT6885/MT6873 series */
+	IRQ_PMIC_CMD_ERR_PARITY_ERR = 17,
+	IRQ_PMIF_ACC_VIO = 20,
+	IRQ_PMIC_ACC_VIO = 21,
+	/* MT6985/MT6897 */
+	IRQ_PMIF_ACC_VIO_V3 = 27,
+	/* MT6853 series */
+	IRQ_PMIF_ACC_VIO_V2 = 31,
+};
+
+enum {
+	IRQ_PMIC_ACC_VIO_V2 = 0,
+	IRQ_PMIF_SWINF_ACC_ERR_0 = 3,
+	IRQ_PMIF_SWINF_ACC_ERR_1 = 4,
+	IRQ_PMIF_SWINF_ACC_ERR_2 = 5,
+	IRQ_PMIF_SWINF_ACC_ERR_3 = 6,
+	IRQ_PMIF_SWINF_ACC_ERR_4 = 7,
+	IRQ_PMIF_SWINF_ACC_ERR_5 = 8,
+	IRQ_HW_MONITOR_V2 = 18,
+	IRQ_WDT_V2 = 19,
+	IRQ_ALL_PMIC_MPU_VIO_V2 = 20,
+	IRQ_PMIF_SWINF_ACC_ERR_0_V2 = 23,
+	IRQ_PMIF_SWINF_ACC_ERR_1_V2 = 24,
+	IRQ_PMIF_SWINF_ACC_ERR_2_V2 = 25,
+	IRQ_PMIF_SWINF_ACC_ERR_3_V2 = 26,
+	IRQ_PMIF_SWINF_ACC_ERR_4_V2 = 27,
+	IRQ_PMIF_SWINF_ACC_ERR_5_V2 = 28,
+	/* MT6983/MT6879 */
+	IRQ_HW_MONITOR_V4 = 29,
+	IRQ_WDT_V4 = 30,
+	IRQ_ALL_PMIC_MPU_VIO_V4 = 31,
+};
+
+struct spmi_dev {
+	int exist;
+	int slvid;
+	unsigned int path;
+	unsigned short hwcid_addr;
+	unsigned char hwcid_val;
+};
+
+static struct spmi_dev spmidev[16];
+
+static void spmi_dev_parse(struct platform_device *pdev)
 {
-	return readl(arb->base + arb->data->regs[reg]);
+	int i = 0, j = 0, ret = 0;
+	u32 spmi_dev_mask = 0;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "spmi-dev-mask",
+				  &spmi_dev_mask);
+	if (ret)
+		dev_info(&pdev->dev, "No spmi-dev-mask found in dts, default all PMIC on SPMI-M\n");
+
+	j = spmi_dev_mask;
+	for (i = 0; i < 16; i++) {
+		if (j & BIT(i))
+			spmidev[i].path = 1; /* slvid i is in path p */
+		else
+			spmidev[i].path = 0;
+	}
+}
+
+unsigned long long get_current_time_ms(void)
+{
+	unsigned long long cur_ts;
+
+	cur_ts = sched_clock();
+	do_div(cur_ts, 1000000);
+	return cur_ts;
 }
 
-static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)
+static u32 pmif_readl(void __iomem *addr, struct pmif *arb, enum pmif_regs reg)
 {
-	writel(val, arb->base + arb->data->regs[reg]);
+	return readl(addr + arb->data->regs[reg]);
 }
 
-static void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg)
+static void pmif_writel(void __iomem *addr, struct pmif *arb, u32 val, enum pmif_regs reg)
 {
-	writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]);
+	writel(val, addr + arb->data->regs[reg]);
 }
 
-static bool pmif_is_fsm_vldclr(struct pmif *arb)
+static void mtk_spmi_writel(void __iomem *addr, struct pmif *arb, u32 val, enum spmi_regs reg)
+{
+	writel(val, addr + arb->data->spmimst_regs[reg]);
+}
+
+static u32 mtk_spmi_readl(void __iomem *addr, struct pmif *arb, enum spmi_regs reg)
+{
+	return readl(addr + arb->data->spmimst_regs[reg]);
+}
+
+static bool pmif_is_fsm_vldclr(void __iomem *addr, struct pmif *arb)
 {
 	u32 reg_rdata;
 
-	reg_rdata = pmif_readl(arb, arb->chan.ch_sta);
+	reg_rdata = pmif_readl(addr, arb, arb->chan.ch_sta);
 
 	return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR;
 }
@@ -298,8 +507,8 @@ static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 
 	cmd = opc - SPMI_CMD_RESET;
 
-	mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
-	ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA],
+	mtk_spmi_writel(arb->spmimst_base[spmidev[sid].path], arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
+	ret = readl_poll_timeout_atomic(arb->spmimst_base[spmidev[sid].path] + arb->data->spmimst_regs[SPMI_OP_ST_STA],
 					rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0)
@@ -315,7 +524,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	struct ch_reg *inf_reg;
 	int ret;
 	u32 data, cmd;
-	unsigned long flags;
+	unsigned long flags_m;
 
 	/* Check for argument validation. */
 	if (sid & ~0xf) {
@@ -336,31 +545,31 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	raw_spin_lock_irqsave(&arb->lock, flags);
+	raw_spin_lock_irqsave(&arb->lock_m, flags_m);
 	/* Wait for Software Interface FSM state to be IDLE. */
 	inf_reg = &arb->chan;
-	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
+	ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + arb->data->regs[inf_reg->ch_sta],
 					data, GET_SWINF(data) == SWINF_IDLE,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0) {
 		/* set channel ready if the data has transferred */
-		if (pmif_is_fsm_vldclr(arb))
-			pmif_writel(arb, 1, inf_reg->ch_rdy);
-		raw_spin_unlock_irqrestore(&arb->lock, flags);
+		if (pmif_is_fsm_vldclr(arb->pmif_base[spmidev[sid].path], arb))
+			pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy);
+		raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
 		return ret;
 	}
 
 	/* Send the command. */
 	cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
-	pmif_writel(arb, cmd, inf_reg->ch_send);
-	raw_spin_unlock_irqrestore(&arb->lock, flags);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, cmd, inf_reg->ch_send);
+	raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 
 	/*
 	 * Wait for Software Interface FSM state to be WFVLDCLR,
 	 * read the data and clear the valid flag.
 	 */
-	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
+	ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path]  + arb->data->regs[inf_reg->ch_sta],
 					data, GET_SWINF(data) == SWINF_WFVLDCLR,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0) {
@@ -368,9 +577,9 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 		return ret;
 	}
 
-	data = pmif_readl(arb, inf_reg->rdata);
+	data = pmif_readl(arb->pmif_base[spmidev[sid].path], arb, inf_reg->rdata);
 	memcpy(buf, &data, len);
-	pmif_writel(arb, 1, inf_reg->ch_rdy);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy);
 
 	return 0;
 }
@@ -382,7 +591,7 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	struct ch_reg *inf_reg;
 	int ret;
 	u32 data, wdata, cmd;
-	unsigned long flags;
+	unsigned long flags_m;
 
 	/* Check for argument validation. */
 	if (unlikely(sid & ~0xf)) {
@@ -409,27 +618,27 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	/* Set the write data. */
 	memcpy(&wdata, buf, len);
 
-	raw_spin_lock_irqsave(&arb->lock, flags);
+	raw_spin_lock_irqsave(&arb->lock_m, flags_m);
 	/* Wait for Software Interface FSM state to be IDLE. */
 	inf_reg = &arb->chan;
-	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
+	ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + arb->data->regs[inf_reg->ch_sta],
 					data, GET_SWINF(data) == SWINF_IDLE,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0) {
 		/* set channel ready if the data has transferred */
-		if (pmif_is_fsm_vldclr(arb))
-			pmif_writel(arb, 1, inf_reg->ch_rdy);
-		raw_spin_unlock_irqrestore(&arb->lock, flags);
+		if (pmif_is_fsm_vldclr(arb->pmif_base[spmidev[sid].path], arb))
+			pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy);
+		raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
 		return ret;
 	}
 
-	pmif_writel(arb, wdata, inf_reg->wdata);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, wdata, inf_reg->wdata);
 
 	/* Send the command. */
 	cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;
-	pmif_writel(arb, cmd, inf_reg->ch_send);
-	raw_spin_unlock_irqrestore(&arb->lock, flags);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, cmd, inf_reg->ch_send);
+	raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 
 	return 0;
 }
@@ -437,15 +646,642 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 static const struct pmif_data mt6873_pmif_arb = {
 	.regs = mt6873_regs,
 	.spmimst_regs = mt6873_spmi_regs,
-	.soc_chan = 2,
+	.soc_chan = SPMI_SOC_CHANNEL,
+	.caps = PMIF_CAPS_VER_1,
 };
 
 static const struct pmif_data mt8195_pmif_arb = {
 	.regs = mt8195_regs,
 	.spmimst_regs = mt8195_spmi_regs,
-	.soc_chan = 2,
+	.soc_chan = SPMI_SOC_CHANNEL,
+	.caps = PMIF_CAPS_VER_1,
 };
+static const struct pmif_data mt6xxx_pmif_arb = {
+	.regs = mt6xxx_regs,
+	.spmimst_regs = mt6853_spmi_regs,
+	.soc_chan = SPMI_SOC_CHANNEL,
+	.caps = PMIF_CAPS_VER_2,
+};
+static void mtk_spmi_readl_datas(struct pmif *arb, int id, unsigned int *spmi_nack,
+		unsigned int *spmi_nack_data, unsigned int *spmi_rcs_nack,
+		unsigned int *spmi_debug_nack, unsigned int *spmi_mst_nack)
+{
+	if (id < 0 || id >= PMIF_CAPS_VER_2) {
+		dev_err(&arb->spmic->dev, "%s Invalid id: %d\n", __func__, id);
+		return;
+	}
+	*spmi_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC0);
+	*spmi_nack_data = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC1);
+	*spmi_rcs_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC_CMD_DEC);
+	*spmi_debug_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_DEC_DBG);
+	*spmi_mst_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_MST_DBG);
+}
+static irqreturn_t spmi_nack_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int sid = 0;
+	unsigned int spmi_nack = 0, spmi_p_nack = 0, spmi_nack_data = 0, spmi_p_nack_data = 0;
+	unsigned int spmi_rcs_nack = 0, spmi_debug_nack = 0, spmi_mst_nack = 0,
+		spmi_p_rcs_nack = 0, spmi_p_debug_nack = 0, spmi_p_mst_nack = 0;
+	u8 rdata = 0, rdata1 = 0;
+	unsigned short mt6316INTSTA = 0x240, hwcidaddr_mt6316 = 0x209, VIO18_SWITCH_6363 = 0x53,
+		hwcidaddr_mt6363 = 0x9;
+
+	mutex_lock(&arb->pmif_m_mutex);
+
+	mtk_spmi_readl_datas(arb, 0, &spmi_nack, &spmi_nack_data, &spmi_rcs_nack,
+		&spmi_debug_nack, &spmi_mst_nack);
+	if (!IS_ERR(arb->spmimst_base[1])) {
+		mtk_spmi_readl_datas(arb, 1, &spmi_p_nack, &spmi_p_nack_data, &spmi_p_rcs_nack,
+			&spmi_p_debug_nack, &spmi_p_mst_nack);
+	}
+	if ((spmi_nack & 0xD8) || (spmi_p_nack & 0xD8)) {
+		if (spmi_p_nack & 0xD8) {
+			for (sid = 0x8; sid >= 0x6; sid--) {
+				arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, sid,
+					mt6316INTSTA, &rdata, 1);
+				arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, sid,
+					hwcidaddr_mt6316, &rdata1, 1);
+				dev_notice(&arb->spmic->dev, "%s slvid 0x%x INT_RAW_STA 0x%x cid 0x%x\n",
+					__func__, sid, rdata, rdata1);
+			}
+		}
+		dev_notice(&arb->spmic->dev, "%s spmi transaction fail irq triggered", __func__);
+		dev_notice(&arb->spmic->dev, "SPMI_REC0 m/p:0x%x/0x%x SPMI_REC1 m/p 0x%x/0x%x\n",
+			spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data);
+	}
+	if ((spmi_rcs_nack & 0xC0000) || (spmi_p_rcs_nack & 0xC0000)) {
+		dev_notice(&arb->spmic->dev, "%s spmi_rcs transaction fail irq triggered SPMI_REC_CMD_DEC m/p:0x%x/0x%x\n",
+			__func__, spmi_rcs_nack, spmi_p_rcs_nack);
+	}
+	if ((spmi_debug_nack & 0xF0000) || (spmi_p_debug_nack & 0xF0000)) {
+		dev_notice(&arb->spmic->dev, "%s spmi_debug_nack transaction fail irq triggered SPMI_DEC_DBG m/p: 0x%x/0x%x\n",
+			__func__, spmi_debug_nack, spmi_p_debug_nack);
+	}
+	if ((spmi_mst_nack & 0xC0000) || (spmi_p_mst_nack & 0xC0000)) {
+		dev_notice(&arb->spmic->dev, "%s spmi_mst_nack transaction fail irq triggered SPMI_MST_DBG m/p: 0x%x/0x%x\n",
+		__func__, spmi_mst_nack, spmi_p_mst_nack);
+	}
 
+	if ((spmi_nack & 0x20) || (spmi_p_nack & 0x20)) {
+		dev_notice(&arb->spmic->dev, "%s spmi transaction fail (Read) irq triggered", __func__);
+		dev_notice(&arb->spmic->dev, "SPMI_REC0 m/p:0x%x/0x%x SPMI_REC1 m/p 0x%x/0x%x\n",
+			spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data);
+	}
+
+	if ((spmi_nack & 0xF8) || (spmi_rcs_nack & 0xC0000) ||
+		(spmi_debug_nack & 0xF0000) || (spmi_mst_nack & 0xC0000)) {
+		mtk_spmi_writel(arb->spmimst_base[0], arb, 0x3, SPMI_REC_CTRL);
+	} else if ((spmi_p_nack & 0xF8) || (spmi_p_rcs_nack & 0xC0000) ||
+		(spmi_p_debug_nack & 0xF0000) || (spmi_p_mst_nack & 0xC0000)) {
+		if (spmi_p_nack & 0xD8) {
+			dev_notice(&arb->spmic->dev, "%s SPMI_REC0 m/p:0x%x/0x%x, SPMI_REC1 m/p:0x%x/0x%x\n",
+				__func__, spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data);
+			dev_notice(&arb->spmic->dev, "%s SPMI_REC_CMD_DEC m/p:0x%x/0x%x\n", __func__,
+				spmi_rcs_nack, spmi_p_rcs_nack);
+			dev_notice(&arb->spmic->dev, "%s SPMI_DEC_DBG m/p:0x%x/0x%x\n", __func__,
+				spmi_debug_nack, spmi_p_debug_nack);
+			dev_notice(&arb->spmic->dev, "%s SPMI_MST_DBG m/p:0x%x/0x%x\n", __func__,
+				spmi_mst_nack, spmi_p_mst_nack);
+			arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, 0x4,
+				hwcidaddr_mt6363, &rdata, 1);
+			arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, 0x4,
+				VIO18_SWITCH_6363, &rdata1, 1);
+			dev_notice(&arb->spmic->dev, "%s 6363 CID/VIO18_SWITCH 0x%x/0x%x\n", __func__, rdata, rdata1);
+		}
+		mtk_spmi_writel(arb->spmimst_base[1], arb, 0x3, SPMI_REC_CTRL);
+	} else
+		dev_notice(&arb->spmic->dev, "%s IRQ not cleared\n", __func__);
+
+	mutex_unlock(&arb->pmif_m_mutex);
+
+	return IRQ_HANDLED;
+}
+static int spmi_nack_irq_register(struct platform_device *pdev,
+		struct pmif *arb, int irq)
+{
+	int ret = 0;
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				spmi_nack_irq_handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_SHARED,
+				"spmi_nack_irq", arb);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "request %s irq fail\n",
+			"spmi_nack_irq");
+	}
+	return ret;
+}
+static void rcs_irq_lock(struct irq_data *data)
+{
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	mutex_lock(&arb->rcs_m_irqlock);
+}
+static void rcs_irq_sync_unlock(struct irq_data *data)
+{
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	mutex_unlock(&arb->rcs_m_irqlock);
+}
+static void rcs_irq_enable(struct irq_data *data)
+{
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	arb->rcs_enable_hwirq[hwirq] = true;
+}
+static void rcs_irq_disable(struct irq_data *data)
+{
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	arb->rcs_enable_hwirq[hwirq] = false;
+}
+static int rcs_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	return irq_set_irq_wake(arb->rcs_irq, on);
+}
+static int rcs_irq_p_set_wake(struct irq_data *data, unsigned int on)
+{
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	return irq_set_irq_wake(arb->rcs_irq_p, on);
+}
+static const struct irq_chip rcs_irq_chip = {
+	.name			= "rcs_irq",
+	.irq_bus_lock		= rcs_irq_lock,
+	.irq_bus_sync_unlock	= rcs_irq_sync_unlock,
+	.irq_enable		= rcs_irq_enable,
+	.irq_disable		= rcs_irq_disable,
+	.irq_set_wake 		= rcs_irq_set_wake,
+};
+
+static const struct irq_chip rcs_irq_chip_p = {
+	.name			= "rcs_irq_p",
+	.irq_bus_lock		= rcs_irq_lock,
+	.irq_bus_sync_unlock	= rcs_irq_sync_unlock,
+	.irq_enable		= rcs_irq_enable,
+	.irq_disable		= rcs_irq_disable,
+	.irq_set_wake 		= rcs_irq_p_set_wake,
+};
+static int rcs_irq_map(struct irq_domain *d, unsigned int virq,
+			irq_hw_number_t hw)
+{
+	struct pmif *arb = d->host_data;
+	irq_set_chip_data(virq, arb);
+	irq_set_chip(virq, &arb->irq_chip);
+	irq_set_nested_thread(virq, 1);
+	irq_set_parent(virq, arb->rcs_irq);
+	irq_set_noprobe(virq);
+	return 0;
+}
+static const struct irq_domain_ops rcs_irq_domain_ops = {
+	.map	= rcs_irq_map,
+	.xlate	= irq_domain_xlate_onetwocell,
+};
+static void pmif_lat_limit_reached_irq_handler(int irq, void *data)
+{
+}
+static void pmif_acc_vio_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF ACC violation debug info\n");
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF-M\n");
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_0 = 0x%x\n", pmif_readl(arb->pmif_base[0],
+		arb, PMIF_ACC_VIO_INFO_0));
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_1 = 0x%x\n", pmif_readl(arb->pmif_base[0],
+		arb, PMIF_ACC_VIO_INFO_1));
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_2 = 0x%x\n", pmif_readl(arb->pmif_base[0],
+		arb, PMIF_ACC_VIO_INFO_2));
+	if (!IS_ERR(arb->pmif_base[1])) {
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF-P\n");
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_0 = 0x%x\n", pmif_readl(arb->pmif_base[1],
+			arb, PMIF_ACC_VIO_INFO_0));
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_1 = 0x%x\n", pmif_readl(arb->pmif_base[1],
+			arb, PMIF_ACC_VIO_INFO_1));
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_2 = 0x%x\n", pmif_readl(arb->pmif_base[1],
+			arb, PMIF_ACC_VIO_INFO_2));
+	}
+}
+static void pmif_wdt_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	pmif_writel(arb->pmif_base[0], arb, 0x40000000, PMIF_IRQ_CLR_0);
+	if (!IS_ERR(arb->pmif_base[1]))
+		pmif_writel(arb->pmif_base[1], arb, 0x40000000, PMIF_IRQ_CLR_0);
+	dev_notice(&arb->spmic->dev, "[PMIF]:WDT IRQ HANDLER DONE\n");
+}
+static void pmif_pmif_acc_vio_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:pmif_acc_vio");
+#endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:pmif_acc_vio\n");
+}
+static void pmif_pmic_acc_vio_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:pmic_acc_vio");
+#endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:pmic_acc_vio\n");
+}
+static void pmif_cmd_err_parity_err_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:parity error");
+#endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:parity error\n");
+}
+static void pmif_hw_monitor_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:pmif_hw_monitor_match");
+#endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:pmif_hw_monitor_match\n");
+}
+static void pmif_swinf_acc_err_irq_handler(int irq, void *data, u32 val)
+{
+	struct pmif *arb = data;
+	pmif_writel(arb->pmif_base[0], arb, val, MD_AUXADC_RDATA_0_ADDR);
+	pmif_writel(arb->pmif_base[0], arb, (u32)get_current_time_ms(), MD_AUXADC_RDATA_1_ADDR);
+	if (!IS_ERR(arb->pmif_base[1])) {
+		pmif_writel(arb->pmif_base[1], arb, val, MD_AUXADC_RDATA_0_ADDR);
+		pmif_writel(arb->pmif_base[1], arb, (u32)get_current_time_ms(), MD_AUXADC_RDATA_1_ADDR);
+	}
+	dev_notice(&arb->spmic->dev, "[PMIF]:SWINF_ACC_ERR:%d\n", val);
+}
+static irqreturn_t pmif_event_0_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_0);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_0);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			case IRQ_PMIF_ACC_VIO_V3:
+				pmif_acc_vio_irq_handler(irq, data);
+			break;
+			case IRQ_WDT_V4:
+				pmif_wdt_irq_handler(irq, data);
+			break;
+			case IRQ_ALL_PMIC_MPU_VIO_V4:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+			break;
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_0);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_0);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_1_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_1);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_1);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_1);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_1);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_2_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_2);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_2);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			case IRQ_PMIC_CMD_ERR_PARITY_ERR:
+				pmif_cmd_err_parity_err_irq_handler(irq, data);
+			break;
+			case IRQ_PMIF_ACC_VIO_V2:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+			break;
+			case IRQ_PMIC_ACC_VIO:
+				pmif_pmic_acc_vio_irq_handler(irq, data);
+			break;
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_2);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_2);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_3_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_3);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_3);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			case IRQ_PMIF_SWINF_ACC_ERR_0:
+			case IRQ_PMIF_SWINF_ACC_ERR_0_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x0);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_1:
+			case IRQ_PMIF_SWINF_ACC_ERR_1_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x1);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_2:
+			case IRQ_PMIF_SWINF_ACC_ERR_2_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x2);
+				break;
+			case IRQ_LAT_LIMIT_REACHED:
+			case IRQ_PMIF_SWINF_ACC_ERR_3_V2:
+				if (arb->data->caps == 1)
+					pmif_lat_limit_reached_irq_handler(irq, data);
+				else
+					pmif_swinf_acc_err_irq_handler(irq, data, 0x3);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_4:
+			case IRQ_PMIF_SWINF_ACC_ERR_4_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x4);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_5:
+			case IRQ_PMIF_SWINF_ACC_ERR_5_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x5);
+				break;
+			case IRQ_HW_MONITOR_V2:
+			case IRQ_HW_MONITOR_V3:
+				pmif_hw_monitor_irq_handler(irq, data);
+				break;
+			case IRQ_WDT_V2:
+			case IRQ_WDT_V3:
+				pmif_wdt_irq_handler(irq, data);
+				break;
+			case IRQ_PMIC_ACC_VIO_V2:
+				pmif_pmic_acc_vio_irq_handler(irq, data);
+				break;
+			case IRQ_ALL_PMIC_MPU_VIO_V2:
+			case IRQ_ALL_PMIC_MPU_VIO_V3:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+				break;
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", __func__, idx);
+				break;
+			}
+			if (irq_f) {
+				if ((!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0))) &&
+					(!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0_V2))))
+					pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_3);
+			} else if (irq_f_p) {
+				if ((!(irq_f_p & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0))) &&
+					(!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0_V2))))
+					pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_3);
+			} else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_4_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_4);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_4);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_4);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_4);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static struct pmif_irq_desc pmif_event_irq[] = {
+	PMIF_IRQDESC(event_0),
+	PMIF_IRQDESC(event_1),
+	PMIF_IRQDESC(event_2),
+	PMIF_IRQDESC(event_3),
+	PMIF_IRQDESC(event_4),
+};
+static void pmif_irq_register(struct platform_device *pdev,
+		struct pmif *arb, int irq)
+{
+	int i = 0, ret = 0;
+	u32 irq_event_en[5] = {0};
+	for (i = 0; i < ARRAY_SIZE(pmif_event_irq); i++) {
+		if (!pmif_event_irq[i].name)
+			continue;
+		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				pmif_event_irq[i].irq_handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_SHARED,
+				pmif_event_irq[i].name, arb);
+		if (ret < 0) {
+			dev_notice(&pdev->dev, "request %s irq fail\n",
+				pmif_event_irq[i].name);
+			continue;
+		}
+		pmif_event_irq[i].irq = irq;
+	}
+	ret = of_property_read_u32_array(pdev->dev.of_node, "irq-event-en",
+		irq_event_en, ARRAY_SIZE(irq_event_en));
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[0] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_0), PMIF_IRQ_EVENT_EN_0);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[1] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_1), PMIF_IRQ_EVENT_EN_1);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[2] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_2), PMIF_IRQ_EVENT_EN_2);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[3] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_3), PMIF_IRQ_EVENT_EN_3);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[4] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_4), PMIF_IRQ_EVENT_EN_4);
+	if (!IS_ERR(arb->pmif_base[1])) {
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[0] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_0), PMIF_IRQ_EVENT_EN_0);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[1] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_1), PMIF_IRQ_EVENT_EN_1);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[2] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_2), PMIF_IRQ_EVENT_EN_2);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[3] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_3), PMIF_IRQ_EVENT_EN_3);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[4] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_4), PMIF_IRQ_EVENT_EN_4);
+	}
+}
+static irqreturn_t rcs_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	unsigned int slv_irq_sta, slv_irq_sta_p;
+	int i;
+
+	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
+		slv_irq_sta = mtk_spmi_readl(arb->spmimst_base[0], arb, SPMI_SLV_3_0_EINT + (i / 4));
+		slv_irq_sta = (slv_irq_sta >> ((i % 4) * 8)) & 0xFF;
+		if (!IS_ERR(arb->spmimst_base[1])) {
+			slv_irq_sta_p = mtk_spmi_readl(arb->spmimst_base[1], arb, SPMI_SLV_3_0_EINT + (i / 4));
+			slv_irq_sta_p = (slv_irq_sta_p >> ((i % 4) * 8)) & 0xFF;
+		}
+		if (slv_irq_sta) {
+			mtk_spmi_writel(arb->spmimst_base[0], arb, (0xFF << ((i % 4) * 8)),
+					SPMI_SLV_3_0_EINT + (i / 4));
+			if (arb->rcs_enable_hwirq[i] && slv_irq_sta) {
+				dev_info(&arb->spmic->dev,
+					"hwirq=%d, sta=0x%x\n", i, slv_irq_sta);
+				handle_nested_irq(irq_find_mapping(arb->domain, i));
+			}
+		} else {
+			if (!IS_ERR(arb->spmimst_base[1])) {
+				mtk_spmi_writel(arb->spmimst_base[1], arb, (0xFF << ((i % 4) * 8)),
+					SPMI_SLV_3_0_EINT + (i / 4));
+				if (arb->rcs_enable_hwirq[i] && slv_irq_sta_p) {
+					dev_info(&arb->spmic->dev,
+						"hwirq=%d, sta=0x%x\n", i, slv_irq_sta_p);
+					handle_nested_irq(irq_find_mapping(arb->domain, i));
+				}
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+static int rcs_irq_register(struct platform_device *pdev,
+			    struct pmif *arb, int irq)
+{
+	int i, ret = 0;
+	mutex_init(&arb->rcs_m_irqlock);
+	mutex_init(&arb->rcs_p_irqlock);
+	arb->rcs_enable_hwirq = devm_kcalloc(&pdev->dev, SPMI_MAX_SLAVE_ID,
+					     sizeof(*arb->rcs_enable_hwirq),
+					     GFP_KERNEL);
+	if (!arb->rcs_enable_hwirq)
+		return -ENOMEM;
+	if (arb->rcs_irq == irq)
+		arb->irq_chip = rcs_irq_chip;
+	else if (arb->rcs_irq_p == irq)
+		arb->irq_chip_p = rcs_irq_chip_p;
+	else
+		dev_notice(&pdev->dev, "no rcs irq %d registered\n", irq);
+	arb->domain = irq_domain_add_linear(pdev->dev.of_node,
+					    SPMI_MAX_SLAVE_ID,
+					    &rcs_irq_domain_ops, arb);
+	if (!arb->domain) {
+		dev_notice(&pdev->dev, "Failed to create IRQ domain\n");
+		return -ENODEV;
+	}
+	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
+		mtk_spmi_writel(arb->spmimst_base[0], arb, (0xFF << ((i % 4) * 8)),
+				SPMI_SLV_3_0_EINT + (i / 4));
+		if (!IS_ERR(arb->spmimst_base[1])) {
+			mtk_spmi_writel(arb->spmimst_base[1], arb, (0xFF << ((i % 4) * 8)),
+				SPMI_SLV_3_0_EINT + (i / 4));
+		}
+	}
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					rcs_irq_handler, IRQF_ONESHOT,
+					rcs_irq_chip.name, arb);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "Failed to request IRQ=%d, ret = %d\n",
+			   irq, ret);
+		return ret;
+	}
+	enable_irq_wake(irq);
+	return ret;
+}
 static int mtk_spmi_probe(struct platform_device *pdev)
 {
 	struct pmif *arb;
@@ -457,41 +1293,50 @@ static int mtk_spmi_probe(struct platform_device *pdev)
 	if (IS_ERR(ctrl))
 		return PTR_ERR(ctrl);
 
+	ctrl->cmd = pmif_arb_cmd;
+	ctrl->read_cmd = pmif_spmi_read_cmd;
+	ctrl->write_cmd = pmif_spmi_write_cmd;
 	arb = spmi_controller_get_drvdata(ctrl);
+	arb->spmic = ctrl;
 	arb->data = device_get_match_data(&pdev->dev);
 	if (!arb->data) {
 		dev_err(&pdev->dev, "Cannot get drv_data\n");
 		return -EINVAL;
 	}
 
-	arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");
-	if (IS_ERR(arb->base))
-		return PTR_ERR(arb->base);
-
-	arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");
-	if (IS_ERR(arb->spmimst_base))
-		return PTR_ERR(arb->spmimst_base);
-
-	arb->nclks = ARRAY_SIZE(pmif_clock_names);
-	for (i = 0; i < arb->nclks; i++)
-		arb->clks[i].id = pmif_clock_names[i];
-
-	err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
-	if (err) {
-		dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
-		return err;
-	}
-
-	err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
-	if (err) {
-		dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
-		goto err_put_clks;
+	arb->pmif_base[0] = devm_platform_ioremap_resource_byname(pdev, "pmif");
+	if (IS_ERR(arb->pmif_base[0]))
+		return PTR_ERR(arb->pmif_base[0]);
+
+	arb->spmimst_base[0] = devm_platform_ioremap_resource_byname(pdev, "spmimst");
+	if (IS_ERR(arb->spmimst_base[0]))
+		return PTR_ERR(arb->spmimst_base[0]);
+
+	arb->pmif_base[1] = devm_platform_ioremap_resource_byname(pdev, "pmif-p");
+	if (IS_ERR(arb->pmif_base[1]))
+		dev_notice(&pdev->dev, "[PMIF]:no pmif-p found\n");
+	arb->spmimst_base[1] = devm_platform_ioremap_resource_byname(pdev, "spmimst-p");
+	if (IS_ERR(arb->spmimst_base[1]))
+		dev_notice(&pdev->dev, "[PMIF]:no spmimst-p found\n");
+		if (arb->data->caps == 1) {
+
+		arb->nclks = ARRAY_SIZE(pmif_clock_names);
+		for (i = 0; i < arb->nclks; i++)
+			arb->clks[i].id = pmif_clock_names[i];
+
+		err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
+			return err;
+		}
+
+		err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
+			goto err_put_clks;
+		}
 	}
 
-	ctrl->cmd = pmif_arb_cmd;
-	ctrl->read_cmd = pmif_spmi_read_cmd;
-	ctrl->write_cmd = pmif_spmi_write_cmd;
-
 	chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan;
 	arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset;
 	arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset;
@@ -499,7 +1344,71 @@ static int mtk_spmi_probe(struct platform_device *pdev)
 	arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;
 	arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;
 
-	raw_spin_lock_init(&arb->lock);
+	raw_spin_lock_init(&arb->lock_m);
+	raw_spin_lock_init(&arb->lock_p);
+	arb->pmif_m_Thread_lock =
+		wakeup_source_register(NULL, "pmif_m wakelock");
+	arb->pmif_p_Thread_lock =
+		wakeup_source_register(NULL, "pmif_p wakelock");
+	mutex_init(&arb->pmif_m_mutex);
+	mutex_init(&arb->pmif_p_mutex);
+	if (arb->data->caps == 2) {
+		arb->irq = platform_get_irq_byname(pdev, "pmif_irq");
+		if (arb->irq < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get pmif_irq, ret = %d\n", arb->irq);
+		}
+		pmif_irq_register(pdev, arb, arb->irq);
+		arb->irq_p = platform_get_irq_byname(pdev, "pmif_p_irq");
+		if (arb->irq_p < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get pmif_p_irq, ret = %d\n", arb->irq_p);
+		}
+		pmif_irq_register(pdev, arb, arb->irq_p);
+		arb->rcs_irq = platform_get_irq_byname(pdev, "rcs_irq");
+		if (arb->rcs_irq < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get rcs_irq, ret = %d\n", arb->rcs_irq);
+		} else {
+			err = rcs_irq_register(pdev, arb, arb->rcs_irq);
+			if (err)
+				dev_notice(&pdev->dev,
+				   "Failed to register rcs_irq, ret = %d\n", arb->rcs_irq);
+		}
+		arb->rcs_irq_p = platform_get_irq_byname(pdev, "rcs_irq_p");
+		if (arb->rcs_irq_p < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get rcs_irq_p, ret = %d\n", arb->rcs_irq_p);
+		} else {
+			err = rcs_irq_register(pdev, arb, arb->rcs_irq_p);
+			if (err)
+				dev_notice(&pdev->dev,
+				   "Failed to register rcs_irq_p, ret = %d\n", arb->rcs_irq_p);
+		}
+		arb->spmi_nack_irq = platform_get_irq_byname(pdev, "spmi_nack_irq");
+		if (arb->spmi_nack_irq < 0) {
+			dev_notice(&pdev->dev,
+				"Failed to get spmi_nack_irq, ret = %d\n", arb->spmi_nack_irq);
+		} else {
+			err = spmi_nack_irq_register(pdev, arb, arb->spmi_nack_irq);
+			if (err)
+				dev_notice(&pdev->dev,
+					"Failed to register spmi_nack_irq, ret = %d\n",
+						 arb->spmi_nack_irq);
+		}
+		arb->spmi_p_nack_irq = platform_get_irq_byname(pdev, "spmi_p_nack_irq");
+		if (arb->spmi_p_nack_irq < 0) {
+			dev_notice(&pdev->dev,
+				"Failed to get spmi_p_nack_irq, ret = %d\n", arb->spmi_p_nack_irq);
+		} else {
+			err = spmi_nack_irq_register(pdev, arb, arb->spmi_p_nack_irq);
+			if (err)
+				dev_notice(&pdev->dev,
+					"Failed to register spmi_p_nack_irq, ret = %d\n",
+						 arb->spmi_p_nack_irq);
+		}
+	}
+	spmi_dev_parse(pdev);
 
 	platform_set_drvdata(pdev, ctrl);
 
@@ -533,6 +1442,9 @@ static const struct of_device_id mtk_spmi_match_table[] = {
 	}, {
 		.compatible = "mediatek,mt8195-spmi",
 		.data = &mt8195_pmif_arb,
+	}, {
+		.compatible = "mediatek,mt8196-spmi",
+		.data = &mt6xxx_pmif_arb,
 	}, {
 		/* sentinel */
 	},
-- 
2.46.0


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

* [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
                   ` (3 preceding siblings ...)
  2025-03-14  7:32 ` [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196 Lu.Tang
@ 2025-03-14  7:32 ` Lu.Tang
  2025-03-14  8:25   ` Rob Herring (Arm)
                     ` (3 more replies)
  2025-03-14  8:27 ` [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Chen-Yu Tsai
  2025-03-14  9:06 ` 回复: " Lu Tang (汤璐)
  6 siblings, 4 replies; 24+ messages in thread
From: Lu.Tang @ 2025-03-14  7:32 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group, Lu.Tang

Add new pmic mfd and adc documents for mt8196

Signed-off-by: Lu.Tang <Lu.Tang@mediatek.com>
---
 .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |  31 ++++
 .../bindings/input/mediatek,pmic-keys.yaml    |   1 +
 .../bindings/mfd/mediatek,mt6685.yaml         |  50 +++++
 .../bindings/mfd/mediatek,spmi-pmic.yaml      | 173 ++++++++++++++++++
 .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |   1 +
 5 files changed, 256 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml

diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
new file mode 100644
index 000000000000..250782ad7d01
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek SPMI PMIC AUXADC
+
+maintainers:
+  - Lu Tang <lu.tang@mediatek.com>
+
+description:
+  The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
+  in some MediaTek PMICs, performing various PMIC related measurements
+  such as battery and PMIC internal voltage regulators temperatures,
+  other than voltages for various PMIC internal components.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6363-auxadc
+      - mediatek,mt6373-auxadc
+
+  "#io-channel-cells":
+    const: 1
+
+required:
+  - compatible
+  - "#io-channel-cells"
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
index b95435bd6a9b..ce760039d4c2 100644
--- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
+++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
@@ -31,6 +31,7 @@ properties:
       - mediatek,mt6358-keys
       - mediatek,mt6359-keys
       - mediatek,mt6397-keys
+      - mediatek,mt6363-keys
 
   power-off-time-sec: true
 
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
new file mode 100644
index 000000000000..d3276df8952b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,mt6685.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6685 Clock IC
+
+maintainers:
+  - Lu Tang <lu.tang@mediatek.com>
+
+description: |
+  MT6685 is a clock IC.
+  Please see the sub-modules below for supported features.
+
+  MT6685 is a multifunction device with the following sub modules:
+  - RTC
+  - Clock
+
+properties:
+  compatible:
+    const: mediatek,mt6685
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/spmi/spmi.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    spmi {
+        mfd@9 {
+            compatible = "mediatek,mt6685";
+            reg = <0x9 SPMI_USID>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
new file mode 100644
index 000000000000..a8f1231623cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
@@ -0,0 +1,173 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek SPMI PMICs multi-function device
+
+maintainers:
+  - Lu Tang <lu.tang@mediatek.com>
+
+description: |
+  Some Mediatek PMICs are interfaced to the chip via the SPMI (System Power
+  Management Interface) bus.
+
+  The Mediatek SPMI series includes the MT6363, MT6373, MT6316 and other
+  PMICs.Please see the sub-modules below for supported features.
+
+   MT6363/MT6373 is a multifunction device with the following sub modules:
+  - Regulators
+  - ADC
+  - GPIO
+  - Keys
+   MT6316 is a multifunction device with the following sub modules:
+  - Regulators
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - mediatek,mt6363
+          - mediatek,mt6373
+          - mediatek,mt6316
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+  regulators:
+    type: object
+    description:
+      List of child nodes that specify the regulators.
+    additionalProperties: true
+
+    properties:
+      compatible:
+        oneOf:
+          - enum:
+              - mediatek,mt6363-regulator
+              - mediatek,mt6373-regulator
+              - mediatek,mt6316-regulator
+
+    required:
+      - compatible
+
+  adc:
+    type: object
+    $ref: /schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml#
+    unevaluatedProperties: false
+
+  keys:
+    type: object
+    $ref: /schemas/input/mediatek,pmic-keys.yaml
+    unevaluatedProperties: false
+    description:
+      Power and Home keys.
+
+  pinctrl:
+    type: object
+    $ref: /schemas/pinctrl/mediatek,mt65xx-pinctrl.yaml
+    unevaluatedProperties: false
+    description:
+      Pin controller
+
+required:
+  - compatible
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/spmi/spmi.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    spmi {
+        main_pmic: pmic@4 {
+            compatible = "mediatek,mt6363";
+            reg = <0x4 SPMI_USID>;
+            interrupts = <0x4 IRQ_TYPE_NONE>;
+            #address-cells = <0>;
+            interrupt-controller;
+            #interrupt-cells = <2>;
+
+            mt6363keys: keys {
+                compatible = "mediatek,mt6363-keys";
+                mediatek,long-press-mode = <1>;
+                power-off-time-sec = <0>;
+
+                power {
+                    linux,keycodes = <116>;
+                    wakeup-source;
+                };
+
+                home {
+                    linux,keycodes = <115>;
+                };
+            };
+
+            mt6363_pio: pinctrl {
+                compatible = "mediatek,mt6363-pinctrl";
+                gpio-controller;
+                #gpio-cells = <2>;
+            };
+
+            mt6363regulator: regulators {
+                compatible = "mediatek,mt6363-regulator";
+
+                mt6363_vs2: vs2 {
+                    regulator-name = "mt6363_vs2";
+                    regulator-allowed-modes = <0 1 2>;
+                    regulator-always-on;
+                    regulator-allow-set-load;
+                };
+
+                mt6363_vbuck1: vbuck1 {
+                    regulator-name = "mt6363_vbuck1";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck2: vbuck2 {
+                    regulator-name = "mt6363_vbuck2";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck3: vbuck3 {
+                    regulator-name = "mt6363_vbuck3";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck4: vbuck4 {
+                    regulator-name = "mt6363_vbuck4";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck5: vbuck5 {
+                    regulator-name = "mt6363_vbuck5";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck6: vbuck6 {
+                    regulator-name = "mt6363_vbuck6";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck7: vbuck7 {
+                    regulator-name = "mt6363_vbuck7";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                // ...
+
+                mt6363_isink_load: isink-load {
+                    regulator-name = "mt6363_isink_load";
+                };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
index bccff08a5ba3..bf3ba58a7705 100644
--- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
@@ -17,6 +17,7 @@ properties:
     enum:
       - mediatek,mt2701-pinctrl
       - mediatek,mt2712-pinctrl
+      - mediatek,mt6363-pinctrl
       - mediatek,mt6397-pinctrl
       - mediatek,mt7623-pinctrl
       - mediatek,mt8127-pinctrl
-- 
2.46.0


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

* Re: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
@ 2025-03-14  8:25   ` Rob Herring (Arm)
  2025-03-14  8:34   ` Chen-Yu Tsai
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Rob Herring (Arm) @ 2025-03-14  8:25 UTC (permalink / raw)
  To: Lu.Tang
  Cc: Krzysztof Kozlowski, Conor Dooley, Lee Jones, Mark Brown,
	Jonathan Cameron, Dmitry Torokhov, Liam Girdwood, linux-input,
	Stephen Boyd, Sean Wang, Matthias Brugger, devicetree,
	linux-kernel, AngeloGioacchino Del Regno, linux-iio,
	Linus Walleij, linux-mediatek,
	Project_Global_Chrome_Upstream_Group, linux-gpio,
	linux-arm-kernel, Chen Zhong, Lars-Peter Clausen, Sen Chu


On Fri, 14 Mar 2025 15:32:31 +0800, Lu.Tang wrote:
> Add new pmic mfd and adc documents for mt8196
> 
> Signed-off-by: Lu.Tang <Lu.Tang@mediatek.com>
> ---
>  .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |  31 ++++
>  .../bindings/input/mediatek,pmic-keys.yaml    |   1 +
>  .../bindings/mfd/mediatek,mt6685.yaml         |  50 +++++
>  .../bindings/mfd/mediatek,spmi-pmic.yaml      | 173 ++++++++++++++++++
>  .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |   1 +
>  5 files changed, 256 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
> 

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

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dts:25.17-31: Warning (reg_format): /example-0/spmi/mfd@9:reg: property has invalid length (8 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dts:23.19-28.15: Warning (avoid_default_addr_size): /example-0/spmi/mfd@9: Relying on default #address-cells value
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dts:23.19-28.15: Warning (avoid_default_addr_size): /example-0/spmi/mfd@9: Relying on default #size-cells value
Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: Warning (unique_unit_address_if_enabled): Failed prerequisite 'avoid_default_addr_size'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,mt6685.example.dtb: mfd@9: '#address-cells', '#size-cells', 'reg' do not match any of the regexes: 'pinctrl-[0-9]+'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6685.yaml#
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dts:31.17-31: Warning (reg_format): /example-0/spmi/pmic@4:reg: property has invalid length (8 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dts:29.31-109.15: Warning (avoid_default_addr_size): /example-0/spmi/pmic@4: Relying on default #address-cells value
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dts:29.31-109.15: Warning (avoid_default_addr_size): /example-0/spmi/pmic@4: Relying on default #size-cells value
Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: Warning (unique_unit_address_if_enabled): Failed prerequisite 'avoid_default_addr_size'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.example.dtb: pmic@4: '#address-cells', 'reg' do not match any of the regexes: 'pinctrl-[0-9]+'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250314073307.25092-6-Lu.Tang@mediatek.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] 24+ messages in thread

* Re: [PATCH 2/5] pmic: mediatek: Add pmic regulator driver
  2025-03-14  7:32 ` [PATCH 2/5] pmic: mediatek: Add pmic regulator driver Lu.Tang
@ 2025-03-14  8:26   ` Chen-Yu Tsai
  2025-03-14  9:02   ` 回复: " Lu Tang (汤璐)
  1 sibling, 0 replies; 24+ messages in thread
From: Chen-Yu Tsai @ 2025-03-14  8:26 UTC (permalink / raw)
  To: Lu.Tang
  Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu, linux-iio, devicetree, linux-kernel,
	linux-input, linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

On Fri, Mar 14, 2025 at 3:58 PM Lu.Tang <Lu.Tang@mediatek.com> wrote:
>
> From: "Lu.Tang" <lu.tang@mediatek.com>
>
> Add pmic mt6316/mt6373/mt6363 regulator driver

Please split this into one patch per PMIC. That will make the patch
size much more manageable. And the patch subject should just say what
PMIC is added.

> Signed-off-by: Lu Tang <lu.tang@mediatek.com>
> ---
>  drivers/regulator/Kconfig                  |   34 +
>  drivers/regulator/Makefile                 |    3 +
>  drivers/regulator/mt6316-regulator.c       |  381 +++++++

How much of the MT6316 driver is the same or similar to MT6315?
AFAICT they are both 4 buck regulators where some of the outputs
can be combined into a polyphase output.

>  drivers/regulator/mt6363-regulator.c       | 1106 ++++++++++++++++++++
>  drivers/regulator/mt6373-regulator.c       |  826 +++++++++++++++
>  include/linux/regulator/mt6316-regulator.h |   48 +
>  include/linux/regulator/mt6363-regulator.h |  424 ++++++++
>  include/linux/regulator/mt6373-regulator.h |  318 ++++++
>  8 files changed, 3140 insertions(+)
>  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/regulator/mt6316-regulator.h
>  create mode 100644 include/linux/regulator/mt6363-regulator.h
>  create mode 100644 include/linux/regulator/mt6373-regulator.h
>
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 39297f7d8177..7b2d47fee535 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -853,6 +853,16 @@ config REGULATOR_MT6315
>           This driver supports the control of different power rails of device
>           through regulator interface.
>
> +config REGULATOR_MT6316
> +       tristate "MediaTek MT6316 PMIC"
> +       depends on SPMI
> +       select REGMAP_SPMI
> +       help
> +         Say y here to select this option to enable the power regulator of
> +         MediaTek MT6316 PMIC.
> +         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
> @@ -916,6 +926,18 @@ 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 Regulator driver"
> +       depends on MFD_MTK_SPMI_PMIC
> +       help
> +         Say y here to select this option to enable the power regulator of
> +         MediaTek MT6363 PMIC.
> +         This driver supports the control of different power rails of device
> +         through regulator interface.
> +
> +         The driver can also be build as a module.
> +         If so, the module will be called mt6363_regulator
> +
>  config REGULATOR_MT6370
>         tristate "MT6370 SubPMIC Regulator"
>         depends on MFD_MT6370
> @@ -924,6 +946,18 @@ 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 Regulator driver"
> +       depends on MFD_MTK_SPMI_PMIC
> +       help
> +         Say y here to select this option to enable the power regulator of
> +         MediaTek MT6373 PMIC.
> +         This driver supports the control of different power rails of device
> +         through regulator interface.
> +
> +         The driver can also be build as a module.
> +         If so, the module will be called mt6373_regulator
> +
>  config REGULATOR_MT6380
>         tristate "MediaTek MT6380 PMIC"
>         depends on MTK_PMIC_WRAP
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 3d5a803dce8a..b54a64522499 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -102,6 +102,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_MT6316) += mt6316-regulator.o
>  obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
>  obj-$(CONFIG_REGULATOR_MT6331) += mt6331-regulator.o
>  obj-$(CONFIG_REGULATOR_MT6332) += mt6332-regulator.o
> @@ -109,7 +110,9 @@ 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_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/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c
> new file mode 100644
> index 000000000000..1c069a0d4cff
> --- /dev/null
> +++ b/drivers/regulator/mt6316-regulator.c
> @@ -0,0 +1,381 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (c) 2024 MediaTek Inc.
> +
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/mt6316-regulator.h>
> +#include <linux/regulator/of_regulator.h>
> +
> +#define SET_OFFSET     0x1
> +#define CLR_OFFSET     0x2
> +
> +#define MT6316_REG_WIDTH       8
> +
> +#define MT6316_BUCK_MODE_AUTO          0
> +#define MT6316_BUCK_MODE_FORCE_PWM     1
> +#define MT6316_BUCK_MODE_NORMAL                0
> +#define MT6316_BUCK_MODE_LP            2
> +
> +#define BUCK_PHASE_3                   3
> +#define BUCK_PHASE_4                   4
> +
> +struct mt6316_regulator_info {
> +       struct regulator_desc desc;
> +       u32 da_reg;
> +       u32 qi;
> +       u32 modeset_reg;
> +       u32 modeset_mask;
> +       u32 lp_mode_reg;
> +       u32 lp_mode_mask;
> +       u32 lp_mode_shift;
> +};
> +
> +struct mt6316_init_data {
> +       u32 id;
> +       u32 size;
> +};
> +
> +struct mt6316_chip {
> +       struct device *dev;
> +       struct regmap *regmap;
> +       u32 slave_id;
> +};
> +
> +#define MT_BUCK(match, _name, volt_ranges, _bid, _vsel)        \
> +[MT6316_ID_##_name] = {                                        \
> +       .desc = {                                       \
> +               .name = #_name,                         \
> +               .of_match = of_match_ptr(match),        \
> +               .ops = &mt6316_volt_range_ops,          \
> +               .type = REGULATOR_VOLTAGE,              \
> +               .id = MT6316_ID_##_name,                \
> +               .owner = THIS_MODULE,                   \
> +               .n_voltages = 0x1ff,                    \
> +               .linear_ranges = volt_ranges,           \
> +               .n_linear_ranges = ARRAY_SIZE(volt_ranges),\
> +               .vsel_reg = _vsel,                      \
> +               .vsel_mask = 0xff,                      \
> +               .enable_reg = MT6316_BUCK_TOP_CON0,     \
> +               .enable_mask = BIT(_bid - 1),           \
> +               .of_map_mode = mt6316_map_mode,         \
> +       },                                              \
> +       .da_reg = MT6316_VBUCK##_bid##_DBG8,            \
> +       .qi = BIT(0),                                   \
> +       .lp_mode_reg = MT6316_BUCK_TOP_CON1,            \
> +       .lp_mode_mask = BIT(_bid - 1),                  \
> +       .lp_mode_shift = _bid - 1,                      \
> +       .modeset_reg = MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0,\
> +       .modeset_mask = BIT(_bid - 1),                  \
> +}
> +
> +static const struct linear_range mt_volt_range1[] = {
> +       REGULATOR_LINEAR_RANGE(0, 0, 0x1fe, 2500),
> +};
> +
> +static int mt6316_regulator_enable(struct regulator_dev *rdev)
> +{
> +       return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
> +                           rdev->desc->enable_mask);
> +}
> +
> +static int mt6316_regulator_disable(struct regulator_dev *rdev)
> +{
> +       return regmap_write(rdev->regmap, rdev->desc->enable_reg + CLR_OFFSET,
> +                           rdev->desc->enable_mask);
> +}
> +
> +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_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
> +{
> +       unsigned short reg_val = 0;
> +       int ret = 0;
> +
> +       reg_val = ((selector & 0x1) << 8) | (selector >> 1);
> +       ret = regmap_bulk_write(rdev->regmap, rdev->desc->vsel_reg, (u8 *) &reg_val, 2);
> +
> +       return ret;
> +}
> +
> +static int mt6316_regulator_get_voltage_sel(struct regulator_dev *rdev)
> +{
> +       int ret = 0;
> +       unsigned int reg_val = 0;
> +
> +       ret = regmap_bulk_read(rdev->regmap, rdev->desc->vsel_reg, (u8 *) &reg_val, 2);
> +       if (ret != 0) {
> +               dev_err(&rdev->dev, "Failed to get mt6316 regulator voltage: %d\n", ret);
> +               return ret;
> +       }
> +       ret = ((reg_val >> 8) & 0x1) + ((reg_val & rdev->desc->vsel_mask) << 1);
> +
> +       return ret;
> +}
> +
> +static unsigned int mt6316_regulator_get_mode(struct regulator_dev *rdev)
> +{
> +       struct mt6316_regulator_info *info;
> +       int ret = 0, regval = 0;
> +       u32 modeset_mask;
> +
> +       info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
> +       ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
> +       if (ret != 0) {
> +               dev_err(&rdev->dev, "Failed to get mt6316 buck mode: %d\n", ret);
> +               return ret;
> +       }
> +
> +       modeset_mask = info->modeset_mask;
> +
> +       if ((regval & modeset_mask) == modeset_mask)
> +               return REGULATOR_MODE_FAST;
> +
> +       ret = regmap_read(rdev->regmap, info->lp_mode_reg, &regval);
> +       if (ret != 0) {
> +               dev_err(&rdev->dev, "Failed to get mt6316 buck lp mode: %d\n", ret);
> +               return ret;
> +       }
> +
> +       if (regval & info->lp_mode_mask)
> +               return REGULATOR_MODE_IDLE;
> +       else
> +               return REGULATOR_MODE_NORMAL;
> +}
> +
> +static int mt6316_regulator_set_mode(struct regulator_dev *rdev, u32 mode)
> +{
> +       struct mt6316_regulator_info *info;
> +       int ret = 0, val, curr_mode;
> +       u32 modeset_mask;
> +
> +       info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
> +       modeset_mask = info->modeset_mask;
> +
> +       curr_mode = mt6316_regulator_get_mode(rdev);
> +       switch (mode) {
> +       case REGULATOR_MODE_FAST:
> +               ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
> +                                        modeset_mask, modeset_mask);
> +               break;
> +       case REGULATOR_MODE_NORMAL:
> +               if (curr_mode == REGULATOR_MODE_FAST) {
> +                       ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
> +                                                modeset_mask, 0);
> +               } else if (curr_mode == REGULATOR_MODE_IDLE) {
> +                       ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg,
> +                                                info->lp_mode_mask, 0);
> +                       usleep_range(100, 110);
> +               }
> +               break;
> +       case REGULATOR_MODE_IDLE:
> +               val = MT6316_BUCK_MODE_LP >> 1;
> +               val <<= info->lp_mode_shift;
> +               ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, info->lp_mode_mask, val);
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               goto err_mode;
> +       }
> +
> +err_mode:
> +       if (ret != 0) {
> +               dev_err(&rdev->dev, "Failed to set mt6316 buck mode: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int mt6316_get_status(struct regulator_dev *rdev)
> +{
> +       int ret = 0;
> +       u32 regval = 0;
> +       struct mt6316_regulator_info *info;
> +
> +       info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
> +       ret = regmap_read(rdev->regmap, info->da_reg, &regval);
> +       if (ret != 0) {
> +               dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
> +}
> +
> +static void mt6316_buck_phase_init(struct mt6316_chip *chip, unsigned int *s6_buck_phase)
> +{
> +       int ret = 0;
> +       u32 val = 0;
> +
> +       ret = regmap_read(chip->regmap, MT6316_BUCK_TOP_4PHASE_TOP_ELR_0, &val);
> +       if (ret) {
> +               dev_err(chip->dev, "Failed to get mt6316 buck phase: %d\n", ret);
> +               return;
> +       }
> +
> +       dev_info(chip->dev, "S%d RG_4PH_CONFIG:%d\n", chip->slave_id, val);
> +       if (chip->slave_id == MT6316_SLAVE_ID_6)
> +               *s6_buck_phase = val;
> +}
> +
> +static const struct regulator_ops mt6316_volt_range_ops = {
> +       .list_voltage = regulator_list_voltage_linear_range,
> +       .map_voltage = regulator_map_voltage_linear_range,
> +       .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_regulator_enable,
> +       .disable = mt6316_regulator_disable,
> +       .is_enabled = regulator_is_enabled_regmap,
> +       .get_status = mt6316_get_status,
> +       .set_mode = mt6316_regulator_set_mode,
> +       .get_mode = mt6316_regulator_get_mode,
> +};
> +
> +static struct mt6316_regulator_info mt6316_regulators[] = {
> +       MT_BUCK("vbuck1", VBUCK1, mt_volt_range1, 1, MT6316_BUCK_TOP_ELR0),
> +       MT_BUCK("vbuck2", VBUCK2, mt_volt_range1, 2, MT6316_BUCK_TOP_ELR2),
> +       MT_BUCK("vbuck3", VBUCK3, mt_volt_range1, 3, MT6316_BUCK_TOP_ELR4),
> +       MT_BUCK("vbuck4", VBUCK4, mt_volt_range1, 4, MT6316_BUCK_TOP_ELR6),
> +};
> +
> +static struct mt6316_init_data mt6316_3_init_data = {
> +       .id = MT6316_SLAVE_ID_3,
> +       .size = MT6316_ID_3_MAX,
> +};
> +
> +static struct mt6316_init_data mt6316_6_init_data = {
> +       .id = MT6316_SLAVE_ID_6,
> +       .size = MT6316_ID_6_MAX,
> +};
> +
> +static struct mt6316_init_data mt6316_7_init_data = {
> +       .id = MT6316_SLAVE_ID_7,
> +       .size = MT6316_ID_7_MAX,
> +};
> +
> +static struct mt6316_init_data mt6316_8_init_data = {
> +       .id = MT6316_SLAVE_ID_8,
> +       .size = MT6316_ID_8_MAX,
> +};
> +
> +static struct mt6316_init_data mt6316_15_init_data = {
> +       .id = MT6316_SLAVE_ID_15,
> +       .size = MT6316_ID_15_MAX,
> +};
> +
> +static const struct of_device_id mt6316_of_match[] = {
> +       {
> +               .compatible = "mediatek,mt6316-3-regulator",
> +               .data = &mt6316_3_init_data,
> +       }, {
> +               .compatible = "mediatek,mt6316-6-regulator",
> +               .data = &mt6316_6_init_data,
> +       }, {
> +               .compatible = "mediatek,mt6316-7-regulator",
> +               .data = &mt6316_7_init_data,
> +       }, {
> +               .compatible = "mediatek,mt6316-8-regulator",
> +               .data = &mt6316_8_init_data,
> +       }, {
> +               .compatible = "mediatek,mt6316-15-regulator",
> +               .data = &mt6316_15_init_data,
> +       }, {
> +               /* sentinel */
> +       },
> +};
> +MODULE_DEVICE_TABLE(of, mt6316_of_match);
> +
> +static int mt6316_regulator_probe(struct platform_device *pdev)
> +{
> +       const struct of_device_id *of_id;
> +       struct device *dev = &pdev->dev;
> +       struct regmap *regmap;
> +       struct mt6316_init_data *pdata;
> +       struct mt6316_chip *chip;
> +       struct regulator_config config = {};
> +       struct regulator_dev *rdev;
> +       struct device_node *node = pdev->dev.of_node;
> +       u32 val = 0;
> +       int i;
> +       unsigned int s6_buck_phase;
> +
> +       regmap = dev_get_regmap(dev->parent, NULL);
> +       if (!regmap)
> +               return -ENODEV;
> +
> +       chip = devm_kzalloc(dev, sizeof(struct mt6316_chip), GFP_KERNEL);
> +       if (!chip)
> +               return -ENOMEM;

Replace the following block:

> +       of_id = of_match_device(mt6316_of_match, dev);
> +       if (!of_id || !of_id->data)
> +               return -ENODEV;
> +
> +       pdata = (struct mt6316_init_data *)of_id->data;

with

    pdata = of_device_get_match_data(dev);

pdata should never be NULL since the driver is probed only when an
OF match happens, and all the entries in mt6316_of_match[] have .data
set.

> +       chip->slave_id = pdata->id;

If the ID is supposed to be the SPMI ID, then there should be no
reason to tie it to the compatible string. Simply get the ID from
the device tree.

> +       if (!of_property_read_u32(node, "buck-size", &val))
> +               pdata->size = val;

As mentioned in downstream review, the chip has 4 buck regulators,
regardless of whether they are being used or not. This is not the
right way to describe unused regulators.

> +       chip->dev = dev;
> +       chip->regmap = regmap;
> +       dev_set_drvdata(dev, chip);
> +
> +       dev->fwnode = &(dev->of_node->fwnode);
> +       if (dev->fwnode && !dev->fwnode->dev)
> +               dev->fwnode->dev = dev;
> +
> +       config.dev = dev;
> +       config.driver_data = pdata;
> +       config.regmap = regmap;
> +
> +       mt6316_buck_phase_init(chip, &s6_buck_phase);
> +       for (i = 0; i < pdata->size; i++) {
> +               if (pdata->id == MT6316_SLAVE_ID_6 &&
> +                   s6_buck_phase == BUCK_PHASE_4 &&
> +                   (mt6316_regulators + i)->desc.id == MT6316_ID_VBUCK3) {
> +                       dev_info(dev, "skip registering %s.\n", (mt6316_regulators + i)->desc.name);
> +                       continue;
> +               }
> +
> +               rdev = devm_regulator_register(dev, &(mt6316_regulators + i)->desc, &config);
> +               if (IS_ERR(rdev)) {
> +                       dev_err(dev, "failed to register %s\n", (mt6316_regulators + i)->desc.name);
> +                       continue;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static struct platform_driver mt6316_regulator_driver = {

The MT6316 only has regulators. Why does it need to go through another
layer, instead of this driver being the SPMI driver?

> +       .driver         = {
> +               .name   = "mt6316-regulator",
> +               .of_match_table = mt6316_of_match,
> +       },
> +       .probe = mt6316_regulator_probe,
> +};
> +
> +module_platform_driver(mt6316_regulator_driver);
> +
> +MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
> +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6316 PMIC");
> +MODULE_LICENSE("GPL");

[...]

Skipping the other two PMICs for now.

> diff --git a/include/linux/regulator/mt6316-regulator.h b/include/linux/regulator/mt6316-regulator.h
> new file mode 100644
> index 000000000000..dd11b3d856fd
> --- /dev/null
> +++ b/include/linux/regulator/mt6316-regulator.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2024 MediaTek Inc.
> + */
> +
> +#ifndef __LINUX_REGULATOR_MT6316_H
> +#define __LINUX_REGULATOR_MT6316_H
> +
> +#define MT6316_SLAVE_ID_3      3
> +#define MT6316_SLAVE_ID_6      6
> +#define MT6316_SLAVE_ID_7      7
> +#define MT6316_SLAVE_ID_8      8
> +#define MT6316_SLAVE_ID_15     15
> +
> +#define MT6316_ID_3_MAX                3
> +#define MT6316_ID_6_MAX                3
> +#define MT6316_ID_7_MAX                3
> +#define MT6316_ID_8_MAX                3
> +#define MT6316_ID_15_MAX       2
> +
> +enum {
> +       MT6316_ID_VBUCK1 = 0,
> +       MT6316_ID_VBUCK2,
> +       MT6316_ID_VBUCK3,
> +       MT6316_ID_VBUCK4,
> +       MT6316_ID_MAX,
> +};
> +
> +/* Register */
> +#define MT6316_TOP_CFG_ELR4                    0x143
> +#define MT6316_BUCK_TOP_CON0                   0x1440
> +#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_VBUCK1_DBG4                     0x14A4
> +#define MT6316_VBUCK1_DBG8                     0x14A8
> +#define MT6316_VBUCK2_DBG4                     0x1524
> +#define MT6316_VBUCK2_DBG8                     0x1528
> +#define MT6316_VBUCK3_DBG4                     0x15A4
> +#define MT6316_VBUCK3_DBG8                     0x15A8
> +#define MT6316_VBUCK4_DBG4                     0x1624
> +#define MT6316_VBUCK4_DBG8                     0x1628
> +#define MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0     0x1688
> +#define MT6316_BUCK_TOP_4PHASE_TOP_ELR_0       0x1690
> +
> +#endif /* __LINUX_REGULATOR_MT6316_H */

AFAICT, no part of this file is used by other parts of the kernel. It
can be moved under drivers/regulator/, or even recombined with the
.c file.


Thanks
ChenYu

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

* Re: [PATCH 0/5] Add PMIC and SPMI driver for mt8196
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
                   ` (4 preceding siblings ...)
  2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
@ 2025-03-14  8:27 ` Chen-Yu Tsai
  2025-03-14  9:06 ` 回复: " Lu Tang (汤璐)
  6 siblings, 0 replies; 24+ messages in thread
From: Chen-Yu Tsai @ 2025-03-14  8:27 UTC (permalink / raw)
  To: Lu.Tang
  Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu, linux-iio, devicetree, linux-kernel,
	linux-input, linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

On Fri, Mar 14, 2025 at 3:56 PM Lu.Tang <Lu.Tang@mediatek.com> wrote:
>
> This series is based on linux-next.
>
> Changes in v0:
> - Modify SPMI driver for mt8196
> - Add SPMI PMIC mfd driver
> - Add PMIC regulator driver for mt8196
>
> *** BLURB HERE ***
>
> Lu.Tang (5):
>   pmic: mediatek: Add pmic auxadc driver
>   pmic: mediatek: Add pmic regulator driver
>   pmic: mediatek: Add spmi pmic mfd driver
>   spmi: mediatek: modify spmi dirver for mt8196
>   dt-bindings: pmic: mediatek: Add pmic documents

You are adding three PMICs at the same time. Please separate each
patch in this series so that it is one patch per type per PMIC.

ChenYu


>  .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |   31 +
>  .../bindings/input/mediatek,pmic-keys.yaml    |    1 +
>  .../bindings/mfd/mediatek,mt6685.yaml         |   50 +
>  .../bindings/mfd/mediatek,spmi-pmic.yaml      |  173 +++
>  .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |    1 +
>  drivers/iio/adc/Kconfig                       |   10 +
>  drivers/iio/adc/Makefile                      |    1 +
>  drivers/iio/adc/mtk-spmi-pmic-adc.c           |  576 +++++++++
>  drivers/mfd/Kconfig                           |   26 +
>  drivers/mfd/Makefile                          |    2 +
>  drivers/mfd/mt6685-core.c                     |   83 ++
>  drivers/mfd/mtk-spmi-pmic.c                   |  518 ++++++++
>  drivers/regulator/Kconfig                     |   34 +
>  drivers/regulator/Makefile                    |    3 +
>  drivers/regulator/mt6316-regulator.c          |  381 ++++++
>  drivers/regulator/mt6363-regulator.c          | 1106 +++++++++++++++++
>  drivers/regulator/mt6373-regulator.c          |  826 ++++++++++++
>  drivers/spmi/spmi-mtk-pmif.c                  | 1040 +++++++++++++++-
>  include/linux/mfd/mt6363/core.h               |  134 ++
>  include/linux/mfd/mt6363/registers.h          |  168 +++
>  include/linux/mfd/mt6373/core.h               |   94 ++
>  include/linux/mfd/mt6373/registers.h          |   53 +
>  include/linux/regulator/mt6316-regulator.h    |   48 +
>  include/linux/regulator/mt6363-regulator.h    |  424 +++++++
>  include/linux/regulator/mt6373-regulator.h    |  318 +++++
>  25 files changed, 6037 insertions(+), 64 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
>  create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c
>  create mode 100644 drivers/mfd/mt6685-core.c
>  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/core.h
>  create mode 100644 include/linux/mfd/mt6363/registers.h
>  create mode 100644 include/linux/mfd/mt6373/core.h
>  create mode 100644 include/linux/mfd/mt6373/registers.h
>  create mode 100644 include/linux/regulator/mt6316-regulator.h
>  create mode 100644 include/linux/regulator/mt6363-regulator.h
>  create mode 100644 include/linux/regulator/mt6373-regulator.h
>
> --
> 2.46.0
>
>

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

* Re: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
  2025-03-14  8:25   ` Rob Herring (Arm)
@ 2025-03-14  8:34   ` Chen-Yu Tsai
  2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
  2025-03-14 10:32   ` Krzysztof Kozlowski
  3 siblings, 0 replies; 24+ messages in thread
From: Chen-Yu Tsai @ 2025-03-14  8:34 UTC (permalink / raw)
  To: Lu.Tang
  Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu, linux-iio, devicetree, linux-kernel,
	linux-input, linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

On Fri, Mar 14, 2025 at 4:03 PM Lu.Tang <Lu.Tang@mediatek.com> wrote:
>
> Add new pmic mfd and adc documents for mt8196
>
> Signed-off-by: Lu.Tang <Lu.Tang@mediatek.com>
> ---
>  .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |  31 ++++
>  .../bindings/input/mediatek,pmic-keys.yaml    |   1 +
>  .../bindings/mfd/mediatek,mt6685.yaml         |  50 +++++
>  .../bindings/mfd/mediatek,spmi-pmic.yaml      | 173 ++++++++++++++++++
>  .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |   1 +
>  5 files changed, 256 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
>  create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
> new file mode 100644
> index 000000000000..250782ad7d01
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
> @@ -0,0 +1,31 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek SPMI PMIC AUXADC
> +
> +maintainers:
> +  - Lu Tang <lu.tang@mediatek.com>
> +
> +description:
> +  The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> +  in some MediaTek PMICs, performing various PMIC related measurements
> +  such as battery and PMIC internal voltage regulators temperatures,
> +  other than voltages for various PMIC internal components.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt6363-auxadc
> +      - mediatek,mt6373-auxadc
> +
> +  "#io-channel-cells":
> +    const: 1
> +
> +required:
> +  - compatible
> +  - "#io-channel-cells"
> +
> +additionalProperties: false

This is simply a sub-function of the PMIC, and is really not tied to
whatever interface the PMIC uses. Please integrate this into the existing
binding:

    Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml

> diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
> index b95435bd6a9b..ce760039d4c2 100644
> --- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
> +++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
> @@ -31,6 +31,7 @@ properties:
>        - mediatek,mt6358-keys
>        - mediatek,mt6359-keys
>        - mediatek,mt6397-keys
> +      - mediatek,mt6363-keys
>
>    power-off-time-sec: true
>
> diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
> new file mode 100644
> index 000000000000..d3276df8952b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
> @@ -0,0 +1,50 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/mediatek,mt6685.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT6685 Clock IC
> +
> +maintainers:
> +  - Lu Tang <lu.tang@mediatek.com>
> +
> +description: |
> +  MT6685 is a clock IC.
> +  Please see the sub-modules below for supported features.
> +
> +  MT6685 is a multifunction device with the following sub modules:
> +  - RTC
> +  - Clock
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt6685
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  interrupt-controller: true
> +
> +  "#interrupt-cells":
> +    const: 2
> +
> +required:
> +  - compatible
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/spmi/spmi.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    spmi {
> +        mfd@9 {
> +            compatible = "mediatek,mt6685";
> +            reg = <0x9 SPMI_USID>;
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +        };
> +    };
> diff --git a/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
> new file mode 100644
> index 000000000000..a8f1231623cf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
> @@ -0,0 +1,173 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek SPMI PMICs multi-function device
> +
> +maintainers:
> +  - Lu Tang <lu.tang@mediatek.com>
> +
> +description: |
> +  Some Mediatek PMICs are interfaced to the chip via the SPMI (System Power
> +  Management Interface) bus.
> +
> +  The Mediatek SPMI series includes the MT6363, MT6373, MT6316 and other
> +  PMICs.Please see the sub-modules below for supported features.
> +
> +   MT6363/MT6373 is a multifunction device with the following sub modules:
> +  - Regulators
> +  - ADC
> +  - GPIO
> +  - Keys


> +   MT6316 is a multifunction device with the following sub modules:
> +  - Regulators

Then it is not multifunctional. Please move this to the MT6315
binding:

    Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml

Also, you have not covered regulator bindings in this series.


ChenYu

> +properties:
> +  compatible:
> +    oneOf:
> +      - enum:
> +          - mediatek,mt6363
> +          - mediatek,mt6373
> +          - mediatek,mt6316
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  interrupt-controller: true
> +
> +  "#interrupt-cells":
> +    const: 2
> +
> +  regulators:
> +    type: object
> +    description:
> +      List of child nodes that specify the regulators.
> +    additionalProperties: true
> +
> +    properties:
> +      compatible:
> +        oneOf:
> +          - enum:
> +              - mediatek,mt6363-regulator
> +              - mediatek,mt6373-regulator
> +              - mediatek,mt6316-regulator
> +
> +    required:
> +      - compatible
> +
> +  adc:
> +    type: object
> +    $ref: /schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml#
> +    unevaluatedProperties: false
> +
> +  keys:
> +    type: object
> +    $ref: /schemas/input/mediatek,pmic-keys.yaml
> +    unevaluatedProperties: false
> +    description:
> +      Power and Home keys.
> +
> +  pinctrl:
> +    type: object
> +    $ref: /schemas/pinctrl/mediatek,mt65xx-pinctrl.yaml
> +    unevaluatedProperties: false
> +    description:
> +      Pin controller
> +
> +required:
> +  - compatible
> +  - regulators
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/spmi/spmi.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    spmi {
> +        main_pmic: pmic@4 {
> +            compatible = "mediatek,mt6363";
> +            reg = <0x4 SPMI_USID>;
> +            interrupts = <0x4 IRQ_TYPE_NONE>;
> +            #address-cells = <0>;
> +            interrupt-controller;
> +            #interrupt-cells = <2>;
> +
> +            mt6363keys: keys {
> +                compatible = "mediatek,mt6363-keys";
> +                mediatek,long-press-mode = <1>;
> +                power-off-time-sec = <0>;
> +
> +                power {
> +                    linux,keycodes = <116>;
> +                    wakeup-source;
> +                };
> +
> +                home {
> +                    linux,keycodes = <115>;
> +                };
> +            };
> +
> +            mt6363_pio: pinctrl {
> +                compatible = "mediatek,mt6363-pinctrl";
> +                gpio-controller;
> +                #gpio-cells = <2>;
> +            };
> +
> +            mt6363regulator: regulators {
> +                compatible = "mediatek,mt6363-regulator";
> +
> +                mt6363_vs2: vs2 {
> +                    regulator-name = "mt6363_vs2";
> +                    regulator-allowed-modes = <0 1 2>;
> +                    regulator-always-on;
> +                    regulator-allow-set-load;
> +                };
> +
> +                mt6363_vbuck1: vbuck1 {
> +                    regulator-name = "mt6363_vbuck1";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                mt6363_vbuck2: vbuck2 {
> +                    regulator-name = "mt6363_vbuck2";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                mt6363_vbuck3: vbuck3 {
> +                    regulator-name = "mt6363_vbuck3";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                mt6363_vbuck4: vbuck4 {
> +                    regulator-name = "mt6363_vbuck4";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                mt6363_vbuck5: vbuck5 {
> +                    regulator-name = "mt6363_vbuck5";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                mt6363_vbuck6: vbuck6 {
> +                    regulator-name = "mt6363_vbuck6";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                mt6363_vbuck7: vbuck7 {
> +                    regulator-name = "mt6363_vbuck7";
> +                    regulator-allowed-modes = <0 1 2>;
> +                };
> +
> +                // ...
> +
> +                mt6363_isink_load: isink-load {
> +                    regulator-name = "mt6363_isink_load";
> +                };
> +            };
> +        };
> +    };
> diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
> index bccff08a5ba3..bf3ba58a7705 100644
> --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
> +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
> @@ -17,6 +17,7 @@ properties:
>      enum:
>        - mediatek,mt2701-pinctrl
>        - mediatek,mt2712-pinctrl
> +      - mediatek,mt6363-pinctrl
>        - mediatek,mt6397-pinctrl
>        - mediatek,mt7623-pinctrl
>        - mediatek,mt8127-pinctrl
> --
> 2.46.0
>
>

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

* Re: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver
  2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
@ 2025-03-14  8:53   ` AngeloGioacchino Del Regno
  2025-03-14  9:21     ` 回复: " Lu Tang (汤璐)
  2025-03-14  9:04   ` Lu Tang (汤璐)
  2025-03-15 12:50   ` Jonathan Cameron
  2 siblings, 1 reply; 24+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-03-14  8:53 UTC (permalink / raw)
  To: Lu.Tang, Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, Sean Wang, Linus Walleij, Liam Girdwood,
	Mark Brown, Stephen Boyd, Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

Il 14/03/25 08:32, Lu.Tang ha scritto:
> From: "Lu.Tang" <lu.tang@mediatek.com>
> 
> Add pmic mt6363 and mt6373 auxadc driver
> 

Can't you just add MT6363 and MT6373 support to the already present
mt6359-auxadc driver?!

Regards,
Angelo



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

* 回复: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
  2025-03-14  8:25   ` Rob Herring (Arm)
  2025-03-14  8:34   ` Chen-Yu Tsai
@ 2025-03-14  9:01   ` Lu Tang (汤璐)
  2025-03-17 10:49     ` Krzysztof Kozlowski
  2025-03-14 10:32   ` Krzysztof Kozlowski
  3 siblings, 1 reply; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:01 UTC (permalink / raw)
  To: Lu Tang (汤璐), Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, AngeloGioacchino Del Regno,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

Update email

-----邮件原件-----
发件人: Lu.Tang <Lu.Tang@mediatek.com> 
发送时间: 2025年3月14日 15:33
收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
主题: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents

Add new pmic mfd and adc documents for mt8196

Signed-off-by: Lu.Tang <Lu.Tang@mediatek.com>
---
 .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |  31 ++++
 .../bindings/input/mediatek,pmic-keys.yaml    |   1 +
 .../bindings/mfd/mediatek,mt6685.yaml         |  50 +++++
 .../bindings/mfd/mediatek,spmi-pmic.yaml      | 173 ++++++++++++++++++
 .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |   1 +
 5 files changed, 256 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml

diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
new file mode 100644
index 000000000000..250782ad7d01
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxad
+++ c.yaml
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2
+---
+$id: 
+http://devicetree.org/schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek SPMI PMIC AUXADC
+
+maintainers:
+  - Lu Tang <lu.tang@mediatek.com>
+
+description:
+  The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
+  in some MediaTek PMICs, performing various PMIC related measurements
+  such as battery and PMIC internal voltage regulators temperatures,
+  other than voltages for various PMIC internal components.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6363-auxadc
+      - mediatek,mt6373-auxadc
+
+  "#io-channel-cells":
+    const: 1
+
+required:
+  - compatible
+  - "#io-channel-cells"
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
index b95435bd6a9b..ce760039d4c2 100644
--- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
+++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
@@ -31,6 +31,7 @@ properties:
       - mediatek,mt6358-keys
       - mediatek,mt6359-keys
       - mediatek,mt6397-keys
+      - mediatek,mt6363-keys
 
   power-off-time-sec: true
 
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
new file mode 100644
index 000000000000..d3276df8952b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,mt6685.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6685 Clock IC
+
+maintainers:
+  - Lu Tang <lu.tang@mediatek.com>
+
+description: |
+  MT6685 is a clock IC.
+  Please see the sub-modules below for supported features.
+
+  MT6685 is a multifunction device with the following sub modules:
+  - RTC
+  - Clock
+
+properties:
+  compatible:
+    const: mediatek,mt6685
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/spmi/spmi.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    spmi {
+        mfd@9 {
+            compatible = "mediatek,mt6685";
+            reg = <0x9 SPMI_USID>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
new file mode 100644
index 000000000000..a8f1231623cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
@@ -0,0 +1,173 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek SPMI PMICs multi-function device
+
+maintainers:
+  - Lu Tang <lu.tang@mediatek.com>
+
+description: |
+  Some Mediatek PMICs are interfaced to the chip via the SPMI (System 
+Power
+  Management Interface) bus.
+
+  The Mediatek SPMI series includes the MT6363, MT6373, MT6316 and 
+ other  PMICs.Please see the sub-modules below for supported features.
+
+   MT6363/MT6373 is a multifunction device with the following sub modules:
+  - Regulators
+  - ADC
+  - GPIO
+  - Keys
+   MT6316 is a multifunction device with the following sub modules:
+  - Regulators
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - mediatek,mt6363
+          - mediatek,mt6373
+          - mediatek,mt6316
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+  regulators:
+    type: object
+    description:
+      List of child nodes that specify the regulators.
+    additionalProperties: true
+
+    properties:
+      compatible:
+        oneOf:
+          - enum:
+              - mediatek,mt6363-regulator
+              - mediatek,mt6373-regulator
+              - mediatek,mt6316-regulator
+
+    required:
+      - compatible
+
+  adc:
+    type: object
+    $ref: /schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml#
+    unevaluatedProperties: false
+
+  keys:
+    type: object
+    $ref: /schemas/input/mediatek,pmic-keys.yaml
+    unevaluatedProperties: false
+    description:
+      Power and Home keys.
+
+  pinctrl:
+    type: object
+    $ref: /schemas/pinctrl/mediatek,mt65xx-pinctrl.yaml
+    unevaluatedProperties: false
+    description:
+      Pin controller
+
+required:
+  - compatible
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/spmi/spmi.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    spmi {
+        main_pmic: pmic@4 {
+            compatible = "mediatek,mt6363";
+            reg = <0x4 SPMI_USID>;
+            interrupts = <0x4 IRQ_TYPE_NONE>;
+            #address-cells = <0>;
+            interrupt-controller;
+            #interrupt-cells = <2>;
+
+            mt6363keys: keys {
+                compatible = "mediatek,mt6363-keys";
+                mediatek,long-press-mode = <1>;
+                power-off-time-sec = <0>;
+
+                power {
+                    linux,keycodes = <116>;
+                    wakeup-source;
+                };
+
+                home {
+                    linux,keycodes = <115>;
+                };
+            };
+
+            mt6363_pio: pinctrl {
+                compatible = "mediatek,mt6363-pinctrl";
+                gpio-controller;
+                #gpio-cells = <2>;
+            };
+
+            mt6363regulator: regulators {
+                compatible = "mediatek,mt6363-regulator";
+
+                mt6363_vs2: vs2 {
+                    regulator-name = "mt6363_vs2";
+                    regulator-allowed-modes = <0 1 2>;
+                    regulator-always-on;
+                    regulator-allow-set-load;
+                };
+
+                mt6363_vbuck1: vbuck1 {
+                    regulator-name = "mt6363_vbuck1";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck2: vbuck2 {
+                    regulator-name = "mt6363_vbuck2";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck3: vbuck3 {
+                    regulator-name = "mt6363_vbuck3";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck4: vbuck4 {
+                    regulator-name = "mt6363_vbuck4";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck5: vbuck5 {
+                    regulator-name = "mt6363_vbuck5";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck6: vbuck6 {
+                    regulator-name = "mt6363_vbuck6";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                mt6363_vbuck7: vbuck7 {
+                    regulator-name = "mt6363_vbuck7";
+                    regulator-allowed-modes = <0 1 2>;
+                };
+
+                // ...
+
+                mt6363_isink_load: isink-load {
+                    regulator-name = "mt6363_isink_load";
+                };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
index bccff08a5ba3..bf3ba58a7705 100644
--- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.
+++ yaml
@@ -17,6 +17,7 @@ properties:
     enum:
       - mediatek,mt2701-pinctrl
       - mediatek,mt2712-pinctrl
+      - mediatek,mt6363-pinctrl
       - mediatek,mt6397-pinctrl
       - mediatek,mt7623-pinctrl
       - mediatek,mt8127-pinctrl
--
2.46.0


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

* 回复: [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196
  2025-03-14  7:32 ` [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196 Lu.Tang
@ 2025-03-14  9:01   ` Lu Tang (汤璐)
  0 siblings, 0 replies; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:01 UTC (permalink / raw)
  To: Lu Tang (汤璐), Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, AngeloGioacchino Del Regno,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

Update email address

-----邮件原件-----
发件人: Lu.Tang <Lu.Tang@mediatek.com> 
发送时间: 2025年3月14日 15:33
收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
主题: [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196

From: "Lu.Tang" <lu.tang@mediatek.com>

Modify spmi driver for mt8196 pmic.
Add pmif_s/pmif_m controller and rcs irq handler.

Signed-off-by: Lu.Tang <lu.tang@mediatek.com>
---
 drivers/spmi/spmi-mtk-pmif.c | 1040 +++++++++++++++++++++++++++++++---
 1 file changed, 976 insertions(+), 64 deletions(-)

diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c index 160d36f7d238..36f7ef80e7c4 100644
--- a/drivers/spmi/spmi-mtk-pmif.c
+++ b/drivers/spmi/spmi-mtk-pmif.c
@@ -1,14 +1,20 @@
 // SPDX-License-Identifier: GPL-2.0
 //
-// Copyright (c) 2021 MediaTek Inc.
+// Copyright (c) 2024 MediaTek Inc.
 
 #include <linux/clk.h>
 #include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/sched/clock.h>
+#include <linux/sched/mm.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/spmi.h>
+#include <linux/irq.h>
 
 #define SWINF_IDLE	0x00
 #define SWINF_WFVLDCLR	0x06
@@ -21,14 +27,21 @@
 #define PMIF_CMD_EXT_REG_LONG	3
 
 #define PMIF_DELAY_US   10
-#define PMIF_TIMEOUT_US (10 * 1000)
+#define PMIF_TIMEOUT_US (100 * 1000)
 
 #define PMIF_CHAN_OFFSET 0x5
 
+#define PMIF_CAPS_VER_1 1
+#define PMIF_CAPS_VER_2 2
+
 #define PMIF_MAX_CLKS	3
 
 #define SPMI_OP_ST_BUSY 1
 
+#define SPMI_SOC_CHANNEL 2
+
+#define PMIF_IRQDESC(name) { #name, pmif_##name##_irq_handler, -1}
+
 struct ch_reg {
 	u32 ch_sta;
 	u32 wdata;
@@ -41,25 +54,53 @@ struct pmif_data {
 	const u32	*regs;
 	const u32	*spmimst_regs;
 	u32	soc_chan;
+	u32 caps;
 };
 
 struct pmif {
-	void __iomem	*base;
-	void __iomem	*spmimst_base;
+	void __iomem	*pmif_base[2];
+	void __iomem	*spmimst_base[2];
 	struct ch_reg	chan;
 	struct clk_bulk_data clks[PMIF_MAX_CLKS];
 	size_t nclks;
 	const struct pmif_data *data;
-	raw_spinlock_t lock;
+	raw_spinlock_t	lock_m;
+	raw_spinlock_t	lock_p;
+	struct spmi_controller  *spmic;
+	struct wakeup_source *pmif_m_Thread_lock;
+	struct wakeup_source *pmif_p_Thread_lock;
+	struct mutex pmif_m_mutex;
+	struct mutex pmif_p_mutex;
+	int		irq;
+	int		irq_p;
+	struct irq_domain	*domain;
+	struct irq_chip		irq_chip;
+	struct irq_chip		irq_chip_p;
+	int			rcs_irq;
+	int			rcs_irq_p;
+	struct mutex		rcs_m_irqlock;
+	struct mutex		rcs_p_irqlock;
+	bool	   *rcs_enable_hwirq;
+	int spmi_nack_irq;
+	int spmi_p_nack_irq;
 };
 
 static const char * const pmif_clock_names[] = {
 	"pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux",  };
 
+struct pmif_irq_desc {
+	const char *name;
+	irq_handler_t irq_handler;
+	int irq;
+};
+
 enum pmif_regs {
 	PMIF_INIT_DONE,
 	PMIF_INF_EN,
+	MD_AUXADC_RDATA_0_ADDR,
+	MD_AUXADC_RDATA_1_ADDR,
+	MD_AUXADC_RDATA_2_ADDR,
 	PMIF_ARB_EN,
 	PMIF_CMDISSUE_EN,
 	PMIF_TIMER_CTRL,
@@ -103,6 +144,11 @@ enum pmif_regs {
 	PMIF_SWINF_3_RDATA_31_0,
 	PMIF_SWINF_3_ACC,
 	PMIF_SWINF_3_VLD_CLR,
+	PMIF_PMIC_SWINF_0_PER,
+	PMIF_PMIC_SWINF_1_PER,
+	PMIF_ACC_VIO_INFO_0,
+	PMIF_ACC_VIO_INFO_1,
+	PMIF_ACC_VIO_INFO_2,
 };
 
 static const u32 mt6873_regs[] = {
@@ -201,6 +247,63 @@ static const u32 mt8195_regs[] = {
 	[PMIF_SWINF_3_STA] = 0x08E8,
 };
 
+static const u32 mt6xxx_regs[] = {
+	[PMIF_INIT_DONE] =			0x0000,
+	[PMIF_INF_EN] =				0x0024,
+	[MD_AUXADC_RDATA_0_ADDR] =		0x0080,
+	[MD_AUXADC_RDATA_1_ADDR] =		0x0084,
+	[MD_AUXADC_RDATA_2_ADDR] =		0x0088,
+	[PMIF_ARB_EN] =				0x0150,
+	[PMIF_CMDISSUE_EN] =			0x03B8,
+	[PMIF_TIMER_CTRL] =			0x03E4,
+	[PMIF_SPI_MODE_CTRL] =			0x0408,
+	[PMIF_IRQ_EVENT_EN_0] =			0x0420,
+	[PMIF_IRQ_FLAG_0] =			0x0428,
+	[PMIF_IRQ_CLR_0] =			0x042C,
+	[PMIF_IRQ_EVENT_EN_1] =			0x0430,
+	[PMIF_IRQ_FLAG_1] =			0x0438,
+	[PMIF_IRQ_CLR_1] =			0x043C,
+	[PMIF_IRQ_EVENT_EN_2] =			0x0440,
+	[PMIF_IRQ_FLAG_2] =			0x0448,
+	[PMIF_IRQ_CLR_2] =			0x044C,
+	[PMIF_IRQ_EVENT_EN_3] =			0x0450,
+	[PMIF_IRQ_FLAG_3] =			0x0458,
+	[PMIF_IRQ_CLR_3] =			0x045C,
+	[PMIF_IRQ_EVENT_EN_4] =			0x0460,
+	[PMIF_IRQ_FLAG_4] =			0x0468,
+	[PMIF_IRQ_CLR_4] =			0x046C,
+	[PMIF_WDT_EVENT_EN_0] =			0x0474,
+	[PMIF_WDT_FLAG_0] =			0x0478,
+	[PMIF_WDT_EVENT_EN_1] =			0x047C,
+	[PMIF_WDT_FLAG_1] =			0x0480,
+	[PMIF_SWINF_0_ACC] =			0x0800,
+	[PMIF_SWINF_0_WDATA_31_0] =		0x0804,
+	[PMIF_SWINF_0_RDATA_31_0] =		0x0814,
+	[PMIF_SWINF_0_VLD_CLR] =		0x0824,
+	[PMIF_SWINF_0_STA] =			0x0828,
+	[PMIF_SWINF_1_ACC] =			0x0840,
+	[PMIF_SWINF_1_WDATA_31_0] =		0x0844,
+	[PMIF_SWINF_1_RDATA_31_0] =		0x0854,
+	[PMIF_SWINF_1_VLD_CLR] =		0x0864,
+	[PMIF_SWINF_1_STA] =			0x0868,
+	[PMIF_SWINF_2_ACC] =			0x0880,
+	[PMIF_SWINF_2_WDATA_31_0] =		0x0884,
+	[PMIF_SWINF_2_RDATA_31_0] =		0x0894,
+	[PMIF_SWINF_2_VLD_CLR] =		0x08A4,
+	[PMIF_SWINF_2_STA] =			0x08A8,
+	[PMIF_SWINF_3_ACC] =			0x08C0,
+	[PMIF_SWINF_3_WDATA_31_0] =		0x08C4,
+	[PMIF_SWINF_3_RDATA_31_0] =		0x08D4,
+	[PMIF_SWINF_3_VLD_CLR] =		0x08E4,
+	[PMIF_SWINF_3_STA] =			0x08E8,
+	[PMIF_PMIC_SWINF_0_PER] =		0x093C,
+	[PMIF_PMIC_SWINF_1_PER] =		0x0940,
+	[PMIF_ACC_VIO_INFO_0] =			0x0980,
+	[PMIF_ACC_VIO_INFO_1] =			0x0984,
+	[PMIF_ACC_VIO_INFO_2] =			0x0988,
+
+};
+
 enum spmi_regs {
 	SPMI_OP_ST_CTRL,
 	SPMI_GRP_ID_EN,
@@ -262,26 +365,132 @@ static const u32 mt8195_spmi_regs[] = {
 	[SPMI_MST_DBG] = 0x00FC,
 };
 
-static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)
+static const u32 mt6853_spmi_regs[] = {
+	[SPMI_OP_ST_CTRL] =	0x0000,
+	[SPMI_GRP_ID_EN] =	0x0004,
+	[SPMI_OP_ST_STA] =	0x0008,
+	[SPMI_MST_SAMPL] =	0x000C,
+	[SPMI_MST_REQ_EN] =	0x0010,
+	[SPMI_MST_RCS_CTRL] =	0x0014,
+	[SPMI_SLV_3_0_EINT] =	0x0020,
+	[SPMI_SLV_7_4_EINT] =	0x0024,
+	[SPMI_SLV_B_8_EINT] =	0x0028,
+	[SPMI_SLV_F_C_EINT] =	0x002C,
+	[SPMI_REC_CTRL] =	0x0040,
+	[SPMI_REC0] =		0x0044,
+	[SPMI_REC1] =		0x0048,
+	[SPMI_REC2] =		0x004C,
+	[SPMI_REC3] =		0x0050,
+	[SPMI_REC4] =		0x0054,
+	[SPMI_REC_CMD_DEC] =	0x005C,
+	[SPMI_DEC_DBG] =	0x00F8,
+	[SPMI_MST_DBG] =	0x00FC,
+};
+
+enum {
+	IRQ_LAT_LIMIT_REACHED = 6,
+	IRQ_HW_MONITOR = 7,
+	IRQ_WDT = 8,
+	/* MT6833/MT6877 series */
+	IRQ_HW_MONITOR_V3 = 12,
+	IRQ_WDT_V3 = 13,
+	IRQ_ALL_PMIC_MPU_VIO_V3 = 14,
+	/* MT6885/MT6873 series */
+	IRQ_PMIC_CMD_ERR_PARITY_ERR = 17,
+	IRQ_PMIF_ACC_VIO = 20,
+	IRQ_PMIC_ACC_VIO = 21,
+	/* MT6985/MT6897 */
+	IRQ_PMIF_ACC_VIO_V3 = 27,
+	/* MT6853 series */
+	IRQ_PMIF_ACC_VIO_V2 = 31,
+};
+
+enum {
+	IRQ_PMIC_ACC_VIO_V2 = 0,
+	IRQ_PMIF_SWINF_ACC_ERR_0 = 3,
+	IRQ_PMIF_SWINF_ACC_ERR_1 = 4,
+	IRQ_PMIF_SWINF_ACC_ERR_2 = 5,
+	IRQ_PMIF_SWINF_ACC_ERR_3 = 6,
+	IRQ_PMIF_SWINF_ACC_ERR_4 = 7,
+	IRQ_PMIF_SWINF_ACC_ERR_5 = 8,
+	IRQ_HW_MONITOR_V2 = 18,
+	IRQ_WDT_V2 = 19,
+	IRQ_ALL_PMIC_MPU_VIO_V2 = 20,
+	IRQ_PMIF_SWINF_ACC_ERR_0_V2 = 23,
+	IRQ_PMIF_SWINF_ACC_ERR_1_V2 = 24,
+	IRQ_PMIF_SWINF_ACC_ERR_2_V2 = 25,
+	IRQ_PMIF_SWINF_ACC_ERR_3_V2 = 26,
+	IRQ_PMIF_SWINF_ACC_ERR_4_V2 = 27,
+	IRQ_PMIF_SWINF_ACC_ERR_5_V2 = 28,
+	/* MT6983/MT6879 */
+	IRQ_HW_MONITOR_V4 = 29,
+	IRQ_WDT_V4 = 30,
+	IRQ_ALL_PMIC_MPU_VIO_V4 = 31,
+};
+
+struct spmi_dev {
+	int exist;
+	int slvid;
+	unsigned int path;
+	unsigned short hwcid_addr;
+	unsigned char hwcid_val;
+};
+
+static struct spmi_dev spmidev[16];
+
+static void spmi_dev_parse(struct platform_device *pdev)
 {
-	return readl(arb->base + arb->data->regs[reg]);
+	int i = 0, j = 0, ret = 0;
+	u32 spmi_dev_mask = 0;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "spmi-dev-mask",
+				  &spmi_dev_mask);
+	if (ret)
+		dev_info(&pdev->dev, "No spmi-dev-mask found in dts, default all PMIC 
+on SPMI-M\n");
+
+	j = spmi_dev_mask;
+	for (i = 0; i < 16; i++) {
+		if (j & BIT(i))
+			spmidev[i].path = 1; /* slvid i is in path p */
+		else
+			spmidev[i].path = 0;
+	}
+}
+
+unsigned long long get_current_time_ms(void) {
+	unsigned long long cur_ts;
+
+	cur_ts = sched_clock();
+	do_div(cur_ts, 1000000);
+	return cur_ts;
 }
 
-static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)
+static u32 pmif_readl(void __iomem *addr, struct pmif *arb, enum 
+pmif_regs reg)
 {
-	writel(val, arb->base + arb->data->regs[reg]);
+	return readl(addr + arb->data->regs[reg]);
 }
 
-static void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg)
+static void pmif_writel(void __iomem *addr, struct pmif *arb, u32 val, 
+enum pmif_regs reg)
 {
-	writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]);
+	writel(val, addr + arb->data->regs[reg]);
 }
 
-static bool pmif_is_fsm_vldclr(struct pmif *arb)
+static void mtk_spmi_writel(void __iomem *addr, struct pmif *arb, u32 
+val, enum spmi_regs reg) {
+	writel(val, addr + arb->data->spmimst_regs[reg]); }
+
+static u32 mtk_spmi_readl(void __iomem *addr, struct pmif *arb, enum 
+spmi_regs reg) {
+	return readl(addr + arb->data->spmimst_regs[reg]); }
+
+static bool pmif_is_fsm_vldclr(void __iomem *addr, struct pmif *arb)
 {
 	u32 reg_rdata;
 
-	reg_rdata = pmif_readl(arb, arb->chan.ch_sta);
+	reg_rdata = pmif_readl(addr, arb, arb->chan.ch_sta);
 
 	return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR;  } @@ -298,8 +507,8 @@ static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 
 	cmd = opc - SPMI_CMD_RESET;
 
-	mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
-	ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA],
+	mtk_spmi_writel(arb->spmimst_base[spmidev[sid].path], arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
+	ret = readl_poll_timeout_atomic(arb->spmimst_base[spmidev[sid].path] + 
+arb->data->spmimst_regs[SPMI_OP_ST_STA],
 					rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0)
@@ -315,7 +524,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	struct ch_reg *inf_reg;
 	int ret;
 	u32 data, cmd;
-	unsigned long flags;
+	unsigned long flags_m;
 
 	/* Check for argument validation. */
 	if (sid & ~0xf) {
@@ -336,31 +545,31 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	raw_spin_lock_irqsave(&arb->lock, flags);
+	raw_spin_lock_irqsave(&arb->lock_m, flags_m);
 	/* Wait for Software Interface FSM state to be IDLE. */
 	inf_reg = &arb->chan;
-	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
+	ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + 
+arb->data->regs[inf_reg->ch_sta],
 					data, GET_SWINF(data) == SWINF_IDLE,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0) {
 		/* set channel ready if the data has transferred */
-		if (pmif_is_fsm_vldclr(arb))
-			pmif_writel(arb, 1, inf_reg->ch_rdy);
-		raw_spin_unlock_irqrestore(&arb->lock, flags);
+		if (pmif_is_fsm_vldclr(arb->pmif_base[spmidev[sid].path], arb))
+			pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy);
+		raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
 		return ret;
 	}
 
 	/* Send the command. */
 	cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
-	pmif_writel(arb, cmd, inf_reg->ch_send);
-	raw_spin_unlock_irqrestore(&arb->lock, flags);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, cmd, inf_reg->ch_send);
+	raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 
 	/*
 	 * Wait for Software Interface FSM state to be WFVLDCLR,
 	 * read the data and clear the valid flag.
 	 */
-	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
+	ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path]  + 
+arb->data->regs[inf_reg->ch_sta],
 					data, GET_SWINF(data) == SWINF_WFVLDCLR,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0) {
@@ -368,9 +577,9 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 		return ret;
 	}
 
-	data = pmif_readl(arb, inf_reg->rdata);
+	data = pmif_readl(arb->pmif_base[spmidev[sid].path], arb, 
+inf_reg->rdata);
 	memcpy(buf, &data, len);
-	pmif_writel(arb, 1, inf_reg->ch_rdy);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, 
+inf_reg->ch_rdy);
 
 	return 0;
 }
@@ -382,7 +591,7 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	struct ch_reg *inf_reg;
 	int ret;
 	u32 data, wdata, cmd;
-	unsigned long flags;
+	unsigned long flags_m;
 
 	/* Check for argument validation. */
 	if (unlikely(sid & ~0xf)) {
@@ -409,27 +618,27 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	/* Set the write data. */
 	memcpy(&wdata, buf, len);
 
-	raw_spin_lock_irqsave(&arb->lock, flags);
+	raw_spin_lock_irqsave(&arb->lock_m, flags_m);
 	/* Wait for Software Interface FSM state to be IDLE. */
 	inf_reg = &arb->chan;
-	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
+	ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + 
+arb->data->regs[inf_reg->ch_sta],
 					data, GET_SWINF(data) == SWINF_IDLE,
 					PMIF_DELAY_US, PMIF_TIMEOUT_US);
 	if (ret < 0) {
 		/* set channel ready if the data has transferred */
-		if (pmif_is_fsm_vldclr(arb))
-			pmif_writel(arb, 1, inf_reg->ch_rdy);
-		raw_spin_unlock_irqrestore(&arb->lock, flags);
+		if (pmif_is_fsm_vldclr(arb->pmif_base[spmidev[sid].path], arb))
+			pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy);
+		raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
 		return ret;
 	}
 
-	pmif_writel(arb, wdata, inf_reg->wdata);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, wdata, 
+inf_reg->wdata);
 
 	/* Send the command. */
 	cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;
-	pmif_writel(arb, cmd, inf_reg->ch_send);
-	raw_spin_unlock_irqrestore(&arb->lock, flags);
+	pmif_writel(arb->pmif_base[spmidev[sid].path], arb, cmd, inf_reg->ch_send);
+	raw_spin_unlock_irqrestore(&arb->lock_m, flags_m);
 
 	return 0;
 }
@@ -437,15 +646,642 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,  static const struct pmif_data mt6873_pmif_arb = {
 	.regs = mt6873_regs,
 	.spmimst_regs = mt6873_spmi_regs,
-	.soc_chan = 2,
+	.soc_chan = SPMI_SOC_CHANNEL,
+	.caps = PMIF_CAPS_VER_1,
 };
 
 static const struct pmif_data mt8195_pmif_arb = {
 	.regs = mt8195_regs,
 	.spmimst_regs = mt8195_spmi_regs,
-	.soc_chan = 2,
+	.soc_chan = SPMI_SOC_CHANNEL,
+	.caps = PMIF_CAPS_VER_1,
 };
+static const struct pmif_data mt6xxx_pmif_arb = {
+	.regs = mt6xxx_regs,
+	.spmimst_regs = mt6853_spmi_regs,
+	.soc_chan = SPMI_SOC_CHANNEL,
+	.caps = PMIF_CAPS_VER_2,
+};
+static void mtk_spmi_readl_datas(struct pmif *arb, int id, unsigned int *spmi_nack,
+		unsigned int *spmi_nack_data, unsigned int *spmi_rcs_nack,
+		unsigned int *spmi_debug_nack, unsigned int *spmi_mst_nack) {
+	if (id < 0 || id >= PMIF_CAPS_VER_2) {
+		dev_err(&arb->spmic->dev, "%s Invalid id: %d\n", __func__, id);
+		return;
+	}
+	*spmi_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC0);
+	*spmi_nack_data = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC1);
+	*spmi_rcs_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC_CMD_DEC);
+	*spmi_debug_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_DEC_DBG);
+	*spmi_mst_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, 
+SPMI_MST_DBG); } static irqreturn_t spmi_nack_irq_handler(int irq, void 
+*data) {
+	struct pmif *arb = data;
+	int sid = 0;
+	unsigned int spmi_nack = 0, spmi_p_nack = 0, spmi_nack_data = 0, spmi_p_nack_data = 0;
+	unsigned int spmi_rcs_nack = 0, spmi_debug_nack = 0, spmi_mst_nack = 0,
+		spmi_p_rcs_nack = 0, spmi_p_debug_nack = 0, spmi_p_mst_nack = 0;
+	u8 rdata = 0, rdata1 = 0;
+	unsigned short mt6316INTSTA = 0x240, hwcidaddr_mt6316 = 0x209, VIO18_SWITCH_6363 = 0x53,
+		hwcidaddr_mt6363 = 0x9;
+
+	mutex_lock(&arb->pmif_m_mutex);
+
+	mtk_spmi_readl_datas(arb, 0, &spmi_nack, &spmi_nack_data, &spmi_rcs_nack,
+		&spmi_debug_nack, &spmi_mst_nack);
+	if (!IS_ERR(arb->spmimst_base[1])) {
+		mtk_spmi_readl_datas(arb, 1, &spmi_p_nack, &spmi_p_nack_data, &spmi_p_rcs_nack,
+			&spmi_p_debug_nack, &spmi_p_mst_nack);
+	}
+	if ((spmi_nack & 0xD8) || (spmi_p_nack & 0xD8)) {
+		if (spmi_p_nack & 0xD8) {
+			for (sid = 0x8; sid >= 0x6; sid--) {
+				arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, sid,
+					mt6316INTSTA, &rdata, 1);
+				arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, sid,
+					hwcidaddr_mt6316, &rdata1, 1);
+				dev_notice(&arb->spmic->dev, "%s slvid 0x%x INT_RAW_STA 0x%x cid 0x%x\n",
+					__func__, sid, rdata, rdata1);
+			}
+		}
+		dev_notice(&arb->spmic->dev, "%s spmi transaction fail irq triggered", __func__);
+		dev_notice(&arb->spmic->dev, "SPMI_REC0 m/p:0x%x/0x%x SPMI_REC1 m/p 0x%x/0x%x\n",
+			spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data);
+	}
+	if ((spmi_rcs_nack & 0xC0000) || (spmi_p_rcs_nack & 0xC0000)) {
+		dev_notice(&arb->spmic->dev, "%s spmi_rcs transaction fail irq triggered SPMI_REC_CMD_DEC m/p:0x%x/0x%x\n",
+			__func__, spmi_rcs_nack, spmi_p_rcs_nack);
+	}
+	if ((spmi_debug_nack & 0xF0000) || (spmi_p_debug_nack & 0xF0000)) {
+		dev_notice(&arb->spmic->dev, "%s spmi_debug_nack transaction fail irq triggered SPMI_DEC_DBG m/p: 0x%x/0x%x\n",
+			__func__, spmi_debug_nack, spmi_p_debug_nack);
+	}
+	if ((spmi_mst_nack & 0xC0000) || (spmi_p_mst_nack & 0xC0000)) {
+		dev_notice(&arb->spmic->dev, "%s spmi_mst_nack transaction fail irq triggered SPMI_MST_DBG m/p: 0x%x/0x%x\n",
+		__func__, spmi_mst_nack, spmi_p_mst_nack);
+	}
 
+	if ((spmi_nack & 0x20) || (spmi_p_nack & 0x20)) {
+		dev_notice(&arb->spmic->dev, "%s spmi transaction fail (Read) irq triggered", __func__);
+		dev_notice(&arb->spmic->dev, "SPMI_REC0 m/p:0x%x/0x%x SPMI_REC1 m/p 0x%x/0x%x\n",
+			spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data);
+	}
+
+	if ((spmi_nack & 0xF8) || (spmi_rcs_nack & 0xC0000) ||
+		(spmi_debug_nack & 0xF0000) || (spmi_mst_nack & 0xC0000)) {
+		mtk_spmi_writel(arb->spmimst_base[0], arb, 0x3, SPMI_REC_CTRL);
+	} else if ((spmi_p_nack & 0xF8) || (spmi_p_rcs_nack & 0xC0000) ||
+		(spmi_p_debug_nack & 0xF0000) || (spmi_p_mst_nack & 0xC0000)) {
+		if (spmi_p_nack & 0xD8) {
+			dev_notice(&arb->spmic->dev, "%s SPMI_REC0 m/p:0x%x/0x%x, SPMI_REC1 m/p:0x%x/0x%x\n",
+				__func__, spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data);
+			dev_notice(&arb->spmic->dev, "%s SPMI_REC_CMD_DEC m/p:0x%x/0x%x\n", __func__,
+				spmi_rcs_nack, spmi_p_rcs_nack);
+			dev_notice(&arb->spmic->dev, "%s SPMI_DEC_DBG m/p:0x%x/0x%x\n", __func__,
+				spmi_debug_nack, spmi_p_debug_nack);
+			dev_notice(&arb->spmic->dev, "%s SPMI_MST_DBG m/p:0x%x/0x%x\n", __func__,
+				spmi_mst_nack, spmi_p_mst_nack);
+			arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, 0x4,
+				hwcidaddr_mt6363, &rdata, 1);
+			arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, 0x4,
+				VIO18_SWITCH_6363, &rdata1, 1);
+			dev_notice(&arb->spmic->dev, "%s 6363 CID/VIO18_SWITCH 0x%x/0x%x\n", __func__, rdata, rdata1);
+		}
+		mtk_spmi_writel(arb->spmimst_base[1], arb, 0x3, SPMI_REC_CTRL);
+	} else
+		dev_notice(&arb->spmic->dev, "%s IRQ not cleared\n", __func__);
+
+	mutex_unlock(&arb->pmif_m_mutex);
+
+	return IRQ_HANDLED;
+}
+static int spmi_nack_irq_register(struct platform_device *pdev,
+		struct pmif *arb, int irq)
+{
+	int ret = 0;
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				spmi_nack_irq_handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_SHARED,
+				"spmi_nack_irq", arb);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "request %s irq fail\n",
+			"spmi_nack_irq");
+	}
+	return ret;
+}
+static void rcs_irq_lock(struct irq_data *data) {
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	mutex_lock(&arb->rcs_m_irqlock);
+}
+static void rcs_irq_sync_unlock(struct irq_data *data) {
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	mutex_unlock(&arb->rcs_m_irqlock);
+}
+static void rcs_irq_enable(struct irq_data *data) {
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	arb->rcs_enable_hwirq[hwirq] = true;
+}
+static void rcs_irq_disable(struct irq_data *data) {
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	arb->rcs_enable_hwirq[hwirq] = false;
+}
+static int rcs_irq_set_wake(struct irq_data *data, unsigned int on) {
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	return irq_set_irq_wake(arb->rcs_irq, on); } static int 
+rcs_irq_p_set_wake(struct irq_data *data, unsigned int on) {
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+	return irq_set_irq_wake(arb->rcs_irq_p, on); } static const struct 
+irq_chip rcs_irq_chip = {
+	.name			= "rcs_irq",
+	.irq_bus_lock		= rcs_irq_lock,
+	.irq_bus_sync_unlock	= rcs_irq_sync_unlock,
+	.irq_enable		= rcs_irq_enable,
+	.irq_disable		= rcs_irq_disable,
+	.irq_set_wake 		= rcs_irq_set_wake,
+};
+
+static const struct irq_chip rcs_irq_chip_p = {
+	.name			= "rcs_irq_p",
+	.irq_bus_lock		= rcs_irq_lock,
+	.irq_bus_sync_unlock	= rcs_irq_sync_unlock,
+	.irq_enable		= rcs_irq_enable,
+	.irq_disable		= rcs_irq_disable,
+	.irq_set_wake 		= rcs_irq_p_set_wake,
+};
+static int rcs_irq_map(struct irq_domain *d, unsigned int virq,
+			irq_hw_number_t hw)
+{
+	struct pmif *arb = d->host_data;
+	irq_set_chip_data(virq, arb);
+	irq_set_chip(virq, &arb->irq_chip);
+	irq_set_nested_thread(virq, 1);
+	irq_set_parent(virq, arb->rcs_irq);
+	irq_set_noprobe(virq);
+	return 0;
+}
+static const struct irq_domain_ops rcs_irq_domain_ops = {
+	.map	= rcs_irq_map,
+	.xlate	= irq_domain_xlate_onetwocell,
+};
+static void pmif_lat_limit_reached_irq_handler(int irq, void *data) { } 
+static void pmif_acc_vio_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF ACC violation debug info\n");
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF-M\n");
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_0 = 0x%x\n", pmif_readl(arb->pmif_base[0],
+		arb, PMIF_ACC_VIO_INFO_0));
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_1 = 0x%x\n", pmif_readl(arb->pmif_base[0],
+		arb, PMIF_ACC_VIO_INFO_1));
+	dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_2 = 0x%x\n", pmif_readl(arb->pmif_base[0],
+		arb, PMIF_ACC_VIO_INFO_2));
+	if (!IS_ERR(arb->pmif_base[1])) {
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF-P\n");
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_0 = 0x%x\n", pmif_readl(arb->pmif_base[1],
+			arb, PMIF_ACC_VIO_INFO_0));
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_1 = 0x%x\n", pmif_readl(arb->pmif_base[1],
+			arb, PMIF_ACC_VIO_INFO_1));
+		dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_2 = 0x%x\n", pmif_readl(arb->pmif_base[1],
+			arb, PMIF_ACC_VIO_INFO_2));
+	}
+}
+static void pmif_wdt_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	pmif_writel(arb->pmif_base[0], arb, 0x40000000, PMIF_IRQ_CLR_0);
+	if (!IS_ERR(arb->pmif_base[1]))
+		pmif_writel(arb->pmif_base[1], arb, 0x40000000, PMIF_IRQ_CLR_0);
+	dev_notice(&arb->spmic->dev, "[PMIF]:WDT IRQ HANDLER DONE\n"); } 
+static void pmif_pmif_acc_vio_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:pmif_acc_vio"); #endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:pmif_acc_vio\n"); } static void 
+pmif_pmic_acc_vio_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:pmic_acc_vio"); #endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:pmic_acc_vio\n"); } static void 
+pmif_cmd_err_parity_err_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:parity error"); #endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:parity error\n"); } static void 
+pmif_hw_monitor_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE))
+	aee_kernel_warning("PMIF", "PMIF:pmif_hw_monitor_match"); #endif
+	dev_notice(&arb->spmic->dev, "[PMIF]:pmif_hw_monitor_match\n");
+}
+static void pmif_swinf_acc_err_irq_handler(int irq, void *data, u32 
+val) {
+	struct pmif *arb = data;
+	pmif_writel(arb->pmif_base[0], arb, val, MD_AUXADC_RDATA_0_ADDR);
+	pmif_writel(arb->pmif_base[0], arb, (u32)get_current_time_ms(), MD_AUXADC_RDATA_1_ADDR);
+	if (!IS_ERR(arb->pmif_base[1])) {
+		pmif_writel(arb->pmif_base[1], arb, val, MD_AUXADC_RDATA_0_ADDR);
+		pmif_writel(arb->pmif_base[1], arb, (u32)get_current_time_ms(), MD_AUXADC_RDATA_1_ADDR);
+	}
+	dev_notice(&arb->spmic->dev, "[PMIF]:SWINF_ACC_ERR:%d\n", val); } 
+static irqreturn_t pmif_event_0_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_0);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_0);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			case IRQ_PMIF_ACC_VIO_V3:
+				pmif_acc_vio_irq_handler(irq, data);
+			break;
+			case IRQ_WDT_V4:
+				pmif_wdt_irq_handler(irq, data);
+			break;
+			case IRQ_ALL_PMIC_MPU_VIO_V4:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+			break;
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_0);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_0);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_1_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_1);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_1);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_1);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_1);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_2_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_2);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_2);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			case IRQ_PMIC_CMD_ERR_PARITY_ERR:
+				pmif_cmd_err_parity_err_irq_handler(irq, data);
+			break;
+			case IRQ_PMIF_ACC_VIO_V2:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+			break;
+			case IRQ_PMIC_ACC_VIO:
+				pmif_pmic_acc_vio_irq_handler(irq, data);
+			break;
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_2);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_2);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_3_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_3);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_3);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			case IRQ_PMIF_SWINF_ACC_ERR_0:
+			case IRQ_PMIF_SWINF_ACC_ERR_0_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x0);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_1:
+			case IRQ_PMIF_SWINF_ACC_ERR_1_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x1);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_2:
+			case IRQ_PMIF_SWINF_ACC_ERR_2_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x2);
+				break;
+			case IRQ_LAT_LIMIT_REACHED:
+			case IRQ_PMIF_SWINF_ACC_ERR_3_V2:
+				if (arb->data->caps == 1)
+					pmif_lat_limit_reached_irq_handler(irq, data);
+				else
+					pmif_swinf_acc_err_irq_handler(irq, data, 0x3);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_4:
+			case IRQ_PMIF_SWINF_ACC_ERR_4_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x4);
+				break;
+			case IRQ_PMIF_SWINF_ACC_ERR_5:
+			case IRQ_PMIF_SWINF_ACC_ERR_5_V2:
+				pmif_swinf_acc_err_irq_handler(irq, data, 0x5);
+				break;
+			case IRQ_HW_MONITOR_V2:
+			case IRQ_HW_MONITOR_V3:
+				pmif_hw_monitor_irq_handler(irq, data);
+				break;
+			case IRQ_WDT_V2:
+			case IRQ_WDT_V3:
+				pmif_wdt_irq_handler(irq, data);
+				break;
+			case IRQ_PMIC_ACC_VIO_V2:
+				pmif_pmic_acc_vio_irq_handler(irq, data);
+				break;
+			case IRQ_ALL_PMIC_MPU_VIO_V2:
+			case IRQ_ALL_PMIC_MPU_VIO_V3:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+				break;
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", __func__, idx);
+				break;
+			}
+			if (irq_f) {
+				if ((!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0))) &&
+					(!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0_V2))))
+					pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_3);
+			} else if (irq_f_p) {
+				if ((!(irq_f_p & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0))) &&
+					(!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0_V2))))
+					pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_3);
+			} else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static irqreturn_t pmif_event_4_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	int irq_f = 0, irq_f_p = 0, idx = 0;
+	__pm_stay_awake(arb->pmif_m_Thread_lock);
+	mutex_lock(&arb->pmif_m_mutex);
+	irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_4);
+	if (!IS_ERR(arb->pmif_base[1]))
+		irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_4);
+	if ((irq_f == 0) && (irq_f_p == 0)) {
+		mutex_unlock(&arb->pmif_m_mutex);
+		__pm_relax(arb->pmif_m_Thread_lock);
+		return IRQ_NONE;
+	}
+	for (idx = 0; idx < 32; idx++) {
+		if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) {
+			switch (idx) {
+			default:
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n",
+					__func__, idx);
+			break;
+			}
+			if (irq_f)
+				pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_4);
+			else if (irq_f_p)
+				pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_4);
+			else
+				dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n",
+					__func__, idx);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_m_mutex);
+	__pm_relax(arb->pmif_m_Thread_lock);
+	return IRQ_HANDLED;
+}
+static struct pmif_irq_desc pmif_event_irq[] = {
+	PMIF_IRQDESC(event_0),
+	PMIF_IRQDESC(event_1),
+	PMIF_IRQDESC(event_2),
+	PMIF_IRQDESC(event_3),
+	PMIF_IRQDESC(event_4),
+};
+static void pmif_irq_register(struct platform_device *pdev,
+		struct pmif *arb, int irq)
+{
+	int i = 0, ret = 0;
+	u32 irq_event_en[5] = {0};
+	for (i = 0; i < ARRAY_SIZE(pmif_event_irq); i++) {
+		if (!pmif_event_irq[i].name)
+			continue;
+		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				pmif_event_irq[i].irq_handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_SHARED,
+				pmif_event_irq[i].name, arb);
+		if (ret < 0) {
+			dev_notice(&pdev->dev, "request %s irq fail\n",
+				pmif_event_irq[i].name);
+			continue;
+		}
+		pmif_event_irq[i].irq = irq;
+	}
+	ret = of_property_read_u32_array(pdev->dev.of_node, "irq-event-en",
+		irq_event_en, ARRAY_SIZE(irq_event_en));
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[0] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_0), PMIF_IRQ_EVENT_EN_0);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[1] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_1), PMIF_IRQ_EVENT_EN_1);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[2] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_2), PMIF_IRQ_EVENT_EN_2);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[3] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_3), PMIF_IRQ_EVENT_EN_3);
+	pmif_writel(arb->pmif_base[0], arb, irq_event_en[4] | pmif_readl(arb->pmif_base[0],
+		arb, PMIF_IRQ_EVENT_EN_4), PMIF_IRQ_EVENT_EN_4);
+	if (!IS_ERR(arb->pmif_base[1])) {
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[0] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_0), PMIF_IRQ_EVENT_EN_0);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[1] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_1), PMIF_IRQ_EVENT_EN_1);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[2] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_2), PMIF_IRQ_EVENT_EN_2);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[3] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_3), PMIF_IRQ_EVENT_EN_3);
+		pmif_writel(arb->pmif_base[1], arb, irq_event_en[4] | pmif_readl(arb->pmif_base[1],
+			arb, PMIF_IRQ_EVENT_EN_4), PMIF_IRQ_EVENT_EN_4);
+	}
+}
+static irqreturn_t rcs_irq_handler(int irq, void *data) {
+	struct pmif *arb = data;
+	unsigned int slv_irq_sta, slv_irq_sta_p;
+	int i;
+
+	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
+		slv_irq_sta = mtk_spmi_readl(arb->spmimst_base[0], arb, SPMI_SLV_3_0_EINT + (i / 4));
+		slv_irq_sta = (slv_irq_sta >> ((i % 4) * 8)) & 0xFF;
+		if (!IS_ERR(arb->spmimst_base[1])) {
+			slv_irq_sta_p = mtk_spmi_readl(arb->spmimst_base[1], arb, SPMI_SLV_3_0_EINT + (i / 4));
+			slv_irq_sta_p = (slv_irq_sta_p >> ((i % 4) * 8)) & 0xFF;
+		}
+		if (slv_irq_sta) {
+			mtk_spmi_writel(arb->spmimst_base[0], arb, (0xFF << ((i % 4) * 8)),
+					SPMI_SLV_3_0_EINT + (i / 4));
+			if (arb->rcs_enable_hwirq[i] && slv_irq_sta) {
+				dev_info(&arb->spmic->dev,
+					"hwirq=%d, sta=0x%x\n", i, slv_irq_sta);
+				handle_nested_irq(irq_find_mapping(arb->domain, i));
+			}
+		} else {
+			if (!IS_ERR(arb->spmimst_base[1])) {
+				mtk_spmi_writel(arb->spmimst_base[1], arb, (0xFF << ((i % 4) * 8)),
+					SPMI_SLV_3_0_EINT + (i / 4));
+				if (arb->rcs_enable_hwirq[i] && slv_irq_sta_p) {
+					dev_info(&arb->spmic->dev,
+						"hwirq=%d, sta=0x%x\n", i, slv_irq_sta_p);
+					handle_nested_irq(irq_find_mapping(arb->domain, i));
+				}
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+static int rcs_irq_register(struct platform_device *pdev,
+			    struct pmif *arb, int irq)
+{
+	int i, ret = 0;
+	mutex_init(&arb->rcs_m_irqlock);
+	mutex_init(&arb->rcs_p_irqlock);
+	arb->rcs_enable_hwirq = devm_kcalloc(&pdev->dev, SPMI_MAX_SLAVE_ID,
+					     sizeof(*arb->rcs_enable_hwirq),
+					     GFP_KERNEL);
+	if (!arb->rcs_enable_hwirq)
+		return -ENOMEM;
+	if (arb->rcs_irq == irq)
+		arb->irq_chip = rcs_irq_chip;
+	else if (arb->rcs_irq_p == irq)
+		arb->irq_chip_p = rcs_irq_chip_p;
+	else
+		dev_notice(&pdev->dev, "no rcs irq %d registered\n", irq);
+	arb->domain = irq_domain_add_linear(pdev->dev.of_node,
+					    SPMI_MAX_SLAVE_ID,
+					    &rcs_irq_domain_ops, arb);
+	if (!arb->domain) {
+		dev_notice(&pdev->dev, "Failed to create IRQ domain\n");
+		return -ENODEV;
+	}
+	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
+		mtk_spmi_writel(arb->spmimst_base[0], arb, (0xFF << ((i % 4) * 8)),
+				SPMI_SLV_3_0_EINT + (i / 4));
+		if (!IS_ERR(arb->spmimst_base[1])) {
+			mtk_spmi_writel(arb->spmimst_base[1], arb, (0xFF << ((i % 4) * 8)),
+				SPMI_SLV_3_0_EINT + (i / 4));
+		}
+	}
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					rcs_irq_handler, IRQF_ONESHOT,
+					rcs_irq_chip.name, arb);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "Failed to request IRQ=%d, ret = %d\n",
+			   irq, ret);
+		return ret;
+	}
+	enable_irq_wake(irq);
+	return ret;
+}
 static int mtk_spmi_probe(struct platform_device *pdev)  {
 	struct pmif *arb;
@@ -457,41 +1293,50 @@ static int mtk_spmi_probe(struct platform_device *pdev)
 	if (IS_ERR(ctrl))
 		return PTR_ERR(ctrl);
 
+	ctrl->cmd = pmif_arb_cmd;
+	ctrl->read_cmd = pmif_spmi_read_cmd;
+	ctrl->write_cmd = pmif_spmi_write_cmd;
 	arb = spmi_controller_get_drvdata(ctrl);
+	arb->spmic = ctrl;
 	arb->data = device_get_match_data(&pdev->dev);
 	if (!arb->data) {
 		dev_err(&pdev->dev, "Cannot get drv_data\n");
 		return -EINVAL;
 	}
 
-	arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");
-	if (IS_ERR(arb->base))
-		return PTR_ERR(arb->base);
-
-	arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");
-	if (IS_ERR(arb->spmimst_base))
-		return PTR_ERR(arb->spmimst_base);
-
-	arb->nclks = ARRAY_SIZE(pmif_clock_names);
-	for (i = 0; i < arb->nclks; i++)
-		arb->clks[i].id = pmif_clock_names[i];
-
-	err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
-	if (err) {
-		dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
-		return err;
-	}
-
-	err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
-	if (err) {
-		dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
-		goto err_put_clks;
+	arb->pmif_base[0] = devm_platform_ioremap_resource_byname(pdev, "pmif");
+	if (IS_ERR(arb->pmif_base[0]))
+		return PTR_ERR(arb->pmif_base[0]);
+
+	arb->spmimst_base[0] = devm_platform_ioremap_resource_byname(pdev, "spmimst");
+	if (IS_ERR(arb->spmimst_base[0]))
+		return PTR_ERR(arb->spmimst_base[0]);
+
+	arb->pmif_base[1] = devm_platform_ioremap_resource_byname(pdev, "pmif-p");
+	if (IS_ERR(arb->pmif_base[1]))
+		dev_notice(&pdev->dev, "[PMIF]:no pmif-p found\n");
+	arb->spmimst_base[1] = devm_platform_ioremap_resource_byname(pdev, "spmimst-p");
+	if (IS_ERR(arb->spmimst_base[1]))
+		dev_notice(&pdev->dev, "[PMIF]:no spmimst-p found\n");
+		if (arb->data->caps == 1) {
+
+		arb->nclks = ARRAY_SIZE(pmif_clock_names);
+		for (i = 0; i < arb->nclks; i++)
+			arb->clks[i].id = pmif_clock_names[i];
+
+		err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
+			return err;
+		}
+
+		err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
+			goto err_put_clks;
+		}
 	}
 
-	ctrl->cmd = pmif_arb_cmd;
-	ctrl->read_cmd = pmif_spmi_read_cmd;
-	ctrl->write_cmd = pmif_spmi_write_cmd;
-
 	chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan;
 	arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset;
 	arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset; @@ -499,7 +1344,71 @@ static int mtk_spmi_probe(struct platform_device *pdev)
 	arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;
 	arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;
 
-	raw_spin_lock_init(&arb->lock);
+	raw_spin_lock_init(&arb->lock_m);
+	raw_spin_lock_init(&arb->lock_p);
+	arb->pmif_m_Thread_lock =
+		wakeup_source_register(NULL, "pmif_m wakelock");
+	arb->pmif_p_Thread_lock =
+		wakeup_source_register(NULL, "pmif_p wakelock");
+	mutex_init(&arb->pmif_m_mutex);
+	mutex_init(&arb->pmif_p_mutex);
+	if (arb->data->caps == 2) {
+		arb->irq = platform_get_irq_byname(pdev, "pmif_irq");
+		if (arb->irq < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get pmif_irq, ret = %d\n", arb->irq);
+		}
+		pmif_irq_register(pdev, arb, arb->irq);
+		arb->irq_p = platform_get_irq_byname(pdev, "pmif_p_irq");
+		if (arb->irq_p < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get pmif_p_irq, ret = %d\n", arb->irq_p);
+		}
+		pmif_irq_register(pdev, arb, arb->irq_p);
+		arb->rcs_irq = platform_get_irq_byname(pdev, "rcs_irq");
+		if (arb->rcs_irq < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get rcs_irq, ret = %d\n", arb->rcs_irq);
+		} else {
+			err = rcs_irq_register(pdev, arb, arb->rcs_irq);
+			if (err)
+				dev_notice(&pdev->dev,
+				   "Failed to register rcs_irq, ret = %d\n", arb->rcs_irq);
+		}
+		arb->rcs_irq_p = platform_get_irq_byname(pdev, "rcs_irq_p");
+		if (arb->rcs_irq_p < 0) {
+			dev_notice(&pdev->dev,
+				   "Failed to get rcs_irq_p, ret = %d\n", arb->rcs_irq_p);
+		} else {
+			err = rcs_irq_register(pdev, arb, arb->rcs_irq_p);
+			if (err)
+				dev_notice(&pdev->dev,
+				   "Failed to register rcs_irq_p, ret = %d\n", arb->rcs_irq_p);
+		}
+		arb->spmi_nack_irq = platform_get_irq_byname(pdev, "spmi_nack_irq");
+		if (arb->spmi_nack_irq < 0) {
+			dev_notice(&pdev->dev,
+				"Failed to get spmi_nack_irq, ret = %d\n", arb->spmi_nack_irq);
+		} else {
+			err = spmi_nack_irq_register(pdev, arb, arb->spmi_nack_irq);
+			if (err)
+				dev_notice(&pdev->dev,
+					"Failed to register spmi_nack_irq, ret = %d\n",
+						 arb->spmi_nack_irq);
+		}
+		arb->spmi_p_nack_irq = platform_get_irq_byname(pdev, "spmi_p_nack_irq");
+		if (arb->spmi_p_nack_irq < 0) {
+			dev_notice(&pdev->dev,
+				"Failed to get spmi_p_nack_irq, ret = %d\n", arb->spmi_p_nack_irq);
+		} else {
+			err = spmi_nack_irq_register(pdev, arb, arb->spmi_p_nack_irq);
+			if (err)
+				dev_notice(&pdev->dev,
+					"Failed to register spmi_p_nack_irq, ret = %d\n",
+						 arb->spmi_p_nack_irq);
+		}
+	}
+	spmi_dev_parse(pdev);
 
 	platform_set_drvdata(pdev, ctrl);
 
@@ -533,6 +1442,9 @@ static const struct of_device_id mtk_spmi_match_table[] = {
 	}, {
 		.compatible = "mediatek,mt8195-spmi",
 		.data = &mt8195_pmif_arb,
+	}, {
+		.compatible = "mediatek,mt8196-spmi",
+		.data = &mt6xxx_pmif_arb,
 	}, {
 		/* sentinel */
 	},
--
2.46.0


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

* 回复: [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver
  2025-03-14  7:32 ` [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver Lu.Tang
@ 2025-03-14  9:01   ` Lu Tang (汤璐)
  2025-03-14  9:47     ` Lee Jones
  0 siblings, 1 reply; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:01 UTC (permalink / raw)
  To: Lu Tang (汤璐), Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, AngeloGioacchino Del Regno,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

Update email address

-----邮件原件-----
发件人: Lu.Tang <Lu.Tang@mediatek.com> 
发送时间: 2025年3月14日 15:32
收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
主题: [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver

From: "Lu.Tang" <lu.tang@mediatek.com>

Add spmi pmic mfd driver for mt8196

Signed-off-by: Lu Tang <lu.tang@mediatek.com>
---
 drivers/mfd/Kconfig                  |  26 ++
 drivers/mfd/Makefile                 |   2 +
 drivers/mfd/mt6685-core.c            |  83 +++++
 drivers/mfd/mtk-spmi-pmic.c          | 518 +++++++++++++++++++++++++++
 include/linux/mfd/mt6363/core.h      | 134 +++++++
 include/linux/mfd/mt6363/registers.h | 168 +++++++++
 include/linux/mfd/mt6373/core.h      |  94 +++++
 include/linux/mfd/mt6373/registers.h |  53 +++
 8 files changed, 1078 insertions(+)
 create mode 100644 drivers/mfd/mt6685-core.c  create mode 100644 drivers/mfd/mtk-spmi-pmic.c  create mode 100644 include/linux/mfd/mt6363/core.h  create mode 100644 include/linux/mfd/mt6363/registers.h
 create mode 100644 include/linux/mfd/mt6373/core.h  create mode 100644 include/linux/mfd/mt6373/registers.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d44c69bb3dfd..a62625566893 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1030,6 +1030,32 @@ config MFD_MT6397
 	  accessing the device; additional drivers must be enabled in order
 	  to use the functionality of the device.
 
+config MFD_MT6685
+	tristate "MT6685 SPMI PMIC"
+	depends on OF
+	depends on SPMI
+	select REGMAP_SPMI
+	select REGMAP_IRQ
+	help
+	  This enables support for the Mediatek SPMI PMICs.
+	  These PMICs are currently used with the Mediatek series of
+	  SoCs.  Note, that this will only be useful paired with descriptions
+	  of the independent functions as children nodes in the device tree.
+
+config MFD_MTK_SPMI_PMIC
+	tristate "Mediatek SPMI PMICs"
+	depends on OF
+	depends on SPMI
+	select REGMAP_SPMI
+	help
+	  This enables support for the Mediatek SPMI PMICs.
+	  These PMICs are currently used with the MT63xx 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 SPMI PMIC
+	  series 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 9220eaf7cf12..b8cb34284e56 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -182,6 +182,8 @@ 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_MT6685)	+= mt6685-core.o
+obj-$(CONFIG_MFD_MTK_SPMI_PMIC)	+= mtk-spmi-pmic.o
 
 pcf50633-objs			:= pcf50633-core.o pcf50633-irq.o
 obj-$(CONFIG_MFD_PCF50633)	+= pcf50633.o
diff --git a/drivers/mfd/mt6685-core.c b/drivers/mfd/mt6685-core.c new file mode 100644 index 000000000000..c71008184666
--- /dev/null
+++ b/drivers/mfd/mt6685-core.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 MediaTek Inc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+static const struct mfd_cell mt6685_devs[] = {
+	{
+		.name = "mt6685-clkbuf",
+		.of_compatible = "mediatek,mt6685-clkbuf",
+	}, {
+		.name = "mt6685-tb-clkbuf",
+		.of_compatible = "mediatek,mt6685-tb-clkbuf",
+	}, {
+		.name = "mt6685-rtc",
+		.of_compatible = "mediatek,mt6685-rtc",
+	}, {
+		.name = "mt6685-audclk",
+		.of_compatible = "mediatek,mt6685-audclk",
+	}, {
+		.name = "mt6685-consys",
+		.of_compatible = "mediatek,mt6685-consys",
+	}, {
+		.name = "mt6685-gps",
+		.of_compatible = "mediatek,mt6685-gps",
+	}
+};
+
+static const struct regmap_config spmi_regmap_config = {
+	.reg_bits	= 16,
+	.val_bits	= 8,
+	.max_register	= 0x2000,
+	.fast_io	= true,
+	.use_single_read = true,
+	.use_single_write = true
+};
+
+static int mt6685_spmi_probe(struct spmi_device *sdev) {
+	int ret;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&sdev->dev, "Failed to init mt6685 regmap: %ld\n", PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	ret = devm_mfd_add_devices(&sdev->dev, -1, mt6685_devs,
+				   ARRAY_SIZE(mt6685_devs), NULL, 0, NULL);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to add child devices: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6685_id_table[] = {
+	{ .compatible = "mediatek,mt6685", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6685_id_table);
+
+static struct spmi_driver mt6685_spmi_driver = {
+	.probe = mt6685_spmi_probe,
+	.driver = {
+		.name = "mt6685",
+		.of_match_table = mt6685_id_table,
+	},
+};
+module_spmi_driver(mt6685_spmi_driver);
+
+MODULE_DESCRIPTION("Mediatek SPMI MT6685 Clock IC driver"); 
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>"); MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mtk-spmi-pmic.c b/drivers/mfd/mtk-spmi-pmic.c new file mode 100644 index 000000000000..4c4bed5e991a
--- /dev/null
+++ b/drivers/mfd/mtk-spmi-pmic.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mt6363/core.h>
+#include <linux/mfd/mt6363/registers.h> #include 
+<linux/mfd/mt6373/core.h> #include <linux/mfd/mt6373/registers.h> 
+#include <linux/module.h> #include <linux/mutex.h> #include 
+<linux/of_device.h> #include <linux/of_platform.h> #include 
+<linux/of_irq.h> #include <linux/regmap.h> #include <linux/spmi.h>
+
+#define MTK_SPMI_PMIC_REG_WIDTH	8
+#define PMIC_SWCID		0xB
+#define PMIC_MT6316_SWCID	0x20B
+#define RCS_INT_DONE		0x41B
+
+struct irq_top_t {
+	int hwirq_base;
+	unsigned int num_int_regs;
+	unsigned int en_reg;
+	unsigned int en_reg_shift;
+	unsigned int sta_reg;
+	unsigned int sta_reg_shift;
+	unsigned int top_offset;
+};
+
+struct mtk_spmi_pmic_data {
+	const struct mfd_cell *cells;
+	int cell_size;
+	unsigned int num_top;
+	unsigned int num_pmic_irqs;
+	unsigned short top_int_status_reg;
+	struct irq_top_t *pmic_ints;
+	unsigned int cid_addr;
+};
+
+struct pmic_core {
+	struct device *dev;
+	struct spmi_device *sdev;
+	struct regmap *regmap;
+	u16 chip_id;
+	int irq;
+	bool *enable_hwirq;
+	bool *cache_hwirq;
+	struct mutex irqlock;
+	struct irq_domain *irq_domain;
+	const struct mtk_spmi_pmic_data *chip_data; };
+
+static const struct resource mt6363_regulators_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN15_OC, "VCN15"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN13_OC, "VCN13"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF09_OC, "VRF09"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF12_OC, "VRF12"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF13_OC, "VRF13"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF18_OC, "VRF18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRFIO18_OC, "VRFIO18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_MDFE_OC, "VSRAM_MDFE"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VTREF18_OC, "VTREF18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_APU_OC, "VSRAM_APU"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VAUX18_OC, "VAUX18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VEMC_OC, "VEMC"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS12_OC, "VUFS12"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS18_OC, "VUFS18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO18_OC, "VIO18"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO075_OC, "VIO075"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_1_OC, "VA12_1"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_2_OC, "VA12_2"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA15_OC, "VA15"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VM18_OC, "VM18"), };
+
+static const struct resource mt6363_keys_resources[] = {
+	DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY),
+	DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY),
+	DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY_R),
+	DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY_R),
+};
+
+static const struct resource mt6363_lvsys_notify_resources[] = {
+	/* MT6363 LVSYS interrupt name is contrary,
+	 * we name LVSYS_R to MT6363_IRQ_NI_LVSYS_INT_FALLING;
+	 * LVSYS_F to MT6363_IRQ_NI_LVSYS_INT_RISING
+	 */
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_FALLING, "LVSYS_R"),
+	DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_RISING, "LVSYS_F"), };
+
+static const struct resource mt6373_regulators_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VUSB_OC, "VUSB"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VAUX18_OC, "VAUX18"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF13_AIF_OC, "VRF13_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF18_AIF_OC, "VRF18_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRFIO18_AIF_OC, "VRFIO18_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_1_OC, "VCN33_1"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_2_OC, "VCN33_2"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_3_OC, "VCN33_3"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN18IO_OC, "VCN18IO"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF09_AIF_OC, "VRF09_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF12_AIF_OC, "VRF12_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VANT18_OC, "VANT18"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VSRAM_DIGRF_AIF_OC, "VSRAM_DIGRF_AIF"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VEFUSE_OC, "VEFUSE"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMCH_OC, "VMCH"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMC_OC, "VMC"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIBR_OC, "VIBR"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIO28_OC, "VIO28"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VFP_OC, "VFP"),
+	DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VTP_OC, "VTP"), };
+
+static const struct mfd_cell mt6363_devs[] = {
+	{
+		.name = "mt6363-auxadc",
+		.of_compatible = "mediatek,mt6363-auxadc",
+	}, {
+		.name = "mtk-dynamic-loading-throttling",
+		.of_compatible = "mediatek,mt6363-dynamic_loading_throttling",
+	}, {
+		.name = "mt6363-efuse",
+		.of_compatible = "mediatek,mt6363-efuse",
+	}, {
+		.name = "mt6363-regulator",
+		.num_resources = ARRAY_SIZE(mt6363_regulators_resources),
+		.resources = mt6363_regulators_resources,
+		.of_compatible = "mediatek,mt6363-regulator",
+	}, {
+		.name = "mtk-pmic-keys",
+		.num_resources = ARRAY_SIZE(mt6363_keys_resources),
+		.resources = mt6363_keys_resources,
+		.of_compatible = "mediatek,mt6363-keys"
+	}, {
+		.name = "mt6363-consys",
+		.of_compatible = "mediatek,mt6363-consys",
+	}, {
+		.name = "mt6363-lvsys-notify",
+		.num_resources = ARRAY_SIZE(mt6363_lvsys_notify_resources),
+		.resources = mt6363_lvsys_notify_resources,
+		.of_compatible = "mediatek,mt6363-lvsys-notify",
+	}, {
+		.name = "mt6363-pinctrl",
+		.of_compatible = "mediatek,mt6363-pinctrl",
+	},
+};
+
+static const struct mfd_cell mt6373_devs[] = {
+	{
+		.name = "mt6373-regulator",
+		.num_resources = ARRAY_SIZE(mt6373_regulators_resources),
+		.resources = mt6373_regulators_resources,
+		.of_compatible = "mediatek,mt6373-regulator",
+	}, {
+		.name = "mt6373-auxadc",
+		.of_compatible = "mediatek,mt6373-auxadc",
+	}, {
+		.name = "mt6373-efuse",
+		.of_compatible = "mediatek,mt6373-efuse",
+	}, {
+		.name = "mt6373-consys",
+		.of_compatible = "mediatek,mt6373-consys",
+	}, {
+		.name = "mt6373-pinctrl",
+		.of_compatible = "mediatek,mt6373-pinctrl",
+	},
+};
+
+static struct irq_top_t mt6363_ints[] = {
+	MT6363_TOP_GEN(BUCK),
+	MT6363_TOP_GEN(LDO),
+	MT6363_TOP_GEN(PSC),
+	MT6363_TOP_GEN(MISC),
+	MT6363_TOP_GEN(HK),
+	MT6363_TOP_GEN(BM),
+};
+
+
+static struct irq_top_t mt6373_ints[] = {
+	MT6373_TOP_GEN(BUCK),
+	MT6373_TOP_GEN(LDO),
+	MT6373_TOP_GEN(MISC),
+};
+
+static const struct mtk_spmi_pmic_data mt6316_data = {
+	.num_pmic_irqs = 0,
+	.cid_addr = PMIC_MT6316_SWCID,
+};
+
+static const struct mtk_spmi_pmic_data mt6363_data = {
+	.cells = mt6363_devs,
+	.cell_size = ARRAY_SIZE(mt6363_devs),
+	.num_top = ARRAY_SIZE(mt6363_ints),
+	.num_pmic_irqs = MT6363_IRQ_NR,
+	.top_int_status_reg = MT6363_TOP_INT_STATUS1,
+	.pmic_ints = mt6363_ints,
+};
+
+static const struct mtk_spmi_pmic_data mt6373_data = {
+	.cells = mt6373_devs,
+	.cell_size = ARRAY_SIZE(mt6373_devs),
+	.num_top = ARRAY_SIZE(mt6373_ints),
+	.num_pmic_irqs = MT6373_IRQ_NR,
+	.top_int_status_reg = MT6373_TOP_INT_STATUS1,
+	.pmic_ints = mt6373_ints,
+};
+
+static void mtk_spmi_pmic_irq_enable(struct irq_data *data) {
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+
+	core->enable_hwirq[hwirq] = true;
+}
+
+static void mtk_spmi_pmic_irq_disable(struct irq_data *data) {
+	unsigned int hwirq = irqd_to_hwirq(data);
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+
+	core->enable_hwirq[hwirq] = false;
+}
+
+static void mtk_spmi_pmic_irq_lock(struct irq_data *data) {
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&core->irqlock);
+}
+
+static void mtk_spmi_pmic_irq_sync_unlock(struct irq_data *data) {
+	unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift;
+	struct irq_top_t *pmic_int;
+	struct pmic_core *core = irq_data_get_irq_chip_data(data);
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	for (i = 0; i < chip_data->num_pmic_irqs; i++) {
+		if (core->enable_hwirq[i] == core->cache_hwirq[i])
+			continue;
+
+		/* Find out the IRQ group */
+		top_gp = 0;
+		while ((top_gp + 1) < chip_data->num_top &&
+			i >= chip_data->pmic_ints[top_gp + 1].hwirq_base)
+			top_gp++;
+
+		pmic_int = &(chip_data->pmic_ints[top_gp]);
+		/* Find the IRQ registers */
+		gp_offset = i - pmic_int->hwirq_base;
+		int_regs = gp_offset / MTK_SPMI_PMIC_REG_WIDTH;
+		shift = gp_offset % MTK_SPMI_PMIC_REG_WIDTH;
+		en_reg = pmic_int->en_reg + (pmic_int->en_reg_shift * int_regs);
+
+		regmap_update_bits(core->regmap, en_reg, BIT(shift),
+				   core->enable_hwirq[i] << shift);
+		core->cache_hwirq[i] = core->enable_hwirq[i];
+	}
+	mutex_unlock(&core->irqlock);
+}
+
+static struct irq_chip mtk_spmi_pmic_irq_chip = {
+	.name = "spmi-pmic-irq",
+	.flags = IRQCHIP_SKIP_SET_WAKE,
+	.irq_enable = mtk_spmi_pmic_irq_enable,
+	.irq_disable = mtk_spmi_pmic_irq_disable,
+	.irq_bus_lock = mtk_spmi_pmic_irq_lock,
+	.irq_bus_sync_unlock = mtk_spmi_pmic_irq_sync_unlock, };
+
+static void mtk_spmi_pmic_irq_sp_handler(struct pmic_core *core,
+					 unsigned int top_gp)
+{
+	unsigned int irq_status = 0, sta_reg, status;
+	unsigned int hwirq, virq;
+	int ret, i, j;
+	struct irq_top_t *pmic_int;
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	for (i = 0; i < chip_data->pmic_ints[top_gp].num_int_regs; i++) {
+		pmic_int = &(chip_data->pmic_ints[top_gp]);
+		sta_reg = pmic_int->sta_reg + (pmic_int->sta_reg_shift * i);
+
+		ret = regmap_read(core->regmap, sta_reg, &irq_status);
+		if (ret) {
+			dev_err(core->dev,
+				"Failed to read irq status: %d\n", ret);
+			return;
+		}
+
+		if (!irq_status)
+			continue;
+
+		status = irq_status;
+		do {
+			j = __ffs(status);
+
+			hwirq = pmic_int->hwirq_base + MTK_SPMI_PMIC_REG_WIDTH * i + j;
+
+			virq = irq_find_mapping(core->irq_domain, hwirq);
+			dev_info(core->dev, "[%x]Reg[0x%x]=0x%x,hwirq=%d\n",
+				 core->chip_id, sta_reg, irq_status, hwirq);
+			if (virq)
+				handle_nested_irq(virq);
+
+			status &= ~BIT(j);
+		} while (status);
+
+		regmap_write(core->regmap, sta_reg, irq_status);
+	}
+}
+
+static irqreturn_t mtk_spmi_pmic_irq_handler(int irq, void *data) {
+	int ret;
+	unsigned int bit, i, top_irq_status = 0;
+	struct pmic_core *core = data;
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	ret = regmap_read(core->regmap, chip_data->top_int_status_reg,
+			  &top_irq_status);
+	if (ret) {
+		dev_err(core->dev,
+			"Failed to read status from the device, ret=%d\n", ret);
+		return IRQ_NONE;
+	}
+
+	dev_info(core->dev, "top_irq_sts:0x%x\n", top_irq_status);
+	for (i = 0; i < chip_data->num_top; i++) {
+		bit = BIT(chip_data->pmic_ints[i].top_offset);
+		if (top_irq_status & bit)
+			mtk_spmi_pmic_irq_sp_handler(core, i);
+	}
+
+	ret = regmap_write(core->regmap, RCS_INT_DONE, 1);
+	if (ret) {
+		dev_err(core->dev,
+			"Failed to clear RCS flag, ret=%d\n", ret);
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mtk_spmi_pmic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+					irq_hw_number_t hw)
+{
+	struct pmic_core *core = d->host_data;
+
+	irq_set_chip_data(irq, core);
+	irq_set_chip_and_handler(irq, &mtk_spmi_pmic_irq_chip,
+				 handle_level_irq);
+	irq_set_nested_thread(irq, 1);
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops pmic_irq_domain_ops = {
+	.map = mtk_spmi_pmic_irq_domain_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
+static int mtk_spmi_pmic_irq_init(struct pmic_core *core) {
+	int i, j, ret;
+	unsigned int en_reg, sta_reg;
+	const struct mtk_spmi_pmic_data *chip_data = core->chip_data;
+
+	mutex_init(&core->irqlock);
+	core->enable_hwirq = devm_kcalloc(core->dev,
+					  chip_data->num_pmic_irqs,
+					  sizeof(bool), GFP_KERNEL);
+	if (!core->enable_hwirq)
+		return -ENOMEM;
+
+	core->cache_hwirq = devm_kcalloc(core->dev,
+					 chip_data->num_pmic_irqs,
+					 sizeof(bool), GFP_KERNEL);
+	if (!core->cache_hwirq)
+		return -ENOMEM;
+
+	/* Disable all interrupt for initializing */
+	for (i = 0; i < chip_data->num_top; i++) {
+		for (j = 0; j < chip_data->pmic_ints[i].num_int_regs; j++) {
+			en_reg = chip_data->pmic_ints[i].en_reg +
+				chip_data->pmic_ints[i].en_reg_shift * j;
+			regmap_write(core->regmap, en_reg, 0);
+			sta_reg = chip_data->pmic_ints[i].sta_reg +
+				chip_data->pmic_ints[i].sta_reg_shift * j;
+			regmap_write(core->regmap, sta_reg, 0xFF);
+		}
+	}
+	regmap_write(core->regmap, RCS_INT_DONE, 1);
+
+	core->irq_domain = irq_domain_add_linear(core->dev->of_node,
+						 chip_data->num_pmic_irqs,
+						 &pmic_irq_domain_ops,
+						 core);
+	if (!core->irq_domain) {
+		dev_err(core->dev, "Could not create IRQ domain\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_threaded_irq(core->dev, core->irq, NULL,
+					mtk_spmi_pmic_irq_handler, IRQF_ONESHOT,
+					mtk_spmi_pmic_irq_chip.name, core);
+	if (ret) {
+		dev_err(core->dev, "Failed to register IRQ=%d, ret=%d\n",
+			core->irq, ret);
+		return ret;
+	}
+
+	enable_irq_wake(core->irq);
+	return ret;
+}
+
+static const struct regmap_config spmi_regmap_config = {
+	.reg_bits	= 16,
+	.val_bits	= 8,
+	.max_register	= 0xffff,
+	.fast_io	= true,
+};
+
+static int mtk_spmi_pmic_probe(struct spmi_device *sdev) {
+	int ret;
+	unsigned int id;
+	struct device_node *np = sdev->dev.of_node;
+	struct pmic_core *core;
+	const struct mtk_spmi_pmic_data *chip_data;
+
+	core = devm_kzalloc(&sdev->dev, sizeof(*core), GFP_KERNEL);
+	if (!core)
+		return -ENOMEM;
+
+	core->sdev = sdev;
+	core->dev = &sdev->dev;
+	chip_data = (struct mtk_spmi_pmic_data *)of_device_get_match_data(&sdev->dev);
+	if (!chip_data)
+		return -ENODEV;
+
+	core->chip_data = chip_data;
+	core->regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
+	if (IS_ERR(core->regmap))
+		return PTR_ERR(core->regmap);
+	if (chip_data->cid_addr)
+		ret = regmap_read(core->regmap, chip_data->cid_addr, &id);
+	else
+		ret = regmap_read(core->regmap, PMIC_SWCID, &id);
+	if (ret || id == 0) {
+		dev_err(&sdev->dev, "Failed to read chip id: %d\n", ret);
+		return ret;
+	}
+
+	core->chip_id = id;
+
+	if (chip_data->num_pmic_irqs) {
+		core->irq = of_irq_get(np, 0);
+		if (core->irq < 0)
+			dev_err(&sdev->dev, "Failed to get irq(%d)\n", core->irq);
+
+		ret = mtk_spmi_pmic_irq_init(core);
+		if (ret)
+			dev_err(&sdev->dev, "IRQ_init failed(%d)\n", core->irq);
+
+		ret = devm_mfd_add_devices(&sdev->dev, -1, chip_data->cells,
+					   chip_data->cell_size, NULL, 0,
+					   core->irq_domain);
+		if (ret) {
+			irq_domain_remove(core->irq_domain);
+			dev_err(&sdev->dev, "Failed to add mfd devices: %d\n", ret);
+			return ret;
+		}
+	} else {
+		ret = devm_of_platform_populate(&sdev->dev);
+		if (ret) {
+			dev_err(&sdev->dev, "Failed to platform populate: %d\n", ret);
+			return ret;
+		}
+	}
+
+	device_init_wakeup(&sdev->dev, true);
+
+	dev_dbg(&sdev->dev, "probe chip id=0x%x done\n", core->chip_id);
+
+	return ret;
+}
+
+static const struct of_device_id mtk_spmi_pmic_of_match[] = {
+	{ .compatible = "mediatek,mt6316", .data = &mt6316_data, },
+	{ .compatible = "mediatek,mt6363", .data = &mt6363_data, },
+	{ .compatible = "mediatek,mt6373", .data = &mt6373_data, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mtk_spmi_pmic_of_match);
+
+static struct spmi_driver mtk_spmi_pmic_driver = {
+	.driver = {
+		.name = "mtk-spmi-pmic",
+		.of_match_table = of_match_ptr(mtk_spmi_pmic_of_match),
+	},
+	.probe = mtk_spmi_pmic_probe,
+};
+module_spmi_driver(mtk_spmi_pmic_driver);
+
+MODULE_DESCRIPTION("Mediatek SPMI PMIC driver"); 
+MODULE_ALIAS("spmi:spmi-pmic"); MODULE_LICENSE("GPL"); 
+MODULE_AUTHOR("Argus Lin <argus.lin@mediatek.com>"); 
+MODULE_AUTHOR("Jeter Chen <jeter.chen@mediatek.com>"); 
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
diff --git a/include/linux/mfd/mt6363/core.h b/include/linux/mfd/mt6363/core.h new file mode 100644 index 000000000000..3243a52da34d
--- /dev/null
+++ b/include/linux/mfd/mt6363/core.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6363_CORE_H__
+#define __MFD_MT6363_CORE_H__
+
+#define MT6363_REG_WIDTH 8
+
+enum mt6363_irq_top_status_shift {
+	MT6363_BUCK_TOP = 0,
+	MT6363_LDO_TOP,
+	MT6363_PSC_TOP,
+	MT6363_MISC_TOP,
+	MT6363_HK_TOP,
+	MT6363_SCK_TOP,
+	MT6363_BM_TOP,
+	MT6363_AUD_TOP,
+};
+
+enum mt6363_irq_numbers {
+	MT6363_IRQ_VS2_OC = 0,
+	MT6363_IRQ_VBUCK1_OC,
+	MT6363_IRQ_VBUCK2_OC,
+	MT6363_IRQ_VBUCK3_OC,
+	MT6363_IRQ_VBUCK4_OC,
+	MT6363_IRQ_VBUCK5_OC,
+	MT6363_IRQ_VBUCK6_OC,
+	MT6363_IRQ_VBUCK7_OC,
+	MT6363_IRQ_VS1_OC,
+	MT6363_IRQ_VS3_OC,
+	MT6363_IRQ_VCN15_OC = 16,
+	MT6363_IRQ_VCN13_OC,
+	MT6363_IRQ_VRF09_OC,
+	MT6363_IRQ_VRF12_OC,
+	MT6363_IRQ_VRF13_OC,
+	MT6363_IRQ_VRF18_OC,
+	MT6363_IRQ_VRFIO18_OC,
+	MT6363_IRQ_VSRAM_DIGRF_OC,
+	MT6363_IRQ_VSRAM_MDFE_OC,
+	MT6363_IRQ_VSRAM_MODEM_OC,
+	MT6363_IRQ_VTREF18_OC,
+	MT6363_IRQ_VSRAM_CPUB_OC,
+	MT6363_IRQ_VSRAM_CPUM_OC,
+	MT6363_IRQ_VSRAM_CPUL_OC,
+	MT6363_IRQ_VSRAM_APU_OC,
+	MT6363_IRQ_VAUX18_OC,
+	MT6363_IRQ_VEMC_OC,
+	MT6363_IRQ_VUFS12_OC,
+	MT6363_IRQ_VUFS18_OC,
+	MT6363_IRQ_VIO18_OC,
+	MT6363_IRQ_VIO075_OC,
+	MT6363_IRQ_VA12_1_OC,
+	MT6363_IRQ_VA12_2_OC,
+	MT6363_IRQ_VA15_OC,
+	MT6363_IRQ_VM18_OC,
+	MT6363_IRQ_PWRKEY = 48,
+	MT6363_IRQ_HOMEKEY,
+	MT6363_IRQ_HOMEKEY_2,
+	MT6363_IRQ_PWRKEY_R,
+	MT6363_IRQ_HOMEKEY_R,
+	MT6363_IRQ_HOMEKEY_2_R,
+	MT6363_IRQ_NI_LVSYS_INT_FALLING,
+	MT6363_IRQ_NI_LVSYS_INT_RISING,
+	MT6363_IRQ_CHRDET_LEVEL,
+	MT6363_IRQ_CHRDET_EDGE,
+	MT6363_IRQ_RCS0 = 64,
+	MT6363_IRQ_SPMI_CMD_ALERT,
+	MT6363_IRQ_BM_PROTREG = 70,
+	MT6363_IRQ_BUCK_PROTREG = 72,
+	MT6363_IRQ_LDO_PROTREG,
+	MT6363_IRQ_PSC_PROTREG,
+	MT6363_IRQ_PLT_PROTREG,
+	MT6363_IRQ_HK_PROTREG,
+	MT6363_IRQ_TOP_PROTREG = 79,
+	MT6363_IRQ_BAT_H,
+	MT6363_IRQ_BAT_L,
+	MT6363_IRQ_BAT2_H,
+	MT6363_IRQ_BAT2_L,
+	MT6363_IRQ_BAT_TEMP_H,
+	MT6363_IRQ_BAT_TEMP_L,
+	MT6363_IRQ_THR_H,
+	MT6363_IRQ_THR_L,
+	MT6363_IRQ_AUXADC_IMP,
+	MT6363_IRQ_NAG_C_DLTV,
+	MT6363_IRQ_FG_BAT_H = 88,
+	MT6363_IRQ_FG_BAT_L,
+	MT6363_IRQ_FG_CUR_H,
+	MT6363_IRQ_FG_CUR_L,
+	MT6363_IRQ_FG_ZCV,
+	MT6363_IRQ_FG_N_CHARGE_L = 95,
+	MT6363_IRQ_FG_IAVG_H,
+	MT6363_IRQ_FG_IAVG_L,
+	MT6363_IRQ_FG_DISCHARGE = 99,
+	MT6363_IRQ_FG_CHARGE,
+	MT6363_IRQ_BATON_LV = 104,
+	MT6363_IRQ_BATON_BAT_IN = 106,
+	MT6363_IRQ_BATON_BAT_OUT,
+	MT6363_IRQ_NR = 108,
+};
+
+#define MT6363_IRQ_BUCK_BASE MT6363_IRQ_VS2_OC #define 
+MT6363_IRQ_LDO_BASE MT6363_IRQ_VCN15_OC #define MT6363_IRQ_PSC_BASE 
+MT6363_IRQ_PWRKEY #define MT6363_IRQ_MISC_BASE MT6363_IRQ_RCS0 #define 
+MT6363_IRQ_HK_BASE MT6363_IRQ_BAT_H #define MT6363_IRQ_BM_BASE 
+MT6363_IRQ_FG_BAT_H
+
+#define MT6363_IRQ_BUCK_BITS \
+	(MT6363_IRQ_VS3_OC - MT6363_IRQ_BUCK_BASE + 1) #define 
+MT6363_IRQ_LDO_BITS \
+	(MT6363_IRQ_VM18_OC - MT6363_IRQ_LDO_BASE + 1) #define 
+MT6363_IRQ_PSC_BITS \
+	(MT6363_IRQ_CHRDET_EDGE - MT6363_IRQ_PSC_BASE + 1) #define 
+MT6363_IRQ_MISC_BITS \
+	(MT6363_IRQ_TOP_PROTREG - MT6363_IRQ_MISC_BASE + 1) #define 
+MT6363_IRQ_HK_BITS \
+	(MT6363_IRQ_NAG_C_DLTV - MT6363_IRQ_HK_BASE + 1) #define 
+MT6363_IRQ_BM_BITS \
+	(MT6363_IRQ_BATON_BAT_OUT - MT6363_IRQ_BM_BASE + 1)
+
+#define MT6363_TOP_GEN(sp) \
+{ \
+	.hwirq_base = MT6363_IRQ_##sp##_BASE, \
+	.num_int_regs =	((MT6363_IRQ_##sp##_BITS - 1) / MT6363_REG_WIDTH) + 1, \
+	.en_reg = MT6363_##sp##_TOP_INT_CON0, \
+	.en_reg_shift = 0x3, \
+	.sta_reg = MT6363_##sp##_TOP_INT_STATUS0, \
+	.sta_reg_shift = 0x1, \
+	.top_offset = MT6363_##sp##_TOP, \
+}
+
+#endif /* __MFD_MT6363_CORE_H__ */
diff --git a/include/linux/mfd/mt6363/registers.h b/include/linux/mfd/mt6363/registers.h
new file mode 100644
index 000000000000..e22ca686a7d0
--- /dev/null
+++ b/include/linux/mfd/mt6363/registers.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+
+#ifndef __MFD_MT6363_REGISTERS_H__
+#define __MFD_MT6363_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6363_TOPSTATUS		   (0x1e)
+#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_STRUP_CON11		   (0xa0e)
+#define MT6363_STRUP_CON12		   (0xa0f)
+#define MT6363_PCHR_VREF_ANA_CON1          (0xa89)
+#define MT6363_PCHR_VREF_ANA_CON2          (0xa8a)
+#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)
+
+/* voter */
+#define MT6363_BUCK_VS2_VOTER_CON0         (0x149a)
+#define MT6363_BUCK_VS2_VOTER_CON0_SET     (0x149b)
+#define MT6363_BUCK_VS2_VOTER_CON0_CLR     (0x149c)
+#define MT6363_BUCK_VS2_VOTER_CON1         (0x149d)
+#define MT6363_BUCK_VS2_VOTER_CON1_SET     (0x149e)
+#define MT6363_BUCK_VS2_VOTER_CON1_CLR     (0x149f)
+#define MT6363_BUCK_VS2_VOTER_CFG          (0x14a0)
+#define MT6363_BUCK_VS1_VOTER_CON0         (0x189a)
+#define MT6363_BUCK_VS1_VOTER_CON0_SET     (0x189b)
+#define MT6363_BUCK_VS1_VOTER_CON0_CLR     (0x189c)
+#define MT6363_BUCK_VS1_VOTER_CON1         (0x189d)
+#define MT6363_BUCK_VS1_VOTER_CON1_SET     (0x189e)
+#define MT6363_BUCK_VS1_VOTER_CON1_CLR     (0x189f)
+#define MT6363_BUCK_VS1_VOTER_CFG          (0x18a0)
+#define MT6363_BUCK_VS3_VOTER_CON0         (0x191a)
+#define MT6363_BUCK_VS3_VOTER_CON0_SET     (0x191b)
+#define MT6363_BUCK_VS3_VOTER_CON0_CLR     (0x191c)
+#define MT6363_BUCK_VS3_VOTER_CON1         (0x191d)
+#define MT6363_BUCK_VS3_VOTER_CON1_SET     (0x191e)
+#define MT6363_BUCK_VS3_VOTER_CON1_CLR     (0x191f)
+#define MT6363_BUCK_VS3_VOTER_CFG          (0x1920)
+
+#define MT6363_CHRDET_DEB_ADDR             MT6363_TOPSTATUS
+#define MT6363_CHRDET_DEB_MASK             (0x1)
+#define MT6363_CHRDET_DEB_SHIFT            (2)
+#define MT6363_RG_VBB_UVLO_VTHL_ADDR       MT6363_PCHR_VREF_ANA_CON1
+#define MT6363_RG_VBB_UVLO_VTHL_MASK       (0xF)
+#define MT6363_RG_VBB_UVLO_VTHL_SHIFT      (0)
+#define MT6363_RG_VSYS_UVLO_VTHL_ADDR      MT6363_PCHR_VREF_ANA_CON2
+#define MT6363_RG_VSYS_UVLO_VTHL_MASK      (0xF)
+#define MT6363_RG_VSYS_UVLO_VTHL_SHIFT     (0)
+
+#define MT6363_AUXADC_ADC0_L               (0x1088)
+#define MT6363_AUXADC_ADC3_L               (0x108e)
+#define MT6363_AUXADC_ADC4_L               (0x1090)
+#define MT6363_AUXADC_ADC11_L              (0x109e)
+#define MT6363_AUXADC_ADC38_L              (0x10c4)
+#define MT6363_AUXADC_ADC39_L              (0x10c6)
+#define MT6363_AUXADC_ADC40_L              (0x10c8)
+#define MT6363_AUXADC_ADC_CH12_L           (0x10d2)
+#define MT6363_AUXADC_ADC_CH14_L           (0x10d8)
+#define MT6363_AUXADC_ADC42_L              (0x10dc)
+#define MT6363_AUXADC_RQST0                (0x1108)
+#define MT6363_AUXADC_RQST1                (0x1109)
+#define MT6363_AUXADC_RQST3                (0x110c)
+#define MT6363_SDMADC_RQST0                (0x110e)
+#define MT6363_SDMADC_CON0                 (0x11c4)
+#define MT6363_AUXADC_IMP0                 (0x1208)
+#define MT6363_AUXADC_IMP1                 (0x1209)
+
+/* voter */
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_ADDR                 \
+	MT6363_BUCK_VS2_VOTER_CON0
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SHIFT                (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON0_SET
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON0_CLR
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_ADDR                 \
+	MT6363_BUCK_VS2_VOTER_CON1
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_MASK                 (0xF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SHIFT                (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON1_SET
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_MASK             (0xF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_ADDR             \
+	MT6363_BUCK_VS2_VOTER_CON1_CLR
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_MASK             (0xF)
+#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_ADDR                 \
+	MT6363_BUCK_VS2_VOTER_CFG
+#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_SHIFT                (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_ADDR                 \
+	MT6363_BUCK_VS1_VOTER_CON0
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SHIFT                (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON0_SET
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON0_CLR
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_ADDR                 \
+	MT6363_BUCK_VS1_VOTER_CON1
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_MASK                 (0xF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SHIFT                (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON1_SET
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_MASK             (0xF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_ADDR             \
+	MT6363_BUCK_VS1_VOTER_CON1_CLR
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_MASK             (0xF)
+#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_ADDR                 \
+	MT6363_BUCK_VS1_VOTER_CFG
+#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_SHIFT                (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_ADDR                 \
+	MT6363_BUCK_VS3_VOTER_CON0
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SHIFT                (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON0_SET
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON0_CLR
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_MASK             (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_ADDR                 \
+	MT6363_BUCK_VS3_VOTER_CON1
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_MASK                 (0xF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SHIFT                (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON1_SET
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_MASK             (0xF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_ADDR             \
+	MT6363_BUCK_VS3_VOTER_CON1_CLR
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_MASK             (0xF)
+#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_SHIFT            (0)
+#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_ADDR                 \
+	MT6363_BUCK_VS3_VOTER_CFG
+#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_MASK                 (0xFF)
+#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_SHIFT                (0)
+
+#endif /* __MFD_MT6363_REGISTERS_H__ */
+
diff --git a/include/linux/mfd/mt6373/core.h b/include/linux/mfd/mt6373/core.h new file mode 100644 index 000000000000..dd77d8cf29a2
--- /dev/null
+++ b/include/linux/mfd/mt6373/core.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6373_CORE_H__
+#define __MFD_MT6373_CORE_H__
+
+#define MT6373_REG_WIDTH 8
+
+enum mt6373_irq_top_status_shift {
+	MT6373_BUCK_TOP = 0,
+	MT6373_LDO_TOP,
+	MT6373_PSC_TOP,
+	MT6373_MISC_TOP,
+	MT6373_HK_TOP,
+	MT6373_SCK_TOP,
+	MT6373_BM_TOP,
+	MT6373_AUD_TOP,
+};
+
+enum mt6373_irq_numbers {
+	MT6373_IRQ_VBUCK0_OC,
+	MT6373_IRQ_VBUCK1_OC,
+	MT6373_IRQ_VBUCK2_OC,
+	MT6373_IRQ_VBUCK3_OC,
+	MT6373_IRQ_VBUCK4_OC,
+	MT6373_IRQ_VBUCK5_OC,
+	MT6373_IRQ_VBUCK6_OC,
+	MT6373_IRQ_VBUCK7_OC,
+	MT6373_IRQ_VBUCK8_OC,
+	MT6373_IRQ_VBUCK9_OC,
+	MT6373_IRQ_VAUD18_OC = 16,
+	MT6373_IRQ_VUSB_OC,
+	MT6373_IRQ_VAUX18_OC,
+	MT6373_IRQ_VRF13_AIF_OC,
+	MT6373_IRQ_VRF18_AIF_OC,
+	MT6373_IRQ_VRFIO18_AIF_OC,
+	MT6373_IRQ_VCN33_1_OC,
+	MT6373_IRQ_VCN33_2_OC,
+	MT6373_IRQ_VCN33_3_OC,
+	MT6373_IRQ_VCN18IO_OC,
+	MT6373_IRQ_VRF09_AIF_OC,
+	MT6373_IRQ_VRF12_AIF_OC,
+	MT6373_IRQ_VANT18_OC,
+	MT6373_IRQ_VSRAM_DIGRF_AIF_OC,
+	MT6373_IRQ_VMDDR_OC,
+	MT6373_IRQ_VEFUSE_OC,
+	MT6373_IRQ_VMCH_OC,
+	MT6373_IRQ_VMC_OC,
+	MT6373_IRQ_VIBR_OC,
+	MT6373_IRQ_VIO28_OC,
+	MT6373_IRQ_VFP_OC,
+	MT6373_IRQ_VTP_OC,
+	MT6373_IRQ_VSIM1_OC,
+	MT6373_IRQ_VSIM2_OC,
+	MT6373_IRQ_RCS0 = 56,
+	MT6373_IRQ_SPMI_CMD_ALERT,
+	MT6373_IRQ_BM_PROTREG = 62,
+	MT6373_IRQ_VRC_PROTREG,
+	MT6373_IRQ_BUCK_PROTREG = 64,
+	MT6373_IRQ_LDO_PROTREG,
+	MT6373_IRQ_PSC_PROTREG,
+	MT6373_IRQ_PLT_PROTREG,
+	MT6373_IRQ_HK_PROTREG,
+	MT6373_IRQ_SCK_PROTREG,
+	MT6373_IRQ_XPP_PROTREG,
+	MT6373_IRQ_TOP_PROTREG,
+	MT6373_IRQ_NR = 72,
+};
+
+#define MT6373_IRQ_BUCK_BASE MT6373_IRQ_VBUCK0_OC #define 
+MT6373_IRQ_LDO_BASE MT6373_IRQ_VAUD18_OC #define MT6373_IRQ_MISC_BASE 
+MT6373_IRQ_RCS0
+
+#define MT6373_IRQ_BUCK_BITS \
+	(MT6373_IRQ_VBUCK9_OC - MT6373_IRQ_BUCK_BASE + 1) #define 
+MT6373_IRQ_LDO_BITS \
+	(MT6373_IRQ_VSIM2_OC - MT6373_IRQ_LDO_BASE + 1) #define 
+MT6373_IRQ_MISC_BITS \
+	(MT6373_IRQ_TOP_PROTREG - MT6373_IRQ_MISC_BASE + 1)
+
+#define MT6373_TOP_GEN(sp) \
+{ \
+	.hwirq_base = MT6373_IRQ_##sp##_BASE, \
+	.num_int_regs =	((MT6373_IRQ_##sp##_BITS - 1) / MT6373_REG_WIDTH) + 1, \
+	.en_reg = MT6373_##sp##_TOP_INT_CON0, \
+	.en_reg_shift = 0x3, \
+	.sta_reg = MT6373_##sp##_TOP_INT_STATUS0, \
+	.sta_reg_shift = 0x1, \
+	.top_offset = MT6373_##sp##_TOP, \
+}
+
+#endif /* __MFD_MT6373_CORE_H__ */
diff --git a/include/linux/mfd/mt6373/registers.h b/include/linux/mfd/mt6373/registers.h
new file mode 100644
index 000000000000..05aef78abfdf
--- /dev/null
+++ b/include/linux/mfd/mt6373/registers.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+
+#ifndef __MFD_MT6373_REGISTERS_H__
+#define __MFD_MT6373_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6373_TOPSTATUS                       0x1e
+#define MT6373_MISC_TOP_INT_CON0               0x3c
+#define MT6373_MISC_TOP_INT_CON1               0x3f
+#define MT6373_MISC_TOP_INT_STATUS0            0x48
+#define MT6373_MISC_TOP_INT_STATUS1            0x49
+#define MT6373_TOP_INT_MASK_CON0               0x4c
+#define MT6373_TOP_INT_MASK_CON0_SET           0x4d
+#define MT6373_TOP_INT_MASK_CON0_CLR           0x4e
+#define MT6373_TOP_INT_MASK_CON1               0x4f
+#define MT6373_TOP_INT_MASK_CON1_SET           0x50
+#define MT6373_TOP_INT_MASK_CON1_CLR           0x51
+#define MT6373_TOP_INT_STATUS0                 0x52
+#define MT6373_TOP_INT_STATUS1                 0x53
+#define MT6373_HK_TOP_INT_CON0                 0xf92
+#define MT6373_HK_TOP_INT_CON1                 0xf95
+#define MT6373_HK_TOP_INT_STATUS0              0xf9e
+#define MT6373_HK_TOP_INT_STATUS1              0xf9f
+#define MT6373_AUXADC_ADC4_L                   0x1090
+#define MT6373_AUXADC_ADC38_L                  0x10c4
+#define MT6373_AUXADC_ADC39_L                  0x10c6
+#define MT6373_AUXADC_ADC40_L                  0x10c8
+#define MT6373_AUXADC_ADC_CH12_L               0x10d2
+#define MT6373_AUXADC_ADC_CH12_H               0x10d3
+#define MT6373_AUXADC_RQST0                    0x1108
+#define MT6373_AUXADC_RQST1                    0x1109
+#define MT6373_AUXADC_RQST3                    0x110c
+#define MT6373_SDMADC_RQST0                    0x110e
+#define MT6373_SDMADC_CON0                     0x11c4
+#define MT6373_BUCK_TOP_INT_CON0               0x1411
+#define MT6373_BUCK_TOP_INT_CON1               0x1414
+#define MT6373_BUCK_TOP_INT_STATUS0            0x141d
+#define MT6373_BUCK_TOP_INT_STATUS1            0x141e
+#define MT6373_LDO_TOP_INT_CON0                0x1b10
+#define MT6373_LDO_TOP_INT_CON1                0x1b13
+#define MT6373_LDO_TOP_INT_CON2                0x1b16
+#define MT6373_LDO_TOP_INT_STATUS0             0x1b22
+#define MT6373_LDO_TOP_INT_STATUS1             0x1b23
+#define MT6373_LDO_TOP_INT_STATUS2             0x1b24
+#define MT6373_LDO_VMCH_CON0                   0x1cb1
+#define MT6373_LDO_VMCH_CON1                   0x1cb2
+#define MT6373_LDO_VMCH_CON2                   0x1cb3
+
+#endif /* __MFD_MT6373_REGISTERS_H__ */
--
2.46.0


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

* 回复: [PATCH 2/5] pmic: mediatek: Add pmic regulator driver
  2025-03-14  7:32 ` [PATCH 2/5] pmic: mediatek: Add pmic regulator driver Lu.Tang
  2025-03-14  8:26   ` Chen-Yu Tsai
@ 2025-03-14  9:02   ` Lu Tang (汤璐)
  1 sibling, 0 replies; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:02 UTC (permalink / raw)
  To: Lu Tang (汤璐), Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, AngeloGioacchino Del Regno,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group


Update email address

-----邮件原件-----
发件人: Lu.Tang <Lu.Tang@mediatek.com> 
发送时间: 2025年3月14日 15:32
收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
主题: [PATCH 2/5] pmic: mediatek: Add pmic regulator driver

From: "Lu.Tang" <lu.tang@mediatek.com>

Add pmic mt6316/mt6373/mt6363 regulator driver

Signed-off-by: Lu Tang <lu.tang@mediatek.com>
---
 drivers/regulator/Kconfig                  |   34 +
 drivers/regulator/Makefile                 |    3 +
 drivers/regulator/mt6316-regulator.c       |  381 +++++++
 drivers/regulator/mt6363-regulator.c       | 1106 ++++++++++++++++++++
 drivers/regulator/mt6373-regulator.c       |  826 +++++++++++++++
 include/linux/regulator/mt6316-regulator.h |   48 +
 include/linux/regulator/mt6363-regulator.h |  424 ++++++++
 include/linux/regulator/mt6373-regulator.h |  318 ++++++
 8 files changed, 3140 insertions(+)
 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/regulator/mt6316-regulator.h
 create mode 100644 include/linux/regulator/mt6363-regulator.h
 create mode 100644 include/linux/regulator/mt6373-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 39297f7d8177..7b2d47fee535 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -853,6 +853,16 @@ config REGULATOR_MT6315
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6316
+	tristate "MediaTek MT6316 PMIC"
+	depends on SPMI
+	select REGMAP_SPMI
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6316 PMIC.
+	  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
@@ -916,6 +926,18 @@ 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 Regulator driver"
+	depends on MFD_MTK_SPMI_PMIC
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6363 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
+	  The driver can also be build as a module.
+	  If so, the module will be called mt6363_regulator
+
 config REGULATOR_MT6370
 	tristate "MT6370 SubPMIC Regulator"
 	depends on MFD_MT6370
@@ -924,6 +946,18 @@ 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 Regulator driver"
+	depends on MFD_MTK_SPMI_PMIC
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6373 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
+	  The driver can also be build as a module.
+	  If so, the module will be called mt6373_regulator
+
 config REGULATOR_MT6380
 	tristate "MediaTek MT6380 PMIC"
 	depends on MTK_PMIC_WRAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3d5a803dce8a..b54a64522499 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -102,6 +102,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_MT6316) += mt6316-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6331)	+= mt6331-regulator.o
 obj-$(CONFIG_REGULATOR_MT6332)	+= mt6332-regulator.o
@@ -109,7 +110,9 @@ 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_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/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c
new file mode 100644
index 000000000000..1c069a0d4cff
--- /dev/null
+++ b/drivers/regulator/mt6316-regulator.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6316-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SET_OFFSET	0x1
+#define CLR_OFFSET	0x2
+
+#define MT6316_REG_WIDTH	8
+
+#define MT6316_BUCK_MODE_AUTO		0
+#define MT6316_BUCK_MODE_FORCE_PWM	1
+#define MT6316_BUCK_MODE_NORMAL		0
+#define MT6316_BUCK_MODE_LP		2
+
+#define BUCK_PHASE_3			3
+#define BUCK_PHASE_4			4
+
+struct mt6316_regulator_info {
+	struct regulator_desc desc;
+	u32 da_reg;
+	u32 qi;
+	u32 modeset_reg;
+	u32 modeset_mask;
+	u32 lp_mode_reg;
+	u32 lp_mode_mask;
+	u32 lp_mode_shift;
+};
+
+struct mt6316_init_data {
+	u32 id;
+	u32 size;
+};
+
+struct mt6316_chip {
+	struct device *dev;
+	struct regmap *regmap;
+	u32 slave_id;
+};
+
+#define MT_BUCK(match, _name, volt_ranges, _bid, _vsel)	\
+[MT6316_ID_##_name] = {					\
+	.desc = {					\
+		.name = #_name,				\
+		.of_match = of_match_ptr(match),	\
+		.ops = &mt6316_volt_range_ops,		\
+		.type = REGULATOR_VOLTAGE,		\
+		.id = MT6316_ID_##_name,		\
+		.owner = THIS_MODULE,			\
+		.n_voltages = 0x1ff,			\
+		.linear_ranges = volt_ranges,		\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),\
+		.vsel_reg = _vsel,			\
+		.vsel_mask = 0xff,			\
+		.enable_reg = MT6316_BUCK_TOP_CON0,	\
+		.enable_mask = BIT(_bid - 1),		\
+		.of_map_mode = mt6316_map_mode,		\
+	},						\
+	.da_reg = MT6316_VBUCK##_bid##_DBG8,		\
+	.qi = BIT(0),					\
+	.lp_mode_reg = MT6316_BUCK_TOP_CON1,		\
+	.lp_mode_mask = BIT(_bid - 1),			\
+	.lp_mode_shift = _bid - 1,			\
+	.modeset_reg = MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0,\
+	.modeset_mask = BIT(_bid - 1),			\
+}
+
+static const struct linear_range mt_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(0, 0, 0x1fe, 2500),
+};
+
+static int mt6316_regulator_enable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6316_regulator_disable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + CLR_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+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_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+	unsigned short reg_val = 0;
+	int ret = 0;
+
+	reg_val = ((selector & 0x1) << 8) | (selector >> 1);
+	ret = regmap_bulk_write(rdev->regmap, rdev->desc->vsel_reg, (u8 *) &reg_val, 2);
+
+	return ret;
+}
+
+static int mt6316_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	unsigned int reg_val = 0;
+
+	ret = regmap_bulk_read(rdev->regmap, rdev->desc->vsel_reg, (u8 *) &reg_val, 2);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get mt6316 regulator voltage: %d\n", ret);
+		return ret;
+	}
+	ret = ((reg_val >> 8) & 0x1) + ((reg_val & rdev->desc->vsel_mask) << 1);
+
+	return ret;
+}
+
+static unsigned int mt6316_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6316_regulator_info *info;
+	int ret = 0, regval = 0;
+	u32 modeset_mask;
+
+	info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get mt6316 buck mode: %d\n", ret);
+		return ret;
+	}
+
+	modeset_mask = info->modeset_mask;
+
+	if ((regval & modeset_mask) == modeset_mask)
+		return REGULATOR_MODE_FAST;
+
+	ret = regmap_read(rdev->regmap, info->lp_mode_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get mt6316 buck lp mode: %d\n", ret);
+		return ret;
+	}
+
+	if (regval & info->lp_mode_mask)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6316_regulator_set_mode(struct regulator_dev *rdev, u32 mode)
+{
+	struct mt6316_regulator_info *info;
+	int ret = 0, val, curr_mode;
+	u32 modeset_mask;
+
+	info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
+	modeset_mask = info->modeset_mask;
+
+	curr_mode = mt6316_regulator_get_mode(rdev);
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+					 modeset_mask, modeset_mask);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		if (curr_mode == REGULATOR_MODE_FAST) {
+			ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+						 modeset_mask, 0);
+		} else if (curr_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg,
+						 info->lp_mode_mask, 0);
+			usleep_range(100, 110);
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		val = MT6316_BUCK_MODE_LP >> 1;
+		val <<= info->lp_mode_shift;
+		ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, info->lp_mode_mask, val);
+		break;
+	default:
+		ret = -EINVAL;
+		goto err_mode;
+	}
+
+err_mode:
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to set mt6316 buck mode: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt6316_get_status(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	u32 regval = 0;
+	struct mt6316_regulator_info *info;
+
+	info = container_of(rdev->desc, struct mt6316_regulator_info, desc);
+	ret = regmap_read(rdev->regmap, info->da_reg, &regval);
+	if (ret != 0) {
+		dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static void mt6316_buck_phase_init(struct mt6316_chip *chip, unsigned int *s6_buck_phase)
+{
+	int ret = 0;
+	u32 val = 0;
+
+	ret = regmap_read(chip->regmap, MT6316_BUCK_TOP_4PHASE_TOP_ELR_0, &val);
+	if (ret) {
+		dev_err(chip->dev, "Failed to get mt6316 buck phase: %d\n", ret);
+		return;
+	}
+
+	dev_info(chip->dev, "S%d RG_4PH_CONFIG:%d\n", chip->slave_id, val);
+	if (chip->slave_id == MT6316_SLAVE_ID_6)
+		*s6_buck_phase = val;
+}
+
+static const struct regulator_ops mt6316_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.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_regulator_enable,
+	.disable = mt6316_regulator_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6316_get_status,
+	.set_mode = mt6316_regulator_set_mode,
+	.get_mode = mt6316_regulator_get_mode,
+};
+
+static struct mt6316_regulator_info mt6316_regulators[] = {
+	MT_BUCK("vbuck1", VBUCK1, mt_volt_range1, 1, MT6316_BUCK_TOP_ELR0),
+	MT_BUCK("vbuck2", VBUCK2, mt_volt_range1, 2, MT6316_BUCK_TOP_ELR2),
+	MT_BUCK("vbuck3", VBUCK3, mt_volt_range1, 3, MT6316_BUCK_TOP_ELR4),
+	MT_BUCK("vbuck4", VBUCK4, mt_volt_range1, 4, MT6316_BUCK_TOP_ELR6),
+};
+
+static struct mt6316_init_data mt6316_3_init_data = {
+	.id = MT6316_SLAVE_ID_3,
+	.size = MT6316_ID_3_MAX,
+};
+
+static struct mt6316_init_data mt6316_6_init_data = {
+	.id = MT6316_SLAVE_ID_6,
+	.size = MT6316_ID_6_MAX,
+};
+
+static struct mt6316_init_data mt6316_7_init_data = {
+	.id = MT6316_SLAVE_ID_7,
+	.size = MT6316_ID_7_MAX,
+};
+
+static struct mt6316_init_data mt6316_8_init_data = {
+	.id = MT6316_SLAVE_ID_8,
+	.size = MT6316_ID_8_MAX,
+};
+
+static struct mt6316_init_data mt6316_15_init_data = {
+	.id = MT6316_SLAVE_ID_15,
+	.size = MT6316_ID_15_MAX,
+};
+
+static const struct of_device_id mt6316_of_match[] = {
+	{
+		.compatible = "mediatek,mt6316-3-regulator",
+		.data = &mt6316_3_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-6-regulator",
+		.data = &mt6316_6_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-7-regulator",
+		.data = &mt6316_7_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-8-regulator",
+		.data = &mt6316_8_init_data,
+	}, {
+		.compatible = "mediatek,mt6316-15-regulator",
+		.data = &mt6316_15_init_data,
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, mt6316_of_match);
+
+static int mt6316_regulator_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+	struct mt6316_init_data *pdata;
+	struct mt6316_chip *chip;
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	struct device_node *node = pdev->dev.of_node;
+	u32 val = 0;
+	int i;
+	unsigned int s6_buck_phase;
+
+	regmap = dev_get_regmap(dev->parent, NULL);
+	if (!regmap)
+		return -ENODEV;
+
+	chip = devm_kzalloc(dev, sizeof(struct mt6316_chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	of_id = of_match_device(mt6316_of_match, dev);
+	if (!of_id || !of_id->data)
+		return -ENODEV;
+
+	pdata = (struct mt6316_init_data *)of_id->data;
+	chip->slave_id = pdata->id;
+	if (!of_property_read_u32(node, "buck-size", &val))
+		pdata->size = val;
+	chip->dev = dev;
+	chip->regmap = regmap;
+	dev_set_drvdata(dev, chip);
+
+	dev->fwnode = &(dev->of_node->fwnode);
+	if (dev->fwnode && !dev->fwnode->dev)
+		dev->fwnode->dev = dev;
+
+	config.dev = dev;
+	config.driver_data = pdata;
+	config.regmap = regmap;
+
+	mt6316_buck_phase_init(chip, &s6_buck_phase);
+	for (i = 0; i < pdata->size; i++) {
+		if (pdata->id == MT6316_SLAVE_ID_6 &&
+		    s6_buck_phase == BUCK_PHASE_4 &&
+		    (mt6316_regulators + i)->desc.id == MT6316_ID_VBUCK3) {
+			dev_info(dev, "skip registering %s.\n", (mt6316_regulators + i)->desc.name);
+			continue;
+		}
+
+		rdev = devm_regulator_register(dev, &(mt6316_regulators + i)->desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(dev, "failed to register %s\n", (mt6316_regulators + i)->desc.name);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver mt6316_regulator_driver = {
+	.driver		= {
+		.name	= "mt6316-regulator",
+		.of_match_table = mt6316_of_match,
+	},
+	.probe = mt6316_regulator_probe,
+};
+
+module_platform_driver(mt6316_regulator_driver);
+
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6316 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
new file mode 100644
index 000000000000..cdb280110a9a
--- /dev/null
+++ b/drivers/regulator/mt6363-regulator.c
@@ -0,0 +1,1106 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/mt6363/registers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6363-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SET_OFFSET	0x1
+#define CLR_OFFSET	0x2
+#define OP_CFG_OFFSET	0x5
+#define NORMAL_OP_CFG	0x10
+#define NORMAL_OP_EN	0x800000
+
+#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 DEFAULT_DELAY_MS		10
+
+/*
+ * MT6363 regulator lock register
+ */
+#define MT6363_TMA_UNLOCK_VALUE		0x9c9c
+#define MT6363_BUCK_TOP_UNLOCK_VALUE	0x5543
+
+#define MT6363_RG_BUCK_EFUSE_RSV1	0x1447
+#define MT6363_RG_BUCK_EFUSE_RSV1_MASK	0xf0
+
+/*
+ * MT6363 regulators' information
+ *
+ * @irq: Interrupt request number of the regulator.
+ * @oc_irq_enable_delay_ms: delay in milliseconds before enabling overcurrent interrupt.
+ * @oc_work: Delayed work fields of overcurrent events.
+ * @desc: standard fields of regulator description.
+ * @lp_mode_reg: for operating NORMAL/IDLE mode register.
+ * @lp_mode_mask: MASK for operating lp_mode register.
+ * @hw_lp_mode_reg: hardware NORMAL/IDLE mode status register.
+ * @hw_lp_mode_mask: MASK for hardware NORMAL/IDLE mode status register.
+ * @modeset_reg: for operating AUTO/PWM mode register.
+ * @modeset_mask: MASK for operating modeset register.
+ * @vocal_reg: Calibrates output voltage register.
+ * @vocal_mask: MASK of Calibrates output voltage register.
+ * @lp_imax_uA: Maximum load current in Low power mode.
+ * @op_en_reg: for HW control operating mode register.
+ * @orig_op_en: for HW control original mode register.
+ * @orig_op_cfg: for HW control original mode register.
+ */
+struct mt6363_regulator_info {
+	int irq;
+	int oc_irq_enable_delay_ms;
+	struct delayed_work oc_work;
+	struct regulator_desc desc;
+	u32 lp_mode_reg;
+	u32 lp_mode_mask;
+	u32 hw_lp_mode_reg;
+	u32 hw_lp_mode_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+	u32 vocal_reg;
+	u32 vocal_mask;
+	u32 lp_imax_uA;
+	u32 op_en_reg;
+	u32 orig_op_en;
+	u32 orig_op_cfg;
+};
+
+#define MT6363_BUCK(match, _name, min, max, step, _enable_reg, en_bit, \
+		    _vsel_reg, _vsel_mask, _lp_mode_reg, lp_bit,			\
+		    _modeset_reg, modeset_bit, _en_delay)			\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_buck_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_BUCK_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0xc,					\
+	.modeset_reg = _modeset_reg,				\
+	.modeset_mask = BIT(modeset_bit),			\
+	.lp_imax_uA = 100000,					\
+	.op_en_reg = MT6363_BUCK_##_name##_OP_EN_0,		\
+}
+
+#define MT6363_SSHUB(match, _name, min, max, step, \
+		     _enable_reg, _vsel_reg, _vsel_mask)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_sshub_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(0),				\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+	},							\
+}
+
+#define MT6363_LDO_LINEAR1(match, _name, min, max, step, \
+			   _enable_reg, en_bit, _vsel_reg,	\
+			   _vsel_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_buck_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+}
+
+#define MT6363_LDO_LINEAR2(match, _name, min, max, step,	\
+			   _enable_reg, en_bit, _vsel_reg,	\
+			   _vsel_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_volt_range_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+}
+
+#define MT6363_LDO(match, _name, _volt_table, _enable_reg, en_bit,	\
+		   _vsel_reg, _vsel_mask, _vocal_reg,		\
+		   _vocal_mask, _lp_mode_reg, lp_bit, _en_delay)		\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6363_volt_table_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.vocal_reg = _vocal_reg,				\
+	.vocal_mask = _vocal_mask,				\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+	.lp_imax_uA = 10000,					\
+	.op_en_reg = MT6363_LDO_##_name##_OP_EN0,		\
+}
+
+#define MT6363_LDO_OPS(match, _name, _ops, _volt_table, _enable_reg, en_bit,	\
+		       _vsel_reg, _vsel_mask, _vocal_reg,	\
+		       _vocal_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6363_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6363_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &_ops,					\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6363_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6363_map_mode,			\
+	},							\
+	.vocal_reg = _vocal_reg,				\
+	.vocal_mask = _vocal_mask,				\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE,	\
+	.hw_lp_mode_mask = 0x4,					\
+	.lp_imax_uA = 10000,					\
+	.op_en_reg = MT6363_LDO_##_name##_OP_EN0,		\
+}
+
+static const unsigned int ldo_volt_table0[] = {
+	1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2500000, 2600000,
+	2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int ldo_volt_table1[] = {
+	900000, 1000000, 1100000, 1200000, 1300000, 1700000, 1800000, 1810000,
+};
+
+static const unsigned int ldo_volt_table2[] = {
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static const unsigned int ldo_volt_table3[] = {
+	600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000,
+	1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000,
+};
+
+static const unsigned int ldo_volt_table4[] = {
+	550000, 600000, 650000, 700000, 750000, 800000, 900000, 950000,
+	1000000, 1050000, 1100000, 1150000, 1700000, 1750000, 1800000, 1850000,
+};
+
+static const unsigned int ldo_volt_table5[] = {
+	600000, 650000, 700000, 750000, 800000,
+};
+
+static int mt6363_buck_enable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6363_buck_disable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + 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 = 0;
+	int ret;
+
+	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;
+
+	if (info->hw_lp_mode_reg) {
+		ret = regmap_read(rdev->regmap, info->hw_lp_mode_reg, &val);
+		val &= info->hw_lp_mode_mask;
+	} else {
+		ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+		val &= info->lp_mode_mask;
+	}
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to get mt6363 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, 2);
+}
+
+static int mt6363_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret = 0;
+	int curr_mode;
+
+	curr_mode = mt6363_regulator_get_mode(rdev);
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = mt6363_buck_unlock(rdev->regmap, true);
+		if (ret)
+			return ret;
+		ret = regmap_update_bits(rdev->regmap,
+					 info->modeset_reg,
+					 info->modeset_mask,
+					 info->modeset_mask);
+		ret |= mt6363_buck_unlock(rdev->regmap, false);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		if (curr_mode == REGULATOR_MODE_FAST) {
+			ret = mt6363_buck_unlock(rdev->regmap, true);
+			if (ret)
+				return ret;
+			ret = regmap_update_bits(rdev->regmap,
+						 info->modeset_reg,
+						 info->modeset_mask,
+						 0);
+			ret |= mt6363_buck_unlock(rdev->regmap, false);
+			break;
+		} else if (curr_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_update_bits(rdev->regmap,
+						 info->lp_mode_reg,
+						 info->lp_mode_mask,
+						 0);
+			udelay(100);
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_update_bits(rdev->regmap,
+					 info->lp_mode_reg,
+					 info->lp_mode_mask,
+					 info->lp_mode_mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to set mt6363 mode(%d): %d\n", mode, ret);
+	}
+	return ret;
+}
+
+static int mt6363_regulator_set_load(struct regulator_dev *rdev, int load_uA)
+{
+	int i, ret;
+	struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+
+	/* not support */
+	if (!info->lp_imax_uA)
+		return 0;
+
+	if (load_uA >= info->lp_imax_uA) {
+		ret = mt6363_regulator_set_mode(rdev, REGULATOR_MODE_NORMAL);
+		if (ret)
+			return ret;
+		ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET, NORMAL_OP_CFG);
+		for (i = 0; i < 3; i++) {
+			ret |= regmap_write(rdev->regmap, info->op_en_reg + i,
+					    (NORMAL_OP_EN >> (i * 8)) & 0xff);
+		}
+	} else {
+		ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET,
+				   info->orig_op_cfg);
+		for (i = 0; i < 3; i++) {
+			ret |= regmap_write(rdev->regmap, info->op_en_reg + i,
+					    (info->orig_op_en >> (i * 8)) & 0xff);
+		}
+	}
+
+	return ret;
+}
+
+static int mt6363_vemc_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	int ret;
+	u16 buf = MT6363_TMA_UNLOCK_VALUE;
+	unsigned int val = 0;
+
+	ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &buf, 2);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val);
+	if (ret)
+		return ret;
+	switch (val) {
+	case 0:
+		/* If HW trapping is 0, use VEMC_VOSEL_0 */
+		ret = regmap_update_bits(rdev->regmap,
+					 rdev->desc->vsel_reg,
+					 rdev->desc->vsel_mask, sel);
+		break;
+	case 1:
+		/* If HW trapping is 1, use VEMC_VOSEL_1 */
+		ret = regmap_update_bits(rdev->regmap,
+					 rdev->desc->vsel_reg,
+					 rdev->desc->vsel_mask << 4, sel << 4);
+		break;
+	default:
+		break;
+	}
+	if (ret)
+		return ret;
+
+	buf = 0;
+	ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &buf, 2);
+	return ret;
+}
+
+static int mt6363_vemc_get_voltage_sel(struct regulator_dev *rdev)
+{
+	int ret;
+	unsigned int val = 0, sel = 0;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &sel);
+	if (ret)
+		return ret;
+	ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val);
+	if (ret)
+		return ret;
+	switch (val) {
+	case 0:
+		/* If HW trapping is 0, use VEMC_VOSEL_0 */
+		sel &= rdev->desc->vsel_mask;
+		break;
+	case 1:
+		/* If HW trapping is 1, use VEMC_VOSEL_1 */
+		sel = (sel >> 4) & rdev->desc->vsel_mask;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return sel;
+}
+
+static int mt6363_va15_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	int ret;
+
+	ret = mt6363_buck_unlock(rdev->regmap, true);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel);
+	if (ret)
+		goto va15_unlock;
+	ret = regmap_update_bits(rdev->regmap, MT6363_RG_BUCK_EFUSE_RSV1,
+				 MT6363_RG_BUCK_EFUSE_RSV1_MASK, sel);
+	if (ret)
+		goto va15_unlock;
+
+va15_unlock:
+	ret |= mt6363_buck_unlock(rdev->regmap, false);
+	return ret;
+}
+
+static const struct regulator_ops mt6363_buck_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_buck_enable,
+	.disable = mt6363_buck_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6363_regulator_set_mode,
+	.get_mode = mt6363_regulator_get_mode,
+	.set_load = mt6363_regulator_set_load,
+};
+
+/* for sshub */
+static const struct regulator_ops mt6363_sshub_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,
+};
+
+static const struct regulator_ops mt6363_volt_range_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,
+};
+
+static const struct regulator_ops mt6363_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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_load = mt6363_regulator_set_load,
+};
+
+static const struct regulator_ops mt6363_vemc_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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,
+};
+
+static const struct regulator_ops mt6363_va15_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = mt6363_va15_set_voltage_sel,
+	.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_load = mt6363_regulator_set_load,
+};
+
+static int _isink_load_control(struct regulator_dev *rdev, bool enable)
+{
+	const struct {
+		unsigned int reg;
+		unsigned int mask;
+		unsigned int val;
+	} en_settings[] = {
+		{ MT6363_ISINK_EN_CTRL0, 0xFF, 0xFF },
+		{ MT6363_ISINK_EN_CTRL1, 0xF0, 0xF0 },
+	}, dis_settings[] = {
+		{ MT6363_ISINK_EN_CTRL1, 0xF0, 0 },
+		{ MT6363_ISINK_EN_CTRL0, 0xFF, 0 },
+	}, *settings;
+	int i, setting_size, ret;
+
+	if (enable) {
+		settings = en_settings;
+		setting_size = ARRAY_SIZE(en_settings);
+	} else {
+		settings = dis_settings;
+		setting_size = ARRAY_SIZE(dis_settings);
+	}
+
+	for (i = 0; i < setting_size; i++) {
+		ret = regmap_update_bits(rdev->regmap,
+					 settings[i].reg, settings[i].mask,
+					 settings[i].val);
+		if (ret) {
+			dev_err(&rdev->dev,
+				"Failed to %s isink settings[%d], ret=%d\n",
+				enable ? "enable" : "disable",
+				i, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int isink_load_enable(struct regulator_dev *rdev)
+{
+	return _isink_load_control(rdev, true);
+}
+
+static int isink_load_disable(struct regulator_dev *rdev)
+{
+	return _isink_load_control(rdev, false);
+}
+
+static int isink_load_is_enabled(struct regulator_dev *rdev)
+{
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, MT6363_ISINK_EN_CTRL1, &val);
+	if (ret)
+		return ret;
+
+	val &= 0xF0;
+	return (val == 0xF0);
+}
+
+static const struct regulator_ops isink_load_ops = {
+	.enable = isink_load_enable,
+	.disable = isink_load_disable,
+	.is_enabled = isink_load_is_enabled,
+};
+
+static int mt6363_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config);
+
+/* The array is indexed by id(MT6363_ID_XXX) */
+static struct mt6363_regulator_info mt6363_regulators[] = {
+	MT6363_BUCK("vs2", VS2, 0, 1600000, 12500,
+		    MT6363_RG_BUCK_VS2_EN_ADDR,
+		    MT6363_RG_BUCK_VS2_EN_SHIFT,
+		    MT6363_RG_BUCK_VS2_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VS2_VOSEL_MASK,
+		    MT6363_RG_BUCK_VS2_LP_ADDR,
+		    MT6363_RG_BUCK_VS2_LP_SHIFT,
+		    MT6363_RG_VS2_FCCM_ADDR,
+		    MT6363_RG_VS2_FCCM_SHIFT, 180),
+	MT6363_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK1_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK1_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK1_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK1_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK1_LP_SHIFT,
+		    MT6363_RG_VBUCK1_FCCM_ADDR,
+		    MT6363_RG_VBUCK1_FCCM_SHIFT, 180),
+	MT6363_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK2_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK2_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK2_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK2_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK2_LP_SHIFT,
+		    MT6363_RG_VBUCK2_FCCM_ADDR,
+		    MT6363_RG_VBUCK2_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK3_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK3_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK3_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK3_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK3_LP_SHIFT,
+		    MT6363_RG_VBUCK3_FCCM_ADDR,
+		    MT6363_RG_VBUCK3_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK4_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK4_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK4_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK4_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK4_LP_SHIFT,
+		    MT6363_RG_VBUCK4_FCCM_ADDR,
+		    MT6363_RG_VBUCK4_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK5_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK5_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK5_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK5_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK5_LP_SHIFT,
+		    MT6363_RG_VBUCK5_FCCM_ADDR,
+		    MT6363_RG_VBUCK5_FCCM_SHIFT, 200),
+	MT6363_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK6_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK6_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK6_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK6_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK6_LP_SHIFT,
+		    MT6363_RG_VBUCK6_FCCM_ADDR,
+		    MT6363_RG_VBUCK6_FCCM_SHIFT, 300),
+	MT6363_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VBUCK7_EN_ADDR,
+		    MT6363_RG_BUCK_VBUCK7_EN_SHIFT,
+		    MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VBUCK7_VOSEL_MASK,
+		    MT6363_RG_BUCK_VBUCK7_LP_ADDR,
+		    MT6363_RG_BUCK_VBUCK7_LP_SHIFT,
+		    MT6363_RG_VBUCK7_FCCM_ADDR,
+		    MT6363_RG_VBUCK7_FCCM_SHIFT, 300),
+	MT6363_BUCK("vs1", VS1, 0, 2200000, 12500,
+		    MT6363_RG_BUCK_VS1_EN_ADDR,
+		    MT6363_RG_BUCK_VS1_EN_SHIFT,
+		    MT6363_RG_BUCK_VS1_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VS1_VOSEL_MASK,
+		    MT6363_RG_BUCK_VS1_LP_ADDR,
+		    MT6363_RG_BUCK_VS1_LP_SHIFT,
+		    MT6363_RG_VS1_FCCM_ADDR,
+		    MT6363_RG_VS1_FCCM_SHIFT, 180),
+	MT6363_BUCK("vs3", VS3, 0, 1193750, 6250,
+		    MT6363_RG_BUCK_VS3_EN_ADDR,
+		    MT6363_RG_BUCK_VS3_EN_SHIFT,
+		    MT6363_RG_BUCK_VS3_VOSEL_ADDR,
+		    MT6363_RG_BUCK_VS3_VOSEL_MASK,
+		    MT6363_RG_BUCK_VS3_LP_ADDR,
+		    MT6363_RG_BUCK_VS3_LP_SHIFT,
+		    MT6363_RG_VS3_FCCM_ADDR,
+		    MT6363_RG_VS3_FCCM_SHIFT, 180),
+	MT6363_SSHUB("vbuck1-sshub", VBUCK1_SSHUB, 0, 1193750, 6250,
+		     MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR,
+		     MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR,
+		     MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK),
+	MT6363_SSHUB("vbuck2-sshub", VBUCK2_SSHUB, 0, 1193750, 6250,
+		     MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR,
+		     MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR,
+		     MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK),
+	MT6363_SSHUB("vbuck4-sshub", VBUCK4_SSHUB, 0, 1193750, 6250,
+		     MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR,
+		     MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR,
+		     MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK),
+	MT6363_LDO_LINEAR1("vsram-digrf", VSRAM_DIGRF, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_DIGRF_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_DIGRF_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_DIGRF_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_DIGRF_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR1("vsram-mdfe", VSRAM_MDFE, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_MDFE_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_MDFE_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_MDFE_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_MDFE_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR1("vsram-modem", VSRAM_MODEM, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_MODEM_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_MODEM_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_MODEM_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_MODEM_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-cpub", VSRAM_CPUB, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_CPUB_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUB_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_CPUB_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUB_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-cpum", VSRAM_CPUM, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_CPUM_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUM_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_CPUM_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUM_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-cpul", VSRAM_CPUL, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_CPUL_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUL_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_CPUL_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_CPUL_LP_SHIFT, 180),
+	MT6363_LDO_LINEAR2("vsram-apu", VSRAM_APU, 400000, 1193750, 6250,
+			   MT6363_RG_LDO_VSRAM_APU_EN_ADDR,
+			   MT6363_RG_LDO_VSRAM_APU_EN_SHIFT,
+			   MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR,
+			   MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK,
+			   MT6363_RG_LDO_VSRAM_APU_LP_ADDR,
+			   MT6363_RG_LDO_VSRAM_APU_LP_SHIFT, 180),
+	MT6363_LDO_OPS("vemc", VEMC, mt6363_vemc_ops, ldo_volt_table0,
+		       MT6363_RG_LDO_VEMC_EN_ADDR, MT6363_RG_LDO_VEMC_EN_SHIFT,
+		       MT6363_RG_VEMC_VOSEL_0_ADDR,
+		       MT6363_RG_VEMC_VOSEL_0_MASK,
+		       MT6363_RG_VEMC_VOCAL_0_ADDR,
+		       MT6363_RG_VEMC_VOCAL_0_MASK,
+		       MT6363_RG_LDO_VEMC_LP_ADDR,
+		       MT6363_RG_LDO_VEMC_LP_SHIFT, 680),
+	MT6363_LDO("vcn13", VCN13, ldo_volt_table1,
+		   MT6363_RG_LDO_VCN13_EN_ADDR, MT6363_RG_LDO_VCN13_EN_SHIFT,
+		   MT6363_RG_VCN13_VOSEL_ADDR,
+		   MT6363_RG_VCN13_VOSEL_MASK,
+		   MT6363_RG_VCN13_VOCAL_ADDR,
+		   MT6363_RG_VCN13_VOCAL_MASK,
+		   MT6363_RG_LDO_VCN13_LP_ADDR,
+		   MT6363_RG_LDO_VCN13_LP_SHIFT, 180),
+	MT6363_LDO("vtref18", VTREF18, ldo_volt_table2,
+		   MT6363_RG_LDO_VTREF18_EN_ADDR, MT6363_RG_LDO_VTREF18_EN_SHIFT,
+		   MT6363_RG_VTREF18_VOSEL_ADDR,
+		   MT6363_RG_VTREF18_VOSEL_MASK,
+		   MT6363_RG_VTREF18_VOCAL_ADDR,
+		   MT6363_RG_VTREF18_VOCAL_MASK,
+		   MT6363_RG_LDO_VTREF18_LP_ADDR,
+		   MT6363_RG_LDO_VTREF18_LP_SHIFT, 240),
+	MT6363_LDO("vaux18", VAUX18, ldo_volt_table2,
+		   MT6363_RG_LDO_VAUX18_EN_ADDR, MT6363_RG_LDO_VAUX18_EN_SHIFT,
+		   MT6363_RG_VAUX18_VOSEL_ADDR,
+		   MT6363_RG_VAUX18_VOSEL_MASK,
+		   MT6363_RG_VAUX18_VOCAL_ADDR,
+		   MT6363_RG_VAUX18_VOCAL_MASK,
+		   MT6363_RG_LDO_VAUX18_LP_ADDR,
+		   MT6363_RG_LDO_VAUX18_LP_SHIFT, 240),
+	MT6363_LDO("vcn15", VCN15, ldo_volt_table3,
+		   MT6363_RG_LDO_VCN15_EN_ADDR, MT6363_RG_LDO_VCN15_EN_SHIFT,
+		   MT6363_RG_VCN15_VOSEL_ADDR,
+		   MT6363_RG_VCN15_VOSEL_MASK,
+		   MT6363_RG_VCN15_VOCAL_ADDR,
+		   MT6363_RG_VCN15_VOCAL_MASK,
+		   MT6363_RG_LDO_VCN15_LP_ADDR,
+		   MT6363_RG_LDO_VCN15_LP_SHIFT, 180),
+	MT6363_LDO("vufs18", VUFS18, ldo_volt_table3,
+		   MT6363_RG_LDO_VUFS18_EN_ADDR, MT6363_RG_LDO_VUFS18_EN_SHIFT,
+		   MT6363_RG_VUFS18_VOSEL_ADDR,
+		   MT6363_RG_VUFS18_VOSEL_MASK,
+		   MT6363_RG_VUFS18_VOCAL_ADDR,
+		   MT6363_RG_VUFS18_VOCAL_MASK,
+		   MT6363_RG_LDO_VUFS18_LP_ADDR,
+		   MT6363_RG_LDO_VUFS18_LP_SHIFT, 680),
+	MT6363_LDO("vio18", VIO18, ldo_volt_table3,
+		   MT6363_RG_LDO_VIO18_EN_ADDR, MT6363_RG_LDO_VIO18_EN_SHIFT,
+		   MT6363_RG_VIO18_VOSEL_ADDR,
+		   MT6363_RG_VIO18_VOSEL_MASK,
+		   MT6363_RG_VIO18_VOCAL_ADDR,
+		   MT6363_RG_VIO18_VOCAL_MASK,
+		   MT6363_RG_LDO_VIO18_LP_ADDR,
+		   MT6363_RG_LDO_VIO18_LP_SHIFT, 680),
+	MT6363_LDO("vm18", VM18, ldo_volt_table4,
+		   MT6363_RG_LDO_VM18_EN_ADDR, MT6363_RG_LDO_VM18_EN_SHIFT,
+		   MT6363_RG_VM18_VOSEL_ADDR,
+		   MT6363_RG_VM18_VOSEL_MASK,
+		   MT6363_RG_VM18_VOCAL_ADDR,
+		   MT6363_RG_VM18_VOCAL_MASK,
+		   MT6363_RG_LDO_VM18_LP_ADDR,
+		   MT6363_RG_LDO_VM18_LP_SHIFT, 280),
+	MT6363_LDO_OPS("va15", VA15, mt6363_va15_ops, ldo_volt_table3,
+		       MT6363_RG_LDO_VA15_EN_ADDR, MT6363_RG_LDO_VA15_EN_SHIFT,
+		       MT6363_RG_VA15_VOSEL_ADDR,
+		       MT6363_RG_VA15_VOSEL_MASK,
+		       MT6363_RG_VA15_VOCAL_ADDR,
+		       MT6363_RG_VA15_VOCAL_MASK,
+		       MT6363_RG_LDO_VA15_LP_ADDR,
+		       MT6363_RG_LDO_VA15_LP_SHIFT, 180),
+	MT6363_LDO("vrf18", VRF18, ldo_volt_table3,
+		   MT6363_RG_LDO_VRF18_EN_ADDR, MT6363_RG_LDO_VRF18_EN_SHIFT,
+		   MT6363_RG_VRF18_VOSEL_ADDR,
+		   MT6363_RG_VRF18_VOSEL_MASK,
+		   MT6363_RG_VRF18_VOCAL_ADDR,
+		   MT6363_RG_VRF18_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF18_LP_ADDR,
+		   MT6363_RG_LDO_VRF18_LP_SHIFT, 180),
+	MT6363_LDO("vrfio18", VRFIO18, ldo_volt_table3,
+		   MT6363_RG_LDO_VRFIO18_EN_ADDR, MT6363_RG_LDO_VRFIO18_EN_SHIFT,
+		   MT6363_RG_VRFIO18_VOSEL_ADDR,
+		   MT6363_RG_VRFIO18_VOSEL_MASK,
+		   MT6363_RG_VRFIO18_VOCAL_ADDR,
+		   MT6363_RG_VRFIO18_VOCAL_MASK,
+		   MT6363_RG_LDO_VRFIO18_LP_ADDR,
+		   MT6363_RG_LDO_VRFIO18_LP_SHIFT, 180),
+	MT6363_LDO("vio075", VIO075, ldo_volt_table5,
+		   MT6363_RG_LDO_VIO075_EN_ADDR, MT6363_RG_LDO_VIO075_EN_SHIFT,
+		   MT6363_RG_VIO075_VOSEL_ADDR,
+		   MT6363_RG_VIO075_VOSEL_MASK,
+		   MT6363_RG_VIO075_VOCAL_ADDR,
+		   MT6363_RG_VIO075_VOCAL_MASK,
+		   MT6363_RG_LDO_VIO075_LP_ADDR,
+		   MT6363_RG_LDO_VIO075_LP_SHIFT, 3000),
+	MT6363_LDO("vufs12", VUFS12, ldo_volt_table4,
+		   MT6363_RG_LDO_VUFS12_EN_ADDR, MT6363_RG_LDO_VUFS12_EN_SHIFT,
+		   MT6363_RG_VUFS12_VOSEL_ADDR,
+		   MT6363_RG_VUFS12_VOSEL_MASK,
+		   MT6363_RG_VUFS12_VOCAL_ADDR,
+		   MT6363_RG_VUFS12_VOCAL_MASK,
+		   MT6363_RG_LDO_VUFS12_LP_ADDR,
+		   MT6363_RG_LDO_VUFS12_LP_SHIFT, 280),
+	MT6363_LDO("va12-1", VA12_1, ldo_volt_table3,
+		   MT6363_RG_LDO_VA12_1_EN_ADDR, MT6363_RG_LDO_VA12_1_EN_SHIFT,
+		   MT6363_RG_VA12_1_VOSEL_ADDR,
+		   MT6363_RG_VA12_1_VOSEL_MASK,
+		   MT6363_RG_VA12_1_VOCAL_ADDR,
+		   MT6363_RG_VA12_1_VOCAL_MASK,
+		   MT6363_RG_LDO_VA12_1_LP_ADDR,
+		   MT6363_RG_LDO_VA12_1_LP_SHIFT, 180),
+	MT6363_LDO("va12-2", VA12_2, ldo_volt_table3,
+		   MT6363_RG_LDO_VA12_2_EN_ADDR, MT6363_RG_LDO_VA12_2_EN_SHIFT,
+		   MT6363_RG_VA12_2_VOSEL_ADDR,
+		   MT6363_RG_VA12_2_VOSEL_MASK,
+		   MT6363_RG_VA12_2_VOCAL_ADDR,
+		   MT6363_RG_VA12_2_VOCAL_MASK,
+		   MT6363_RG_LDO_VA12_2_LP_ADDR,
+		   MT6363_RG_LDO_VA12_2_LP_SHIFT, 180),
+	MT6363_LDO("vrf12", VRF12, ldo_volt_table3,
+		   MT6363_RG_LDO_VRF12_EN_ADDR, MT6363_RG_LDO_VRF12_EN_SHIFT,
+		   MT6363_RG_VRF12_VOSEL_ADDR,
+		   MT6363_RG_VRF12_VOSEL_MASK,
+		   MT6363_RG_VRF12_VOCAL_ADDR,
+		   MT6363_RG_VRF12_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF12_LP_ADDR,
+		   MT6363_RG_LDO_VRF12_LP_SHIFT, 180),
+	MT6363_LDO("vrf13", VRF13, ldo_volt_table1,
+		   MT6363_RG_LDO_VRF13_EN_ADDR, MT6363_RG_LDO_VRF13_EN_SHIFT,
+		   MT6363_RG_VRF13_VOSEL_ADDR,
+		   MT6363_RG_VRF13_VOSEL_MASK,
+		   MT6363_RG_VRF13_VOCAL_ADDR,
+		   MT6363_RG_VRF13_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF13_LP_ADDR,
+		   MT6363_RG_LDO_VRF13_LP_SHIFT, 180),
+	MT6363_LDO("vrf09", VRF09, ldo_volt_table1,
+		   MT6363_RG_LDO_VRF09_EN_ADDR, MT6363_RG_LDO_VRF09_EN_SHIFT,
+		   MT6363_RG_VRF09_VOSEL_ADDR,
+		   MT6363_RG_VRF09_VOSEL_MASK,
+		   MT6363_RG_VRF09_VOCAL_ADDR,
+		   MT6363_RG_VRF09_VOCAL_MASK,
+		   MT6363_RG_LDO_VRF09_LP_ADDR,
+		   MT6363_RG_LDO_VRF09_LP_SHIFT, 180),
+	[MT6363_ID_ISINK_LOAD] = {
+		.desc = {
+			.name = "isink_load",
+			.of_match = of_match_ptr("isink-load"),
+			.regulators_node = "regulators",
+			.id = MT6363_ID_ISINK_LOAD,
+			.type = REGULATOR_CURRENT,
+			.ops = &isink_load_ops,
+			.owner = THIS_MODULE,
+		},
+	}
+};
+
+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->irq);
+}
+
+static irqreturn_t mt6363_oc_irq(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->irq);
+	if (!regulator_is_enabled_regmap(rdev))
+		goto delayed_enable;
+	regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT,
+				      NULL);
+delayed_enable:
+	schedule_delayed_work(&info->oc_work,
+			      msecs_to_jiffies(info->oc_irq_enable_delay_ms));
+	return IRQ_HANDLED;
+}
+
+static int mt6363_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config)
+{
+	int ret;
+	struct mt6363_regulator_info *info = config->driver_data;
+
+	if (info->irq > 0) {
+		ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms",
+					   &info->oc_irq_enable_delay_ms);
+		if (ret || !info->oc_irq_enable_delay_ms)
+			info->oc_irq_enable_delay_ms = DEFAULT_DELAY_MS;
+		INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work);
+	}
+	return 0;
+}
+
+static int mt6363_backup_op_setting(struct regmap *map, struct mt6363_regulator_info *info)
+{
+	int i, ret;
+	u32 val = 0;
+
+	ret = regmap_read(map, info->op_en_reg + OP_CFG_OFFSET, &info->orig_op_cfg);
+	for (i = 0; i < 3; i++) {
+		ret |= regmap_read(map, info->op_en_reg + i, &val);
+		info->orig_op_en |= val << (i * 8);
+	}
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mt6363_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	struct mt6363_regulator_info *info;
+	int i, ret;
+
+	config.dev = pdev->dev.parent;
+	config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	for (i = 0; i < MT6363_MAX_REGULATOR; i++) {
+		info = &mt6363_regulators[i];
+		info->irq = platform_get_irq_byname_optional(pdev, info->desc.name);
+		config.driver_data = info;
+
+		rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
+		if (IS_ERR(rdev)) {
+			ret = PTR_ERR(rdev);
+			dev_err(&pdev->dev, "failed to register %s, ret=%d\n",
+				info->desc.name, ret);
+			continue;
+		}
+		if (info->lp_imax_uA) {
+			ret = mt6363_backup_op_setting(config.regmap, info);
+			if (ret) {
+				dev_notice(&pdev->dev, "failed to backup op_setting (%s)\n",
+					   info->desc.name);
+				info->lp_imax_uA = 0;
+			}
+		}
+
+		if (info->irq <= 0)
+			continue;
+		ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+						mt6363_oc_irq,
+						IRQF_TRIGGER_HIGH,
+						info->desc.name,
+						rdev);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request IRQ:%s, ret=%d",
+				info->desc.name, ret);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id mt6363_regulator_ids[] = {
+	{ "mt6363-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6363_regulator_ids);
+
+static struct platform_driver mt6363_regulator_driver = {
+	.driver = {
+		.name = "mt6363-regulator",
+	},
+	.probe = mt6363_regulator_probe,
+	.id_table = mt6363_regulator_ids,
+};
+module_platform_driver(mt6363_regulator_driver);
+
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6363 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mt6373-regulator.c b/drivers/regulator/mt6373-regulator.c
new file mode 100644
index 000000000000..5a8a9f84d13a
--- /dev/null
+++ b/drivers/regulator/mt6373-regulator.c
@@ -0,0 +1,826 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/mt6373/registers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6373-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SET_OFFSET	0x1
+#define CLR_OFFSET	0x2
+
+#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 DEFAULT_DELAY_MS		10
+
+#define MT6373_RG_RSV_SWREG_H		0xa09
+#define MT6373_PLG_CFG_ELR1		0x3ab
+#define MT6373_ELR_MASK			0xc
+
+/*
+ * MT6373 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @lp_mode_reg: for operating NORMAL/IDLE mode register.
+ * @lp_mode_mask: MASK for operating lp_mode register.
+ * @modeset_reg: for operating AUTO/PWM mode register.
+ * @modeset_mask: MASK for operating modeset register.
+ * @modeset_reg: Calibrates output voltage register.
+ * @modeset_mask: MASK of Calibrates output voltage register.
+ */
+struct mt6373_regulator_info {
+	int irq;
+	int oc_irq_enable_delay_ms;
+	struct delayed_work oc_work;
+	struct regulator_desc desc;
+	u32 lp_mode_reg;
+	u32 lp_mode_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+	u32 vocal_reg;
+	u32 vocal_mask;
+};
+
+#define MT6373_BUCK(match, _name, min, max, step,		\
+		    _enable_reg, en_bit, _vsel_reg, _vsel_mask, \
+		    _lp_mode_reg, lp_bit,			\
+		    _modeset_reg, modeset_bit, _en_delay)			\
+[MT6373_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_buck_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+	.modeset_reg = _modeset_reg,				\
+	.modeset_mask = BIT(modeset_bit),			\
+}
+
+#define MT6373_LDO_LINEAR(match, _name, min, max, step,	\
+			  _enable_reg, en_bit, _vsel_reg,	\
+			  _vsel_mask, _lp_mode_reg, lp_bit, _en_delay)	\
+[MT6373_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_volt_range_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ((max) - (min)) / (step) + 1,	\
+		.min_uV = (min),		\
+		.uV_step = (step),		\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+}
+
+#define MT6373_LDO(match, _name, _volt_table, _enable_reg, en_bit,	\
+		   _vsel_reg, _vsel_mask, _vocal_reg,		\
+		   _vocal_mask, _lp_mode_reg, lp_bit, _en_delay)		\
+[MT6373_ID_##_name] = {						\
+	.desc = {						\
+		.name = #_name,					\
+		.of_match = of_match_ptr(match),		\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_volt_table_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_##_name,			\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = _enable_reg,			\
+		.enable_mask = BIT(en_bit),			\
+		.enable_time = _en_delay,			\
+		.vsel_reg = _vsel_reg,				\
+		.vsel_mask = _vsel_mask,			\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.vocal_reg = _vocal_reg,				\
+	.vocal_mask = _vocal_mask,				\
+	.lp_mode_reg = _lp_mode_reg,				\
+	.lp_mode_mask = BIT(lp_bit),				\
+}
+
+#define MT6373_VMCH_EINT(match, _eint_pol, _volt_table, _en_delay)		\
+[MT6373_ID_VMCH_##_eint_pol] = {				\
+	.desc = {						\
+		.name = "VMCH_"#_eint_pol,			\
+		.of_match = of_match_ptr(match),	\
+		.of_parse_cb = mt6373_of_parse_cb,		\
+		.regulators_node = "regulators",		\
+		.ops = &mt6373_vmch_eint_ops,			\
+		.type = REGULATOR_VOLTAGE,			\
+		.id = MT6373_ID_VMCH_##_eint_pol,		\
+		.owner = THIS_MODULE,				\
+		.n_voltages = ARRAY_SIZE(_volt_table),		\
+		.volt_table = _volt_table,			\
+		.enable_reg = MT6373_LDO_VMCH_EINT,	\
+		.enable_mask = MT6373_PMIC_RG_LDO_VMCH_EINT_EN_MASK,	\
+		.enable_time = _en_delay,			\
+		.vsel_reg = MT6373_PMIC_RG_VMCH_VOSEL_ADDR,	\
+		.vsel_mask = MT6373_PMIC_RG_VMCH_VOSEL_MASK,	\
+		.of_map_mode = mt6373_map_mode,			\
+	},							\
+	.vocal_reg = MT6373_PMIC_RG_VMCH_VOCAL_ADDR,		\
+	.vocal_mask = MT6373_PMIC_RG_VMCH_VOCAL_MASK,		\
+	.lp_mode_reg = MT6373_PMIC_RG_LDO_VMCH_LP_ADDR,		\
+	.lp_mode_mask = BIT(MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT),	\
+}
+
+static const unsigned int ldo_volt_table1[] = {
+	1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2100000, 2200000,
+	2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int ldo_volt_table2[] = {
+	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+	2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static const unsigned int ldo_volt_table3[] = {
+	600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000,
+	1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000,
+};
+
+static const unsigned int ldo_volt_table4[] = {
+	1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2500000, 2600000,
+	2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int ldo_volt_table5[] = {
+	900000, 1000000, 1100000, 1200000, 1300000, 1700000, 1800000, 1810000,
+};
+
+static int mt6373_buck_enable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET,
+			    rdev->desc->enable_mask);
+}
+
+static int mt6373_buck_disable(struct regulator_dev *rdev)
+{
+	return regmap_write(rdev->regmap, rdev->desc->enable_reg + 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 unsigned int mt6373_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val = 0;
+	int ret;
+
+	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;
+
+	ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to get mt6373 lp mode: %d\n", ret);
+		return ret;
+	}
+
+	if (val & info->lp_mode_mask)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6373_buck_unlock(struct regmap *map, bool unlock)
+{
+	u8 buf[2];
+
+	if (unlock) {
+		buf[0] = 0x43;
+		buf[1] = 0x55;
+	} else
+		buf[0] = buf[1] = 0;
+	return regmap_bulk_write(map, MT6373_BUCK_TOP_KEY_PROT_LO, buf, 2);
+}
+
+static int mt6373_regulator_set_mode(struct regulator_dev *rdev,
+				     unsigned int mode)
+{
+	struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret = 0;
+	int curr_mode;
+
+	curr_mode = mt6373_regulator_get_mode(rdev);
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		ret = mt6373_buck_unlock(rdev->regmap, true);
+		if (ret)
+			return ret;
+		ret = regmap_update_bits(rdev->regmap,
+					 info->modeset_reg,
+					 info->modeset_mask,
+					 info->modeset_mask);
+		ret |= mt6373_buck_unlock(rdev->regmap, false);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		if (curr_mode == REGULATOR_MODE_FAST) {
+			ret = mt6373_buck_unlock(rdev->regmap, true);
+			if (ret)
+				return ret;
+			ret = regmap_update_bits(rdev->regmap,
+						 info->modeset_reg,
+						 info->modeset_mask,
+						 0);
+			ret |= mt6373_buck_unlock(rdev->regmap, false);
+		} else if (curr_mode == REGULATOR_MODE_IDLE) {
+			ret = regmap_update_bits(rdev->regmap,
+						 info->lp_mode_reg,
+						 info->lp_mode_mask,
+						 0);
+			udelay(100);
+		}
+		break;
+	case REGULATOR_MODE_IDLE:
+		ret = regmap_update_bits(rdev->regmap,
+					 info->lp_mode_reg,
+					 info->lp_mode_mask,
+					 info->lp_mode_mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&rdev->dev,
+			"Failed to set mt6373 mode(%d): %d\n", mode, ret);
+	}
+	return ret;
+}
+
+static int mt6373_vmch_eint_enable(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	int ret;
+
+	if (rdev->desc->id == MT6373_ID_VMCH_EINT_HIGH)
+		val = MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK;
+	else
+		val = 0;
+	ret = regmap_update_bits(rdev->regmap, MT6373_LDO_VMCH_EINT,
+				 MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK, val);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rdev->regmap, MT6373_PMIC_RG_LDO_VMCH_EN_ADDR,
+				 BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT),
+				 BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				 rdev->desc->enable_mask, rdev->desc->enable_mask);
+	return ret;
+}
+
+static int mt6373_vmch_eint_disable(struct regulator_dev *rdev)
+{
+	int ret;
+
+	ret = regmap_update_bits(rdev->regmap, MT6373_PMIC_RG_LDO_VMCH_EN_ADDR,
+				 BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT), 0);
+	if (ret)
+		return ret;
+
+	udelay(1500); /* Must delay for VMCH discharging */
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				 rdev->desc->enable_mask, 0);
+	return ret;
+}
+
+static const struct regulator_ops mt6373_buck_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_buck_enable,
+	.disable = mt6373_buck_disable,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_mode = mt6373_regulator_set_mode,
+	.get_mode = mt6373_regulator_get_mode,
+};
+
+static const struct regulator_ops mt6373_volt_range_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,
+};
+
+static const struct regulator_ops mt6373_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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,
+};
+
+static const struct regulator_ops mt6373_vmch_eint_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.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_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,
+};
+
+static int mt6373_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config);
+
+/* 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_BUCK_VBUCK0_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK0_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK0_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK0_FCCM_SHIFT, 180),
+	MT6373_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK1_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK1_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK1_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK2_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK2_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK2_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK3_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK3_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK3_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT, 180),
+	MT6373_BUCK("vbuck4-ufs", VBUCK4_UFS, 0, 2650125, 13875,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT, 180),
+	MT6373_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK5_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK5_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK5_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK6_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK6_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK6_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK7_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK7_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK7_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck8", VBUCK8, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK8_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK8_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK8_FCCM_SHIFT, 200),
+	MT6373_BUCK("vbuck9", VBUCK9, 0, 1193750, 6250,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_EN_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_EN_SHIFT,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_MASK,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_LP_ADDR,
+		    MT6373_PMIC_RG_BUCK_VBUCK9_LP_SHIFT,
+		    MT6373_PMIC_RG_VBUCK9_FCCM_ADDR,
+		    MT6373_PMIC_RG_VBUCK9_FCCM_SHIFT, 200),
+	MT6373_LDO_LINEAR("vsram-digrf-aif", VSRAM_DIGRF_AIF, 400000, 1193750, 6250,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_ADDR,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_SHIFT,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_ADDR,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_MASK,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_ADDR,
+			  MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_SHIFT, 180),
+	MT6373_LDO("vusb", VUSB, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VUSB_EN_ADDR, MT6373_PMIC_RG_LDO_VUSB_EN_SHIFT,
+		   MT6373_PMIC_RG_VUSB_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VUSB_VOSEL_MASK,
+		   MT6373_PMIC_RG_VUSB_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VUSB_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VUSB_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VUSB_LP_SHIFT, 720),
+	MT6373_LDO("vaux18", VAUX18, ldo_volt_table2,
+		   MT6373_PMIC_RG_LDO_VAUX18_EN_ADDR, MT6373_PMIC_RG_LDO_VAUX18_EN_SHIFT,
+		   MT6373_PMIC_RG_VAUX18_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VAUX18_VOSEL_MASK,
+		   MT6373_PMIC_RG_VAUX18_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VAUX18_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VAUX18_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VAUX18_LP_SHIFT, 240),
+	MT6373_LDO("vrf13-aif", VRF13_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRF13_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF13_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF13_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF13_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF13_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF13_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrf18-aif", VRF18_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRF18_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF18_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF18_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF18_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF18_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF18_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrfio18-aif", VRFIO18_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrf09-aif", VRF09_AIF, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VRF09_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF09_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF09_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF09_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF09_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF09_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vrf12-aif", VRF12_AIF, ldo_volt_table5,
+		   MT6373_PMIC_RG_LDO_VRF12_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF12_AIF_EN_SHIFT,
+		   MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VRF12_AIF_VOSEL_MASK,
+		   MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VRF12_AIF_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VRF12_AIF_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VRF12_AIF_LP_SHIFT, 720),
+	MT6373_LDO("vant18", VANT18, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VANT18_EN_ADDR, MT6373_PMIC_RG_LDO_VANT18_EN_SHIFT,
+		   MT6373_PMIC_RG_VANT18_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VANT18_VOSEL_MASK,
+		   MT6373_PMIC_RG_VANT18_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VANT18_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VANT18_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VANT18_LP_SHIFT, 720),
+	MT6373_LDO("vibr", VIBR, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VIBR_EN_ADDR, MT6373_PMIC_RG_LDO_VIBR_EN_SHIFT,
+		   MT6373_PMIC_RG_VIBR_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VIBR_VOSEL_MASK,
+		   MT6373_PMIC_RG_VIBR_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VIBR_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VIBR_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VIBR_LP_SHIFT, 210),
+	MT6373_LDO("vio28", VIO28, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VIO28_EN_ADDR, MT6373_PMIC_RG_LDO_VIO28_EN_SHIFT,
+		   MT6373_PMIC_RG_VIO28_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VIO28_VOSEL_MASK,
+		   MT6373_PMIC_RG_VIO28_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VIO28_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VIO28_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VIO28_LP_SHIFT, 210),
+	MT6373_LDO("vfp", VFP, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VFP_EN_ADDR, MT6373_PMIC_RG_LDO_VFP_EN_SHIFT,
+		   MT6373_PMIC_RG_VFP_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VFP_VOSEL_MASK,
+		   MT6373_PMIC_RG_VFP_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VFP_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VFP_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VFP_LP_SHIFT, 210),
+	MT6373_LDO("vtp", VTP, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VTP_EN_ADDR, MT6373_PMIC_RG_LDO_VTP_EN_SHIFT,
+		   MT6373_PMIC_RG_VTP_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VTP_VOSEL_MASK,
+		   MT6373_PMIC_RG_VTP_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VTP_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VTP_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VTP_LP_SHIFT, 720),
+	MT6373_LDO("vmch", VMCH, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VMCH_EN_ADDR, MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT,
+		   MT6373_PMIC_RG_VMCH_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VMCH_VOSEL_MASK,
+		   MT6373_PMIC_RG_VMCH_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VMCH_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VMCH_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT, 720),
+	MT6373_LDO("vmc", VMC, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VMC_EN_ADDR, MT6373_PMIC_RG_LDO_VMC_EN_SHIFT,
+		   MT6373_PMIC_RG_VMC_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VMC_VOSEL_MASK,
+		   MT6373_PMIC_RG_VMC_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VMC_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VMC_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VMC_LP_SHIFT, 720),
+	MT6373_LDO("vaud18", VAUD18, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VAUD18_EN_ADDR, MT6373_PMIC_RG_LDO_VAUD18_EN_SHIFT,
+		   MT6373_PMIC_RG_VAUD18_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VAUD18_VOSEL_MASK,
+		   MT6373_PMIC_RG_VAUD18_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VAUD18_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VAUD18_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VAUD18_LP_SHIFT, 720),
+	MT6373_LDO("vcn33-1", VCN33_1, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VCN33_1_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_1_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN33_1_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN33_1_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN33_1_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN33_1_LP_SHIFT, 210),
+	MT6373_LDO("vcn33-2", VCN33_2, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VCN33_2_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_2_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN33_2_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN33_2_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN33_2_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN33_2_LP_SHIFT, 210),
+	MT6373_LDO("vcn33-3", VCN33_3, ldo_volt_table4,
+		   MT6373_PMIC_RG_LDO_VCN33_3_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_3_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN33_3_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN33_3_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN33_3_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN33_3_LP_SHIFT, 210),
+	MT6373_LDO("vcn18io", VCN18IO, ldo_volt_table3,
+		   MT6373_PMIC_RG_LDO_VCN18IO_EN_ADDR, MT6373_PMIC_RG_LDO_VCN18IO_EN_SHIFT,
+		   MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VCN18IO_VOSEL_MASK,
+		   MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VCN18IO_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VCN18IO_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VCN18IO_LP_SHIFT, 720),
+	MT6373_LDO("vefuse", VEFUSE, ldo_volt_table1,
+		   MT6373_PMIC_RG_LDO_VEFUSE_EN_ADDR, MT6373_PMIC_RG_LDO_VEFUSE_EN_SHIFT,
+		   MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR,
+		   MT6373_PMIC_RG_VEFUSE_VOSEL_MASK,
+		   MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR,
+		   MT6373_PMIC_RG_VEFUSE_VOCAL_MASK,
+		   MT6373_PMIC_RG_LDO_VEFUSE_LP_ADDR,
+		   MT6373_PMIC_RG_LDO_VEFUSE_LP_SHIFT, 720),
+	MT6373_VMCH_EINT("vmch-eint-high", EINT_HIGH, ldo_volt_table4, 720),
+	MT6373_VMCH_EINT("vmch-eint-low", EINT_LOW, ldo_volt_table4, 720),
+};
+
+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->irq);
+}
+
+static irqreturn_t mt6373_oc_irq(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->irq);
+	if (!regulator_is_enabled_regmap(rdev))
+		goto delayed_enable;
+	regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT,
+				      NULL);
+delayed_enable:
+	schedule_delayed_work(&info->oc_work,
+			      msecs_to_jiffies(info->oc_irq_enable_delay_ms));
+	return IRQ_HANDLED;
+}
+
+static int mt6373_of_parse_cb(struct device_node *np,
+			      const struct regulator_desc *desc,
+			      struct regulator_config *config)
+{
+	int ret;
+	struct mt6373_regulator_info *info = config->driver_data;
+
+	if (info->irq > 0) {
+		ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms",
+					   &info->oc_irq_enable_delay_ms);
+		if (ret || !info->oc_irq_enable_delay_ms)
+			info->oc_irq_enable_delay_ms = DEFAULT_DELAY_MS;
+		INIT_DELAYED_WORK(&info->oc_work, mt6373_oc_irq_enable_work);
+	}
+	return 0;
+}
+
+static bool mt6373_bypass_register(struct mt6373_regulator_info *info)
+{
+	return info->desc.id == MT6373_ID_VBUCK4_UFS;
+}
+
+static int mt6373_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	struct mt6373_regulator_info *info;
+	int i, ret;
+	unsigned int val = 0;
+	bool is_mt6373_cw = false;
+
+	config.dev = pdev->dev.parent;
+	config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
+
+	if (!config.regmap) {
+		dev_err(&pdev->dev, "failed to get regmap\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_read(config.regmap, MT6373_PLG_CFG_ELR1, &val);
+	if (ret)
+		dev_notice(&pdev->dev, "failed to read ELR, ret=%d\n", ret);
+	else if ((val & MT6373_ELR_MASK) == 0x4)
+		is_mt6373_cw = true;
+
+	/* MT6373_RG_RSV_SWREG_H for checking 6989p */
+	ret = regmap_read(config.regmap, MT6373_RG_RSV_SWREG_H, &val);
+
+	for (i = 0; i < MT6373_MAX_REGULATOR; i++) {
+		info = &mt6373_regulators[i];
+		info->irq = platform_get_irq_byname_optional(pdev, info->desc.name);
+		config.driver_data = info;
+		if (is_mt6373_cw && mt6373_bypass_register(info))
+			continue;
+		if ((info->desc.id == MT6373_ID_VBUCK4) && (val & 0x1)) {
+			dev_info(&pdev->dev, "skip registering %s\n", info->desc.name);
+			continue;
+		}
+
+		rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
+		if (IS_ERR(rdev)) {
+			ret = PTR_ERR(rdev);
+			dev_err(&pdev->dev, "failed to register %s, ret=%d\n",
+				info->desc.name, ret);
+			continue;
+		}
+
+		if (info->irq <= 0)
+			continue;
+		ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+						mt6373_oc_irq,
+						IRQF_TRIGGER_HIGH,
+						info->desc.name,
+						rdev);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request IRQ:%s, ret=%d",
+				info->desc.name, ret);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static void mt6373_regulator_shutdown(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+	int ret = 0;
+
+	regmap = dev_get_regmap(dev->parent, NULL);
+	if (!regmap) {
+		dev_notice(&pdev->dev, "invalid regmap.\n");
+		return;
+	}
+
+	ret = regmap_write(regmap, MT6373_TOP_CFG_ELR5, 0x1);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "enable sequence off failed.\n");
+		return;
+	}
+}
+
+static const struct platform_device_id mt6373_regulator_ids[] = {
+	{ "mt6373-regulator", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6373_regulator_ids);
+
+static struct platform_driver mt6373_regulator_driver = {
+	.driver = {
+		.name = "mt6373-regulator",
+	},
+	.probe = mt6373_regulator_probe,
+	.shutdown = mt6373_regulator_shutdown,
+	.id_table = mt6373_regulator_ids,
+};
+module_platform_driver(mt6373_regulator_driver);
+
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6373 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6316-regulator.h b/include/linux/regulator/mt6316-regulator.h
new file mode 100644
index 000000000000..dd11b3d856fd
--- /dev/null
+++ b/include/linux/regulator/mt6316-regulator.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6316_H
+#define __LINUX_REGULATOR_MT6316_H
+
+#define MT6316_SLAVE_ID_3	3
+#define MT6316_SLAVE_ID_6	6
+#define MT6316_SLAVE_ID_7	7
+#define MT6316_SLAVE_ID_8	8
+#define MT6316_SLAVE_ID_15	15
+
+#define MT6316_ID_3_MAX		3
+#define MT6316_ID_6_MAX		3
+#define MT6316_ID_7_MAX		3
+#define MT6316_ID_8_MAX		3
+#define MT6316_ID_15_MAX	2
+
+enum {
+	MT6316_ID_VBUCK1 = 0,
+	MT6316_ID_VBUCK2,
+	MT6316_ID_VBUCK3,
+	MT6316_ID_VBUCK4,
+	MT6316_ID_MAX,
+};
+
+/* Register */
+#define MT6316_TOP_CFG_ELR4			0x143
+#define MT6316_BUCK_TOP_CON0			0x1440
+#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_VBUCK1_DBG4			0x14A4
+#define MT6316_VBUCK1_DBG8			0x14A8
+#define MT6316_VBUCK2_DBG4			0x1524
+#define MT6316_VBUCK2_DBG8			0x1528
+#define MT6316_VBUCK3_DBG4			0x15A4
+#define MT6316_VBUCK3_DBG8			0x15A8
+#define MT6316_VBUCK4_DBG4			0x1624
+#define MT6316_VBUCK4_DBG8			0x1628
+#define MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0     0x1688
+#define MT6316_BUCK_TOP_4PHASE_TOP_ELR_0	0x1690
+
+#endif /* __LINUX_REGULATOR_MT6316_H */
diff --git a/include/linux/regulator/mt6363-regulator.h b/include/linux/regulator/mt6363-regulator.h
new file mode 100644
index 000000000000..f9c2220ae18c
--- /dev/null
+++ b/include/linux/regulator/mt6363-regulator.h
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6363_H
+#define __LINUX_REGULATOR_MT6363_H
+
+enum {
+	MT6363_ID_VS2,
+	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_VS3,
+	MT6363_ID_VBUCK1_SSHUB,
+	MT6363_ID_VBUCK2_SSHUB,
+	MT6363_ID_VBUCK4_SSHUB,
+	MT6363_ID_VSRAM_DIGRF,
+	MT6363_ID_VSRAM_MDFE,
+	MT6363_ID_VSRAM_MODEM,
+	MT6363_ID_VSRAM_CPUB,
+	MT6363_ID_VSRAM_CPUM,
+	MT6363_ID_VSRAM_CPUL,
+	MT6363_ID_VSRAM_APU,
+	MT6363_ID_VEMC,
+	MT6363_ID_VCN13,
+	MT6363_ID_VTREF18,
+	MT6363_ID_VAUX18,
+	MT6363_ID_VCN15,
+	MT6363_ID_VUFS18,
+	MT6363_ID_VIO18,
+	MT6363_ID_VM18,
+	MT6363_ID_VA15,
+	MT6363_ID_VRF18,
+	MT6363_ID_VRFIO18,
+	MT6363_ID_VIO075,
+	MT6363_ID_VUFS12,
+	MT6363_ID_VA12_1,
+	MT6363_ID_VA12_2,
+	MT6363_ID_VRF12,
+	MT6363_ID_VRF13,
+	MT6363_ID_VRF09,
+	MT6363_ID_ISINK_LOAD,
+	MT6363_MAX_REGULATOR,
+};
+
+#define MTK_REGULATOR_MAX_NR MT6363_MAX_REGULATOR
+
+/* Register */
+#define MT6363_TOP_TRAP                             (0x36)
+#define MT6363_TOP_TMA_KEY_L                        (0x39e)
+#define MT6363_BUCK_TOP_KEY_PROT_LO                 (0x142a)
+#define MT6363_BUCK_VS2_OP_EN_0                     (0x148d)
+#define MT6363_BUCK_VS2_HW_LP_MODE                  (0x1498)
+#define MT6363_BUCK_VBUCK1_OP_EN_0                  (0x150d)
+#define MT6363_BUCK_VBUCK1_HW_LP_MODE               (0x1518)
+#define MT6363_BUCK_VBUCK2_OP_EN_0                  (0x158d)
+#define MT6363_BUCK_VBUCK2_HW_LP_MODE               (0x1598)
+#define MT6363_BUCK_VBUCK3_OP_EN_0                  (0x160d)
+#define MT6363_BUCK_VBUCK3_HW_LP_MODE               (0x1618)
+#define MT6363_BUCK_VBUCK4_OP_EN_0                  (0x168d)
+#define MT6363_BUCK_VBUCK4_HW_LP_MODE               (0x1698)
+#define MT6363_BUCK_VBUCK5_OP_EN_0                  (0x170d)
+#define MT6363_BUCK_VBUCK5_HW_LP_MODE               (0x1718)
+#define MT6363_BUCK_VBUCK6_OP_EN_0                  (0x178d)
+#define MT6363_BUCK_VBUCK6_HW_LP_MODE               (0x1798)
+#define MT6363_BUCK_VBUCK7_OP_EN_0                  (0x180d)
+#define MT6363_BUCK_VBUCK7_HW_LP_MODE               (0x1818)
+#define MT6363_BUCK_VS1_OP_EN_0                     (0x188d)
+#define MT6363_BUCK_VS1_HW_LP_MODE                  (0x1898)
+#define MT6363_BUCK_VS3_OP_EN_0                     (0x190d)
+#define MT6363_BUCK_VS3_HW_LP_MODE                  (0x1918)
+#define MT6363_LDO_VCN15_HW_LP_MODE                 (0x1b8b)
+#define MT6363_LDO_VCN15_OP_EN0                     (0x1b8c)
+#define MT6363_LDO_VRF09_HW_LP_MODE                 (0x1b99)
+#define MT6363_LDO_VRF09_OP_EN0                     (0x1b9a)
+#define MT6363_LDO_VRF12_HW_LP_MODE                 (0x1ba7)
+#define MT6363_LDO_VRF12_OP_EN0                     (0x1ba8)
+#define MT6363_LDO_VRF13_HW_LP_MODE                 (0x1bb5)
+#define MT6363_LDO_VRF13_OP_EN0                     (0x1bb6)
+#define MT6363_LDO_VRF18_HW_LP_MODE                 (0x1bc3)
+#define MT6363_LDO_VRF18_OP_EN0                     (0x1bc4)
+#define MT6363_LDO_VRFIO18_HW_LP_MODE               (0x1bd1)
+#define MT6363_LDO_VRFIO18_OP_EN0                   (0x1bd2)
+#define MT6363_LDO_VTREF18_HW_LP_MODE               (0x1c0b)
+#define MT6363_LDO_VTREF18_OP_EN0                   (0x1c0c)
+#define MT6363_LDO_VAUX18_HW_LP_MODE                (0x1c19)
+#define MT6363_LDO_VAUX18_OP_EN0                    (0x1c1a)
+#define MT6363_LDO_VEMC_HW_LP_MODE                  (0x1c27)
+#define MT6363_LDO_VEMC_OP_EN0                      (0x1c28)
+#define MT6363_LDO_VUFS12_HW_LP_MODE                (0x1c35)
+#define MT6363_LDO_VUFS12_OP_EN0                    (0x1c36)
+#define MT6363_LDO_VUFS18_HW_LP_MODE                (0x1c43)
+#define MT6363_LDO_VUFS18_OP_EN0                    (0x1c44)
+#define MT6363_LDO_VIO18_HW_LP_MODE                 (0x1c51)
+#define MT6363_LDO_VIO18_OP_EN0                     (0x1c52)
+#define MT6363_LDO_VIO075_HW_LP_MODE                (0x1c8b)
+#define MT6363_LDO_VIO075_OP_EN0                    (0x1c8c)
+#define MT6363_LDO_VA12_1_HW_LP_MODE                (0x1c99)
+#define MT6363_LDO_VA12_1_OP_EN0                    (0x1c9a)
+#define MT6363_LDO_VA12_2_HW_LP_MODE                (0x1ca7)
+#define MT6363_LDO_VA12_2_OP_EN0                    (0x1ca8)
+#define MT6363_LDO_VA15_HW_LP_MODE                  (0x1cb5)
+#define MT6363_LDO_VA15_OP_EN0                      (0x1cb6)
+#define MT6363_LDO_VM18_HW_LP_MODE                  (0x1cc3)
+#define MT6363_LDO_VM18_OP_EN0                      (0x1cc4)
+#define MT6363_LDO_VCN13_HW_LP_MODE                 (0x1d0b)
+#define MT6363_LDO_VCN13_OP_EN0                     (0x1d14)
+#define MT6363_LDO_VSRAM_DIGRF_HW_LP_MODE           (0x1d21)
+#define MT6363_LDO_VSRAM_DIGRF_OP_EN0               (0x1d2a)
+#define MT6363_LDO_VSRAM_MDFE_HW_LP_MODE            (0x1d8b)
+#define MT6363_LDO_VSRAM_MDFE_OP_EN0                (0x1d94)
+#define MT6363_LDO_VSRAM_MODEM_HW_LP_MODE           (0x1da6)
+#define MT6363_LDO_VSRAM_MODEM_OP_EN0               (0x1daf)
+#define MT6363_LDO_VSRAM_CPUB_HW_LP_MODE            (0x1e0b)
+#define MT6363_LDO_VSRAM_CPUB_OP_EN0                (0x1e14)
+#define MT6363_LDO_VSRAM_CPUM_HW_LP_MODE            (0x1e21)
+#define MT6363_LDO_VSRAM_CPUM_OP_EN0                (0x1e2a)
+#define MT6363_LDO_VSRAM_CPUL_HW_LP_MODE            (0x1e8b)
+#define MT6363_LDO_VSRAM_CPUL_OP_EN0                (0x1e94)
+#define MT6363_LDO_VSRAM_APU_HW_LP_MODE             (0x1ea1)
+#define MT6363_LDO_VSRAM_APU_OP_EN0                 (0x1eaa)
+#define MT6363_RG_BUCK_VS2_EN_ADDR                  (0x240)
+#define MT6363_RG_BUCK_VS2_EN_SHIFT                 (0)
+#define MT6363_RG_BUCK_VBUCK1_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK1_EN_SHIFT              (1)
+#define MT6363_RG_BUCK_VBUCK2_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK2_EN_SHIFT              (2)
+#define MT6363_RG_BUCK_VBUCK3_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK3_EN_SHIFT              (3)
+#define MT6363_RG_BUCK_VBUCK4_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK4_EN_SHIFT              (4)
+#define MT6363_RG_BUCK_VBUCK5_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK5_EN_SHIFT              (5)
+#define MT6363_RG_BUCK_VBUCK6_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK6_EN_SHIFT              (6)
+#define MT6363_RG_BUCK_VBUCK7_EN_ADDR               (0x240)
+#define MT6363_RG_BUCK_VBUCK7_EN_SHIFT              (7)
+#define MT6363_RG_BUCK_VS1_EN_ADDR                  (0x243)
+#define MT6363_RG_BUCK_VS1_EN_SHIFT                 (0)
+#define MT6363_RG_BUCK_VS3_EN_ADDR                  (0x243)
+#define MT6363_RG_BUCK_VS3_EN_SHIFT                 (1)
+#define MT6363_RG_LDO_VSRAM_DIGRF_EN_ADDR           (0x243)
+#define MT6363_RG_LDO_VSRAM_DIGRF_EN_SHIFT          (4)
+#define MT6363_RG_LDO_VSRAM_MDFE_EN_ADDR            (0x243)
+#define MT6363_RG_LDO_VSRAM_MDFE_EN_SHIFT           (5)
+#define MT6363_RG_LDO_VSRAM_MODEM_EN_ADDR           (0x243)
+#define MT6363_RG_LDO_VSRAM_MODEM_EN_SHIFT          (6)
+#define MT6363_RG_BUCK_VS2_LP_ADDR                  (0x246)
+#define MT6363_RG_BUCK_VS2_LP_SHIFT                 (0)
+#define MT6363_RG_BUCK_VBUCK1_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK1_LP_SHIFT              (1)
+#define MT6363_RG_BUCK_VBUCK2_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK2_LP_SHIFT              (2)
+#define MT6363_RG_BUCK_VBUCK3_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK3_LP_SHIFT              (3)
+#define MT6363_RG_BUCK_VBUCK4_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK4_LP_SHIFT              (4)
+#define MT6363_RG_BUCK_VBUCK5_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK5_LP_SHIFT              (5)
+#define MT6363_RG_BUCK_VBUCK6_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK6_LP_SHIFT              (6)
+#define MT6363_RG_BUCK_VBUCK7_LP_ADDR               (0x246)
+#define MT6363_RG_BUCK_VBUCK7_LP_SHIFT              (7)
+#define MT6363_RG_BUCK_VS1_LP_ADDR                  (0x249)
+#define MT6363_RG_BUCK_VS1_LP_SHIFT                 (0)
+#define MT6363_RG_BUCK_VS3_LP_ADDR                  (0x249)
+#define MT6363_RG_BUCK_VS3_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VSRAM_DIGRF_LP_ADDR           (0x249)
+#define MT6363_RG_LDO_VSRAM_DIGRF_LP_SHIFT          (4)
+#define MT6363_RG_LDO_VSRAM_MDFE_LP_ADDR            (0x249)
+#define MT6363_RG_LDO_VSRAM_MDFE_LP_SHIFT           (5)
+#define MT6363_RG_LDO_VSRAM_MODEM_LP_ADDR           (0x249)
+#define MT6363_RG_LDO_VSRAM_MODEM_LP_SHIFT          (6)
+#define MT6363_RG_BUCK_VS2_VOSEL_ADDR               (0x24c)
+#define MT6363_RG_BUCK_VS2_VOSEL_MASK               (0xff)
+#define MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR            (0x24d)
+#define MT6363_RG_BUCK_VBUCK1_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR            (0x24e)
+#define MT6363_RG_BUCK_VBUCK2_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR            (0x24f)
+#define MT6363_RG_BUCK_VBUCK3_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR            (0x250)
+#define MT6363_RG_BUCK_VBUCK4_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR            (0x251)
+#define MT6363_RG_BUCK_VBUCK5_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR            (0x252)
+#define MT6363_RG_BUCK_VBUCK6_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR            (0x253)
+#define MT6363_RG_BUCK_VBUCK7_VOSEL_MASK            (0xff)
+#define MT6363_RG_BUCK_VS1_VOSEL_ADDR               (0x254)
+#define MT6363_RG_BUCK_VS1_VOSEL_MASK               (0xff)
+#define MT6363_RG_BUCK_VS3_VOSEL_ADDR               (0x255)
+#define MT6363_RG_BUCK_VS3_VOSEL_MASK               (0xff)
+#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR        (0x258)
+#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK        (0x7f)
+#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR         (0x259)
+#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR        (0x25a)
+#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK        (0x7f)
+#define MT6363_BUCK_VS2_WDTDBG_VOSEL_ADDR           (0x142c)
+#define MT6363_BUCK_VBUCK1_WDTDBG_VOSEL_ADDR        (0x142d)
+#define MT6363_BUCK_VBUCK2_WDTDBG_VOSEL_ADDR        (0x142e)
+#define MT6363_BUCK_VBUCK3_WDTDBG_VOSEL_ADDR        (0x142f)
+#define MT6363_BUCK_VBUCK4_WDTDBG_VOSEL_ADDR        (0x1430)
+#define MT6363_BUCK_VBUCK5_WDTDBG_VOSEL_ADDR        (0x1431)
+#define MT6363_BUCK_VBUCK6_WDTDBG_VOSEL_ADDR        (0x1432)
+#define MT6363_BUCK_VBUCK7_WDTDBG_VOSEL_ADDR        (0x1433)
+#define MT6363_BUCK_VS1_WDTDBG_VOSEL_ADDR           (0x1434)
+#define MT6363_BUCK_VS3_WDTDBG_VOSEL_ADDR           (0x1435)
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR         (0x151a)
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR      (0x151b)
+#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK      (0xff)
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR         (0x159a)
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR      (0x159b)
+#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK      (0xff)
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR         (0x169a)
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR      (0x169b)
+#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK      (0xff)
+#define MT6363_RG_VS1_FCCM_ADDR                     (0x1994)
+#define MT6363_RG_VS1_FCCM_SHIFT                    (0)
+#define MT6363_RG_VS3_FCCM_ADDR                     (0x19a3)
+#define MT6363_RG_VS3_FCCM_SHIFT                    (0)
+#define MT6363_RG_VBUCK1_FCCM_ADDR                  (0x1a32)
+#define MT6363_RG_VBUCK1_FCCM_SHIFT                 (0)
+#define MT6363_RG_VBUCK2_FCCM_ADDR                  (0x1a32)
+#define MT6363_RG_VBUCK2_FCCM_SHIFT                 (1)
+#define MT6363_RG_VBUCK3_FCCM_ADDR                  (0x1a32)
+#define MT6363_RG_VBUCK3_FCCM_SHIFT                 (2)
+#define MT6363_RG_VS2_FCCM_ADDR                     (0x1a32)
+#define MT6363_RG_VS2_FCCM_SHIFT                    (3)
+#define MT6363_RG_VBUCK4_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK4_FCCM_SHIFT                 (0)
+#define MT6363_RG_VBUCK5_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK5_FCCM_SHIFT                 (1)
+#define MT6363_RG_VBUCK6_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK6_FCCM_SHIFT                 (2)
+#define MT6363_RG_VBUCK7_FCCM_ADDR                  (0x1ab2)
+#define MT6363_RG_VBUCK7_FCCM_SHIFT                 (3)
+#define MT6363_RG_VCN13_VOSEL_ADDR                  (0x1b3f)
+#define MT6363_RG_VCN13_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VEMC_VOSEL_0_ADDR                 (0x1b40)
+#define MT6363_RG_VEMC_VOSEL_0_MASK                 (0xf)
+#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR         (0x1b44)
+#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR         (0x1b45)
+#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR         (0x1b46)
+#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK         (0x7f)
+#define MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR          (0x1b47)
+#define MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK          (0x7f)
+#define MT6363_RG_VEMC_VOCAL_0_ADDR                 (0x1b4b)
+#define MT6363_RG_VEMC_VOCAL_0_MASK                 (0xf)
+#define MT6363_RG_LDO_VCN15_EN_ADDR                 (0x1b87)
+#define MT6363_RG_LDO_VCN15_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VCN15_LP_ADDR                 (0x1b87)
+#define MT6363_RG_LDO_VCN15_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF09_EN_ADDR                 (0x1b95)
+#define MT6363_RG_LDO_VRF09_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF09_LP_ADDR                 (0x1b95)
+#define MT6363_RG_LDO_VRF09_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF12_EN_ADDR                 (0x1ba3)
+#define MT6363_RG_LDO_VRF12_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF12_LP_ADDR                 (0x1ba3)
+#define MT6363_RG_LDO_VRF12_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF13_EN_ADDR                 (0x1bb1)
+#define MT6363_RG_LDO_VRF13_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF13_LP_ADDR                 (0x1bb1)
+#define MT6363_RG_LDO_VRF13_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRF18_EN_ADDR                 (0x1bbf)
+#define MT6363_RG_LDO_VRF18_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VRF18_LP_ADDR                 (0x1bbf)
+#define MT6363_RG_LDO_VRF18_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VRFIO18_EN_ADDR               (0x1bcd)
+#define MT6363_RG_LDO_VRFIO18_EN_SHIFT              (0)
+#define MT6363_RG_LDO_VRFIO18_LP_ADDR               (0x1bcd)
+#define MT6363_RG_LDO_VRFIO18_LP_SHIFT              (1)
+#define MT6363_RG_LDO_VTREF18_EN_ADDR               (0x1c07)
+#define MT6363_RG_LDO_VTREF18_EN_SHIFT              (0)
+#define MT6363_RG_LDO_VTREF18_LP_ADDR               (0x1c07)
+#define MT6363_RG_LDO_VTREF18_LP_SHIFT              (1)
+#define MT6363_RG_LDO_VAUX18_EN_ADDR                (0x1c15)
+#define MT6363_RG_LDO_VAUX18_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VAUX18_LP_ADDR                (0x1c15)
+#define MT6363_RG_LDO_VAUX18_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VEMC_EN_ADDR                  (0x1c23)
+#define MT6363_RG_LDO_VEMC_EN_SHIFT                 (0)
+#define MT6363_RG_LDO_VEMC_LP_ADDR                  (0x1c23)
+#define MT6363_RG_LDO_VEMC_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VUFS12_EN_ADDR                (0x1c31)
+#define MT6363_RG_LDO_VUFS12_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VUFS12_LP_ADDR                (0x1c31)
+#define MT6363_RG_LDO_VUFS12_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VUFS18_EN_ADDR                (0x1c3f)
+#define MT6363_RG_LDO_VUFS18_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VUFS18_LP_ADDR                (0x1c3f)
+#define MT6363_RG_LDO_VUFS18_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VIO18_EN_ADDR                 (0x1c4d)
+#define MT6363_RG_LDO_VIO18_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VIO18_LP_ADDR                 (0x1c4d)
+#define MT6363_RG_LDO_VIO18_LP_SHIFT                (1)
+#define MT6363_RG_LDO_VIO075_EN_ADDR                (0x1c87)
+#define MT6363_RG_LDO_VIO075_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VIO075_LP_ADDR                (0x1c87)
+#define MT6363_RG_LDO_VIO075_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VA12_1_EN_ADDR                (0x1c95)
+#define MT6363_RG_LDO_VA12_1_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VA12_1_LP_ADDR                (0x1c95)
+#define MT6363_RG_LDO_VA12_1_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VA12_2_EN_ADDR                (0x1ca3)
+#define MT6363_RG_LDO_VA12_2_EN_SHIFT               (0)
+#define MT6363_RG_LDO_VA12_2_LP_ADDR                (0x1ca3)
+#define MT6363_RG_LDO_VA12_2_LP_SHIFT               (1)
+#define MT6363_RG_LDO_VA15_EN_ADDR                  (0x1cb1)
+#define MT6363_RG_LDO_VA15_EN_SHIFT                 (0)
+#define MT6363_RG_LDO_VA15_LP_ADDR                  (0x1cb1)
+#define MT6363_RG_LDO_VA15_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VM18_EN_ADDR                  (0x1cbf)
+#define MT6363_RG_LDO_VM18_EN_SHIFT                 (0)
+#define MT6363_RG_LDO_VM18_LP_ADDR                  (0x1cbf)
+#define MT6363_RG_LDO_VM18_LP_SHIFT                 (1)
+#define MT6363_RG_LDO_VCN13_EN_ADDR                 (0x1d07)
+#define MT6363_RG_LDO_VCN13_EN_SHIFT                (0)
+#define MT6363_RG_LDO_VCN13_LP_ADDR                 (0x1d07)
+#define MT6363_RG_LDO_VCN13_LP_SHIFT                (1)
+#define MT6363_LDO_VSRAM_DIGRF_WDTDBG_VOSEL_ADDR    (0x1d24)
+#define MT6363_LDO_VSRAM_MDFE_WDTDBG_VOSEL_ADDR     (0x1d8e)
+#define MT6363_LDO_VSRAM_MODEM_WDTDBG_VOSEL_ADDR    (0x1da9)
+#define MT6363_RG_LDO_VSRAM_CPUB_EN_ADDR            (0x1e07)
+#define MT6363_RG_LDO_VSRAM_CPUB_EN_SHIFT           (0)
+#define MT6363_RG_LDO_VSRAM_CPUB_LP_ADDR            (0x1e07)
+#define MT6363_RG_LDO_VSRAM_CPUB_LP_SHIFT           (1)
+#define MT6363_LDO_VSRAM_CPUB_WDTDBG_VOSEL_ADDR     (0x1e0e)
+#define MT6363_RG_LDO_VSRAM_CPUM_EN_ADDR            (0x1e1d)
+#define MT6363_RG_LDO_VSRAM_CPUM_EN_SHIFT           (0)
+#define MT6363_RG_LDO_VSRAM_CPUM_LP_ADDR            (0x1e1d)
+#define MT6363_RG_LDO_VSRAM_CPUM_LP_SHIFT           (1)
+#define MT6363_LDO_VSRAM_CPUM_WDTDBG_VOSEL_ADDR     (0x1e24)
+#define MT6363_RG_LDO_VSRAM_CPUL_EN_ADDR            (0x1e87)
+#define MT6363_RG_LDO_VSRAM_CPUL_EN_SHIFT           (0)
+#define MT6363_RG_LDO_VSRAM_CPUL_LP_ADDR            (0x1e87)
+#define MT6363_RG_LDO_VSRAM_CPUL_LP_SHIFT           (1)
+#define MT6363_LDO_VSRAM_CPUL_WDTDBG_VOSEL_ADDR     (0x1e8e)
+#define MT6363_RG_LDO_VSRAM_APU_EN_ADDR             (0x1e9d)
+#define MT6363_RG_LDO_VSRAM_APU_EN_SHIFT            (0)
+#define MT6363_RG_LDO_VSRAM_APU_LP_ADDR             (0x1e9d)
+#define MT6363_RG_LDO_VSRAM_APU_LP_SHIFT            (1)
+#define MT6363_LDO_VSRAM_APU_WDTDBG_VOSEL_ADDR      (0x1ea4)
+#define MT6363_RG_VTREF18_VOCAL_ADDR                (0x1f08)
+#define MT6363_RG_VTREF18_VOCAL_MASK                (0xf)
+#define MT6363_RG_VTREF18_VOSEL_ADDR                (0x1f09)
+#define MT6363_RG_VTREF18_VOSEL_MASK                (0xf)
+#define MT6363_RG_VAUX18_VOCAL_ADDR                 (0x1f0c)
+#define MT6363_RG_VAUX18_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VAUX18_VOSEL_ADDR                 (0x1f0d)
+#define MT6363_RG_VAUX18_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VCN15_VOCAL_ADDR                  (0x1f13)
+#define MT6363_RG_VCN15_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VCN15_VOSEL_ADDR                  (0x1f14)
+#define MT6363_RG_VCN15_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VUFS18_VOCAL_ADDR                 (0x1f17)
+#define MT6363_RG_VUFS18_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VUFS18_VOSEL_ADDR                 (0x1f18)
+#define MT6363_RG_VUFS18_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VIO18_VOCAL_ADDR                  (0x1f1b)
+#define MT6363_RG_VIO18_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VIO18_VOSEL_ADDR                  (0x1f1c)
+#define MT6363_RG_VIO18_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VM18_VOCAL_ADDR                   (0x1f1f)
+#define MT6363_RG_VM18_VOCAL_MASK                   (0xf)
+#define MT6363_RG_VM18_VOSEL_ADDR                   (0x1f20)
+#define MT6363_RG_VM18_VOSEL_MASK                   (0xf)
+#define MT6363_RG_VA15_VOCAL_ADDR                   (0x1f23)
+#define MT6363_RG_VA15_VOCAL_MASK                   (0xf)
+#define MT6363_RG_VA15_VOSEL_ADDR                   (0x1f24)
+#define MT6363_RG_VA15_VOSEL_MASK                   (0xf)
+#define MT6363_RG_VRF18_VOCAL_ADDR                  (0x1f27)
+#define MT6363_RG_VRF18_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF18_VOSEL_ADDR                  (0x1f28)
+#define MT6363_RG_VRF18_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VRFIO18_VOCAL_ADDR                (0x1f2b)
+#define MT6363_RG_VRFIO18_VOCAL_MASK                (0xf)
+#define MT6363_RG_VRFIO18_VOSEL_ADDR                (0x1f2c)
+#define MT6363_RG_VRFIO18_VOSEL_MASK                (0xf)
+#define MT6363_RG_VIO075_VOCAL_ADDR                 (0x1f31)
+#define MT6363_RG_VIO075_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VIO075_VOSEL_ADDR                 (0x1f31)
+#define MT6363_RG_VIO075_VOSEL_MASK                 (0x70)
+#define MT6363_RG_VCN13_VOCAL_ADDR                  (0x1f88)
+#define MT6363_RG_VCN13_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VUFS12_VOCAL_ADDR                 (0x1f91)
+#define MT6363_RG_VUFS12_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VUFS12_VOSEL_ADDR                 (0x1f92)
+#define MT6363_RG_VUFS12_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VA12_1_VOCAL_ADDR                 (0x1f95)
+#define MT6363_RG_VA12_1_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VA12_1_VOSEL_ADDR                 (0x1f96)
+#define MT6363_RG_VA12_1_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VA12_2_VOCAL_ADDR                 (0x1f99)
+#define MT6363_RG_VA12_2_VOCAL_MASK                 (0xf)
+#define MT6363_RG_VA12_2_VOSEL_ADDR                 (0x1f9a)
+#define MT6363_RG_VA12_2_VOSEL_MASK                 (0xf)
+#define MT6363_RG_VRF12_VOCAL_ADDR                  (0x1f9d)
+#define MT6363_RG_VRF12_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF12_VOSEL_ADDR                  (0x1f9e)
+#define MT6363_RG_VRF12_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VRF13_VOCAL_ADDR                  (0x1fa1)
+#define MT6363_RG_VRF13_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF13_VOSEL_ADDR                  (0x1fa2)
+#define MT6363_RG_VRF13_VOSEL_MASK                  (0xf)
+#define MT6363_RG_VRF09_VOCAL_ADDR                  (0x1fa8)
+#define MT6363_RG_VRF09_VOCAL_MASK                  (0xf)
+#define MT6363_RG_VRF09_VOSEL_ADDR                  (0x1fa9)
+#define MT6363_RG_VRF09_VOSEL_MASK                  (0xf)
+#define MT6363_ISINK_EN_CTRL0                       (0x220b)
+#define MT6363_ISINK_EN_CTRL1                       (0x220c)
+
+
+#endif /* __LINUX_REGULATOR_MT6363_H */
diff --git a/include/linux/regulator/mt6373-regulator.h b/include/linux/regulator/mt6373-regulator.h
new file mode 100644
index 000000000000..9aa38741c31a
--- /dev/null
+++ b/include/linux/regulator/mt6373-regulator.h
@@ -0,0 +1,318 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6373_H
+#define __LINUX_REGULATOR_MT6373_H
+
+enum {
+	MT6373_ID_VBUCK0,
+	MT6373_ID_VBUCK1,
+	MT6373_ID_VBUCK2,
+	MT6373_ID_VBUCK3,
+	MT6373_ID_VBUCK4,
+	MT6373_ID_VBUCK4_UFS,
+	MT6373_ID_VBUCK5,
+	MT6373_ID_VBUCK6,
+	MT6373_ID_VBUCK7,
+	MT6373_ID_VBUCK8,
+	MT6373_ID_VBUCK9,
+	MT6373_ID_VUSB,
+	MT6373_ID_VAUX18,
+	MT6373_ID_VRF13_AIF,
+	MT6373_ID_VRF18_AIF,
+	MT6373_ID_VRFIO18_AIF,
+	MT6373_ID_VRF09_AIF,
+	MT6373_ID_VRF12_AIF,
+	MT6373_ID_VANT18,
+	MT6373_ID_VSRAM_DIGRF_AIF,
+	MT6373_ID_VIBR,
+	MT6373_ID_VIO28,
+	MT6373_ID_VFP,
+	MT6373_ID_VTP,
+	MT6373_ID_VMCH,
+	MT6373_ID_VMC,
+	MT6373_ID_VAUD18,
+	MT6373_ID_VCN33_1,
+	MT6373_ID_VCN33_2,
+	MT6373_ID_VCN33_3,
+	MT6373_ID_VCN18IO,
+	MT6373_ID_VEFUSE,
+	MT6373_ID_VMCH_EINT_HIGH,
+	MT6373_ID_VMCH_EINT_LOW,
+	MT6373_MAX_REGULATOR,
+};
+
+/* Register */
+#define MT6373_BUCK_TOP_KEY_PROT_LO                 0x142a
+#define MT6373_TOP_CFG_ELR5                         0x147
+#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_SHIFT         2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_SHIFT         3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT         4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_SHIFT         5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_SHIFT         6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_ADDR          0x240
+#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_SHIFT         7
+#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_ADDR          0x243
+#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_ADDR          0x243
+#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_SHIFT         2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_SHIFT         3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT         4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_SHIFT         5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_SHIFT         6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_ADDR          0x246
+#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_SHIFT         7
+#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_ADDR          0x249
+#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_SHIFT         0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_ADDR          0x249
+#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_SHIFT         1
+#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR       0x24c
+#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR       0x24d
+#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR       0x24e
+#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR       0x24f
+#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR       0x250
+#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR       0x251
+#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR       0x252
+#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR       0x253
+#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR       0x254
+#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR       0x255
+#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_MASK       0xFF
+#define MT6373_PMIC_RG_VBUCK8_FCCM_ADDR             0x199d
+#define MT6373_PMIC_RG_VBUCK8_FCCM_SHIFT            6
+#define MT6373_PMIC_RG_VBUCK9_FCCM_ADDR             0x199d
+#define MT6373_PMIC_RG_VBUCK9_FCCM_SHIFT            7
+#define MT6373_PMIC_RG_VBUCK0_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK0_FCCM_SHIFT            0
+#define MT6373_PMIC_RG_VBUCK1_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK1_FCCM_SHIFT            1
+#define MT6373_PMIC_RG_VBUCK2_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK2_FCCM_SHIFT            2
+#define MT6373_PMIC_RG_VBUCK3_FCCM_ADDR             0x1a32
+#define MT6373_PMIC_RG_VBUCK3_FCCM_SHIFT            3
+#define MT6373_PMIC_RG_VBUCK4_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT            0
+#define MT6373_PMIC_RG_VBUCK5_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK5_FCCM_SHIFT            1
+#define MT6373_PMIC_RG_VBUCK6_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK6_FCCM_SHIFT            2
+#define MT6373_PMIC_RG_VBUCK7_FCCM_ADDR             0x1ab2
+#define MT6373_PMIC_RG_VBUCK7_FCCM_SHIFT            3
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_ADDR 0x1b39
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_MASK 0x7F
+#define MT6373_PMIC_RG_LDO_VAUD18_EN_ADDR           0x1b87
+#define MT6373_PMIC_RG_LDO_VAUD18_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VAUD18_LP_ADDR           0x1b87
+#define MT6373_PMIC_RG_LDO_VAUD18_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VUSB_EN_ADDR             0x1b95
+#define MT6373_PMIC_RG_LDO_VUSB_EN_SHIFT            0
+#define MT6373_PMIC_RG_LDO_VUSB_LP_ADDR             0x1b95
+#define MT6373_PMIC_RG_LDO_VUSB_LP_SHIFT            1
+#define MT6373_PMIC_RG_LDO_VAUX18_EN_ADDR           0x1ba3
+#define MT6373_PMIC_RG_LDO_VAUX18_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VAUX18_LP_ADDR           0x1ba3
+#define MT6373_PMIC_RG_LDO_VAUX18_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_EN_ADDR        0x1bb1
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_LP_ADDR        0x1bb1
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_EN_ADDR        0x1bbf
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_LP_ADDR        0x1bbf
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_ADDR      0x1bcd
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_SHIFT     0
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_ADDR      0x1bcd
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_SHIFT     1
+#define MT6373_PMIC_RG_LDO_VCN33_1_EN_ADDR          0x1c07
+#define MT6373_PMIC_RG_LDO_VCN33_1_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN33_1_LP_ADDR          0x1c07
+#define MT6373_PMIC_RG_LDO_VCN33_1_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VCN33_2_EN_ADDR          0x1c15
+#define MT6373_PMIC_RG_LDO_VCN33_2_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN33_2_LP_ADDR          0x1c15
+#define MT6373_PMIC_RG_LDO_VCN33_2_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VCN33_3_EN_ADDR          0x1c23
+#define MT6373_PMIC_RG_LDO_VCN33_3_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN33_3_LP_ADDR          0x1c23
+#define MT6373_PMIC_RG_LDO_VCN33_3_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VCN18IO_EN_ADDR          0x1c31
+#define MT6373_PMIC_RG_LDO_VCN18IO_EN_SHIFT         0
+#define MT6373_PMIC_RG_LDO_VCN18IO_LP_ADDR          0x1c31
+#define MT6373_PMIC_RG_LDO_VCN18IO_LP_SHIFT         1
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_EN_ADDR        0x1c3f
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_LP_ADDR        0x1c3f
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_EN_ADDR        0x1c4d
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_EN_SHIFT       0
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_LP_ADDR        0x1c4d
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_LP_SHIFT       1
+#define MT6373_PMIC_RG_LDO_VANT18_EN_ADDR           0x1c87
+#define MT6373_PMIC_RG_LDO_VANT18_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VANT18_LP_ADDR           0x1c87
+#define MT6373_PMIC_RG_LDO_VANT18_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VEFUSE_EN_ADDR           0x1ca3
+#define MT6373_PMIC_RG_LDO_VEFUSE_EN_SHIFT          0
+#define MT6373_PMIC_RG_LDO_VEFUSE_LP_ADDR           0x1ca3
+#define MT6373_PMIC_RG_LDO_VEFUSE_LP_SHIFT          1
+#define MT6373_PMIC_RG_LDO_VMCH_EN_ADDR             0x1cb1
+#define MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT            0
+#define MT6373_PMIC_RG_LDO_VMCH_LP_ADDR             0x1cb1
+#define MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT            1
+#define MT6373_PMIC_RG_LDO_VMC_EN_ADDR              0x1cc0
+#define MT6373_PMIC_RG_LDO_VMC_EN_SHIFT             0
+#define MT6373_PMIC_RG_LDO_VMC_LP_ADDR              0x1cc0
+#define MT6373_PMIC_RG_LDO_VMC_LP_SHIFT             1
+#define MT6373_PMIC_RG_LDO_VIBR_EN_ADDR             0x1cce
+#define MT6373_PMIC_RG_LDO_VIBR_EN_SHIFT            0
+#define MT6373_PMIC_RG_LDO_VIBR_LP_ADDR             0x1cce
+#define MT6373_PMIC_RG_LDO_VIBR_LP_SHIFT            1
+#define MT6373_PMIC_RG_LDO_VIO28_EN_ADDR            0x1d07
+#define MT6373_PMIC_RG_LDO_VIO28_EN_SHIFT           0
+#define MT6373_PMIC_RG_LDO_VIO28_LP_ADDR            0x1d07
+#define MT6373_PMIC_RG_LDO_VIO28_LP_SHIFT           1
+#define MT6373_PMIC_RG_LDO_VFP_EN_ADDR              0x1d15
+#define MT6373_PMIC_RG_LDO_VFP_EN_SHIFT             0
+#define MT6373_PMIC_RG_LDO_VFP_LP_ADDR              0x1d15
+#define MT6373_PMIC_RG_LDO_VFP_LP_SHIFT             1
+#define MT6373_PMIC_RG_LDO_VTP_EN_ADDR              0x1d23
+#define MT6373_PMIC_RG_LDO_VTP_EN_SHIFT             0
+#define MT6373_PMIC_RG_LDO_VTP_LP_ADDR              0x1d23
+#define MT6373_PMIC_RG_LDO_VTP_LP_SHIFT             1
+#define MT6373_PMIC_RG_LDO_VSIM1_EN_ADDR            0x1d31
+#define MT6373_PMIC_RG_LDO_VSIM1_EN_SHIFT           0
+#define MT6373_PMIC_RG_LDO_VSIM1_LP_ADDR            0x1d31
+#define MT6373_PMIC_RG_LDO_VSIM1_LP_SHIFT           1
+#define MT6373_PMIC_RG_LDO_VSIM2_EN_ADDR            0x1d40
+#define MT6373_PMIC_RG_LDO_VSIM2_EN_SHIFT           0
+#define MT6373_PMIC_RG_LDO_VSIM2_LP_ADDR            0x1d40
+#define MT6373_PMIC_RG_LDO_VSIM2_LP_SHIFT           1
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_ADDR  0x1d87
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_SHIFT 0
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_ADDR  0x1d87
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_SHIFT 1
+#define MT6373_PMIC_RG_VAUX18_VOCAL_ADDR            0x1e08
+#define MT6373_PMIC_RG_VAUX18_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VAUX18_VOSEL_ADDR            0x1e09
+#define MT6373_PMIC_RG_VAUX18_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VUSB_VOCAL_ADDR              0x1e0c
+#define MT6373_PMIC_RG_VUSB_VOCAL_MASK              0xF
+#define MT6373_PMIC_RG_VUSB_VOSEL_ADDR              0x1e0d
+#define MT6373_PMIC_RG_VUSB_VOSEL_MASK              0xF
+#define MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR           0x1e10
+#define MT6373_PMIC_RG_VCN33_1_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR           0x1e11
+#define MT6373_PMIC_RG_VCN33_1_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR           0x1e14
+#define MT6373_PMIC_RG_VCN33_2_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR           0x1e15
+#define MT6373_PMIC_RG_VCN33_2_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR           0x1e18
+#define MT6373_PMIC_RG_VCN33_3_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR           0x1e19
+#define MT6373_PMIC_RG_VCN33_3_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VMCH_VOCAL_ADDR              0x1e1c
+#define MT6373_PMIC_RG_VMCH_VOCAL_MASK              0xF
+#define MT6373_PMIC_RG_VMCH_VOSEL_ADDR              0x1e1d
+#define MT6373_PMIC_RG_VMCH_VOSEL_MASK              0xF
+#define MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR            0x1e20
+#define MT6373_PMIC_RG_VEFUSE_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR            0x1e21
+#define MT6373_PMIC_RG_VEFUSE_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VMC_VOCAL_ADDR               0x1e24
+#define MT6373_PMIC_RG_VMC_VOCAL_MASK               0xF
+#define MT6373_PMIC_RG_VMC_VOSEL_ADDR               0x1e25
+#define MT6373_PMIC_RG_VMC_VOSEL_MASK               0xF
+#define MT6373_PMIC_RG_VIBR_VOCAL_ADDR              0x1e28
+#define MT6373_PMIC_RG_VIBR_VOCAL_MASK              0xF
+#define MT6373_PMIC_RG_VIBR_VOSEL_ADDR              0x1e29
+#define MT6373_PMIC_RG_VIBR_VOSEL_MASK              0xF
+#define MT6373_PMIC_RG_VIO28_VOCAL_ADDR             0x1e2c
+#define MT6373_PMIC_RG_VIO28_VOCAL_MASK             0xF
+#define MT6373_PMIC_RG_VIO28_VOSEL_ADDR             0x1e2d
+#define MT6373_PMIC_RG_VIO28_VOSEL_MASK             0xF
+#define MT6373_PMIC_RG_VFP_VOCAL_ADDR               0x1e30
+#define MT6373_PMIC_RG_VFP_VOCAL_MASK               0xF
+#define MT6373_PMIC_RG_VFP_VOSEL_ADDR               0x1e31
+#define MT6373_PMIC_RG_VFP_VOSEL_MASK               0xF
+#define MT6373_PMIC_RG_VTP_VOCAL_ADDR               0x1e34
+#define MT6373_PMIC_RG_VTP_VOCAL_MASK               0xF
+#define MT6373_PMIC_RG_VTP_VOSEL_ADDR               0x1e35
+#define MT6373_PMIC_RG_VTP_VOSEL_MASK               0xF
+#define MT6373_PMIC_RG_VSIM1_VOCAL_ADDR             0x1e38
+#define MT6373_PMIC_RG_VSIM1_VOCAL_MASK             0xF
+#define MT6373_PMIC_RG_VSIM1_VOSEL_ADDR             0x1e39
+#define MT6373_PMIC_RG_VSIM1_VOSEL_MASK             0xF
+#define MT6373_PMIC_RG_VSIM2_VOCAL_ADDR             0x1e3c
+#define MT6373_PMIC_RG_VSIM2_VOCAL_MASK             0xF
+#define MT6373_PMIC_RG_VSIM2_VOSEL_ADDR             0x1e3d
+#define MT6373_PMIC_RG_VSIM2_VOSEL_MASK             0xF
+#define MT6373_PMIC_RG_VAUD18_VOCAL_ADDR            0x1e88
+#define MT6373_PMIC_RG_VAUD18_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VAUD18_VOSEL_ADDR            0x1e89
+#define MT6373_PMIC_RG_VAUD18_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR         0x1e8c
+#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR         0x1e8d
+#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_MASK         0xF
+#define MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR           0x1e90
+#define MT6373_PMIC_RG_VCN18IO_VOCAL_MASK           0xF
+#define MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR           0x1e91
+#define MT6373_PMIC_RG_VCN18IO_VOSEL_MASK           0xF
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR       0x1e94
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_MASK       0xF
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR       0x1e95
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_MASK       0xF
+#define MT6373_PMIC_RG_VANT18_VOCAL_ADDR            0x1e98
+#define MT6373_PMIC_RG_VANT18_VOCAL_MASK            0xF
+#define MT6373_PMIC_RG_VANT18_VOSEL_ADDR            0x1e99
+#define MT6373_PMIC_RG_VANT18_VOSEL_MASK            0xF
+#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR         0x1f08
+#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR         0x1f09
+#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_MASK         0xF
+#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR         0x1f0c
+#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR         0x1f0d
+#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_MASK         0xF
+#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR         0x1f88
+#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_MASK         0xF
+#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR         0x1f89
+#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_MASK         0xF
+
+#define MT6373_LDO_VMCH_EINT                        0x1cbf
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_EN_MASK        0x1
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK       0x4
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_DB_MASK        0x10
+
+#endif /* __LINUX_REGULATOR_MT6373_H */
-- 
2.46.0


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

* 回复: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver
  2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
  2025-03-14  8:53   ` AngeloGioacchino Del Regno
@ 2025-03-14  9:04   ` Lu Tang (汤璐)
  2025-03-15 12:50   ` Jonathan Cameron
  2 siblings, 0 replies; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:04 UTC (permalink / raw)
  To: Lu Tang (汤璐), Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, AngeloGioacchino Del Regno,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group


Update email address

-----邮件原件-----
发件人: Lu.Tang <Lu.Tang@mediatek.com> 
发送时间: 2025年3月14日 15:32
收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
主题: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver

From: "Lu.Tang" <lu.tang@mediatek.com>

Add pmic mt6363 and mt6373 auxadc driver

Signed-off-by: Lu Tang <lu.tang@mediatek.com>
---
 drivers/iio/adc/Kconfig             |  10 +
 drivers/iio/adc/Makefile            |   1 +
 drivers/iio/adc/mtk-spmi-pmic-adc.c | 576 ++++++++++++++++++++++++++++
 3 files changed, 587 insertions(+)
 create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 27413516216c..7c4b5f8f7209 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1039,6 +1039,16 @@ config MEDIATEK_MT6577_AUXADC
 	  This driver can also be built as a module. If so, the module will be
 	  called mt6577_auxadc.
 
+config MEDIATEK_SPMI_PMIC_ADC
+	tristate "MediaTek SPMI PMIC ADC Support"
+	depends on MFD_MTK_SPMI_PMIC
+	help
+	  Say yes here to enable support for MediaTek SPMI PMIC ADC.
+	  The driver supports multiple channels read.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called mtk-spmi-pmic-adc.
+
 config MEN_Z188_ADC
 	tristate "MEN 16z188 ADC IP Core support"
 	depends on MCB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9f26d5eca822..b3224abea040 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
 obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
 obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
+obj-$(CONFIG_MEDIATEK_SPMI_PMIC_ADC) += mtk-spmi-pmic-adc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
 obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o diff --git a/drivers/iio/adc/mtk-spmi-pmic-adc.c b/drivers/iio/adc/mtk-spmi-pmic-adc.c
new file mode 100644
index 000000000000..61e062bc8cf5
--- /dev/null
+++ b/drivers/iio/adc/mtk-spmi-pmic-adc.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/mt6363/registers.h> #include 
+<linux/mfd/mt6373/registers.h> #include <linux/module.h> #include 
+<linux/of.h> #include <linux/of_device.h> #include <linux/property.h> 
+#include <linux/platform_device.h> #include <linux/power_supply.h> 
+#include <linux/regmap.h> #include <linux/regulator/consumer.h> 
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/iio/mt635x-auxadc.h>
+
+#define AUXADC_RDY_BIT			BIT(15)
+
+#define AUXADC_DEF_R_RATIO		1
+#define AUXADC_DEF_AVG_NUM		32
+
+#define AUXADC_AVG_TIME_US		10
+#define AUXADC_POLL_DELAY_US		100
+#define AUXADC_TIMEOUT_US		32000
+#define VOLT_FULL			1840
+
+#define IMP_VOLT_FULL			18400
+#define IMIX_R_MIN_MOHM			100
+#define IMIX_R_CALI_CNT			2
+
+#define EXT_THR_PURES_SHIFT		3
+#define EXT_THR_SEL_MASK		0x1F
+
+#define DT_CHANNEL_CONVERT(val)		((val) & 0xFF)
+#define DT_PURES_CONVERT(val)		(((val) & 0xFF00) >> 8)
+
+struct pmic_adc_device {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex lock;
+	struct iio_chan_spec *iio_chans;
+	unsigned int nchannels;
+	const struct auxadc_info *info;
+	struct regulator *isink_load;
+	int imix_r;
+	int imp_curr;
+	int pre_uisoc;
+};
+
+static struct pmic_adc_device *imix_r_dev;
+
+/*
+ * @ch_name:	HW channel name
+ * @res:	ADC resolution
+ * @r_ratio:	resistance ratio, represented by r_ratio[0] / r_ratio[1]
+ * @avg_num:	sampling times of AUXADC measurements then average it
+ * @regs:	request and data output registers for this channel
+ */
+struct auxadc_channels {
+	enum iio_chan_type type;
+	long info_mask;
+	/* AUXADC channel attribute */
+	const char *ch_name;
+	unsigned char res;
+	unsigned char r_ratio[2];
+	unsigned short avg_num;
+	const struct auxadc_regs *regs;
+};
+
+#define AUXADC_CHANNEL(_ch_name, _res)	\
+	[AUXADC_##_ch_name] = {				\
+		.type = IIO_VOLTAGE,			\
+		.info_mask = BIT(IIO_CHAN_INFO_RAW) |		\
+			     BIT(IIO_CHAN_INFO_PROCESSED),	\
+		.ch_name = __stringify(_ch_name),	\
+		.res = _res,				\
+	}
+
+/*
+ * The array represents all possible AUXADC channels found
+ * in the supported PMICs.
+ */
+static struct auxadc_channels auxadc_chans[] = {
+	AUXADC_CHANNEL(BATADC, 15),
+	AUXADC_CHANNEL(VCDT, 12),
+	AUXADC_CHANNEL(BAT_TEMP, 12),
+	AUXADC_CHANNEL(CHIP_TEMP, 12),
+	AUXADC_CHANNEL(VCORE_TEMP, 12),
+	AUXADC_CHANNEL(VPROC_TEMP, 12),
+	AUXADC_CHANNEL(VGPU_TEMP, 12),
+	AUXADC_CHANNEL(ACCDET, 12),
+	AUXADC_CHANNEL(HPOFS_CAL, 15),
+	AUXADC_CHANNEL(VTREF, 12),
+	AUXADC_CHANNEL(VBIF, 12),
+	AUXADC_CHANNEL(IMP, 15),
+	[AUXADC_IMIX_R] = {
+		.type = IIO_RESISTANCE,
+		.info_mask = BIT(IIO_CHAN_INFO_RAW),
+		.ch_name = "IMIX_R",
+	},
+	AUXADC_CHANNEL(VSYSSNS, 15),
+	AUXADC_CHANNEL(VIN1, 15),
+	AUXADC_CHANNEL(VIN2, 15),
+	AUXADC_CHANNEL(VIN3, 15),
+	AUXADC_CHANNEL(VIN4, 15),
+	AUXADC_CHANNEL(VIN5, 15),
+	AUXADC_CHANNEL(VIN6, 15),
+	AUXADC_CHANNEL(VIN7, 15),
+};
+
+struct auxadc_regs {
+	unsigned int enable_reg;
+	unsigned int enable_mask;
+	unsigned int ready_reg;
+	unsigned int ready_mask;
+	unsigned int value_reg;
+	unsigned int ext_thr_sel;
+	u8 src_sel;
+};
+
+#define AUXADC_REG(_ch_name, _chip, _enable_reg, _enable_mask, _value_reg) \
+	[AUXADC_##_ch_name] = {				\
+		.enable_reg = _chip##_##_enable_reg,	\
+		.enable_mask = _enable_mask,		\
+		.ready_reg = _chip##_##_value_reg,	\
+		.ready_mask = AUXADC_RDY_BIT,		\
+		.value_reg = _chip##_##_value_reg,	\
+	}						\
+
+#define TIA_ADC_REG(_src_sel, _chip)	\
+	[AUXADC_VIN##_src_sel] = {			\
+		.enable_reg = _chip##_AUXADC_RQST1,	\
+		.enable_mask = BIT(4),			\
+		.ready_reg = _chip##_AUXADC_ADC_CH12_L,	\
+		.ready_mask = AUXADC_RDY_BIT,		\
+		.value_reg = _chip##_AUXADC_ADC_CH12_L,	\
+		.ext_thr_sel = _chip##_SDMADC_CON0,	\
+		.src_sel = _src_sel,			\
+	}						\
+
+static const struct auxadc_regs mt6363_auxadc_regs_tbl[] = {
+	AUXADC_REG(BATADC, MT6363, AUXADC_RQST0, BIT(0), AUXADC_ADC0_L),
+	AUXADC_REG(BAT_TEMP, MT6363, AUXADC_RQST0, BIT(3), AUXADC_ADC3_L),
+	AUXADC_REG(CHIP_TEMP, MT6363, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L),
+	AUXADC_REG(VCORE_TEMP, MT6363, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L),
+	AUXADC_REG(VPROC_TEMP, MT6363, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L),
+	AUXADC_REG(VGPU_TEMP, MT6363, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L),
+	AUXADC_REG(VTREF, MT6363, AUXADC_RQST1, BIT(3), AUXADC_ADC11_L),
+	[AUXADC_IMP] = {
+		.enable_reg = MT6363_AUXADC_IMP0,
+		.enable_mask = BIT(0),
+		.ready_reg = MT6363_AUXADC_IMP1,
+		.ready_mask = BIT(7),
+		.value_reg = MT6363_AUXADC_ADC42_L,
+	},
+	AUXADC_REG(VSYSSNS, MT6363, AUXADC_RQST1, BIT(6), AUXADC_ADC_CH14_L),
+	TIA_ADC_REG(1, MT6363),
+	TIA_ADC_REG(2, MT6363),
+	TIA_ADC_REG(3, MT6363),
+	TIA_ADC_REG(4, MT6363),
+	TIA_ADC_REG(5, MT6363),
+	TIA_ADC_REG(6, MT6363),
+	TIA_ADC_REG(7, MT6363),
+};
+
+static const struct auxadc_regs mt6373_auxadc_regs_tbl[] = {
+	AUXADC_REG(CHIP_TEMP, MT6373, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L),
+	AUXADC_REG(VCORE_TEMP, MT6373, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L),
+	AUXADC_REG(VPROC_TEMP, MT6373, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L),
+	AUXADC_REG(VGPU_TEMP, MT6373, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L),
+	TIA_ADC_REG(1, MT6373),
+	TIA_ADC_REG(2, MT6373),
+	TIA_ADC_REG(3, MT6373),
+	TIA_ADC_REG(4, MT6373),
+	TIA_ADC_REG(5, MT6373),
+};
+
+struct auxadc_info {
+	const struct auxadc_regs *regs_tbl;
+};
+
+static const struct auxadc_info mt6363_info = {
+	.regs_tbl = mt6363_auxadc_regs_tbl,
+};
+
+static const struct auxadc_info mt6373_info = {
+	.regs_tbl = mt6373_auxadc_regs_tbl,
+};
+
+#define regmap_bulk_read_poll_timeout(map, addr, val, val_count, cond, 
+sleep_us, timeout_us) \ ({ \
+	u64 __timeout_us = (timeout_us); \
+	unsigned long __sleep_us = (sleep_us); \
+	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
+	int __ret; \
+	might_sleep_if(__sleep_us); \
+	for (;;) { \
+		__ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \
+		if (__ret) \
+			break; \
+		if (cond) \
+			break; \
+		if ((__timeout_us) && \
+		    ktime_compare(ktime_get(), __timeout) > 0) { \
+			__ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \
+			break; \
+		} \
+		if (__sleep_us) \
+			usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
+	} \
+	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
+/*
+ * @adc_dev:	 pointer to the struct pmic_adc_device
+ * @auxadc_chan: pointer to the struct auxadc_channels, it represents specific
+		 auxadc channel
+ * @val:	 pointer to output value
+ */
+static int get_auxadc_out(struct pmic_adc_device *adc_dev,
+			  int channel, int channel2, int *val) {
+	int ret;
+	u16 buf = 0;
+	const struct auxadc_channels *auxadc_chan = &auxadc_chans[channel];
+
+	if (!auxadc_chan->regs)
+		return -EINVAL;
+
+	if (auxadc_chan->regs->ext_thr_sel) {
+		buf = (channel2 << EXT_THR_PURES_SHIFT)
+			| auxadc_chan->regs->src_sel;
+		ret = regmap_update_bits(adc_dev->regmap,
+					 auxadc_chan->regs->ext_thr_sel,
+					 EXT_THR_SEL_MASK, buf);
+		if (ret < 0)
+			return ret;
+	}
+	regmap_write(adc_dev->regmap,
+		     auxadc_chan->regs->enable_reg,
+		     auxadc_chan->regs->enable_mask);
+	usleep_range(auxadc_chan->avg_num * AUXADC_AVG_TIME_US,
+		     (auxadc_chan->avg_num + 1) * AUXADC_AVG_TIME_US);
+
+	ret = regmap_bulk_read_poll_timeout(adc_dev->regmap,
+					    auxadc_chan->regs->value_reg,
+					    buf, 2,
+					    (buf & AUXADC_RDY_BIT),
+					    AUXADC_POLL_DELAY_US,
+					    AUXADC_TIMEOUT_US);
+	*val = buf & (BIT(auxadc_chan->res) - 1);
+	if (ret)
+		dev_err(adc_dev->dev, "%s ret error code:%d!\n", 
+auxadc_chan->ch_name, ret);
+
+	/* set PURES to OPEN after measuring done */
+	if (auxadc_chan->regs->ext_thr_sel) {
+		buf = (ADC_PURES_OPEN << EXT_THR_PURES_SHIFT)
+			| auxadc_chan->regs->src_sel;
+		ret = regmap_update_bits(adc_dev->regmap,
+					 auxadc_chan->regs->ext_thr_sel,
+					 EXT_THR_SEL_MASK, buf);
+	}
+
+	return ret;
+}
+
+static int gauge_get_imp_ibat(void)
+{
+	struct power_supply *psy;
+	union power_supply_propval prop;
+	int ret;
+
+	psy = power_supply_get_by_name("mtk-gauge");
+	if (!psy)
+		return 0;
+
+	ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop);
+	if (ret)
+		return ret;
+
+	power_supply_put(psy);
+	return prop.intval;
+}
+
+static int get_imp_out(struct pmic_adc_device *adc_dev, int *val) {
+	int ret;
+	unsigned int buf = 0;
+	const struct auxadc_channels *auxadc_chan = &auxadc_chans[AUXADC_IMP];
+
+	if (!auxadc_chan->regs)
+		return -EINVAL;
+
+	regmap_write(adc_dev->regmap,
+		     auxadc_chan->regs->enable_reg,
+		     auxadc_chan->regs->enable_mask);
+	ret = regmap_read_poll_timeout(adc_dev->regmap, auxadc_chan->regs->ready_reg,
+					   buf, buf & auxadc_chan->regs->ready_mask,
+					   AUXADC_POLL_DELAY_US,
+					   AUXADC_TIMEOUT_US);
+	if (ret) {
+		dev_err(adc_dev->dev, "%s %s ret error code:%d!\n",
+			__func__, auxadc_chan->ch_name, ret);
+		return ret;
+	}
+
+	ret = regmap_bulk_read(adc_dev->regmap, auxadc_chan->regs->value_reg, (u8 *) &buf, 2);
+	if (ret)
+		return ret;
+	*val = buf & (BIT(auxadc_chan->res) - 1);
+	adc_dev->imp_curr = gauge_get_imp_ibat();
+
+	regmap_write(adc_dev->regmap,
+		     auxadc_chan->regs->enable_reg, 0);
+
+	return 0;
+}
+
+static int pmic_adc_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask) {
+	struct pmic_adc_device *adc_dev = iio_priv(indio_dev);
+	const struct auxadc_channels *auxadc_chan;
+	int auxadc_out = 0;
+	int ret = 0;
+
+	mutex_lock(&adc_dev->lock);
+	switch (chan->channel) {
+	case AUXADC_IMP:
+		ret = get_imp_out(adc_dev, &auxadc_out);
+		break;
+	case AUXADC_IMIX_R:
+		auxadc_out = adc_dev->imix_r;
+		break;
+	default:
+		ret = get_auxadc_out(adc_dev,
+				     chan->channel, chan->channel2,
+				     &auxadc_out);
+		break;
+	}
+	mutex_unlock(&adc_dev->lock);
+
+	if (ret && ret != -ETIMEDOUT)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		auxadc_chan = &auxadc_chans[chan->channel];
+		*val = auxadc_out * auxadc_chan->r_ratio[0] * VOLT_FULL;
+		*val = (*val / auxadc_chan->r_ratio[1]) >> auxadc_chan->res;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_RAW:
+		*val = auxadc_out;
+		ret = IIO_VAL_INT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (chan->channel == AUXADC_IMP) {
+		*val2 = adc_dev->imp_curr;
+		ret = IIO_VAL_INT_MULTIPLE;
+	}
+
+	return ret;
+}
+
+static int pmic_adc_fwnode_xlate(struct iio_dev *indio_dev,
+			     const struct fwnode_reference_args *iiospec) {
+	int i;
+	int channel = DT_CHANNEL_CONVERT(iiospec->args[0]);
+	int channel2 = DT_PURES_CONVERT(iiospec->args[0]);
+
+	for (i = 0; i < indio_dev->num_channels; i++) {
+		if (indio_dev->channels[i].channel == channel &&
+		    indio_dev->channels[i].channel2 == channel2)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info pmic_adc_info = {
+	.read_raw = &pmic_adc_read_raw,
+	.fwnode_xlate = &pmic_adc_fwnode_xlate, };
+
+static int auxadc_init_imix_r(struct pmic_adc_device *adc_dev,
+			      struct device_node *imix_r_node) {
+	unsigned int val = 0;
+	int ret;
+
+	if (!adc_dev)
+		return -EINVAL;
+
+	adc_dev->isink_load = devm_regulator_get_exclusive(adc_dev->dev, "isink_load");
+	if (IS_ERR(adc_dev->isink_load)) {
+		dev_err(adc_dev->dev, "Failed to get isink_load regulator, ret=%d\n",
+			(int)PTR_ERR(adc_dev->isink_load));
+		return PTR_ERR(adc_dev->isink_load);
+	}
+
+	imix_r_dev = adc_dev;
+	if (imix_r_dev->imix_r)
+		return 0;
+
+	ret = of_property_read_u32(imix_r_node, "val", &val);
+	if (ret)
+		dev_notice(imix_r_dev->dev, "no imix_r, ret=%d\n", ret);
+	imix_r_dev->imix_r = (int)val;
+	imix_r_dev->pre_uisoc = 101;
+	return 0;
+}
+
+static int auxadc_get_data_from_dt(struct pmic_adc_device *adc_dev,
+				   struct iio_chan_spec *iio_chan,
+				   struct device_node *node)
+{
+	struct auxadc_channels *auxadc_chan;
+	unsigned int channel = 0;
+	unsigned int value = 0;
+	unsigned int val_arr[2] = {0};
+	int ret;
+
+	ret = of_property_read_u32(node, "channel", &channel);
+	if (ret) {
+		dev_err(adc_dev->dev, "invalid channel in node:%s\n",
+			   node->name);
+		return ret;
+	}
+	if (channel > AUXADC_CHAN_MAX) {
+		dev_err(adc_dev->dev, "invalid channel number %d in node:%s\n",
+			   channel, node->name);
+		return -EINVAL;
+	}
+	if (channel >= ARRAY_SIZE(auxadc_chans)) {
+		dev_err(adc_dev->dev, "channel number %d in node:%s not exists\n",
+			   channel, node->name);
+		return -EINVAL;
+	}
+	iio_chan->channel = channel;
+	iio_chan->datasheet_name = auxadc_chans[channel].ch_name;
+	iio_chan->info_mask_separate = auxadc_chans[channel].info_mask;
+	iio_chan->type = auxadc_chans[channel].type;
+	iio_chan->extend_name = node->name;
+	ret = of_property_read_u32(node, "pures", &value);
+	if (!ret)
+		iio_chan->channel2 = value;
+
+	if (channel == AUXADC_IMIX_R)
+		return auxadc_init_imix_r(adc_dev, node);
+
+	auxadc_chan = &auxadc_chans[channel];
+	auxadc_chan->regs = &adc_dev->info->regs_tbl[channel];
+
+	ret = of_property_read_u32_array(node, "resistance-ratio", val_arr, 2);
+	if (!ret) {
+		auxadc_chan->r_ratio[0] = val_arr[0];
+		auxadc_chan->r_ratio[1] = val_arr[1];
+	} else {
+		auxadc_chan->r_ratio[0] = AUXADC_DEF_R_RATIO;
+		auxadc_chan->r_ratio[1] = 1;
+	}
+
+	ret = of_property_read_u32(node, "avg-num", &value);
+	if (!ret)
+		auxadc_chan->avg_num = value;
+	else
+		auxadc_chan->avg_num = AUXADC_DEF_AVG_NUM;
+
+	return 0;
+}
+
+static int auxadc_parse_dt(struct pmic_adc_device *adc_dev,
+			   struct device_node *node)
+{
+	struct iio_chan_spec *iio_chan;
+	struct device_node *child;
+	unsigned int index = 0;
+	int ret;
+
+	adc_dev->nchannels = of_get_available_child_count(node);
+	if (!adc_dev->nchannels)
+		return -EINVAL;
+
+	adc_dev->iio_chans = devm_kcalloc(adc_dev->dev, adc_dev->nchannels,
+		sizeof(*adc_dev->iio_chans), GFP_KERNEL);
+	if (!adc_dev->iio_chans)
+		return -ENOMEM;
+	iio_chan = adc_dev->iio_chans;
+
+	for_each_available_child_of_node(node, child) {
+		ret = auxadc_get_data_from_dt(adc_dev, iio_chan, child);
+		if (ret < 0) {
+			of_node_put(child);
+			return ret;
+		}
+		iio_chan->indexed = 1;
+		iio_chan->address = index++;
+		iio_chan++;
+	}
+
+	return 0;
+}
+
+static int pmic_adc_probe(struct platform_device *pdev) {
+	struct device_node *node = pdev->dev.of_node;
+	struct pmic_adc_device *adc_dev;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+	adc_dev->dev = &pdev->dev;
+	adc_dev->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	mutex_init(&adc_dev->lock);
+	adc_dev->info = of_device_get_match_data(&pdev->dev);
+
+	ret = auxadc_parse_dt(adc_dev, node);
+	if (ret) {
+		dev_notice(&pdev->dev, "auxadc_parse_dt fail, ret=%d\n", ret);
+		return ret;
+	}
+
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &pmic_adc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = adc_dev->iio_chans;
+	indio_dev->num_channels = adc_dev->nchannels;
+
+	ret = devm_iio_device_register(&pdev->dev, indio_dev);
+	if (ret < 0) {
+		dev_notice(&pdev->dev, "failed to register iio device!\n");
+		return ret;
+	}
+
+	dev_dbg(&pdev->dev, "probe done\n");
+
+	return 0;
+}
+
+static const struct of_device_id pmic_adc_of_match[] = {
+	{ .compatible = "mediatek,mt6363-auxadc", .data = &mt6363_info, },
+	{ .compatible = "mediatek,mt6373-auxadc", .data = &mt6373_info, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pmic_adc_of_match);
+
+static struct platform_driver pmic_adc_driver = {
+	.driver = {
+		.name = "mtk-spmi-pmic-adc",
+		.of_match_table = pmic_adc_of_match,
+	},
+	.probe	= pmic_adc_probe,
+};
+module_platform_driver(pmic_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lu Tang <lu.tang@mediatek.com>"); 
+MODULE_DESCRIPTION("MediaTek SPMI PMIC ADC Driver");
--
2.46.0


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

* 回复: [PATCH 0/5] Add PMIC and SPMI driver for mt8196
  2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
                   ` (5 preceding siblings ...)
  2025-03-14  8:27 ` [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Chen-Yu Tsai
@ 2025-03-14  9:06 ` Lu Tang (汤璐)
  6 siblings, 0 replies; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:06 UTC (permalink / raw)
  To: Lu Tang (汤璐), Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, AngeloGioacchino Del Regno,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group


Update email address

-----邮件原件-----
发件人: Lu.Tang <Lu.Tang@mediatek.com> 
发送时间: 2025年3月14日 15:32
收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
主题: [PATCH 0/5] Add PMIC and SPMI driver for mt8196

This series is based on linux-next.

Changes in v0:
- Modify SPMI driver for mt8196
- Add SPMI PMIC mfd driver
- Add PMIC regulator driver for mt8196

*** BLURB HERE ***

Lu.Tang (5):
  pmic: mediatek: Add pmic auxadc driver
  pmic: mediatek: Add pmic regulator driver
  pmic: mediatek: Add spmi pmic mfd driver
  spmi: mediatek: modify spmi dirver for mt8196
  dt-bindings: pmic: mediatek: Add pmic documents

 .../iio/adc/mediatek,spmi-pmic-auxadc.yaml    |   31 +
 .../bindings/input/mediatek,pmic-keys.yaml    |    1 +
 .../bindings/mfd/mediatek,mt6685.yaml         |   50 +
 .../bindings/mfd/mediatek,spmi-pmic.yaml      |  173 +++
 .../pinctrl/mediatek,mt65xx-pinctrl.yaml      |    1 +
 drivers/iio/adc/Kconfig                       |   10 +
 drivers/iio/adc/Makefile                      |    1 +
 drivers/iio/adc/mtk-spmi-pmic-adc.c           |  576 +++++++++
 drivers/mfd/Kconfig                           |   26 +
 drivers/mfd/Makefile                          |    2 +
 drivers/mfd/mt6685-core.c                     |   83 ++
 drivers/mfd/mtk-spmi-pmic.c                   |  518 ++++++++
 drivers/regulator/Kconfig                     |   34 +
 drivers/regulator/Makefile                    |    3 +
 drivers/regulator/mt6316-regulator.c          |  381 ++++++
 drivers/regulator/mt6363-regulator.c          | 1106 +++++++++++++++++
 drivers/regulator/mt6373-regulator.c          |  826 ++++++++++++
 drivers/spmi/spmi-mtk-pmif.c                  | 1040 +++++++++++++++-
 include/linux/mfd/mt6363/core.h               |  134 ++
 include/linux/mfd/mt6363/registers.h          |  168 +++
 include/linux/mfd/mt6373/core.h               |   94 ++
 include/linux/mfd/mt6373/registers.h          |   53 +
 include/linux/regulator/mt6316-regulator.h    |   48 +
 include/linux/regulator/mt6363-regulator.h    |  424 +++++++
 include/linux/regulator/mt6373-regulator.h    |  318 +++++
 25 files changed, 6037 insertions(+), 64 deletions(-)  create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
 create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c
 create mode 100644 drivers/mfd/mt6685-core.c  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/core.h  create mode 100644 include/linux/mfd/mt6363/registers.h
 create mode 100644 include/linux/mfd/mt6373/core.h  create mode 100644 include/linux/mfd/mt6373/registers.h
 create mode 100644 include/linux/regulator/mt6316-regulator.h
 create mode 100644 include/linux/regulator/mt6363-regulator.h
 create mode 100644 include/linux/regulator/mt6373-regulator.h

--
2.46.0


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

* 回复: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver
  2025-03-14  8:53   ` AngeloGioacchino Del Regno
@ 2025-03-14  9:21     ` Lu Tang (汤璐)
  2025-03-14 12:15       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 24+ messages in thread
From: Lu Tang (汤璐) @ 2025-03-14  9:21 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno, Jonathan Cameron, Lars-Peter Clausen,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Lee Jones, Matthias Brugger, Sean Wang, Linus Walleij,
	Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

Update email

-----邮件原件-----
发件人: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 
发送时间: 2025年3月14日 16:53
收件人: Lu Tang (汤璐) <Lu.Tang@mediatek.com>; Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>
主题: Re: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver


External email : Please do not click links or open attachments until you have verified the sender or the content.


Il 14/03/25 08:32, Lu.Tang ha scritto:
> From: "Lu.Tang" <lu.tang@mediatek.com>
>
> Add pmic mt6363 and mt6373 auxadc driver
>

Can't you just add MT6363 and MT6373 support to the already present mt6359-auxadc driver?!

Regards,
Angelo



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

* Re: 回复: [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver
  2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
@ 2025-03-14  9:47     ` Lee Jones
  0 siblings, 0 replies; 24+ messages in thread
From: Lee Jones @ 2025-03-14  9:47 UTC (permalink / raw)
  To: Lu Tang (汤璐)
  Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森),
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On Fri, 14 Mar 2025, Lu Tang (汤璐) wrote:

> Update email address

What is this?

Please refrain from top-posting.

> -----邮件原件-----
> 发件人: Lu.Tang <Lu.Tang@mediatek.com> 
> 发送时间: 2025年3月14日 15:32
> 收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
> 抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
> 主题: [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver

Fix your mailer.  Headers have no place in the body of an email.

> From: "Lu.Tang" <lu.tang@mediatek.com>
> 
> Add spmi pmic mfd driver for mt8196

7 words for a 900 line change is not going to fly.

What is this device?  What does it provide?  What are its dependencies?

Etc.

> Signed-off-by: Lu Tang <lu.tang@mediatek.com>
> ---
>  drivers/mfd/Kconfig                  |  26 ++
>  drivers/mfd/Makefile                 |   2 +
>  drivers/mfd/mt6685-core.c            |  83 +++++
>  drivers/mfd/mtk-spmi-pmic.c          | 518 +++++++++++++++++++++++++++
>  include/linux/mfd/mt6363/core.h      | 134 +++++++
>  include/linux/mfd/mt6363/registers.h | 168 +++++++++
>  include/linux/mfd/mt6373/core.h      |  94 +++++
>  include/linux/mfd/mt6373/registers.h |  53 +++
>  8 files changed, 1078 insertions(+)
>  create mode 100644 drivers/mfd/mt6685-core.c  create mode 100644 drivers/mfd/mtk-spmi-pmic.c  create mode 100644 include/linux/mfd/mt6363/core.h  create mode 100644 include/linux/mfd/mt6363/registers.h
>  create mode 100644 include/linux/mfd/mt6373/core.h  create mode 100644 include/linux/mfd/mt6373/registers.h

Please try again.

-- 
Lee Jones [李琼斯]

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

* Re: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
                     ` (2 preceding siblings ...)
  2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
@ 2025-03-14 10:32   ` Krzysztof Kozlowski
  2025-03-14 10:35     ` AngeloGioacchino Del Regno
  3 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-14 10:32 UTC (permalink / raw)
  To: Lu.Tang, Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

On 14/03/2025 08:32, Lu.Tang wrote:

Please use subject prefixes matching the subsystem. You can get them for
example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
your patch is touching. For bindings, the preferred subjects are
explained here:
https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters

There is no subsystem "pmic".

> Add new pmic mfd and adc documents for mt8196
> 
> Signed-off-by: Lu.Tang <Lu.Tang@mediatek.com>

Are you sure Latin transcription of your name includes '.' or you just
copy-paste email address?


...

> +  - Lu Tang <lu.tang@mediatek.com>
> +
> +description:
> +  The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
> +  in some MediaTek PMICs, performing various PMIC related measurements
> +  such as battery and PMIC internal voltage regulators temperatures,
> +  other than voltages for various PMIC internal components.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt6363-auxadc
> +      - mediatek,mt6373-auxadc

Just fold the device to the parent node.



..



> diff --git a/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
> new file mode 100644
> index 000000000000..a8f1231623cf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml

Filename matching one of the compatibles, e.g. the oldest one.

> @@ -0,0 +1,173 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek SPMI PMICs multi-function device
> +
> +maintainers:
> +  - Lu Tang <lu.tang@mediatek.com>
> +
> +description: |
> +  Some Mediatek PMICs are interfaced to the chip via the SPMI (System Power
> +  Management Interface) bus.
> +
> +  The Mediatek SPMI series includes the MT6363, MT6373, MT6316 and other
> +  PMICs.Please see the sub-modules below for supported features.
> +
> +   MT6363/MT6373 is a multifunction device with the following sub modules:
> +  - Regulators
> +  - ADC
> +  - GPIO
> +  - Keys
> +   MT6316 is a multifunction device with the following sub modules:
> +  - Regulators

I don't get why they are in the same schema. It would result in
unnecessary big if:then with half of children not applicable for other
variants.

> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - enum:
> +          - mediatek,mt6363
> +          - mediatek,mt6373
> +          - mediatek,mt6316
Sort these with alphanumeric order.

Best regards,
Krzysztof

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

* Re: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14 10:32   ` Krzysztof Kozlowski
@ 2025-03-14 10:35     ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 24+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-03-14 10:35 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Lu.Tang, Jonathan Cameron,
	Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Dmitry Torokhov, Lee Jones, Matthias Brugger,
	Sean Wang, Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong, Sen Chu
  Cc: linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

Il 14/03/25 11:32, Krzysztof Kozlowski ha scritto:
> On 14/03/2025 08:32, Lu.Tang wrote:
> 
> Please use subject prefixes matching the subsystem. You can get them for
> example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
> your patch is touching. For bindings, the preferred subjects are
> explained here:
> https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
> 
> There is no subsystem "pmic".
> 
>> Add new pmic mfd and adc documents for mt8196
>>
>> Signed-off-by: Lu.Tang <Lu.Tang@mediatek.com>
> 
> Are you sure Latin transcription of your name includes '.' or you just
> copy-paste email address?
> 
> 
> ...
> 
>> +  - Lu Tang <lu.tang@mediatek.com>
>> +
>> +description:
>> +  The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
>> +  in some MediaTek PMICs, performing various PMIC related measurements
>> +  such as battery and PMIC internal voltage regulators temperatures,
>> +  other than voltages for various PMIC internal components.
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - mediatek,mt6363-auxadc
>> +      - mediatek,mt6373-auxadc
> 
> Just fold the device to the parent node.
> 
> 
> 
> ..
> 
> 
> 
>> diff --git a/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
>> new file mode 100644
>> index 000000000000..a8f1231623cf
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml
> 
> Filename matching one of the compatibles, e.g. the oldest one.
> 

Yeah but besides that I don't see valid reasons why this should be a different
binding (and also why this should use a different driver, fwiw) - when it can
most probably just extend the current PMIC MFD driver... and the same goes for
the PMIC AUXADC: there's a mt6359-auxadc binding and driver that can be extended
to 6363 and 6373 rather easily.

There's nothing "really special" about those.....

Cheers

>> @@ -0,0 +1,173 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: MediaTek SPMI PMICs multi-function device
>> +
>> +maintainers:
>> +  - Lu Tang <lu.tang@mediatek.com>
>> +
>> +description: |
>> +  Some Mediatek PMICs are interfaced to the chip via the SPMI (System Power
>> +  Management Interface) bus.
>> +
>> +  The Mediatek SPMI series includes the MT6363, MT6373, MT6316 and other
>> +  PMICs.Please see the sub-modules below for supported features.
>> +
>> +   MT6363/MT6373 is a multifunction device with the following sub modules:
>> +  - Regulators
>> +  - ADC
>> +  - GPIO
>> +  - Keys
>> +   MT6316 is a multifunction device with the following sub modules:
>> +  - Regulators
> 
> I don't get why they are in the same schema. It would result in
> unnecessary big if:then with half of children not applicable for other
> variants.
> 
>> +
>> +properties:
>> +  compatible:
>> +    oneOf:
>> +      - enum:
>> +          - mediatek,mt6363
>> +          - mediatek,mt6373
>> +          - mediatek,mt6316
> Sort these with alphanumeric order.
> 
> Best regards,
> Krzysztof




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

* Re: 回复: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver
  2025-03-14  9:21     ` 回复: " Lu Tang (汤璐)
@ 2025-03-14 12:15       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 24+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-14 12:15 UTC (permalink / raw)
  To: Lu Tang (汤璐), Chen Zhong (钟辰),
	Sen Chu (储森)
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On 14/03/2025 10:21, Lu Tang (汤璐) wrote:
> Update email
> 
You just sent 10 emails like this to everyone. This is pointless, don't.

Best regards,
Krzysztof

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

* Re: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver
  2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
  2025-03-14  8:53   ` AngeloGioacchino Del Regno
  2025-03-14  9:04   ` Lu Tang (汤璐)
@ 2025-03-15 12:50   ` Jonathan Cameron
  2 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2025-03-15 12:50 UTC (permalink / raw)
  To: Lu.Tang
  Cc: Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Dmitry Torokhov, Lee Jones, Matthias Brugger,
	AngeloGioacchino Del Regno, Sean Wang, Linus Walleij,
	Liam Girdwood, Mark Brown, Stephen Boyd, Chen Zhong, Sen Chu,
	linux-iio, devicetree, linux-kernel, linux-input,
	linux-arm-kernel, linux-mediatek, linux-gpio,
	Project_Global_Chrome_Upstream_Group

On Fri, 14 Mar 2025 15:32:27 +0800
Lu.Tang <Lu.Tang@mediatek.com> wrote:

> From: "Lu.Tang" <lu.tang@mediatek.com>
> 
> Add pmic mt6363 and mt6373 auxadc driver

On assumption that there is good reason to not combine this with existing
driver I'll give it a quick review.  Definitely confirm why this can't
be combined with existing driver though before looking at this.

Jonathan


> 
> Signed-off-by: Lu Tang <lu.tang@mediatek.com>
> ---
>  drivers/iio/adc/Kconfig             |  10 +
>  drivers/iio/adc/Makefile            |   1 +
>  drivers/iio/adc/mtk-spmi-pmic-adc.c | 576 ++++++++++++++++++++++++++++
>  3 files changed, 587 insertions(+)
>  create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 27413516216c..7c4b5f8f7209 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -1039,6 +1039,16 @@ config MEDIATEK_MT6577_AUXADC
>  	  This driver can also be built as a module. If so, the module will be
>  	  called mt6577_auxadc.
>  
> +config MEDIATEK_SPMI_PMIC_ADC

Clearly a history of non compatible mediatek parts so it is probably better
to just name this after one of the supported parts than it is to use
a generic name.

> +	tristate "MediaTek SPMI PMIC ADC Support"
> +	depends on MFD_MTK_SPMI_PMIC
> +	help
> +	  Say yes here to enable support for MediaTek SPMI PMIC ADC.
> +	  The driver supports multiple channels read.
> +
> +	  This driver can also be built as a module. If so, the module will be
> +	  called mtk-spmi-pmic-adc.
> +

> diff --git a/drivers/iio/adc/mtk-spmi-pmic-adc.c b/drivers/iio/adc/mtk-spmi-pmic-adc.c
> new file mode 100644
> index 000000000000..61e062bc8cf5
> --- /dev/null
> +++ b/drivers/iio/adc/mtk-spmi-pmic-adc.c
> @@ -0,0 +1,576 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2024 MediaTek Inc.

Update?

> + */
> +
> +#include <linux/completion.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/iio/iio.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/mt6363/registers.h>
> +#include <linux/mfd/mt6373/registers.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
These shouldn't be used.
> +#include <linux/property.h>
only this should be so the of includes should be dropped.
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/syscore_ops.h>
> +
> +#include <dt-bindings/iio/mt635x-auxadc.h>


> +
> +#define AUXADC_RDY_BIT			BIT(15)
> +
> +#define AUXADC_DEF_R_RATIO		1
> +#define AUXADC_DEF_AVG_NUM		32
> +
> +#define AUXADC_AVG_TIME_US		10
> +#define AUXADC_POLL_DELAY_US		100
> +#define AUXADC_TIMEOUT_US		32000
These aren't really magic values so the only benefit in a define
would be to put a comment giving a spec reference next to them.
If not consider just putting the values inline.

> +#define VOLT_FULL			1840

Prefix all defines with something related to the driver.
MT8195_AUXADC_xx
That avoid potential aliasing that can occur with generic names.

> +
> +#define IMP_VOLT_FULL			18400
> +#define IMIX_R_MIN_MOHM			100
> +#define IMIX_R_CALI_CNT			2
> +
> +#define EXT_THR_PURES_SHIFT		3
> +#define EXT_THR_SEL_MASK		0x1F
> +
> +#define DT_CHANNEL_CONVERT(val)		((val) & 0xFF)
> +#define DT_PURES_CONVERT(val)		(((val) & 0xFF00) >> 8)
> +
> +struct pmic_adc_device {
> +	struct device *dev;
> +	struct regmap *regmap;
> +	struct mutex lock;
All locks must have comment describing the scope of data they protect.
> +	struct iio_chan_spec *iio_chans;

Looks like some of these only exist to avoid passing more variables
into the dt parsing function.  Make them local to the caller of that
and pass them in.  We should not have them in here.

> +	unsigned int nchannels;
> +	const struct auxadc_info *info;
> +	struct regulator *isink_load;
> +	int imix_r;
> +	int imp_curr;
> +	int pre_uisoc;
> +};
> +
> +static struct pmic_adc_device *imix_r_dev;
> +
> +/*

Make this correct kernel-doc. It nearly is already!

> + * @ch_name:	HW channel name
> + * @res:	ADC resolution
> + * @r_ratio:	resistance ratio, represented by r_ratio[0] / r_ratio[1]
> + * @avg_num:	sampling times of AUXADC measurements then average it
> + * @regs:	request and data output registers for this channel
> + */
> +struct auxadc_channels {
> +	enum iio_chan_type type;

Random things aren't documented. Document all structure elements.

> +	long info_mask;
> +	/* AUXADC channel attribute */
> +	const char *ch_name;
> +	unsigned char res;
> +	unsigned char r_ratio[2];
> +	unsigned short avg_num;
> +	const struct auxadc_regs *regs;
> +};
> +
> +#define AUXADC_CHANNEL(_ch_name, _res)	\
> +	[AUXADC_##_ch_name] = {				\
> +		.type = IIO_VOLTAGE,			\
> +		.info_mask = BIT(IIO_CHAN_INFO_RAW) |		\
> +			     BIT(IIO_CHAN_INFO_PROCESSED),	\

We almost never allow both raw and processed. There are a few exceptions
to that rule though. Why does it make sense here?

> +		.ch_name = __stringify(_ch_name),	\
> +		.res = _res,				\
> +	}
> +
> +/*
> + * The array represents all possible AUXADC channels found
> + * in the supported PMICs.
> + */
> +static struct auxadc_channels auxadc_chans[] = {
> +	AUXADC_CHANNEL(BATADC, 15),
> +	AUXADC_CHANNEL(VCDT, 12),
> +	AUXADC_CHANNEL(BAT_TEMP, 12),
> +	AUXADC_CHANNEL(CHIP_TEMP, 12),
> +	AUXADC_CHANNEL(VCORE_TEMP, 12),
> +	AUXADC_CHANNEL(VPROC_TEMP, 12),
> +	AUXADC_CHANNEL(VGPU_TEMP, 12),
> +	AUXADC_CHANNEL(ACCDET, 12),
> +	AUXADC_CHANNEL(HPOFS_CAL, 15),
> +	AUXADC_CHANNEL(VTREF, 12),
> +	AUXADC_CHANNEL(VBIF, 12),
> +	AUXADC_CHANNEL(IMP, 15),
> +	[AUXADC_IMIX_R] = {
> +		.type = IIO_RESISTANCE,
> +		.info_mask = BIT(IIO_CHAN_INFO_RAW),
> +		.ch_name = "IMIX_R",
> +	},
> +	AUXADC_CHANNEL(VSYSSNS, 15),
> +	AUXADC_CHANNEL(VIN1, 15),
> +	AUXADC_CHANNEL(VIN2, 15),
> +	AUXADC_CHANNEL(VIN3, 15),
> +	AUXADC_CHANNEL(VIN4, 15),
> +	AUXADC_CHANNEL(VIN5, 15),
> +	AUXADC_CHANNEL(VIN6, 15),
> +	AUXADC_CHANNEL(VIN7, 15),
> +};
> +
> +struct auxadc_regs {
> +	unsigned int enable_reg;
> +	unsigned int enable_mask;
> +	unsigned int ready_reg;
> +	unsigned int ready_mask;
> +	unsigned int value_reg;
> +	unsigned int ext_thr_sel;
> +	u8 src_sel;
> +};
> +
> +#define AUXADC_REG(_ch_name, _chip, _enable_reg, _enable_mask, _value_reg) \
> +	[AUXADC_##_ch_name] = {				\
> +		.enable_reg = _chip##_##_enable_reg,	\
> +		.enable_mask = _enable_mask,		\
> +		.ready_reg = _chip##_##_value_reg,	\
> +		.ready_mask = AUXADC_RDY_BIT,		\
> +		.value_reg = _chip##_##_value_reg,	\
> +	}						\
Should be no \ on last line.

> +
> +#define TIA_ADC_REG(_src_sel, _chip)	\
> +	[AUXADC_VIN##_src_sel] = {			\
> +		.enable_reg = _chip##_AUXADC_RQST1,	\
> +		.enable_mask = BIT(4),			\
> +		.ready_reg = _chip##_AUXADC_ADC_CH12_L,	\
> +		.ready_mask = AUXADC_RDY_BIT,		\
> +		.value_reg = _chip##_AUXADC_ADC_CH12_L,	\
> +		.ext_thr_sel = _chip##_SDMADC_CON0,	\
> +		.src_sel = _src_sel,			\
> +	}						\
same here.

> +
> +static const struct auxadc_regs mt6363_auxadc_regs_tbl[] = {
> +	AUXADC_REG(BATADC, MT6363, AUXADC_RQST0, BIT(0), AUXADC_ADC0_L),
> +	AUXADC_REG(BAT_TEMP, MT6363, AUXADC_RQST0, BIT(3), AUXADC_ADC3_L),
> +	AUXADC_REG(CHIP_TEMP, MT6363, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L),
> +	AUXADC_REG(VCORE_TEMP, MT6363, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L),
> +	AUXADC_REG(VPROC_TEMP, MT6363, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L),
> +	AUXADC_REG(VGPU_TEMP, MT6363, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L),
> +	AUXADC_REG(VTREF, MT6363, AUXADC_RQST1, BIT(3), AUXADC_ADC11_L),
> +	[AUXADC_IMP] = {
> +		.enable_reg = MT6363_AUXADC_IMP0,
> +		.enable_mask = BIT(0),
> +		.ready_reg = MT6363_AUXADC_IMP1,
> +		.ready_mask = BIT(7),
> +		.value_reg = MT6363_AUXADC_ADC42_L,
> +	},
> +	AUXADC_REG(VSYSSNS, MT6363, AUXADC_RQST1, BIT(6), AUXADC_ADC_CH14_L),
> +	TIA_ADC_REG(1, MT6363),
> +	TIA_ADC_REG(2, MT6363),
> +	TIA_ADC_REG(3, MT6363),
> +	TIA_ADC_REG(4, MT6363),
> +	TIA_ADC_REG(5, MT6363),
> +	TIA_ADC_REG(6, MT6363),
> +	TIA_ADC_REG(7, MT6363),
> +};
> +
> +static const struct auxadc_regs mt6373_auxadc_regs_tbl[] = {
> +	AUXADC_REG(CHIP_TEMP, MT6373, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L),
> +	AUXADC_REG(VCORE_TEMP, MT6373, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L),
> +	AUXADC_REG(VPROC_TEMP, MT6373, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L),
> +	AUXADC_REG(VGPU_TEMP, MT6373, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L),
> +	TIA_ADC_REG(1, MT6373),
> +	TIA_ADC_REG(2, MT6373),
> +	TIA_ADC_REG(3, MT6373),
> +	TIA_ADC_REG(4, MT6373),
> +	TIA_ADC_REG(5, MT6373),
> +};
> +
> +struct auxadc_info {
> +	const struct auxadc_regs *regs_tbl;
> +};
> +
> +static const struct auxadc_info mt6363_info = {
> +	.regs_tbl = mt6363_auxadc_regs_tbl,
> +};
> +
> +static const struct auxadc_info mt6373_info = {
> +	.regs_tbl = mt6373_auxadc_regs_tbl,
> +};
> +
> +#define regmap_bulk_read_poll_timeout(map, addr, val, val_count, cond, sleep_us, timeout_us) \

This looks generic so shouldn't be in a driver.  Either propose it
for the regmap core, or give it a non generic driver specific name.

> +({ \
> +	u64 __timeout_us = (timeout_us); \
> +	unsigned long __sleep_us = (sleep_us); \
> +	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
> +	int __ret; \
> +	might_sleep_if(__sleep_us); \
> +	for (;;) { \
> +		__ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \
> +		if (__ret) \
> +			break; \
> +		if (cond) \
> +			break; \
> +		if ((__timeout_us) && \
> +		    ktime_compare(ktime_get(), __timeout) > 0) { \
> +			__ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \
> +			break; \
> +		} \
> +		if (__sleep_us) \
> +			usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
> +	} \
> +	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
> +})
> +
> +/*
For this sort of text make it all kernel-doc style and run the script
on the file to make sure no warnings / errors.

> + * @adc_dev:	 pointer to the struct pmic_adc_device
> + * @auxadc_chan: pointer to the struct auxadc_channels, it represents specific
> +		 auxadc channel
> + * @val:	 pointer to output value
> + */
> +static int get_auxadc_out(struct pmic_adc_device *adc_dev,
> +			  int channel, int channel2, int *val)

For example these parameters are different from the docs and
the kernel-doc script would point that out for you.

> +{
> +	int ret;
> +	u16 buf = 0;
> +	const struct auxadc_channels *auxadc_chan = &auxadc_chans[channel];
> +
> +	if (!auxadc_chan->regs)
> +		return -EINVAL;

Why would that happen?  Don't defend against things that can't occur.

> +
> +	if (auxadc_chan->regs->ext_thr_sel) {
> +		buf = (channel2 << EXT_THR_PURES_SHIFT)
> +			| auxadc_chan->regs->src_sel;

FIELD_PREP plus use appropriate mask not shift.  Also apply
FIELD_PREP() for the src_sel.

Avoids anyone needing to check values are in range or where the
various register fields are.

> +		ret = regmap_update_bits(adc_dev->regmap,
> +					 auxadc_chan->regs->ext_thr_sel,
> +					 EXT_THR_SEL_MASK, buf);
> +		if (ret < 0)
> +			return ret;
> +	}
> +	regmap_write(adc_dev->regmap,
Check for errors.

> +		     auxadc_chan->regs->enable_reg,
> +		     auxadc_chan->regs->enable_mask);
> +	usleep_range(auxadc_chan->avg_num * AUXADC_AVG_TIME_US,
> +		     (auxadc_chan->avg_num + 1) * AUXADC_AVG_TIME_US);
> +
> +	ret = regmap_bulk_read_poll_timeout(adc_dev->regmap,
> +					    auxadc_chan->regs->value_reg,
> +					    buf, 2,

buf should be u16 and use sizeof(buf) for that 2.

> +					    (buf & AUXADC_RDY_BIT),
brackets add nothing.
> +					    AUXADC_POLL_DELAY_US,
> +					    AUXADC_TIMEOUT_US);
> +	*val = buf & (BIT(auxadc_chan->res) - 1);
> +	if (ret)
> +		dev_err(adc_dev->dev, "%s ret error code:%d!\n", auxadc_chan->ch_name, ret);
> +
> +	/* set PURES to OPEN after measuring done */
> +	if (auxadc_chan->regs->ext_thr_sel) {
> +		buf = (ADC_PURES_OPEN << EXT_THR_PURES_SHIFT)
> +			| auxadc_chan->regs->src_sel;
FIELD_PREP() for both of those.

> +		ret = regmap_update_bits(adc_dev->regmap,
> +					 auxadc_chan->regs->ext_thr_sel,
> +					 EXT_THR_SEL_MASK, buf);

Overwrite the earlier error potentially which is not something we normally
want to do as can make debugging harder.

> +	}
> +
> +	return ret;
> +}
> +
> +static int gauge_get_imp_ibat(void)
> +{
> +	struct power_supply *psy;
> +	union power_supply_propval prop;
> +	int ret;
> +
> +	psy = power_supply_get_by_name("mtk-gauge");
> +	if (!psy)
> +		return 0;
> +
> +	ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop);
> +	if (ret)
> +		return ret;
> +
> +	power_supply_put(psy);
> +	return prop.intval;
> +}
> +
> +static int get_imp_out(struct pmic_adc_device *adc_dev, int *val)
> +{
> +	int ret;
> +	unsigned int buf = 0;
> +	const struct auxadc_channels *auxadc_chan = &auxadc_chans[AUXADC_IMP];
> +
> +	if (!auxadc_chan->regs)
> +		return -EINVAL;
> +
> +	regmap_write(adc_dev->regmap,

Probably worth a local variable for the regmap to shorten some lines.

> +		     auxadc_chan->regs->enable_reg,
> +		     auxadc_chan->regs->enable_mask);

Check for errors.

> +	ret = regmap_read_poll_timeout(adc_dev->regmap, auxadc_chan->regs->ready_reg,
> +					   buf, buf & auxadc_chan->regs->ready_mask,
> +					   AUXADC_POLL_DELAY_US,
> +					   AUXADC_TIMEOUT_US);
> +	if (ret) {
> +		dev_err(adc_dev->dev, "%s %s ret error code:%d!\n",
> +			__func__, auxadc_chan->ch_name, ret);
No need for the __func__ in here.  Say what failed in the error message.
> +		return ret;
> +	}
> +
> +	ret = regmap_bulk_read(adc_dev->regmap, auxadc_chan->regs->value_reg, (u8 *) &buf, 2);

Why cast to u8 *?  It takes a void * and you never need to cast to that.
However, you also shouldn't be doing a 2 byte read into a integer.  Use a u16
and get the size with appropriate sizeof()



> +	if (ret)
> +		return ret;
> +	*val = buf & (BIT(auxadc_chan->res) - 1);
> +	adc_dev->imp_curr = gauge_get_imp_ibat();
> +
> +	regmap_write(adc_dev->regmap,
> +		     auxadc_chan->regs->enable_reg, 0);

Check for errors.

> +
> +	return 0;
> +}
> +
> +static int pmic_adc_read_raw(struct iio_dev *indio_dev,

All functions should be prefixed with driver name. Avoids
potential clashes if generic stuff ends up in headers later.

> +			     struct iio_chan_spec const *chan,
> +			     int *val, int *val2, long mask)
> +{
> +	struct pmic_adc_device *adc_dev = iio_priv(indio_dev);
> +	const struct auxadc_channels *auxadc_chan;
> +	int auxadc_out = 0;
> +	int ret = 0;
> +
> +	mutex_lock(&adc_dev->lock);
consider pushing the lock down into the various implementations.
> +	switch (chan->channel) {
> +	case AUXADC_IMP:
> +		ret = get_imp_out(adc_dev, &auxadc_out);
> +		break;
> +	case AUXADC_IMIX_R:
> +		auxadc_out = adc_dev->imix_r;
> +		break;
> +	default:
> +		ret = get_auxadc_out(adc_dev,
> +				     chan->channel, chan->channel2,
> +				     &auxadc_out);
> +		break;
> +	}
> +	mutex_unlock(&adc_dev->lock);
> +
> +	if (ret && ret != -ETIMEDOUT)
> +		return ret;

Why would you carry on if it timed out?

> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		auxadc_chan = &auxadc_chans[chan->channel];
> +		*val = auxadc_out * auxadc_chan->r_ratio[0] * VOLT_FULL;
> +		*val = (*val / auxadc_chan->r_ratio[1]) >> auxadc_chan->res;
This looks linear - in which case why not leave the maths to userspace
and provide IIO_CHAN_INFO_SCALE + _RAW

> +		ret = IIO_VAL_INT;
> +		break;
> +	case IIO_CHAN_INFO_RAW:

Why provide this at all if you are providing processed output.

> +		*val = auxadc_out;
> +		ret = IIO_VAL_INT;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	if (chan->channel == AUXADC_IMP) {
> +		*val2 = adc_dev->imp_curr;
> +		ret = IIO_VAL_INT_MULTIPLE;
> +	}
> +
> +	return ret;
> +}

> +
> +static const struct iio_info pmic_adc_info = {
> +	.read_raw = &pmic_adc_read_raw,
> +	.fwnode_xlate = &pmic_adc_fwnode_xlate,
> +};
> +
> +static int auxadc_init_imix_r(struct pmic_adc_device *adc_dev,
> +			      struct device_node *imix_r_node)
> +{
> +	unsigned int val = 0;
> +	int ret;
> +
> +	if (!adc_dev)
> +		return -EINVAL;
> +
> +	adc_dev->isink_load = devm_regulator_get_exclusive(adc_dev->dev, "isink_load");
> +	if (IS_ERR(adc_dev->isink_load)) {
> +		dev_err(adc_dev->dev, "Failed to get isink_load regulator, ret=%d\n",
> +			(int)PTR_ERR(adc_dev->isink_load));
> +		return PTR_ERR(adc_dev->isink_load);

Use dev_err_probe() which will also pretty print the return value so remember to
drop that bit.

> +	}
> +
> +	imix_r_dev = adc_dev;
> +	if (imix_r_dev->imix_r)
> +		return 0;
> +
> +	ret = of_property_read_u32(imix_r_node, "val", &val);
> +	if (ret)
> +		dev_notice(imix_r_dev->dev, "no imix_r, ret=%d\n", ret);
> +	imix_r_dev->imix_r = (int)val;
> +	imix_r_dev->pre_uisoc = 101;
> +	return 0;
> +}
> +
> +static int auxadc_get_data_from_dt(struct pmic_adc_device *adc_dev,

from_fw() and use the generic property.h accessors, not the dt specific ones.

> +				   struct iio_chan_spec *iio_chan,
> +				   struct device_node *node)
> +{
> +	struct auxadc_channels *auxadc_chan;
> +	unsigned int channel = 0;
> +	unsigned int value = 0;
> +	unsigned int val_arr[2] = {0};
> +	int ret;
> +
> +	ret = of_property_read_u32(node, "channel", &channel);

That doesn't looks like a standard dt binding. why do you need it
vs what is in adc.yaml?  Probably just reg is enough.


> +	if (ret) {
> +		dev_err(adc_dev->dev, "invalid channel in node:%s\n",
> +			   node->name);

use return dev_err_probe() for all error prints that are part of probe.
Gives prettier printing and other benefits in some cases.

> +		return ret;
> +	}
> +	if (channel > AUXADC_CHAN_MAX) {
> +		dev_err(adc_dev->dev, "invalid channel number %d in node:%s\n",
> +			   channel, node->name);
> +		return -EINVAL;
> +	}
> +	if (channel >= ARRAY_SIZE(auxadc_chans)) {
> +		dev_err(adc_dev->dev, "channel number %d in node:%s not exists\n",
> +			   channel, node->name);
> +		return -EINVAL;
> +	}
> +	iio_chan->channel = channel;
> +	iio_chan->datasheet_name = auxadc_chans[channel].ch_name;
> +	iio_chan->info_mask_separate = auxadc_chans[channel].info_mask;
> +	iio_chan->type = auxadc_chans[channel].type;
> +	iio_chan->extend_name = node->name;

No. This is almost never used in a modern driver as it makes for really nasty
userspace ABI.  Use label if you need to mark a channel as something specific.

> +	ret = of_property_read_u32(node, "pures", &value);

I have no idea what this one is or why you'd put anything in channel2 for
a single ended ADC channel with no modifier.


> +	if (!ret)
> +		iio_chan->channel2 = value;
> +
> +	if (channel == AUXADC_IMIX_R)
> +		return auxadc_init_imix_r(adc_dev, node);
> +
> +	auxadc_chan = &auxadc_chans[channel];
> +	auxadc_chan->regs = &adc_dev->info->regs_tbl[channel];
> +
> +	ret = of_property_read_u32_array(node, "resistance-ratio", val_arr, 2);

Interesting but not standard DT binding. In general this seems to have no connect
to the dt bindings in this seris.

> +	if (!ret) {
> +		auxadc_chan->r_ratio[0] = val_arr[0];
> +		auxadc_chan->r_ratio[1] = val_arr[1];
> +	} else {
> +		auxadc_chan->r_ratio[0] = AUXADC_DEF_R_RATIO;
> +		auxadc_chan->r_ratio[1] = 1;
> +	}
> +
> +	ret = of_property_read_u32(node, "avg-num", &value);

Also not a standing binding and rarely found in DT because it
is usually a policy decision on noise vs sampling rate and exposed as
oversampling control to userspace.

> +	if (!ret)
> +		auxadc_chan->avg_num = value;
> +	else
> +		auxadc_chan->avg_num = AUXADC_DEF_AVG_NUM;
> +
> +	return 0;
> +}
> +
> +static int auxadc_parse_dt(struct pmic_adc_device *adc_dev,

parse_fw() as you'll be using generic accessors thoughout.

> +			   struct device_node *node)
> +{
> +	struct iio_chan_spec *iio_chan;
> +	struct device_node *child;
> +	unsigned int index = 0;
> +	int ret;
> +
> +	adc_dev->nchannels = of_get_available_child_count(node);

Use generic property accessors, not of specific ones (property.h)

> +	if (!adc_dev->nchannels)
> +		return -EINVAL;
> +
> +	adc_dev->iio_chans = devm_kcalloc(adc_dev->dev, adc_dev->nchannels,
> +		sizeof(*adc_dev->iio_chans), GFP_KERNEL);
> +	if (!adc_dev->iio_chans)
> +		return -ENOMEM;
> +	iio_chan = adc_dev->iio_chans;
> +
> +	for_each_available_child_of_node(node, child) {
> +		ret = auxadc_get_data_from_dt(adc_dev, iio_chan, child);
> +		if (ret < 0) {
> +			of_node_put(child);
> +			return ret;
> +		}
> +		iio_chan->indexed = 1;
> +		iio_chan->address = index++;
> +		iio_chan++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int pmic_adc_probe(struct platform_device *pdev)
> +{
> +	struct device_node *node = pdev->dev.of_node;
> +	struct pmic_adc_device *adc_dev;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc_dev = iio_priv(indio_dev);
> +	adc_dev->dev = &pdev->dev;
> +	adc_dev->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> +	mutex_init(&adc_dev->lock);
In new drivers I prefer to see
	ret = devm_mutex_init()
	if (ret)
		return ret;

Brings only a minor debug benefit, but the cost of getting that is
low so it is a nice thing to have!

> +	adc_dev->info = of_device_get_match_data(&pdev->dev);
> +
> +	ret = auxadc_parse_dt(adc_dev, node);
> +	if (ret) {
> +		dev_notice(&pdev->dev, "auxadc_parse_dt fail, ret=%d\n", ret);
> +		return ret;
> +	}
> +
> +	indio_dev->dev.parent = &pdev->dev;

No need for that - it's done the IIO core.

> +	indio_dev->name = dev_name(&pdev->dev);

This needs to be the part number, not come from the device name which can
be very different depending on how the device is created etc.
So just hard code the part number in the info structure and set it here.


> +	indio_dev->info = &pmic_adc_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = adc_dev->iio_chans;
> +	indio_dev->num_channels = adc_dev->nchannels;
> +
> +	ret = devm_iio_device_register(&pdev->dev, indio_dev);
> +	if (ret < 0) {
> +		dev_notice(&pdev->dev, "failed to register iio device!\n");
dev_err() given if you manage to hit here you definitely have an error.
Same for other error paths.

> +		return ret;
> +	}
> +
> +	dev_dbg(&pdev->dev, "probe done\n");
No purpose in this one.  It is very easy to see if probe succeeded without it.
> +
> +	return 0;
> +}


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

* Re: 回复: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents
  2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
@ 2025-03-17 10:49     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 24+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-17 10:49 UTC (permalink / raw)
  To: Lu Tang (汤璐)
  Cc: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
	Matthias Brugger, AngeloGioacchino Del Regno, Sean Wang,
	Linus Walleij, Liam Girdwood, Mark Brown, Stephen Boyd,
	Chen Zhong (钟辰), Sen Chu (储森),
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On Fri, Mar 14, 2025 at 09:01:11AM +0000, Lu Tang (汤璐) wrote:
> Update email
> 
> -----邮件原件-----
> 发件人: Lu.Tang <Lu.Tang@mediatek.com> 
> 发送时间: 2025年3月14日 15:33
> 收件人: Jonathan Cameron <jic23@kernel.org>; Lars-Peter Clausen <lars@metafoo.de>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Dmitry Torokhov <dmitry.torokhov@gmail.com>; Lee Jones <lee@kernel.org>; Matthias Brugger <matthias.bgg@gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>; Sean Wang <sean.wang@kernel.org>; Linus Walleij <linus.walleij@linaro.org>; Liam Girdwood <lgirdwood@gmail.com>; Mark Brown <broonie@kernel.org>; Stephen Boyd <sboyd@kernel.org>; Chen Zhong (钟辰) <Chen.Zhong@mediatek.com>; Sen Chu <shen.chu@mediatek.com>
> 抄送: linux-iio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-input@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org; linux-gpio@vger.kernel.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group@mediatek.com>; Lu Tang (汤璐) <Lu.Tang@mediatek.com>
> 主题: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents

The amount of errors shown by checkpatch on this is just shocking.

Best regards,
Krzysztof


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

end of thread, other threads:[~2025-03-17 10:49 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-14  7:32 [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Lu.Tang
2025-03-14  7:32 ` [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Lu.Tang
2025-03-14  8:53   ` AngeloGioacchino Del Regno
2025-03-14  9:21     ` 回复: " Lu Tang (汤璐)
2025-03-14 12:15       ` Krzysztof Kozlowski
2025-03-14  9:04   ` Lu Tang (汤璐)
2025-03-15 12:50   ` Jonathan Cameron
2025-03-14  7:32 ` [PATCH 2/5] pmic: mediatek: Add pmic regulator driver Lu.Tang
2025-03-14  8:26   ` Chen-Yu Tsai
2025-03-14  9:02   ` 回复: " Lu Tang (汤璐)
2025-03-14  7:32 ` [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver Lu.Tang
2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
2025-03-14  9:47     ` Lee Jones
2025-03-14  7:32 ` [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196 Lu.Tang
2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
2025-03-14  7:32 ` [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Lu.Tang
2025-03-14  8:25   ` Rob Herring (Arm)
2025-03-14  8:34   ` Chen-Yu Tsai
2025-03-14  9:01   ` 回复: " Lu Tang (汤璐)
2025-03-17 10:49     ` Krzysztof Kozlowski
2025-03-14 10:32   ` Krzysztof Kozlowski
2025-03-14 10:35     ` AngeloGioacchino Del Regno
2025-03-14  8:27 ` [PATCH 0/5] Add PMIC and SPMI driver for mt8196 Chen-Yu Tsai
2025-03-14  9:06 ` 回复: " Lu Tang (汤璐)

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