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