162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright (c) 2021 MediaTek Inc.
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/clk.h>
662306a36Sopenharmony_ci#include <linux/iopoll.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/of.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/property.h>
1162306a36Sopenharmony_ci#include <linux/spmi.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define SWINF_IDLE	0x00
1462306a36Sopenharmony_ci#define SWINF_WFVLDCLR	0x06
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define GET_SWINF(x)	(((x) >> 1) & 0x7)
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define PMIF_CMD_REG_0		0
1962306a36Sopenharmony_ci#define PMIF_CMD_REG		1
2062306a36Sopenharmony_ci#define PMIF_CMD_EXT_REG	2
2162306a36Sopenharmony_ci#define PMIF_CMD_EXT_REG_LONG	3
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define PMIF_DELAY_US   10
2462306a36Sopenharmony_ci#define PMIF_TIMEOUT_US (10 * 1000)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define PMIF_CHAN_OFFSET 0x5
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define PMIF_MAX_CLKS	3
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define SPMI_OP_ST_BUSY 1
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct ch_reg {
3362306a36Sopenharmony_ci	u32 ch_sta;
3462306a36Sopenharmony_ci	u32 wdata;
3562306a36Sopenharmony_ci	u32 rdata;
3662306a36Sopenharmony_ci	u32 ch_send;
3762306a36Sopenharmony_ci	u32 ch_rdy;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct pmif_data {
4162306a36Sopenharmony_ci	const u32	*regs;
4262306a36Sopenharmony_ci	const u32	*spmimst_regs;
4362306a36Sopenharmony_ci	u32	soc_chan;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistruct pmif {
4762306a36Sopenharmony_ci	void __iomem	*base;
4862306a36Sopenharmony_ci	void __iomem	*spmimst_base;
4962306a36Sopenharmony_ci	struct ch_reg	chan;
5062306a36Sopenharmony_ci	struct clk_bulk_data clks[PMIF_MAX_CLKS];
5162306a36Sopenharmony_ci	size_t nclks;
5262306a36Sopenharmony_ci	const struct pmif_data *data;
5362306a36Sopenharmony_ci	raw_spinlock_t lock;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic const char * const pmif_clock_names[] = {
5762306a36Sopenharmony_ci	"pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux",
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cienum pmif_regs {
6162306a36Sopenharmony_ci	PMIF_INIT_DONE,
6262306a36Sopenharmony_ci	PMIF_INF_EN,
6362306a36Sopenharmony_ci	PMIF_ARB_EN,
6462306a36Sopenharmony_ci	PMIF_CMDISSUE_EN,
6562306a36Sopenharmony_ci	PMIF_TIMER_CTRL,
6662306a36Sopenharmony_ci	PMIF_SPI_MODE_CTRL,
6762306a36Sopenharmony_ci	PMIF_IRQ_EVENT_EN_0,
6862306a36Sopenharmony_ci	PMIF_IRQ_FLAG_0,
6962306a36Sopenharmony_ci	PMIF_IRQ_CLR_0,
7062306a36Sopenharmony_ci	PMIF_IRQ_EVENT_EN_1,
7162306a36Sopenharmony_ci	PMIF_IRQ_FLAG_1,
7262306a36Sopenharmony_ci	PMIF_IRQ_CLR_1,
7362306a36Sopenharmony_ci	PMIF_IRQ_EVENT_EN_2,
7462306a36Sopenharmony_ci	PMIF_IRQ_FLAG_2,
7562306a36Sopenharmony_ci	PMIF_IRQ_CLR_2,
7662306a36Sopenharmony_ci	PMIF_IRQ_EVENT_EN_3,
7762306a36Sopenharmony_ci	PMIF_IRQ_FLAG_3,
7862306a36Sopenharmony_ci	PMIF_IRQ_CLR_3,
7962306a36Sopenharmony_ci	PMIF_IRQ_EVENT_EN_4,
8062306a36Sopenharmony_ci	PMIF_IRQ_FLAG_4,
8162306a36Sopenharmony_ci	PMIF_IRQ_CLR_4,
8262306a36Sopenharmony_ci	PMIF_WDT_EVENT_EN_0,
8362306a36Sopenharmony_ci	PMIF_WDT_FLAG_0,
8462306a36Sopenharmony_ci	PMIF_WDT_EVENT_EN_1,
8562306a36Sopenharmony_ci	PMIF_WDT_FLAG_1,
8662306a36Sopenharmony_ci	PMIF_SWINF_0_STA,
8762306a36Sopenharmony_ci	PMIF_SWINF_0_WDATA_31_0,
8862306a36Sopenharmony_ci	PMIF_SWINF_0_RDATA_31_0,
8962306a36Sopenharmony_ci	PMIF_SWINF_0_ACC,
9062306a36Sopenharmony_ci	PMIF_SWINF_0_VLD_CLR,
9162306a36Sopenharmony_ci	PMIF_SWINF_1_STA,
9262306a36Sopenharmony_ci	PMIF_SWINF_1_WDATA_31_0,
9362306a36Sopenharmony_ci	PMIF_SWINF_1_RDATA_31_0,
9462306a36Sopenharmony_ci	PMIF_SWINF_1_ACC,
9562306a36Sopenharmony_ci	PMIF_SWINF_1_VLD_CLR,
9662306a36Sopenharmony_ci	PMIF_SWINF_2_STA,
9762306a36Sopenharmony_ci	PMIF_SWINF_2_WDATA_31_0,
9862306a36Sopenharmony_ci	PMIF_SWINF_2_RDATA_31_0,
9962306a36Sopenharmony_ci	PMIF_SWINF_2_ACC,
10062306a36Sopenharmony_ci	PMIF_SWINF_2_VLD_CLR,
10162306a36Sopenharmony_ci	PMIF_SWINF_3_STA,
10262306a36Sopenharmony_ci	PMIF_SWINF_3_WDATA_31_0,
10362306a36Sopenharmony_ci	PMIF_SWINF_3_RDATA_31_0,
10462306a36Sopenharmony_ci	PMIF_SWINF_3_ACC,
10562306a36Sopenharmony_ci	PMIF_SWINF_3_VLD_CLR,
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic const u32 mt6873_regs[] = {
10962306a36Sopenharmony_ci	[PMIF_INIT_DONE] = 0x0000,
11062306a36Sopenharmony_ci	[PMIF_INF_EN] = 0x0024,
11162306a36Sopenharmony_ci	[PMIF_ARB_EN] = 0x0150,
11262306a36Sopenharmony_ci	[PMIF_CMDISSUE_EN] = 0x03B4,
11362306a36Sopenharmony_ci	[PMIF_TIMER_CTRL] = 0x03E0,
11462306a36Sopenharmony_ci	[PMIF_SPI_MODE_CTRL] = 0x0400,
11562306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_0] = 0x0418,
11662306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_0] = 0x0420,
11762306a36Sopenharmony_ci	[PMIF_IRQ_CLR_0] = 0x0424,
11862306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_1] = 0x0428,
11962306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_1] = 0x0430,
12062306a36Sopenharmony_ci	[PMIF_IRQ_CLR_1] = 0x0434,
12162306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_2] = 0x0438,
12262306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_2] = 0x0440,
12362306a36Sopenharmony_ci	[PMIF_IRQ_CLR_2] = 0x0444,
12462306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_3] = 0x0448,
12562306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_3] = 0x0450,
12662306a36Sopenharmony_ci	[PMIF_IRQ_CLR_3] = 0x0454,
12762306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_4] = 0x0458,
12862306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_4] = 0x0460,
12962306a36Sopenharmony_ci	[PMIF_IRQ_CLR_4] = 0x0464,
13062306a36Sopenharmony_ci	[PMIF_WDT_EVENT_EN_0] = 0x046C,
13162306a36Sopenharmony_ci	[PMIF_WDT_FLAG_0] = 0x0470,
13262306a36Sopenharmony_ci	[PMIF_WDT_EVENT_EN_1] = 0x0474,
13362306a36Sopenharmony_ci	[PMIF_WDT_FLAG_1] = 0x0478,
13462306a36Sopenharmony_ci	[PMIF_SWINF_0_ACC] = 0x0C00,
13562306a36Sopenharmony_ci	[PMIF_SWINF_0_WDATA_31_0] = 0x0C04,
13662306a36Sopenharmony_ci	[PMIF_SWINF_0_RDATA_31_0] = 0x0C14,
13762306a36Sopenharmony_ci	[PMIF_SWINF_0_VLD_CLR] = 0x0C24,
13862306a36Sopenharmony_ci	[PMIF_SWINF_0_STA] = 0x0C28,
13962306a36Sopenharmony_ci	[PMIF_SWINF_1_ACC] = 0x0C40,
14062306a36Sopenharmony_ci	[PMIF_SWINF_1_WDATA_31_0] = 0x0C44,
14162306a36Sopenharmony_ci	[PMIF_SWINF_1_RDATA_31_0] = 0x0C54,
14262306a36Sopenharmony_ci	[PMIF_SWINF_1_VLD_CLR] = 0x0C64,
14362306a36Sopenharmony_ci	[PMIF_SWINF_1_STA] = 0x0C68,
14462306a36Sopenharmony_ci	[PMIF_SWINF_2_ACC] = 0x0C80,
14562306a36Sopenharmony_ci	[PMIF_SWINF_2_WDATA_31_0] = 0x0C84,
14662306a36Sopenharmony_ci	[PMIF_SWINF_2_RDATA_31_0] = 0x0C94,
14762306a36Sopenharmony_ci	[PMIF_SWINF_2_VLD_CLR] = 0x0CA4,
14862306a36Sopenharmony_ci	[PMIF_SWINF_2_STA] = 0x0CA8,
14962306a36Sopenharmony_ci	[PMIF_SWINF_3_ACC] = 0x0CC0,
15062306a36Sopenharmony_ci	[PMIF_SWINF_3_WDATA_31_0] = 0x0CC4,
15162306a36Sopenharmony_ci	[PMIF_SWINF_3_RDATA_31_0] = 0x0CD4,
15262306a36Sopenharmony_ci	[PMIF_SWINF_3_VLD_CLR] = 0x0CE4,
15362306a36Sopenharmony_ci	[PMIF_SWINF_3_STA] = 0x0CE8,
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic const u32 mt8195_regs[] = {
15762306a36Sopenharmony_ci	[PMIF_INIT_DONE] = 0x0000,
15862306a36Sopenharmony_ci	[PMIF_INF_EN] = 0x0024,
15962306a36Sopenharmony_ci	[PMIF_ARB_EN] = 0x0150,
16062306a36Sopenharmony_ci	[PMIF_CMDISSUE_EN] = 0x03B8,
16162306a36Sopenharmony_ci	[PMIF_TIMER_CTRL] = 0x03E4,
16262306a36Sopenharmony_ci	[PMIF_SPI_MODE_CTRL] = 0x0408,
16362306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_0] = 0x0420,
16462306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_0] = 0x0428,
16562306a36Sopenharmony_ci	[PMIF_IRQ_CLR_0] = 0x042C,
16662306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_1] = 0x0430,
16762306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_1] = 0x0438,
16862306a36Sopenharmony_ci	[PMIF_IRQ_CLR_1] = 0x043C,
16962306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_2] = 0x0440,
17062306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_2] = 0x0448,
17162306a36Sopenharmony_ci	[PMIF_IRQ_CLR_2] = 0x044C,
17262306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_3] = 0x0450,
17362306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_3] = 0x0458,
17462306a36Sopenharmony_ci	[PMIF_IRQ_CLR_3] = 0x045C,
17562306a36Sopenharmony_ci	[PMIF_IRQ_EVENT_EN_4] = 0x0460,
17662306a36Sopenharmony_ci	[PMIF_IRQ_FLAG_4] = 0x0468,
17762306a36Sopenharmony_ci	[PMIF_IRQ_CLR_4] = 0x046C,
17862306a36Sopenharmony_ci	[PMIF_WDT_EVENT_EN_0] = 0x0474,
17962306a36Sopenharmony_ci	[PMIF_WDT_FLAG_0] = 0x0478,
18062306a36Sopenharmony_ci	[PMIF_WDT_EVENT_EN_1] = 0x047C,
18162306a36Sopenharmony_ci	[PMIF_WDT_FLAG_1] = 0x0480,
18262306a36Sopenharmony_ci	[PMIF_SWINF_0_ACC] = 0x0800,
18362306a36Sopenharmony_ci	[PMIF_SWINF_0_WDATA_31_0] = 0x0804,
18462306a36Sopenharmony_ci	[PMIF_SWINF_0_RDATA_31_0] = 0x0814,
18562306a36Sopenharmony_ci	[PMIF_SWINF_0_VLD_CLR] = 0x0824,
18662306a36Sopenharmony_ci	[PMIF_SWINF_0_STA] = 0x0828,
18762306a36Sopenharmony_ci	[PMIF_SWINF_1_ACC] = 0x0840,
18862306a36Sopenharmony_ci	[PMIF_SWINF_1_WDATA_31_0] = 0x0844,
18962306a36Sopenharmony_ci	[PMIF_SWINF_1_RDATA_31_0] = 0x0854,
19062306a36Sopenharmony_ci	[PMIF_SWINF_1_VLD_CLR] = 0x0864,
19162306a36Sopenharmony_ci	[PMIF_SWINF_1_STA] = 0x0868,
19262306a36Sopenharmony_ci	[PMIF_SWINF_2_ACC] = 0x0880,
19362306a36Sopenharmony_ci	[PMIF_SWINF_2_WDATA_31_0] = 0x0884,
19462306a36Sopenharmony_ci	[PMIF_SWINF_2_RDATA_31_0] = 0x0894,
19562306a36Sopenharmony_ci	[PMIF_SWINF_2_VLD_CLR] = 0x08A4,
19662306a36Sopenharmony_ci	[PMIF_SWINF_2_STA] = 0x08A8,
19762306a36Sopenharmony_ci	[PMIF_SWINF_3_ACC] = 0x08C0,
19862306a36Sopenharmony_ci	[PMIF_SWINF_3_WDATA_31_0] = 0x08C4,
19962306a36Sopenharmony_ci	[PMIF_SWINF_3_RDATA_31_0] = 0x08D4,
20062306a36Sopenharmony_ci	[PMIF_SWINF_3_VLD_CLR] = 0x08E4,
20162306a36Sopenharmony_ci	[PMIF_SWINF_3_STA] = 0x08E8,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cienum spmi_regs {
20562306a36Sopenharmony_ci	SPMI_OP_ST_CTRL,
20662306a36Sopenharmony_ci	SPMI_GRP_ID_EN,
20762306a36Sopenharmony_ci	SPMI_OP_ST_STA,
20862306a36Sopenharmony_ci	SPMI_MST_SAMPL,
20962306a36Sopenharmony_ci	SPMI_MST_REQ_EN,
21062306a36Sopenharmony_ci	SPMI_REC_CTRL,
21162306a36Sopenharmony_ci	SPMI_REC0,
21262306a36Sopenharmony_ci	SPMI_REC1,
21362306a36Sopenharmony_ci	SPMI_REC2,
21462306a36Sopenharmony_ci	SPMI_REC3,
21562306a36Sopenharmony_ci	SPMI_REC4,
21662306a36Sopenharmony_ci	SPMI_MST_DBG,
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* MT8195 spmi regs */
21962306a36Sopenharmony_ci	SPMI_MST_RCS_CTRL,
22062306a36Sopenharmony_ci	SPMI_SLV_3_0_EINT,
22162306a36Sopenharmony_ci	SPMI_SLV_7_4_EINT,
22262306a36Sopenharmony_ci	SPMI_SLV_B_8_EINT,
22362306a36Sopenharmony_ci	SPMI_SLV_F_C_EINT,
22462306a36Sopenharmony_ci	SPMI_REC_CMD_DEC,
22562306a36Sopenharmony_ci	SPMI_DEC_DBG,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const u32 mt6873_spmi_regs[] = {
22962306a36Sopenharmony_ci	[SPMI_OP_ST_CTRL] = 0x0000,
23062306a36Sopenharmony_ci	[SPMI_GRP_ID_EN] = 0x0004,
23162306a36Sopenharmony_ci	[SPMI_OP_ST_STA] = 0x0008,
23262306a36Sopenharmony_ci	[SPMI_MST_SAMPL] = 0x000c,
23362306a36Sopenharmony_ci	[SPMI_MST_REQ_EN] = 0x0010,
23462306a36Sopenharmony_ci	[SPMI_REC_CTRL] = 0x0040,
23562306a36Sopenharmony_ci	[SPMI_REC0] = 0x0044,
23662306a36Sopenharmony_ci	[SPMI_REC1] = 0x0048,
23762306a36Sopenharmony_ci	[SPMI_REC2] = 0x004c,
23862306a36Sopenharmony_ci	[SPMI_REC3] = 0x0050,
23962306a36Sopenharmony_ci	[SPMI_REC4] = 0x0054,
24062306a36Sopenharmony_ci	[SPMI_MST_DBG] = 0x00fc,
24162306a36Sopenharmony_ci};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic const u32 mt8195_spmi_regs[] = {
24462306a36Sopenharmony_ci	[SPMI_OP_ST_CTRL] = 0x0000,
24562306a36Sopenharmony_ci	[SPMI_GRP_ID_EN] = 0x0004,
24662306a36Sopenharmony_ci	[SPMI_OP_ST_STA] = 0x0008,
24762306a36Sopenharmony_ci	[SPMI_MST_SAMPL] = 0x000C,
24862306a36Sopenharmony_ci	[SPMI_MST_REQ_EN] = 0x0010,
24962306a36Sopenharmony_ci	[SPMI_MST_RCS_CTRL] = 0x0014,
25062306a36Sopenharmony_ci	[SPMI_SLV_3_0_EINT] = 0x0020,
25162306a36Sopenharmony_ci	[SPMI_SLV_7_4_EINT] = 0x0024,
25262306a36Sopenharmony_ci	[SPMI_SLV_B_8_EINT] = 0x0028,
25362306a36Sopenharmony_ci	[SPMI_SLV_F_C_EINT] = 0x002C,
25462306a36Sopenharmony_ci	[SPMI_REC_CTRL] = 0x0040,
25562306a36Sopenharmony_ci	[SPMI_REC0] = 0x0044,
25662306a36Sopenharmony_ci	[SPMI_REC1] = 0x0048,
25762306a36Sopenharmony_ci	[SPMI_REC2] = 0x004C,
25862306a36Sopenharmony_ci	[SPMI_REC3] = 0x0050,
25962306a36Sopenharmony_ci	[SPMI_REC4] = 0x0054,
26062306a36Sopenharmony_ci	[SPMI_REC_CMD_DEC] = 0x005C,
26162306a36Sopenharmony_ci	[SPMI_DEC_DBG] = 0x00F8,
26262306a36Sopenharmony_ci	[SPMI_MST_DBG] = 0x00FC,
26362306a36Sopenharmony_ci};
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return readl(arb->base + arb->data->regs[reg]);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	writel(val, arb->base + arb->data->regs[reg]);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]);
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic bool pmif_is_fsm_vldclr(struct pmif *arb)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	u32 reg_rdata;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	reg_rdata = pmif_readl(arb, arb->chan.ch_sta);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
29262306a36Sopenharmony_ci	u32 rdata, cmd;
29362306a36Sopenharmony_ci	int ret;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* Check the opcode */
29662306a36Sopenharmony_ci	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
29762306a36Sopenharmony_ci		return -EINVAL;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	cmd = opc - SPMI_CMD_RESET;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
30262306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA],
30362306a36Sopenharmony_ci					rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY,
30462306a36Sopenharmony_ci					PMIF_DELAY_US, PMIF_TIMEOUT_US);
30562306a36Sopenharmony_ci	if (ret < 0)
30662306a36Sopenharmony_ci		dev_err(&ctrl->dev, "timeout, err = %d\n", ret);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return ret;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
31262306a36Sopenharmony_ci			      u16 addr, u8 *buf, size_t len)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
31562306a36Sopenharmony_ci	struct ch_reg *inf_reg;
31662306a36Sopenharmony_ci	int ret;
31762306a36Sopenharmony_ci	u32 data, cmd;
31862306a36Sopenharmony_ci	unsigned long flags;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Check for argument validation. */
32162306a36Sopenharmony_ci	if (sid & ~0xf) {
32262306a36Sopenharmony_ci		dev_err(&ctrl->dev, "exceed the max slv id\n");
32362306a36Sopenharmony_ci		return -EINVAL;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (len > 4) {
32762306a36Sopenharmony_ci		dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		return -EINVAL;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (opc >= 0x60 && opc <= 0x7f)
33362306a36Sopenharmony_ci		opc = PMIF_CMD_REG;
33462306a36Sopenharmony_ci	else if ((opc >= 0x20 && opc <= 0x2f) || (opc >= 0x38 && opc <= 0x3f))
33562306a36Sopenharmony_ci		opc = PMIF_CMD_EXT_REG_LONG;
33662306a36Sopenharmony_ci	else
33762306a36Sopenharmony_ci		return -EINVAL;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&arb->lock, flags);
34062306a36Sopenharmony_ci	/* Wait for Software Interface FSM state to be IDLE. */
34162306a36Sopenharmony_ci	inf_reg = &arb->chan;
34262306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
34362306a36Sopenharmony_ci					data, GET_SWINF(data) == SWINF_IDLE,
34462306a36Sopenharmony_ci					PMIF_DELAY_US, PMIF_TIMEOUT_US);
34562306a36Sopenharmony_ci	if (ret < 0) {
34662306a36Sopenharmony_ci		/* set channel ready if the data has transferred */
34762306a36Sopenharmony_ci		if (pmif_is_fsm_vldclr(arb))
34862306a36Sopenharmony_ci			pmif_writel(arb, 1, inf_reg->ch_rdy);
34962306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&arb->lock, flags);
35062306a36Sopenharmony_ci		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* Send the command. */
35562306a36Sopenharmony_ci	cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
35662306a36Sopenharmony_ci	pmif_writel(arb, cmd, inf_reg->ch_send);
35762306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&arb->lock, flags);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * Wait for Software Interface FSM state to be WFVLDCLR,
36162306a36Sopenharmony_ci	 * read the data and clear the valid flag.
36262306a36Sopenharmony_ci	 */
36362306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
36462306a36Sopenharmony_ci					data, GET_SWINF(data) == SWINF_WFVLDCLR,
36562306a36Sopenharmony_ci					PMIF_DELAY_US, PMIF_TIMEOUT_US);
36662306a36Sopenharmony_ci	if (ret < 0) {
36762306a36Sopenharmony_ci		dev_err(&ctrl->dev, "failed to wait for SWINF_WFVLDCLR\n");
36862306a36Sopenharmony_ci		return ret;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	data = pmif_readl(arb, inf_reg->rdata);
37262306a36Sopenharmony_ci	memcpy(buf, &data, len);
37362306a36Sopenharmony_ci	pmif_writel(arb, 1, inf_reg->ch_rdy);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return 0;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
37962306a36Sopenharmony_ci			       u16 addr, const u8 *buf, size_t len)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
38262306a36Sopenharmony_ci	struct ch_reg *inf_reg;
38362306a36Sopenharmony_ci	int ret;
38462306a36Sopenharmony_ci	u32 data, wdata, cmd;
38562306a36Sopenharmony_ci	unsigned long flags;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (len > 4) {
38862306a36Sopenharmony_ci		dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		return -EINVAL;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Check the opcode */
39462306a36Sopenharmony_ci	if (opc >= 0x40 && opc <= 0x5F)
39562306a36Sopenharmony_ci		opc = PMIF_CMD_REG;
39662306a36Sopenharmony_ci	else if ((opc <= 0xF) || (opc >= 0x30 && opc <= 0x37))
39762306a36Sopenharmony_ci		opc = PMIF_CMD_EXT_REG_LONG;
39862306a36Sopenharmony_ci	else if (opc >= 0x80)
39962306a36Sopenharmony_ci		opc = PMIF_CMD_REG_0;
40062306a36Sopenharmony_ci	else
40162306a36Sopenharmony_ci		return -EINVAL;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* Set the write data. */
40462306a36Sopenharmony_ci	memcpy(&wdata, buf, len);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&arb->lock, flags);
40762306a36Sopenharmony_ci	/* Wait for Software Interface FSM state to be IDLE. */
40862306a36Sopenharmony_ci	inf_reg = &arb->chan;
40962306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
41062306a36Sopenharmony_ci					data, GET_SWINF(data) == SWINF_IDLE,
41162306a36Sopenharmony_ci					PMIF_DELAY_US, PMIF_TIMEOUT_US);
41262306a36Sopenharmony_ci	if (ret < 0) {
41362306a36Sopenharmony_ci		/* set channel ready if the data has transferred */
41462306a36Sopenharmony_ci		if (pmif_is_fsm_vldclr(arb))
41562306a36Sopenharmony_ci			pmif_writel(arb, 1, inf_reg->ch_rdy);
41662306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&arb->lock, flags);
41762306a36Sopenharmony_ci		dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
41862306a36Sopenharmony_ci		return ret;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	pmif_writel(arb, wdata, inf_reg->wdata);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Send the command. */
42462306a36Sopenharmony_ci	cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;
42562306a36Sopenharmony_ci	pmif_writel(arb, cmd, inf_reg->ch_send);
42662306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&arb->lock, flags);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic const struct pmif_data mt6873_pmif_arb = {
43262306a36Sopenharmony_ci	.regs = mt6873_regs,
43362306a36Sopenharmony_ci	.spmimst_regs = mt6873_spmi_regs,
43462306a36Sopenharmony_ci	.soc_chan = 2,
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic const struct pmif_data mt8195_pmif_arb = {
43862306a36Sopenharmony_ci	.regs = mt8195_regs,
43962306a36Sopenharmony_ci	.spmimst_regs = mt8195_spmi_regs,
44062306a36Sopenharmony_ci	.soc_chan = 2,
44162306a36Sopenharmony_ci};
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int mtk_spmi_probe(struct platform_device *pdev)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct pmif *arb;
44662306a36Sopenharmony_ci	struct spmi_controller *ctrl;
44762306a36Sopenharmony_ci	int err, i;
44862306a36Sopenharmony_ci	u32 chan_offset;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*arb));
45162306a36Sopenharmony_ci	if (!ctrl)
45262306a36Sopenharmony_ci		return -ENOMEM;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	arb = spmi_controller_get_drvdata(ctrl);
45562306a36Sopenharmony_ci	arb->data = device_get_match_data(&pdev->dev);
45662306a36Sopenharmony_ci	if (!arb->data) {
45762306a36Sopenharmony_ci		err = -EINVAL;
45862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot get drv_data\n");
45962306a36Sopenharmony_ci		goto err_put_ctrl;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");
46362306a36Sopenharmony_ci	if (IS_ERR(arb->base)) {
46462306a36Sopenharmony_ci		err = PTR_ERR(arb->base);
46562306a36Sopenharmony_ci		goto err_put_ctrl;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");
46962306a36Sopenharmony_ci	if (IS_ERR(arb->spmimst_base)) {
47062306a36Sopenharmony_ci		err = PTR_ERR(arb->spmimst_base);
47162306a36Sopenharmony_ci		goto err_put_ctrl;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	arb->nclks = ARRAY_SIZE(pmif_clock_names);
47562306a36Sopenharmony_ci	for (i = 0; i < arb->nclks; i++)
47662306a36Sopenharmony_ci		arb->clks[i].id = pmif_clock_names[i];
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
47962306a36Sopenharmony_ci	if (err) {
48062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
48162306a36Sopenharmony_ci		goto err_put_ctrl;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
48562306a36Sopenharmony_ci	if (err) {
48662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
48762306a36Sopenharmony_ci		goto err_put_clks;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ctrl->cmd = pmif_arb_cmd;
49162306a36Sopenharmony_ci	ctrl->read_cmd = pmif_spmi_read_cmd;
49262306a36Sopenharmony_ci	ctrl->write_cmd = pmif_spmi_write_cmd;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan;
49562306a36Sopenharmony_ci	arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset;
49662306a36Sopenharmony_ci	arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset;
49762306a36Sopenharmony_ci	arb->chan.rdata = PMIF_SWINF_0_RDATA_31_0 + chan_offset;
49862306a36Sopenharmony_ci	arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;
49962306a36Sopenharmony_ci	arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	raw_spin_lock_init(&arb->lock);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	platform_set_drvdata(pdev, ctrl);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	err = spmi_controller_add(ctrl);
50662306a36Sopenharmony_ci	if (err)
50762306a36Sopenharmony_ci		goto err_domain_remove;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cierr_domain_remove:
51262306a36Sopenharmony_ci	clk_bulk_disable_unprepare(arb->nclks, arb->clks);
51362306a36Sopenharmony_cierr_put_clks:
51462306a36Sopenharmony_ci	clk_bulk_put(arb->nclks, arb->clks);
51562306a36Sopenharmony_cierr_put_ctrl:
51662306a36Sopenharmony_ci	spmi_controller_put(ctrl);
51762306a36Sopenharmony_ci	return err;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic void mtk_spmi_remove(struct platform_device *pdev)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
52362306a36Sopenharmony_ci	struct pmif *arb = spmi_controller_get_drvdata(ctrl);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	clk_bulk_disable_unprepare(arb->nclks, arb->clks);
52662306a36Sopenharmony_ci	clk_bulk_put(arb->nclks, arb->clks);
52762306a36Sopenharmony_ci	spmi_controller_remove(ctrl);
52862306a36Sopenharmony_ci	spmi_controller_put(ctrl);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic const struct of_device_id mtk_spmi_match_table[] = {
53262306a36Sopenharmony_ci	{
53362306a36Sopenharmony_ci		.compatible = "mediatek,mt6873-spmi",
53462306a36Sopenharmony_ci		.data = &mt6873_pmif_arb,
53562306a36Sopenharmony_ci	}, {
53662306a36Sopenharmony_ci		.compatible = "mediatek,mt8195-spmi",
53762306a36Sopenharmony_ci		.data = &mt8195_pmif_arb,
53862306a36Sopenharmony_ci	}, {
53962306a36Sopenharmony_ci		/* sentinel */
54062306a36Sopenharmony_ci	},
54162306a36Sopenharmony_ci};
54262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtk_spmi_match_table);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic struct platform_driver mtk_spmi_driver = {
54562306a36Sopenharmony_ci	.driver		= {
54662306a36Sopenharmony_ci		.name	= "spmi-mtk",
54762306a36Sopenharmony_ci		.of_match_table = mtk_spmi_match_table,
54862306a36Sopenharmony_ci	},
54962306a36Sopenharmony_ci	.probe		= mtk_spmi_probe,
55062306a36Sopenharmony_ci	.remove_new	= mtk_spmi_remove,
55162306a36Sopenharmony_ci};
55262306a36Sopenharmony_cimodule_platform_driver(mtk_spmi_driver);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ciMODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");
55562306a36Sopenharmony_ciMODULE_DESCRIPTION("MediaTek SPMI Driver");
55662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
557