xref: /OK3568_Linux_fs/kernel/drivers/spmi/spmi-pmic-arb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2012-2015, 2017, 2021, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/bitmap.h>
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/err.h>
8*4882a593Smuzhiyun #include <linux/interrupt.h>
9*4882a593Smuzhiyun #include <linux/io.h>
10*4882a593Smuzhiyun #include <linux/irqchip/chained_irq.h>
11*4882a593Smuzhiyun #include <linux/irqdomain.h>
12*4882a593Smuzhiyun #include <linux/irq.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/of.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/spmi.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* PMIC Arbiter configuration registers */
21*4882a593Smuzhiyun #define PMIC_ARB_VERSION		0x0000
22*4882a593Smuzhiyun #define PMIC_ARB_VERSION_V2_MIN		0x20010000
23*4882a593Smuzhiyun #define PMIC_ARB_VERSION_V3_MIN		0x30000000
24*4882a593Smuzhiyun #define PMIC_ARB_VERSION_V5_MIN		0x50000000
25*4882a593Smuzhiyun #define PMIC_ARB_INT_EN			0x0004
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* PMIC Arbiter channel registers offsets */
28*4882a593Smuzhiyun #define PMIC_ARB_CMD			0x00
29*4882a593Smuzhiyun #define PMIC_ARB_CONFIG			0x04
30*4882a593Smuzhiyun #define PMIC_ARB_STATUS			0x08
31*4882a593Smuzhiyun #define PMIC_ARB_WDATA0			0x10
32*4882a593Smuzhiyun #define PMIC_ARB_WDATA1			0x14
33*4882a593Smuzhiyun #define PMIC_ARB_RDATA0			0x18
34*4882a593Smuzhiyun #define PMIC_ARB_RDATA1			0x1C
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* Mapping Table */
37*4882a593Smuzhiyun #define SPMI_MAPPING_TABLE_REG(N)	(0x0B00 + (4 * (N)))
38*4882a593Smuzhiyun #define SPMI_MAPPING_BIT_INDEX(X)	(((X) >> 18) & 0xF)
39*4882a593Smuzhiyun #define SPMI_MAPPING_BIT_IS_0_FLAG(X)	(((X) >> 17) & 0x1)
40*4882a593Smuzhiyun #define SPMI_MAPPING_BIT_IS_0_RESULT(X)	(((X) >> 9) & 0xFF)
41*4882a593Smuzhiyun #define SPMI_MAPPING_BIT_IS_1_FLAG(X)	(((X) >> 8) & 0x1)
42*4882a593Smuzhiyun #define SPMI_MAPPING_BIT_IS_1_RESULT(X)	(((X) >> 0) & 0xFF)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define SPMI_MAPPING_TABLE_TREE_DEPTH	16	/* Maximum of 16-bits */
45*4882a593Smuzhiyun #define PMIC_ARB_MAX_PPID		BIT(12) /* PPID is 12bit */
46*4882a593Smuzhiyun #define PMIC_ARB_APID_VALID		BIT(15)
47*4882a593Smuzhiyun #define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg)	((reg) & BIT(24))
48*4882a593Smuzhiyun #define INVALID_EE				0xFF
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* Ownership Table */
51*4882a593Smuzhiyun #define SPMI_OWNERSHIP_TABLE_REG(N)	(0x0700 + (4 * (N)))
52*4882a593Smuzhiyun #define SPMI_OWNERSHIP_PERIPH2OWNER(X)	((X) & 0x7)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* Channel Status fields */
55*4882a593Smuzhiyun enum pmic_arb_chnl_status {
56*4882a593Smuzhiyun 	PMIC_ARB_STATUS_DONE	= BIT(0),
57*4882a593Smuzhiyun 	PMIC_ARB_STATUS_FAILURE	= BIT(1),
58*4882a593Smuzhiyun 	PMIC_ARB_STATUS_DENIED	= BIT(2),
59*4882a593Smuzhiyun 	PMIC_ARB_STATUS_DROPPED	= BIT(3),
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* Command register fields */
63*4882a593Smuzhiyun #define PMIC_ARB_CMD_MAX_BYTE_COUNT	8
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* Command Opcodes */
66*4882a593Smuzhiyun enum pmic_arb_cmd_op_code {
67*4882a593Smuzhiyun 	PMIC_ARB_OP_EXT_WRITEL = 0,
68*4882a593Smuzhiyun 	PMIC_ARB_OP_EXT_READL = 1,
69*4882a593Smuzhiyun 	PMIC_ARB_OP_EXT_WRITE = 2,
70*4882a593Smuzhiyun 	PMIC_ARB_OP_RESET = 3,
71*4882a593Smuzhiyun 	PMIC_ARB_OP_SLEEP = 4,
72*4882a593Smuzhiyun 	PMIC_ARB_OP_SHUTDOWN = 5,
73*4882a593Smuzhiyun 	PMIC_ARB_OP_WAKEUP = 6,
74*4882a593Smuzhiyun 	PMIC_ARB_OP_AUTHENTICATE = 7,
75*4882a593Smuzhiyun 	PMIC_ARB_OP_MSTR_READ = 8,
76*4882a593Smuzhiyun 	PMIC_ARB_OP_MSTR_WRITE = 9,
77*4882a593Smuzhiyun 	PMIC_ARB_OP_EXT_READ = 13,
78*4882a593Smuzhiyun 	PMIC_ARB_OP_WRITE = 14,
79*4882a593Smuzhiyun 	PMIC_ARB_OP_READ = 15,
80*4882a593Smuzhiyun 	PMIC_ARB_OP_ZERO_WRITE = 16,
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /*
84*4882a593Smuzhiyun  * PMIC arbiter version 5 uses different register offsets for read/write vs
85*4882a593Smuzhiyun  * observer channels.
86*4882a593Smuzhiyun  */
87*4882a593Smuzhiyun enum pmic_arb_channel {
88*4882a593Smuzhiyun 	PMIC_ARB_CHANNEL_RW,
89*4882a593Smuzhiyun 	PMIC_ARB_CHANNEL_OBS,
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun /* Maximum number of support PMIC peripherals */
93*4882a593Smuzhiyun #define PMIC_ARB_MAX_PERIPHS		512
94*4882a593Smuzhiyun #define PMIC_ARB_TIMEOUT_US		100
95*4882a593Smuzhiyun #define PMIC_ARB_MAX_TRANS_BYTES	(8)
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun #define PMIC_ARB_APID_MASK		0xFF
98*4882a593Smuzhiyun #define PMIC_ARB_PPID_MASK		0xFFF
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun /* interrupt enable bit */
101*4882a593Smuzhiyun #define SPMI_PIC_ACC_ENABLE_BIT		BIT(0)
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \
104*4882a593Smuzhiyun 	((((slave_id) & 0xF)   << 28) | \
105*4882a593Smuzhiyun 	(((periph_id) & 0xFF)  << 20) | \
106*4882a593Smuzhiyun 	(((irq_id)    & 0x7)   << 16) | \
107*4882a593Smuzhiyun 	(((apid)      & 0x1FF) << 0))
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #define hwirq_to_sid(hwirq)  (((hwirq) >> 28) & 0xF)
110*4882a593Smuzhiyun #define hwirq_to_per(hwirq)  (((hwirq) >> 20) & 0xFF)
111*4882a593Smuzhiyun #define hwirq_to_irq(hwirq)  (((hwirq) >> 16) & 0x7)
112*4882a593Smuzhiyun #define hwirq_to_apid(hwirq) (((hwirq) >> 0)  & 0x1FF)
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun struct pmic_arb_ver_ops;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun struct apid_data {
117*4882a593Smuzhiyun 	u16		ppid;
118*4882a593Smuzhiyun 	u8		write_ee;
119*4882a593Smuzhiyun 	u8		irq_ee;
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun /**
123*4882a593Smuzhiyun  * spmi_pmic_arb - SPMI PMIC Arbiter object
124*4882a593Smuzhiyun  *
125*4882a593Smuzhiyun  * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
126*4882a593Smuzhiyun  * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
127*4882a593Smuzhiyun  * @intr:		address of the SPMI interrupt control registers.
128*4882a593Smuzhiyun  * @cnfg:		address of the PMIC Arbiter configuration registers.
129*4882a593Smuzhiyun  * @lock:		lock to synchronize accesses.
130*4882a593Smuzhiyun  * @channel:		execution environment channel to use for accesses.
131*4882a593Smuzhiyun  * @irq:		PMIC ARB interrupt.
132*4882a593Smuzhiyun  * @ee:			the current Execution Environment
133*4882a593Smuzhiyun  * @min_apid:		minimum APID (used for bounding IRQ search)
134*4882a593Smuzhiyun  * @max_apid:		maximum APID
135*4882a593Smuzhiyun  * @mapping_table:	in-memory copy of PPID -> APID mapping table.
136*4882a593Smuzhiyun  * @domain:		irq domain object for PMIC IRQ domain
137*4882a593Smuzhiyun  * @spmic:		SPMI controller object
138*4882a593Smuzhiyun  * @ver_ops:		version dependent operations.
139*4882a593Smuzhiyun  * @ppid_to_apid	in-memory copy of PPID -> APID mapping table.
140*4882a593Smuzhiyun  */
141*4882a593Smuzhiyun struct spmi_pmic_arb {
142*4882a593Smuzhiyun 	void __iomem		*rd_base;
143*4882a593Smuzhiyun 	void __iomem		*wr_base;
144*4882a593Smuzhiyun 	void __iomem		*intr;
145*4882a593Smuzhiyun 	void __iomem		*cnfg;
146*4882a593Smuzhiyun 	void __iomem		*core;
147*4882a593Smuzhiyun 	resource_size_t		core_size;
148*4882a593Smuzhiyun 	raw_spinlock_t		lock;
149*4882a593Smuzhiyun 	u8			channel;
150*4882a593Smuzhiyun 	int			irq;
151*4882a593Smuzhiyun 	u8			ee;
152*4882a593Smuzhiyun 	u16			min_apid;
153*4882a593Smuzhiyun 	u16			max_apid;
154*4882a593Smuzhiyun 	u32			*mapping_table;
155*4882a593Smuzhiyun 	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
156*4882a593Smuzhiyun 	struct irq_domain	*domain;
157*4882a593Smuzhiyun 	struct spmi_controller	*spmic;
158*4882a593Smuzhiyun 	const struct pmic_arb_ver_ops *ver_ops;
159*4882a593Smuzhiyun 	u16			*ppid_to_apid;
160*4882a593Smuzhiyun 	u16			last_apid;
161*4882a593Smuzhiyun 	struct apid_data	apid_data[PMIC_ARB_MAX_PERIPHS];
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun /**
165*4882a593Smuzhiyun  * pmic_arb_ver: version dependent functionality.
166*4882a593Smuzhiyun  *
167*4882a593Smuzhiyun  * @ver_str:		version string.
168*4882a593Smuzhiyun  * @ppid_to_apid:	finds the apid for a given ppid.
169*4882a593Smuzhiyun  * @non_data_cmd:	on v1 issues an spmi non-data command.
170*4882a593Smuzhiyun  *			on v2 no HW support, returns -EOPNOTSUPP.
171*4882a593Smuzhiyun  * @offset:		on v1 offset of per-ee channel.
172*4882a593Smuzhiyun  *			on v2 offset of per-ee and per-ppid channel.
173*4882a593Smuzhiyun  * @fmt_cmd:		formats a GENI/SPMI command.
174*4882a593Smuzhiyun  * @owner_acc_status:	on v1 address of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn
175*4882a593Smuzhiyun  *			on v2 address of SPMI_PIC_OWNERm_ACC_STATUSn.
176*4882a593Smuzhiyun  * @acc_enable:		on v1 address of PMIC_ARB_SPMI_PIC_ACC_ENABLEn
177*4882a593Smuzhiyun  *			on v2 address of SPMI_PIC_ACC_ENABLEn.
178*4882a593Smuzhiyun  * @irq_status:		on v1 address of PMIC_ARB_SPMI_PIC_IRQ_STATUSn
179*4882a593Smuzhiyun  *			on v2 address of SPMI_PIC_IRQ_STATUSn.
180*4882a593Smuzhiyun  * @irq_clear:		on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn
181*4882a593Smuzhiyun  *			on v2 address of SPMI_PIC_IRQ_CLEARn.
182*4882a593Smuzhiyun  * @apid_map_offset:	offset of PMIC_ARB_REG_CHNLn
183*4882a593Smuzhiyun  */
184*4882a593Smuzhiyun struct pmic_arb_ver_ops {
185*4882a593Smuzhiyun 	const char *ver_str;
186*4882a593Smuzhiyun 	int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid);
187*4882a593Smuzhiyun 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
188*4882a593Smuzhiyun 	int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
189*4882a593Smuzhiyun 			enum pmic_arb_channel ch_type);
190*4882a593Smuzhiyun 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
191*4882a593Smuzhiyun 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
192*4882a593Smuzhiyun 	/* Interrupts controller functionality (offset of PIC registers) */
193*4882a593Smuzhiyun 	void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m,
194*4882a593Smuzhiyun 					  u16 n);
195*4882a593Smuzhiyun 	void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n);
196*4882a593Smuzhiyun 	void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n);
197*4882a593Smuzhiyun 	void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n);
198*4882a593Smuzhiyun 	u32 (*apid_map_offset)(u16 n);
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun 
pmic_arb_base_write(struct spmi_pmic_arb * pmic_arb,u32 offset,u32 val)201*4882a593Smuzhiyun static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
202*4882a593Smuzhiyun 				       u32 offset, u32 val)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	writel_relaxed(val, pmic_arb->wr_base + offset);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
pmic_arb_set_rd_cmd(struct spmi_pmic_arb * pmic_arb,u32 offset,u32 val)207*4882a593Smuzhiyun static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb,
208*4882a593Smuzhiyun 				       u32 offset, u32 val)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	writel_relaxed(val, pmic_arb->rd_base + offset);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /**
214*4882a593Smuzhiyun  * pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
215*4882a593Smuzhiyun  * @bc:		byte count -1. range: 0..3
216*4882a593Smuzhiyun  * @reg:	register's address
217*4882a593Smuzhiyun  * @buf:	output parameter, length must be bc + 1
218*4882a593Smuzhiyun  */
219*4882a593Smuzhiyun static void
pmic_arb_read_data(struct spmi_pmic_arb * pmic_arb,u8 * buf,u32 reg,u8 bc)220*4882a593Smuzhiyun pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	u32 data = __raw_readl(pmic_arb->rd_base + reg);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	memcpy(buf, &data, (bc & 3) + 1);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun /**
228*4882a593Smuzhiyun  * pmic_arb_write_data: write 1..4 bytes from buf to pmic-arb's register
229*4882a593Smuzhiyun  * @bc:		byte-count -1. range: 0..3.
230*4882a593Smuzhiyun  * @reg:	register's address.
231*4882a593Smuzhiyun  * @buf:	buffer to write. length must be bc + 1.
232*4882a593Smuzhiyun  */
pmic_arb_write_data(struct spmi_pmic_arb * pmic_arb,const u8 * buf,u32 reg,u8 bc)233*4882a593Smuzhiyun static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf,
234*4882a593Smuzhiyun 				u32 reg, u8 bc)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	u32 data = 0;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	memcpy(&data, buf, (bc & 3) + 1);
239*4882a593Smuzhiyun 	__raw_writel(data, pmic_arb->wr_base + reg);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
pmic_arb_wait_for_done(struct spmi_controller * ctrl,void __iomem * base,u8 sid,u16 addr,enum pmic_arb_channel ch_type)242*4882a593Smuzhiyun static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
243*4882a593Smuzhiyun 				  void __iomem *base, u8 sid, u16 addr,
244*4882a593Smuzhiyun 				  enum pmic_arb_channel ch_type)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
247*4882a593Smuzhiyun 	u32 status = 0;
248*4882a593Smuzhiyun 	u32 timeout = PMIC_ARB_TIMEOUT_US;
249*4882a593Smuzhiyun 	u32 offset;
250*4882a593Smuzhiyun 	int rc;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type);
253*4882a593Smuzhiyun 	if (rc < 0)
254*4882a593Smuzhiyun 		return rc;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	offset = rc;
257*4882a593Smuzhiyun 	offset += PMIC_ARB_STATUS;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	while (timeout--) {
260*4882a593Smuzhiyun 		status = readl_relaxed(base + offset);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		if (status & PMIC_ARB_STATUS_DONE) {
263*4882a593Smuzhiyun 			if (status & PMIC_ARB_STATUS_DENIED) {
264*4882a593Smuzhiyun 				dev_err(&ctrl->dev, "%s: transaction denied (0x%x)\n",
265*4882a593Smuzhiyun 					__func__, status);
266*4882a593Smuzhiyun 				return -EPERM;
267*4882a593Smuzhiyun 			}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 			if (status & PMIC_ARB_STATUS_FAILURE) {
270*4882a593Smuzhiyun 				dev_err(&ctrl->dev, "%s: transaction failed (0x%x)\n",
271*4882a593Smuzhiyun 					__func__, status);
272*4882a593Smuzhiyun 				return -EIO;
273*4882a593Smuzhiyun 			}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 			if (status & PMIC_ARB_STATUS_DROPPED) {
276*4882a593Smuzhiyun 				dev_err(&ctrl->dev, "%s: transaction dropped (0x%x)\n",
277*4882a593Smuzhiyun 					__func__, status);
278*4882a593Smuzhiyun 				return -EIO;
279*4882a593Smuzhiyun 			}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 			return 0;
282*4882a593Smuzhiyun 		}
283*4882a593Smuzhiyun 		udelay(1);
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	dev_err(&ctrl->dev, "%s: timeout, status 0x%x\n",
287*4882a593Smuzhiyun 		__func__, status);
288*4882a593Smuzhiyun 	return -ETIMEDOUT;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun static int
pmic_arb_non_data_cmd_v1(struct spmi_controller * ctrl,u8 opc,u8 sid)292*4882a593Smuzhiyun pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
295*4882a593Smuzhiyun 	unsigned long flags;
296*4882a593Smuzhiyun 	u32 cmd;
297*4882a593Smuzhiyun 	int rc;
298*4882a593Smuzhiyun 	u32 offset;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW);
301*4882a593Smuzhiyun 	if (rc < 0)
302*4882a593Smuzhiyun 		return rc;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	offset = rc;
305*4882a593Smuzhiyun 	cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
308*4882a593Smuzhiyun 	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
309*4882a593Smuzhiyun 	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0,
310*4882a593Smuzhiyun 				    PMIC_ARB_CHANNEL_RW);
311*4882a593Smuzhiyun 	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return rc;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun static int
pmic_arb_non_data_cmd_v2(struct spmi_controller * ctrl,u8 opc,u8 sid)317*4882a593Smuzhiyun pmic_arb_non_data_cmd_v2(struct spmi_controller *ctrl, u8 opc, u8 sid)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	return -EOPNOTSUPP;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun /* Non-data command */
pmic_arb_cmd(struct spmi_controller * ctrl,u8 opc,u8 sid)323*4882a593Smuzhiyun static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	/* Check for valid non-data command */
330*4882a593Smuzhiyun 	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
331*4882a593Smuzhiyun 		return -EINVAL;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid);
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
pmic_arb_read_cmd(struct spmi_controller * ctrl,u8 opc,u8 sid,u16 addr,u8 * buf,size_t len)336*4882a593Smuzhiyun static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
337*4882a593Smuzhiyun 			     u16 addr, u8 *buf, size_t len)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
340*4882a593Smuzhiyun 	unsigned long flags;
341*4882a593Smuzhiyun 	u8 bc = len - 1;
342*4882a593Smuzhiyun 	u32 cmd;
343*4882a593Smuzhiyun 	int rc;
344*4882a593Smuzhiyun 	u32 offset;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr,
347*4882a593Smuzhiyun 				       PMIC_ARB_CHANNEL_OBS);
348*4882a593Smuzhiyun 	if (rc < 0)
349*4882a593Smuzhiyun 		return rc;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	offset = rc;
352*4882a593Smuzhiyun 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
353*4882a593Smuzhiyun 		dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
354*4882a593Smuzhiyun 			PMIC_ARB_MAX_TRANS_BYTES, len);
355*4882a593Smuzhiyun 		return  -EINVAL;
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	/* Check the opcode */
359*4882a593Smuzhiyun 	if (opc >= 0x60 && opc <= 0x7F)
360*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_READ;
361*4882a593Smuzhiyun 	else if (opc >= 0x20 && opc <= 0x2F)
362*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_EXT_READ;
363*4882a593Smuzhiyun 	else if (opc >= 0x38 && opc <= 0x3F)
364*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_EXT_READL;
365*4882a593Smuzhiyun 	else
366*4882a593Smuzhiyun 		return -EINVAL;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
371*4882a593Smuzhiyun 	pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd);
372*4882a593Smuzhiyun 	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr,
373*4882a593Smuzhiyun 				    PMIC_ARB_CHANNEL_OBS);
374*4882a593Smuzhiyun 	if (rc)
375*4882a593Smuzhiyun 		goto done;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	pmic_arb_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0,
378*4882a593Smuzhiyun 		     min_t(u8, bc, 3));
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (bc > 3)
381*4882a593Smuzhiyun 		pmic_arb_read_data(pmic_arb, buf + 4, offset + PMIC_ARB_RDATA1,
382*4882a593Smuzhiyun 					bc - 4);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun done:
385*4882a593Smuzhiyun 	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
386*4882a593Smuzhiyun 	return rc;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun 
pmic_arb_write_cmd(struct spmi_controller * ctrl,u8 opc,u8 sid,u16 addr,const u8 * buf,size_t len)389*4882a593Smuzhiyun static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
390*4882a593Smuzhiyun 			u16 addr, const u8 *buf, size_t len)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
393*4882a593Smuzhiyun 	unsigned long flags;
394*4882a593Smuzhiyun 	u8 bc = len - 1;
395*4882a593Smuzhiyun 	u32 cmd;
396*4882a593Smuzhiyun 	int rc;
397*4882a593Smuzhiyun 	u32 offset;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr,
400*4882a593Smuzhiyun 					PMIC_ARB_CHANNEL_RW);
401*4882a593Smuzhiyun 	if (rc < 0)
402*4882a593Smuzhiyun 		return rc;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	offset = rc;
405*4882a593Smuzhiyun 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
406*4882a593Smuzhiyun 		dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
407*4882a593Smuzhiyun 			PMIC_ARB_MAX_TRANS_BYTES, len);
408*4882a593Smuzhiyun 		return  -EINVAL;
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/* Check the opcode */
412*4882a593Smuzhiyun 	if (opc >= 0x40 && opc <= 0x5F)
413*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_WRITE;
414*4882a593Smuzhiyun 	else if (opc <= 0x0F)
415*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_EXT_WRITE;
416*4882a593Smuzhiyun 	else if (opc >= 0x30 && opc <= 0x37)
417*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_EXT_WRITEL;
418*4882a593Smuzhiyun 	else if (opc >= 0x80)
419*4882a593Smuzhiyun 		opc = PMIC_ARB_OP_ZERO_WRITE;
420*4882a593Smuzhiyun 	else
421*4882a593Smuzhiyun 		return -EINVAL;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	/* Write data to FIFOs */
426*4882a593Smuzhiyun 	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
427*4882a593Smuzhiyun 	pmic_arb_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0,
428*4882a593Smuzhiyun 				min_t(u8, bc, 3));
429*4882a593Smuzhiyun 	if (bc > 3)
430*4882a593Smuzhiyun 		pmic_arb_write_data(pmic_arb, buf + 4, offset + PMIC_ARB_WDATA1,
431*4882a593Smuzhiyun 					bc - 4);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	/* Start the transaction */
434*4882a593Smuzhiyun 	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
435*4882a593Smuzhiyun 	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr,
436*4882a593Smuzhiyun 				    PMIC_ARB_CHANNEL_RW);
437*4882a593Smuzhiyun 	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	return rc;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun enum qpnpint_regs {
443*4882a593Smuzhiyun 	QPNPINT_REG_RT_STS		= 0x10,
444*4882a593Smuzhiyun 	QPNPINT_REG_SET_TYPE		= 0x11,
445*4882a593Smuzhiyun 	QPNPINT_REG_POLARITY_HIGH	= 0x12,
446*4882a593Smuzhiyun 	QPNPINT_REG_POLARITY_LOW	= 0x13,
447*4882a593Smuzhiyun 	QPNPINT_REG_LATCHED_CLR		= 0x14,
448*4882a593Smuzhiyun 	QPNPINT_REG_EN_SET		= 0x15,
449*4882a593Smuzhiyun 	QPNPINT_REG_EN_CLR		= 0x16,
450*4882a593Smuzhiyun 	QPNPINT_REG_LATCHED_STS		= 0x18,
451*4882a593Smuzhiyun };
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun struct spmi_pmic_arb_qpnpint_type {
454*4882a593Smuzhiyun 	u8 type; /* 1 -> edge */
455*4882a593Smuzhiyun 	u8 polarity_high;
456*4882a593Smuzhiyun 	u8 polarity_low;
457*4882a593Smuzhiyun } __packed;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun /* Simplified accessor functions for irqchip callbacks */
qpnpint_spmi_write(struct irq_data * d,u8 reg,void * buf,size_t len)460*4882a593Smuzhiyun static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
461*4882a593Smuzhiyun 			       size_t len)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
464*4882a593Smuzhiyun 	u8 sid = hwirq_to_sid(d->hwirq);
465*4882a593Smuzhiyun 	u8 per = hwirq_to_per(d->hwirq);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
468*4882a593Smuzhiyun 			       (per << 8) + reg, buf, len))
469*4882a593Smuzhiyun 		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n",
470*4882a593Smuzhiyun 				    d->irq);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
qpnpint_spmi_read(struct irq_data * d,u8 reg,void * buf,size_t len)473*4882a593Smuzhiyun static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
476*4882a593Smuzhiyun 	u8 sid = hwirq_to_sid(d->hwirq);
477*4882a593Smuzhiyun 	u8 per = hwirq_to_per(d->hwirq);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (pmic_arb_read_cmd(pmic_arb->spmic, SPMI_CMD_EXT_READL, sid,
480*4882a593Smuzhiyun 			      (per << 8) + reg, buf, len))
481*4882a593Smuzhiyun 		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n",
482*4882a593Smuzhiyun 				    d->irq);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
cleanup_irq(struct spmi_pmic_arb * pmic_arb,u16 apid,int id)485*4882a593Smuzhiyun static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	u16 ppid = pmic_arb->apid_data[apid].ppid;
488*4882a593Smuzhiyun 	u8 sid = ppid >> 8;
489*4882a593Smuzhiyun 	u8 per = ppid & 0xFF;
490*4882a593Smuzhiyun 	u8 irq_mask = BIT(id);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
495*4882a593Smuzhiyun 			(per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1))
496*4882a593Smuzhiyun 		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n",
497*4882a593Smuzhiyun 				irq_mask, ppid);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
500*4882a593Smuzhiyun 			       (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1))
501*4882a593Smuzhiyun 		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n",
502*4882a593Smuzhiyun 				irq_mask, ppid);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
periph_interrupt(struct spmi_pmic_arb * pmic_arb,u16 apid)505*4882a593Smuzhiyun static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	unsigned int irq;
508*4882a593Smuzhiyun 	u32 status, id;
509*4882a593Smuzhiyun 	u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF;
510*4882a593Smuzhiyun 	u8 per = pmic_arb->apid_data[apid].ppid & 0xFF;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid));
513*4882a593Smuzhiyun 	while (status) {
514*4882a593Smuzhiyun 		id = ffs(status) - 1;
515*4882a593Smuzhiyun 		status &= ~BIT(id);
516*4882a593Smuzhiyun 		irq = irq_find_mapping(pmic_arb->domain,
517*4882a593Smuzhiyun 					spec_to_hwirq(sid, per, id, apid));
518*4882a593Smuzhiyun 		if (irq == 0) {
519*4882a593Smuzhiyun 			cleanup_irq(pmic_arb, apid, id);
520*4882a593Smuzhiyun 			continue;
521*4882a593Smuzhiyun 		}
522*4882a593Smuzhiyun 		generic_handle_irq(irq);
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
pmic_arb_chained_irq(struct irq_desc * desc)526*4882a593Smuzhiyun static void pmic_arb_chained_irq(struct irq_desc *desc)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc);
529*4882a593Smuzhiyun 	const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops;
530*4882a593Smuzhiyun 	struct irq_chip *chip = irq_desc_get_chip(desc);
531*4882a593Smuzhiyun 	int first = pmic_arb->min_apid >> 5;
532*4882a593Smuzhiyun 	int last = pmic_arb->max_apid >> 5;
533*4882a593Smuzhiyun 	u8 ee = pmic_arb->ee;
534*4882a593Smuzhiyun 	u32 status, enable;
535*4882a593Smuzhiyun 	int i, id, apid;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	chained_irq_enter(chip, desc);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	for (i = first; i <= last; ++i) {
540*4882a593Smuzhiyun 		status = readl_relaxed(
541*4882a593Smuzhiyun 				ver_ops->owner_acc_status(pmic_arb, ee, i));
542*4882a593Smuzhiyun 		while (status) {
543*4882a593Smuzhiyun 			id = ffs(status) - 1;
544*4882a593Smuzhiyun 			status &= ~BIT(id);
545*4882a593Smuzhiyun 			apid = id + i * 32;
546*4882a593Smuzhiyun 			enable = readl_relaxed(
547*4882a593Smuzhiyun 					ver_ops->acc_enable(pmic_arb, apid));
548*4882a593Smuzhiyun 			if (enable & SPMI_PIC_ACC_ENABLE_BIT)
549*4882a593Smuzhiyun 				periph_interrupt(pmic_arb, apid);
550*4882a593Smuzhiyun 		}
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	chained_irq_exit(chip, desc);
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
qpnpint_irq_ack(struct irq_data * d)556*4882a593Smuzhiyun static void qpnpint_irq_ack(struct irq_data *d)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
559*4882a593Smuzhiyun 	u8 irq = hwirq_to_irq(d->hwirq);
560*4882a593Smuzhiyun 	u16 apid = hwirq_to_apid(d->hwirq);
561*4882a593Smuzhiyun 	u8 data;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	data = BIT(irq);
566*4882a593Smuzhiyun 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
qpnpint_irq_mask(struct irq_data * d)569*4882a593Smuzhiyun static void qpnpint_irq_mask(struct irq_data *d)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun 	u8 irq = hwirq_to_irq(d->hwirq);
572*4882a593Smuzhiyun 	u8 data = BIT(irq);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun 
qpnpint_irq_unmask(struct irq_data * d)577*4882a593Smuzhiyun static void qpnpint_irq_unmask(struct irq_data *d)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
580*4882a593Smuzhiyun 	const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops;
581*4882a593Smuzhiyun 	u8 irq = hwirq_to_irq(d->hwirq);
582*4882a593Smuzhiyun 	u16 apid = hwirq_to_apid(d->hwirq);
583*4882a593Smuzhiyun 	u8 buf[2];
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
586*4882a593Smuzhiyun 			ver_ops->acc_enable(pmic_arb, apid));
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1);
589*4882a593Smuzhiyun 	if (!(buf[0] & BIT(irq))) {
590*4882a593Smuzhiyun 		/*
591*4882a593Smuzhiyun 		 * Since the interrupt is currently disabled, write to both the
592*4882a593Smuzhiyun 		 * LATCHED_CLR and EN_SET registers so that a spurious interrupt
593*4882a593Smuzhiyun 		 * cannot be triggered when the interrupt is enabled
594*4882a593Smuzhiyun 		 */
595*4882a593Smuzhiyun 		buf[0] = BIT(irq);
596*4882a593Smuzhiyun 		buf[1] = BIT(irq);
597*4882a593Smuzhiyun 		qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 2);
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun 
qpnpint_irq_set_type(struct irq_data * d,unsigned int flow_type)601*4882a593Smuzhiyun static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	struct spmi_pmic_arb_qpnpint_type type;
604*4882a593Smuzhiyun 	irq_flow_handler_t flow_handler;
605*4882a593Smuzhiyun 	u8 irq = hwirq_to_irq(d->hwirq);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
610*4882a593Smuzhiyun 		type.type |= BIT(irq);
611*4882a593Smuzhiyun 		if (flow_type & IRQF_TRIGGER_RISING)
612*4882a593Smuzhiyun 			type.polarity_high |= BIT(irq);
613*4882a593Smuzhiyun 		if (flow_type & IRQF_TRIGGER_FALLING)
614*4882a593Smuzhiyun 			type.polarity_low  |= BIT(irq);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 		flow_handler = handle_edge_irq;
617*4882a593Smuzhiyun 	} else {
618*4882a593Smuzhiyun 		if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
619*4882a593Smuzhiyun 		    (flow_type & (IRQF_TRIGGER_LOW)))
620*4882a593Smuzhiyun 			return -EINVAL;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 		type.type &= ~BIT(irq); /* level trig */
623*4882a593Smuzhiyun 		if (flow_type & IRQF_TRIGGER_HIGH)
624*4882a593Smuzhiyun 			type.polarity_high |= BIT(irq);
625*4882a593Smuzhiyun 		else
626*4882a593Smuzhiyun 			type.polarity_low  |= BIT(irq);
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 		flow_handler = handle_level_irq;
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
632*4882a593Smuzhiyun 	irq_set_handler_locked(d, flow_handler);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	return 0;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
qpnpint_irq_set_wake(struct irq_data * d,unsigned int on)637*4882a593Smuzhiyun static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return irq_set_irq_wake(pmic_arb->irq, on);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
qpnpint_get_irqchip_state(struct irq_data * d,enum irqchip_irq_state which,bool * state)644*4882a593Smuzhiyun static int qpnpint_get_irqchip_state(struct irq_data *d,
645*4882a593Smuzhiyun 				     enum irqchip_irq_state which,
646*4882a593Smuzhiyun 				     bool *state)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun 	u8 irq = hwirq_to_irq(d->hwirq);
649*4882a593Smuzhiyun 	u8 status = 0;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	if (which != IRQCHIP_STATE_LINE_LEVEL)
652*4882a593Smuzhiyun 		return -EINVAL;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	qpnpint_spmi_read(d, QPNPINT_REG_RT_STS, &status, 1);
655*4882a593Smuzhiyun 	*state = !!(status & BIT(irq));
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	return 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
qpnpint_irq_domain_activate(struct irq_domain * domain,struct irq_data * d,bool reserve)660*4882a593Smuzhiyun static int qpnpint_irq_domain_activate(struct irq_domain *domain,
661*4882a593Smuzhiyun 				       struct irq_data *d, bool reserve)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
664*4882a593Smuzhiyun 	u16 periph = hwirq_to_per(d->hwirq);
665*4882a593Smuzhiyun 	u16 apid = hwirq_to_apid(d->hwirq);
666*4882a593Smuzhiyun 	u16 sid = hwirq_to_sid(d->hwirq);
667*4882a593Smuzhiyun 	u16 irq = hwirq_to_irq(d->hwirq);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) {
670*4882a593Smuzhiyun 		dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n",
671*4882a593Smuzhiyun 			sid, periph, irq, pmic_arb->ee,
672*4882a593Smuzhiyun 			pmic_arb->apid_data[apid].irq_ee);
673*4882a593Smuzhiyun 		return -ENODEV;
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	return 0;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun static struct irq_chip pmic_arb_irqchip = {
680*4882a593Smuzhiyun 	.name		= "pmic_arb",
681*4882a593Smuzhiyun 	.irq_ack	= qpnpint_irq_ack,
682*4882a593Smuzhiyun 	.irq_mask	= qpnpint_irq_mask,
683*4882a593Smuzhiyun 	.irq_unmask	= qpnpint_irq_unmask,
684*4882a593Smuzhiyun 	.irq_set_type	= qpnpint_irq_set_type,
685*4882a593Smuzhiyun 	.irq_set_wake	= qpnpint_irq_set_wake,
686*4882a593Smuzhiyun 	.irq_get_irqchip_state	= qpnpint_get_irqchip_state,
687*4882a593Smuzhiyun 	.flags		= IRQCHIP_MASK_ON_SUSPEND,
688*4882a593Smuzhiyun };
689*4882a593Smuzhiyun 
qpnpint_irq_domain_translate(struct irq_domain * d,struct irq_fwspec * fwspec,unsigned long * out_hwirq,unsigned int * out_type)690*4882a593Smuzhiyun static int qpnpint_irq_domain_translate(struct irq_domain *d,
691*4882a593Smuzhiyun 					struct irq_fwspec *fwspec,
692*4882a593Smuzhiyun 					unsigned long *out_hwirq,
693*4882a593Smuzhiyun 					unsigned int *out_type)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = d->host_data;
696*4882a593Smuzhiyun 	u32 *intspec = fwspec->param;
697*4882a593Smuzhiyun 	u16 apid, ppid;
698*4882a593Smuzhiyun 	int rc;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
701*4882a593Smuzhiyun 		intspec[0], intspec[1], intspec[2]);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	if (irq_domain_get_of_node(d) != pmic_arb->spmic->dev.of_node)
704*4882a593Smuzhiyun 		return -EINVAL;
705*4882a593Smuzhiyun 	if (fwspec->param_count != 4)
706*4882a593Smuzhiyun 		return -EINVAL;
707*4882a593Smuzhiyun 	if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
708*4882a593Smuzhiyun 		return -EINVAL;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	ppid = intspec[0] << 8 | intspec[1];
711*4882a593Smuzhiyun 	rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
712*4882a593Smuzhiyun 	if (rc < 0) {
713*4882a593Smuzhiyun 		dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n",
714*4882a593Smuzhiyun 		intspec[0], intspec[1], intspec[2], rc);
715*4882a593Smuzhiyun 		return rc;
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	apid = rc;
719*4882a593Smuzhiyun 	/* Keep track of {max,min}_apid for bounding search during interrupt */
720*4882a593Smuzhiyun 	if (apid > pmic_arb->max_apid)
721*4882a593Smuzhiyun 		pmic_arb->max_apid = apid;
722*4882a593Smuzhiyun 	if (apid < pmic_arb->min_apid)
723*4882a593Smuzhiyun 		pmic_arb->min_apid = apid;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	*out_hwirq = spec_to_hwirq(intspec[0], intspec[1], intspec[2], apid);
726*4882a593Smuzhiyun 	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	dev_dbg(&pmic_arb->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	return 0;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun static struct lock_class_key qpnpint_irq_lock_class, qpnpint_irq_request_class;
734*4882a593Smuzhiyun 
qpnpint_irq_domain_map(struct spmi_pmic_arb * pmic_arb,struct irq_domain * domain,unsigned int virq,irq_hw_number_t hwirq,unsigned int type)735*4882a593Smuzhiyun static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb,
736*4882a593Smuzhiyun 				   struct irq_domain *domain, unsigned int virq,
737*4882a593Smuzhiyun 				   irq_hw_number_t hwirq, unsigned int type)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	irq_flow_handler_t handler;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu, type = %u\n",
742*4882a593Smuzhiyun 		virq, hwirq, type);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	if (type & IRQ_TYPE_EDGE_BOTH)
745*4882a593Smuzhiyun 		handler = handle_edge_irq;
746*4882a593Smuzhiyun 	else
747*4882a593Smuzhiyun 		handler = handle_level_irq;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	irq_set_lockdep_class(virq, &qpnpint_irq_lock_class,
751*4882a593Smuzhiyun 			      &qpnpint_irq_request_class);
752*4882a593Smuzhiyun 	irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, pmic_arb,
753*4882a593Smuzhiyun 			    handler, NULL, NULL);
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun 
qpnpint_irq_domain_alloc(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs,void * data)756*4882a593Smuzhiyun static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
757*4882a593Smuzhiyun 				    unsigned int virq, unsigned int nr_irqs,
758*4882a593Smuzhiyun 				    void *data)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = domain->host_data;
761*4882a593Smuzhiyun 	struct irq_fwspec *fwspec = data;
762*4882a593Smuzhiyun 	irq_hw_number_t hwirq;
763*4882a593Smuzhiyun 	unsigned int type;
764*4882a593Smuzhiyun 	int ret, i;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	ret = qpnpint_irq_domain_translate(domain, fwspec, &hwirq, &type);
767*4882a593Smuzhiyun 	if (ret)
768*4882a593Smuzhiyun 		return ret;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	for (i = 0; i < nr_irqs; i++)
771*4882a593Smuzhiyun 		qpnpint_irq_domain_map(pmic_arb, domain, virq + i, hwirq + i,
772*4882a593Smuzhiyun 				       type);
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	return 0;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun 
pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb * pmic_arb,u16 ppid)777*4882a593Smuzhiyun static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun 	u32 *mapping_table = pmic_arb->mapping_table;
780*4882a593Smuzhiyun 	int index = 0, i;
781*4882a593Smuzhiyun 	u16 apid_valid;
782*4882a593Smuzhiyun 	u16 apid;
783*4882a593Smuzhiyun 	u32 data;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	apid_valid = pmic_arb->ppid_to_apid[ppid];
786*4882a593Smuzhiyun 	if (apid_valid & PMIC_ARB_APID_VALID) {
787*4882a593Smuzhiyun 		apid = apid_valid & ~PMIC_ARB_APID_VALID;
788*4882a593Smuzhiyun 		return apid;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
792*4882a593Smuzhiyun 		if (!test_and_set_bit(index, pmic_arb->mapping_table_valid))
793*4882a593Smuzhiyun 			mapping_table[index] = readl_relaxed(pmic_arb->cnfg +
794*4882a593Smuzhiyun 						SPMI_MAPPING_TABLE_REG(index));
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 		data = mapping_table[index];
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
799*4882a593Smuzhiyun 			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
800*4882a593Smuzhiyun 				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
801*4882a593Smuzhiyun 			} else {
802*4882a593Smuzhiyun 				apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
803*4882a593Smuzhiyun 				pmic_arb->ppid_to_apid[ppid]
804*4882a593Smuzhiyun 					= apid | PMIC_ARB_APID_VALID;
805*4882a593Smuzhiyun 				pmic_arb->apid_data[apid].ppid = ppid;
806*4882a593Smuzhiyun 				return apid;
807*4882a593Smuzhiyun 			}
808*4882a593Smuzhiyun 		} else {
809*4882a593Smuzhiyun 			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
810*4882a593Smuzhiyun 				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
811*4882a593Smuzhiyun 			} else {
812*4882a593Smuzhiyun 				apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
813*4882a593Smuzhiyun 				pmic_arb->ppid_to_apid[ppid]
814*4882a593Smuzhiyun 					= apid | PMIC_ARB_APID_VALID;
815*4882a593Smuzhiyun 				pmic_arb->apid_data[apid].ppid = ppid;
816*4882a593Smuzhiyun 				return apid;
817*4882a593Smuzhiyun 			}
818*4882a593Smuzhiyun 		}
819*4882a593Smuzhiyun 	}
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	return -ENODEV;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun /* v1 offset per ee */
pmic_arb_offset_v1(struct spmi_pmic_arb * pmic_arb,u8 sid,u16 addr,enum pmic_arb_channel ch_type)825*4882a593Smuzhiyun static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
826*4882a593Smuzhiyun 			enum pmic_arb_channel ch_type)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun 	return 0x800 + 0x80 * pmic_arb->channel;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun 
pmic_arb_find_apid(struct spmi_pmic_arb * pmic_arb,u16 ppid)831*4882a593Smuzhiyun static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun 	struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid];
834*4882a593Smuzhiyun 	u32 regval, offset;
835*4882a593Smuzhiyun 	u16 id, apid;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	for (apid = pmic_arb->last_apid; ; apid++, apidd++) {
838*4882a593Smuzhiyun 		offset = pmic_arb->ver_ops->apid_map_offset(apid);
839*4882a593Smuzhiyun 		if (offset >= pmic_arb->core_size)
840*4882a593Smuzhiyun 			break;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 		regval = readl_relaxed(pmic_arb->cnfg +
843*4882a593Smuzhiyun 				      SPMI_OWNERSHIP_TABLE_REG(apid));
844*4882a593Smuzhiyun 		apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
845*4882a593Smuzhiyun 		apidd->write_ee = apidd->irq_ee;
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 		regval = readl_relaxed(pmic_arb->core + offset);
848*4882a593Smuzhiyun 		if (!regval)
849*4882a593Smuzhiyun 			continue;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
852*4882a593Smuzhiyun 		pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID;
853*4882a593Smuzhiyun 		apidd->ppid = id;
854*4882a593Smuzhiyun 		if (id == ppid) {
855*4882a593Smuzhiyun 			apid |= PMIC_ARB_APID_VALID;
856*4882a593Smuzhiyun 			break;
857*4882a593Smuzhiyun 		}
858*4882a593Smuzhiyun 	}
859*4882a593Smuzhiyun 	pmic_arb->last_apid = apid & ~PMIC_ARB_APID_VALID;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	return apid;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun 
pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb * pmic_arb,u16 ppid)864*4882a593Smuzhiyun static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun 	u16 apid_valid;
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	apid_valid = pmic_arb->ppid_to_apid[ppid];
869*4882a593Smuzhiyun 	if (!(apid_valid & PMIC_ARB_APID_VALID))
870*4882a593Smuzhiyun 		apid_valid = pmic_arb_find_apid(pmic_arb, ppid);
871*4882a593Smuzhiyun 	if (!(apid_valid & PMIC_ARB_APID_VALID))
872*4882a593Smuzhiyun 		return -ENODEV;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	return apid_valid & ~PMIC_ARB_APID_VALID;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun 
pmic_arb_read_apid_map_v5(struct spmi_pmic_arb * pmic_arb)877*4882a593Smuzhiyun static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun 	struct apid_data *apidd = pmic_arb->apid_data;
880*4882a593Smuzhiyun 	struct apid_data *prev_apidd;
881*4882a593Smuzhiyun 	u16 i, apid, ppid;
882*4882a593Smuzhiyun 	bool valid, is_irq_ee;
883*4882a593Smuzhiyun 	u32 regval, offset;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	/*
886*4882a593Smuzhiyun 	 * In order to allow multiple EEs to write to a single PPID in arbiter
887*4882a593Smuzhiyun 	 * version 5, there is more than one APID mapped to each PPID.
888*4882a593Smuzhiyun 	 * The owner field for each of these mappings specifies the EE which is
889*4882a593Smuzhiyun 	 * allowed to write to the APID.  The owner of the last (highest) APID
890*4882a593Smuzhiyun 	 * which has the IRQ owner bit set for a given PPID will receive
891*4882a593Smuzhiyun 	 * interrupts from the PPID.
892*4882a593Smuzhiyun 	 */
893*4882a593Smuzhiyun 	for (i = 0; ; i++, apidd++) {
894*4882a593Smuzhiyun 		offset = pmic_arb->ver_ops->apid_map_offset(i);
895*4882a593Smuzhiyun 		if (offset >= pmic_arb->core_size)
896*4882a593Smuzhiyun 			break;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 		regval = readl_relaxed(pmic_arb->core + offset);
899*4882a593Smuzhiyun 		if (!regval)
900*4882a593Smuzhiyun 			continue;
901*4882a593Smuzhiyun 		ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
902*4882a593Smuzhiyun 		is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 		regval = readl_relaxed(pmic_arb->cnfg +
905*4882a593Smuzhiyun 				      SPMI_OWNERSHIP_TABLE_REG(i));
906*4882a593Smuzhiyun 		apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 		apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 		valid = pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID;
911*4882a593Smuzhiyun 		apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
912*4882a593Smuzhiyun 		prev_apidd = &pmic_arb->apid_data[apid];
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 		if (!valid || apidd->write_ee == pmic_arb->ee) {
915*4882a593Smuzhiyun 			/* First PPID mapping or one for this EE */
916*4882a593Smuzhiyun 			pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
917*4882a593Smuzhiyun 		} else if (valid && is_irq_ee &&
918*4882a593Smuzhiyun 			   prev_apidd->write_ee == pmic_arb->ee) {
919*4882a593Smuzhiyun 			/*
920*4882a593Smuzhiyun 			 * Duplicate PPID mapping after the one for this EE;
921*4882a593Smuzhiyun 			 * override the irq owner
922*4882a593Smuzhiyun 			 */
923*4882a593Smuzhiyun 			prev_apidd->irq_ee = apidd->irq_ee;
924*4882a593Smuzhiyun 		}
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 		apidd->ppid = ppid;
927*4882a593Smuzhiyun 		pmic_arb->last_apid = i;
928*4882a593Smuzhiyun 	}
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	/* Dump the mapping table for debug purposes. */
931*4882a593Smuzhiyun 	dev_dbg(&pmic_arb->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
932*4882a593Smuzhiyun 	for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) {
933*4882a593Smuzhiyun 		apid = pmic_arb->ppid_to_apid[ppid];
934*4882a593Smuzhiyun 		if (apid & PMIC_ARB_APID_VALID) {
935*4882a593Smuzhiyun 			apid &= ~PMIC_ARB_APID_VALID;
936*4882a593Smuzhiyun 			apidd = &pmic_arb->apid_data[apid];
937*4882a593Smuzhiyun 			dev_dbg(&pmic_arb->spmic->dev, "%#03X %3u %2u %2u\n",
938*4882a593Smuzhiyun 			      ppid, apid, apidd->write_ee, apidd->irq_ee);
939*4882a593Smuzhiyun 		}
940*4882a593Smuzhiyun 	}
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	return 0;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun 
pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb * pmic_arb,u16 ppid)945*4882a593Smuzhiyun static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pmic_arb, u16 ppid)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun 	if (!(pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID))
948*4882a593Smuzhiyun 		return -ENODEV;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	return pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun /* v2 offset per ppid and per ee */
pmic_arb_offset_v2(struct spmi_pmic_arb * pmic_arb,u8 sid,u16 addr,enum pmic_arb_channel ch_type)954*4882a593Smuzhiyun static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
955*4882a593Smuzhiyun 			   enum pmic_arb_channel ch_type)
956*4882a593Smuzhiyun {
957*4882a593Smuzhiyun 	u16 apid;
958*4882a593Smuzhiyun 	u16 ppid;
959*4882a593Smuzhiyun 	int rc;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	ppid = sid << 8 | ((addr >> 8) & 0xFF);
962*4882a593Smuzhiyun 	rc = pmic_arb_ppid_to_apid_v2(pmic_arb, ppid);
963*4882a593Smuzhiyun 	if (rc < 0)
964*4882a593Smuzhiyun 		return rc;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	apid = rc;
967*4882a593Smuzhiyun 	return 0x1000 * pmic_arb->ee + 0x8000 * apid;
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun /*
971*4882a593Smuzhiyun  * v5 offset per ee and per apid for observer channels and per apid for
972*4882a593Smuzhiyun  * read/write channels.
973*4882a593Smuzhiyun  */
pmic_arb_offset_v5(struct spmi_pmic_arb * pmic_arb,u8 sid,u16 addr,enum pmic_arb_channel ch_type)974*4882a593Smuzhiyun static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
975*4882a593Smuzhiyun 			   enum pmic_arb_channel ch_type)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun 	u16 apid;
978*4882a593Smuzhiyun 	int rc;
979*4882a593Smuzhiyun 	u32 offset = 0;
980*4882a593Smuzhiyun 	u16 ppid = (sid << 8) | (addr >> 8);
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	rc = pmic_arb_ppid_to_apid_v5(pmic_arb, ppid);
983*4882a593Smuzhiyun 	if (rc < 0)
984*4882a593Smuzhiyun 		return rc;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	apid = rc;
987*4882a593Smuzhiyun 	switch (ch_type) {
988*4882a593Smuzhiyun 	case PMIC_ARB_CHANNEL_OBS:
989*4882a593Smuzhiyun 		offset = 0x10000 * pmic_arb->ee + 0x80 * apid;
990*4882a593Smuzhiyun 		break;
991*4882a593Smuzhiyun 	case PMIC_ARB_CHANNEL_RW:
992*4882a593Smuzhiyun 		offset = 0x10000 * apid;
993*4882a593Smuzhiyun 		break;
994*4882a593Smuzhiyun 	}
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	return offset;
997*4882a593Smuzhiyun }
998*4882a593Smuzhiyun 
pmic_arb_fmt_cmd_v1(u8 opc,u8 sid,u16 addr,u8 bc)999*4882a593Smuzhiyun static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
1000*4882a593Smuzhiyun {
1001*4882a593Smuzhiyun 	return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun 
pmic_arb_fmt_cmd_v2(u8 opc,u8 sid,u16 addr,u8 bc)1004*4882a593Smuzhiyun static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun 	return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7);
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun static void __iomem *
pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb * pmic_arb,u8 m,u16 n)1010*4882a593Smuzhiyun pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun 	return pmic_arb->intr + 0x20 * m + 0x4 * n;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun static void __iomem *
pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb * pmic_arb,u8 m,u16 n)1016*4882a593Smuzhiyun pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
1017*4882a593Smuzhiyun {
1018*4882a593Smuzhiyun 	return pmic_arb->intr + 0x100000 + 0x1000 * m + 0x4 * n;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun static void __iomem *
pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb * pmic_arb,u8 m,u16 n)1022*4882a593Smuzhiyun pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
1023*4882a593Smuzhiyun {
1024*4882a593Smuzhiyun 	return pmic_arb->intr + 0x200000 + 0x1000 * m + 0x4 * n;
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun static void __iomem *
pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb * pmic_arb,u8 m,u16 n)1028*4882a593Smuzhiyun pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun 	return pmic_arb->intr + 0x10000 * m + 0x4 * n;
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun static void __iomem *
pmic_arb_acc_enable_v1(struct spmi_pmic_arb * pmic_arb,u16 n)1034*4882a593Smuzhiyun pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun 	return pmic_arb->intr + 0x200 + 0x4 * n;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun static void __iomem *
pmic_arb_acc_enable_v2(struct spmi_pmic_arb * pmic_arb,u16 n)1040*4882a593Smuzhiyun pmic_arb_acc_enable_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun 	return pmic_arb->intr + 0x1000 * n;
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun static void __iomem *
pmic_arb_acc_enable_v5(struct spmi_pmic_arb * pmic_arb,u16 n)1046*4882a593Smuzhiyun pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
1047*4882a593Smuzhiyun {
1048*4882a593Smuzhiyun 	return pmic_arb->wr_base + 0x100 + 0x10000 * n;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun static void __iomem *
pmic_arb_irq_status_v1(struct spmi_pmic_arb * pmic_arb,u16 n)1052*4882a593Smuzhiyun pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
1053*4882a593Smuzhiyun {
1054*4882a593Smuzhiyun 	return pmic_arb->intr + 0x600 + 0x4 * n;
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun static void __iomem *
pmic_arb_irq_status_v2(struct spmi_pmic_arb * pmic_arb,u16 n)1058*4882a593Smuzhiyun pmic_arb_irq_status_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
1059*4882a593Smuzhiyun {
1060*4882a593Smuzhiyun 	return pmic_arb->intr + 0x4 + 0x1000 * n;
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun static void __iomem *
pmic_arb_irq_status_v5(struct spmi_pmic_arb * pmic_arb,u16 n)1064*4882a593Smuzhiyun pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
1065*4882a593Smuzhiyun {
1066*4882a593Smuzhiyun 	return pmic_arb->wr_base + 0x104 + 0x10000 * n;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun static void __iomem *
pmic_arb_irq_clear_v1(struct spmi_pmic_arb * pmic_arb,u16 n)1070*4882a593Smuzhiyun pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun 	return pmic_arb->intr + 0xA00 + 0x4 * n;
1073*4882a593Smuzhiyun }
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun static void __iomem *
pmic_arb_irq_clear_v2(struct spmi_pmic_arb * pmic_arb,u16 n)1076*4882a593Smuzhiyun pmic_arb_irq_clear_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun 	return pmic_arb->intr + 0x8 + 0x1000 * n;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun static void __iomem *
pmic_arb_irq_clear_v5(struct spmi_pmic_arb * pmic_arb,u16 n)1082*4882a593Smuzhiyun pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun 	return pmic_arb->wr_base + 0x108 + 0x10000 * n;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun 
pmic_arb_apid_map_offset_v2(u16 n)1087*4882a593Smuzhiyun static u32 pmic_arb_apid_map_offset_v2(u16 n)
1088*4882a593Smuzhiyun {
1089*4882a593Smuzhiyun 	return 0x800 + 0x4 * n;
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun 
pmic_arb_apid_map_offset_v5(u16 n)1092*4882a593Smuzhiyun static u32 pmic_arb_apid_map_offset_v5(u16 n)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun 	return 0x900 + 0x4 * n;
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun static const struct pmic_arb_ver_ops pmic_arb_v1 = {
1098*4882a593Smuzhiyun 	.ver_str		= "v1",
1099*4882a593Smuzhiyun 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v1,
1100*4882a593Smuzhiyun 	.non_data_cmd		= pmic_arb_non_data_cmd_v1,
1101*4882a593Smuzhiyun 	.offset			= pmic_arb_offset_v1,
1102*4882a593Smuzhiyun 	.fmt_cmd		= pmic_arb_fmt_cmd_v1,
1103*4882a593Smuzhiyun 	.owner_acc_status	= pmic_arb_owner_acc_status_v1,
1104*4882a593Smuzhiyun 	.acc_enable		= pmic_arb_acc_enable_v1,
1105*4882a593Smuzhiyun 	.irq_status		= pmic_arb_irq_status_v1,
1106*4882a593Smuzhiyun 	.irq_clear		= pmic_arb_irq_clear_v1,
1107*4882a593Smuzhiyun 	.apid_map_offset	= pmic_arb_apid_map_offset_v2,
1108*4882a593Smuzhiyun };
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun static const struct pmic_arb_ver_ops pmic_arb_v2 = {
1111*4882a593Smuzhiyun 	.ver_str		= "v2",
1112*4882a593Smuzhiyun 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v2,
1113*4882a593Smuzhiyun 	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
1114*4882a593Smuzhiyun 	.offset			= pmic_arb_offset_v2,
1115*4882a593Smuzhiyun 	.fmt_cmd		= pmic_arb_fmt_cmd_v2,
1116*4882a593Smuzhiyun 	.owner_acc_status	= pmic_arb_owner_acc_status_v2,
1117*4882a593Smuzhiyun 	.acc_enable		= pmic_arb_acc_enable_v2,
1118*4882a593Smuzhiyun 	.irq_status		= pmic_arb_irq_status_v2,
1119*4882a593Smuzhiyun 	.irq_clear		= pmic_arb_irq_clear_v2,
1120*4882a593Smuzhiyun 	.apid_map_offset	= pmic_arb_apid_map_offset_v2,
1121*4882a593Smuzhiyun };
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun static const struct pmic_arb_ver_ops pmic_arb_v3 = {
1124*4882a593Smuzhiyun 	.ver_str		= "v3",
1125*4882a593Smuzhiyun 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v2,
1126*4882a593Smuzhiyun 	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
1127*4882a593Smuzhiyun 	.offset			= pmic_arb_offset_v2,
1128*4882a593Smuzhiyun 	.fmt_cmd		= pmic_arb_fmt_cmd_v2,
1129*4882a593Smuzhiyun 	.owner_acc_status	= pmic_arb_owner_acc_status_v3,
1130*4882a593Smuzhiyun 	.acc_enable		= pmic_arb_acc_enable_v2,
1131*4882a593Smuzhiyun 	.irq_status		= pmic_arb_irq_status_v2,
1132*4882a593Smuzhiyun 	.irq_clear		= pmic_arb_irq_clear_v2,
1133*4882a593Smuzhiyun 	.apid_map_offset	= pmic_arb_apid_map_offset_v2,
1134*4882a593Smuzhiyun };
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun static const struct pmic_arb_ver_ops pmic_arb_v5 = {
1137*4882a593Smuzhiyun 	.ver_str		= "v5",
1138*4882a593Smuzhiyun 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v5,
1139*4882a593Smuzhiyun 	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
1140*4882a593Smuzhiyun 	.offset			= pmic_arb_offset_v5,
1141*4882a593Smuzhiyun 	.fmt_cmd		= pmic_arb_fmt_cmd_v2,
1142*4882a593Smuzhiyun 	.owner_acc_status	= pmic_arb_owner_acc_status_v5,
1143*4882a593Smuzhiyun 	.acc_enable		= pmic_arb_acc_enable_v5,
1144*4882a593Smuzhiyun 	.irq_status		= pmic_arb_irq_status_v5,
1145*4882a593Smuzhiyun 	.irq_clear		= pmic_arb_irq_clear_v5,
1146*4882a593Smuzhiyun 	.apid_map_offset	= pmic_arb_apid_map_offset_v5,
1147*4882a593Smuzhiyun };
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
1150*4882a593Smuzhiyun 	.activate = qpnpint_irq_domain_activate,
1151*4882a593Smuzhiyun 	.alloc = qpnpint_irq_domain_alloc,
1152*4882a593Smuzhiyun 	.free = irq_domain_free_irqs_common,
1153*4882a593Smuzhiyun 	.translate = qpnpint_irq_domain_translate,
1154*4882a593Smuzhiyun };
1155*4882a593Smuzhiyun 
spmi_pmic_arb_probe(struct platform_device * pdev)1156*4882a593Smuzhiyun static int spmi_pmic_arb_probe(struct platform_device *pdev)
1157*4882a593Smuzhiyun {
1158*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb;
1159*4882a593Smuzhiyun 	struct spmi_controller *ctrl;
1160*4882a593Smuzhiyun 	struct resource *res;
1161*4882a593Smuzhiyun 	void __iomem *core;
1162*4882a593Smuzhiyun 	u32 *mapping_table;
1163*4882a593Smuzhiyun 	u32 channel, ee, hw_ver;
1164*4882a593Smuzhiyun 	int err;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
1167*4882a593Smuzhiyun 	if (!ctrl)
1168*4882a593Smuzhiyun 		return -ENOMEM;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	pmic_arb = spmi_controller_get_drvdata(ctrl);
1171*4882a593Smuzhiyun 	pmic_arb->spmic = ctrl;
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
1174*4882a593Smuzhiyun 	core = devm_ioremap_resource(&ctrl->dev, res);
1175*4882a593Smuzhiyun 	if (IS_ERR(core)) {
1176*4882a593Smuzhiyun 		err = PTR_ERR(core);
1177*4882a593Smuzhiyun 		goto err_put_ctrl;
1178*4882a593Smuzhiyun 	}
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	pmic_arb->core_size = resource_size(res);
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID,
1183*4882a593Smuzhiyun 					      sizeof(*pmic_arb->ppid_to_apid),
1184*4882a593Smuzhiyun 					      GFP_KERNEL);
1185*4882a593Smuzhiyun 	if (!pmic_arb->ppid_to_apid) {
1186*4882a593Smuzhiyun 		err = -ENOMEM;
1187*4882a593Smuzhiyun 		goto err_put_ctrl;
1188*4882a593Smuzhiyun 	}
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 	hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	if (hw_ver < PMIC_ARB_VERSION_V2_MIN) {
1193*4882a593Smuzhiyun 		pmic_arb->ver_ops = &pmic_arb_v1;
1194*4882a593Smuzhiyun 		pmic_arb->wr_base = core;
1195*4882a593Smuzhiyun 		pmic_arb->rd_base = core;
1196*4882a593Smuzhiyun 	} else {
1197*4882a593Smuzhiyun 		pmic_arb->core = core;
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 		if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
1200*4882a593Smuzhiyun 			pmic_arb->ver_ops = &pmic_arb_v2;
1201*4882a593Smuzhiyun 		else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
1202*4882a593Smuzhiyun 			pmic_arb->ver_ops = &pmic_arb_v3;
1203*4882a593Smuzhiyun 		else
1204*4882a593Smuzhiyun 			pmic_arb->ver_ops = &pmic_arb_v5;
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1207*4882a593Smuzhiyun 						   "obsrvr");
1208*4882a593Smuzhiyun 		pmic_arb->rd_base = devm_ioremap_resource(&ctrl->dev, res);
1209*4882a593Smuzhiyun 		if (IS_ERR(pmic_arb->rd_base)) {
1210*4882a593Smuzhiyun 			err = PTR_ERR(pmic_arb->rd_base);
1211*4882a593Smuzhiyun 			goto err_put_ctrl;
1212*4882a593Smuzhiyun 		}
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1215*4882a593Smuzhiyun 						   "chnls");
1216*4882a593Smuzhiyun 		pmic_arb->wr_base = devm_ioremap_resource(&ctrl->dev, res);
1217*4882a593Smuzhiyun 		if (IS_ERR(pmic_arb->wr_base)) {
1218*4882a593Smuzhiyun 			err = PTR_ERR(pmic_arb->wr_base);
1219*4882a593Smuzhiyun 			goto err_put_ctrl;
1220*4882a593Smuzhiyun 		}
1221*4882a593Smuzhiyun 	}
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
1224*4882a593Smuzhiyun 		 pmic_arb->ver_ops->ver_str, hw_ver);
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
1227*4882a593Smuzhiyun 	pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
1228*4882a593Smuzhiyun 	if (IS_ERR(pmic_arb->intr)) {
1229*4882a593Smuzhiyun 		err = PTR_ERR(pmic_arb->intr);
1230*4882a593Smuzhiyun 		goto err_put_ctrl;
1231*4882a593Smuzhiyun 	}
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
1234*4882a593Smuzhiyun 	pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res);
1235*4882a593Smuzhiyun 	if (IS_ERR(pmic_arb->cnfg)) {
1236*4882a593Smuzhiyun 		err = PTR_ERR(pmic_arb->cnfg);
1237*4882a593Smuzhiyun 		goto err_put_ctrl;
1238*4882a593Smuzhiyun 	}
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 	pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq");
1241*4882a593Smuzhiyun 	if (pmic_arb->irq < 0) {
1242*4882a593Smuzhiyun 		err = pmic_arb->irq;
1243*4882a593Smuzhiyun 		goto err_put_ctrl;
1244*4882a593Smuzhiyun 	}
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
1247*4882a593Smuzhiyun 	if (err) {
1248*4882a593Smuzhiyun 		dev_err(&pdev->dev, "channel unspecified.\n");
1249*4882a593Smuzhiyun 		goto err_put_ctrl;
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	if (channel > 5) {
1253*4882a593Smuzhiyun 		dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
1254*4882a593Smuzhiyun 			channel);
1255*4882a593Smuzhiyun 		err = -EINVAL;
1256*4882a593Smuzhiyun 		goto err_put_ctrl;
1257*4882a593Smuzhiyun 	}
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	pmic_arb->channel = channel;
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 	err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee);
1262*4882a593Smuzhiyun 	if (err) {
1263*4882a593Smuzhiyun 		dev_err(&pdev->dev, "EE unspecified.\n");
1264*4882a593Smuzhiyun 		goto err_put_ctrl;
1265*4882a593Smuzhiyun 	}
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	if (ee > 5) {
1268*4882a593Smuzhiyun 		dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee);
1269*4882a593Smuzhiyun 		err = -EINVAL;
1270*4882a593Smuzhiyun 		goto err_put_ctrl;
1271*4882a593Smuzhiyun 	}
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	pmic_arb->ee = ee;
1274*4882a593Smuzhiyun 	mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS,
1275*4882a593Smuzhiyun 					sizeof(*mapping_table), GFP_KERNEL);
1276*4882a593Smuzhiyun 	if (!mapping_table) {
1277*4882a593Smuzhiyun 		err = -ENOMEM;
1278*4882a593Smuzhiyun 		goto err_put_ctrl;
1279*4882a593Smuzhiyun 	}
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	pmic_arb->mapping_table = mapping_table;
1282*4882a593Smuzhiyun 	/* Initialize max_apid/min_apid to the opposite bounds, during
1283*4882a593Smuzhiyun 	 * the irq domain translation, we are sure to update these */
1284*4882a593Smuzhiyun 	pmic_arb->max_apid = 0;
1285*4882a593Smuzhiyun 	pmic_arb->min_apid = PMIC_ARB_MAX_PERIPHS - 1;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	platform_set_drvdata(pdev, ctrl);
1288*4882a593Smuzhiyun 	raw_spin_lock_init(&pmic_arb->lock);
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	ctrl->cmd = pmic_arb_cmd;
1291*4882a593Smuzhiyun 	ctrl->read_cmd = pmic_arb_read_cmd;
1292*4882a593Smuzhiyun 	ctrl->write_cmd = pmic_arb_write_cmd;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
1295*4882a593Smuzhiyun 		err = pmic_arb_read_apid_map_v5(pmic_arb);
1296*4882a593Smuzhiyun 		if (err) {
1297*4882a593Smuzhiyun 			dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n",
1298*4882a593Smuzhiyun 				err);
1299*4882a593Smuzhiyun 			goto err_put_ctrl;
1300*4882a593Smuzhiyun 		}
1301*4882a593Smuzhiyun 	}
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	dev_dbg(&pdev->dev, "adding irq domain\n");
1304*4882a593Smuzhiyun 	pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node,
1305*4882a593Smuzhiyun 					 &pmic_arb_irq_domain_ops, pmic_arb);
1306*4882a593Smuzhiyun 	if (!pmic_arb->domain) {
1307*4882a593Smuzhiyun 		dev_err(&pdev->dev, "unable to create irq_domain\n");
1308*4882a593Smuzhiyun 		err = -ENOMEM;
1309*4882a593Smuzhiyun 		goto err_put_ctrl;
1310*4882a593Smuzhiyun 	}
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq,
1313*4882a593Smuzhiyun 					pmic_arb);
1314*4882a593Smuzhiyun 	err = spmi_controller_add(ctrl);
1315*4882a593Smuzhiyun 	if (err)
1316*4882a593Smuzhiyun 		goto err_domain_remove;
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	return 0;
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun err_domain_remove:
1321*4882a593Smuzhiyun 	irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
1322*4882a593Smuzhiyun 	irq_domain_remove(pmic_arb->domain);
1323*4882a593Smuzhiyun err_put_ctrl:
1324*4882a593Smuzhiyun 	spmi_controller_put(ctrl);
1325*4882a593Smuzhiyun 	return err;
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun 
spmi_pmic_arb_remove(struct platform_device * pdev)1328*4882a593Smuzhiyun static int spmi_pmic_arb_remove(struct platform_device *pdev)
1329*4882a593Smuzhiyun {
1330*4882a593Smuzhiyun 	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
1331*4882a593Smuzhiyun 	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
1332*4882a593Smuzhiyun 	spmi_controller_remove(ctrl);
1333*4882a593Smuzhiyun 	irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
1334*4882a593Smuzhiyun 	irq_domain_remove(pmic_arb->domain);
1335*4882a593Smuzhiyun 	spmi_controller_put(ctrl);
1336*4882a593Smuzhiyun 	return 0;
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun static const struct of_device_id spmi_pmic_arb_match_table[] = {
1340*4882a593Smuzhiyun 	{ .compatible = "qcom,spmi-pmic-arb", },
1341*4882a593Smuzhiyun 	{},
1342*4882a593Smuzhiyun };
1343*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun static struct platform_driver spmi_pmic_arb_driver = {
1346*4882a593Smuzhiyun 	.probe		= spmi_pmic_arb_probe,
1347*4882a593Smuzhiyun 	.remove		= spmi_pmic_arb_remove,
1348*4882a593Smuzhiyun 	.driver		= {
1349*4882a593Smuzhiyun 		.name	= "spmi_pmic_arb",
1350*4882a593Smuzhiyun 		.of_match_table = spmi_pmic_arb_match_table,
1351*4882a593Smuzhiyun 	},
1352*4882a593Smuzhiyun };
1353*4882a593Smuzhiyun module_platform_driver(spmi_pmic_arb_driver);
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1356*4882a593Smuzhiyun MODULE_ALIAS("platform:spmi_pmic_arb");
1357