[][openwrt][mt7988][integration][Add basic Filogic 880 SoC support]

[Description]
Add basic filogic 880 SoC support to openwrt 21.02

[Release-log]

Change-Id: I57791df2e9f9f4729cb2d32f734090de52c370f2
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6592143
Build: srv_hbgsm110
diff --git a/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c b/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
index ad1f092..637e2c5 100644
--- a/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
+++ b/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
@@ -31,7 +31,7 @@
 
 static int bring_up_probe(struct platform_device *pdev)
 {
-	const int NR_CLKS = 300;
+	const int NR_CLKS = 400;
 	char clk_name_buf[16];
 	struct clk *clk;
 	int i, r;
diff --git a/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7988.c b/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7988.c
new file mode 100644
index 0000000..86111c4
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7988.c
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+
+#include <dt-bindings/clock/mt7988-clk.h>
+
+static DEFINE_SPINLOCK(mt7988_clk_lock);
+
+static const struct mtk_fixed_factor top_divs[] __initconst = {
+	FACTOR(CK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),
+	FACTOR(CK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1),
+	FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),
+	FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 2),
+	FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),
+	FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),
+	FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),
+	FACTOR(CK_TOP_CB_MM_720M, "cb_mm_720m", "mmpll", 1, 1),
+	FACTOR(CK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2),
+	FACTOR(CK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", "mmpll", 1, 15),
+	FACTOR(CK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4),
+	FACTOR(CK_TOP_MM_D6_D2, "mm_d6_d2", "mmpll", 1, 12),
+	FACTOR(CK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8),
+	FACTOR(CK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1),
+	FACTOR(CK_TOP_CB_APLL2_D4, "cb_apll2_d4", "apll2", 1, 4),
+	FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),
+	FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),
+	FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),
+	FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),
+	FACTOR(CK_TOP_CB_NET1_D8, "cb_net1_d8", "net1pll", 1, 8),
+	FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),
+	FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),
+	FACTOR(CK_TOP_NET1_D8_D8, "net1_d8_d8", "net1pll", 1, 64),
+	FACTOR(CK_TOP_NET1_D8_D16, "net1_d8_d16", "net1pll", 1, 128),
+	FACTOR(CK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1),
+	FACTOR(CK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2),
+	FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),
+	FACTOR(CK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16),
+	FACTOR(CK_TOP_NET2_D4_D8, "net2_d4_d8", "net2pll", 1, 32),
+	FACTOR(CK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6),
+	FACTOR(CK_TOP_CB_NET2_D8, "cb_net2_d8", "net2pll", 1, 8),
+	FACTOR(CK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m", "wedmcupll", 1, 1),
+	FACTOR(CK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1),
+	FACTOR(CK_TOP_CB_NETSYS_850M, "cb_netsys_850m", "netsyspll", 1, 1),
+	FACTOR(CK_TOP_CB_MSDC_400M, "cb_msdc_400m", "msdcpll", 1, 1),
+	FACTOR(CK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2),
+	FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),
+	FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220),
+	FACTOR(CK_TOP_INFRA_F32K, "csw_infra_f32k", "cb_rtc_32p7k", 1, 1),
+	FACTOR(CK_TOP_CKSQ_SRC, "cksq_src", "clkxtal", 1, 1),
+	FACTOR(CK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1),
+	FACTOR(CK_TOP_NETSYS_GSW, "netsys_gsw", "netsys_gsw_sel", 1, 1),
+	FACTOR(CK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1),
+	FACTOR(CK_TOP_EIP197, "eip197", "eip197_sel", 1, 1),
+	FACTOR(CK_TOP_EMMC_250M, "emmc_250m", "emmc_250m_sel", 1, 1),
+	FACTOR(CK_TOP_EMMC_400M, "emmc_400m", "emmc_400m_sel", 1, 1),
+	FACTOR(CK_TOP_SPI, "spi", "spi_sel", 1, 1),
+	FACTOR(CK_TOP_SPIM_MST, "spim_mst", "spim_mst_sel", 1, 1),
+	FACTOR(CK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1),
+	FACTOR(CK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1),
+	FACTOR(CK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1),
+	FACTOR(CK_TOP_USB_SYS, "usb_sys", "usb_sys_sel", 1, 1),
+	FACTOR(CK_TOP_USB_SYS_P1, "usb_sys_p1", "usb_sys_p1_sel", 1, 1),
+	FACTOR(CK_TOP_USB_XHCI, "usb_xhci", "usb_xhci_sel", 1, 1),
+	FACTOR(CK_TOP_USB_XHCI_P1, "usb_xhci_p1", "usb_xhci_p1_sel", 1, 1),
+	FACTOR(CK_TOP_USB_FRMCNT, "usb_frmcnt", "usb_frmcnt_sel", 1, 1),
+	FACTOR(CK_TOP_USB_FRMCNT_P1, "usb_frmcnt_p1", "usb_frmcnt_p1_sel", 1,
+	       1),
+	FACTOR(CK_TOP_AUD, "aud", "aud_sel", 1, 1),
+	FACTOR(CK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1),
+	FACTOR(CK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1),
+	FACTOR(CK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1),
+	FACTOR(CK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1),
+	FACTOR(CK_TOP_INFRA_F26M, "csw_infra_f26m", "csw_infra_f26m_sel", 1, 1),
+	FACTOR(CK_TOP_USB_REF, "usb_ref", "cksq_src", 1, 1),
+	FACTOR(CK_TOP_USB_CK_P1, "usb_ck_p1", "cksq_src", 1, 1),
+};
+
+static const struct mtk_fixed_factor infra_divs[] __initconst = {
+	FACTOR(CK_INFRA_CK_F26M, "infra_ck_f26m", "csw_infra_f26m_sel", 1, 1),
+	FACTOR(CK_INFRA_PWM_O, "infra_pwm_o", "pwm_sel", 1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P0, "infra_pcie_ck_occ_p0", "pextp_tl_ck_sel",
+	       1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P1, "infra_pcie_ck_occ_p1",
+	       "pextp_tl_ck_p1_sel", 1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P2, "infra_pcie_ck_occ_p2",
+	       "pextp_tl_ck_p2_sel", 1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P3, "infra_pcie_ck_occ_p3",
+	       "pextp_tl_ck_p3_sel", 1, 1),
+	FACTOR(CK_INFRA_133M_HCK, "infra_133m_hck", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", "infra_133m_hck", 1, 1),
+	FACTOR(CK_INFRA_66M_PHCK, "infra_66m_phck", "infra_133m_hck", 1, 1),
+	FACTOR(CK_INFRA_FAUD_L_O, "infra_faud_l_o", "aud_l", 1, 1),
+	FACTOR(CK_INFRA_FAUD_AUD_O, "infra_faud_aud_o", "a1sys", 1, 1),
+	FACTOR(CK_INFRA_FAUD_EG2_O, "infra_faud_eg2_o", "a_tuner", 1, 1),
+	FACTOR(CK_INFRA_I2C_O, "infra_i2c_o", "i2c_bck", 1, 1),
+	FACTOR(CK_INFRA_UART_O0, "infra_uart_o0", "uart_sel", 1, 1),
+	FACTOR(CK_INFRA_UART_O1, "infra_uart_o1", "uart_sel", 1, 1),
+	FACTOR(CK_INFRA_UART_O2, "infra_uart_o2", "uart_sel", 1, 1),
+	FACTOR(CK_INFRA_NFI_O, "infra_nfi_o", "nfi1x", 1, 1),
+	FACTOR(CK_INFRA_SPINFI_O, "infra_spinfi_o", "spinfi_bck", 1, 1),
+	FACTOR(CK_INFRA_SPI0_O, "infra_spi0_o", "spi", 1, 1),
+	FACTOR(CK_INFRA_SPI1_O, "infra_spi1_o", "spim_mst", 1, 1),
+	FACTOR(CK_INFRA_LB_MUX_FRTC, "infra_lb_mux_frtc", "infra_frtc", 1, 1),
+	FACTOR(CK_INFRA_FRTC, "infra_frtc", "cb_rtc_32k", 1, 1),
+	FACTOR(CK_INFRA_FMSDC400_O, "infra_fmsdc400_o", "emmc_400m", 1, 1),
+	FACTOR(CK_INFRA_FMSDC2_HCK_OCC, "infra_fmsdc2_hck_occ", "emmc_250m", 1,
+	       1),
+	FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_USB_O, "infra_usb_o", "usb_ref", 1, 1),
+	FACTOR(CK_INFRA_USB_O_P1, "infra_usb_o_p1", "usb_ck_p1", 1, 1),
+	FACTOR(CK_INFRA_USB_FRMCNT_O, "infra_usb_frmcnt_o", "usb_frmcnt", 1, 1),
+	FACTOR(CK_INFRA_USB_FRMCNT_O_P1, "infra_usb_frmcnt_o_p1",
+	       "usb_frmcnt_p1", 1, 1),
+	FACTOR(CK_INFRA_USB_XHCI_O, "infra_usb_xhci_o", "usb_xhci", 1, 1),
+	FACTOR(CK_INFRA_USB_XHCI_O_P1, "infra_usb_xhci_o_p1", "usb_xhci_p1", 1,
+	       1),
+	FACTOR(CK_INFRA_USB_PIPE_O, "infra_usb_pipe_o", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_USB_PIPE_O_P1, "infra_usb_pipe_o_p1", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_USB_UTMI_O, "infra_usb_utmi_o", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_USB_UTMI_O_P1, "infra_usb_utmi_o_p1", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P0, "infra_pcie_pipe_ck_occ_p0",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P1, "infra_pcie_pipe_ck_occ_p1",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P2, "infra_pcie_pipe_ck_occ_p2",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P3, "infra_pcie_pipe_ck_occ_p3",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_F26M_O0, "infra_f26m_o0", "csw_infra_f26m", 1, 1),
+	FACTOR(CK_INFRA_F26M_O1, "infra_f26m_o1", "csw_infra_f26m", 1, 1),
+	FACTOR(CK_INFRA_133M_MCK, "infra_133m_mck", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_PERI_66M_O, "infra_peri_66m_o", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_USB_SYS_O, "infra_usb_sys_o", "usb_sys", 1, 1),
+	FACTOR(CK_INFRA_USB_SYS_O_P1, "infra_usb_sys_o_p1", "usb_sys_p1", 1, 1),
+};
+
+static const char *const mcu_bus_div_parents[] = { "cb_cksq_40m", "ccipll2_b",
+						   "cb_net1_d4" };
+
+static const char *const mcu_arm_div_parents[] = { "cb_cksq_40m", "arm_b",
+						   "cb_net1_d4" };
+
+static struct mtk_composite mcu_muxes[] = {
+	/* bus_pll_divider_cfg */
+	MUX_GATE_FLAGS(CK_MCU_BUS_DIV_SEL, "mcu_bus_div_sel",
+		       mcu_bus_div_parents, 0x7C0, 9, 2, -1, CLK_IS_CRITICAL),
+	/* mp2_pll_divider_cfg */
+	MUX_GATE_FLAGS(CK_MCU_ARM_DIV_SEL, "mcu_arm_div_sel",
+		       mcu_arm_div_parents, 0x7A8, 9, 2, -1, CLK_IS_CRITICAL),
+};
+
+static const char *const netsys_parents[] = { "cb_cksq_40m", "cb_net2_d2",
+					      "cb_mm_d2" };
+
+static const char *const netsys_500m_parents[] = { "cb_cksq_40m", "cb_net1_d5",
+						   "net1_d5_d2" };
+
+static const char *const netsys_2x_parents[] = { "cb_cksq_40m", "cb_net2_800m",
+						 "cb_mm_720m" };
+
+static const char *const netsys_gsw_parents[] = { "cb_cksq_40m", "cb_net1_d4",
+						  "cb_net1_d5" };
+
+static const char *const eth_gmii_parents[] = { "cb_cksq_40m", "net1_d5_d4" };
+
+static const char *const netsys_mcu_parents[] = { "cb_cksq_40m", "cb_net2_800m",
+						  "cb_mm_720m",	 "cb_net1_d4",
+						  "cb_net1_d5",	 "cb_m_416m" };
+
+static const char *const eip197_parents[] = { "cb_cksq_40m",  "cb_netsys_850m",
+					      "cb_net2_800m", "cb_mm_720m",
+					      "cb_net1_d4",   "cb_net1_d5" };
+
+static const char *const axi_infra_parents[] = { "cb_cksq_40m", "net1_d8_d2" };
+
+static const char *const uart_parents[] = { "cb_cksq_40m", "cb_m_d8",
+					    "m_d8_d2" };
+
+static const char *const emmc_250m_parents[] = { "cb_cksq_40m", "net1_d5_d2",
+						 "cb_mm_d4" };
+
+static const char *const emmc_400m_parents[] = { "cb_cksq_40m", "cb_msdc_400m",
+						 "cb_mm_d2",	"cb_m_d2",
+						 "cb_mm_d4",	"net1_d8_d2" };
+
+static const char *const spi_parents[] = { "cb_cksq_40m", "cb_m_d2",
+					   "cb_mm_d4",	  "net1_d8_d2",
+					   "cb_net2_d6",  "net1_d5_d4",
+					   "cb_m_d4",	  "net1_d8_d4" };
+
+static const char *const nfi1x_parents[] = { "cb_cksq_40m", "cb_mm_d4",
+					     "net1_d8_d2",  "cb_net2_d6",
+					     "cb_m_d4",	    "cb_mm_d8",
+					     "net1_d8_d4",  "cb_m_d8" };
+
+static const char *const spinfi_parents[] = { "cksq_40m_d2", "cb_cksq_40m",
+					      "net1_d5_d4",  "cb_m_d4",
+					      "cb_mm_d8",    "net1_d8_d4",
+					      "mm_d6_d2",    "cb_m_d8" };
+
+static const char *const pwm_parents[] = { "cb_cksq_40m", "net1_d8_d2",
+					   "net1_d5_d4",  "cb_m_d4",
+					   "m_d8_d2",	  "cb_rtc_32k" };
+
+static const char *const i2c_parents[] = { "cb_cksq_40m", "net1_d5_d4",
+					   "cb_m_d4", "net1_d8_d4" };
+
+static const char *const pcie_mbist_250m_parents[] = { "cb_cksq_40m",
+						       "net1_d5_d2" };
+
+static const char *const pextp_tl_ck_parents[] = { "cb_cksq_40m", "cb_net2_d6",
+						   "cb_mm_d8", "m_d8_d2",
+						   "cb_rtc_32k" };
+
+static const char *const usb_frmcnt_parents[] = { "cb_cksq_40m",
+						  "cb_mm_d3_d5" };
+
+static const char *const aud_parents[] = { "cb_cksq_40m", "cb_apll2_196m" };
+
+static const char *const a1sys_parents[] = { "cb_cksq_40m", "cb_apll2_d4" };
+
+static const char *const aud_l_parents[] = { "cb_cksq_40m", "cb_apll2_196m",
+					     "m_d8_d2" };
+
+static const char *const sspxtp_parents[] = { "cksq_40m_d2", "m_d8_d2" };
+
+static const char *const usxgmii_sbus_0_parents[] = { "cb_cksq_40m",
+						      "net1_d8_d4" };
+
+static const char *const sgm_0_parents[] = { "cb_cksq_40m", "cb_sgm_325m" };
+
+static const char *const sysapb_parents[] = { "cb_cksq_40m", "m_d3_d2" };
+
+static const char *const eth_refck_50m_parents[] = { "cb_cksq_40m",
+						     "net2_d4_d4" };
+
+static const char *const eth_sys_200m_parents[] = { "cb_cksq_40m",
+						    "cb_net2_d4" };
+
+static const char *const eth_xgmii_parents[] = { "cksq_40m_d2", "net1_d8_d8",
+						 "net1_d8_d16" };
+
+static const char *const bus_tops_parents[] = { "cb_cksq_40m", "cb_net1_d5",
+						"cb_net2_d2" };
+
+static const char *const npu_tops_parents[] = { "cb_cksq_40m", "cb_net2_800m" };
+
+static const char *const dramc_md32_parents[] = { "cb_cksq_40m", "cb_m_d2",
+						  "cb_wedmcu_208m" };
+
+static const char *const da_xtp_glb_p0_parents[] = { "cb_cksq_40m",
+						     "cb_net2_d8" };
+
+static const char *const mcusys_backup_625m_parents[] = { "cb_cksq_40m",
+							  "cb_net1_d4" };
+
+static const char *const macsec_parents[] = { "cb_cksq_40m", "cb_sgm_325m",
+					      "cb_net1_d8" };
+
+static const char *const netsys_tops_400m_parents[] = { "cb_cksq_40m",
+							"cb_net2_d2" };
+
+static const char *const eth_mii_parents[] = { "cksq_40m_d2", "net2_d4_d8" };
+
+static struct mtk_mux top_muxes[] = {
+	/* CLK_CFG_0 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents,
+			     0x000, 0x004, 0x008, 0, 2, 7, 0x1C0, 0),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",
+			     netsys_500m_parents, 0x000, 0x004, 0x008, 8, 2, 15,
+			     0x1C0, 1),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",
+			     netsys_2x_parents, 0x000, 0x004, 0x008, 16, 2, 23,
+			     0x1C0, 2),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_GSW_SEL, "netsys_gsw_sel",
+			     netsys_gsw_parents, 0x000, 0x004, 0x008, 24, 2, 31,
+			     0x1C0, 3),
+	/* CLK_CFG_1 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_GMII_SEL, "eth_gmii_sel",
+			     eth_gmii_parents, 0x010, 0x014, 0x018, 0, 1, 7,
+			     0x1C0, 4),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel",
+			     netsys_mcu_parents, 0x010, 0x014, 0x018, 8, 3, 15,
+			     0x1C0, 5),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_PAO_2X_SEL, "netsys_pao_2x_sel",
+			     netsys_mcu_parents, 0x010, 0x014, 0x018, 16, 3, 23,
+			     0x1C0, 6),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_EIP197_SEL, "eip197_sel", eip197_parents,
+			     0x010, 0x014, 0x018, 24, 3, 31, 0x1C0, 7),
+	/* CLK_CFG_2 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_AXI_INFRA_SEL, "axi_infra_sel",
+			     axi_infra_parents, 0x020, 0x024, 0x028, 0, 1, 7,
+			     0x1C0, 8),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_UART_SEL, "uart_sel", uart_parents, 0x020,
+			     0x024, 0x028, 8, 2, 15, 0x1C0, 9),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_250M_SEL, "emmc_250m_sel",
+			     emmc_250m_parents, 0x020, 0x024, 0x028, 16, 2, 23,
+			     0x1C0, 10),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_400M_SEL, "emmc_400m_sel",
+			     emmc_400m_parents, 0x020, 0x024, 0x028, 24, 3, 31,
+			     0x1C0, 11),
+	/* CLK_CFG_3 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x030,
+			     0x034, 0x038, 0, 3, 7, 0x1C0, 12),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents,
+			     0x030, 0x034, 0x038, 8, 3, 15, 0x1C0, 13),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents,
+			     0x030, 0x034, 0x038, 16, 3, 23, 0x1C0, 14),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents,
+			     0x030, 0x034, 0x038, 24, 3, 31, 0x1C0, 15),
+	/* CLK_CFG_4 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x040,
+			     0x044, 0x048, 0, 3, 7, 0x1C0, 16),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x040,
+			     0x044, 0x048, 8, 2, 15, 0x1C0, 17),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PCIE_MBIST_250M_SEL, "pcie_mbist_250m_sel",
+			     pcie_mbist_250m_parents, 0x040, 0x044, 0x048, 16,
+			     1, 23, 0x1C0, 18),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",
+			     pextp_tl_ck_parents, 0x040, 0x044, 0x048, 24, 3,
+			     31, 0x1C0, 19),
+	/* CLK_CFG_5 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_ck_p1_sel",
+			     pextp_tl_ck_parents, 0x050, 0x054, 0x058, 0, 3, 7,
+			     0x1C0, 20),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P2_SEL, "pextp_tl_ck_p2_sel",
+			     pextp_tl_ck_parents, 0x050, 0x054, 0x058, 8, 3, 15,
+			     0x1C0, 21),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P3_SEL, "pextp_tl_ck_p3_sel",
+			     pextp_tl_ck_parents, 0x050, 0x054, 0x058, 16, 3,
+			     23, 0x1C0, 22),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_SYS_SEL, "usb_sys_sel",
+			     eth_gmii_parents, 0x050, 0x054, 0x058, 24, 1, 31,
+			     0x1C0, 23),
+	/* CLK_CFG_6 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel",
+			     eth_gmii_parents, 0x060, 0x064, 0x068, 0, 1, 7,
+			     0x1C0, 24),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_XHCI_SEL, "usb_xhci_sel",
+			     eth_gmii_parents, 0x060, 0x064, 0x068, 8, 1, 15,
+			     0x1C0, 25),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel",
+			     eth_gmii_parents, 0x060, 0x064, 0x068, 16, 1, 23,
+			     0x1C0, 26),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel",
+			     usb_frmcnt_parents, 0x060, 0x064, 0x068, 24, 1, 31,
+			     0x1C0, 27),
+	/* CLK_CFG_7 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_FRMCNT_P1_SEL, "usb_frmcnt_p1_sel",
+			     usb_frmcnt_parents, 0x070, 0x074, 0x078, 0, 1, 7,
+			     0x1C0, 28),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x070,
+			     0x074, 0x078, 8, 1, 15, 0x1C0, 29),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
+			     0x070, 0x074, 0x078, 16, 1, 23, 0x1C0, 30),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
+			     0x070, 0x074, 0x078, 24, 2, 31, 0x1C4, 0),
+	/* CLK_CFG_8 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents,
+			     0x080, 0x084, 0x088, 0, 1, 7, 0x1C4, 1),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SSPXTP_SEL, "sspxtp_sel", sspxtp_parents,
+			     0x080, 0x084, 0x088, 8, 1, 15, 0x1C4, 2),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_PHY_SEL, "usb_phy_sel", sspxtp_parents,
+			     0x080, 0x084, 0x088, 16, 1, 23, 0x1C4, 3),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USXGMII_SBUS_0_SEL, "usxgmii_sbus_0_sel",
+			     usxgmii_sbus_0_parents, 0x080, 0x084, 0x088, 24, 1,
+			     31, 0x1C4, 4),
+	/* CLK_CFG_9 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USXGMII_SBUS_1_SEL, "usxgmii_sbus_1_sel",
+			     usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 0, 1,
+			     7, 0x1C4, 5),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents,
+			     0x090, 0x094, 0x098, 8, 1, 15, 0x1C4, 6),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel",
+			     usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 16, 1,
+			     23, 0x1C4, 7),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents,
+			     0x090, 0x094, 0x098, 24, 1, 31, 0x1C4, 8),
+	/* CLK_CFG_10 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel",
+			     usxgmii_sbus_0_parents, 0x0A0, 0x0A4, 0x0A8, 0, 1,
+			     7, 0x1C4, 9),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_XFI_PHY_0_XTAL_SEL, "xfi_phy_0_xtal_sel",
+			     sspxtp_parents, 0x0A0, 0x0A4, 0x0A8, 8, 1, 15,
+			     0x1C4, 10),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_XFI_PHY_1_XTAL_SEL, "xfi_phy_1_xtal_sel",
+			     sspxtp_parents, 0x0A0, 0x0A4, 0x0A8, 16, 1, 23,
+			     0x1C4, 11),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAXI_SEL, "sysaxi_sel", axi_infra_parents,
+			     0x0A0, 0x0A4, 0x0A8, 24, 1, 31, 0x1C4, 12),
+	/* CLK_CFG_11 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents,
+			     0x0B0, 0x0B4, 0x0B8, 0, 1, 7, 0x1C4, 13),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel",
+			     eth_refck_50m_parents, 0x0B0, 0x0B4, 0x0B8, 8, 1,
+			     15, 0x1C4, 14),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel",
+			     eth_sys_200m_parents, 0x0B0, 0x0B4, 0x0B8, 16, 1,
+			     23, 0x1C4, 15),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_SYS_SEL, "eth_sys_sel",
+			     pcie_mbist_250m_parents, 0x0B0, 0x0B4, 0x0B8, 24,
+			     1, 31, 0x1C4, 16),
+	/* CLK_CFG_12 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel",
+			     eth_xgmii_parents, 0x0C0, 0x0C4, 0x0C8, 0, 2, 7,
+			     0x1C4, 17),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_BUS_TOPS_SEL, "bus_tops_sel",
+			     bus_tops_parents, 0x0C0, 0x0C4, 0x0C8, 8, 2, 15,
+			     0x1C4, 18),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NPU_TOPS_SEL, "npu_tops_sel",
+			     npu_tops_parents, 0x0C0, 0x0C4, 0x0C8, 16, 1, 23,
+			     0x1C4, 19),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_SEL, "dramc_sel", sspxtp_parents,
+			     0x0C0, 0x0C4, 0x0C8, 24, 1, 31, 0x1C4, 20),
+	/* CLK_CFG_13 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
+			     dramc_md32_parents, 0x0D0, 0x0D4, 0x0D8, 0, 2, 7,
+			     0x1C4, 21),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel",
+			     sspxtp_parents, 0x0D0, 0x0D4, 0x0D8, 8, 1, 15,
+			     0x1C4, 22),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P0_SEL, "pextp_p0_sel",
+			     sspxtp_parents, 0x0D0, 0x0D4, 0x0D8, 16, 1, 23,
+			     0x1C4, 23),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P1_SEL, "pextp_p1_sel",
+			     sspxtp_parents, 0x0D0, 0x0D4, 0x0D8, 24, 1, 31,
+			     0x1C4, 24),
+	/* CLK_CFG_14 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P2_SEL, "pextp_p2_sel",
+			     sspxtp_parents, 0x0E0, 0x0E4, 0x0E8, 0, 1, 7,
+			     0x1C4, 25),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P3_SEL, "pextp_p3_sel",
+			     sspxtp_parents, 0x0E0, 0x0E4, 0x0E8, 8, 1, 15,
+			     0x1C4, 26),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel",
+			     da_xtp_glb_p0_parents, 0x0E0, 0x0E4, 0x0E8, 16, 1,
+			     23, 0x1C4, 27),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel",
+			     da_xtp_glb_p0_parents, 0x0E0, 0x0E4, 0x0E8, 24, 1,
+			     31, 0x1C4, 28),
+	/* CLK_CFG_15 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P2_SEL, "da_xtp_glb_p2_sel",
+			     da_xtp_glb_p0_parents, 0x0F0, 0x0F4, 0x0F8, 0, 1,
+			     7, 0x1C4, 29),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P3_SEL, "da_xtp_glb_p3_sel",
+			     da_xtp_glb_p0_parents, 0x0F0, 0x0F4, 0x0F8, 8, 1,
+			     15, 0x1C4, 30),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_CKM_SEL, "ckm_sel", sspxtp_parents, 0x0F0,
+			     0x0F4, 0x0F8, 16, 1, 23, 0x1C8, 0),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_SELM_XTAL_SEL, "da_selm_xtal_sel",
+			     sspxtp_parents, 0x0F0, 0x0F4, 0x0F8, 24, 1, 31,
+			     0x1C8, 1),
+	/* CLK_CFG_16 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_SEL, "pextp_sel", sspxtp_parents,
+			     0x0100, 0x104, 0x108, 0, 1, 7, 0x1C8, 2),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_TOPS_P2_26M_SEL, "tops_p2_26m_sel",
+			     sspxtp_parents, 0x0100, 0x104, 0x108, 8, 1, 15,
+			     0x1C8, 3),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_MCUSYS_BACKUP_625M_SEL,
+			     "mcusys_backup_625m_sel",
+			     mcusys_backup_625m_parents, 0x0100, 0x104, 0x108,
+			     16, 1, 23, 0x1C8, 4),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SYNC_250M_SEL,
+			     "netsys_sync_250m_sel", pcie_mbist_250m_parents,
+			     0x0100, 0x104, 0x108, 24, 1, 31, 0x1C8, 5),
+	/* CLK_CFG_17 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_MACSEC_SEL, "macsec_sel", macsec_parents,
+			     0x0110, 0x114, 0x118, 0, 2, 7, 0x1C8, 6),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_TOPS_400M_SEL,
+			     "netsys_tops_400m_sel", netsys_tops_400m_parents,
+			     0x0110, 0x114, 0x118, 8, 1, 15, 0x1C8, 7),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_PPEFB_250M_SEL,
+			     "netsys_ppefb_250m_sel", pcie_mbist_250m_parents,
+			     0x0110, 0x114, 0x118, 16, 1, 23, 0x1C8, 8),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_WARP_SEL, "netsys_warp_sel",
+			     netsys_parents, 0x0110, 0x114, 0x118, 24, 2, 31,
+			     0x1C8, 9),
+	/* CLK_CFG_18 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_MII_SEL, "eth_mii_sel", eth_mii_parents,
+			     0x0120, 0x124, 0x128, 0, 1, 7, 0x1C8, 10),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_CK_NPU_SEL_CM_TOPS_SEL,
+			     "ck_npu_sel_cm_tops_sel", netsys_2x_parents,
+			     0x0120, 0x124, 0x128, 8, 2, 15, 0x1C8, 11),
+};
+
+static const char *const infra_mux_uart0_parents[] __initconst = {
+	"infra_ck_f26m", "infra_uart_o0"
+};
+
+static const char *const infra_mux_uart1_parents[] __initconst = {
+	"infra_ck_f26m", "infra_uart_o1"
+};
+
+static const char *const infra_mux_uart2_parents[] __initconst = {
+	"infra_ck_f26m", "infra_uart_o2"
+};
+
+static const char *const infra_mux_spi0_parents[] __initconst = {
+	"infra_i2c_o", "infra_spi0_o"
+};
+
+static const char *const infra_mux_spi1_parents[] __initconst = {
+	"infra_i2c_o", "infra_spi1_o"
+};
+
+static const char *const infra_pwm_bck_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_66m_mck", "infra_pwm_o"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p0"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p1"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p2_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p2"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p3"
+};
+
+static const struct mtk_mux infra_muxes[] = {
+	/* MODULE_CLK_SEL_0 */
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
+			     infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
+			     infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
+			     infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel",
+			     infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 4,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel",
+			     infra_mux_spi1_parents, 0x0018, 0x0010, 0x0014, 5,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel",
+			     infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 6,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_SEL, "infra_pwm_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 14,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 16,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 18,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 20,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 22,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 24,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 26,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 28,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 30,
+			     2, -1, -1, -1),
+	/* MODULE_CLK_SEL_1 */
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P0_SEL,
+			     "infra_pcie_gfmux_tl_o_p0_sel",
+			     infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028,
+			     0x0020, 0x0024, 0, 2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P1_SEL,
+			     "infra_pcie_gfmux_tl_o_p1_sel",
+			     infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028,
+			     0x0020, 0x0024, 2, 2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P2_SEL,
+			     "infra_pcie_gfmux_tl_o_p2_sel",
+			     infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028,
+			     0x0020, 0x0024, 4, 2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P3_SEL,
+			     "infra_pcie_gfmux_tl_o_p3_sel",
+			     infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028,
+			     0x0020, 0x0024, 6, 2, -1, -1, -1),
+};
+
+static const struct mtk_clk_divider top_adj_divs[] = {
+	DIV_ADJ(CK_TOP_AUD_I2S_M, "aud_i2s_m", "aud", 0x0420, 8, 8),
+};
+
+static const struct mtk_gate_regs infra0_cg_regs = {
+	.set_ofs = 0x10,
+	.clr_ofs = 0x14,
+	.sta_ofs = 0x18,
+};
+
+static const struct mtk_gate_regs infra1_cg_regs = {
+	.set_ofs = 0x40,
+	.clr_ofs = 0x44,
+	.sta_ofs = 0x48,
+};
+
+static const struct mtk_gate_regs infra2_cg_regs = {
+	.set_ofs = 0x50,
+	.clr_ofs = 0x54,
+	.sta_ofs = 0x58,
+};
+
+static const struct mtk_gate_regs infra3_cg_regs = {
+	.set_ofs = 0x60,
+	.clr_ofs = 0x64,
+	.sta_ofs = 0x68,
+};
+
+#define GATE_INFRA0(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra0_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+#define GATE_INFRA1(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra1_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+#define GATE_INFRA2(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra2_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+#define GATE_INFRA3(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra3_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+static const struct mtk_gate infra_clks[] __initconst = {
+	/* INFRA0 */
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P0,
+		    "infra_pcie_peri_ck_26m_ck_p0", "infra_f26m_o0", 7),
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P1,
+		    "infra_pcie_peri_ck_26m_ck_p1", "infra_f26m_o0", 8),
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P2,
+		    "infra_pcie_peri_ck_26m_ck_p2", "infra_f26m_o0", 9),
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P3,
+		    "infra_pcie_peri_ck_26m_ck_p3", "infra_f26m_o0", 10),
+	/* INFRA1 */
+	GATE_INFRA1(CK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck",
+		    "infra_66m_mck", 0),
+	GATE_INFRA1(CK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck",
+		    "infra_66m_mck", 1),
+	GATE_INFRA1(CK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck",
+		    "infra_pwm_sel", 2),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK1, "infra_hf_66m_pwm_ck1",
+		    "infra_pwm_ck1_sel", 3),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK2, "infra_hf_66m_pwm_ck2",
+		    "infra_pwm_ck2_sel", 4),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK3, "infra_hf_66m_pwm_ck3",
+		    "infra_pwm_ck3_sel", 5),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK4, "infra_hf_66m_pwm_ck4",
+		    "infra_pwm_ck4_sel", 6),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK5, "infra_hf_66m_pwm_ck5",
+		    "infra_pwm_ck5_sel", 7),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK6, "infra_hf_66m_pwm_ck6",
+		    "infra_pwm_ck6_sel", 8),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK7, "infra_hf_66m_pwm_ck7",
+		    "infra_pwm_ck7_sel", 9),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK8, "infra_hf_66m_pwm_ck8",
+		    "infra_pwm_ck8_sel", 10),
+	GATE_INFRA1(CK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck",
+		    "infra_133m_mck", 12),
+	GATE_INFRA1(CK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck",
+		    "infra_66m_phck", 13),
+	GATE_INFRA1(CK_INFRA_AUD_26M, "infra_f_faud_26m", "infra_ck_f26m", 14),
+	GATE_INFRA1(CK_INFRA_AUD_L, "infra_f_faud_l", "infra_faud_l_o", 15),
+	GATE_INFRA1(CK_INFRA_AUD_AUD, "infra_f_aud_aud", "infra_faud_aud_o",
+		    16),
+	GATE_INFRA1(CK_INFRA_AUD_EG2, "infra_f_faud_eg2", "infra_faud_eg2_o",
+		    18),
+	GATE_INFRA1(CK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "infra_ck_f26m",
+		    19),
+	GATE_INFRA1(CK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm",
+		    "infra_133m_mck", 20),
+	GATE_INFRA1(CK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck",
+		    "infra_66m_mck", 21),
+	GATE_INFRA1(CK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck",
+		    "infra_66m_mck", 29),
+	GATE_INFRA1(CK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m",
+		    "infra_ck_f26m", 30),
+	GATE_INFRA1(CK_INFRA_66M_TRNG, "infra_hf_66m_trng", "infra_peri_66m_o",
+		    31),
+	/* INFRA2 */
+	GATE_INFRA2(CK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system",
+		    "infra_ck_f26m", 0),
+	GATE_INFRA2(CK_INFRA_I2C_BCK, "infra_i2c_bck", "infra_i2c_o", 1),
+	GATE_INFRA2(CK_INFRA_66M_UART0_PCK, "infra_hf_66m_uart0_pck",
+		    "infra_66m_mck", 3),
+	GATE_INFRA2(CK_INFRA_66M_UART1_PCK, "infra_hf_66m_uart1_pck",
+		    "infra_66m_mck", 4),
+	GATE_INFRA2(CK_INFRA_66M_UART2_PCK, "infra_hf_66m_uart2_pck",
+		    "infra_66m_mck", 5),
+	GATE_INFRA2(CK_INFRA_52M_UART0_CK, "infra_f_52m_uart0",
+		    "infra_mux_uart0_sel", 3),
+	GATE_INFRA2(CK_INFRA_52M_UART1_CK, "infra_f_52m_uart1",
+		    "infra_mux_uart1_sel", 4),
+	GATE_INFRA2(CK_INFRA_52M_UART2_CK, "infra_f_52m_uart2",
+		    "infra_mux_uart2_sel", 5),
+	GATE_INFRA2(CK_INFRA_NFI, "infra_f_fnfi", "infra_nfi_o", 9),
+	GATE_INFRA2(CK_INFRA_SPINFI, "infra_f_fspinfi", "infra_spinfi_o", 10),
+	GATE_INFRA2(CK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck",
+		    "infra_66m_mck", 11),
+	GATE_INFRA2(CK_INFRA_104M_SPI0, "infra_hf_104m_spi0",
+		    "infra_mux_spi0_sel", 12),
+	GATE_INFRA2(CK_INFRA_104M_SPI1, "infra_hf_104m_spi1",
+		    "infra_mux_spi1_sel", 13),
+	GATE_INFRA2(CK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck",
+		    "infra_mux_spi2_sel", 14),
+	GATE_INFRA2(CK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck",
+		    "infra_66m_mck", 15),
+	GATE_INFRA2(CK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck",
+		    "infra_66m_mck", 16),
+	GATE_INFRA2(CK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck",
+		    "infra_66m_mck", 17),
+	GATE_INFRA2(CK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi",
+		    "infra_66m_mck", 18),
+	GATE_INFRA2(CK_INFRA_RTC, "infra_f_frtc", "infra_lb_mux_frtc", 19),
+	GATE_INFRA2(CK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck",
+		    "infra_f26m_o1", 20),
+	GATE_INFRA2(CK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck",
+		    21),
+	GATE_INFRA2(CK_INFRA_MSDC400, "infra_f_fmsdc400", "infra_fmsdc400_o",
+		    22),
+	GATE_INFRA2(CK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck",
+		    "infra_fmsdc2_hck_occ", 23),
+	GATE_INFRA2(CK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck",
+		    "infra_peri_133m", 24),
+	GATE_INFRA2(CK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck",
+		    "infra_66m_phck", 25),
+	GATE_INFRA2(CK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck",
+		    "infra_133m_mck", 26),
+	GATE_INFRA2(CK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "infra_nfi_o", 27),
+	GATE_INFRA2(CK_INFRA_I2C_X16W_MCK_CK_P1, "infra_hf_i2c_x16w_mck_ck_p1",
+		    "infra_133m_mck", 29),
+	GATE_INFRA2(CK_INFRA_I2C_X16W_PCK_CK_P1, "infra_hf_i2c_x16w_pck_ck_p1",
+		    "infra_66m_phck", 31),
+	/* INFRA3 */
+	GATE_INFRA3(CK_INFRA_133M_USB_HCK, "infra_133m_usb_hck",
+		    "infra_133m_phck", 0),
+	GATE_INFRA3(CK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1",
+		    "infra_133m_phck", 1),
+	GATE_INFRA3(CK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "infra_66m_phck",
+		    2),
+	GATE_INFRA3(CK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1",
+		    "infra_66m_phck", 3),
+	GATE_INFRA3(CK_INFRA_USB_SYS, "infra_usb_sys", "infra_usb_sys_o", 4),
+	GATE_INFRA3(CK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1",
+		    "infra_usb_sys_o_p1", 5),
+	GATE_INFRA3(CK_INFRA_USB_REF, "infra_usb_ref", "infra_usb_o", 6),
+	GATE_INFRA3(CK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "infra_usb_o_p1", 7),
+	GATE_INFRA3(CK_INFRA_USB_FRMCNT, "infra_usb_frmcnt",
+		    "infra_usb_frmcnt_o", 8),
+	GATE_INFRA3(CK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1",
+		    "infra_usb_frmcnt_o_p1", 9),
+	GATE_INFRA3(CK_INFRA_USB_PIPE, "infra_usb_pipe", "infra_usb_pipe_o",
+		    10),
+	GATE_INFRA3(CK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1",
+		    "infra_usb_pipe_o_p1", 11),
+	GATE_INFRA3(CK_INFRA_USB_UTMI, "infra_usb_utmi", "infra_usb_utmi_o",
+		    12),
+	GATE_INFRA3(CK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1",
+		    "infra_usb_utmi_o_p1", 13),
+	GATE_INFRA3(CK_INFRA_USB_XHCI, "infra_usb_xhci", "infra_usb_xhci_o",
+		    14),
+	GATE_INFRA3(CK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1",
+		    "infra_usb_xhci_o_p1", 15),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0",
+		    "infra_pcie_gfmux_tl_o_p0_sel", 20),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1",
+		    "infra_pcie_gfmux_tl_o_p1_sel", 21),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P2, "infra_pcie_gfmux_tl_ck_p2",
+		    "infra_pcie_gfmux_tl_o_p2_sel", 22),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P3, "infra_pcie_gfmux_tl_ck_p3",
+		    "infra_pcie_gfmux_tl_o_p3_sel", 23),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0",
+		    "infra_pcie_pipe_ck_occ_p0", 24),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1",
+		    "infra_pcie_pipe_ck_occ_p1", 25),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P2, "infra_pcie_pipe_ck_p2",
+		    "infra_pcie_pipe_ck_occ_p2", 26),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P3, "infra_pcie_pipe_ck_p3",
+		    "infra_pcie_pipe_ck_occ_p3", 27),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0",
+		    "infra_133m_phck", 28),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1",
+		    "infra_133m_phck", 29),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P2, "infra_133m_pcie_ck_p2",
+		    "infra_133m_phck", 30),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3",
+		    "infra_133m_phck", 31),
+};
+
+static const struct mtk_gate_regs sgmii0_cg_regs = {
+	.set_ofs = 0xE4,
+	.clr_ofs = 0xE4,
+	.sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII0(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &sgmii0_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate sgmii0_clks[] __initconst = {
+	GATE_SGMII0(CK_SGM0_TX_EN, "sgm0_tx_en", "clkxtal", 2),
+	GATE_SGMII0(CK_SGM0_RX_EN, "sgm0_rx_en", "clkxtal", 3),
+};
+
+static const struct mtk_gate_regs sgmii1_cg_regs = {
+	.set_ofs = 0xE4,
+	.clr_ofs = 0xE4,
+	.sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII1(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &sgmii1_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate sgmii1_clks[] __initconst = {
+	GATE_SGMII1(CK_SGM1_TX_EN, "sgm1_tx_en", "clkxtal", 2),
+	GATE_SGMII1(CK_SGM1_RX_EN, "sgm1_rx_en", "clkxtal", 3),
+};
+
+static const struct mtk_gate_regs ethdma_cg_regs = {
+	.set_ofs = 0x30,
+	.clr_ofs = 0x30,
+	.sta_ofs = 0x30,
+};
+
+#define GATE_ETHDMA(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &ethdma_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate ethdma_clks[] __initconst = {
+	GATE_ETHDMA(CK_ETHDMA_XGP1_EN, "ethdma_xgp1_en", "clkxtal", 0),
+	GATE_ETHDMA(CK_ETHDMA_XGP2_EN, "ethdma_xgp2_en", "clkxtal", 1),
+	GATE_ETHDMA(CK_ETHDMA_XGP3_EN, "ethdma_xgp3_en", "clkxtal", 2),
+	GATE_ETHDMA(CK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x", 6),
+	GATE_ETHDMA(CK_ETHDMA_GP2_EN, "ethdma_gp2_en", "clkxtal", 7),
+	GATE_ETHDMA(CK_ETHDMA_GP1_EN, "ethdma_gp1_en", "clkxtal", 8),
+	GATE_ETHDMA(CK_ETHDMA_GP3_EN, "ethdma_gp3_en", "clkxtal", 10),
+	GATE_ETHDMA(CK_ETHDMA_ESW_EN, "ethdma_esw_en", "netsys_gsw", 16),
+	GATE_ETHDMA(CK_ETHDMA_CRYPT0_EN, "ethdma_crypt0_en", "eip197", 29),
+};
+
+static const struct mtk_gate_regs ethwarp_cg_regs = {
+	.set_ofs = 0x14,
+	.clr_ofs = 0x14,
+	.sta_ofs = 0x14,
+};
+
+#define GATE_ETHWARP(_id, _name, _parent, _shift)                              \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &ethwarp_cg_regs, .shift = _shift,                     \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate ethwarp_clks[] __initconst = {
+	GATE_ETHWARP(CK_ETHWARP_WOCPU2_EN, "ethwarp_wocpu2_en",
+		     "netsys_wed_mcu", 13),
+	GATE_ETHWARP(CK_ETHWARP_WOCPU1_EN, "ethwarp_wocpu1_en",
+		     "netsys_wed_mcu", 14),
+	GATE_ETHWARP(CK_ETHWARP_WOCPU0_EN, "ethwarp_wocpu0_en",
+		     "netsys_wed_mcu", 15),
+};
+
+#define MT7988_PLL_FMAX	     (2500UL * MHZ)
+#define MT7988_PCW_CHG_SHIFT 2
+
+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask,     \
+	      _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg,         \
+	      _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, _div_table,   \
+	      _parent_name)                                                    \
+	{                                                                      \
+		.id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg,    \
+		.en_mask = _en_mask, .flags = _flags,                          \
+		.rst_bar_mask = BIT(_rst_bar_mask), .fmax = MT7988_PLL_FMAX,   \
+		.pcwbits = _pcwbits, .pd_reg = _pd_reg, .pd_shift = _pd_shift, \
+		.tuner_reg = _tuner_reg, .tuner_en_reg = _tuner_en_reg,        \
+		.tuner_en_bit = _tuner_en_bit, .pcw_reg = _pcw_reg,            \
+		.pcw_shift = _pcw_shift, .pcw_chg_reg = _pcw_chg_reg,          \
+		.pcw_chg_shift = MT7988_PCW_CHG_SHIFT,                         \
+		.div_table = _div_table, .parent_name = _parent_name,          \
+	}
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask,       \
+	    _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg,           \
+	    _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, _parent_name)   \
+	PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask,     \
+	      _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg,         \
+	      _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, NULL,         \
+	      _parent_name)
+
+static const struct mtk_pll_data plls[] = {
+	PLL(CK_APMIXED_NETSYSPLL, "netsyspll", 0x0104, 0x0110, 0x00000001, 0, 0,
+	    32, 0x0104, 4, 0, 0, 0, 0x0108, 0, 0x0104, "clkxtal"),
+	PLL(CK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR,
+	    23, 32, 0x0114, 4, 0, 0, 0, 0x0118, 0, 0x0114, "clkxtal"),
+	PLL(CK_APMIXED_MMPLL, "mmpll", 0x0124, 0x0130, 0xff000001, HAVE_RST_BAR,
+	    23, 32, 0x0124, 4, 0, 0, 0, 0x0128, 0, 0x0124, "clkxtal"),
+	PLL(CK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32,
+	    0x0134, 4, 0x0704, 0x0700, 1, 0x0138, 0, 0x0134, "clkxtal"),
+	PLL(CK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144,
+	    "clkxtal"),
+	PLL(CK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0154, 4, 0, 0, 0, 0x0158, 0, 0x0154,
+	    "clkxtal"),
+	PLL(CK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, 0,
+	    32, 0x0164, 4, 0, 0, 0, 0x0168, 0, 0x0164, "clkxtal"),
+	PLL(CK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32,
+	    0x0174, 4, 0, 0, 0, 0x0178, 0, 0x0174, "clkxtal"),
+	PLL(CK_APMIXED_ARM_B, "arm_b", 0x0204, 0x0210, 0xff000001, HAVE_RST_BAR,
+	    23, 32, 0x0204, 4, 0, 0, 0, 0x0208, 0, 0x0204, "clkxtal"),
+	PLL(CK_APMIXED_CCIPLL2_B, "ccipll2_b", 0x0214, 0x0220, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0214, 4, 0, 0, 0, 0x0218, 0, 0x0214,
+	    "clkxtal"),
+	PLL(CK_APMIXED_USXGMIIPLL, "usxgmiipll", 0x0304, 0x0310, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0304, 4, 0, 0, 0, 0x0308, 0, 0x0304,
+	    "clkxtal"),
+	PLL(CK_APMIXED_MSDCPLL, "msdcpll", 0x0314, 0x0320, 0x00000001, 0, 0, 32,
+	    0x0314, 4, 0, 0, 0, 0x0318, 0, 0x0314, "clkxtal"),
+};
+
+static struct clk_onecell_data *mt7988_top_clk_data __initdata;
+static struct clk_onecell_data *mt7988_pll_clk_data __initdata;
+
+static void __init mtk_clk_enable_critical(void)
+{
+	if (!mt7988_top_clk_data || !mt7988_pll_clk_data)
+		return;
+
+	clk_prepare_enable(mt7988_pll_clk_data->clks[CK_APMIXED_ARM_B]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_SYSAXI_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_SYSAPB_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_DRAMC_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_DRAMC_MD32_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_INFRA_F26M_SEL]);
+}
+
+static void __init mtk_infracfg_init(struct device_node *node)
+{
+	int r;
+
+	mt7988_top_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+
+	mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs),
+				 mt7988_top_clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get,
+				mt7988_top_clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+
+	mtk_clk_enable_critical();
+}
+CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt7988-infracfg", mtk_infracfg_init);
+
+static void __init mtk_topckgen_init(struct device_node *node)
+{
+	int r;
+	void __iomem *base;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s(): ioremap failed\n", __func__);
+		return;
+	}
+
+	mt7988_top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+
+	mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
+				 mt7988_top_clk_data);
+	mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
+			       &mt7988_clk_lock, mt7988_top_clk_data);
+	mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
+				  &mt7988_clk_lock, mt7988_top_clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get,
+				mt7988_top_clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+
+	mtk_clk_enable_critical();
+}
+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt7988-topckgen", mtk_topckgen_init);
+
+static void __init mtk_infracfg_ao_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+	void __iomem *base;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s(): ioremap failed\n", __func__);
+		return;
+	}
+
+	clk_data = mtk_alloc_clk_data(CLK_INFRA_AO_NR_CLK);
+
+	mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node,
+			       &mt7988_clk_lock, clk_data);
+	mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_infracfg_ao, "mediatek,mt7988-infracfg_ao",
+	       mtk_infracfg_ao_init);
+
+static void __init mtk_apmixedsys_init(struct device_node *node)
+{
+	int r;
+
+	mt7988_pll_clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+
+	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
+			      mt7988_pll_clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get,
+				mt7988_pll_clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+
+	mtk_clk_enable_critical();
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt7988-apmixedsys",
+	       mtk_apmixedsys_init);
+
+static void __init mtk_mcusys_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+	void __iomem *base;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s(): ioremap failed\n", __func__);
+		return;
+	}
+
+	clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK);
+	mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base,
+				    &mt7988_clk_lock, clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_mcusys, "mediatek,mt7988-mcusys", mtk_mcusys_init);
+
+static void __init mtk_sgmiisys_0_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_SGMII0_NR_CLK);
+
+	mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7988-sgmiisys_0",
+	       mtk_sgmiisys_0_init);
+
+static void __init mtk_sgmiisys_1_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_SGMII1_NR_CLK);
+
+	mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7988-sgmiisys_1",
+	       mtk_sgmiisys_1_init);
+
+static void __init mtk_ethdma_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_ETHDMA_NR_CLK);
+
+	mtk_clk_register_gates(node, ethdma_clks, ARRAY_SIZE(ethdma_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_ethdma, "mediatek,mt7988-ethsys", mtk_ethdma_init);
+
+static void __init mtk_ethwarp_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_ETHWARP_NR_CLK);
+
+	mtk_clk_register_gates(node, ethwarp_clks, ARRAY_SIZE(ethwarp_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_ethwarp, "mediatek,mt7988-ethwarp", mtk_ethwarp_init);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c
new file mode 100644
index 0000000..251a412
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+
+#define MEDAITEK_2P5GE_PHY_DMB_FW "mediatek-2p5ge-phy-dmb.bin"
+#define MEDIATEK_2P5GE_PHY_PMB_FW "mediatek-2p5ge-phy-pmb.bin"
+
+#define MD32_EN_CFG	0x18
+#define   MD32_EN	BIT(0)
+
+static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
+{
+	int ret;
+	int i;
+	const struct firmware *fw;
+	struct device *dev = &phydev->mdio.dev;
+	struct device_node *np;
+	void __iomem *dmb_addr;
+	void __iomem *pmb_addr;
+	void __iomem *mcucsr_base;
+	u16 reg;
+
+	np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
+	if (!np)
+		return -ENOENT;
+
+	dmb_addr = of_iomap(np, 0);
+	if (!dmb_addr)
+		return -ENOMEM;
+	pmb_addr = of_iomap(np, 1);
+	if (!pmb_addr)
+		return -ENOMEM;
+	mcucsr_base = of_iomap(np, 2);
+	if (!mcucsr_base)
+		return -ENOMEM;
+
+	ret = request_firmware(&fw, MEDAITEK_2P5GE_PHY_DMB_FW, dev);
+	if (ret) {
+		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
+			MEDAITEK_2P5GE_PHY_DMB_FW, ret);
+		return ret;
+	}
+	for (i = 0; i < fw->size - 1; i += 4)
+		writel(*((uint32_t *)(fw->data + i)), dmb_addr + i);
+	release_firmware(fw);
+
+	ret = request_firmware(&fw, MEDIATEK_2P5GE_PHY_PMB_FW, dev);
+	if (ret) {
+		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
+			MEDIATEK_2P5GE_PHY_PMB_FW, ret);
+		return ret;
+	}
+	for (i = 0; i < fw->size - 1; i += 4)
+		writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
+	release_firmware(fw);
+
+	reg = readw(mcucsr_base + MD32_EN_CFG);
+	writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG);
+	dev_info(dev, "Firmware loading/trigger ok.\n");
+
+	return 0;
+}
+
+static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = genphy_read_abilities(phydev);
+	if (ret)
+		return ret;
+
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
+
+	return 0;
+}
+
+static struct phy_driver mtk_gephy_driver[] = {
+	{
+		PHY_ID_MATCH_EXACT(0x00339c11),
+		.name		= "MediaTek MT798x 2.5GbE PHY",
+		.config_init	= mt798x_2p5ge_phy_config_init,
+		.config_aneg    = genphy_c45_config_aneg,
+		.get_features	= mt798x_2p5ge_phy_get_features,
+		//.config_intr	= genphy_no_config_intr,
+		//.handle_interrupt = genphy_no_ack_interrupt,
+		//.suspend	= genphy_suspend,
+		//.resume		= genphy_resume,
+	},
+};
+
+module_phy_driver(mtk_gephy_driver);
+
+static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
+	{ PHY_ID_MATCH_VENDOR(0x00339c00) },
+	{ }
+};
+
+MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
+MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile
old mode 100755
new mode 100644
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c
old mode 100755
new mode 100644
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
index 7253042..854a586 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
@@ -7,6 +7,10 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/hrtimer.h>
+#include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of_address.h>
 
 #include "mt753x.h"
 #include "mt753x_regs.h"
