[Feature] add GA346 baseline version

Change-Id: Ic62933698569507dcf98240cdf5d9931ae34348f
diff --git a/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c b/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c
new file mode 100644
index 0000000..b254a88
--- /dev/null
+++ b/src/kernel/linux/v4.19/drivers/spmi/mtk-pmif.c
@@ -0,0 +1,2007 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 MediaTek Inc.
+ * Author: Argus Lin <argus.lin@mediatek.com>
+ */
+/* #define DEBUG */
+
+#include <dt-bindings/spmi/spmi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/pmif.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/sched/clock.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <mt-plat/aee.h>
+
+#include "spmi_sw.h"
+
+/*
+ * marco
+ */
+#define PMIF_TIMEOUT    1
+#define PMIF_BRINGUP    0
+
+/* macro for PMIF SWINF FSM */
+#define PMIF_SWINF_FSM_IDLE		0x00
+#define PMIF_SWINF_FSM_REQ		0x02
+#define PMIF_SWINF_FSM_WFDLE		0x04
+#define PMIF_SWINF_FSM_WFVLDCLR		0x06
+#define PMIF_SWINF_INIT_DONE		0x01
+#define PMIF_SWINF_SYS_IDLE		0x00
+#define PMIF_SWINF_SYS_BUSY		0x01
+
+#define PMIF_GET_SWINF_FSM(x)           ((x>>1)  & 0x00000007)
+
+#define PMIF_CMD_REG_0			0
+#define PMIF_CMD_REG			1
+#define PMIF_CMD_EXT_REG		2
+#define PMIF_CMD_EXT_REG_LONG		3
+/* 0: SPI, 1: SPMI */
+#define PMIF_PMIFID_SPI			0
+#define PMIF_PMIFID_SPMI0		0
+#define PMIF_PMIFID_SPMI1		1
+#define PMIF_PMIFID_SPMI2		2
+#define PMIF_PMIFID_SPMI3		3
+
+enum pmif_regs {
+	PMIF_INIT_DONE,
+	PMIF_INF_EN,
+	PMIF_ARB_EN,
+	PMIF_CMDISSUE_EN,
+	PMIF_TIMER_CTRL,
+	PMIF_SPI_MODE_CTRL,
+	PMIF_IRQ_EVENT_EN_0,
+	PMIF_IRQ_FLAG_0,
+	PMIF_IRQ_CLR_0,
+	PMIF_IRQ_EVENT_EN_1,
+	PMIF_IRQ_FLAG_1,
+	PMIF_IRQ_CLR_1,
+	PMIF_IRQ_EVENT_EN_2,
+	PMIF_IRQ_FLAG_2,
+	PMIF_IRQ_CLR_2,
+	PMIF_IRQ_EVENT_EN_3,
+	PMIF_IRQ_FLAG_3,
+	PMIF_IRQ_CLR_3,
+	PMIF_IRQ_EVENT_EN_4,
+	PMIF_IRQ_FLAG_4,
+	PMIF_IRQ_CLR_4,
+	PMIF_WDT_EVENT_EN_0,
+	PMIF_WDT_FLAG_0,
+	PMIF_WDT_EVENT_EN_1,
+	PMIF_WDT_FLAG_1,
+	PMIF_SWINF_0_STA,
+	PMIF_SWINF_0_WDATA_31_0,
+	PMIF_SWINF_0_RDATA_31_0,
+	PMIF_SWINF_0_ACC,
+	PMIF_SWINF_0_VLD_CLR,
+	PMIF_SWINF_1_STA,
+	PMIF_SWINF_1_WDATA_31_0,
+	PMIF_SWINF_1_RDATA_31_0,
+	PMIF_SWINF_1_ACC,
+	PMIF_SWINF_1_VLD_CLR,
+	PMIF_SWINF_2_STA,
+	PMIF_SWINF_2_WDATA_31_0,
+	PMIF_SWINF_2_RDATA_31_0,
+	PMIF_SWINF_2_ACC,
+	PMIF_SWINF_2_VLD_CLR,
+	PMIF_SWINF_3_STA,
+	PMIF_SWINF_3_WDATA_31_0,
+	PMIF_SWINF_3_RDATA_31_0,
+	PMIF_SWINF_3_ACC,
+	PMIF_SWINF_3_VLD_CLR,
+};
+
+static const u32 mt6xxx_regs[] = {
+	[PMIF_INIT_DONE] =			0x0000,
+	[PMIF_INF_EN] =				0x0024,
+	[PMIF_ARB_EN] =				0x0150,
+	[PMIF_CMDISSUE_EN] =			0x03B4,
+	[PMIF_TIMER_CTRL] =			0x03E0,
+	[PMIF_SPI_MODE_CTRL] =			0x0400,
+	[PMIF_IRQ_EVENT_EN_0] =                 0x0418,
+	[PMIF_IRQ_FLAG_0] =                     0x0420,
+	[PMIF_IRQ_CLR_0] =                      0x0424,
+	[PMIF_IRQ_EVENT_EN_1] =                 0x0428,
+	[PMIF_IRQ_FLAG_1] =                     0x0430,
+	[PMIF_IRQ_CLR_1] =                      0x0434,
+	[PMIF_IRQ_EVENT_EN_2] =                 0x0438,
+	[PMIF_IRQ_FLAG_2] =                     0x0440,
+	[PMIF_IRQ_CLR_2] =                      0x0444,
+	[PMIF_IRQ_EVENT_EN_3] =                 0x0448,
+	[PMIF_IRQ_FLAG_3] =                     0x0450,
+	[PMIF_IRQ_CLR_3] =                      0x0454,
+	[PMIF_IRQ_EVENT_EN_4] =                 0x0458,
+	[PMIF_IRQ_FLAG_4] =                     0x0460,
+	[PMIF_IRQ_CLR_4] =                      0x0464,
+	[PMIF_WDT_EVENT_EN_0] =			0x046C,
+	[PMIF_WDT_FLAG_0] =			0x0470,
+	[PMIF_WDT_EVENT_EN_1] =			0x0474,
+	[PMIF_WDT_FLAG_1] =			0x0478,
+	[PMIF_SWINF_0_ACC] =			0x0C00,
+	[PMIF_SWINF_0_WDATA_31_0] =		0x0C04,
+	[PMIF_SWINF_0_RDATA_31_0] =		0x0C14,
+	[PMIF_SWINF_0_VLD_CLR] =		0x0C24,
+	[PMIF_SWINF_0_STA] =			0x0C28,
+	[PMIF_SWINF_1_ACC] =			0x0C40,
+	[PMIF_SWINF_1_WDATA_31_0] =		0x0C44,
+	[PMIF_SWINF_1_RDATA_31_0] =		0x0C54,
+	[PMIF_SWINF_1_VLD_CLR] =		0x0C64,
+	[PMIF_SWINF_1_STA] =			0x0C68,
+	[PMIF_SWINF_2_ACC] =			0x0C80,
+	[PMIF_SWINF_2_WDATA_31_0] =		0x0C84,
+	[PMIF_SWINF_2_RDATA_31_0] =		0x0C94,
+	[PMIF_SWINF_2_VLD_CLR] =		0x0CA4,
+	[PMIF_SWINF_2_STA] =			0x0CA8,
+	[PMIF_SWINF_3_ACC] =			0x0CC0,
+	[PMIF_SWINF_3_WDATA_31_0] =		0x0CC4,
+	[PMIF_SWINF_3_RDATA_31_0] =		0x0CD4,
+	[PMIF_SWINF_3_VLD_CLR] =		0x0CE4,
+	[PMIF_SWINF_3_STA] =			0x0CE8,
+};
+
+static const u32 mt6880_regs[] = {
+	[PMIF_INIT_DONE] =			0x0000,
+	[PMIF_INF_EN] =				0x0024,
+	[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,
+};
+
+static const u32 mt6853_regs[] = {
+	[PMIF_INIT_DONE] =			0x0000,
+	[PMIF_INF_EN] =				0x0024,
+	[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] =			0x0C00,
+	[PMIF_SWINF_0_WDATA_31_0] =		0x0C04,
+	[PMIF_SWINF_0_RDATA_31_0] =		0x0C14,
+	[PMIF_SWINF_0_VLD_CLR] =		0x0C24,
+	[PMIF_SWINF_0_STA] =			0x0C28,
+	[PMIF_SWINF_1_ACC] =			0x0C40,
+	[PMIF_SWINF_1_WDATA_31_0] =		0x0C44,
+	[PMIF_SWINF_1_RDATA_31_0] =		0x0C54,
+	[PMIF_SWINF_1_VLD_CLR] =		0x0C64,
+	[PMIF_SWINF_1_STA] =			0x0C68,
+	[PMIF_SWINF_2_ACC] =			0x0C80,
+	[PMIF_SWINF_2_WDATA_31_0] =		0x0C84,
+	[PMIF_SWINF_2_RDATA_31_0] =		0x0C94,
+	[PMIF_SWINF_2_VLD_CLR] =		0x0CA4,
+	[PMIF_SWINF_2_STA] =			0x0CA8,
+	[PMIF_SWINF_3_ACC] =			0x0CC0,
+	[PMIF_SWINF_3_WDATA_31_0] =		0x0CC4,
+	[PMIF_SWINF_3_RDATA_31_0] =		0x0CD4,
+	[PMIF_SWINF_3_VLD_CLR] =		0x0CE4,
+	[PMIF_SWINF_3_STA] =			0x0CE8,
+};
+
+static const u32 mt6xxx_spmi_regs[] = {
+	[SPMI_OP_ST_CTRL] =			0x0000,
+	[SPMI_GRP_ID_EN] =			0x0004,
+	[SPMI_OP_ST_STA] =			0x0008,
+	[SPMI_SAMPL_CTRL] =			0x000c,
+	[SPMI_REQ_EN] =				0x0010,
+	[SPMI_REC_CTRL] =			0x0040,
+	[SPMI_REC0] =				0x0044,
+	[SPMI_REC1] =				0x0048,
+	[SPMI_REC2] =				0x004c,
+	[SPMI_REC3] =				0x0050,
+	[SPMI_REC4] =				0x0054,
+	[SPMI_MST_DBG] =			0x00fc,
+};
+
+static const u32 mt6880_spmi_regs[] = {
+	[SPMI_OP_ST_CTRL] =			0x0000,
+	[SPMI_GRP_ID_EN] =			0x0004,
+	[SPMI_OP_ST_STA] =			0x0008,
+	[SPMI_SAMPL_CTRL] =			0x000C,
+	[SPMI_REQ_EN] =				0x0010,
+	[SPMI_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,
+};
+
+static const u32 mt6853_spmi_regs[] = {
+	[SPMI_OP_ST_CTRL] =			0x0000,
+	[SPMI_GRP_ID_EN] =			0x0004,
+	[SPMI_OP_ST_STA] =			0x0008,
+	[SPMI_SAMPL_CTRL] =			0x000C,
+	[SPMI_REQ_EN] =				0x0010,
+	[SPMI_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 {
+	SPMI_OP_ST_BUSY = 1,
+	SPMI_OP_ST_ACK = 0,
+	SPMI_OP_ST_NACK = 1
+};
+
+enum {
+	SPMI_RCS_SR_BIT,
+	SPMI_RCS_A_BIT
+};
+
+enum {
+	SPMI_RCS_MST_W = 1,
+	SPMI_RCS_SLV_W = 3
+};
+
+enum infra_regs {
+	MODULE_SW_CG_0_SET,
+	MODULE_SW_CG_0_CLR,
+	MODULE_SW_CG_2_SET,
+	MODULE_SW_CG_2_CLR,
+	PMICW_CLOCK_CTRL,
+	INFRA_GLOBALCON_RST2_SET,
+	INFRA_GLOBALCON_RST2_CLR,
+};
+
+static const u32 mt6xxx_infra_regs[] = {
+	[MODULE_SW_CG_0_SET] =			0x0080,
+	[MODULE_SW_CG_0_CLR] =			0x0084,
+	[MODULE_SW_CG_2_SET] =			0x00a4,
+	[MODULE_SW_CG_2_CLR] =			0x00a8,
+	[PMICW_CLOCK_CTRL] =			0x0108,
+	[INFRA_GLOBALCON_RST2_SET] =		0x0140,
+	[INFRA_GLOBALCON_RST2_CLR] =		0x0144,
+};
+
+enum topckgen_regs {
+	CLK_CFG_UPDATE,
+	CLK_CFG_UPDATE1,
+	CLK_CFG_UPDATE2,
+	CLK_CFG_3_CLR,
+	CLK_CFG_6,
+	CLK_CFG_6_SET,
+	CLK_CFG_6_CLR,
+	CLK_CFG_8_CLR,
+	CLK_CFG_15,
+	CLK_CFG_15_CLR,
+	CLK_CFG_16,
+	CLK_CFG_16_CLR,
+};
+
+static const u32 mt6xxx_topckgen_regs[] = {
+	[CLK_CFG_UPDATE] =			0x0004,
+	[CLK_CFG_UPDATE1] =			0x0008,
+	[CLK_CFG_UPDATE2] =			0x000c,
+	[CLK_CFG_3_CLR] =			0x0048,
+	[CLK_CFG_6] =				0x0070,
+	[CLK_CFG_6_SET] =			0x0074,
+	[CLK_CFG_6_CLR] =			0x0078,
+	[CLK_CFG_8_CLR] =			0x0098,
+	[CLK_CFG_15] =				0x0100,
+	[CLK_CFG_15_CLR] =			0x0108,
+	[CLK_CFG_16] =				0x0110,
+	[CLK_CFG_16_CLR] =			0x0118,
+};
+
+enum toprgu_regs {
+	WDT_SWSYSRST2,
+};
+
+static const u32 mt6xxx_toprgu_regs[] = {
+	[WDT_SWSYSRST2] =			0x0090,
+};
+
+enum {
+	/* MT6885/MT6873 series */
+	IRQ_PMIC_CMD_ERR_PARITY_ERR = 17,
+	IRQ_PMIF_ACC_VIO = 20,
+	IRQ_PMIC_ACC_VIO = 21,
+	IRQ_LAT_LIMIT_REACHED = 6,
+	IRQ_HW_MONITOR = 7,
+	IRQ_WDT = 8,
+	/* MT6853/MT6880 series */
+	IRQ_PMIF_ACC_VIO_V2 = 19,
+	IRQ_PMIC_ACC_VIO_V2 = 20,
+	IRQ_HW_MONITOR_V2 = 10,
+	IRQ_WDT_V2 = 11,
+};
+
+struct pmif_irq_desc {
+	const char *name;
+	irq_handler_t irq_handler;
+	int irq;
+};
+
+#define PMIF_IRQDESC(name) { #name, pmif_##name##_irq_handler, -1}
+
+/*
+ * pmif internal API declaration
+ */
+int __attribute__((weak)) spmi_pmif_create_attr(struct device_driver *driver);
+int __attribute__((weak)) spmi_pmif_dbg_init(struct spmi_controller *ctrl);
+void __attribute__((weak)) spmi_dump_spmimst_record_reg(struct pmif *arb);
+static int pmif_timeout_ns(struct spmi_controller *ctrl,
+	unsigned long long start_time_ns, unsigned long long timeout_time_ns);
+static void pmif_enable_soft_reset(struct pmif *arb);
+static void pmif_enable_soft_reset_p_v1(struct pmif *arb);
+static void pmif_spmi_enable_clk_set(struct pmif *arb);
+static void pmif_spmi_enable_clk_set_v2(struct pmif *arb);
+static void pmif_spmi_force_normal_mode(struct pmif *arb);
+static void pmif_spmi_enable_swinf(struct pmif *arb,
+	unsigned int chan_no, unsigned int swinf_no);
+static void pmif_spmi_enable_cmdIssue(struct pmif *arb, bool en);
+static void pmif_spmi_enable(struct pmif *arb);
+static void pmif_spmi_enable_m_v1(struct pmif *arb);
+static void pmif_spmi_enable_p_v1(struct pmif *arb);
+static void pmif_spmi_enable_m_v2(struct pmif *arb);
+static void pmif_spmi_enable_p_v2(struct pmif *arb);
+static int is_pmif_spmi_init_done(struct pmif *arb);
+static int pmif_spmi_read_cmd(struct spmi_controller *ctrl,
+			      u8 opc, u8 sid, u16 addr, u8 *buf, size_t len);
+static int pmif_spmi_write_cmd(struct spmi_controller *ctrl,
+			       u8 opc, u8 sid, u16 addr, const u8 *buf,
+			       size_t len);
+static int mtk_spmi_config_master(struct pmif *arb,
+				  unsigned int mstid, bool en);
+static int mtk_spmi_config_master_v2(struct pmif *arb,
+				  unsigned int mstid, bool en);
+static int mtk_spmi_config_master_m_v1(struct pmif *arb,
+				       unsigned int mstid, bool en);
+static int mtk_spmi_config_master_p_v1(struct pmif *arb,
+				       unsigned int mstid, bool en);
+static int mtk_spmi_config_master_m_v2(struct pmif *arb,
+				       unsigned int mstid, bool en);
+static int mtk_spmi_config_master_p_v2(struct pmif *arb,
+				       unsigned int mstid, bool en);
+static int mtk_spmi_cali_rd_clock_polarity(struct pmif *arb);
+static int mtk_spmi_cali_rd_clock_polarity_m_p_v1(struct pmif *arb);
+static int mtk_spmi_cali_rd_clock_polarity_m_p_v2(struct pmif *arb);
+static int mtk_spmi_ctrl_op_st(struct spmi_controller *ctrl, u8 opc, u8 sid);
+static int mtk_spmi_enable_group_id(struct pmif *arb, u8 grpid);
+
+static struct pmif mt6885_pmif_arb = {
+	.base = 0x0,
+	.regs = mt6xxx_regs,
+	.spmimst_base = 0x0,
+	.spmimst_regs = mt6xxx_spmi_regs,
+	.infra_base = 0x0,
+	.infra_regs = mt6xxx_infra_regs,
+	.topckgen_base = 0x0,
+	.topckgen_regs = mt6xxx_topckgen_regs,
+	.toprgu_base = 0x0,
+	.toprgu_regs = mt6xxx_toprgu_regs,
+	.swinf_ch_start = 0,
+	.ap_swinf_no = 0,
+	.write = 0x0,
+	.mstid = SPMI_MASTER_0,
+	.pmifid = PMIF_PMIFID_SPMI0,
+	.spmic = 0x0,
+	.read_cmd = pmif_spmi_read_cmd,
+	.write_cmd = pmif_spmi_write_cmd,
+	.pmif_enable_clk_set = pmif_spmi_enable_clk_set,
+	.pmif_force_normal_mode = pmif_spmi_force_normal_mode,
+	.pmif_enable_swinf = pmif_spmi_enable_swinf,
+	.pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue,
+	.pmif_enable = pmif_spmi_enable,
+	.is_pmif_init_done = is_pmif_spmi_init_done,
+	.pmif_enable_reset = pmif_enable_soft_reset,
+	.pmif_cali_clock = mtk_spmi_cali_rd_clock_polarity,
+	.spmi_config_master = mtk_spmi_config_master,
+};
+
+static struct pmif mt6873_pmif_arb = {
+	.base = 0x0,
+	.regs = mt6xxx_regs,
+	.spmimst_base = 0x0,
+	.spmimst_regs = mt6xxx_spmi_regs,
+	.infra_base = 0x0,
+	.infra_regs = mt6xxx_infra_regs,
+	.topckgen_base = 0x0,
+	.topckgen_regs = mt6xxx_topckgen_regs,
+	.toprgu_base = 0x0,
+	.toprgu_regs = mt6xxx_toprgu_regs,
+	.swinf_ch_start = 0,
+	.ap_swinf_no = 0,
+	.write = 0x0,
+	.mstid = SPMI_MASTER_0,
+	.pmifid = PMIF_PMIFID_SPMI0,
+	.spmic = 0x0,
+	.read_cmd = pmif_spmi_read_cmd,
+	.write_cmd = pmif_spmi_write_cmd,
+	.pmif_enable_clk_set = pmif_spmi_enable_clk_set,
+	.pmif_force_normal_mode = pmif_spmi_force_normal_mode,
+	.pmif_enable_swinf = pmif_spmi_enable_swinf,
+	.pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue,
+	.pmif_enable = pmif_spmi_enable,
+	.is_pmif_init_done = is_pmif_spmi_init_done,
+	.pmif_enable_reset = pmif_enable_soft_reset,
+	.pmif_cali_clock = mtk_spmi_cali_rd_clock_polarity,
+	.spmi_config_master = mtk_spmi_config_master_v2,
+};
+
+static struct pmif mt6853_pmif_m_arb = {
+	.base = 0x0,
+	.regs = mt6853_regs,
+	.spmimst_base = 0x0,
+	.spmimst_regs = mt6853_spmi_regs,
+	.infra_base = 0x0,
+	.infra_regs = mt6xxx_infra_regs,
+	.topckgen_base = 0x0,
+	.topckgen_regs = mt6xxx_topckgen_regs,
+	.toprgu_base = 0x0,
+	.toprgu_regs = mt6xxx_toprgu_regs,
+	.swinf_ch_start = 0,
+	.ap_swinf_no = 0,
+	.write = 0x0,
+	.mstid = SPMI_MASTER_1,
+	.pmifid = PMIF_PMIFID_SPMI1,
+	.spmic = 0x0,
+	.read_cmd = pmif_spmi_read_cmd,
+	.write_cmd = pmif_spmi_write_cmd,
+	.pmif_enable_clk_set = pmif_spmi_enable_clk_set,
+	.pmif_force_normal_mode = pmif_spmi_force_normal_mode,
+	.pmif_enable_swinf = pmif_spmi_enable_swinf,
+	.pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue,
+	.pmif_enable = pmif_spmi_enable_m_v1,
+	.is_pmif_init_done = is_pmif_spmi_init_done,
+	.pmif_enable_reset = pmif_enable_soft_reset,
+	.pmif_cali_clock = mtk_spmi_cali_rd_clock_polarity_m_p_v1,
+	.spmi_config_master = mtk_spmi_config_master_m_v1,
+};
+
+static struct pmif mt6853_pmif_p_arb = {
+	.base = 0x0,
+	.regs = mt6853_regs,
+	.spmimst_base = 0x0,
+	.spmimst_regs = mt6853_spmi_regs,
+	.infra_base = 0x0,
+	.infra_regs = mt6xxx_infra_regs,
+	.topckgen_base = 0x0,
+	.topckgen_regs = mt6xxx_topckgen_regs,
+	.toprgu_base = 0x0,
+	.toprgu_regs = mt6xxx_toprgu_regs,
+	.swinf_ch_start = 0,
+	.ap_swinf_no = 0,
+	.write = 0x0,
+	.mstid = SPMI_MASTER_1,
+	.pmifid = PMIF_PMIFID_SPMI2,
+	.spmic = 0x0,
+	.read_cmd = pmif_spmi_read_cmd,
+	.write_cmd = pmif_spmi_write_cmd,
+	.pmif_enable_clk_set = pmif_spmi_enable_clk_set,
+	.pmif_force_normal_mode = pmif_spmi_force_normal_mode,
+	.pmif_enable_swinf = pmif_spmi_enable_swinf,
+	.pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue,
+	.pmif_enable = pmif_spmi_enable_p_v1,
+	.is_pmif_init_done = is_pmif_spmi_init_done,
+	.pmif_enable_reset = pmif_enable_soft_reset_p_v1,
+	.pmif_cali_clock = mtk_spmi_cali_rd_clock_polarity_m_p_v1,
+	.spmi_config_master = mtk_spmi_config_master_p_v1,
+};
+
+static struct pmif mt6880_pmif_m_arb = {
+	.base = 0x0,
+	.regs = mt6880_regs,
+	.spmimst_base = 0x0,
+	.spmimst_regs = mt6880_spmi_regs,
+	.infra_base = 0x0,
+	.infra_regs = mt6xxx_infra_regs,
+	.topckgen_base = 0x0,
+	.topckgen_regs = mt6xxx_topckgen_regs,
+	.toprgu_base = 0x0,
+	.toprgu_regs = mt6xxx_toprgu_regs,
+	.swinf_ch_start = 0,
+	.ap_swinf_no = 0,
+	.write = 0x0,
+	.mstid = SPMI_MASTER_1,
+	.pmifid = PMIF_PMIFID_SPMI1,
+	.spmic = 0x0,
+	.read_cmd = pmif_spmi_read_cmd,
+	.write_cmd = pmif_spmi_write_cmd,
+	.pmif_enable_clk_set = pmif_spmi_enable_clk_set_v2,
+	.pmif_force_normal_mode = pmif_spmi_force_normal_mode,
+	.pmif_enable_swinf = pmif_spmi_enable_swinf,
+	.pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue,
+	.pmif_enable = pmif_spmi_enable_m_v2,
+	.is_pmif_init_done = is_pmif_spmi_init_done,
+	.pmif_enable_reset = pmif_enable_soft_reset,
+	.pmif_cali_clock = mtk_spmi_cali_rd_clock_polarity_m_p_v2,
+	.spmi_config_master = mtk_spmi_config_master_m_v2,
+};
+
+static struct pmif mt6880_pmif_p_arb = {
+	.base = 0x0,
+	.regs = mt6880_regs,
+	.spmimst_base = 0x0,
+	.spmimst_regs = mt6880_spmi_regs,
+	.infra_base = 0x0,
+	.infra_regs = mt6xxx_infra_regs,
+	.topckgen_base = 0x0,
+	.topckgen_regs = mt6xxx_topckgen_regs,
+	.toprgu_base = 0x0,
+	.toprgu_regs = mt6xxx_toprgu_regs,
+	.swinf_ch_start = 0,
+	.ap_swinf_no = 0,
+	.write = 0x0,
+	.mstid = SPMI_MASTER_1,
+	.pmifid = PMIF_PMIFID_SPMI2,
+	.spmic = 0x0,
+	.read_cmd = pmif_spmi_read_cmd,
+	.write_cmd = pmif_spmi_write_cmd,
+	.pmif_enable_clk_set = pmif_spmi_enable_clk_set_v2,
+	.pmif_force_normal_mode = pmif_spmi_force_normal_mode,
+	.pmif_enable_swinf = pmif_spmi_enable_swinf,
+	.pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue,
+	.pmif_enable = pmif_spmi_enable_p_v2,
+	.is_pmif_init_done = is_pmif_spmi_init_done,
+	.pmif_enable_reset = pmif_enable_soft_reset_p_v1,
+	.pmif_cali_clock = mtk_spmi_cali_rd_clock_polarity_m_p_v2,
+	.spmi_config_master = mtk_spmi_config_master_p_v2,
+};
+
+static const struct of_device_id pmif_match_table[] = {
+	{
+		.compatible = "mediatek,mt6885-pmif",
+		.data = &mt6885_pmif_arb,
+	}, {
+		.compatible = "mediatek,mt6873-pmif",
+		.data = &mt6873_pmif_arb,
+	}, {
+		.compatible = "mediatek,mt6853-pmif-m",
+		.data = &mt6853_pmif_m_arb,
+	}, {
+		.compatible = "mediatek,mt6853-pmif-p",
+		.data = &mt6853_pmif_p_arb,
+	}, {
+		.compatible = "mediatek,mt6880-pmif-m",
+		.data = &mt6880_pmif_m_arb,
+	}, {
+		.compatible = "mediatek,mt6880-pmif-p",
+		.data = &mt6880_pmif_p_arb,
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, pmif_match_table);
+static struct platform_driver pmif_driver;
+
+/*
+ * pmif timeout
+ */
+#if PMIF_TIMEOUT
+static int pmif_timeout_ns(struct spmi_controller *ctrl,
+	unsigned long long start_time_ns, unsigned long long timeout_time_ns)
+{
+	unsigned long long cur_time = 0;
+	unsigned long long elapse_time = 0;
+
+	/* get current tick */
+	cur_time = sched_clock();  /* ns */
+
+	/* avoid timer over flow exiting in FPGA env */
+	if (cur_time < start_time_ns)
+		start_time_ns = cur_time;
+
+	elapse_time = cur_time - start_time_ns;
+
+	/* check if timeout */
+	if (timeout_time_ns <= elapse_time) {
+		dev_notice(&ctrl->dev,
+			"[PMIF] Timeout start time: %lld\n", start_time_ns);
+		dev_notice(&ctrl->dev,
+			"[PMIF] Timeout cur time: %lld\n", cur_time);
+		dev_notice(&ctrl->dev,
+			"[PMIF] Timeout elapse time: %lld\n", elapse_time);
+		dev_notice(&ctrl->dev,
+			"[PMIF] Timeout set timeout: %lld\n", timeout_time_ns);
+		return 1;
+	}
+	return 0;
+}
+#else
+static int pmif_timeout_ns(struct spmi_controller *ctrl,
+	unsigned long long start_time_ns, unsigned long long timeout_time_ns)
+{
+	return 0;
+}
+
+#endif
+/*
+ * pmif define for FSM
+ */
+static inline bool pmif_is_fsm_idle(struct pmif *arb)
+{
+	u32 offset = 0, reg_rdata = 0;
+
+	offset = arb->regs[PMIF_SWINF_0_STA] + (0x40 * arb->ap_swinf_no);
+	reg_rdata = readl(arb->base + offset);
+	return PMIF_GET_SWINF_FSM(reg_rdata) == PMIF_SWINF_FSM_IDLE;
+}
+
+static inline bool pmif_is_fsm_vldclr(struct pmif *arb)
+{
+	u32 offset = 0, reg_rdata = 0;
+
+	offset = arb->regs[PMIF_SWINF_0_STA] + (0x40 * arb->ap_swinf_no);
+	reg_rdata = readl(arb->base + offset);
+	return PMIF_GET_SWINF_FSM(reg_rdata) == PMIF_SWINF_FSM_WFVLDCLR;
+}
+static inline void pmif_leave_fsm_vldclr(struct pmif *arb)
+{
+	u32 offset = 0;
+
+	offset = arb->regs[PMIF_SWINF_0_VLD_CLR] + (0x40 * arb->ap_swinf_no);
+	if (pmif_is_fsm_vldclr(arb))
+		writel(0x1, arb->base + offset);
+}
+
+static int pmif_wait_for_state(struct spmi_controller *ctrl,
+		bool (*fp)(struct pmif *))
+{
+	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
+	unsigned long long start_time_ns = 0, timeout_ns = 0;
+
+	start_time_ns = sched_clock();
+	timeout_ns = 10000 * 1000;  /* 10000us */
+
+	do {
+		if (pmif_timeout_ns(ctrl, start_time_ns, timeout_ns)) {
+			if (fp(arb)) {
+				return 0;
+			} else if (fp(arb) == 0) {
+				dev_notice(&ctrl->dev, "[PMIF] FSM Timeout\n");
+				return -ETIMEDOUT;
+			}
+		}
+		if (fp(arb))
+			return 0;
+	} while (1);
+}
+
+/*
+ * Function : pmif_readl()
+ * Description : mtk pmif controller read api
+ * Parameter :
+ * Return :
+ */
+static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)
+{
+	return readl(arb->base + arb->regs[reg]);
+}
+
+/*
+ * Function : pmif_writel()
+ * Description : mtk pmif controller write api
+ * Parameter :
+ * Return :
+ */
+static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)
+{
+	writel(val, arb->base + arb->regs[reg]);
+}
+/*
+ * Function : mtk_spmi_readl()
+ * Description : mtk spmi controller read api
+ * Parameter :
+ * Return :
+ */
+u32 mtk_spmi_readl(struct pmif *arb, enum spmi_regs reg)
+{
+	return readl(arb->spmimst_base + arb->spmimst_regs[reg]);
+}
+
+/*
+ * Function : mtk_spmi_writel()
+ * Description : mtk spmi controller write api
+ * Parameter :
+ * Return :
+ */
+void mtk_spmi_writel(struct pmif *arb, u32 val,
+		enum spmi_regs reg)
+{
+	writel(val, arb->spmimst_base + arb->spmimst_regs[reg]);
+}
+
+static void pmif_enable_soft_reset(struct pmif *arb)
+{
+	writel(0x1 << 14,
+		arb->infra_base + arb->infra_regs[INFRA_GLOBALCON_RST2_SET]);
+	writel(0x1 << 14,
+		arb->infra_base + arb->infra_regs[INFRA_GLOBALCON_RST2_CLR]);
+}
+
+static void pmif_enable_soft_reset_p_v1(struct pmif *arb)
+{
+	writel(0x1,
+		arb->infra_base + arb->infra_regs[INFRA_GLOBALCON_RST2_SET]);
+	writel(0x1,
+		arb->infra_base + arb->infra_regs[INFRA_GLOBALCON_RST2_CLR]);
+}
+
+static void pmif_spmi_enable_clk_set(struct pmif *arb)
+{
+	/* sys_ck cg enable, turn off clock */
+	writel(0x0000000f,
+		arb->infra_base + arb->infra_regs[MODULE_SW_CG_0_SET]);
+
+	writel((0x1 << 15) | (0x1 << 12) | (0x7 << 8),
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_8_CLR]);
+	writel(0x1 << 2,
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE1]);
+
+	/* toggle SPMI sw reset */
+	arb->pmif_enable_reset(arb);
+
+	/* sys_ck cg enable, turn on clock */
+	writel(0x0000000f,
+		arb->infra_base + arb->infra_regs[MODULE_SW_CG_0_CLR]);
+}
+
+static void pmif_spmi_enable_clk_set_v2(struct pmif *arb)
+{
+	/* sys_ck cg enable, turn off clock */
+	writel(0x0000000f,
+		arb->infra_base + arb->infra_regs[MODULE_SW_CG_0_SET]);
+
+#if !defined(CONFIG_FPGA_EARLY_PORTING)
+	writel((0x1 << 31) | (0x1 << 28) | (0x7 << 24),
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_3_CLR]);
+	writel(0x1 << 15,
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE]);
+#endif
+
+	/* toggle SPMI sw reset */
+	arb->pmif_enable_reset(arb);
+
+	/* sys_ck cg enable, turn on clock */
+	writel(0x0000000f,
+		arb->infra_base + arb->infra_regs[MODULE_SW_CG_0_CLR]);
+}
+
+static void pmif_spmi_force_normal_mode(struct pmif *arb)
+{
+	/* Force SPMI in normal mode. */
+	pmif_writel(arb, pmif_readl(arb, PMIF_SPI_MODE_CTRL) & (~(0x3 << 9)),
+			PMIF_SPI_MODE_CTRL);
+	pmif_writel(arb, pmif_readl(arb, PMIF_SPI_MODE_CTRL) | (0x1 << 9),
+			PMIF_SPI_MODE_CTRL);
+#if defined(CONFIG_FPGA_EARLY_PORTING)
+	pmif_writel(arb, pmif_readl(arb, PMIF_SPI_MODE_CTRL) & (~(0x1 << 13)),
+			PMIF_SPI_MODE_CTRL);
+#endif
+}
+
+static void pmif_spmi_enable_swinf(struct pmif *arb, unsigned int chan_no,
+	unsigned int swinf_no)
+{
+	/* Enable swinf */
+	pmif_writel(arb, 0x1 << (chan_no + swinf_no), PMIF_INF_EN);
+
+	/* Enable arbitration */
+	pmif_writel(arb, 0x1 << (chan_no + swinf_no), PMIF_ARB_EN);
+
+}
+
+static void pmif_spmi_enable_cmdIssue(struct pmif *arb, bool en)
+{
+	/* Enable cmdIssue */
+	pmif_writel(arb, en, PMIF_CMDISSUE_EN);
+
+}
+
+static void pmif_spmi_enable(struct pmif *arb)
+{
+	pmif_writel(arb, 0x2F7, PMIF_INF_EN);
+	pmif_writel(arb, 0x2F7, PMIF_ARB_EN);
+	pmif_writel(arb, 0x3, PMIF_TIMER_CTRL);
+	pmif_writel(arb, 0x1, PMIF_INIT_DONE);
+}
+
+static void pmif_spmi_enable_m_v1(struct pmif *arb)
+{
+	pmif_writel(arb, 0x2F6, PMIF_INF_EN);
+	pmif_writel(arb, 0x2F6, PMIF_ARB_EN);
+	pmif_writel(arb, 0x3, PMIF_TIMER_CTRL);
+	pmif_writel(arb, 0x1, PMIF_INIT_DONE);
+}
+
+static void pmif_spmi_enable_p_v1(struct pmif *arb)
+{
+	pmif_writel(arb, 0xF1, PMIF_INF_EN);
+	pmif_writel(arb, 0xF1, PMIF_ARB_EN);
+	pmif_writel(arb, 0x3, PMIF_TIMER_CTRL);
+	pmif_writel(arb, 0x1, PMIF_INIT_DONE);
+}
+
+static void pmif_spmi_enable_m_v2(struct pmif *arb)
+{
+	pmif_writel(arb, 0x1FFF, PMIF_INF_EN);
+	pmif_writel(arb, 0x1FFF, PMIF_ARB_EN);
+	pmif_writel(arb, 0x3, PMIF_TIMER_CTRL);
+	pmif_writel(arb, 0x1, PMIF_INIT_DONE);
+}
+
+static void pmif_spmi_enable_p_v2(struct pmif *arb)
+{
+	pmif_writel(arb, 0x1FFF, PMIF_INF_EN);
+	pmif_writel(arb, 0x1FFF, PMIF_ARB_EN);
+	pmif_writel(arb, 0x3, PMIF_TIMER_CTRL);
+	pmif_writel(arb, 0x1, PMIF_INIT_DONE);
+}
+
+static int mtk_spmi_ctrl_op_st(struct spmi_controller *ctrl,
+			u8 opc, u8 sid)
+{
+	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
+	u32 rdata = 0x0;
+	u8 cmd = 0;
+
+	/* Check the opcode */
+	if (opc == SPMI_CMD_RESET)
+		cmd = 0;
+	else if (opc == SPMI_CMD_SLEEP)
+		cmd = 1;
+	else if (opc == SPMI_CMD_SHUTDOWN)
+		cmd = 2;
+	else if (opc == SPMI_CMD_WAKEUP)
+		cmd = 3;
+
+	mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
+
+	rdata = mtk_spmi_readl(arb, SPMI_OP_ST_CTRL);
+	pr_notice("[SPMIMST]:pmif_ctrl_op_st 0x%x\r\n", rdata);
+
+	do {
+		rdata = mtk_spmi_readl(arb, SPMI_OP_ST_STA);
+		pr_notice("[SPMIMST]:pmif_ctrl_op_st 0x%x\r\n", rdata);
+
+		if (((rdata >> 0x1) & SPMI_OP_ST_NACK) == SPMI_OP_ST_NACK) {
+			spmi_dump_spmimst_record_reg(arb);
+			break;
+		}
+	} while ((rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY);
+
+	return 0;
+}
+
+/* Non-data command */
+static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
+{
+	return mtk_spmi_ctrl_op_st(ctrl, opc, sid);
+}
+
+static int mtk_spmi_enable_group_id(struct pmif *arb, u8 grpid)
+{
+	mtk_spmi_writel(arb, 0x1 << grpid, SPMI_GRP_ID_EN);
+
+	return 0;
+}
+
+static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+		u16 addr, u8 *buf, size_t len)
+{
+	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
+	int ret = 0, write = 0x0;
+	u32 offset = 0, data = 0;
+	u8 bc = len - 1;
+	unsigned long flags;
+
+	/* Check for argument validation. */
+	if ((arb->ap_swinf_no & ~(0x3)) != 0x0)
+		return -EINVAL;
+
+	if ((arb->pmifid & ~(0x3)) != 0x0)
+		return -EINVAL;
+
+	if ((sid & ~(0xf)) != 0x0)
+		return -EINVAL;
+
+	/* Check the opcode */
+	if (opc >= 0x60 && opc <= 0x7F)
+		opc = PMIF_CMD_REG;
+	else if (opc >= 0x20 && opc <= 0x2F)
+		opc = PMIF_CMD_EXT_REG_LONG; /* wk1 opc = PMIF_CMD_EXT_REG; */
+	else if (opc >= 0x38 && opc <= 0x3F)
+		opc = PMIF_CMD_EXT_REG_LONG;
+	else
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&arb->lock, flags);
+	/* Wait for Software Interface FSM state to be IDLE. */
+	ret = pmif_wait_for_state(ctrl, pmif_is_fsm_idle);
+	if (ret) {
+		pmif_leave_fsm_vldclr(arb);
+		raw_spin_unlock_irqrestore(&arb->lock, flags);
+		return ret;
+	}
+	/* Send the command. */
+	offset = arb->regs[PMIF_SWINF_0_ACC] + (0x40 * arb->ap_swinf_no);
+	writel((opc << 30) | (write << 29) | (sid << 24) | (bc << 16) | addr,
+		arb->base + offset);
+
+	/* Wait for Software Interface FSM state to be WFVLDCLR,
+	 *
+	 * read the data and clear the valid flag.
+	 */
+	if (write == 0) {
+		ret = pmif_wait_for_state(ctrl, pmif_is_fsm_vldclr);
+		if (ret) {
+			raw_spin_unlock_irqrestore(&arb->lock, flags);
+			return ret;
+		}
+		offset =
+		arb->regs[PMIF_SWINF_0_RDATA_31_0] + (0x40 * arb->ap_swinf_no);
+
+		data = readl(arb->base + offset);
+		memcpy(buf, &data, (bc & 3) + 1);
+		offset =
+		arb->regs[PMIF_SWINF_0_VLD_CLR] + (0x40 * arb->ap_swinf_no);
+
+		writel(0x1, arb->base + offset);
+	}
+
+	raw_spin_unlock_irqrestore(&arb->lock, flags);
+
+	return 0x0;
+}
+
+static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+		u16 addr, const u8 *buf, size_t len)
+{
+	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
+	int ret = 0, write = 0x1;
+	u32 offset = 0, data = 0;
+	u8 bc = len - 1;
+	unsigned long flags = 0;
+
+	/* Check for argument validation. */
+	if ((arb->ap_swinf_no & ~(0x3)) != 0x0)
+		return -EINVAL;
+
+	if ((arb->pmifid & ~(0x3)) != 0x0)
+		return -EINVAL;
+
+	if ((sid & ~(0xf)) != 0x0)
+		return -EINVAL;
+
+	/* Check the opcode */
+	if (opc >= 0x40 && opc <= 0x5F)
+		opc = PMIF_CMD_REG;
+	else if (opc <= 0x0F)
+		opc = PMIF_CMD_EXT_REG_LONG; /* wk1 opc = PMIF_CMD_EXT_REG; */
+	else if (opc >= 0x30 && opc <= 0x37)
+		opc = PMIF_CMD_EXT_REG_LONG;
+	else if (opc >= 0x80)
+		opc = PMIF_CMD_REG_0;
+	else
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&arb->lock, flags);
+
+	/* Wait for Software Interface FSM state to be IDLE. */
+	ret = pmif_wait_for_state(ctrl, pmif_is_fsm_idle);
+	if (ret) {
+		pmif_leave_fsm_vldclr(arb);
+		raw_spin_unlock_irqrestore(&arb->lock, flags);
+		return ret;
+	}
+	/* Set the write data. */
+	offset = arb->regs[PMIF_SWINF_0_WDATA_31_0] + (0x40 * arb->ap_swinf_no);
+	if (write == 1) {
+		memcpy(&data, buf, (bc & 3) + 1);
+		writel(data, arb->base + offset);
+	}
+
+	/* Send the command. */
+	offset = arb->regs[PMIF_SWINF_0_ACC] + (0x40 * arb->ap_swinf_no);
+	writel((opc << 30) | (write << 29) | (sid << 24) | (bc << 16) | addr,
+			arb->base + offset);
+	raw_spin_unlock_irqrestore(&arb->lock, flags);
+
+	return 0x0;
+}
+
+int is_pmif_spmi_init_done(struct pmif *arb)
+{
+	return pmif_readl(arb, PMIF_INIT_DONE) & 0x1;
+}
+
+static int mtk_spmi_config_master(struct pmif *arb,
+				  unsigned int mstid, bool en)
+{
+	/* Software reset */
+	writel(0x85 << 24 | 0x1 << 4,
+		arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	writel(0x7 | (0x1 << 4) | (0x1 << 7),
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_16_CLR]);
+	writel(0x1 << 2,
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE2]);
+
+	/* Software reset */
+	writel(0x85 << 24,
+		arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	/* Enable SPMI */
+	mtk_spmi_writel(arb, en, SPMI_REQ_EN);
+
+	return 0;
+}
+
+static int mtk_spmi_config_master_v2(struct pmif *arb,
+				     unsigned int mstid, bool en)
+{
+	/* Software reset */
+	writel(0x85 << 24 | 0x1 << 4,
+	       arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	writel((0x7 << 8) | (0x1 << 12) | (0x1 << 15),
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_15_CLR]);
+	writel(0x1 << 30,
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE2]);
+
+	/* Software reset */
+	writel(0x85 << 24,
+	       arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	/* Enable SPMI */
+	mtk_spmi_writel(arb, en, SPMI_REQ_EN);
+
+	return 0;
+}
+
+static int mtk_spmi_config_master_m_v1(struct pmif *arb,
+				       unsigned int mstid, bool en)
+{
+	/* Software reset */
+	writel(0x85 << 24 | 0x3 << 3,
+		arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	writel((0x7 << 8) | (0x1 << 12) | (0x1 << 15),
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_15_CLR]);
+	writel(0x1 << 30,
+		arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE2]);
+
+	/* Software reset */
+	writel(0x85 << 24,
+		arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	/* Enable master rcs */
+	mtk_spmi_writel(arb, 0x14 | arb->mstid, SPMI_RCS_CTRL);
+	/* Enable SPMI */
+	mtk_spmi_writel(arb, en, SPMI_REQ_EN);
+
+	return 0;
+}
+
+static int mtk_spmi_config_master_p_v1(struct pmif *arb,
+				       unsigned int mstid, bool en)
+{
+	/* Enable master rcs */
+	mtk_spmi_writel(arb, 0x14 | arb->mstid, SPMI_RCS_CTRL);
+	/* Enable SPMI */
+	mtk_spmi_writel(arb, en, SPMI_REQ_EN);
+
+	return 0;
+}
+
+static int mtk_spmi_config_master_m_v2(struct pmif *arb,
+				       unsigned int mstid, bool en)
+{
+	/* Software reset */
+	writel(0x85 << 24 | 0x1 << 4,
+		arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+#if !defined(CONFIG_FPGA_EARLY_PORTING)
+	writel((0x7 << 16) | (0x1 << 20) | (0x1 << 23),
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_6_CLR]);
+	writel(0x3 << 16,
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_6_SET]);
+	writel(0x1 << 26,
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE]);
+#endif
+
+	/* Software reset */
+	writel(0x85 << 24,
+		arb->toprgu_base + arb->toprgu_regs[WDT_SWSYSRST2]);
+
+	/* Enable master rcs */
+	mtk_spmi_writel(arb, 0x14 | arb->mstid, SPMI_RCS_CTRL);
+	/* Enable SPMI */
+	mtk_spmi_writel(arb, en, SPMI_REQ_EN);
+
+	return 0;
+}
+
+static int mtk_spmi_config_master_p_v2(struct pmif *arb,
+				       unsigned int mstid, bool en)
+{
+	/* no need to reset SPMI master again */
+
+#if !defined(CONFIG_FPGA_EARLY_PORTING)
+	writel((0xF << 24) | (0x1 << 28) | (0x1 << 31),
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_6_CLR]);
+	writel(0x7 << 24,
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_6_SET]);
+	writel(0x1 << 27,
+	       arb->topckgen_base + arb->topckgen_regs[CLK_CFG_UPDATE]);
+#endif
+	/* Enable SPMI */
+	mtk_spmi_writel(arb, en, SPMI_REQ_EN);
+
+	return 0;
+}
+
+static int mtk_spmi_cali_rd_clock_polarity(struct pmif *arb)
+{
+#if defined(CONFIG_MTK_FPGA) || defined(CONFIG_FPGA_EARLY_PORTING)
+	unsigned int dly = 0, pol = 0;
+#else
+	unsigned int dly = 1, pol = 1;
+#endif
+
+	/* Indicate sampling clock polarity, 1: Positive 0: Negative  */
+	mtk_spmi_writel(arb, (dly << 0x1) | pol, SPMI_SAMPL_CTRL);
+
+	return 0;
+}
+
+static int mtk_spmi_cali_rd_clock_polarity_m_p_v1(struct pmif *arb)
+{
+#if defined(CONFIG_MTK_FPGA) || defined(CONFIG_FPGA_EARLY_PORTING)
+	unsigned int dly = 0, pol = 0;
+#else
+	unsigned int dly = 0, pol = 1;
+#endif
+
+	/* Indicate sampling clock polarity, 1: Positive 0: Negative  */
+	mtk_spmi_writel(arb, ((dly + 1) << 0x4) | (dly << 0x1) | pol,
+			SPMI_SAMPL_CTRL);
+
+	return 0;
+}
+
+static int mtk_spmi_cali_rd_clock_polarity_m_p_v2(struct pmif *arb)
+{
+#if defined(CONFIG_MTK_FPGA) || defined(CONFIG_FPGA_EARLY_PORTING)
+	unsigned int dly = 1, pol = 0;
+#else
+	unsigned int dly = 0, pol = 1;
+#endif
+
+	/* Indicate sampling clock polarity, 1: Positive 0: Negative  */
+	mtk_spmi_writel(arb, ((dly + 1) << 0x4) | (dly << 0x1) | pol,
+			SPMI_SAMPL_CTRL);
+
+	return 0;
+}
+
+/*
+ * PMIF Exception IRQ Handler
+ */
+static void pmif_cmd_err_parity_err_irq_handler(int irq, void *data)
+{
+	spmi_dump_spmimst_all_reg();
+	spmi_dump_pmif_record_reg();
+	aee_kernel_warning("PMIF:parity error", "PMIF");
+}
+
+static void pmif_pmif_acc_vio_irq_handler(int irq, void *data)
+{
+	spmi_dump_pmif_acc_vio_reg();
+	aee_kernel_warning("PMIF:pmif_acc_vio", "PMIF");
+}
+
+static void pmif_pmic_acc_vio_irq_handler(int irq, void *data)
+{
+	spmi_dump_pmic_acc_vio_reg();
+	aee_kernel_warning("PMIF:pmic_acc_vio", "PMIF");
+}
+
+static void pmif_lat_limit_reached_irq_handler(int irq, void *data)
+{
+	spmi_dump_pmif_busy_reg();
+	spmi_dump_pmif_record_reg();
+}
+
+static void pmif_hw_monitor_irq_handler(int irq, void *data)
+{
+	spmi_dump_pmif_record_reg();
+	aee_kernel_warning("PMIF:pmif_hw_monitor_match", "PMIF");
+}
+
+static void pmif_wdt_irq_handler(int irq, void *data)
+{
+	spmi_dump_pmif_busy_reg();
+	spmi_dump_pmif_record_reg();
+	spmi_dump_wdt_reg();
+}
+
+static irqreturn_t pmif_event_0_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, idx = 0;
+
+	__pm_stay_awake(arb->pmifThread_lock);
+	mutex_lock(&arb->pmif_mutex);
+	irq_f = pmif_readl(arb, PMIF_IRQ_FLAG_0);
+	if (irq_f == 0) {
+		mutex_unlock(&arb->pmif_mutex);
+		__pm_relax(arb->pmifThread_lock);
+		return IRQ_NONE;
+	}
+
+	for (idx = 0; idx < 31; idx++) {
+		if ((irq_f & (0x1 << idx)) != 0) {
+			switch (idx) {
+			default:
+				pr_notice("%s IRQ[%d] triggered\n",
+					__func__, idx);
+				spmi_dump_pmif_record_reg();
+				break;
+			}
+			pmif_writel(arb, irq_f, PMIF_IRQ_CLR_0);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_mutex);
+	__pm_relax(arb->pmifThread_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pmif_event_1_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, idx = 0;
+
+	__pm_stay_awake(arb->pmifThread_lock);
+	mutex_lock(&arb->pmif_mutex);
+	irq_f = pmif_readl(arb, PMIF_IRQ_FLAG_1);
+	if (irq_f == 0) {
+		mutex_unlock(&arb->pmif_mutex);
+		__pm_relax(arb->pmifThread_lock);
+		return IRQ_NONE;
+	}
+
+	for (idx = 0; idx < 31; idx++) {
+		if ((irq_f & (0x1 << idx)) != 0) {
+			switch (idx) {
+			default:
+				pr_notice("%s IRQ[%d] triggered\n",
+					__func__, idx);
+				spmi_dump_pmif_record_reg();
+				break;
+			}
+			pmif_writel(arb, irq_f, PMIF_IRQ_CLR_1);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_mutex);
+	__pm_relax(arb->pmifThread_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pmif_event_2_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, idx = 0;
+
+	__pm_stay_awake(arb->pmifThread_lock);
+	mutex_lock(&arb->pmif_mutex);
+	irq_f = pmif_readl(arb, PMIF_IRQ_FLAG_2);
+	if (irq_f == 0) {
+		mutex_unlock(&arb->pmif_mutex);
+		__pm_relax(arb->pmifThread_lock);
+		return IRQ_NONE;
+	}
+
+	for (idx = 0; idx < 31; idx++) {
+		if ((irq_f & (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:
+				pmif_pmif_acc_vio_irq_handler(irq, data);
+				break;
+			case IRQ_PMIC_ACC_VIO:
+				pmif_pmic_acc_vio_irq_handler(irq, data);
+				break;
+			default:
+				pr_notice("%s IRQ[%d] triggered\n",
+					__func__, idx);
+				spmi_dump_pmif_record_reg();
+				break;
+			}
+			pmif_writel(arb, irq_f, PMIF_IRQ_CLR_2);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_mutex);
+	__pm_relax(arb->pmifThread_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pmif_event_3_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, idx = 0;
+
+	__pm_stay_awake(arb->pmifThread_lock);
+	mutex_lock(&arb->pmif_mutex);
+	irq_f = pmif_readl(arb, PMIF_IRQ_FLAG_3);
+	if (irq_f == 0) {
+		mutex_unlock(&arb->pmif_mutex);
+		__pm_relax(arb->pmifThread_lock);
+		return IRQ_NONE;
+	}
+
+	for (idx = 0; idx < 31; idx++) {
+		if ((irq_f & (0x1 << idx)) != 0) {
+			switch (idx) {
+			case IRQ_LAT_LIMIT_REACHED:
+				pmif_lat_limit_reached_irq_handler(irq, data);
+				break;
+			case IRQ_HW_MONITOR:
+				pmif_hw_monitor_irq_handler(irq, data);
+				break;
+			case IRQ_WDT:
+				pmif_wdt_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_V2:
+				pmif_pmic_acc_vio_irq_handler(irq, data);
+				break;
+			default:
+				pr_notice("%s IRQ[%d] triggered\n",
+					__func__, idx);
+				spmi_dump_pmif_record_reg();
+			break;
+			}
+			pmif_writel(arb, irq_f, PMIF_IRQ_CLR_3);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_mutex);
+	__pm_relax(arb->pmifThread_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pmif_event_4_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	int irq_f = 0, idx = 0;
+
+	__pm_stay_awake(arb->pmifThread_lock);
+	mutex_lock(&arb->pmif_mutex);
+	irq_f = pmif_readl(arb, PMIF_IRQ_FLAG_4);
+	if (irq_f == 0) {
+		mutex_unlock(&arb->pmif_mutex);
+		__pm_relax(arb->pmifThread_lock);
+		return IRQ_NONE;
+	}
+
+	for (idx = 0; idx < 31; idx++) {
+		if ((irq_f & (0x1 << idx)) != 0) {
+			switch (idx) {
+			default:
+				pr_notice("%s IRQ[%d] triggered\n",
+					__func__, idx);
+				spmi_dump_pmif_record_reg();
+			break;
+			}
+			pmif_writel(arb, irq_f, PMIF_IRQ_CLR_4);
+			break;
+		}
+	}
+	mutex_unlock(&arb->pmif_mutex);
+	__pm_relax(arb->pmifThread_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, irq_event_en[0] | pmif_readl(arb, PMIF_IRQ_EVENT_EN_0),
+			PMIF_IRQ_EVENT_EN_0);
+	pmif_writel(arb, irq_event_en[1] | pmif_readl(arb, PMIF_IRQ_EVENT_EN_1),
+			PMIF_IRQ_EVENT_EN_1);
+	pmif_writel(arb, irq_event_en[2] | pmif_readl(arb, PMIF_IRQ_EVENT_EN_2),
+			PMIF_IRQ_EVENT_EN_2);
+	pmif_writel(arb, irq_event_en[3] | pmif_readl(arb, PMIF_IRQ_EVENT_EN_3),
+			PMIF_IRQ_EVENT_EN_3);
+	pmif_writel(arb, irq_event_en[4] | pmif_readl(arb, PMIF_IRQ_EVENT_EN_4),
+			PMIF_IRQ_EVENT_EN_4);
+}
+
+static void rcs_irq_lock(struct irq_data *data)
+{
+	struct pmif *arb = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&arb->rcs_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_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 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,
+};
+
+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 irqreturn_t rcs_irq_handler(int irq, void *data)
+{
+	struct pmif *arb = data;
+	unsigned int slv_irq_sta;
+	int i;
+
+	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
+		slv_irq_sta = mtk_spmi_readl(arb, SPMI_SLV_3_0_EINT + (i / 4));
+		slv_irq_sta >>= (((i % 4) * 8) & 0xFF);
+		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));
+		}
+		/* need to clear using 0xFF to avoid new irq happen
+		 * after read SPMI_SLV_3_0_EINT + (i/4) value then use
+		 * this value to clean
+		 */
+		mtk_spmi_writel(arb, (0xFF << ((i % 4) * 8)),
+				SPMI_SLV_3_0_EINT + (i / 4));
+	}
+	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_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;
+
+	arb->irq_chip = rcs_irq_chip;
+	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;
+	}
+	/* clear all slave irq status */
+	for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) {
+		mtk_spmi_writel(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_spmimst_init(struct platform_device *pdev, struct pmif *arb)
+{
+	struct resource *res = NULL;
+	int err = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spmimst");
+	arb->spmimst_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(arb->spmimst_base)) {
+		err = PTR_ERR(arb->spmimst_base);
+		return err;
+	}
+
+	err = of_property_read_u32(pdev->dev.of_node, "grpid", &arb->grpid);
+	if (err) {
+		dev_notice(&pdev->dev, "[SPMIMST]:grpid unspecified.\n");
+		return -EINVAL;
+	}
+	/* set group id */
+	mtk_spmi_enable_group_id(arb, arb->grpid);
+
+	/* if spmimst not enabled, enable it */
+	if ((mtk_spmi_readl(arb, SPMI_REQ_EN) & 0x1) != 0x1) {
+		dev_info(&pdev->dev, "[SPMIMST]:enable spmimst.\n");
+		arb->spmi_config_master(arb, arb->mstid, true);
+		arb->pmif_cali_clock(arb);
+	}
+	pr_notice("[SPMIMST]:%s done\n", __func__);
+
+	return 0;
+}
+
+
+static int pmif_probe(struct platform_device *pdev)
+{
+	struct device_node *node = NULL;
+	const struct of_device_id *of_id =
+		of_match_device(pmif_match_table, &pdev->dev);
+	struct spmi_controller *ctrl = NULL;
+	struct pmif *arb = NULL;
+	struct resource *res = NULL;
+	u32 swinf_ch_start = 0, ap_swinf_no = 0;
+#if !defined(CONFIG_FPGA_EARLY_PORTING)
+	int pmif_clk26m = 0, spmimst_clk = 0;
+#endif
+	int err = 0;
+
+#if PMIF_BRINGUP
+	dev_notice(&pdev->dev, "[PMIF]bringup do nothing\n");
+	return 0;
+#endif
+	if (!of_id) {
+		dev_notice(&pdev->dev, "[PMIF]:Error: No device match found\n");
+		return -ENODEV;
+	}
+
+	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*arb));
+	if (!ctrl)
+		return -ENOMEM;
+
+	/* re-assign of_id->data */
+	spmi_controller_set_drvdata(ctrl, (void *)of_id->data);
+	arb = spmi_controller_get_drvdata(ctrl);
+	arb->spmic = ctrl;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmif");
+	arb->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(arb->base)) {
+		err = PTR_ERR(arb->base);
+		goto err_put_ctrl;
+	}
+	/* pmif is not initialized, just init once */
+	node = of_find_compatible_node(NULL, NULL, "mediatek,infracfg_ao");
+	arb->infra_base = of_iomap(node, 0);
+	if (IS_ERR(arb->infra_base)) {
+		err = PTR_ERR(arb->infra_base);
+		goto err_put_ctrl;
+	}
+
+	node = of_find_compatible_node(NULL, NULL, "mediatek,topckgen");
+	arb->topckgen_base = of_iomap(node, 0);
+	if (IS_ERR(arb->topckgen_base)) {
+		err = PTR_ERR(arb->topckgen_base);
+		goto err_put_ctrl;
+	}
+
+	node = of_find_compatible_node(NULL, NULL, "mediatek,toprgu");
+	arb->toprgu_base = of_iomap(node, 0);
+	if (IS_ERR(arb->toprgu_base)) {
+		err = PTR_ERR(arb->toprgu_base);
+		goto err_put_ctrl;
+	}
+#if !defined(CONFIG_FPGA_EARLY_PORTING)
+	/* get pmif infracfg_ao clock */
+	arb->pmif_sys_ck = devm_clk_get(&pdev->dev, "pmif_sys_ck");
+	if (IS_ERR(arb->pmif_sys_ck)) {
+		dev_notice(&pdev->dev, "[PMIF]:failed to get ap clock: %ld\n",
+			PTR_ERR(arb->pmif_sys_ck));
+		return PTR_ERR(arb->pmif_sys_ck);
+	}
+
+	arb->pmif_tmr_ck = devm_clk_get(&pdev->dev, "pmif_tmr_ck");
+	if (IS_ERR(arb->pmif_tmr_ck)) {
+		dev_notice(&pdev->dev, "[PMIF]:failed to get tmr clock: %ld\n",
+			PTR_ERR(arb->pmif_tmr_ck));
+		return PTR_ERR(arb->pmif_tmr_ck);
+	}
+
+	/* get pmif topckgen clock */
+	arb->pmif_clk_mux = devm_clk_get(&pdev->dev, "pmif_clk_mux");
+	if (IS_ERR(arb->pmif_clk_mux)) {
+		dev_notice(&pdev->dev, "[PMIF]:failed to get clock: %ld\n",
+			PTR_ERR(arb->pmif_clk_mux));
+		return PTR_ERR(arb->pmif_clk_mux);
+	}
+	/* now enable pmif/spmimst clock */
+	pmif_clk26m =
+		readl(arb->infra_base + arb->infra_regs[PMICW_CLOCK_CTRL]);
+
+	if ((pmif_clk26m & 0x1) == 0x1) {
+		arb->pmif_clk26m = devm_clk_get(&pdev->dev, "pmif_clk26m");
+		if (IS_ERR(arb->pmif_clk26m)) {
+			dev_notice(&pdev->dev,
+				   "[PMIF]:failed to get clock: %ld\n",
+				   PTR_ERR(arb->pmif_clk26m));
+			return PTR_ERR(arb->pmif_clk26m);
+		}
+		dev_info(&pdev->dev, "[PMIF]:enable clk26m.\n");
+		err = clk_prepare_enable(arb->pmif_clk26m);
+		if (err)
+			return err;
+	} else {
+		arb->pmif_clk_mux_parent = devm_clk_get(&pdev->dev,
+							"pmif_clk_osc_d10");
+		dev_info(&pdev->dev, "[PMIF]:enable ulposc1 osc d10.\n");
+		if (IS_ERR(arb->pmif_clk_mux_parent)) {
+			dev_notice(&pdev->dev,
+				   "[PMIF]:failed to get clock: %ld\n",
+				   PTR_ERR(arb->pmif_clk_mux_parent));
+			return PTR_ERR(arb->pmif_clk_mux_parent);
+		}
+		err = clk_prepare_enable(arb->pmif_clk_mux);
+		if (err)
+			return err;
+		err = clk_set_parent(arb->pmif_clk_mux,
+				     arb->pmif_clk_mux_parent);
+		if (err)
+			return err;
+	}
+	err = clk_prepare_enable(arb->pmif_sys_ck);
+	if (err)
+		return err;
+	err = clk_prepare_enable(arb->pmif_tmr_ck);
+	if (err)
+		return err;
+
+	/* get spmimst topckgen clock */
+	arb->spmimst_clk_mux = devm_clk_get(&pdev->dev, "spmimst_clk_mux");
+	if (IS_ERR(arb->spmimst_clk_mux)) {
+		dev_notice(&pdev->dev, "[SPMIMST]:failed to get clock: %ld\n",
+			PTR_ERR(arb->spmimst_clk_mux));
+		return PTR_ERR(arb->spmimst_clk_mux);
+	}
+	if (of_device_is_compatible(ctrl->dev.parent->of_node,
+				    "mediatek,mt6885-pmif")) {
+		spmimst_clk =
+		readl(arb->topckgen_base + arb->topckgen_regs[CLK_CFG_16]);
+		spmimst_clk = 0x7;
+	} else if (of_device_is_compatible(ctrl->dev.parent->of_node,
+					   "mediatek,mt6880-pmif-m")) {
+		spmimst_clk =
+		readl(arb->topckgen_base + arb->topckgen_regs[CLK_CFG_6]);
+		spmimst_clk = (spmimst_clk >> 16) & 0x7;
+	} else if (of_device_is_compatible(ctrl->dev.parent->of_node,
+					   "mediatek,mt6880-pmif-p")) {
+		spmimst_clk =
+		readl(arb->topckgen_base + arb->topckgen_regs[CLK_CFG_6]);
+		spmimst_clk = (spmimst_clk >> 24) & 0xF;
+	} else {
+		spmimst_clk =
+		readl(arb->topckgen_base + arb->topckgen_regs[CLK_CFG_15]);
+		spmimst_clk = (spmimst_clk >> 0x8) & 0x7;
+	}
+	switch (spmimst_clk) {
+	case 0:
+		arb->spmimst_clk_mux_parent =
+			devm_clk_get(&pdev->dev, "spmimst_clk26m");
+		dev_info(&pdev->dev, "[SPMIMST]:enable clk26m.\n");
+		break;
+	case 3:
+		arb->spmimst_clk_mux_parent =
+			devm_clk_get(&pdev->dev, "spmimst_clk_osc_d10");
+		dev_info(&pdev->dev, "[SPMIMST]:enable ulposc1 osc d10.\n");
+		break;
+	case 7:
+		arb->spmimst_clk_mux_parent =
+			devm_clk_get(&pdev->dev, "spmimst_clk_mainpll_d7_d8");
+		dev_info(&pdev->dev, "[SPMIMST]:enable mainpll d7 d8.\n");
+		break;
+	}
+	if (IS_ERR(arb->spmimst_clk_mux_parent)) {
+		dev_notice(&pdev->dev,
+			   "[SPMIMST]:failed to get clock: %ld\n",
+			   PTR_ERR(arb->spmimst_clk_mux_parent));
+		return PTR_ERR(arb->spmimst_clk_mux_parent);
+	}
+	err = clk_prepare_enable(arb->spmimst_clk_mux);
+	if (err)
+		return err;
+	err = clk_set_parent(arb->spmimst_clk_mux, arb->spmimst_clk_mux_parent);
+	if (err)
+		return err;
+#else
+	dev_notice(&pdev->dev, "[PMIF]:no need to get clock at fpga\n");
+#endif /* #if defined(CONFIG_MTK_FPGA) || defined(CONFIG_FPGA_EARLY_PORTING) */
+
+	err = of_property_read_u32(pdev->dev.of_node,
+				   "swinf_ch_start", &swinf_ch_start);
+	if (err) {
+		dev_notice(&pdev->dev, "[PMIF]:swinf_ch_start unspecified.\n");
+		goto err_put_ctrl;
+	}
+	arb->swinf_ch_start = swinf_ch_start;
+
+	err = of_property_read_u32(pdev->dev.of_node,
+			"ap_swinf_no", &ap_swinf_no);
+	if (err) {
+		dev_notice(&pdev->dev, "[PMIF]:ap_swinf_no unspecified.\n");
+		goto err_put_ctrl;
+	}
+	arb->ap_swinf_no = ap_swinf_no;
+
+	if (arb->is_pmif_init_done(arb) == 0) {
+		/* pmif initialize start */
+		arb->pmif_enable_clk_set(arb);
+		arb->pmif_force_normal_mode(arb);
+		/* Enable SWINF and arbitration for AP. */
+		arb->pmif_enable_swinf(arb,
+				arb->swinf_ch_start, arb->ap_swinf_no);
+		arb->pmif_enable_cmdIssue(arb, true);
+
+		arb->pmif_enable(arb);
+		/* pmif initialize end */
+	}
+
+	raw_spin_lock_init(&arb->lock);
+	arb->pmifThread_lock =
+		wakeup_source_register(NULL, "pmif wakelock");
+	mutex_init(&arb->pmif_mutex);
+
+	ctrl->cmd = pmif_arb_cmd;
+	ctrl->read_cmd = pmif_spmi_read_cmd;
+	ctrl->write_cmd = pmif_spmi_write_cmd;
+
+	if (arb->is_pmif_init_done(arb)) {
+		/* pmif already done, call spmi master driver init */
+		err = mtk_spmimst_init(pdev, arb);
+		if (err)
+			goto err_put_ctrl;
+	}
+	if (arb->pmifid != PMIF_PMIFID_SPMI2) {
+		/* enable debugger for SPMI-M */
+		spmi_pmif_dbg_init(ctrl);
+		spmi_pmif_create_attr(&pmif_driver.driver);
+	}
+	arb->irq = platform_get_irq_byname(pdev, "pmif_irq");
+	if (arb->irq < 0) {
+		err = arb->irq;
+		goto err_put_ctrl;
+	}
+	pmif_irq_register(pdev, arb, arb->irq);
+
+	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)
+			goto err_domain_remove;
+	}
+
+	platform_set_drvdata(pdev, ctrl);
+
+	err = spmi_controller_add(ctrl);
+	if (err)
+		goto err_domain_remove;
+
+	return 0;
+
+err_domain_remove:
+	if (arb->domain)
+		irq_domain_remove(arb->domain);
+#if !defined(CONFIG_FPGA_EARLY_PORTING)
+	clk_disable_unprepare(arb->spmimst_clk_mux);
+	clk_disable_unprepare(arb->pmif_tmr_ck);
+	clk_disable_unprepare(arb->pmif_sys_ck);
+	if ((pmif_clk26m & 0x1) == 0x1)
+		clk_disable_unprepare(arb->pmif_clk26m);
+	else
+		clk_disable_unprepare(arb->pmif_clk_mux);
+#endif
+err_put_ctrl:
+	spmi_controller_put(ctrl);
+	return err;
+}
+
+static int pmif_remove(struct platform_device *pdev)
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
+
+	if (arb->domain)
+		irq_domain_remove(arb->domain);
+	spmi_controller_remove(ctrl);
+	spmi_controller_put(ctrl);
+	return 0;
+}
+
+static struct platform_driver pmif_driver = {
+	.probe		= pmif_probe,
+	.remove		= pmif_remove,
+	.driver		= {
+		.name	= "pmif",
+		.of_match_table = of_match_ptr(pmif_match_table),
+	},
+};
+
+static int __init mtk_pmif_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&pmif_driver);
+	if (ret)
+		return -ENODEV;
+	return 0;
+}
+postcore_initcall(mtk_pmif_init);
+
+/* Module information */
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIF module");
+MODULE_AUTHOR("Argus Lin <argus.lin@mediatek.com>");
+MODULE_ALIAS("platform:pmif");