@@ -682,6 +686,24 @@
 	return -ENODEV;
 }
 
+static int mt7988_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev)
+{
+	const char *model;
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "mediatek,mt7988-switch");
+	if (!np)
+		return -ENODEV;
+
+	of_node_put(np);
+
+	crev->rev = 0;
+	crev->name = "MT7988";
+	gsw->direct_access = true;
+
+	return 0;
+}
+
 static void pinmux_set_mux_7531(struct gsw_mt753x *gsw, u32 pin, u32 mode)
 {
 	u32 val;
@@ -810,7 +832,8 @@
 	u32 val;
 
 	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		mt7531_phy_100m_eye_diag_setting(gsw, i);
+		if (!gsw->direct_access)
+			mt7531_phy_100m_eye_diag_setting(gsw, i);
 
 		/* Enable HW auto downshift */
 		gsw->mii_write(gsw, i, 0x1f, 0x1);
@@ -834,10 +857,14 @@
 		val |= PHY_LINKDOWN_POWER_SAVING_EN;
 		gsw->mii_write(gsw, i, PHY_EXT_REG_17, val);
 
-		val = gsw->mmd_read(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6);
-		val &= ~PHY_POWER_SAVING_M;
-		val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
-		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6, val);
+		if (!gsw->direct_access) {
+			val = gsw->mmd_read(gsw, i, PHY_DEV1E,
+					    PHY_DEV1E_REG_0C6);
+			val &= ~PHY_POWER_SAVING_M;
+			val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
+			gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6,
+				       val);
+		}
 
 		/* Timing Recovery for GbE slave mode */
 		mt753x_tr_write(gsw, i, PMA_CH, PMA_NOD, PMA_01, 0x6fb90a);
@@ -952,7 +979,8 @@
 	gsw->mmd_read = mt753x_mmd_read;
 	gsw->mmd_write = mt753x_mmd_write;
 
-	gsw->hw_phy_cal = of_property_read_bool(gsw->dev->of_node, "mediatek,hw_phy_cal");
+	gsw->hw_phy_cal = of_property_read_bool(gsw->dev->of_node,
+						"mediatek,hw_phy_cal");
 
 	for (i = 0; i < MT753X_NUM_PHYS; i++) {
 		val = gsw->mii_read(gsw, i, MII_BMCR);
@@ -966,7 +994,7 @@
 
 	/* Switch soft reset */
 	mt753x_reg_write(gsw, SYS_CTRL, SW_SYS_RST | SW_REG_RST);
-	usleep_range(10, 20);
+	udelay(20);
 
 	/* Enable MDC input Schmitt Trigger */
 	val = mt753x_reg_read(gsw, SMT0_IOLB);
@@ -976,6 +1004,7 @@
 	mt7531_set_gpio_pinmux(gsw);
 
 	mt7531_core_pll_setup(gsw);
+
 	mt7531_mac_port_setup(gsw, 5, &gsw->port5_cfg);
 	mt7531_mac_port_setup(gsw, 6, &gsw->port6_cfg);
 
@@ -999,6 +1028,89 @@
 	return 0;
 }
 
+static int mt7988_sw_init(struct gsw_mt753x *gsw)
+{
+	struct device_node *switch_node = NULL;
+	struct platform_device *pdev;
+	int i;
+	u32 val;
+	u32 pmcr;
+	u32 speed;
+
+	switch_node = of_find_node_by_name(NULL, "switch0");
+	if (switch_node == NULL) {
+		dev_err(&pdev->dev, "switch node invaild\n");
+		return -ENOENT;
+	}
+
+	gsw->base = of_iomap(switch_node, 0);
+	if (IS_ERR(gsw->base)) {
+		dev_err(&pdev->dev, "switch ioremap failed\n");
+		return -EIO;
+	}
+
+	pdev = container_of(gsw->dev, struct platform_device, dev);
+	gsw->sysctrl_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							"mediatek,sysctrl");
+	if (IS_ERR(gsw->sysctrl_base)) {
+		dev_err(&pdev->dev, "no sysctl regmap found\n");
+		return -ENODEV;
+	}
+
+	/* reset control */
+	regmap_write(gsw->sysctrl_base, ETH_RESET, 0x200);
+	udelay(20);
+	regmap_write(gsw->sysctrl_base, ETH_RESET, 0);
+	udelay(20);
+
+	gsw->phy_base = (gsw->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
+
+	gsw->mii_read = mt753x_mii_read;
+	gsw->mii_write = mt753x_mii_write;
+	gsw->mmd_read = mt753x_mmd_read;
+	gsw->mmd_write = mt753x_mmd_write;
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val |= BMCR_ISOLATE;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	speed = MAC_SPD_1000;
+	pmcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+		MAC_MODE | MAC_TX_EN | MAC_RX_EN | BKOFF_EN |
+		BACKPR_EN | FORCE_MODE_LNK | FORCE_LINK | FORCE_MODE_SPD |
+		FORCE_MODE_DPX | FORCE_MODE_RX_FC | FORCE_MODE_TX_FC |
+		FORCE_RX_FC | FORCE_TX_FC | (speed << FORCE_SPD_S) | FORCE_DPX;
+
+	mt753x_reg_write(gsw, PMCR(6), pmcr);
+
+	/* Global mac control settings */
+	mt753x_reg_write(gsw, GMACCR,
+			 (15 << MTCC_LMT_S) | (15 << MAX_RX_JUMBO_S) |
+			 RX_PKT_LEN_MAX_JUMBO);
+
+	/* Enable Collision Poll */
+	val = mt753x_reg_read(gsw, CPGC_CTRL);
+	val |= COL_CLK_EN;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+	val |= COL_RST_N;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+	val |= COL_EN;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+
+	/* Disable AFIFO reset for extra short IPG */
+	mt7531_afifo_reset(gsw, 0);
+
+	/* PHY force slave 1G*/
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		gsw->mii_write(gsw, i, MII_CTRL1000, 0x1200);
+		gsw->mii_write(gsw, i, MII_BMCR, 0x140);
+	}
+
+	return 0;
+}
+
 static int mt7531_sw_post_init(struct gsw_mt753x *gsw)
 {
 	int i;
@@ -1016,7 +1128,8 @@
 	val |= POWER_ON_OFF;
 	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
 
-	mt7531_phy_pll_setup(gsw);
+	if (!gsw->direct_access)
+		mt7531_phy_pll_setup(gsw);
 
 	/* Enable Internal PHYs before phy setting */
 	val = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403);
@@ -1041,7 +1154,14 @@
 	for (i = 0; i < MT753X_NUM_PHYS; i++)
 		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_141, 0x0);
 
-	mt7531_internal_phy_calibration(gsw);
+	if (!gsw->direct_access)
+		mt7531_internal_phy_calibration(gsw);
+
+	/* PHY force slave disable, restart AN*/
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		gsw->mii_write(gsw, i, MII_CTRL1000, 0x200);
+		gsw->mii_write(gsw, i, MII_BMCR, 0x1240);
+	}
 
 	return 0;
 }
@@ -1053,6 +1173,13 @@
 	.post_init = mt7531_sw_post_init
 };
 
+struct mt753x_sw_id mt7988_id = {
+	.model = MT7988,
+	.detect = mt7988_sw_detect,
+	.init = mt7988_sw_init,
+	.post_init = mt7531_sw_post_init
+};
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Zhanguo Ju <zhanguo.ju@mediatek.com>");
 MODULE_DESCRIPTION("Driver for MediaTek MT753x Gigabit Switch");
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
new file mode 100644
index 0000000..2167722
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ */
+#ifndef _MT7531_H_
+#define _MT7531_H_
+#include "mt753x.h"
+extern struct mt753x_sw_id mt7531_id;
+extern struct mt753x_sw_id mt7988_id;
+#endif /* _MT7531_H_ */
+
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
old mode 100755
new mode 100644
index 732bda1..344d2b0
--- a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
@@ -13,6 +13,7 @@
 #include <linux/of_mdio.h>
 #include <linux/workqueue.h>
 #include <linux/gpio/consumer.h>
+#include <linux/phy.h>
 
 #ifdef CONFIG_SWCONFIG
 #include <linux/switch.h>
@@ -30,12 +31,13 @@
 
 enum mt753x_model {
 	MT7530 = 0x7530,
-	MT7531 = 0x7531
+	MT7531 = 0x7531,
+	MT7988 = 0x7988,
 };
 
 struct mt753x_port_cfg {
 	struct device_node *np;
-	int phy_mode;
+	phy_interface_t phy_mode;
 	u32 enabled: 1;
 	u32 force_link: 1;
 	u32 speed: 2;
@@ -60,6 +62,10 @@
 	u32 smi_addr;
 	u32 phy_base;
 	int direct_phy_access;
+	bool direct_access;
+
+	void __iomem *base;
+	struct regmap *sysctrl_base;
 
 	enum mt753x_model model;
 	const char *name;
@@ -70,7 +76,7 @@
 	bool hw_phy_cal;
 	bool phy_status_poll;
 	struct mt753x_phy phys[MT753X_NUM_PHYS];
-//	int phy_irqs[PHY_MAX_ADDR]; //FIXME 
+//	int phy_irqs[PHY_MAX_ADDR]; //FIXME
 
 	int phy_link_sts;
 
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
old mode 100755
new mode 100644
index 3639df1..c57a5a2
--- a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
@@ -33,19 +33,24 @@
 static struct mt753x_sw_id *mt753x_sw_ids[] = {
 	&mt7530_id,
 	&mt7531_id,
+	&mt7988_id,
 };
 
 u32 mt753x_reg_read(struct gsw_mt753x *gsw, u32 reg)
 {
 	u32 high, low;
 
-	mutex_lock(&gsw->host_bus->mdio_lock);
+	if (gsw->direct_access)
+		return __raw_readl(gsw->base + reg);
 
+	mutex_lock(&gsw->host_bus->mdio_lock);
 	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
-		(reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S);
+			     (reg & MT753X_REG_PAGE_ADDR_M) >>
+				     MT753X_REG_PAGE_ADDR_S);
 
 	low = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr,
-		(reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S);
+				  (reg & MT753X_REG_ADDR_M) >>
+					  MT753X_REG_ADDR_S);
 
 	high = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x10);
 
@@ -56,17 +61,24 @@
 
 void mt753x_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val)
 {
-	mutex_lock(&gsw->host_bus->mdio_lock);
-
-	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
-		(reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S);
+	if (gsw->direct_access) {
+		__raw_writel(val, gsw->base + reg);
+	} else {
+		mutex_lock(&gsw->host_bus->mdio_lock);
+		gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
+				     (reg & MT753X_REG_PAGE_ADDR_M) >>
+					     MT753X_REG_PAGE_ADDR_S);
 
-	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr,
-		(reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S, val & 0xffff);
+		gsw->host_bus->write(gsw->host_bus, gsw->smi_addr,
+				     (reg & MT753X_REG_ADDR_M) >>
+					     MT753X_REG_ADDR_S,
+				     val & 0xffff);
 
-	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, val >> 16);
+		gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10,
+				     val >> 16);
 
-	mutex_unlock(&gsw->host_bus->mdio_lock);
+		mutex_unlock(&gsw->host_bus->mdio_lock);
+	}
 }
 
 /* Indirect MDIO clause 22/45 access */
@@ -89,8 +101,7 @@
 			return -ETIMEDOUT;
 	}
 
-	val = (st << MDIO_ST_S) |
-	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+	val = (st << MDIO_ST_S) | ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
 	      ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
 	      ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
 
@@ -182,19 +193,19 @@
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_ADDR << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg,
-		      MDIO_CMD_WRITE, MDIO_ST_C22);
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg, MDIO_CMD_WRITE,
+		      MDIO_ST_C22);
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_DATA << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	val = mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, 0,
-			    MDIO_CMD_READ, MDIO_ST_C22);
+	val = mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, 0, MDIO_CMD_READ,
+			    MDIO_ST_C22);
 
 	mutex_unlock(&gsw->mii_lock);
 
@@ -211,19 +222,19 @@
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_ADDR << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg,
-		      MDIO_CMD_WRITE, MDIO_ST_C22);
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg, MDIO_CMD_WRITE,
+		      MDIO_ST_C22);
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_DATA << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, val,
-		      MDIO_CMD_WRITE, MDIO_ST_C22);
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, val, MDIO_CMD_WRITE,
+		      MDIO_ST_C22);
 
 	mutex_unlock(&gsw->mii_lock);
 }
@@ -239,6 +250,7 @@
 	struct device_node *fixed_link_node;
 	struct mt753x_port_cfg *port_cfg;
 	u32 port;
+	int ret;
 
 	for_each_child_of_node(gsw->dev->of_node, port_np) {
 		if (!of_device_is_compatible(port_np, "mediatek,mt753x-port"))
@@ -269,8 +281,8 @@
 
 		port_cfg->np = port_np;
 
-		port_cfg->phy_mode = of_get_phy_mode(port_np);
-		if (port_cfg->phy_mode < 0) {
+		ret = of_get_phy_mode(port_cfg->np);
+		if (ret < 0) {
 			dev_info(gsw->dev, "incorrect phy-mode %d\n", port);
 			continue;
 		}
@@ -303,6 +315,7 @@
 			case 2500:
 				port_cfg->speed = MAC_SPD_2500;
 				break;
+
 			default:
 				dev_info(gsw->dev, "incorrect speed %d\n",
 					 speed);
@@ -310,10 +323,10 @@
 			}
 		}
 
-		port_cfg->ssc_on = of_property_read_bool(port_cfg->np,
-							 "mediatek,ssc-on");
-		port_cfg->stag_on = of_property_read_bool(port_cfg->np,
-							  "mediatek,stag-on");
+		port_cfg->ssc_on =
+			of_property_read_bool(port_cfg->np, "mediatek,ssc-on");
+		port_cfg->stag_on =
+			of_property_read_bool(port_cfg->np, "mediatek,stag-on");
 		port_cfg->enabled = 1;
 	}
 }
@@ -438,7 +451,6 @@
 	mutex_unlock(&mt753x_devs_lock);
 }
 
-
 struct gsw_mt753x *mt753x_get_gsw(u32 id)
 {
 	struct gsw_mt753x *dev;
@@ -505,8 +517,8 @@
 
 	gsw->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
 	if (gsw->reset_pin < 0) {
-		dev_err(gsw->dev, "Missing reset pin of switch\n");
-		return ret;
+		dev_info(gsw->dev, "No reset pin of switch\n");
+		return 0;
 	}
 
 	ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mt753x-reset");
@@ -523,7 +535,7 @@
 
 	return 0;
 }
-#if 1 //XDXDXDXD
+
 static int mt753x_mdio_read(struct mii_bus *bus, int addr, int reg)
 {
 	struct gsw_mt753x *gsw = bus->priv;
@@ -540,8 +552,7 @@
 	return 0;
 }
 
-static const struct net_device_ops mt753x_dummy_netdev_ops = {
-};
+static const struct net_device_ops mt753x_dummy_netdev_ops = {};
 
 static void mt753x_phy_link_handler(struct net_device *dev)
 {
@@ -552,8 +563,8 @@
 
 	if (phydev->link) {
 		dev_info(gsw->dev,
-			 "Port %d Link is Up - %s/%s - flow control %s\n",
-			 port, phy_speed_to_str(phydev->speed),
+			 "Port %d Link is Up - %s/%s - flow control %s\n", port,
+			 phy_speed_to_str(phydev->speed),
 			 (phydev->duplex == DUPLEX_FULL) ? "Full" : "Half",
 			 phydev->pause ? "rx/tx" : "off");
 	} else {
@@ -566,7 +577,8 @@
 {
 	struct device_node *phy_np;
 	struct mt753x_phy *phy;
-	int phy_mode;
+	phy_interface_t iface;
+	int ret;
 	u32 phyad;
 
 	if (!mii_np)
@@ -579,10 +591,10 @@
 		if (phyad >= MT753X_NUM_PHYS)
 			continue;
 
-		phy_mode = of_get_phy_mode(phy_np);
-		if (phy_mode < 0) {
+		ret = of_get_phy_mode(phy_np);
+		if (ret < 0) {
 			dev_info(gsw->dev, "incorrect phy-mode %d for PHY %d\n",
-				 phy_mode, phyad);
+				 iface, phyad);
 			continue;
 		}
 
@@ -593,7 +605,7 @@
 		phy->netdev.netdev_ops = &mt753x_dummy_netdev_ops;
 
 		phy->phydev = of_phy_connect(&phy->netdev, phy_np,
-					mt753x_phy_link_handler, 0, phy_mode);
+					     mt753x_phy_link_handler, 0, iface);
 		if (!phy->phydev) {
 			dev_info(gsw->dev, "could not connect to PHY %d\n",
 				 phyad);
@@ -640,7 +652,7 @@
 	gsw->gphy_bus->priv = gsw;
 	gsw->gphy_bus->parent = gsw->dev;
 	gsw->gphy_bus->phy_mask = BIT(MT753X_NUM_PHYS) - 1;
-//	gsw->gphy_bus->irq = gsw->phy_irqs;
+	//	gsw->gphy_bus->irq = gsw->phy_irqs;
 
 	for (i = 0; i < PHY_MAX_ADDR; i++)
 		gsw->gphy_bus->irq[i] = PHY_POLL;
@@ -655,7 +667,6 @@
 	ret = of_mdiobus_register(gsw->gphy_bus, mii_np);
 
 	if (ret) {
-		devm_mdiobus_free(gsw->dev, gsw->gphy_bus);
 		gsw->gphy_bus = NULL;
 	} else {
 		if (gsw->phy_status_poll)
@@ -668,7 +679,6 @@
 
 	return ret;
 }
-#endif
 
 static irqreturn_t mt753x_irq_handler(int irq, void *dev)
 {
@@ -710,8 +720,10 @@
 	mutex_init(&gsw->mii_lock);
 
 	/* Switch hard reset */
-	if (mt753x_hw_reset(gsw))
+	if (mt753x_hw_reset(gsw)) {
+		dev_info(&pdev->dev, "reset switch fail.\n");
 		goto fail;
+	}
 
 	/* Fetch the SMI address dirst */
 	if (of_property_read_u32(np, "mediatek,smi-addr", &gsw->smi_addr))
@@ -768,8 +780,8 @@
 
 	platform_set_drvdata(pdev, gsw);
 
-	gsw->phy_status_poll = of_property_read_bool(gsw->dev->of_node,
-						     "mediatek,phy-poll");
+	gsw->phy_status_poll =
+		of_property_read_bool(gsw->dev->of_node, "mediatek,phy-poll");
 
 	mt753x_add_gsw(gsw);
 #if 1 //XDXD
@@ -825,7 +837,7 @@
 
 static const struct of_device_id mt753x_ids[] = {
 	{ .compatible = "mediatek,mt753x" },
-	{ },
+	{},
 };
 
 MODULE_DEVICE_TABLE(of, mt753x_ids);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c
old mode 100755
new mode 100644
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
old mode 100755
new mode 100644
index 7a2a992..e36b6f3
--- a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
@@ -38,7 +38,6 @@
 #ifdef __KERNEL__
 int mt753x_nl_init(void);
 void mt753x_nl_exit(void);
-
 #endif /* __KERNEL__ */
 
 #endif /* _MT753X_NL_H_ */
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
old mode 100755
new mode 100644
index 1784873..733da63
--- a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
@@ -9,6 +9,9 @@
 
 #include <linux/bitops.h>
 
+/* ethernet wrap register */
+#define ETH_RESET		0x8
+
 /* Values of Egress TAG Control */
 #define ETAG_CTRL_UNTAG			0
 #define ETAG_CTRL_TAG			2
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c
old mode 100755
new mode 100644
diff --git a/target/linux/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/target/linux/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
new file mode 100644
index 0000000..3be91dd
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
@@ -0,0 +1,1467 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7988 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include "pinctrl-moore.h"
+
+enum MT7988_PINCTRL_REG_PAGE {
+	GPIO_BASE,
+	IOCFG_TR_BASE,
+	IOCFG_BR_BASE,
+	IOCFG_RB_BASE,
+	IOCFG_LB_BASE,
+	IOCFG_TL_BASE,
+};
+
+#define MT7988_PIN(_number, _name) MTK_PIN(_number, _name, 0, _number, DRV_GRP4)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,     \
+		       _x_bits)                                                \
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,     \
+		       _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,    \
+			_x_bits)                                               \
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,     \
+		       _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt7988_pin_mode_range[] = {
+	PIN_FIELD(0, 83, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_dir_range[] = {
+	PIN_FIELD(0, 83, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_di_range[] = {
+	PIN_FIELD(0, 83, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_do_range[] = {
+	PIN_FIELD(0, 83, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_ies_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x30, 0x10, 13, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x30, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0x30, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x40, 0x10, 21, 1),
+	PIN_FIELD_BASE(13, 13, 1, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0x40, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(15, 15, 5, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(16, 16, 5, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(17, 17, 5, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(18, 18, 5, 0x30, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x30, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x50, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x50, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x50, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x50, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x50, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x50, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x50, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x50, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x50, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x50, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x50, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x50, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x50, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x50, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x50, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x50, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x50, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x50, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x50, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(63, 63, 1, 0x40, 0x10, 20, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x40, 0x10, 11, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x40, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x30, 0x10, 6, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(75, 75, 4, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0x30, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x40, 0x10, 18, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x40, 0x10, 19, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x40, 0x10, 17, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_smt_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0xc0, 0x10, 13, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0xc0, 0x10, 14, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0xc0, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0xc0, 0x10, 12, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0xc0, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0xc0, 0x10, 9, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0xc0, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(7, 7, 4, 0xb0, 0x10, 8, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0xb0, 0x10, 6, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0xb0, 0x10, 5, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0xb0, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0xe0, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0xe0, 0x10, 21, 1),
+	PIN_FIELD_BASE(13, 13, 1, 0xe0, 0x10, 1, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0xe0, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(15, 15, 5, 0xc0, 0x10, 7, 1),
+	PIN_FIELD_BASE(16, 16, 5, 0xc0, 0x10, 8, 1),
+	PIN_FIELD_BASE(17, 17, 5, 0xc0, 0x10, 3, 1),
+	PIN_FIELD_BASE(18, 18, 5, 0xc0, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0xb0, 0x10, 7, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0xb0, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x140, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x140, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x140, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x140, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x140, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x140, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x140, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x140, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x140, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x140, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x140, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x140, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x150, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x140, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x140, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x140, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x150, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x140, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x140, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x140, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x140, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x140, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x140, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x140, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x140, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x140, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x140, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x140, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x140, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x140, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x140, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x140, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x140, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x140, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0xe0, 0x10, 14, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0xe0, 0x10, 15, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0xe0, 0x10, 13, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0xe0, 0x10, 4, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0xe0, 0x10, 5, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0xe0, 0x10, 6, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0xe0, 0x10, 3, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0xe0, 0x10, 7, 1),
+	PIN_FIELD_BASE(63, 63, 1, 0xe0, 0x10, 20, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0xe0, 0x10, 8, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0xe0, 0x10, 9, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0xe0, 0x10, 10, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0xe0, 0x10, 11, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0xe0, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0xc0, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0xc0, 0x10, 2, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0xc0, 0x10, 5, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0xc0, 0x10, 6, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0xb0, 0x10, 10, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0xb0, 0x10, 1, 1),
+	PIN_FIELD_BASE(75, 75, 4, 0xb0, 0x10, 11, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0xb0, 0x10, 9, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0xb0, 0x10, 2, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0xb0, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0xb0, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0xe0, 0x10, 18, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0xe0, 0x10, 19, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0xe0, 0x10, 16, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0xe0, 0x10, 17, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_pu_range[] = {
+	PIN_FIELD_BASE(7, 7, 4, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x60, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0x60, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(13, 13, 1, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(63, 63, 1, 0x70, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(75, 75, 4, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0x60, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_pd_range[] = {
+	PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0x40, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(13, 13, 1, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0x50, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(15, 15, 5, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(16, 16, 5, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(17, 17, 5, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(18, 18, 5, 0x40, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(63, 63, 1, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x40, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(75, 75, 4, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0x40, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_drv_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(1, 1, 5, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(3, 3, 5, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(4, 4, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(5, 5, 5, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(6, 6, 5, 0x00, 0x10, 12, 3),
+
+	PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 28, 3),
+	PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(10, 10, 4, 0x00, 0x10, 9, 3),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(12, 12, 1, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(13, 13, 1, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(14, 14, 1, 0x00, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(20, 20, 4, 0x00, 0x10, 12, 3),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x10, 0x10, 21, 3),
+	PIN_FIELD_BASE(22, 22, 3, 0x20, 0x10, 9, 3),
+	PIN_FIELD_BASE(23, 23, 3, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(24, 24, 3, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(25, 25, 3, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(26, 26, 3, 0x20, 0x10, 6, 3),
+	PIN_FIELD_BASE(27, 27, 3, 0x10, 0x10, 24, 3),
+	PIN_FIELD_BASE(28, 28, 3, 0x20, 0x10, 15, 3),
+	PIN_FIELD_BASE(29, 29, 3, 0x20, 0x10, 18, 3),
+	PIN_FIELD_BASE(30, 30, 3, 0x20, 0x10, 21, 3),
+	PIN_FIELD_BASE(31, 31, 3, 0x20, 0x10, 12, 3),
+	PIN_FIELD_BASE(32, 32, 3, 0x20, 0x10, 24, 3),
+	PIN_FIELD_BASE(33, 33, 3, 0x30, 0x10, 6, 3),
+	PIN_FIELD_BASE(34, 34, 3, 0x30, 0x10, 3, 3),
+	PIN_FIELD_BASE(35, 35, 3, 0x20, 0x10, 27, 3),
+	PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 0, 3),
+	PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 9, 3),
+	PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(40, 40, 3, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(41, 41, 3, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(42, 42, 3, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(43, 43, 3, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(44, 44, 3, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(45, 45, 3, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(46, 46, 3, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(47, 47, 3, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(48, 48, 3, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(49, 49, 3, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(50, 50, 3, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(51, 51, 3, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(52, 52, 3, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(53, 53, 3, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(54, 54, 3, 0x10, 0x10, 18, 3),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(56, 56, 1, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(57, 57, 1, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(58, 58, 1, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(59, 59, 1, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(60, 60, 1, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(61, 61, 1, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(62, 62, 1, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(63, 63, 1, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(64, 64, 1, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(65, 65, 1, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(66, 66, 1, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(67, 67, 1, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(68, 68, 1, 0x10, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(70, 70, 5, 0x00, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(74, 74, 4, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(75, 75, 4, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(76, 76, 4, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(77, 77, 4, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(78, 78, 4, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(79, 79, 4, 0x10, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x10, 0x10, 24, 3),
+	PIN_FIELD_BASE(81, 81, 1, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(82, 82, 1, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(83, 83, 1, 0x10, 0x10, 21, 3),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_pupd_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x50, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x60, 0x10, 18, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x50, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x70, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x70, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x70, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x70, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x70, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x70, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x70, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x70, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x70, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x70, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x70, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x70, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x70, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x70, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x70, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x70, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x70, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x70, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x70, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x70, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x70, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x70, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x70, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x60, 0x10, 12, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x60, 0x10, 13, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x60, 0x10, 11, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x60, 0x10, 4, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x60, 0x10, 9, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x60, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x50, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x50, 0x10, 0, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x60, 0x10, 16, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x60, 0x10, 17, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x60, 0x10, 14, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x60, 0x10, 15, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_r0_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x60, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x80, 0x10, 18, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x70, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x90, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x90, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x90, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x90, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x90, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x90, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x90, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x90, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x90, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x90, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x90, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x90, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0xa0, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x90, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x90, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x90, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0xa0, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x90, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x90, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x90, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x90, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x90, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x90, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x80, 0x10, 12, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x80, 0x10, 13, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x80, 0x10, 11, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x80, 0x10, 7, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x80, 0x10, 8, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x80, 0x10, 9, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x80, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x60, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x70, 0x10, 0, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x80, 0x10, 16, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x80, 0x10, 17, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x80, 0x10, 14, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x80, 0x10, 15, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_r1_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x70, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x90, 0x10, 18, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x80, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0xb0, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0xb0, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0xb0, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0xb0, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0xb0, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0xb0, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0xb0, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0xb0, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0xb0, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0xb0, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0xb0, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0xb0, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0xc0, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0xb0, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0xb0, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0xb0, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0xc0, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0xb0, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0xb0, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0xb0, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0xb0, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0xb0, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0xb0, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0xb0, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0xb0, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0xb0, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0xb0, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0xb0, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0xb0, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0xb0, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0xb0, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0xb0, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0xb0, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0xb0, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x90, 0x10, 12, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x90, 0x10, 13, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x90, 0x10, 11, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x90, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x70, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x80, 0x10, 0, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x90, 0x10, 16, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x90, 0x10, 17, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x90, 0x10, 14, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x90, 0x10, 15, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7988_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7988_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7988_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7988_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7988_pin_do_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7988_pin_smt_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7988_pin_ies_range),
+	[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7988_pin_pu_range),
+	[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7988_pin_pd_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7988_pin_drv_range),
+	[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7988_pin_pupd_range),
+	[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7988_pin_r0_range),
+	[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7988_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7988_pins[] = {
+	MT7988_PIN(0, "UART2_RXD"),
+	MT7988_PIN(1, "UART2_TXD"),
+	MT7988_PIN(2, "UART2_CTS"),
+	MT7988_PIN(3, "UART2_RTS"),
+	MT7988_PIN(4, "GPIO_A"),
+	MT7988_PIN(5, "SMI_0_MDC"),
+	MT7988_PIN(6, "SMI_0_MDIO"),
+	MT7988_PIN(7, "PCIE30_2L_0_WAKE_N"),
+	MT7988_PIN(8, "PCIE30_2L_0_CLKREQ_N"),
+	MT7988_PIN(9, "PCIE30_1L_1_WAKE_N"),
+	MT7988_PIN(10, "PCIE30_1L_1_CLKREQ_N"),
+	MT7988_PIN(11, "GPIO_P"),
+	MT7988_PIN(12, "WATCHDOG"),
+	MT7988_PIN(13, "GPIO_RESET"),
+	MT7988_PIN(14, "GPIO_WPS"),
+	MT7988_PIN(15, "PMIC_I2C_SCL"),
+	MT7988_PIN(16, "PMIC_I2C_SDA"),
+	MT7988_PIN(17, "I2C_1_SCL"),
+	MT7988_PIN(18, "I2C_1_SDA"),
+	MT7988_PIN(19, "PCIE30_2L_0_PRESET_N"),
+	MT7988_PIN(20, "PCIE30_1L_1_PRESET_N"),
+	MT7988_PIN(21, "PWMD1"),
+	MT7988_PIN(22, "SPI0_WP"),
+	MT7988_PIN(23, "SPI0_HOLD"),
+	MT7988_PIN(24, "SPI0_CSB"),
+	MT7988_PIN(25, "SPI0_MISO"),
+	MT7988_PIN(26, "SPI0_MOSI"),
+	MT7988_PIN(27, "SPI0_CLK"),
+	MT7988_PIN(28, "SPI1_CSB"),
+	MT7988_PIN(29, "SPI1_MISO"),
+	MT7988_PIN(30, "SPI1_MOSI"),
+	MT7988_PIN(31, "SPI1_CLK"),
+	MT7988_PIN(32, "SPI2_CLK"),
+	MT7988_PIN(33, "SPI2_MOSI"),
+	MT7988_PIN(34, "SPI2_MISO"),
+	MT7988_PIN(35, "SPI2_CSB"),
+	MT7988_PIN(36, "SPI2_HOLD"),
+	MT7988_PIN(37, "SPI2_WP"),
+	MT7988_PIN(38, "EMMC_RSTB"),
+	MT7988_PIN(39, "EMMC_DSL"),
+	MT7988_PIN(40, "EMMC_CK"),
+	MT7988_PIN(41, "EMMC_CMD"),
+	MT7988_PIN(42, "EMMC_DATA_7"),
+	MT7988_PIN(43, "EMMC_DATA_6"),
+	MT7988_PIN(44, "EMMC_DATA_5"),
+	MT7988_PIN(45, "EMMC_DATA_4"),
+	MT7988_PIN(46, "EMMC_DATA_3"),
+	MT7988_PIN(47, "EMMC_DATA_2"),
+	MT7988_PIN(48, "EMMC_DATA_1"),
+	MT7988_PIN(49, "EMMC_DATA_0"),
+	MT7988_PIN(50, "PCM_FS_I2S_LRCK"),
+	MT7988_PIN(51, "PCM_CLK_I2S_BCLK"),
+	MT7988_PIN(52, "PCM_DRX_I2S_DIN"),
+	MT7988_PIN(53, "PCM_DTX_I2S_DOUT"),
+	MT7988_PIN(54, "PCM_MCK_I2S_MCLK"),
+	MT7988_PIN(55, "UART0_RXD"),
+	MT7988_PIN(56, "UART0_TXD"),
+	MT7988_PIN(57, "PWMD0"),
+	MT7988_PIN(58, "JTAG_JTDI"),
+	MT7988_PIN(59, "JTAG_JTDO"),
+	MT7988_PIN(60, "JTAG_JTMS"),
+	MT7988_PIN(61, "JTAG_JTCLK"),
+	MT7988_PIN(62, "JTAG_JTRST_N"),
+	MT7988_PIN(63, "USB_DRV_VBUS_P1"),
+	MT7988_PIN(64, "LED_A"),
+	MT7988_PIN(65, "LED_B"),
+	MT7988_PIN(66, "LED_C"),
+	MT7988_PIN(67, "LED_D"),
+	MT7988_PIN(68, "LED_E"),
+	MT7988_PIN(69, "GPIO_B"),
+	MT7988_PIN(70, "GPIO_C"),
+	MT7988_PIN(71, "I2C_2_SCL"),
+	MT7988_PIN(72, "I2C_2_SDA"),
+	MT7988_PIN(73, "PCIE30_2L_1_PRESET_N"),
+	MT7988_PIN(74, "PCIE30_1L_0_PRESET_N"),
+	MT7988_PIN(75, "PCIE30_2L_1_WAKE_N"),
+	MT7988_PIN(76, "PCIE30_2L_1_CLKREQ_N"),
+	MT7988_PIN(77, "PCIE30_1L_0_WAKE_N"),
+	MT7988_PIN(78, "PCIE30_1L_0_CLKREQ_N"),
+	MT7988_PIN(79, "USB_DRV_VBUS_P0"),
+	MT7988_PIN(80, "UART1_RXD"),
+	MT7988_PIN(81, "UART1_TXD"),
+	MT7988_PIN(82, "UART1_CTS"),
+	MT7988_PIN(83, "UART1_RTS"),
+};
+
+/* jtag */
+static int mt7988_tops_jtag0_0_pins[] = { 0, 1, 2, 3, 4 };
+static int mt7988_tops_jtag0_0_funcs[] = { 2, 2, 2, 2, 2 };
+
+static int mt7988_wo0_jtag_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_wo0_jtag_funcs[] = { 3, 3, 3, 3, 3 };
+
+static int mt7988_wo1_jtag_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_wo1_jtag_funcs[] = { 4, 4, 4, 4, 4 };
+
+static int mt7988_wo2_jtag_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_wo2_jtag_funcs[] = { 5, 5, 5, 5, 5 };
+
+static int mt7988_jtag_pins[] = { 58, 59, 60, 61, 62 };
+static int mt7988_jtag_funcs[] = { 1, 1, 1, 1, 1 };
+
+static int mt7988_tops_jtag0_1_pins[] = { 58, 59, 60, 61, 62 };
+static int mt7988_tops_jtag0_1_funcs[] = { 4, 4, 4, 4, 4 };
+
+/* int_usxgmii */
+static int mt7988_int_usxgmii_pins[] = { 2, 3 };
+static int mt7988_int_usxgmii_funcs[] = { 3, 3 };
+
+/* pwm */
+static int mt7988_pwm7_0_pins[] = { 4 };
+static int mt7988_pwm7_0_funcs[] = { 3 };
+
+static int mt7988_pwm1_pins[] = { 21 };
+static int mt7988_pwm1_funcs[] = { 1 };
+
+static int mt7988_pwm0_pins[] = { 57 };
+static int mt7988_pwm0_funcs[] = { 1 };
+
+static int mt7988_pwm2_pins[] = { 58 };
+static int mt7988_pwm2_funcs[] = { 5 };
+
+static int mt7988_pwm3_pins[] = { 59 };
+static int mt7988_pwm3_funcs[] = { 5 };
+
+static int mt7988_pwm4_pins[] = { 60 };
+static int mt7988_pwm4_funcs[] = { 5 };
+
+static int mt7988_pwm5_pins[] = { 61 };
+static int mt7988_pwm5_funcs[] = { 5 };
+
+static int mt7988_pwm6_0_pins[] = { 62 };
+static int mt7988_pwm6_0_funcs[] = { 5 };
+
+static int mt7988_pwm6_1_pins[] = { 69 };
+static int mt7988_pwm6_1_funcs[] = { 3 };
+
+static int mt7988_pwm7_pins[] = { 70 };
+static int mt7988_pwm7_funcs[] = { 3 };
+
+static int mt7988_pwm2_1_pins[] = { 80 };
+static int mt7988_pwm2_1_funcs[] = { 2 };
+
+static int mt7988_pwm3_1_pins[] = { 81 };
+static int mt7988_pwm3_1_funcs[] = { 2 };
+
+static int mt7988_pwm4_1_pins[] = { 82 };
+static int mt7988_pwm4_1_funcs[] = { 2 };
+
+static int mt7988_pwm5_1_pins[] = { 83 };
+static int mt7988_pwm5_1_funcs[] = { 2 };
+
+/* dfd */
+static int mt7988_dfd_pins[] = { 0, 1, 2, 3, 4 };
+static int mt7988_dfd_funcs[] = { 4, 4, 4, 4, 4 };
+
+/* i2c */
+static int mt7988_xfi_phy0_i2c0_pins[] = { 0, 1 };
+static int mt7988_xfi_phy0_i2c0_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_phy1_i2c0_pins[] = { 0, 1 };
+static int mt7988_xfi_phy1_i2c0_funcs[] = { 6, 6 };
+
+static int mt7988_xfi_phy_pll_i2c0_pins[] = { 3, 4 };
+static int mt7988_xfi_phy_pll_i2c0_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_phy_pll_i2c1_pins[] = { 3, 4 };
+static int mt7988_xfi_phy_pll_i2c1_funcs[] = { 6, 6 };
+
+static int mt7988_i2c0_0_pins[] = { 5, 6 };
+static int mt7988_i2c0_0_funcs[] = { 2, 2 };
+
+static int mt7988_i2c1_sfp_pins[] = { 5, 6 };
+static int mt7988_i2c1_sfp_funcs[] = { 4, 4 };
+
+static int mt7988_xfi_pextp_phy0_i2c_pins[] = { 5, 6 };
+static int mt7988_xfi_pextp_phy0_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_pextp_phy1_i2c_pins[] = { 5, 6 };
+static int mt7988_xfi_pextp_phy1_i2c_funcs[] = { 6, 6 };
+
+static int mt7988_i2c0_1_pins[] = { 15, 16 };
+static int mt7988_i2c0_1_funcs[] = { 1, 1 };
+
+static int mt7988_u30_phy_i2c0_pins[] = { 15, 16 };
+static int mt7988_u30_phy_i2c0_funcs[] = { 2, 2 };
+
+static int mt7988_u32_phy_i2c0_pins[] = { 15, 16 };
+static int mt7988_u32_phy_i2c0_funcs[] = { 3, 3 };
+
+static int mt7988_xfi_phy0_i2c1_pins[] = { 15, 16 };
+static int mt7988_xfi_phy0_i2c1_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_phy1_i2c1_pins[] = { 15, 16 };
+static int mt7988_xfi_phy1_i2c1_funcs[] = { 6, 6 };
+
+static int mt7988_xfi_phy_pll_i2c2_pins[] = { 15, 16 };
+static int mt7988_xfi_phy_pll_i2c2_funcs[] = { 7, 7 };
+
+static int mt7988_i2c1_0_pins[] = { 17, 18 };
+static int mt7988_i2c1_0_funcs[] = { 1, 1 };
+
+static int mt7988_u30_phy_i2c1_pins[] = { 17, 18 };
+static int mt7988_u30_phy_i2c1_funcs[] = { 2, 2 };
+
+static int mt7988_u32_phy_i2c1_pins[] = { 17, 18 };
+static int mt7988_u32_phy_i2c1_funcs[] = { 3, 3 };
+
+static int mt7988_xfi_phy_pll_i2c3_pins[] = { 17, 18 };
+static int mt7988_xfi_phy_pll_i2c3_funcs[] = { 4, 4 };
+
+static int mt7988_sgmii0_i2c_pins[] = { 17, 18 };
+static int mt7988_sgmii0_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_sgmii1_i2c_pins[] = { 17, 18 };
+static int mt7988_sgmii1_i2c_funcs[] = { 6, 6 };
+
+static int mt7988_i2c1_2_pins[] = { 69, 70 };
+static int mt7988_i2c1_2_funcs[] = { 2, 2 };
+
+static int mt7988_i2c2_0_pins[] = { 69, 70 };
+static int mt7988_i2c2_0_funcs[] = { 4, 4 };
+
+static int mt7988_i2c2_1_pins[] = { 70, 71 };
+static int mt7988_i2c2_1_funcs[] = { 1, 1 };
+
+/* eth */
+static int mt7988_mdc_mdio0_pins[] = { 5, 6 };
+static int mt7988_mdc_mdio0_funcs[] = { 1, 1 };
+
+static int mt7988_2p5g_ext_mdio_pins[] = { 28, 29 };
+static int mt7988_2p5g_ext_mdio_funcs[] = { 6, 6 };
+
+static int mt7988_gbe_ext_mdio_pins[] = { 30, 31 };
+static int mt7988_gbe_ext_mdio_funcs[] = { 6, 6 };
+
+static int mt7988_mdc_mdio1_pins[] = { 69, 70 };
+static int mt7988_mdc_mdio1_funcs[] = { 1, 1 };
+
+/* pcie */
+static int mt7988_pcie_wake_n0_0_pins[] = { 7 };
+static int mt7988_pcie_wake_n0_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n0_0_pins[] = { 8 };
+static int mt7988_pcie_clk_req_n0_0_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n3_0_pins[] = { 9 };
+static int mt7988_pcie_wake_n3_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n3_pins[] = { 10 };
+static int mt7988_pcie_clk_req_n3_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n0_1_pins[] = { 10 };
+static int mt7988_pcie_clk_req_n0_1_funcs[] = { 2 };
+
+static int mt7988_pcie_p0_phy_i2c_pins[] = { 7, 8 };
+static int mt7988_pcie_p0_phy_i2c_funcs[] = { 3, 3 };
+
+static int mt7988_pcie_p1_phy_i2c_pins[] = { 7, 8 };
+static int mt7988_pcie_p1_phy_i2c_funcs[] = { 4, 4 };
+
+static int mt7988_pcie_p3_phy_i2c_pins[] = { 9, 10 };
+static int mt7988_pcie_p3_phy_i2c_funcs[] = { 4, 4 };
+
+static int mt7988_pcie_p2_phy_i2c_pins[] = { 7, 8 };
+static int mt7988_pcie_p2_phy_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_ckm_phy_i2c_pins[] = { 9, 10 };
+static int mt7988_ckm_phy_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_pcie_wake_n0_1_pins[] = { 13 };
+static int mt7988_pcie_wake_n0_1_funcs[] = { 2 };
+
+static int mt7988_pcie_wake_n3_1_pins[] = { 14 };
+static int mt7988_pcie_wake_n3_1_funcs[] = { 2 };
+
+static int mt7988_pcie_2l_0_pereset_pins[] = { 19 };
+static int mt7988_pcie_2l_0_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_1l_1_pereset_pins[] = { 20 };
+static int mt7988_pcie_1l_1_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n2_1_pins[] = { 63 };
+static int mt7988_pcie_clk_req_n2_1_funcs[] = { 2 };
+
+static int mt7988_pcie_2l_1_pereset_pins[] = { 73 };
+static int mt7988_pcie_2l_1_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_1l_0_pereset_pins[] = { 74 };
+static int mt7988_pcie_1l_0_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n1_0_pins[] = { 75 };
+static int mt7988_pcie_wake_n1_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n1_pins[] = { 76 };
+static int mt7988_pcie_clk_req_n1_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n2_0_pins[] = { 77 };
+static int mt7988_pcie_wake_n2_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n2_0_pins[] = { 78 };
+static int mt7988_pcie_clk_req_n2_0_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n2_1_pins[] = { 79 };
+static int mt7988_pcie_wake_n2_1_funcs[] = { 2 };
+
+/* pmic */
+static int mt7988_pmic_pins[] = { 11 };
+static int mt7988_pmic_funcs[] = { 1 };
+
+/* watchdog */
+static int mt7988_watchdog_pins[] = { 12 };
+static int mt7988_watchdog_funcs[] = { 1 };
+
+/* spi */
+static int mt7988_spi0_wp_hold_pins[] = { 22, 23 };
+static int mt7988_spi0_wp_hold_funcs[] = { 1, 1 };
+
+static int mt7988_spi0_pins[] = { 24, 25, 26, 27 };
+static int mt7988_spi0_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_spi1_pins[] = { 28, 29, 30, 31 };
+static int mt7988_spi1_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_spi2_pins[] = { 32, 33, 34, 35 };
+static int mt7988_spi2_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_spi2_wp_hold_pins[] = { 36, 37 };
+static int mt7988_spi2_wp_hold_funcs[] = { 1, 1 };
+
+/* flash */
+static int mt7988_snfi_pins[] = { 22, 23, 24, 25, 26, 27 };
+static int mt7988_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+static int mt7988_emmc_45_pins[] = {
+	21, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37
+};
+static int mt7988_emmc_45_funcs[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
+
+static int mt7988_emmc_51_pins[] = { 38, 39, 40, 41, 42, 43,
+				     44, 45, 46, 47, 48, 49 };
+static int mt7988_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+/* uart */
+static int mt7988_uart2_pins[] = { 0, 1, 2, 3 };
+static int mt7988_uart2_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_tops_uart0_0_pins[] = { 22, 23 };
+static int mt7988_tops_uart0_0_funcs[] = { 3, 3 };
+
+static int mt7988_uart2_0_pins[] = { 28, 29, 30, 31 };
+static int mt7988_uart2_0_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart1_0_pins[] = { 32, 33, 34, 35 };
+static int mt7988_uart1_0_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart2_1_pins[] = { 32, 33, 34, 35 };
+static int mt7988_uart2_1_funcs[] = { 3, 3, 3, 3 };
+
+static int mt7988_net_wo0_uart_txd_0_pins[] = { 28 };
+static int mt7988_net_wo0_uart_txd_0_funcs[] = { 3 };
+
+static int mt7988_net_wo1_uart_txd_0_pins[] = { 29 };
+static int mt7988_net_wo1_uart_txd_0_funcs[] = { 3 };
+
+static int mt7988_net_wo2_uart_txd_0_pins[] = { 30 };
+static int mt7988_net_wo2_uart_txd_0_funcs[] = { 3 };
+
+static int mt7988_tops_uart1_0_pins[] = { 28, 29 };
+static int mt7988_tops_uart1_0_funcs[] = { 4, 4 };
+
+static int mt7988_tops_uart0_1_pins[] = { 30, 31 };
+static int mt7988_tops_uart0_1_funcs[] = { 4, 4 };
+
+static int mt7988_tops_uart1_1_pins[] = { 36, 37 };
+static int mt7988_tops_uart1_1_funcs[] = { 3, 3 };
+
+static int mt7988_uart0_pins[] = { 55, 56 };
+static int mt7988_uart0_funcs[] = { 1, 1 };
+
+static int mt7988_tops_uart0_2_pins[] = { 55, 56 };
+static int mt7988_tops_uart0_2_funcs[] = { 2, 2 };
+
+static int mt7988_uart2_2_pins[] = { 50, 51, 52, 53 };
+static int mt7988_uart2_2_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart1_1_pins[] = { 58, 59, 60, 61 };
+static int mt7988_uart1_1_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart2_3_pins[] = { 58, 59, 60, 61 };
+static int mt7988_uart2_3_funcs[] = { 3, 3, 3, 3 };
+
+static int mt7988_uart1_2_pins[] = { 80, 81, 82, 83 };
+static int mt7988_uart1_2_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_tops_uart1_2_pins[] = { 80, 81 };
+static int mt7988_tops_uart1_2_funcs[] = {
+	4,
+	4,
+};
+
+static int mt7988_net_wo0_uart_txd_1_pins[] = { 80 };
+static int mt7988_net_wo0_uart_txd_1_funcs[] = { 3 };
+
+static int mt7988_net_wo1_uart_txd_1_pins[] = { 81 };
+static int mt7988_net_wo1_uart_txd_1_funcs[] = { 3 };
+
+static int mt7988_net_wo2_uart_txd_1_pins[] = { 82 };
+static int mt7988_net_wo2_uart_txd_1_funcs[] = { 3 };
+
+/* udi */
+static int mt7988_udi_pins[] = { 32, 33, 34, 35, 36 };
+static int mt7988_udi_funcs[] = { 4, 4, 4, 4, 4 };
+
+/* pcm */
+static int mt7988_pcm_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_pcm_funcs[] = { 1, 1, 1, 1, 1 };
+
+/* led */
+static int mt7988_gbe_led1_pins[] = { 58, 59, 60, 61 };
+static int mt7988_gbe_led1_funcs[] = { 6, 6, 6, 6 };
+
+static int mt7988_2p5gbe_led1_pins[] = { 62 };
+static int mt7988_2p5gbe_led1_funcs[] = { 6 };
+
+static int mt7988_gbe_led0_pins[] = { 64, 65, 66, 67 };
+static int mt7988_gbe_led0_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_2p5gbe_led0_pins[] = { 68 };
+static int mt7988_2p5gbe_led0_funcs[] = { 1 };
+
+/* usb */
+static int mt7988_drv_vbus_p1_pins[] = { 63 };
+static int mt7988_drv_vbus_p1_funcs[] = { 1 };
+
+static int mt7988_drv_vbus_pins[] = { 79 };
+static int mt7988_drv_vbus_funcs[] = { 1 };
+
+static const struct group_desc mt7988_groups[] = {
+	/*  @GPIO(0,1,2,3): uart2 */
+	PINCTRL_PIN_GROUP("uart2", mt7988_uart2),
+	/*  @GPIO(0,1,2,3,4): tops_jtag0_0 */
+	PINCTRL_PIN_GROUP("tops_jtag0_0", mt7988_tops_jtag0_0),
+	/*  @GPIO(2,3): int_usxgmii */
+	PINCTRL_PIN_GROUP("int_usxgmii", mt7988_int_usxgmii),
+	/*  @GPIO(4): pwm7_0 */
+	PINCTRL_PIN_GROUP("pwm7_0", mt7988_pwm7_0),
+	/*  @GPIO(0,1,2,3,4): dfd */
+	PINCTRL_PIN_GROUP("dfd", mt7988_dfd),
+	/*  @GPIO(0,1): xfi_phy0_i2c0 */
+	PINCTRL_PIN_GROUP("xfi_phy0_i2c0", mt7988_xfi_phy0_i2c0),
+	/*  @GPIO(0,1): xfi_phy1_i2c0 */
+	PINCTRL_PIN_GROUP("xfi_phy1_i2c0", mt7988_xfi_phy1_i2c0),
+	/*  @GPIO(3,4): xfi_phy_pll_i2c0 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c0", mt7988_xfi_phy_pll_i2c0),
+	/*  @GPIO(3,4): xfi_phy_pll_i2c1 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c1", mt7988_xfi_phy_pll_i2c1),
+	/*  @GPIO(5,6) i2c0_0 */
+	PINCTRL_PIN_GROUP("i2c0_0", mt7988_i2c0_0),
+	/*  @GPIO(5,6) i2c1_sfp */
+	PINCTRL_PIN_GROUP("i2c1_sfp", mt7988_i2c1_sfp),
+	/*  @GPIO(5,6) xfi_pextp_phy0_i2c */
+	PINCTRL_PIN_GROUP("xfi_pextp_phy0_i2c", mt7988_xfi_pextp_phy0_i2c),
+	/*  @GPIO(5,6) xfi_pextp_phy1_i2c */
+	PINCTRL_PIN_GROUP("xfi_pextp_phy1_i2c", mt7988_xfi_pextp_phy1_i2c),
+	/*  @GPIO(5,6) mdc_mdio0 */
+	PINCTRL_PIN_GROUP("mdc_mdio0", mt7988_mdc_mdio0),
+	/*  @GPIO(7): pcie_wake_n0_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n0_0", mt7988_pcie_wake_n0_0),
+	/*  @GPIO(8): pcie_clk_req_n0_0 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n0_0", mt7988_pcie_clk_req_n0_0),
+	/*  @GPIO(9): pcie_wake_n3_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n3_0", mt7988_pcie_wake_n3_0),
+	/*  @GPIO(10): pcie_clk_req_n3 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n3", mt7988_pcie_clk_req_n3),
+	/*  @GPIO(10): pcie_clk_req_n0_1 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n0_1", mt7988_pcie_clk_req_n0_1),
+	/*  @GPIO(7,8) pcie_p0_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p0_phy_i2c", mt7988_pcie_p0_phy_i2c),
+	/*  @GPIO(7,8) pcie_p1_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p1_phy_i2c", mt7988_pcie_p1_phy_i2c),
+	/*  @GPIO(7,8) pcie_p2_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p2_phy_i2c", mt7988_pcie_p2_phy_i2c),
+	/*  @GPIO(9,10) pcie_p3_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p3_phy_i2c", mt7988_pcie_p3_phy_i2c),
+	/*  @GPIO(9,10) ckm_phy_i2c */
+	PINCTRL_PIN_GROUP("ckm_phy_i2c", mt7988_ckm_phy_i2c),
+	/*  @GPIO(11): pmic */
+	PINCTRL_PIN_GROUP("pcie_pmic", mt7988_pmic),
+	/*  @GPIO(12): watchdog */
+	PINCTRL_PIN_GROUP("watchdog", mt7988_watchdog),
+	/*  @GPIO(13): pcie_wake_n0_1 */
+	PINCTRL_PIN_GROUP("pcie_wake_n0_1", mt7988_pcie_wake_n0_1),
+	/*  @GPIO(14): pcie_wake_n3_1 */
+	PINCTRL_PIN_GROUP("pcie_wake_n3_1", mt7988_pcie_wake_n3_1),
+	/*  @GPIO(15,16) i2c0_1 */
+	PINCTRL_PIN_GROUP("i2c0_1", mt7988_i2c0_1),
+	/*  @GPIO(15,16) u30_phy_i2c0 */
+	PINCTRL_PIN_GROUP("u30_phy_i2c0", mt7988_u30_phy_i2c0),
+	/*  @GPIO(15,16) u32_phy_i2c0 */
+	PINCTRL_PIN_GROUP("u32_phy_i2c0", mt7988_u32_phy_i2c0),
+	/*  @GPIO(15,16) xfi_phy0_i2c1 */
+	PINCTRL_PIN_GROUP("xfi_phy0_i2c1", mt7988_xfi_phy0_i2c1),
+	/*  @GPIO(15,16) xfi_phy1_i2c1 */
+	PINCTRL_PIN_GROUP("xfi_phy1_i2c1", mt7988_xfi_phy1_i2c1),
+	/*  @GPIO(15,16) xfi_phy_pll_i2c2 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c2", mt7988_xfi_phy_pll_i2c2),
+	/*  @GPIO(17,18) i2c1_0 */
+	PINCTRL_PIN_GROUP("i2c1_0", mt7988_i2c1_0),
+	/*  @GPIO(17,18) u30_phy_i2c1 */
+	PINCTRL_PIN_GROUP("u30_phy_i2c1", mt7988_u30_phy_i2c1),
+	/*  @GPIO(17,18) u32_phy_i2c1 */
+	PINCTRL_PIN_GROUP("u32_phy_i2c1", mt7988_u32_phy_i2c1),
+	/*  @GPIO(17,18) xfi_phy_pll_i2c3 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c3", mt7988_xfi_phy_pll_i2c3),
+	/*  @GPIO(17,18) sgmii0_i2c */
+	PINCTRL_PIN_GROUP("sgmii0_i2c", mt7988_sgmii0_i2c),
+	/*  @GPIO(17,18) sgmii1_i2c */
+	PINCTRL_PIN_GROUP("sgmii1_i2c", mt7988_sgmii1_i2c),
+	/*  @GPIO(19): pcie_2l_0_pereset */
+	PINCTRL_PIN_GROUP("pcie_2l_0_pereset", mt7988_pcie_2l_0_pereset),
+	/*  @GPIO(20): pcie_1l_1_pereset */
+	PINCTRL_PIN_GROUP("pcie_1l_1_pereset", mt7988_pcie_1l_1_pereset),
+	/*  @GPIO(21): pwm1 */
+	PINCTRL_PIN_GROUP("pwm1", mt7988_pwm1),
+	/*  @GPIO(22,23) spi0_wp_hold */
+	PINCTRL_PIN_GROUP("spi0_wp_hold", mt7988_spi0_wp_hold),
+	/*  @GPIO(24,25,26,27) spi0 */
+	PINCTRL_PIN_GROUP("spi0", mt7988_spi0),
+	/*  @GPIO(28,29,30,31) spi1 */
+	PINCTRL_PIN_GROUP("spi1", mt7988_spi1),
+	/*  @GPIO(32,33,34,35) spi2 */
+	PINCTRL_PIN_GROUP("spi2", mt7988_spi2),
+	/*  @GPIO(36,37) spi2_wp_hold */
+	PINCTRL_PIN_GROUP("spi2_wp_hold", mt7988_spi2_wp_hold),
+	/*  @GPIO(22,23,24,25,26,27) snfi */
+	PINCTRL_PIN_GROUP("snfi", mt7988_snfi),
+	/*  @GPIO(22,23) tops_uart0_0 */
+	PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart0_0),
+	/*  @GPIO(28,29,30,31) uart2_0 */
+	PINCTRL_PIN_GROUP("uart2_0", mt7988_uart2_0),
+	/*  @GPIO(32,33,34,35) uart1_0 */
+	PINCTRL_PIN_GROUP("uart1_0", mt7988_uart1_0),
+	/*  @GPIO(32,33,34,35) uart2_1 */
+	PINCTRL_PIN_GROUP("uart2_1", mt7988_uart2_1),
+	/*  @GPIO(28) net_wo0_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0),
+	/*  @GPIO(29) net_wo1_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0),
+	/*  @GPIO(30) net_wo2_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0),
+	/*  @GPIO(28,29) tops_uart1_0 */
+	PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart1_0),
+	/*  @GPIO(30,31) tops_uart0_1 */
+	PINCTRL_PIN_GROUP("tops_uart0_1", mt7988_tops_uart0_1),
+	/*  @GPIO(36,37) tops_uart1_1 */
+	PINCTRL_PIN_GROUP("tops_uart1_1", mt7988_tops_uart1_1),
+	/*  @GPIO(32,33,34,35,36) udi */
+	PINCTRL_PIN_GROUP("udi", mt7988_udi),
+	/*  @GPIO(21,28,29,30,31,32,33,34,35,36,37) emmc_45 */
+	PINCTRL_PIN_GROUP("emmc_45", mt7988_emmc_45),
+	/*  @GPIO(38,39,40,41,42,43,44,45,46,47,48,49) emmc_51 */
+	PINCTRL_PIN_GROUP("emmc_51", mt7988_emmc_51),
+	/*  @GPIO(28,29) 2p5g_ext_mdio */
+	PINCTRL_PIN_GROUP("2p5g_ext_mdio", mt7988_2p5g_ext_mdio),
+	/*  @GPIO(30,31) gbe_ext_mdio */
+	PINCTRL_PIN_GROUP("gbe_ext_mdio", mt7988_gbe_ext_mdio),
+	/*  @GPIO(50,51,52,53,54) pcm */
+	PINCTRL_PIN_GROUP("pcm", mt7988_pcm),
+	/*  @GPIO(55,56) uart0 */
+	PINCTRL_PIN_GROUP("uart0", mt7988_uart0),
+	/*  @GPIO(55,56) tops_uart0_2 */
+	PINCTRL_PIN_GROUP("tops_uart0_2", mt7988_tops_uart0_2),
+	/*  @GPIO(50,51,52,53) uart2_2 */
+	PINCTRL_PIN_GROUP("uart2_2", mt7988_uart2_2),
+	/*  @GPIO(50,51,52,53,54) wo0_jtag */
+	PINCTRL_PIN_GROUP("wo0_jtag", mt7988_wo0_jtag),
+	/*  @GPIO(50,51,52,53,54) wo1-wo1_jtag */
+	PINCTRL_PIN_GROUP("wo1_jtag", mt7988_wo1_jtag),
+	/*  @GPIO(50,51,52,53,54) wo2_jtag */
+	PINCTRL_PIN_GROUP("wo2_jtag", mt7988_wo2_jtag),
+	/*  @GPIO(57) pwm0 */
+	PINCTRL_PIN_GROUP("pwm0", mt7988_pwm0),
+	/*  @GPIO(58,59,60,61,62) jtag */
+	PINCTRL_PIN_GROUP("jtag", mt7988_jtag),
+	/*  @GPIO(58,59,60,61,62) tops_jtag0_1 */
+	PINCTRL_PIN_GROUP("tops_jtag0_1", mt7988_tops_jtag0_1),
+	/*  @GPIO(58,59,60,61) uart2_3 */
+	PINCTRL_PIN_GROUP("uart2_3", mt7988_uart2_3),
+	/*  @GPIO(58,59,60,61) uart1_1 */
+	PINCTRL_PIN_GROUP("uart1_1", mt7988_uart1_1),
+	/*  @GPIO(58) pwm2 */
+	PINCTRL_PIN_GROUP("pwm2", mt7988_pwm2),
+	/*  @GPIO(59) pwm3 */
+	PINCTRL_PIN_GROUP("pwm3", mt7988_pwm3),
+	/*  @GPIO(60) pwm4 */
+	PINCTRL_PIN_GROUP("pwm4", mt7988_pwm4),
+	/*  @GPIO(61) pwm5 */
+	PINCTRL_PIN_GROUP("pwm5", mt7988_pwm5),
+	/*  @GPIO(62) pwm6_0 */
+	PINCTRL_PIN_GROUP("pwm6_0", mt7988_pwm6_0),
+	/*  @GPIO(58,59,60,61) gbe_led1 */
+	PINCTRL_PIN_GROUP("gbe_led1", mt7988_gbe_led1),
+	/*  @GPIO(62) 2p5gbe_led1 */
+	PINCTRL_PIN_GROUP("2p5gbe_led1", mt7988_2p5gbe_led1),
+	/*  @GPIO(64,65,66,67) gbe_led0 */
+	PINCTRL_PIN_GROUP("gbe_led0", mt7988_gbe_led0),
+	/*  @GPIO(68) 2p5gbe_led0 */
+	PINCTRL_PIN_GROUP("2p5gbe_led0", mt7988_2p5gbe_led0),
+	/*  @GPIO(63) drv_vbus_p1 */
+	PINCTRL_PIN_GROUP("drv_vbus_p1", mt7988_drv_vbus_p1),
+	/*  @GPIO(63) pcie_clk_req_n2_1 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n2_1", mt7988_pcie_clk_req_n2_1),
+	/*  @GPIO(69, 70) mdc_mdio1 */
+	PINCTRL_PIN_GROUP("mdc_mdio1", mt7988_mdc_mdio1),
+	/*  @GPIO(69, 70) i2c1_2 */
+	PINCTRL_PIN_GROUP("i2c1_2", mt7988_i2c1_2),
+	/*  @GPIO(69) pwm6_1 */
+	PINCTRL_PIN_GROUP("pwm6_1", mt7988_pwm6_1),
+	/*  @GPIO(70) pwm7 */
+	PINCTRL_PIN_GROUP("pwm7", mt7988_pwm7),
+	/*  @GPIO(69,70) i2c2_0 */
+	PINCTRL_PIN_GROUP("i2c2_0", mt7988_i2c2_0),
+	/*  @GPIO(71,72) i2c2_1 */
+	PINCTRL_PIN_GROUP("i2c2_1", mt7988_i2c2_1),
+	/*  @GPIO(73) pcie_2l_1_pereset */
+	PINCTRL_PIN_GROUP("pcie_2l_1_pereset", mt7988_pcie_2l_1_pereset),
+	/*  @GPIO(74) pcie_1l_0_pereset */
+	PINCTRL_PIN_GROUP("pcie_1l_0_pereset", mt7988_pcie_1l_0_pereset),
+	/*  @GPIO(75) pcie_wake_n1_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n1_0", mt7988_pcie_wake_n1_0),
+	/*  @GPIO(76) pcie_clk_req_n1 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n1", mt7988_pcie_clk_req_n1),
+	/*  @GPIO(77) pcie_wake_n2_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n2_0", mt7988_pcie_wake_n2_0),
+	/*  @GPIO(78) pcie_clk_req_n2_0 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n2_0", mt7988_pcie_clk_req_n2_0),
+	/*  @GPIO(79) drv_vbus */
+	PINCTRL_PIN_GROUP("drv_vbus", mt7988_drv_vbus),
+	/*  @GPIO(79) pcie_wake_n2_1 */
+	PINCTRL_PIN_GROUP("pcie_wake_n2_1", mt7988_pcie_wake_n2_1),
+	/*  @GPIO(80,81,82,83) uart1_2 */
+	PINCTRL_PIN_GROUP("uart1_2", mt7988_uart1_2),
+	/*  @GPIO(80) pwm2_1 */
+	PINCTRL_PIN_GROUP("pwm2_1", mt7988_pwm2_1),
+	/*  @GPIO(81) pwm3_1 */
+	PINCTRL_PIN_GROUP("pwm3_1", mt7988_pwm3_1),
+	/*  @GPIO(82) pwm4_1 */
+	PINCTRL_PIN_GROUP("pwm4_1", mt7988_pwm4_1),
+	/*  @GPIO(83) pwm5_1 */
+	PINCTRL_PIN_GROUP("pwm5_1", mt7988_pwm5_1),
+	/*  @GPIO(80) net_wo0_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0),
+	/*  @GPIO(81) net_wo1_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0),
+	/*  @GPIO(82) net_wo2_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0),
+	/*  @GPIO(80,81) tops_uart1_2 */
+	PINCTRL_PIN_GROUP("tops_uart1_2", mt7988_tops_uart1_2),
+	/*  @GPIO(80) net_wo0_uart_txd_1 */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7988_net_wo0_uart_txd_1),
+	/*  @GPIO(81) net_wo1_uart_txd_1 */
+	PINCTRL_PIN_GROUP("net_wo1_uart_txd_1", mt7988_net_wo1_uart_txd_1),
+	/*  @GPIO(82) net_wo2_uart_txd_1 */
+	PINCTRL_PIN_GROUP("net_wo2_uart_txd_1", mt7988_net_wo2_uart_txd_1),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char * const mt7988_jtag_groups[] = {
+	"tops_jtag0_0", "wo0_jtag", "wo1_jtag",
+	"wo2_jtag",	"jtag",	    "tops_jtag0_1",
+};
+static const char * const mt7988_int_usxgmii_groups[] = {
+	"int_usxgmii",
+};
+static const char * const mt7988_pwm_groups[] = {
+	"pwm7_0", "pwm1",   "pwm0", "pwm2",   "pwm3",	"pwm4",	  "pwm5",
+	"pwm6_0", "pwm6_1", "pwm7", "pwm2_1", "pwm3_1", "pwm4_1", "pwm5_1"
+};
+static const char * const mt7988_dfd_groups[] = {
+	"dfd",
+};
+static const char * const mt7988_i2c_groups[] = {
+	"xfi_phy0_i2c0",
+	"xfi_phy1_i2c0",
+	"xfi_phy_pll_i2c0",
+	"xfi_phy_pll_i2c1",
+	"i2c0_0",
+	"i2c1_sfp",
+	"xfi_pextp_phy0_i2c",
+	"xfi_pextp_phy1_i2c",
+	"i2c0_1",
+	"u30_phy_i2c0",
+	"u32_phy_i2c0",
+	"xfi_phy0_i2c1",
+	"xfi_phy1_i2c1",
+	"xfi_phy_pll_i2c2",
+	"i2c1_0",
+	"u30_phy_i2c1",
+	"u32_phy_i2c1",
+	"xfi_phy_pll_i2c3",
+	"sgmii0_i2c",
+	"sgmii1_i2c",
+	"i2c1_2",
+	"i2c2_0",
+	"i2c2_1",
+};
+static const char * const mt7988_ethernet_groups[] = {
+	"mdc_mdio0",
+	"2p5g_ext_mdio",
+	"gbe_ext_mdio",
+	"mdc_mdio1",
+};
+static const char * const mt7988_pcie_groups[] = {
+	"pcie_wake_n0_0",    "pcie_clk_req_n0_0", "pcie_wake_n3_0",
+	"pcie_clk_req_n3",   "pcie_p0_phy_i2c",	  "pcie_p1_phy_i2c",
+	"pcie_p3_phy_i2c",   "pcie_p2_phy_i2c",	  "ckm_phy_i2c",
+	"pcie_wake_n0_1",    "pcie_wake_n3_1",	  "pcie_2l_0_pereset",
+	"pcie_1l_1_pereset", "pcie_clk_req_n2_1", "pcie_2l_1_pereset",
+	"pcie_1l_0_pereset", "pcie_wake_n1_0",	  "pcie_clk_req_n1",
+	"pcie_wake_n2_0",    "pcie_clk_req_n2_0", "pcie_wake_n2_1",
+	"pcie_clk_req_n0_1"
+};
+static const char * const mt7988_pmic_groups[] = {
+	"pmic",
+};
+static const char * const mt7988_wdt_groups[] = {
+	"watchdog",
+};
+static const char * const mt7988_spi_groups[] = {
+	"spi0", "spi0_wp_hold", "spi1", "spi2", "spi2_wp_hold",
+};
+static const char * const mt7988_flash_groups[] = { "emmc_45", "snfi",
+						    "emmc_51" };
+static const char * const mt7988_uart_groups[] = {
+	"uart2",
+	"tops_uart0_0",
+	"uart2_0",
+	"uart1_0",
+	"uart2_1",
+	"net_wo0_uart_txd_0",
+	"net_wo1_uart_txd_0",
+	"net_wo2_uart_txd_0",
+	"tops_uart1_0",
+	"ops_uart0_1",
+	"ops_uart1_1",
+	"uart0",
+	"tops_uart0_2",
+	"uart1_1",
+	"uart2_3",
+	"uart1_2",
+	"tops_uart1_2",
+	"net_wo0_uart_txd_1",
+	"net_wo1_uart_txd_1",
+	"net_wo2_uart_txd_1",
+};
+static const char * const mt7988_udi_groups[] = {
+	"udi",
+};
+static const char * const mt7988_pcm_groups[] = {
+	"pcm",
+};
+static const char * const mt7988_led_groups[] = {
+	"gbe_led1",    "2p5gbe_led1", "gbe_led0",
+	"2p5gbe_led0", "wf5g_led0",   "wf5g_led1",
+};
+static const char * const mt7988_usb_groups[] = {
+	"drv_vbus",
+	"drv_vbus_p1",
+};
+
+static const struct function_desc mt7988_functions[] = {
+	{ "jtag", mt7988_jtag_groups, ARRAY_SIZE(mt7988_jtag_groups) },
+	{ "int_usxgmii", mt7988_int_usxgmii_groups,
+	  ARRAY_SIZE(mt7988_int_usxgmii_groups) },
+	{ "pwm", mt7988_pwm_groups, ARRAY_SIZE(mt7988_pwm_groups) },
+	{ "dfd", mt7988_dfd_groups, ARRAY_SIZE(mt7988_dfd_groups) },
+	{ "i2c", mt7988_i2c_groups, ARRAY_SIZE(mt7988_i2c_groups) },
+	{ "eth", mt7988_ethernet_groups, ARRAY_SIZE(mt7988_ethernet_groups) },
+	{ "pcie", mt7988_pcie_groups, ARRAY_SIZE(mt7988_pcie_groups) },
+	{ "pmic", mt7988_pmic_groups, ARRAY_SIZE(mt7988_pmic_groups) },
+	{ "watchdog", mt7988_wdt_groups, ARRAY_SIZE(mt7988_wdt_groups) },
+	{ "spi", mt7988_spi_groups, ARRAY_SIZE(mt7988_spi_groups) },
+	{ "flash", mt7988_flash_groups, ARRAY_SIZE(mt7988_flash_groups) },
+	{ "uart", mt7988_uart_groups, ARRAY_SIZE(mt7988_uart_groups) },
+	{ "udi", mt7988_udi_groups, ARRAY_SIZE(mt7988_udi_groups) },
+	{ "pcm", mt7988_pcm_groups, ARRAY_SIZE(mt7988_pcm_groups) },
+	{ "usb", mt7988_usb_groups, ARRAY_SIZE(mt7988_usb_groups) },
+	{ "led", mt7988_led_groups, ARRAY_SIZE(mt7988_led_groups) },
+};
+
+static const struct mtk_eint_hw mt7988_eint_hw = {
+	.port_mask = 7,
+	.ports = 7,
+	.ap_num = ARRAY_SIZE(mt7988_pins),
+	.db_cnt = 16,
+};
+
+static const char * const mt7988_pinctrl_register_base_names[] = {
+	"gpio_base",	 "iocfg_tr_base", "iocfg_br_base",
+	"iocfg_rb_base", "iocfg_lb_base", "iocfg_tl_base",
+};
+
+static struct mtk_pin_soc mt7988_data = {
+	.reg_cal = mt7988_reg_cals,
+	.pins = mt7988_pins,
+	.npins = ARRAY_SIZE(mt7988_pins),
+	.grps = mt7988_groups,
+	.ngrps = ARRAY_SIZE(mt7988_groups),
+	.funcs = mt7988_functions,
+	.nfuncs = ARRAY_SIZE(mt7988_functions),
+	.eint_hw = &mt7988_eint_hw,
+	.gpio_m = 0,
+	.ies_present = false,
+	.base_names = mt7988_pinctrl_register_base_names,
+	.nbase_names = ARRAY_SIZE(mt7988_pinctrl_register_base_names),
+	.bias_disable_set = mtk_pinconf_bias_disable_set,
+	.bias_disable_get = mtk_pinconf_bias_disable_get,
+	.bias_set = mtk_pinconf_bias_set,
+	.bias_get = mtk_pinconf_bias_get,
+	.drive_set = mtk_pinconf_drive_set_rev1,
+	.drive_get = mtk_pinconf_drive_get_rev1,
+	.adv_pull_get = mtk_pinconf_adv_pull_get,
+	.adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt7988_pinctrl_of_match[] = {
+	{
+		.compatible = "mediatek,mt7988-pinctrl",
+	},
+	{}
+};
+
+static int mt7988_pinctrl_probe(struct platform_device *pdev)
+{
+	return mtk_moore_pinctrl_probe(pdev, &mt7988_data);
+}
+
+static struct platform_driver mt7988_pinctrl_driver = {
+	.driver = {
+		.name = "mt7988-pinctrl",
+		.of_match_table = mt7988_pinctrl_of_match,
+	},
+	.probe = mt7988_pinctrl_probe,
+};
+
+static int __init mt7988_pinctrl_init(void)
+{
+	return platform_driver_register(&mt7988_pinctrl_driver);
+}
+arch_initcall(mt7988_pinctrl_init);
diff --git a/target/linux/mediatek/files-5.4/drivers/regulator/rt5190a-regulator.c b/target/linux/mediatek/files-5.4/drivers/regulator/rt5190a-regulator.c
new file mode 100644
index 0000000..c616a46
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/regulator/rt5190a-regulator.c
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <dt-bindings/regulator/richtek,rt5190a-regulator.h>
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT5190A_REG_MANUFACTURE 0x00
+#define RT5190A_REG_BUCK2VSEL	0x04
+#define RT5190A_REG_BUCK3VSEL	0x05
+#define RT5190A_REG_DCDCCNTL	0x06
+#define RT5190A_REG_ENABLE	0x07
+#define RT5190A_REG_DISCHARGE	0x09
+#define RT5190A_REG_PROTMODE	0x0A
+#define RT5190A_REG_MUTECNTL	0x0B
+#define RT5190A_REG_PGSTAT	0x0F
+#define RT5190A_REG_OVINT	0x10
+#define RT5190A_REG_HOTDIEMASK	0x17
+
+#define RT5190A_VSEL_MASK	   GENMASK(6, 0)
+#define RT5190A_RID_BITMASK(rid)   BIT(rid + 1)
+#define RT5190A_BUCK1_DISCHG_MASK  GENMASK(1, 0)
+#define RT5190A_BUCK1_DISCHG_ONVAL 0x01
+#define RT5190A_OVERVOLT_MASK	   GENMASK(7, 0)
+#define RT5190A_UNDERVOLT_MASK	   GENMASK(15, 8)
+#define RT5190A_CH234OT_MASK	   BIT(29)
+#define RT5190A_CHIPOT_MASK	   BIT(28)
+
+#define RT5190A_BUCK23_MINUV   600000
+#define RT5190A_BUCK23_MAXUV   1400000
+#define RT5190A_BUCK23_STEPUV  10000
+#define RT5190A_BUCK23_STEPNUM ((1400000 - 600000) / 10000 + 1)
+
+enum {
+	RT5190A_IDX_BUCK1 = 0,
+	RT5190A_IDX_BUCK2,
+	RT5190A_IDX_BUCK3,
+	RT5190A_IDX_BUCK4,
+	RT5190A_IDX_LDO,
+	RT5190A_MAX_IDX
+};
+
+struct rt5190a_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_desc rdesc[RT5190A_MAX_IDX];
+	struct regulator_dev *rdev[RT5190A_MAX_IDX];
+};
+
+static int rt5190a_get_error_flags(struct regulator_dev *rdev,
+				   unsigned int *flags)
+{
+	struct regmap *regmap = rdev_get_regmap(rdev);
+	int rid = rdev_get_id(rdev);
+	unsigned int pgood_stat;
+	int ret;
+
+	ret = regmap_read(regmap, RT5190A_REG_PGSTAT, &pgood_stat);
+	if (ret)
+		return ret;
+
+	if (!(pgood_stat & RT5190A_RID_BITMASK(rid)))
+		*flags = REGULATOR_ERROR_FAIL;
+	else
+		*flags = 0;
+
+	return 0;
+}
+
+static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev,
+				       unsigned int mode)
+{
+	struct regmap *regmap = rdev_get_regmap(rdev);
+	int rid = rdev_get_id(rdev);
+	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		val = mask;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(regmap, RT5190A_REG_DCDCCNTL, mask, val);
+}
+
+static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev)
+{
+	struct regmap *regmap = rdev_get_regmap(rdev);
+	int rid = rdev_get_id(rdev);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(regmap, RT5190A_REG_DCDCCNTL, &val);
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to get mode [%d]\n", ret);
+		return ret;
+	}
+
+	if (val & RT5190A_RID_BITMASK(rid))
+		return REGULATOR_MODE_FAST;
+
+	return REGULATOR_MODE_NORMAL;
+}
+
+static const struct regulator_ops rt5190a_ranged_buck_ops = {
+	.enable = regulator_enable_regmap,
+	/*.disable = regulator_disable_regmap,*/
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+	.get_error_flags = rt5190a_get_error_flags,
+};
+
+static const struct regulator_ops rt5190a_fixed_buck_ops = {
+	.enable = regulator_enable_regmap,
+	/*.disable = regulator_disable_regmap,*/
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+	.set_mode = rt5190a_fixed_buck_set_mode,
+	.get_mode = rt5190a_fixed_buck_get_mode,
+	.get_error_flags = rt5190a_get_error_flags,
+};
+
+static const struct regulator_ops rt5190a_fixed_ldo_ops = {
+	.enable = regulator_enable_regmap,
+	/*.disable = regulator_disable_regmap,*/
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+	.get_error_flags = rt5190a_get_error_flags,
+};
+
+static const struct event {
+	unsigned int bitmask;
+	unsigned int report;
+};
+
+static const struct event event_tbl[] = {
+	{ RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT },
+	{ RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE }
+};
+
+static irqreturn_t rt5190a_irq_handler(int irq, void *data)
+{
+	struct rt5190a_priv *priv = data;
+	__le32 raws;
+	unsigned int events, fields;
+	int i, j, ret;
+
+	ret = regmap_raw_read(priv->regmap, RT5190A_REG_OVINT, &raws,
+			      sizeof(raws));
+	if (ret) {
+		dev_err(priv->dev, "Failed to read events\n");
+		return IRQ_NONE;
+	}
+
+	events = le32_to_cpu(raws);
+
+	ret = regmap_raw_write(priv->regmap, RT5190A_REG_OVINT, &raws,
+			       sizeof(raws));
+	if (ret)
+		dev_err(priv->dev, "Failed to write-clear events\n");
+
+	/* Handle OV,UV events */
+	for (i = 0; i < ARRAY_SIZE(event_tbl); i++) {
+		fields = events & event_tbl[i].bitmask;
+		fields >>= ffs(event_tbl[i].bitmask) - 1;
+
+		for (j = 0; j < RT5190A_MAX_IDX; j++) {
+			if (!(fields & RT5190A_RID_BITMASK(j)))
+				continue;
+
+			regulator_notifier_call_chain(
+				priv->rdev[j], event_tbl[i].report, NULL);
+		}
+	}
+
+	/* Handle CH234 OT event */
+	if (events & RT5190A_CH234OT_MASK) {
+		for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) {
+			regulator_notifier_call_chain(
+				priv->rdev[j], REGULATOR_ERROR_OVER_TEMP, NULL);
+		}
+	}
+
+	/* Warning if CHIP OT occur */
+	if (events & RT5190A_CHIPOT_MASK)
+		dev_warn(priv->dev, "CHIP overheat\n");
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int rt5190a_of_map_mode(unsigned int mode)
+{
+	switch (mode) {
+	case RT5190A_OPMODE_AUTO:
+		return REGULATOR_MODE_NORMAL;
+	case RT5190A_OPMODE_FPWM:
+		return REGULATOR_MODE_FAST;
+	default:
+		return REGULATOR_MODE_INVALID;
+	}
+}
+
+static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid,
+			       struct of_regulator_match *match)
+{
+	struct regulator_desc *desc = priv->rdesc + rid;
+	struct regulator_init_data *init_data = match->init_data;
+	struct device_node *np = match->of_node;
+	bool latchup_enable;
+	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
+
+	switch (rid) {
+	case RT5190A_IDX_BUCK1:
+	case RT5190A_IDX_BUCK4:
+	case RT5190A_IDX_LDO:
+		init_data->constraints.apply_uV = 0;
+
+		if (init_data->constraints.min_uV ==
+		    init_data->constraints.max_uV)
+			desc->fixed_uV = init_data->constraints.min_uV;
+		else {
+			dev_err(priv->dev,
+				"Variable voltage for fixed regulator\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	latchup_enable = of_property_read_bool(np, "richtek,latchup-enable");
+
+	/* latchup: 0, default hiccup: 1 */
+	val = !latchup_enable ? mask : 0;
+
+	return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask,
+				  val);
+}
+
+static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid)
+{
+	static const char *const regu_name[] = { "buck1", "buck2", "buck3",
+						 "buck4", "ldo" };
+	static const char *const supply[] = { NULL, "vin2", "vin3", "vin4",
+					      "vinldo" };
+
+	desc->name = regu_name[rid];
+	desc->supply_name = supply[rid];
+	desc->owner = THIS_MODULE;
+	desc->type = REGULATOR_VOLTAGE;
+	desc->id = rid;
+	desc->enable_reg = RT5190A_REG_ENABLE;
+	desc->enable_mask = RT5190A_RID_BITMASK(rid);
+	desc->active_discharge_reg = RT5190A_REG_DISCHARGE;
+	desc->active_discharge_mask = RT5190A_RID_BITMASK(rid);
+	desc->active_discharge_on = RT5190A_RID_BITMASK(rid);
+
+	switch (rid) {
+	case RT5190A_IDX_BUCK1:
+		desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK;
+		desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL;
+		desc->n_voltages = 1;
+		desc->ops = &rt5190a_fixed_buck_ops;
+		desc->of_map_mode = rt5190a_of_map_mode;
+		break;
+	case RT5190A_IDX_BUCK2:
+		desc->vsel_reg = RT5190A_REG_BUCK2VSEL;
+		desc->vsel_mask = RT5190A_VSEL_MASK;
+		desc->min_uV = RT5190A_BUCK23_MINUV;
+		desc->uV_step = RT5190A_BUCK23_STEPUV;
+		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
+		desc->ops = &rt5190a_ranged_buck_ops;
+		break;
+	case RT5190A_IDX_BUCK3:
+		desc->vsel_reg = RT5190A_REG_BUCK3VSEL;
+		desc->vsel_mask = RT5190A_VSEL_MASK;
+		desc->min_uV = RT5190A_BUCK23_MINUV;
+		desc->uV_step = RT5190A_BUCK23_STEPUV;
+		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
+		desc->ops = &rt5190a_ranged_buck_ops;
+		break;
+	case RT5190A_IDX_BUCK4:
+		desc->n_voltages = 1;
+		desc->ops = &rt5190a_fixed_buck_ops;
+		desc->of_map_mode = rt5190a_of_map_mode;
+		break;
+	case RT5190A_IDX_LDO:
+		desc->n_voltages = 1;
+		desc->ops = &rt5190a_fixed_ldo_ops;
+		break;
+	}
+}
+
+static struct of_regulator_match rt5190a_regulator_match[] = {
+	{
+		.name = "buck1",
+	},
+	{
+		.name = "buck2",
+	},
+	{
+		.name = "buck3",
+	},
+	{
+		.name = "buck4",
+	},
+	{
+		.name = "ldo",
+	}
+};
+
+static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv)
+{
+	struct device_node *regulator_np;
+	struct regulator_desc *reg_desc;
+	struct of_regulator_match *match;
+	int i, ret;
+
+	for (i = 0; i < RT5190A_MAX_IDX; i++) {
+		reg_desc = priv->rdesc + i;
+		match = rt5190a_regulator_match + i;
+
+		rt5190a_fillin_regulator_desc(reg_desc, i);
+
+		match->desc = reg_desc;
+	}
+
+	regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators");
+	if (!regulator_np) {
+		dev_err(priv->dev, "Could not find 'regulators' node\n");
+		return -ENODEV;
+	}
+
+	ret = of_regulator_match(priv->dev, regulator_np,
+				 rt5190a_regulator_match,
+				 ARRAY_SIZE(rt5190a_regulator_match));
+
+	of_node_put(regulator_np);
+
+	if (ret < 0) {
+		dev_err(priv->dev, "Error parsing regulator init data: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < RT5190A_MAX_IDX; i++) {
+		match = rt5190a_regulator_match + i;
+
+		ret = rt5190a_of_parse_cb(priv, i, match);
+		if (ret) {
+			dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct reg_sequence rt5190a_init_patch[] = { {
+								  0x09,
+								  0x3d,
+							  },
+							{
+								  0x0a,
+								  0x3e,
+							  },
+							{
+								  0x0b,
+								  0x01,
+							  },
+							{
+								  0x10,
+								  0xff,
+							  },
+							{
+								  0x11,
+								  0xff,
+							  },
+							{
+								  0x12,
+								  0xff,
+							  },
+							{
+								  0x13,
+								  0xff,
+							  },
+							{
+								  0x14,
+								  0,
+							  },
+							{
+								  0x15,
+								  0,
+							  },
+							{
+								  0x16,
+								  0x3e,
+							  },
+							{
+								  0x17,
+								  0,
+							  } };
+
+static int rt5190a_device_initialize(struct rt5190a_priv *priv)
+{
+	bool mute_enable;
+	int ret;
+
+	ret = regmap_register_patch(priv->regmap, rt5190a_init_patch,
+				    ARRAY_SIZE(rt5190a_init_patch));
+	if (ret) {
+		dev_err(priv->dev, "Failed to do register patch\n");
+		return ret;
+	}
+
+	mute_enable =
+		device_property_read_bool(priv->dev, "richtek,mute-enable");
+
+	if (mute_enable) {
+		ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00);
+		if (ret) {
+			dev_err(priv->dev, "Failed to enable mute function\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rt5190a_device_check(struct rt5190a_priv *priv)
+{
+	u16 devid;
+	int ret;
+
+	ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid,
+			      sizeof(devid));
+	if (ret)
+		return ret;
+
+	if (devid) {
+		dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config rt5190a_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = RT5190A_REG_HOTDIEMASK,
+};
+
+static int rt5190a_probe(struct i2c_client *i2c)
+{
+	struct rt5190a_priv *priv;
+	struct regulator_config cfg = {};
+	int i, ret;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &i2c->dev;
+
+	priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config);
+	if (IS_ERR(priv->regmap)) {
+		dev_err(&i2c->dev, "Failed to allocate regmap\n");
+		return PTR_ERR(priv->regmap);
+	}
+
+	ret = rt5190a_device_check(priv);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to check device %d\n", ret);
+		return ret;
+	}
+
+	ret = rt5190a_device_initialize(priv);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to initialize the device\n");
+		return ret;
+	}
+
+	ret = rt5190a_parse_regulator_dt_data(priv);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to parse regulator dt\n");
+		return ret;
+	}
+
+	cfg.dev = &i2c->dev;
+	cfg.regmap = priv->regmap;
+
+	for (i = 0; i < RT5190A_MAX_IDX; i++) {
+		struct regulator_desc *desc = priv->rdesc + i;
+		struct of_regulator_match *match = rt5190a_regulator_match + i;
+
+		cfg.init_data = match->init_data;
+		cfg.of_node = match->of_node;
+
+		priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg);
+		if (IS_ERR(priv->rdev[i])) {
+			dev_err(&i2c->dev, "Failed to register regulator %s\n",
+				desc->name);
+			return PTR_ERR(priv->rdev[i]);
+		}
+	}
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+						rt5190a_irq_handler,
+						IRQF_ONESHOT,
+						dev_name(&i2c->dev), priv);
+		if (ret) {
+			dev_err(&i2c->dev, "Failed to register interrupt\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id __maybe_unused rt5190a_device_table[] = {
+	{
+		.compatible = "richtek,rt5190a",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, rt5190a_device_table);
+
+static struct i2c_driver rt5190a_driver = {
+	.driver = {
+		.name = "rt5190a",
+		.of_match_table = rt5190a_device_table,
+	},
+	.probe_new = rt5190a_probe,
+};
+module_i2c_driver(rt5190a_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mt7988-pm-domains.h b/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mt7988-pm-domains.h
new file mode 100644
index 0000000..f7db02c
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mt7988-pm-domains.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ */
+
+#ifndef __SOC_MEDIATEK_MT7988_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT7988_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+//#include "mt7988-power.h"
+#include <dt-bindings/power/mt7988-power.h>
+
+/*
+ * MT8139 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt7988[] = {
+	[MT7988_POWER_DOMAIN_TOPS0] = {
+		.sta_mask = BIT(30),
+		.sta_2nd_mask = BIT(31),
+		.pwr_sta_offs = 0x040,
+		.pwr_sta_2nd_offs = 0x040,
+		.pwr_on_bit = BIT(1),
+		.pwr_on_2nd_bit = BIT(2),
+		.pwr_on_offs  = 0x040,
+		.pwr_on_2nd_offs = 0x040,
+		.pwr_clamp_bit = BIT(4),
+		.pwr_rst_bit = BIT(0),
+		.sram_pdn_bit = BIT(2),
+		.sram_pdn_ack_bit = BIT(28),
+		.sram_clk_iso_bit = BIT(0),
+		.sram_ctrl_offs = 0x048,
+		.sram_2nd_pdn_bit = BIT(8),
+		.sram_2nd_pdn_ack_bit = BIT(24),
+		.sram_2nd_clk_iso_bit = BIT(5),
+		.sram_2nd_clk_dis_bit = BIT(3),
+		.sram_2nd_ctrl_offs = 0x040,
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT7988_POWER_DOMAIN_TOPS1] = {
+		.sta_mask = BIT(30),
+		.sta_2nd_mask = BIT(31),
+		.pwr_sta_offs = 0x044,
+		.pwr_sta_2nd_offs = 0x044,
+		.pwr_on_bit = BIT(1),
+		.pwr_on_2nd_bit = BIT(2),
+		.pwr_on_offs  = 0x044,
+		.pwr_on_2nd_offs = 0x044,
+		.pwr_clamp_bit = BIT(4),
+		.pwr_rst_bit = BIT(0),
+		.sram_pdn_bit = BIT(6),
+		.sram_pdn_ack_bit = BIT(30),
+		.sram_clk_iso_bit = BIT(4),
+		.sram_ctrl_offs = 0x048,
+		.sram_2nd_pdn_bit = BIT(8),
+		.sram_2nd_pdn_ack_bit = BIT(24),
+		.sram_2nd_clk_iso_bit = BIT(5),
+		.sram_2nd_clk_dis_bit = BIT(3),
+		.sram_2nd_ctrl_offs = 0x044,
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+
+	},
+	[MT7988_POWER_DOMAIN_ETH2P5] = {
+		.sta_mask = BIT(30),
+		.sta_2nd_mask = BIT(31),
+		.pwr_sta_offs = 0x060,
+		.pwr_sta_2nd_offs = 0x060,
+		.pwr_on_bit = BIT(1),
+		.pwr_on_2nd_bit = BIT(2),
+		.pwr_on_offs  = 0x060,
+		.pwr_on_2nd_offs = 0x060,
+		.pwr_clamp_bit = BIT(4),
+	    .pwr_rst_bit = BIT(0),
+		.sram_2nd_pdn_bit = BIT(8),
+		.sram_2nd_clk_dis_bit = BIT(5),
+		.sram_2nd_ctrl_offs = 0x060,
+		.caps = MTK_SCPD_CLAMP_PROTECTION,
+
+	},
+
+};
+
+static const struct scpsys_soc_data mt7988_scpsys_data = {
+	.domains_data = scpsys_domain_data_mt7988,
+	.num_domains = ARRAY_SIZE(scpsys_domain_data_mt7988),
+};
+
+#endif /* __SOC_MEDIATEK_MT7988_PM_DOMAINS_H */
diff --git a/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.c b/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.c
new file mode 100644
index 0000000..fc6b5ff
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Collabora Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+#include <linux/soc/mediatek/infracfg.h>
+#include <linux/regulator/consumer.h>
+
+#include "mt7988-pm-domains.h"
+
+#define MTK_POLL_DELAY_US 30
+#define MTK_POLL_TIMEOUT  USEC_PER_SEC
+
+struct scpsys_domain {
+	struct generic_pm_domain genpd;
+	const struct scpsys_domain_data *data;
+	struct scpsys *scpsys;
+	int num_clks;
+	struct clk_bulk_data *clks;
+	int num_subsys_clks;
+	struct clk_bulk_data *subsys_clks;
+	struct regmap *infracfg;
+	struct regulator *supply;
+};
+
+struct scpsys {
+	struct device *dev;
+	struct regmap *base;
+	const struct scpsys_soc_data *soc_data;
+	struct genpd_onecell_data pd_data;
+	struct generic_pm_domain *domains[];
+};
+
+static inline int mtk_regmap_set_bits(struct regmap *map, unsigned int reg,
+				      unsigned int bits)
+{
+	return regmap_update_bits_base(map, reg, bits, bits, NULL, false,
+				       false);
+}
+
+static inline int mtk_regmap_clear_bits(struct regmap *map, unsigned int reg,
+					unsigned int bits)
+{
+	return regmap_update_bits_base(map, reg, bits, 0, NULL, false, false);
+}
+
+#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
+
+static bool scpsys_domain_is_on(struct scpsys_domain *pd)
+{
+	struct scpsys *scpsys = pd->scpsys;
+	u32 status = 0, status2 = 0;
+
+	regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
+	status &= pd->data->sta_mask;
+
+	regmap_read(scpsys->base, pd->data->pwr_sta_2nd_offs, &status2);
+	status2 &= pd->data->sta_2nd_mask;
+
+	/* A domain is on when both status bits are set. */
+	return status && status2;
+}
+
+static int scpsys_sram_enable(struct scpsys_domain *pd)
+{
+	u32 pdn_ack = pd->data->sram_pdn_ack_bit;
+	u32 pdn_2nd_ack = pd->data->sram_2nd_pdn_ack_bit;
+	struct scpsys *scpsys = pd->scpsys;
+	unsigned int tmp = 0;
+	int ret;
+
+	if (pd->data->sram_pdn_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				      pd->data->sram_pdn_bit);
+
+		/* Either wait until SRAM_PDN_ACK all 1 or 0 */
+		ret = regmap_read_poll_timeout(scpsys->base,
+					       pd->data->sram_ctrl_offs, tmp,
+					       (tmp & pdn_ack) == 0,
+					       MTK_POLL_DELAY_US,
+					       MTK_POLL_TIMEOUT);
+		if (ret < 0)
+			return ret;
+	}
+	if (pd->data->sram_2nd_pdn_bit) {
+		/* sram pdn 2nd for special mtcmos */
+		mtk_regmap_clear_bits(scpsys->base,
+				      pd->data->sram_2nd_ctrl_offs,
+				      pd->data->sram_2nd_pdn_bit);
+
+		ret = regmap_read_poll_timeout(scpsys->base,
+					       pd->data->sram_2nd_ctrl_offs,
+					       tmp, (tmp & pdn_2nd_ack) == 0,
+					       MTK_POLL_DELAY_US,
+					       MTK_POLL_TIMEOUT);
+		if (ret < 0)
+			return ret;
+	}
+	if (pd->data->sram_clk_iso_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				      pd->data->sram_clk_iso_bit);
+	}
+	if (pd->data->sram_clk_dis_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				      pd->data->sram_clk_dis_bit);
+	}
+	if (pd->data->sram_2nd_clk_iso_bit) {
+		mtk_regmap_clear_bits(scpsys->base,
+				      pd->data->sram_2nd_ctrl_offs,
+				      pd->data->sram_2nd_clk_iso_bit);
+	}
+	if (pd->data->sram_2nd_clk_dis_bit) {
+		mtk_regmap_clear_bits(scpsys->base,
+				      pd->data->sram_2nd_ctrl_offs,
+				      pd->data->sram_2nd_clk_dis_bit);
+	}
+
+	return 0;
+}
+
+static int scpsys_sram_disable(struct scpsys_domain *pd)
+{
+	u32 pdn_ack = pd->data->sram_pdn_ack_bit;
+	u32 pdn_2nd_ack = pd->data->sram_2nd_pdn_ack_bit;
+	struct scpsys *scpsys = pd->scpsys;
+	unsigned int tmp = 0;
+	int ret;
+
+	if (pd->data->sram_2nd_clk_dis_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
+				    pd->data->sram_2nd_clk_dis_bit);
+	}
+	if (pd->data->sram_clk_iso_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				    pd->data->sram_clk_iso_bit);
+		udelay(1);
+	}
+	if (pd->data->sram_pdn_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				    pd->data->sram_pdn_bit);
+	}
+
+	if (pd->data->sram_2nd_clk_iso_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
+				    pd->data->sram_2nd_clk_iso_bit);
+		udelay(1);
+	}
+	if (pd->data->sram_2nd_pdn_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
+				    pd->data->sram_2nd_pdn_bit);
+	}
+
+	return 0;
+}
+
+static int scpsys_regulator_get(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	struct device_node *node;
+	struct device_node *root;
+
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY) && !pd->supply) {
+		root = pd->scpsys->dev->of_node;
+		node = of_find_node_by_name(root, genpd->name);
+		if (node) {
+			pd->scpsys->dev->of_node = node;
+			pd->supply =
+				devm_regulator_get(pd->scpsys->dev, "domain");
+			pd->scpsys->dev->of_node = root;
+			if (IS_ERR(pd->supply))
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int scpsys_regulator_enable(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	int ret = scpsys_regulator_get(genpd);
+
+	if (ret)
+		return ret;
+
+	return pd->supply ? regulator_enable(pd->supply) : 0;
+}
+
+static int scpsys_regulator_disable(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+
+	return pd->supply ? regulator_disable(pd->supply) : 0;
+}
+
+static int scpsys_power_on(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	struct scpsys *scpsys = pd->scpsys;
+	bool tmp;
+	int ret;
+
+	ret = scpsys_regulator_enable(genpd);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
+	if (ret)
+		goto err_pwr_ack;
+
+	/* subsys power on */
+	mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
+			    pd->data->pwr_on_bit);
+	mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_2nd_offs,
+			    pd->data->pwr_on_2nd_bit);
+
+	/* wait until PWR_ACK = 1 */
+	ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp,
+				 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+	if (ret < 0)
+		goto err_pwr_ack;
+	udelay(30);
+
+	if (pd->data->pwr_clamp_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
+				      pd->data->pwr_clamp_bit);
+		udelay(30);
+	}
+
+	if (pd->data->pwr_rst_bit)
+		mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
+				    pd->data->pwr_rst_bit);
+
+	ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
+	if (ret)
+		goto err_disable_subsys_clks;
+
+	ret = scpsys_sram_enable(pd);
+	if (ret < 0)
+		goto err_disable_sram;
+
+	return 0;
+
+err_disable_sram:
+	scpsys_sram_disable(pd);
+err_disable_subsys_clks:
+	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+err_pwr_ack:
+	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
+err_reg:
+	scpsys_regulator_disable(genpd);
+	return ret;
+}
+
+static int scpsys_power_off(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	struct scpsys *scpsys = pd->scpsys;
+	bool tmp;
+	int ret;
+
+	ret = scpsys_sram_disable(pd);
+	if (ret < 0)
+		return ret;
+
+	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+
+	if (pd->data->pwr_clamp_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
+				    pd->data->pwr_clamp_bit);
+		udelay(30);
+	}
+	if (pd->data->pwr_rst_bit)
+		mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
+				      pd->data->pwr_rst_bit);
+
+	mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
+			      pd->data->pwr_on_bit);
+	mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_2nd_offs,
+			      pd->data->pwr_on_2nd_bit);
+
+	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
+	scpsys_regulator_disable(genpd);
+
+	return 0;
+}
+
+static struct generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys,
+						       struct device_node *node)
+{
+	const struct scpsys_domain_data *domain_data;
+	struct scpsys_domain *pd;
+	struct property *prop;
+	const char *clk_name;
+	int i, ret, num_clks;
+	struct clk *clk;
+	struct device_node *smi_node;
+	struct device_node *larb_node;
+	int clk_ind = 0;
+	u32 id;
+
+	ret = of_property_read_u32(node, "reg", &id);
+	if (ret) {
+		dev_err(scpsys->dev,
+			"%pOF: failed to retrieve domain id from reg: %d\n",
+			node, ret);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (id >= scpsys->soc_data->num_domains) {
+		dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	domain_data = &scpsys->soc_data->domains_data[id];
+	if (domain_data->sta_mask == 0) {
+		dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node,
+			id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return ERR_PTR(-ENOMEM);
+
+	pd->data = domain_data;
+	pd->scpsys = scpsys;
+
+	num_clks = of_clk_get_parent_count(node);
+	if (num_clks > 0) {
+		/* Calculate number of subsys_clks */
+		of_property_for_each_string(node, "clock-names", prop,
+					     clk_name) {
+			char *subsys;
+
+			subsys = strchr(clk_name, '-');
+			if (subsys)
+				pd->num_subsys_clks++;
+			else
+				pd->num_clks++;
+		}
+
+		pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks,
+					sizeof(*pd->clks), GFP_KERNEL);
+		if (!pd->clks)
+			return ERR_PTR(-ENOMEM);
+
+		pd->subsys_clks =
+			devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
+				     sizeof(*pd->subsys_clks), GFP_KERNEL);
+		if (!pd->subsys_clks)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	for (i = 0; i < pd->num_clks; i++) {
+		clk = of_clk_get(node, i);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			dev_err(scpsys->dev,
+				"%pOF: failed to get clk at index %d: %d\n",
+				node, i, ret);
+			goto err_put_clocks;
+		}
+
+		pd->clks[clk_ind++].clk = clk;
+	}
+
+	for (i = 0; i < pd->num_subsys_clks; i++) {
+		clk = of_clk_get(node, i + clk_ind);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			dev_err(scpsys->dev,
+				"%pOF: failed to get clk at index %d: %d\n",
+				node, i + clk_ind, ret);
+			goto err_put_subsys_clocks;
+		}
+
+		pd->subsys_clks[i].clk = clk;
+	}
+
+	/*
+	 * Initially turn on all domains to make the domains usable
+	 * with !CONFIG_PM and to get the hardware in sync with the
+	 * software.  The unused domains will be switched off during
+	 * late_init time.
+	 */
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
+		if (scpsys_domain_is_on(pd))
+			dev_warn(
+				scpsys->dev,
+				"%pOF: A default off power domain has been ON\n",
+				node);
+	} else {
+		ret = scpsys_power_on(&pd->genpd);
+		if (ret < 0) {
+			dev_err(scpsys->dev,
+				"%pOF: failed to power on domain: %d\n", node,
+				ret);
+			goto err_put_subsys_clocks;
+		}
+	}
+
+	if (scpsys->domains[id]) {
+		ret = -EINVAL;
+		dev_err(scpsys->dev,
+			"power domain with id %d already exists, check your device-tree\n",
+			id);
+		goto err_put_subsys_clocks;
+	}
+
+	pd->genpd.name = node->name;
+	pd->genpd.power_off = scpsys_power_off;
+	pd->genpd.power_on = scpsys_power_on;
+
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
+		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
+		pm_genpd_init(&pd->genpd, NULL, true);
+	else
+		pm_genpd_init(&pd->genpd, NULL, false);
+
+	scpsys->domains[id] = &pd->genpd;
+
+	return scpsys->pd_data.domains[id];
+
+err_put_subsys_clocks:
+	clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
+err_put_clocks:
+	clk_bulk_put(pd->num_clks, pd->clks);
+	return ERR_PTR(ret);
+}
+
+static int scpsys_add_subdomain(struct scpsys *scpsys,
+				struct device_node *parent)
+{
+	struct generic_pm_domain *child_pd, *parent_pd;
+	struct device_node *child;
+	int ret;
+
+	for_each_child_of_node(parent, child) {
+		u32 id;
+
+		ret = of_property_read_u32(parent, "reg", &id);
+		if (ret) {
+			dev_err(scpsys->dev,
+				"%pOF: failed to get parent domain id\n",
+				child);
+			goto err_put_node;
+		}
+
+		if (!scpsys->pd_data.domains[id]) {
+			ret = -EINVAL;
+			dev_err(scpsys->dev,
+				"power domain with id %d does not exist\n", id);
+			goto err_put_node;
+		}
+
+		parent_pd = scpsys->pd_data.domains[id];
+
+		child_pd = scpsys_add_one_domain(scpsys, child);
+		if (IS_ERR(child_pd)) {
+			ret = PTR_ERR(child_pd);
+			dev_err(scpsys->dev,
+				"%pOF: failed to get child domain id\n", child);
+			goto err_put_node;
+		}
+
+		ret = pm_genpd_add_subdomain(parent_pd, child_pd);
+		if (ret) {
+			dev_err(scpsys->dev,
+				"failed to add %s subdomain to parent %s\n",
+				child_pd->name, parent_pd->name);
+			goto err_put_node;
+		} else {
+			dev_dbg(scpsys->dev, "%s add subdomain: %s\n",
+				parent_pd->name, child_pd->name);
+		}
+
+		/* recursive call to add all subdomains */
+		ret = scpsys_add_subdomain(scpsys, child);
+		if (ret)
+			goto err_put_node;
+	}
+
+	return 0;
+
+err_put_node:
+	of_node_put(child);
+	return ret;
+}
+
+static void scpsys_remove_one_domain(struct scpsys_domain *pd)
+{
+	int ret;
+
+	if (scpsys_domain_is_on(pd))
+		scpsys_power_off(&pd->genpd);
+
+	/*
+	 * We're in the error cleanup already, so we only complain,
+	 * but won't emit another error on top of the original one.
+	 */
+	ret = pm_genpd_remove(&pd->genpd);
+	if (ret < 0)
+		dev_err(pd->scpsys->dev,
+			"failed to remove domain '%s' : %d - state may be inconsistent\n",
+			pd->genpd.name, ret);
+
+	clk_bulk_put(pd->num_clks, pd->clks);
+	clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
+}
+
+static void scpsys_domain_cleanup(struct scpsys *scpsys)
+{
+	struct generic_pm_domain *genpd;
+	struct scpsys_domain *pd;
+	int i;
+
+	for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
+		genpd = scpsys->pd_data.domains[i];
+		if (genpd) {
+			pd = to_scpsys_domain(genpd);
+			scpsys_remove_one_domain(pd);
+		}
+	}
+}
+
+static const struct of_device_id scpsys_of_match[] = {
+	{
+		.compatible = "mediatek,mt7988-power-controller",
+		.data = &mt7988_scpsys_data,
+	},
+	{}
+};
+
+static int scpsys_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct scpsys_soc_data *soc;
+	struct device_node *node;
+	struct scpsys *scpsys;
+	struct resource *res;
+	int ret;
+
+	soc = of_device_get_match_data(&pdev->dev);
+	if (!soc) {
+		dev_err(&pdev->dev, "no power controller data\n");
+		return -EINVAL;
+	}
+
+	scpsys = devm_kzalloc(dev,
+			      struct_size(scpsys, domains, soc->num_domains),
+			      GFP_KERNEL);
+	if (!scpsys)
+		return -ENOMEM;
+
+	scpsys->dev = dev;
+	scpsys->soc_data = soc;
+
+	scpsys->pd_data.domains = scpsys->domains;
+	scpsys->pd_data.num_domains = soc->num_domains;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	scpsys->base = syscon_node_to_regmap(np);
+	if (IS_ERR(scpsys->base)) {
+		dev_err(dev, "no regmap available\n");
+		return PTR_ERR(scpsys->base);
+	}
+
+	ret = -ENODEV;
+	for_each_available_child_of_node(np, node) {
+		struct generic_pm_domain *domain;
+
+		domain = scpsys_add_one_domain(scpsys, node);
+		if (IS_ERR(domain)) {
+			ret = PTR_ERR(domain);
+			of_node_put(node);
+			goto err_cleanup_domains;
+		}
+
+		ret = scpsys_add_subdomain(scpsys, node);
+		if (ret) {
+			of_node_put(node);
+			goto err_cleanup_domains;
+		}
+	}
+
+	if (ret) {
+		dev_dbg(dev, "no power domains present\n");
+		return ret;
+	}
+
+	ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data);
+	if (ret) {
+		dev_err(dev, "failed to add provider: %d\n", ret);
+		goto err_cleanup_domains;
+	}
+
+	return 0;
+
+err_cleanup_domains:
+	scpsys_domain_cleanup(scpsys);
+	return ret;
+}
+
+static struct platform_driver scpsys_pm_domain_driver = {
+	.probe = scpsys_probe,
+	.driver = {
+		.name = "mtk-power-controller",
+		.suppress_bind_attrs = true,
+		.of_match_table = scpsys_of_match,
+	},
+};
+builtin_platform_driver(scpsys_pm_domain_driver);
diff --git a/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.h b/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.h
new file mode 100644
index 0000000..853f5e6
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MTK_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MTK_PM_DOMAINS_H
+
+#define MTK_SCPD_ACTIVE_WAKEUP		BIT(0)
+#define MTK_SCPD_FWAIT_SRAM		BIT(1)
+#define MTK_SCPD_SRAM_ISO		BIT(2)
+#define MTK_SCPD_KEEP_DEFAULT_OFF	BIT(3)
+#define MTK_SCPD_DOMAIN_SUPPLY		BIT(4)
+#define MTK_SCPD_CLAMP_PROTECTION	BIT(5)
+#define MTK_SCPD_CAPS(_scpd, _x)	((_scpd)->data->caps & (_x))
+
+/**
+ * struct scpsys_domain_data - scp domain data for power on/off flow
+ * @sta_mask: The mask for power on/off status bit.
+ * @sta_2nd_mask: The mask for 2nd power on/off status bit.
+ * @pwr_sta_offs: the main power status register.
+ * @pwr_sta_2nd_offs: the 2nd power status register.
+ * @pwr_on_bit: The power on/off bit.
+ * @pwr_on_2nd_bit: The 2nd power on/off bit.
+ * @pwr_on_offs: The offset for main power control register.
+ * @pwr_on_2nd_offs: The offset for 2nd power control register.
+ * @sram_pdn_bit: The mask for sram power control bit.
+ * @sram_pdn_ack_bit: The sram power control acked bit.
+ * @sram_clk_iso_bit: The sram  clk iso bit.
+ * @sram_clk_dis_bit: The sram clk disable bit.
+ * @sram_ctrl_offs: The sram power control register.
+ * @caps: The flag for active wake-up action.
+ * @bp_infracfg: bus protection for infracfg subsystem
+ */
+struct scpsys_domain_data {
+	u32 sta_mask;
+	u32 sta_2nd_mask;
+	int pwr_sta_offs;
+	int pwr_sta_2nd_offs;
+	u32 pwr_on_bit;
+	u32 pwr_on_2nd_bit;
+	int pwr_on_offs;
+	int pwr_on_2nd_offs;
+	u32 pwr_clamp_bit;
+	u32 pwr_rst_bit;
+	u32 sram_pdn_bit;
+	u32 sram_pdn_ack_bit;
+	u32 sram_clk_iso_bit;
+	u32 sram_clk_dis_bit;
+	int sram_ctrl_offs;
+	u32 sram_2nd_pdn_bit;
+	u32 sram_2nd_pdn_ack_bit;
+	u32 sram_2nd_clk_iso_bit;
+	u32 sram_2nd_clk_dis_bit;
+	int sram_2nd_ctrl_offs;
+	u8 caps;
+
+};
+
+struct scpsys_soc_data {
+	const struct scpsys_domain_data *domains_data;
+	int num_domains;
+};
+
+#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */
diff --git a/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/Kconfig b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/Kconfig
new file mode 100644
index 0000000..edc0aa4
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/Kconfig
@@ -0,0 +1,9 @@
+config MTK_SOC_THERMAL_LVTS
+        tristate "LVTS (Low voltage thermal sensor) driver for Mediatek SoCs"
+        depends on HAS_IOMEM
+        depends on NVMEM
+        help
+          Enable this option if you want to get SoC temperature
+          information for Mediatek platforms. This driver
+          configures LVTS thermal controllers to collect temperatures
+          via Analog Serial Interface(ASIF).
diff --git a/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/Makefile b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/Makefile
new file mode 100644
index 0000000..c9225cb
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTK_SOC_THERMAL_LVTS)	+= soc_temp_lvts.o
diff --git a/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.c b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.c
new file mode 100644
index 0000000..570ac17
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.c
@@ -0,0 +1,1895 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Henry Yen <henry.yen@mediatek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/thermal.h>
+#include "soc_temp_lvts.h"
+
+/*
+ * Definition or macro function
+ */
+#define STOP_COUNTING_V5	     (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
+#define SET_RG_TSFM_LPDLY_V5	     (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
+#define SET_COUNTING_WINDOW_20US1_V5 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
+#define SET_COUNTING_WINDOW_20US2_V5 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20)
+#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V5                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x8C)
+#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V5                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0xFC)
+#define SET_TS_RSV_V5 (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D)
+#define SET_TS_EN_V5  (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF1)
+
+#define SET_MANUAL_RCK_V5	  (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x00)
+#define SELECT_SENSOR_RCK_V5(id)  (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id))
+#define SET_DEVICE_SINGLE_MODE_V5 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
+#define KICK_OFF_RCK_COUNTING_V5  (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02)
+#define SET_SENSOR_NO_RCK_V5(id)                                               \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10 | (id))
+#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V5                                    \
+	(DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
+
+#define STOP_COUNTING_V4	     (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
+#define SET_RG_TSFM_LPDLY_V4	     (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
+#define SET_COUNTING_WINDOW_20US1_V4 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
+#define SET_COUNTING_WINDOW_20US2_V4 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20)
+#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x84)
+#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0x7C)
+#define SET_TS_RSV_V4		    (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D)
+#define SET_TS_EN_V4		    (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4)
+#define TOGGLE_RG_TSV2F_VCO_RST1_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xFC)
+#define TOGGLE_RG_TSV2F_VCO_RST2_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4)
+
+#define SET_LVTS_AUTO_RCK_V4	  (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x01)
+#define SELECT_SENSOR_RCK_V4(id)  (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id))
+#define SET_DEVICE_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0x78)
+#define KICK_OFF_RCK_COUNTING_V4  (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02)
+#define SET_SENSOR_NO_RCK_V4	  (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10)
+#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V4                                    \
+	(DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
+
+#define ENABLE_FEATURE(feature)	 (lvts_data->feature_bitmap |= (feature))
+#define DISABLE_FEATURE(feature) (lvts_data->feature_bitmap &= (~(feature)))
+#define IS_ENABLE(feature)	 (lvts_data->feature_bitmap & (feature))
+
+#define DISABLE_THERMAL_HW_REBOOT (-274000)
+
+#define CLOCK_26MHZ_CYCLE_NS	(38)
+#define BUS_ACCESS_US		(2)
+#define GOLDEN_TEMP_MAX		(62)
+#define FEATURE_DEVICE_AUTO_RCK (BIT(0))
+#define FEATURE_CK26M_ACTIVE	(BIT(1))
+#define FEATURE_IRQ		(BIT(2))
+#define FEATURE_RESET		(BIT(3))
+#define CK26M_ACTIVE                                                           \
+	(((lvts_data->feature_bitmap & FEATURE_CK26M_ACTIVE) ? 1 : 0) << 30)
+#define GET_BASE_ADDR(tc_id)                                                   \
+	(lvts_data->domain[lvts_data->tc[tc_id].domain_index].base +           \
+	 lvts_data->tc[tc_id].addr_offset)
+
+#define SET_TC_SPEED_IN_US(pu, gd, fd, sd)                                     \
+	{                                                                      \
+		.period_unit = (((pu)*1000) / (256 * CLOCK_26MHZ_CYCLE_NS)),   \
+		.group_interval_delay = ((gd) / (pu)),                         \
+		.filter_interval_delay = ((fd) / (pu)),                        \
+		.sensor_interval_delay = ((sd) / (pu)),                        \
+	}
+
+#define GET_CAL_DATA_BITMASK(index, h, l)                                      \
+	(((index) < lvts_data->num_efuse_addr) ?                               \
+		 ((lvts_data->efuse[(index)] & GENMASK(h, l)) >> l) :          \
+		 0)
+
+#define GET_CAL_DATA_BIT(index, bit)                                           \
+	(((index) < lvts_data->num_efuse_addr) ?                               \
+		 ((lvts_data->efuse[index] & BIT(bit)) >> (bit)) :             \
+		 0)
+
+#define GET_TC_SENSOR_NUM(tc_id) (lvts_data->tc[tc_id].num_sensor)
+
+#define ONE_SAMPLE (lvts_data->counting_window_us + 2 * BUS_ACCESS_US)
+
+#define NUM_OF_SAMPLE(tc_id)                                                   \
+	((lvts_data->tc[tc_id].hw_filter < LVTS_FILTER_2) ?                    \
+		 1 :                                                           \
+		 ((lvts_data->tc[tc_id].hw_filter > LVTS_FILTER_16_OF_18) ?    \
+			  1 :                                                  \
+			  ((lvts_data->tc[tc_id].hw_filter ==                  \
+			    LVTS_FILTER_16_OF_18) ?                            \
+				   18 :                                        \
+				   ((lvts_data->tc[tc_id].hw_filter ==         \
+				     LVTS_FILTER_8_OF_10) ?                    \
+					    10 :                               \
+					    (lvts_data->tc[tc_id].hw_filter *  \
+					     2)))))
+
+#define PERIOD_UNIT_US(tc_id)                                                  \
+	((lvts_data->tc[tc_id].tc_speed.period_unit * 256 *                    \
+	  CLOCK_26MHZ_CYCLE_NS) /                                              \
+	 1000)
+#define FILTER_INT_US(tc_id)                                                   \
+	(lvts_data->tc[tc_id].tc_speed.filter_interval_delay *                 \
+	 PERIOD_UNIT_US(tc_id))
+#define SENSOR_INT_US(tc_id)                                                   \
+	(lvts_data->tc[tc_id].tc_speed.sensor_interval_delay *                 \
+	 PERIOD_UNIT_US(tc_id))
+#define GROUP_INT_US(tc_id)                                                    \
+	(lvts_data->tc[tc_id].tc_speed.group_interval_delay *                  \
+	 PERIOD_UNIT_US(tc_id))
+
+#define SENSOR_LATENCY_US(tc_id)                                               \
+	((NUM_OF_SAMPLE(tc_id) - 1) * FILTER_INT_US(tc_id) +                   \
+	 NUM_OF_SAMPLE(tc_id) * ONE_SAMPLE)
+
+#define GROUP_LATENCY_US(tc_id)                                                \
+	(GET_TC_SENSOR_NUM(tc_id) * SENSOR_LATENCY_US(tc_id) +                 \
+	 (GET_TC_SENSOR_NUM(tc_id) - 1) * SENSOR_INT_US(tc_id) +               \
+	 GROUP_INT_US(tc_id))
+
+/*
+ * LVTS local common code
+ */
+static int lvts_raw_to_temp(struct formula_coeff *co, unsigned int msr_raw)
+{
+	/* This function returns degree mC */
+
+	int temp;
+
+	msr_raw &= 0xffff;
+	temp = (co->a * ((unsigned long long)msr_raw)) >> 14;
+	temp = temp + co->golden_temp * 500 + co->b;
+
+	return temp;
+}
+
+static unsigned int lvts_temp_to_raw(struct formula_coeff *co, int temp)
+{
+	unsigned int msr_raw;
+
+	msr_raw = ((long long)((co->golden_temp * 500 + co->b - temp)) << 14) /
+		  (-1 * co->a);
+
+	return msr_raw;
+}
+
+static int lvts_read_all_tc_temperature(struct lvts_data *lvts_data)
+{
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int i, j, s_index, msr_raw;
+	int max_temp = -100000, current_temp;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+
+			msr_raw = readl(LVTSMSR0_0 + base + 0x4 * j) &
+				  MRS_RAW_MASK;
+			current_temp =
+				lvts_raw_to_temp(&lvts_data->coeff, msr_raw);
+
+			if (msr_raw == 0)
+				current_temp = THERMAL_TEMP_INVALID;
+
+			max_temp = max(max_temp, current_temp);
+
+			lvts_data->sen_data[s_index].msr_raw = msr_raw;
+			lvts_data->sen_data[s_index].temp = current_temp;
+		}
+	}
+
+	return max_temp;
+}
+
+static int soc_temp_lvts_read_temp(void *data, int *temperature)
+{
+	struct soc_temp_tz *lvts_tz = (struct soc_temp_tz *)data;
+	struct lvts_data *lvts_data = lvts_tz->lvts_data;
+
+	if (lvts_tz->id == 0)
+		*temperature = lvts_read_all_tc_temperature(lvts_data);
+	else if (lvts_tz->id - 1 < lvts_data->num_sensor)
+		*temperature = lvts_data->sen_data[lvts_tz->id - 1].temp;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct thermal_zone_of_device_ops soc_temp_lvts_ops = {
+	.get_temp = soc_temp_lvts_read_temp,
+};
+
+static void lvts_write_device(struct lvts_data *lvts_data, unsigned int data,
+			      int tc_id)
+{
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	writel(data, LVTS_CONFIG_0 + base);
+
+	usleep_range(5, 15);
+}
+
+static unsigned int lvts_read_device(struct lvts_data *lvts_data,
+				     unsigned int reg_idx, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	void __iomem *base;
+	unsigned int data;
+	int ret;
+
+	base = GET_BASE_ADDR(tc_id);
+	writel(READ_DEVICE_REG(reg_idx), LVTS_CONFIG_0 + base);
+
+	ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data,
+				 !(data & DEVICE_ACCESS_STARTUS), 2, 200);
+	if (ret)
+		dev_err(dev,
+			"Error: LVTS %d DEVICE_ACCESS_START didn't ready\n",
+			tc_id);
+
+	data = readl(LVTSRDATA0_0 + base);
+
+	return data;
+}
+
+static void wait_all_tc_sensing_point_idle(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int mask, error_code, is_error;
+	void __iomem *base;
+	int i, cnt, ret;
+
+	mask = BIT(10) | BIT(7) | BIT(0);
+
+	for (cnt = 0; cnt < 2; cnt++) {
+		is_error = 0;
+		for (i = 0; i < lvts_data->num_tc; i++) {
+			base = GET_BASE_ADDR(i);
+			ret = readl_poll_timeout(LVTSMSRCTL1_0 + base,
+						 error_code,
+						 !(error_code & mask), 2, 200);
+			/*
+			 * Error code
+			 * 000: IDLE
+			 * 001: Write transaction
+			 * 010: Waiting for read after Write
+			 * 011: Disable Continue fetching on Device
+			 * 100: Read transaction
+			 * 101: Set Device special Register for Voltage
+			 *	threshold
+			 * 111: Set TSMCU number for Fetch
+			 */
+			error_code = ((error_code & BIT(10)) >> 8) +
+				     ((error_code & BIT(7)) >> 6) +
+				     (error_code & BIT(0));
+
+			if (ret)
+				dev_err(dev,
+					"Error LVTS %d sensing points aren't idle, error_code %d\n",
+					i, error_code);
+
+			if (error_code != 0)
+				is_error = 1;
+		}
+
+		if (is_error == 0)
+			break;
+	}
+}
+
+static void lvts_reset(struct lvts_data *lvts_data)
+{
+	int i;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		if (lvts_data->domain[i].reset)
+			reset_control_assert(lvts_data->domain[i].reset);
+
+		if (lvts_data->domain[i].reset)
+			reset_control_deassert(lvts_data->domain[i].reset);
+	}
+}
+
+static void device_identification(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int i, data;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+
+		writel(ENABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base);
+
+		lvts_write_device(lvts_data, RESET_ALL_DEVICES, i);
+
+		lvts_write_device(lvts_data, READ_BACK_DEVICE_ID, i);
+
+		/* Check LVTS device ID */
+		data = (readl(LVTS_ID_0 + base) & GENMASK(7, 0));
+		if (data != (0x83 + i))
+			dev_err(dev,
+				"LVTS_TC_%d, Device ID should be 0x%x, but 0x%x\n",
+				i, (0x83 + i), data);
+	}
+}
+
+static void disable_all_sensing_points(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		writel(DISABLE_SENSING_POINT, LVTSMONCTL0_0 + base);
+	}
+}
+
+static void enable_all_sensing_points(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int i, num;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		num = tc[i].num_sensor;
+
+		if (num > ALL_SENSING_POINTS) {
+			dev_err(dev,
+				"%s, LVTS%d, illegal number of sensors: %d\n",
+				__func__, i, tc[i].num_sensor);
+			continue;
+		}
+
+		writel(ENABLE_SENSING_POINT(num), LVTSMONCTL0_0 + base);
+	}
+}
+
+static void set_polling_speed(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int lvts_mon_ctl_1, lvts_mon_ctl_2;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	lvts_mon_ctl_1 = ((tc[tc_id].tc_speed.group_interval_delay << 20) &
+			  GENMASK(29, 20)) |
+			 (tc[tc_id].tc_speed.period_unit & GENMASK(9, 0));
+	lvts_mon_ctl_2 =
+		((tc[tc_id].tc_speed.filter_interval_delay << 16) &
+		 GENMASK(25, 16)) |
+		(tc[tc_id].tc_speed.sensor_interval_delay & GENMASK(9, 0));
+	/*
+	 * Clock source of LVTS thermal controller is 26MHz.
+	 * Period unit is a base for all interval delays
+	 * All interval delays must multiply it to convert a setting to time.
+	 *
+	 * Filter interval delay:
+	 * A delay between two samples of the same sensor
+	 *
+	 * Sensor interval delay:
+	 * A delay between two samples of differnet sensors
+	 *
+	 * Group interval delay:
+	 * A delay between different rounds.
+	 *
+	 * For example:
+	 *     If Period unit = C, filter delay = 1, sensor delay = 2,
+	 *     group delay = 1, and two sensors, TS1 and TS2, are in a LVTS
+	 *     thermal controller and then
+	 *     Period unit = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us
+	 *     Filter interval delay = 1 * Period unit = 118.149us
+	 *     Sensor interval delay = 2 * Period unit = 236.298us
+	 *     Group interval delay = 1 * Period unit = 118.149us
+	 *
+	 *     TS1    TS1 ... TS1    TS2    TS2 ... TS2    TS1...
+	 *        <--> Filter interval delay
+	 *                       <--> Sensor interval delay
+	 *                                             <--> Group interval delay
+	 */
+	writel(lvts_mon_ctl_1, LVTSMONCTL1_0 + base);
+	writel(lvts_mon_ctl_2, LVTSMONCTL2_0 + base);
+
+	dev_info(dev, "%s %d, LVTSMONCTL1_0= 0x%x,LVTSMONCTL2_0= 0x%x\n",
+		 __func__, tc_id, readl(LVTSMONCTL1_0 + base),
+		 readl(LVTSMONCTL2_0 + base));
+}
+
+static void set_hw_filter(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int option;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+	option = tc[tc_id].hw_filter & 0x7;
+	/* hw filter
+	 * 000: Get one sample
+	 * 001: Get 2 samples and average them
+	 * 010: Get 4 samples, drop max and min, then average the rest of 2
+	 *      samples
+	 * 011: Get 6 samples, drop max and min, then average the rest of 4
+	 *      samples
+	 * 100: Get 10 samples, drop max and min, then average the rest of 8
+	 *      samples
+	 * 101: Get 18 samples, drop max and min, then average the rest of 16
+	 * samples
+	 */
+	option = (option << 9) | (option << 6) | (option << 3) | option;
+
+	writel(option, LVTSMSRCTL0_0 + base);
+	dev_info(dev, "%s %d, LVTSMSRCTL0_0= 0x%x\n", __func__, tc_id,
+		 readl(LVTSMSRCTL0_0 + base));
+}
+
+static int get_dominator_index(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	int d_index;
+
+	if (tc[tc_id].dominator_sensing_point == ALL_SENSING_POINTS) {
+		d_index = ALL_SENSING_POINTS;
+	} else if (tc[tc_id].dominator_sensing_point < tc[tc_id].num_sensor) {
+		d_index = tc[tc_id].dominator_sensing_point;
+	} else {
+		dev_err(dev,
+			"Error: LVTS%d, dominator_sensing_point= %d should smaller than num_sensor= %d\n",
+			tc_id, tc[tc_id].dominator_sensing_point,
+			tc[tc_id].num_sensor);
+
+		dev_err(dev,
+			"Use the sensing point 0 as the dominated sensor\n");
+		d_index = SENSING_POINT0;
+	}
+
+	return d_index;
+}
+
+static void disable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id)
+{
+	unsigned int temp;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	/* LVTS thermal controller has two interrupts for thermal HW reboot
+	 * One is for AP SW and the other is for RGU
+	 * The interrupt of AP SW can turn off by a bit of a register, but
+	 * the other for RGU cannot.
+	 * To prevent rebooting device accidentally, we are going to add
+	 * a huge offset to LVTS and make LVTS always report extremely low
+	 * temperature.
+	 */
+
+	/* After adding the huge offset 0x3FFF, LVTS alawys adds the
+	 * offset to MSR_RAW.
+	 * When MSR_RAW is larger, SW will convert lower temperature/
+	 */
+	temp = readl(LVTSPROTCTL_0 + base);
+	writel(temp | 0x3FFF, LVTSPROTCTL_0 + base);
+
+	/* Disable the interrupt of AP SW */
+	temp = readl(LVTSMONINT_0 + base);
+	writel(temp & ~(STAGE3_INT_EN), LVTSMONINT_0 + base);
+}
+
+static void enable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id)
+{
+	unsigned int temp;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	/* Enable the interrupt of AP SW */
+	temp = readl(LVTSMONINT_0 + base);
+	writel(temp | STAGE3_INT_EN, LVTSMONINT_0 + base);
+	/* Clear the offset */
+	temp = readl(LVTSPROTCTL_0 + base);
+	writel(temp & ~PROTOFFSET, LVTSPROTCTL_0 + base);
+}
+
+static void set_tc_hw_reboot_threshold(struct lvts_data *lvts_data,
+				       int trip_point, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int msr_raw, temp, config, d_index;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+	d_index = get_dominator_index(lvts_data, tc_id);
+
+	dev_info(dev, "%s: LVTS%d, the dominator sensing point= %d\n", __func__,
+		 tc_id, d_index);
+
+	disable_hw_reboot_interrupt(lvts_data, tc_id);
+
+	temp = readl(LVTSPROTCTL_0 + base);
+	if (d_index == ALL_SENSING_POINTS) {
+		/* Maximum of 4 sensing points */
+		config = (0x1 << 16);
+		writel(config | temp, LVTSPROTCTL_0 + base);
+	} else {
+		/* Select protection sensor */
+		config = ((d_index << 2) + 0x2) << 16;
+		writel(config | temp, LVTSPROTCTL_0 + base);
+	}
+
+	msr_raw = lvts_temp_to_raw(&lvts_data->coeff, trip_point);
+	writel(msr_raw, LVTSPROTTC_0 + base);
+
+	enable_hw_reboot_interrupt(lvts_data, tc_id);
+}
+
+static void set_all_tc_hw_reboot(struct lvts_data *lvts_data)
+{
+	struct tc_settings *tc = lvts_data->tc;
+	int i, trip_point;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		trip_point = tc[i].hw_reboot_trip_point;
+
+		if (tc[i].num_sensor == 0)
+			continue;
+
+		if (trip_point == DISABLE_THERMAL_HW_REBOOT)
+			continue;
+
+		set_tc_hw_reboot_threshold(lvts_data, trip_point, i);
+	}
+}
+
+static int lvts_init(struct lvts_data *lvts_data)
+{
+	struct platform_ops *ops = &lvts_data->ops;
+	struct device *dev = lvts_data->dev;
+	int ret;
+
+	ret = clk_prepare_enable(lvts_data->clk);
+	if (ret) {
+		dev_err(dev,
+			"Error: Failed to enable lvts controller clock: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (lvts_data->feature_bitmap & FEATURE_RESET)
+		lvts_reset(lvts_data);
+
+	device_identification(lvts_data);
+	if (ops->device_enable_and_init)
+		ops->device_enable_and_init(lvts_data);
+
+	if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK)) {
+		if (ops->device_enable_auto_rck)
+			ops->device_enable_auto_rck(lvts_data);
+	} else {
+		if (ops->device_read_count_rc_n)
+			ops->device_read_count_rc_n(lvts_data);
+	}
+
+	if (ops->set_cal_data)
+		ops->set_cal_data(lvts_data);
+
+	disable_all_sensing_points(lvts_data);
+	wait_all_tc_sensing_point_idle(lvts_data);
+	if (ops->init_controller)
+		ops->init_controller(lvts_data);
+	enable_all_sensing_points(lvts_data);
+
+	set_all_tc_hw_reboot(lvts_data);
+
+	return 0;
+}
+
+static int prepare_calibration_data(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	struct platform_ops *ops = &lvts_data->ops;
+	int i, offset, size;
+	char buffer[512];
+
+	cal_data->count_r =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_r), GFP_KERNEL);
+	if (!cal_data->count_r)
+		return -ENOMEM;
+
+	cal_data->count_rc =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_rc), GFP_KERNEL);
+	if (!cal_data->count_rc)
+		return -ENOMEM;
+
+	if (ops->efuse_to_cal_data && !cal_data->use_fake_efuse)
+		ops->efuse_to_cal_data(lvts_data);
+
+	if (cal_data->golden_temp == 0 ||
+	    cal_data->golden_temp > GOLDEN_TEMP_MAX)
+		cal_data->use_fake_efuse = 1;
+
+	if (cal_data->use_fake_efuse) {
+		/* It means all efuse data are equal to 0 */
+		dev_err(dev,
+			"[lvts_cal] This sample is not calibrated, fake !!\n");
+
+		cal_data->golden_temp = cal_data->default_golden_temp;
+		for (i = 0; i < lvts_data->num_sensor; i++) {
+			cal_data->count_r[i] = cal_data->default_count_r;
+			cal_data->count_rc[i] = cal_data->default_count_rc;
+		}
+	}
+
+	lvts_data->coeff.golden_temp = cal_data->golden_temp;
+
+	dev_info(dev, "[lvts_cal] golden_temp = %d\n", cal_data->golden_temp);
+
+	size = sizeof(buffer);
+	offset = snprintf(buffer, size, "[lvts_cal] num:g_count:g_count_rc ");
+	for (i = 0; i < lvts_data->num_sensor; i++)
+		offset +=
+			snprintf(buffer + offset, size - offset, "%d:%d:%d ", i,
+				 cal_data->count_r[i], cal_data->count_rc[i]);
+
+	buffer[offset] = '\0';
+	dev_info(dev, "%s\n", buffer);
+
+	return 0;
+}
+
+static int get_calibration_data(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	char cell_name[8];
+	struct nvmem_cell *cell;
+	u32 *buf;
+	size_t len;
+	int i, j, index = 0;
+
+	lvts_data->efuse = devm_kcalloc(dev, lvts_data->num_efuse_addr,
+					sizeof(*lvts_data->efuse), GFP_KERNEL);
+	if (!lvts_data->efuse)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_efuse_block; i++) {
+		snprintf(cell_name, sizeof(cell_name), "e_data%d", i + 1);
+		cell = nvmem_cell_get(dev, cell_name);
+		if (IS_ERR(cell)) {
+			dev_err(dev, "Error: Failed to get nvmem cell %s\n",
+				cell_name);
+			return PTR_ERR(cell);
+		}
+
+		buf = (u32 *)nvmem_cell_read(cell, &len);
+		nvmem_cell_put(cell);
+
+		if (IS_ERR(buf))
+			return PTR_ERR(buf);
+
+		for (j = 0; j < (len / sizeof(u32)); j++) {
+			if (index >= lvts_data->num_efuse_addr) {
+				dev_err(dev,
+					"Array efuse is going to overflow");
+				kfree(buf);
+				return -EINVAL;
+			}
+
+			lvts_data->efuse[index] = buf[j];
+			index++;
+		}
+
+		kfree(buf);
+	}
+
+	return 0;
+}
+
+static int of_update_lvts_data(struct lvts_data *lvts_data,
+			       struct platform_device *pdev)
+{
+	struct device *dev = lvts_data->dev;
+	struct power_domain *domain;
+	struct resource *res;
+	unsigned int i;
+	int ret;
+
+	lvts_data->clk = devm_clk_get(dev, "lvts_clk");
+	if (IS_ERR(lvts_data->clk))
+		return PTR_ERR(lvts_data->clk);
+
+	domain = devm_kcalloc(dev, lvts_data->num_domain, sizeof(*domain),
+			      GFP_KERNEL);
+	if (!domain)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		/* Get base address */
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			dev_err(dev, "No IO resource, index %d\n", i);
+			return -ENXIO;
+		}
+
+		domain[i].base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(domain[i].base)) {
+			dev_err(dev, "Failed to remap io, index %d\n", i);
+			return PTR_ERR(domain[i].base);
+		}
+
+		/* Get interrupt number */
+		if (lvts_data->feature_bitmap & FEATURE_IRQ) {
+			res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+			if (!res) {
+				dev_err(dev, "No irq resource, index %d\n", i);
+				return -EINVAL;
+			}
+			domain[i].irq_num = res->start;
+		}
+
+		/* Get reset control */
+		if (lvts_data->feature_bitmap & FEATURE_RESET) {
+			domain[i].reset =
+				devm_reset_control_get_by_index(dev, i);
+			if (IS_ERR(domain[i].reset)) {
+				dev_err(dev, "Failed to get, index %d\n", i);
+				return PTR_ERR(domain[i].reset);
+			}
+		}
+	}
+
+	lvts_data->domain = domain;
+
+	lvts_data->sen_data =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*lvts_data->sen_data), GFP_KERNEL);
+	if (!lvts_data->sen_data)
+		return -ENOMEM;
+
+	ret = get_calibration_data(lvts_data);
+	if (ret)
+		lvts_data->cal_data.use_fake_efuse = 1;
+	ret = prepare_calibration_data(lvts_data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void lvts_device_close(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		lvts_write_device(lvts_data, RESET_ALL_DEVICES, i);
+		writel(DISABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base);
+	}
+}
+
+static void lvts_close(struct lvts_data *lvts_data)
+{
+	disable_all_sensing_points(lvts_data);
+	wait_all_tc_sensing_point_idle(lvts_data);
+	lvts_device_close(lvts_data);
+	clk_disable_unprepare(lvts_data->clk);
+}
+
+static void tc_irq_handler(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int ret = 0;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	ret = readl(LVTSMONINTSTS_0 + base);
+	/* Write back to clear interrupt status */
+	writel(ret, LVTSMONINTSTS_0 + base);
+
+	dev_info(
+		dev,
+		"[Thermal IRQ] LVTS thermal controller %d, LVTSMONINTSTS=0x%08x\n",
+		tc_id, ret);
+
+	if (ret & THERMAL_PROTECTION_STAGE_3)
+		dev_info(
+			dev,
+			"[Thermal IRQ]: Thermal protection stage 3 interrupt triggered\n");
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+	struct lvts_data *lvts_data = (struct lvts_data *)dev_id;
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int i, *irq_bitmap;
+	void __iomem *base;
+
+	irq_bitmap =
+		kcalloc(lvts_data->num_domain, sizeof(*irq_bitmap), GFP_ATOMIC);
+
+	if (!irq_bitmap)
+		return IRQ_NONE;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		base = lvts_data->domain[i].base;
+		irq_bitmap[i] = readl(THERMINTST + base);
+		dev_info(dev, "%s : THERMINTST = 0x%x\n", __func__,
+			 irq_bitmap[i]);
+	}
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		if ((irq_bitmap[tc[i].domain_index] & tc[i].irq_bit) == 0)
+			tc_irq_handler(lvts_data, i);
+	}
+
+	kfree(irq_bitmap);
+
+	return IRQ_HANDLED;
+}
+
+static int lvts_register_irq_handler(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		ret = devm_request_irq(dev, lvts_data->domain[i].irq_num,
+				       irq_handler, IRQF_TRIGGER_HIGH,
+				       "mtk_lvts", lvts_data);
+
+		if (ret) {
+			dev_err(dev,
+				"Failed to register LVTS IRQ, ret %d, domain %d irq_num %d\n",
+				ret, i, lvts_data->domain[i].irq_num);
+			lvts_close(lvts_data);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int lvts_register_thermal_zones(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	struct thermal_zone_device *tzdev;
+	struct soc_temp_tz *lvts_tz;
+	int i, ret;
+
+	for (i = 0; i < lvts_data->num_sensor + 1; i++) {
+		lvts_tz = devm_kzalloc(dev, sizeof(*lvts_tz), GFP_KERNEL);
+		if (!lvts_tz) {
+			lvts_close(lvts_data);
+			return -ENOMEM;
+		}
+
+		lvts_tz->id = i;
+		lvts_tz->lvts_data = lvts_data;
+
+		tzdev = devm_thermal_zone_of_sensor_register(
+			dev, lvts_tz->id, lvts_tz, &soc_temp_lvts_ops);
+
+		if (IS_ERR(tzdev)) {
+			if (lvts_tz->id != 0)
+				return 0;
+
+			ret = PTR_ERR(tzdev);
+			lvts_close(lvts_data);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int lvts_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lvts_data *lvts_data;
+	int ret;
+
+	lvts_data = (struct lvts_data *)of_device_get_match_data(dev);
+
+	if (!lvts_data) {
+		dev_err(dev, "Error: Failed to get lvts platform data\n");
+		return -ENODATA;
+	}
+
+	lvts_data->dev = &pdev->dev;
+
+	ret = of_update_lvts_data(lvts_data, pdev);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, lvts_data);
+
+	ret = lvts_init(lvts_data);
+	if (ret)
+		return ret;
+
+	if (lvts_data->feature_bitmap & FEATURE_IRQ) {
+		ret = lvts_register_irq_handler(lvts_data);
+		if (ret)
+			return ret;
+	}
+
+	ret = lvts_register_thermal_zones(lvts_data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int lvts_remove(struct platform_device *pdev)
+{
+	struct lvts_data *lvts_data;
+
+	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
+
+	lvts_close(lvts_data);
+
+	return 0;
+}
+
+static int lvts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct lvts_data *lvts_data;
+
+	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
+
+	lvts_close(lvts_data);
+
+	return 0;
+}
+
+static int lvts_resume(struct platform_device *pdev)
+{
+	int ret;
+	struct lvts_data *lvts_data;
+
+	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
+
+	ret = lvts_init(lvts_data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * LVTS v4 common code
+ */
+
+static void device_enable_and_init_v4(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		lvts_write_device(lvts_data, STOP_COUNTING_V4, i);
+		lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V4, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V4, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V4, i);
+		lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4,
+				  i);
+		lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4,
+				  i);
+		lvts_write_device(lvts_data, SET_TS_RSV_V4, i);
+		lvts_write_device(lvts_data, SET_TS_EN_V4, i);
+		lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST1_V4, i);
+		lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST2_V4, i);
+	}
+
+	lvts_data->counting_window_us = 20;
+}
+
+static void device_enable_auto_rck_v4(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+
+	for (i = 0; i < lvts_data->num_tc; i++)
+		lvts_write_device(lvts_data, SET_LVTS_AUTO_RCK_V4, i);
+}
+
+static int device_read_count_rc_n_v4(struct lvts_data *lvts_data)
+{
+	/* Resistor-Capacitor Calibration */
+	/* count_RC_N: count RC now */
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	unsigned int offset, size, s_index, data;
+	void __iomem *base;
+	int ret, i, j;
+	char buffer[512];
+
+	cal_data->count_rc_now =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_rc_now), GFP_KERNEL);
+	if (!cal_data->count_rc_now)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+
+			lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V4(j),
+					  i);
+			lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V4,
+					  i);
+			usleep_range(10, 20);
+
+			lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V4,
+					  i);
+			usleep_range(30, 40);
+
+			ret = readl_poll_timeout(
+				LVTS_CONFIG_0 + base, data,
+				!(data & DEVICE_SENSING_STATUS), 2, 200);
+
+			data = lvts_read_device(lvts_data, 0x00, i);
+
+			cal_data->count_rc_now[s_index] =
+				(data & GENMASK(23, 0));
+		}
+
+		/* Recover Setting for Normal Access on
+		 * temperature fetch
+		 */
+		lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V4, i);
+		lvts_write_device(lvts_data,
+				  SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i);
+	}
+
+	size = sizeof(buffer);
+	offset = snprintf(buffer, size, "[COUNT_RC_NOW] ");
+	for (i = 0; i < lvts_data->num_sensor; i++)
+		offset += snprintf(buffer + offset, size - offset, "%d:%d ", i,
+				   cal_data->count_rc_now[i]);
+
+	buffer[offset] = '\0';
+	dev_info(dev, "%s\n", buffer);
+
+	return 0;
+}
+
+static void set_calibration_data_v4(struct lvts_data *lvts_data)
+{
+	struct tc_settings *tc = lvts_data->tc;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	unsigned int i, j, s_index, e_data;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+			if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK))
+				e_data = cal_data->count_r[s_index];
+			else
+				e_data = (((unsigned long long)cal_data
+						   ->count_rc_now[s_index]) *
+					  cal_data->count_r[s_index]) >>
+					 14;
+
+			writel(e_data, LVTSEDATA00_0 + base + 0x4 * j);
+		}
+	}
+}
+
+static void init_controller_v4(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int i;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+
+		lvts_write_device(lvts_data,
+				  SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i);
+
+		writel(SET_SENSOR_INDEX, LVTSTSSEL_0 + base);
+		writel(SET_CALC_SCALE_RULES, LVTSCALSCALE_0 + base);
+
+		set_polling_speed(lvts_data, i);
+		set_hw_filter(lvts_data, i);
+
+		dev_info(dev,
+			 "lvts%d: read all %d sensors in %d us, one in %d us\n",
+			 i, GET_TC_SENSOR_NUM(i), GROUP_LATENCY_US(i),
+			 SENSOR_LATENCY_US(i));
+	}
+}
+
+/*
+ * LVTS v5 common code
+ */
+static void device_enable_and_init_v5(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		lvts_write_device(lvts_data, STOP_COUNTING_V5, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V5, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V5, i);
+		lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V5, i);
+		lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V5,
+				  i);
+		lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V5,
+				  i);
+		lvts_write_device(lvts_data, SET_TS_RSV_V5, i);
+		lvts_write_device(lvts_data, SET_TS_EN_V5, i);
+	}
+
+	lvts_data->counting_window_us = 20;
+}
+
+static int device_read_count_rc_n_v5(struct lvts_data *lvts_data)
+{
+	/* Resistor-Capacitor Calibration */
+	/* count_RC_N: count RC now */
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	unsigned int offset, size, s_index, data;
+	void __iomem *base;
+	int ret, i, j;
+	char buffer[512];
+
+	cal_data->count_rc_now =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_rc_now), GFP_KERNEL);
+	if (!cal_data->count_rc_now)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		lvts_write_device(lvts_data, SET_MANUAL_RCK_V5, i);
+
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+
+			lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V5(j),
+					  i);
+			lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V5,
+					  i);
+			lvts_write_device(lvts_data,
+					  SET_COUNTING_WINDOW_20US2_V5, i);
+			lvts_write_device(lvts_data,
+					  SET_COUNTING_WINDOW_20US1_V5, i);
+			lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V5,
+					  i);
+			udelay(40);
+
+			ret = readl_poll_timeout(
+				LVTS_CONFIG_0 + base, data,
+				!(data & DEVICE_SENSING_STATUS), 2, 200);
+			if (ret)
+				dev_err(dev,
+					"Error: LVTS %d DEVICE_SENSING_STATUS didn't ready\n",
+					i);
+
+			data = lvts_read_device(lvts_data, 0x00, i);
+
+			cal_data->count_rc_now[s_index] =
+				(data & GENMASK(23, 0));
+
+			/* Recover Setting for Normal Access on
+			 * temperature fetch
+			 */
+			lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V5(j),
+					  i);
+			lvts_write_device(lvts_data,
+					  SET_DEVICE_LOW_POWER_SINGLE_MODE_V5,
+					  i);
+		}
+	}
+
+	size = sizeof(buffer);
+	offset = snprintf(buffer, size, "[COUNT_RC_NOW] ");
+	for (i = 0; i < lvts_data->num_sensor; i++)
+		offset += snprintf(buffer + offset, size - offset, "%d:%d ", i,
+				   cal_data->count_rc_now[i]);
+
+	buffer[offset] = '\0';
+	dev_info(dev, "%s\n", buffer);
+
+	return 0;
+}
+
+/*
+ * LVTS MT6873
+ */
+
+#define MT6873_NUM_LVTS (ARRAY_SIZE(mt6873_tc_settings))
+
+enum mt6873_lvts_domain {
+	MT6873_AP_DOMAIN,
+	MT6873_MCU_DOMAIN,
+	MT6873_NUM_DOMAIN
+};
+
+enum mt6873_lvts_sensor_enum {
+	MT6873_TS1_0,
+	MT6873_TS1_1,
+	MT6873_TS2_0,
+	MT6873_TS2_1,
+	MT6873_TS3_0,
+	MT6873_TS3_1,
+	MT6873_TS3_2,
+	MT6873_TS3_3,
+	MT6873_TS4_0,
+	MT6873_TS4_1,
+	MT6873_TS5_0,
+	MT6873_TS5_1,
+	MT6873_TS6_0,
+	MT6873_TS6_1,
+	MT6873_TS7_0,
+	MT6873_TS7_1,
+	MT6873_TS7_2,
+	MT6873_NUM_TS
+};
+
+static void mt6873_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
+	cal_data->count_r[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT6873_TS1_1] = GET_CAL_DATA_BITMASK(2, 23, 0);
+	cal_data->count_r[MT6873_TS2_0] = GET_CAL_DATA_BITMASK(3, 23, 0);
+	cal_data->count_r[MT6873_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0);
+	cal_data->count_r[MT6873_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0);
+	cal_data->count_r[MT6873_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0);
+	cal_data->count_r[MT6873_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
+	cal_data->count_r[MT6873_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0);
+	cal_data->count_r[MT6873_TS4_0] = GET_CAL_DATA_BITMASK(9, 23, 0);
+	cal_data->count_r[MT6873_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0);
+	cal_data->count_r[MT6873_TS5_0] = GET_CAL_DATA_BITMASK(11, 23, 0);
+	cal_data->count_r[MT6873_TS5_1] = GET_CAL_DATA_BITMASK(12, 23, 0);
+	cal_data->count_r[MT6873_TS6_0] = GET_CAL_DATA_BITMASK(13, 23, 0);
+	cal_data->count_r[MT6873_TS6_1] = GET_CAL_DATA_BITMASK(14, 23, 0);
+	cal_data->count_r[MT6873_TS7_0] = GET_CAL_DATA_BITMASK(15, 23, 0);
+	cal_data->count_r[MT6873_TS7_1] = GET_CAL_DATA_BITMASK(16, 23, 0);
+	cal_data->count_r[MT6873_TS7_2] = GET_CAL_DATA_BITMASK(17, 23, 0);
+
+	cal_data->count_rc[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(21, 23, 0);
+
+	cal_data->count_rc[MT6873_TS2_0] =
+		(GET_CAL_DATA_BITMASK(1, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(2, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(3, 31, 24);
+
+	cal_data->count_rc[MT6873_TS3_0] =
+		(GET_CAL_DATA_BITMASK(4, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(5, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(6, 31, 24);
+
+	cal_data->count_rc[MT6873_TS4_0] =
+		(GET_CAL_DATA_BITMASK(7, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(8, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(9, 31, 24);
+
+	cal_data->count_rc[MT6873_TS5_0] =
+		(GET_CAL_DATA_BITMASK(10, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(11, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(12, 31, 24);
+
+	cal_data->count_rc[MT6873_TS6_0] =
+		(GET_CAL_DATA_BITMASK(13, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(14, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(15, 31, 24);
+
+	cal_data->count_rc[MT6873_TS7_0] =
+		(GET_CAL_DATA_BITMASK(16, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(17, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(18, 31, 24);
+}
+
+static struct tc_settings mt6873_tc_settings[] = {
+	[0] = {
+		.domain_index = MT6873_MCU_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS1_0, MT6873_TS1_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[1] = {
+		.domain_index = MT6873_MCU_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS2_0, MT6873_TS2_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[2] = {
+		.domain_index = MT6873_MCU_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 4,
+		.sensor_map = {MT6873_TS3_0, MT6873_TS3_1, MT6873_TS3_2,
+			       MT6873_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[3] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS4_0, MT6873_TS4_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[4] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS5_0, MT6873_TS5_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[5] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS6_0, MT6873_TS6_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[6] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x300,
+		.num_sensor = 3,
+		.sensor_map = {MT6873_TS7_0, MT6873_TS7_1, MT6873_TS7_2},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT2,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(6),
+	}
+};
+
+static struct lvts_data mt6873_lvts_data = {
+	.num_domain = MT6873_NUM_DOMAIN,
+	.num_tc = MT6873_NUM_LVTS,
+	.tc = mt6873_tc_settings,
+	.num_sensor = MT6873_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt6873_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v4,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v4,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
+	.num_efuse_addr = 22,
+	.num_efuse_block = 1,
+	.cal_data = {
+		.default_golden_temp = 50,
+		.default_count_r = 35000,
+		.default_count_rc = 2750,
+	},
+	.coeff = {
+		.a = -250460,
+		.b = 250460,
+	},
+};
+
+/*
+ * LVTS MT7988
+ */
+
+#define MT7988_NUM_LVTS (ARRAY_SIZE(mt7988_tc_settings))
+
+enum mt7988_lvts_domain { MT7988_AP_DOMAIN, MT7988_NUM_DOMAIN };
+
+enum mt7988_lvts_sensor_enum {
+	MT7988_TS2_0,
+	MT7988_TS2_1,
+	MT7988_TS2_2,
+	MT7988_TS2_3,
+	MT7988_TS3_0,
+	MT7988_TS3_1,
+	MT7988_TS3_2,
+	MT7988_TS3_3,
+	MT7988_NUM_TS
+};
+
+static void mt7988_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
+
+	cal_data->count_r[MT7988_TS2_0] = GET_CAL_DATA_BITMASK(0, 23, 0);
+	cal_data->count_r[MT7988_TS2_1] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT7988_TS2_2] = GET_CAL_DATA_BITMASK(2, 23, 0);
+	cal_data->count_r[MT7988_TS2_3] = GET_CAL_DATA_BITMASK(3, 23, 0);
+	cal_data->count_rc[MT7988_TS2_0] = GET_CAL_DATA_BITMASK(4, 23, 0);
+
+	cal_data->count_r[MT7988_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0);
+	cal_data->count_r[MT7988_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0);
+	cal_data->count_r[MT7988_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
+	cal_data->count_r[MT7988_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0);
+	cal_data->count_rc[MT7988_TS3_0] = GET_CAL_DATA_BITMASK(9, 23, 0);
+}
+
+static struct tc_settings mt7988_tc_settings[] = {
+	[0] = {
+		.domain_index = MT7988_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 4,
+		.sensor_map = {MT7988_TS2_0, MT7988_TS2_1, MT7988_TS2_2,
+			       MT7988_TS2_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_16_OF_18,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[1] = {
+		.domain_index = MT7988_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 4,
+		.sensor_map = {MT7988_TS3_0, MT7988_TS3_1, MT7988_TS3_2,
+			       MT7988_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_16_OF_18,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	}
+
+};
+
+static struct lvts_data mt7988_lvts_data = {
+	.num_domain = MT7988_NUM_DOMAIN,
+	.num_tc = MT7988_NUM_LVTS,
+	.tc = mt7988_tc_settings,
+	.num_sensor = MT7988_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt7988_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v5,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v5,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = 0,
+	.num_efuse_addr = 10,
+	.num_efuse_block = 1,
+	.cal_data = {
+		.default_golden_temp = 60,
+		.default_count_r = 19380,
+		.default_count_rc = 5330,
+	},
+	.coeff = {
+		.a = -204650,
+		.b = 204650,
+	},
+};
+
+/*
+ * LVTS MT8195
+ */
+
+#define MT8195_NUM_LVTS (ARRAY_SIZE(mt8195_tc_settings))
+
+enum mt8195_lvts_domain {
+	MT8195_AP_DOMAIN,
+	MT8195_MCU_DOMAIN,
+	MT8195_NUM_DOMAIN
+};
+
+enum mt8195_lvts_sensor_enum {
+	MT8195_TS1_0,
+	MT8195_TS1_1,
+	MT8195_TS2_0,
+	MT8195_TS2_1,
+	MT8195_TS3_0,
+	MT8195_TS3_1,
+	MT8195_TS3_2,
+	MT8195_TS3_3,
+	MT8195_TS4_0,
+	MT8195_TS4_1,
+	MT8195_TS5_0,
+	MT8195_TS5_1,
+	MT8195_TS6_0,
+	MT8195_TS6_1,
+	MT8195_TS6_2,
+	MT8195_TS7_0,
+	MT8195_TS7_1,
+	MT8195_NUM_TS
+};
+
+static void mt8195_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
+	cal_data->count_r[MT8195_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT8195_TS1_1] =
+		(GET_CAL_DATA_BITMASK(2, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(1, 31, 24);
+	cal_data->count_r[MT8195_TS2_0] = GET_CAL_DATA_BITMASK(3, 31, 8);
+	cal_data->count_r[MT8195_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0);
+	cal_data->count_r[MT8195_TS3_0] =
+		(GET_CAL_DATA_BITMASK(6, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(5, 31, 16);
+	cal_data->count_r[MT8195_TS3_1] = GET_CAL_DATA_BITMASK(6, 31, 8);
+	cal_data->count_r[MT8195_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
+	cal_data->count_r[MT8195_TS3_3] =
+		(GET_CAL_DATA_BITMASK(8, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(7, 31, 24);
+	cal_data->count_r[MT8195_TS4_0] = GET_CAL_DATA_BITMASK(9, 31, 8);
+	cal_data->count_r[MT8195_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0);
+	cal_data->count_r[MT8195_TS5_0] =
+		(GET_CAL_DATA_BITMASK(12, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(11, 31, 16);
+	cal_data->count_r[MT8195_TS5_1] = GET_CAL_DATA_BITMASK(12, 31, 8);
+	cal_data->count_r[MT8195_TS6_0] =
+		(GET_CAL_DATA_BITMASK(14, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(13, 31, 24);
+	cal_data->count_r[MT8195_TS6_1] =
+		(GET_CAL_DATA_BITMASK(15, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(14, 31, 16);
+	cal_data->count_r[MT8195_TS6_2] = GET_CAL_DATA_BITMASK(15, 31, 8);
+	cal_data->count_r[MT8195_TS7_0] =
+		(GET_CAL_DATA_BITMASK(17, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(16, 31, 24);
+	cal_data->count_r[MT8195_TS7_1] =
+		(GET_CAL_DATA_BITMASK(18, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(17, 31, 16);
+	cal_data->count_rc[MT8195_TS1_0] =
+		(GET_CAL_DATA_BITMASK(3, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(2, 31, 16);
+	cal_data->count_rc[MT8195_TS2_0] =
+		(GET_CAL_DATA_BITMASK(5, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(4, 31, 24);
+	cal_data->count_rc[MT8195_TS3_0] =
+		(GET_CAL_DATA_BITMASK(9, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(8, 31, 16);
+	cal_data->count_rc[MT8195_TS4_0] =
+		(GET_CAL_DATA_BITMASK(11, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(10, 31, 24);
+	cal_data->count_rc[MT8195_TS5_0] = GET_CAL_DATA_BITMASK(13, 23, 0);
+	cal_data->count_rc[MT8195_TS6_0] = GET_CAL_DATA_BITMASK(16, 23, 0);
+	cal_data->count_rc[MT8195_TS7_0] = GET_CAL_DATA_BITMASK(18, 31, 8);
+}
+
+static struct tc_settings mt8195_tc_settings[] = {
+	[0] = {
+		.domain_index = MT8195_MCU_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS1_0, MT8195_TS1_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[1] = {
+		.domain_index = MT8195_MCU_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS2_0, MT8195_TS2_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[2] = {
+		.domain_index = MT8195_MCU_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 4,
+		.sensor_map = {MT8195_TS3_0, MT8195_TS3_1, MT8195_TS3_2,
+			       MT8195_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[3] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS4_0, MT8195_TS4_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[4] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS5_0, MT8195_TS5_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[5] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 3,
+		.sensor_map = {MT8195_TS6_0, MT8195_TS6_1, MT8195_TS6_2},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[6] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x300,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS7_0, MT8195_TS7_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(6),
+	}
+};
+
+static struct lvts_data mt8195_lvts_data = {
+	.num_domain = MT8195_NUM_DOMAIN,
+	.num_tc = MT8195_NUM_LVTS,
+	.tc = mt8195_tc_settings,
+	.num_sensor = MT8195_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt8195_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v4,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v4,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
+	.num_efuse_addr = 22,
+	.num_efuse_block = 2,
+	.cal_data = {
+		.default_golden_temp = 50,
+		.default_count_r = 35000,
+		.default_count_rc = 2750,
+	},
+	.coeff = {
+		.a = -250460,
+		.b = 250460,
+	},
+};
+
+/*
+ * LVTS MT8139
+ */
+
+#define MT8139_NUM_LVTS (ARRAY_SIZE(mt8139_tc_settings))
+
+enum mt8139_lvts_domain {
+	MT8139_AP_DOMAIN,
+	MT8139_MCU_DOMAIN,
+	MT8139_NUM_DOMAIN
+};
+
+enum mt8139_lvts_sensor_enum {
+	MT8139_TS1_0,
+	MT8139_TS1_1,
+	MT8139_TS1_2,
+	MT8139_TS1_3,
+	MT8139_TS2_0,
+	MT8139_TS2_1,
+	MT8139_TS2_2,
+	MT8139_TS2_3,
+	MT8139_TS3_0,
+	MT8139_TS3_1,
+	MT8139_TS3_2,
+	MT8139_TS3_3,
+	MT8139_NUM_TS
+};
+
+static void mt8139_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 7, 0);
+	cal_data->count_r[MT8139_TS1_0] = GET_CAL_DATA_BITMASK(0, 31, 8);
+	cal_data->count_r[MT8139_TS1_1] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT8139_TS1_2] =
+		(GET_CAL_DATA_BITMASK(2, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(1, 31, 24);
+	cal_data->count_r[MT8139_TS1_3] =
+		(GET_CAL_DATA_BITMASK(3, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(2, 31, 16);
+	cal_data->count_rc[MT8139_TS1_0] = GET_CAL_DATA_BITMASK(3, 31, 8);
+
+	cal_data->count_r[MT8139_TS2_0] = GET_CAL_DATA_BITMASK(4, 23, 0);
+	cal_data->count_r[MT8139_TS2_1] =
+		(GET_CAL_DATA_BITMASK(5, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(4, 31, 24);
+	cal_data->count_r[MT8139_TS2_2] =
+		(GET_CAL_DATA_BITMASK(6, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(5, 31, 16);
+	cal_data->count_r[MT8139_TS2_3] = GET_CAL_DATA_BITMASK(6, 31, 8);
+	cal_data->count_rc[MT8139_TS2_0] = GET_CAL_DATA_BITMASK(7, 23, 0);
+
+	cal_data->count_r[MT8139_TS3_0] =
+		(GET_CAL_DATA_BITMASK(8, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(7, 31, 24);
+	cal_data->count_r[MT8139_TS3_1] =
+		(GET_CAL_DATA_BITMASK(9, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(8, 31, 16);
+	cal_data->count_r[MT8139_TS3_2] = GET_CAL_DATA_BITMASK(9, 31, 8);
+	cal_data->count_r[MT8139_TS3_3] = GET_CAL_DATA_BITMASK(10, 23, 0);
+	cal_data->count_rc[MT8139_TS3_0] =
+		(GET_CAL_DATA_BITMASK(11, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(10, 31, 24);
+}
+
+static struct tc_settings mt8139_tc_settings[] = {
+	[0] = {
+		.domain_index = MT8139_MCU_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 4,
+		.sensor_map = {MT8139_TS1_0, MT8139_TS1_1, MT8139_TS1_2,
+			       MT8139_TS1_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[1] = {
+		.domain_index = MT8139_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 4,
+		.sensor_map = {MT8139_TS2_0, MT8139_TS2_1, MT8139_TS2_2,
+			       MT8139_TS2_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[2] = {
+		.domain_index = MT8139_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 4,
+		.sensor_map = {MT8139_TS3_0, MT8139_TS3_1, MT8139_TS3_2,
+			       MT8139_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	}
+
+};
+
+static struct lvts_data mt8139_lvts_data = {
+	.num_domain = MT8139_NUM_DOMAIN,
+	.num_tc = MT8139_NUM_LVTS,
+	.tc = mt8139_tc_settings,
+	.num_sensor = MT8139_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt8139_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v4,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v4,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = 0,
+	.num_efuse_addr = 48,
+	.num_efuse_block = 1,
+	.cal_data = {
+		.default_golden_temp = 50,
+		.default_count_r = 35000,
+		.default_count_rc = 2750,
+	},
+	.coeff = {
+		.a = -250460,
+		.b = 250460,
+	},
+};
+
+/*
+ * Support chips
+ */
+static const struct of_device_id lvts_of_match[] = {
+	{
+		.compatible = "mediatek,mt6873-lvts",
+		.data = (void *)&mt6873_lvts_data,
+	},
+	{
+		.compatible = "mediatek,mt8195-lvts",
+		.data = (void *)&mt8195_lvts_data,
+	},
+	{
+		.compatible = "mediatek,mt8139-lvts",
+		.data = (void *)&mt8139_lvts_data,
+	},
+	{
+		.compatible = "mediatek,mt7988-lvts",
+		.data = (void *)&mt7988_lvts_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, lvts_of_match);
+
+static struct platform_driver soc_temp_lvts = {
+	.probe = lvts_probe,
+	.remove = lvts_remove,
+	.suspend = lvts_suspend,
+	.resume = lvts_resume,
+	.driver = {
+		.name = "mtk-soc-temp-lvts",
+		.of_match_table = lvts_of_match,
+	},
+};
+
+module_platform_driver(soc_temp_lvts);
+MODULE_AUTHOR("Yu-Chia Chang <ethan.chang@mediatek.com>");
+MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
+MODULE_AUTHOR("Henry Yen <henry.yen@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek soc temperature driver");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.h b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.h
new file mode 100644
index 0000000..ed3d058
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.h
@@ -0,0 +1,314 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ */
+
+#ifndef __MTK_SOC_TEMP_LVTS_H__
+#define __MTK_SOC_TEMP_LVTS_H__
+
+/* LVTS HW filter settings
+ * 000: Get one sample
+ * 001: Get 2 samples and average them
+ * 010: Get 4 samples, drop max and min, then average the rest of 2 samples
+ * 011: Get 6 samples, drop max and min, then average the rest of 4 samples
+ * 100: Get 10 samples, drop max and min, then average the rest of 8 samples
+ * 101: Get 18 samples, drop max and min, then average the rest of 16 samples
+ */
+enum lvts_hw_filter {
+	LVTS_FILTER_1,
+	LVTS_FILTER_2,
+	LVTS_FILTER_2_OF_4,
+	LVTS_FILTER_4_OF_6,
+	LVTS_FILTER_8_OF_10,
+	LVTS_FILTER_16_OF_18
+};
+
+enum lvts_sensing_point {
+	SENSING_POINT0,
+	SENSING_POINT1,
+	SENSING_POINT2,
+	SENSING_POINT3,
+	ALL_SENSING_POINTS
+};
+
+/*
+ * Data structure
+ */
+struct lvts_data;
+
+struct speed_settings {
+	unsigned int period_unit;
+	unsigned int group_interval_delay;
+	unsigned int filter_interval_delay;
+	unsigned int sensor_interval_delay;
+};
+
+struct tc_settings {
+	unsigned int domain_index;
+	unsigned int addr_offset;
+	unsigned int num_sensor;
+	unsigned int sensor_map[ALL_SENSING_POINTS]; /* In sensor ID */
+	struct speed_settings tc_speed;
+	/* HW filter setting
+	 * 000: Get one sample
+	 * 001: Get 2 samples and average them
+	 * 010: Get 4 samples, drop max and min, then average the rest of 2
+	 *	samples
+	 * 011: Get 6 samples, drop max and min, then average the rest of 4
+	 *      samples
+	 * 100: Get 10 samples, drop max and min, then average the rest of 8
+	 *      samples
+	 * 101: Get 18 samples, drop max and min, then average the rest of 16
+	 *      samples
+	 */
+	unsigned int hw_filter;
+	/* Dominator_sensing point is used to select a sensing point
+	 * and reference its temperature to trigger Thermal HW Reboot
+	 * When it is ALL_SENSING_POINTS, it will select all sensing points
+	 */
+	int dominator_sensing_point;
+	int hw_reboot_trip_point; /* -274000: Disable HW reboot */
+	unsigned int irq_bit;
+};
+
+struct formula_coeff {
+	int a;
+	int b;
+	unsigned int golden_temp;
+};
+
+struct sensor_cal_data {
+	int use_fake_efuse; /* 1: Use fake efuse, 0: Use real efuse */
+	unsigned int golden_temp;
+	unsigned int *count_r;
+	unsigned int *count_rc;
+	unsigned int *count_rc_now;
+
+	unsigned int default_golden_temp;
+	unsigned int default_count_r;
+	unsigned int default_count_rc;
+};
+
+struct platform_ops {
+	void (*efuse_to_cal_data)(struct lvts_data *lvts_data);
+	void (*device_enable_and_init)(struct lvts_data *lvts_data);
+	void (*device_enable_auto_rck)(struct lvts_data *lvts_data);
+	int (*device_read_count_rc_n)(struct lvts_data *lvts_data);
+	void (*set_cal_data)(struct lvts_data *lvts_data);
+	void (*init_controller)(struct lvts_data *lvts_data);
+};
+
+struct power_domain {
+	void __iomem *base; /* LVTS base addresses */
+	unsigned int irq_num; /* LVTS interrupt numbers */
+	struct reset_control *reset;
+};
+
+struct sensor_data {
+	int temp; /* Current temperature */
+	unsigned int msr_raw; /* MSR raw data from LVTS */
+};
+
+struct lvts_data {
+	struct device *dev;
+	struct clk *clk;
+	unsigned int num_domain;
+	struct power_domain *domain;
+
+	int num_tc; /* Number of LVTS thermal controllers */
+	struct tc_settings *tc;
+	int counting_window_us; /* LVTS device counting window */
+
+	int num_sensor; /* Number of sensors in this platform */
+	struct sensor_data *sen_data;
+
+	struct platform_ops ops;
+	int feature_bitmap; /* Show what features are enabled */
+
+	unsigned int num_efuse_addr;
+	unsigned int *efuse;
+	unsigned int num_efuse_block; /* Number of contiguous efuse indexes */
+	struct sensor_cal_data cal_data;
+	struct formula_coeff coeff;
+};
+
+struct soc_temp_tz {
+	unsigned int id; /* if id is 0, get max temperature of all sensors */
+	struct lvts_data *lvts_data;
+};
+
+struct match_entry {
+	char chip[32];
+	struct lvts_data *lvts_data;
+};
+
+struct lvts_match_data {
+	unsigned int hw_version;
+	struct match_entry *table;
+	void (*set_up_common_callbacks)(struct lvts_data *lvts_data);
+	struct list_head node;
+};
+
+struct lvts_id {
+	unsigned int hw_version;
+	char chip[32];
+};
+
+/*
+ * LVTS device register
+ */
+#define RG_TSFM_DATA_0	0x00
+#define RG_TSFM_DATA_1	0x01
+#define RG_TSFM_DATA_2	0x02
+#define RG_TSFM_CTRL_0	0x03
+#define RG_TSFM_CTRL_1	0x04
+#define RG_TSFM_CTRL_2	0x05
+#define RG_TSFM_CTRL_3	0x06
+#define RG_TSFM_CTRL_4	0x07
+#define RG_TSV2F_CTRL_0 0x08
+#define RG_TSV2F_CTRL_1 0x09
+#define RG_TSV2F_CTRL_2 0x0A
+#define RG_TSV2F_CTRL_3 0x0B
+#define RG_TSV2F_CTRL_4 0x0C
+#define RG_TSV2F_CTRL_5 0x0D
+#define RG_TSV2F_CTRL_6 0x0E
+#define RG_TEMP_DATA_0	0x10
+#define RG_TEMP_DATA_1	0x11
+#define RG_TEMP_DATA_2	0x12
+#define RG_TEMP_DATA_3	0x13
+#define RG_RC_DATA_0	0x14
+#define RG_RC_DATA_1	0x15
+#define RG_RC_DATA_2	0x16
+#define RG_RC_DATA_3	0x17
+#define RG_DIV_DATA_0	0x18
+#define RG_DIV_DATA_1	0x19
+#define RG_DIV_DATA_2	0x1A
+#define RG_DIV_DATA_3	0x1B
+#define RG_TST_DATA_0	0x70
+#define RG_TST_DATA_1	0x71
+#define RG_TST_DATA_2	0x72
+#define RG_TST_CTRL	0x73
+#define RG_DBG_FQMTR	0xF0
+#define RG_DBG_LPSEQ	0xF1
+#define RG_DBG_STATE	0xF2
+#define RG_DBG_CHKSUM	0xF3
+#define RG_DID_LVTS	0xFC
+#define RG_DID_REV	0xFD
+#define RG_TSFM_RST	0xFF
+/*
+ * LVTS controller register
+ */
+#define LVTSMONCTL0_0		  0x000
+#define LVTS_SINGLE_SENSE	  BIT(9)
+#define ENABLE_SENSING_POINT(num) (LVTS_SINGLE_SENSE | GENMASK(((num)-1), 0))
+#define DISABLE_SENSING_POINT	  (LVTS_SINGLE_SENSE | 0x0)
+#define LVTSMONCTL1_0		  0x004
+#define LVTSMONCTL2_0		  0x008
+#define LVTSMONINT_0		  0x00C
+#define STAGE3_INT_EN		  BIT(31)
+#define LVTSMONINTSTS_0		  0x010
+#define LVTSMONIDET0_0		  0x014
+#define LVTSMONIDET1_0		  0x018
+#define LVTSMONIDET2_0		  0x01C
+#define LVTSMONIDET3_0		  0x020
+#define LVTSH2NTHRE_0		  0x024
+#define LVTSHTHRE_0		  0x028
+#define LVTSCTHRE_0		  0x02C
+#define LVTSOFFSETH_0		  0x030
+#define LVTSOFFSETL_0		  0x034
+#define LVTSMSRCTL0_0		  0x038
+#define LVTSMSRCTL1_0		  0x03C
+#define LVTSTSSEL_0		  0x040
+#define SET_SENSOR_INDEX	  0x13121110
+#define LVTSDEVICETO_0		  0x044
+#define LVTSCALSCALE_0		  0x048
+#define SET_CALC_SCALE_RULES	  0x00000300
+#define LVTS_ID_0		  0x04C
+#define LVTS_CONFIG_0		  0x050
+
+#define BROADCAST_ID_UPDATE	  BIT(26)
+#define DEVICE_SENSING_STATUS	  BIT(25)
+#define DEVICE_ACCESS_STARTUS	  BIT(24)
+#define WRITE_ACCESS		  BIT(16)
+#define DEVICE_WRITE                                                           \
+	(BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS | BIT(17) |            \
+	 WRITE_ACCESS)
+#define DEVICE_READ                                                            \
+	(BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS | 1 << 17)
+#define RESET_ALL_DEVICES                                                      \
+	(DEVICE_WRITE | RG_TSFM_RST << 8 | 0xFF)
+#define READ_BACK_DEVICE_ID                                                    \
+	(BIT(31) | CK26M_ACTIVE | BROADCAST_ID_UPDATE |                        \
+	 DEVICE_ACCESS_STARTUS | BIT(17) | RG_DID_LVTS << 8)
+#define READ_DEVICE_REG(reg_idx) (DEVICE_READ | (reg_idx) << 8 | 0x00)
+#define LVTSEDATA00_0		 0x054
+#define LVTSEDATA01_0		 0x058
+#define LVTSEDATA02_0		 0x05C
+#define LVTSEDATA03_0		 0x060
+#define LVTSMSR0_0		 0x090
+#define MRS_RAW_MASK		 GENMASK(15, 0)
+#define MRS_RAW_VALID_BIT	 BIT(16)
+#define LVTSMSR1_0		 0x094
+#define LVTSMSR2_0		 0x098
+#define LVTSMSR3_0		 0x09C
+#define LVTSIMMD0_0		 0x0A0
+#define LVTSIMMD1_0		 0x0A4
+#define LVTSIMMD2_0		 0x0A8
+#define LVTSIMMD3_0		 0x0AC
+#define LVTSRDATA0_0		 0x0B0
+#define LVTSRDATA1_0		 0x0B4
+#define LVTSRDATA2_0		 0x0B8
+#define LVTSRDATA3_0		 0x0BC
+#define LVTSPROTCTL_0		 0x0C0
+#define PROTOFFSET		 GENMASK(15, 0)
+#define LVTSPROTTA_0		 0x0C4
+#define LVTSPROTTB_0		 0x0C8
+#define LVTSPROTTC_0		 0x0CC
+#define LVTSCLKEN_0		 0x0E4
+#define ENABLE_LVTS_CTRL_CLK	 (1)
+#define DISABLE_LVTS_CTRL_CLK	 (0)
+#define LVTSDBGSEL_0		 0x0E8
+#define LVTSDBGSIG_0		 0x0EC
+#define LVTSSPARE0_0		 0x0F0
+#define LVTSSPARE1_0		 0x0F4
+#define LVTSSPARE2_0		 0x0F8
+#define LVTSSPARE3_0		 0x0FC
+
+#define THERMINTST 0xF04
+/*
+ * LVTS register mask
+ */
+#define THERMAL_COLD_INTERRUPT_0	 0x00000001
+#define THERMAL_HOT_INTERRUPT_0		 0x00000002
+#define THERMAL_LOW_OFFSET_INTERRUPT_0	 0x00000004
+#define THERMAL_HIGH_OFFSET_INTERRUPT_0	 0x00000008
+#define THERMAL_HOT2NORMAL_INTERRUPT_0	 0x00000010
+#define THERMAL_COLD_INTERRUPT_1	 0x00000020
+#define THERMAL_HOT_INTERRUPT_1		 0x00000040
+#define THERMAL_LOW_OFFSET_INTERRUPT_1	 0x00000080
+#define THERMAL_HIGH_OFFSET_INTERRUPT_1	 0x00000100
+#define THERMAL_HOT2NORMAL_INTERRUPT_1	 0x00000200
+#define THERMAL_COLD_INTERRUPT_2	 0x00000400
+#define THERMAL_HOT_INTERRUPT_2		 0x00000800
+#define THERMAL_LOW_OFFSET_INTERRUPT_2	 0x00001000
+#define THERMAL_HIGH_OFFSET_INTERRUPT_2	 0x00002000
+#define THERMAL_HOT2NORMAL_INTERRUPT_2	 0x00004000
+#define THERMAL_AHB_TIMEOUT_INTERRUPT	 0x00008000
+#define THERMAL_DEVICE_TIMEOUT_INTERRUPT 0x00008000
+#define THERMAL_IMMEDIATE_INTERRUPT_0	 0x00010000
+#define THERMAL_IMMEDIATE_INTERRUPT_1	 0x00020000
+#define THERMAL_IMMEDIATE_INTERRUPT_2	 0x00040000
+#define THERMAL_FILTER_INTERRUPT_0	 0x00080000
+#define THERMAL_FILTER_INTERRUPT_1	 0x00100000
+#define THERMAL_FILTER_INTERRUPT_2	 0x00200000
+#define THERMAL_COLD_INTERRUPT_3	 0x00400000
+#define THERMAL_HOT_INTERRUPT_3		 0x00800000
+#define THERMAL_LOW_OFFSET_INTERRUPT_3	 0x01000000
+#define THERMAL_HIGH_OFFSET_INTERRUPT_3	 0x02000000
+#define THERMAL_HOT2NORMAL_INTERRUPT_3	 0x04000000
+#define THERMAL_IMMEDIATE_INTERRUPT_3	 0x08000000
+#define THERMAL_FILTER_INTERRUPT_3	 0x10000000
+#define THERMAL_PROTECTION_STAGE_1	 0x20000000
+#define THERMAL_PROTECTION_STAGE_2	 0x40000000
+#define THERMAL_PROTECTION_STAGE_3	 0x80000000
+#endif /* __MTK_SOC_TEMP_LVTS_H__ */