xref: /OK3568_Linux_fs/kernel/drivers/irqchip/irq-imgpdc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * IMG PowerDown Controller (PDC)
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2010-2013 Imagination Technologies Ltd.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Exposes the syswake and PDC peripheral wake interrupts to the system.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/bitops.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/irqdomain.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/spinlock.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* PDC interrupt register numbers */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define PDC_IRQ_STATUS			0x310
23*4882a593Smuzhiyun #define PDC_IRQ_ENABLE			0x314
24*4882a593Smuzhiyun #define PDC_IRQ_CLEAR			0x318
25*4882a593Smuzhiyun #define PDC_IRQ_ROUTE			0x31c
26*4882a593Smuzhiyun #define PDC_SYS_WAKE_BASE		0x330
27*4882a593Smuzhiyun #define PDC_SYS_WAKE_STRIDE		0x8
28*4882a593Smuzhiyun #define PDC_SYS_WAKE_CONFIG_BASE	0x334
29*4882a593Smuzhiyun #define PDC_SYS_WAKE_CONFIG_STRIDE	0x8
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* PDC interrupt register field masks */
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define PDC_IRQ_SYS3			0x08
34*4882a593Smuzhiyun #define PDC_IRQ_SYS2			0x04
35*4882a593Smuzhiyun #define PDC_IRQ_SYS1			0x02
36*4882a593Smuzhiyun #define PDC_IRQ_SYS0			0x01
37*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_SYS3	0x08000000
38*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_SYS2	0x04000000
39*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_SYS1	0x02000000
40*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_SYS0	0x01000000
41*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_WD		0x00040000
42*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_IR		0x00020000
43*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_WU_EN_RTC		0x00010000
44*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_SYS3	0x00000800
45*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_SYS2	0x00000400
46*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_SYS1	0x00000200
47*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_SYS0	0x00000100
48*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_WD		0x00000004
49*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_IR		0x00000002
50*4882a593Smuzhiyun #define PDC_IRQ_ROUTE_EXT_EN_RTC	0x00000001
51*4882a593Smuzhiyun #define PDC_SYS_WAKE_RESET		0x00000010
52*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_MODE		0x0000000e
53*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_MODE_SHIFT	1
54*4882a593Smuzhiyun #define PDC_SYS_WAKE_PIN_VAL		0x00000001
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /* PDC interrupt constants */
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_LOW		0x0
59*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_HIGH		0x1
60*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_DOWN		0x2
61*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_UP		0x3
62*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_CHANGE		0x6
63*4882a593Smuzhiyun #define PDC_SYS_WAKE_INT_NONE		0x4
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun  * struct pdc_intc_priv - private pdc interrupt data.
67*4882a593Smuzhiyun  * @nr_perips:		Number of peripheral interrupt signals.
68*4882a593Smuzhiyun  * @nr_syswakes:	Number of syswake signals.
69*4882a593Smuzhiyun  * @perip_irqs:		List of peripheral IRQ numbers handled.
70*4882a593Smuzhiyun  * @syswake_irq:	Shared PDC syswake IRQ number.
71*4882a593Smuzhiyun  * @domain:		IRQ domain for PDC peripheral and syswake IRQs.
72*4882a593Smuzhiyun  * @pdc_base:		Base of PDC registers.
73*4882a593Smuzhiyun  * @irq_route:		Cached version of PDC_IRQ_ROUTE register.
74*4882a593Smuzhiyun  * @lock:		Lock to protect the PDC syswake registers and the cached
75*4882a593Smuzhiyun  *			values of those registers in this struct.
76*4882a593Smuzhiyun  */
77*4882a593Smuzhiyun struct pdc_intc_priv {
78*4882a593Smuzhiyun 	unsigned int		nr_perips;
79*4882a593Smuzhiyun 	unsigned int		nr_syswakes;
80*4882a593Smuzhiyun 	unsigned int		*perip_irqs;
81*4882a593Smuzhiyun 	unsigned int		syswake_irq;
82*4882a593Smuzhiyun 	struct irq_domain	*domain;
83*4882a593Smuzhiyun 	void __iomem		*pdc_base;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	u32			irq_route;
86*4882a593Smuzhiyun 	raw_spinlock_t		lock;
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
pdc_write(struct pdc_intc_priv * priv,unsigned int reg_offs,unsigned int data)89*4882a593Smuzhiyun static void pdc_write(struct pdc_intc_priv *priv, unsigned int reg_offs,
90*4882a593Smuzhiyun 		      unsigned int data)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	iowrite32(data, priv->pdc_base + reg_offs);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
pdc_read(struct pdc_intc_priv * priv,unsigned int reg_offs)95*4882a593Smuzhiyun static unsigned int pdc_read(struct pdc_intc_priv *priv,
96*4882a593Smuzhiyun 			     unsigned int reg_offs)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	return ioread32(priv->pdc_base + reg_offs);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /* Generic IRQ callbacks */
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #define SYS0_HWIRQ	8
104*4882a593Smuzhiyun 
hwirq_is_syswake(irq_hw_number_t hw)105*4882a593Smuzhiyun static unsigned int hwirq_is_syswake(irq_hw_number_t hw)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	return hw >= SYS0_HWIRQ;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
hwirq_to_syswake(irq_hw_number_t hw)110*4882a593Smuzhiyun static unsigned int hwirq_to_syswake(irq_hw_number_t hw)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	return hw - SYS0_HWIRQ;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
syswake_to_hwirq(unsigned int syswake)115*4882a593Smuzhiyun static irq_hw_number_t syswake_to_hwirq(unsigned int syswake)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	return SYS0_HWIRQ + syswake;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
irqd_to_priv(struct irq_data * data)120*4882a593Smuzhiyun static struct pdc_intc_priv *irqd_to_priv(struct irq_data *data)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	return (struct pdc_intc_priv *)data->domain->host_data;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * perip_irq_mask() and perip_irq_unmask() use IRQ_ROUTE which also contains
127*4882a593Smuzhiyun  * wake bits, therefore we cannot use the generic irqchip mask callbacks as they
128*4882a593Smuzhiyun  * cache the mask.
129*4882a593Smuzhiyun  */
130*4882a593Smuzhiyun 
perip_irq_mask(struct irq_data * data)131*4882a593Smuzhiyun static void perip_irq_mask(struct irq_data *data)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct pdc_intc_priv *priv = irqd_to_priv(data);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	raw_spin_lock(&priv->lock);
136*4882a593Smuzhiyun 	priv->irq_route &= ~data->mask;
137*4882a593Smuzhiyun 	pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
138*4882a593Smuzhiyun 	raw_spin_unlock(&priv->lock);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
perip_irq_unmask(struct irq_data * data)141*4882a593Smuzhiyun static void perip_irq_unmask(struct irq_data *data)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	struct pdc_intc_priv *priv = irqd_to_priv(data);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	raw_spin_lock(&priv->lock);
146*4882a593Smuzhiyun 	priv->irq_route |= data->mask;
147*4882a593Smuzhiyun 	pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
148*4882a593Smuzhiyun 	raw_spin_unlock(&priv->lock);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
syswake_irq_set_type(struct irq_data * data,unsigned int flow_type)151*4882a593Smuzhiyun static int syswake_irq_set_type(struct irq_data *data, unsigned int flow_type)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct pdc_intc_priv *priv = irqd_to_priv(data);
154*4882a593Smuzhiyun 	unsigned int syswake = hwirq_to_syswake(data->hwirq);
155*4882a593Smuzhiyun 	unsigned int irq_mode;
156*4882a593Smuzhiyun 	unsigned int soc_sys_wake_regoff, soc_sys_wake;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	/* translate to syswake IRQ mode */
159*4882a593Smuzhiyun 	switch (flow_type) {
160*4882a593Smuzhiyun 	case IRQ_TYPE_EDGE_BOTH:
161*4882a593Smuzhiyun 		irq_mode = PDC_SYS_WAKE_INT_CHANGE;
162*4882a593Smuzhiyun 		break;
163*4882a593Smuzhiyun 	case IRQ_TYPE_EDGE_RISING:
164*4882a593Smuzhiyun 		irq_mode = PDC_SYS_WAKE_INT_UP;
165*4882a593Smuzhiyun 		break;
166*4882a593Smuzhiyun 	case IRQ_TYPE_EDGE_FALLING:
167*4882a593Smuzhiyun 		irq_mode = PDC_SYS_WAKE_INT_DOWN;
168*4882a593Smuzhiyun 		break;
169*4882a593Smuzhiyun 	case IRQ_TYPE_LEVEL_HIGH:
170*4882a593Smuzhiyun 		irq_mode = PDC_SYS_WAKE_INT_HIGH;
171*4882a593Smuzhiyun 		break;
172*4882a593Smuzhiyun 	case IRQ_TYPE_LEVEL_LOW:
173*4882a593Smuzhiyun 		irq_mode = PDC_SYS_WAKE_INT_LOW;
174*4882a593Smuzhiyun 		break;
175*4882a593Smuzhiyun 	default:
176*4882a593Smuzhiyun 		return -EINVAL;
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	raw_spin_lock(&priv->lock);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	/* set the IRQ mode */
182*4882a593Smuzhiyun 	soc_sys_wake_regoff = PDC_SYS_WAKE_BASE + syswake*PDC_SYS_WAKE_STRIDE;
183*4882a593Smuzhiyun 	soc_sys_wake = pdc_read(priv, soc_sys_wake_regoff);
184*4882a593Smuzhiyun 	soc_sys_wake &= ~PDC_SYS_WAKE_INT_MODE;
185*4882a593Smuzhiyun 	soc_sys_wake |= irq_mode << PDC_SYS_WAKE_INT_MODE_SHIFT;
186*4882a593Smuzhiyun 	pdc_write(priv, soc_sys_wake_regoff, soc_sys_wake);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	/* and update the handler */
189*4882a593Smuzhiyun 	irq_setup_alt_chip(data, flow_type);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	raw_spin_unlock(&priv->lock);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun /* applies to both peripheral and syswake interrupts */
pdc_irq_set_wake(struct irq_data * data,unsigned int on)197*4882a593Smuzhiyun static int pdc_irq_set_wake(struct irq_data *data, unsigned int on)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct pdc_intc_priv *priv = irqd_to_priv(data);
200*4882a593Smuzhiyun 	irq_hw_number_t hw = data->hwirq;
201*4882a593Smuzhiyun 	unsigned int mask = (1 << 16) << hw;
202*4882a593Smuzhiyun 	unsigned int dst_irq;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	raw_spin_lock(&priv->lock);
205*4882a593Smuzhiyun 	if (on)
206*4882a593Smuzhiyun 		priv->irq_route |= mask;
207*4882a593Smuzhiyun 	else
208*4882a593Smuzhiyun 		priv->irq_route &= ~mask;
209*4882a593Smuzhiyun 	pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
210*4882a593Smuzhiyun 	raw_spin_unlock(&priv->lock);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	/* control the destination IRQ wakeup too for standby mode */
213*4882a593Smuzhiyun 	if (hwirq_is_syswake(hw))
214*4882a593Smuzhiyun 		dst_irq = priv->syswake_irq;
215*4882a593Smuzhiyun 	else
216*4882a593Smuzhiyun 		dst_irq = priv->perip_irqs[hw];
217*4882a593Smuzhiyun 	irq_set_irq_wake(dst_irq, on);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
pdc_intc_perip_isr(struct irq_desc * desc)222*4882a593Smuzhiyun static void pdc_intc_perip_isr(struct irq_desc *desc)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	unsigned int irq = irq_desc_get_irq(desc);
225*4882a593Smuzhiyun 	struct pdc_intc_priv *priv;
226*4882a593Smuzhiyun 	unsigned int i, irq_no;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	/* find the peripheral number */
231*4882a593Smuzhiyun 	for (i = 0; i < priv->nr_perips; ++i)
232*4882a593Smuzhiyun 		if (irq == priv->perip_irqs[i])
233*4882a593Smuzhiyun 			goto found;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/* should never get here */
236*4882a593Smuzhiyun 	return;
237*4882a593Smuzhiyun found:
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/* pass on the interrupt */
240*4882a593Smuzhiyun 	irq_no = irq_linear_revmap(priv->domain, i);
241*4882a593Smuzhiyun 	generic_handle_irq(irq_no);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
pdc_intc_syswake_isr(struct irq_desc * desc)244*4882a593Smuzhiyun static void pdc_intc_syswake_isr(struct irq_desc *desc)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct pdc_intc_priv *priv;
247*4882a593Smuzhiyun 	unsigned int syswake, irq_no;
248*4882a593Smuzhiyun 	unsigned int status;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	status = pdc_read(priv, PDC_IRQ_STATUS) &
253*4882a593Smuzhiyun 		 pdc_read(priv, PDC_IRQ_ENABLE);
254*4882a593Smuzhiyun 	status &= (1 << priv->nr_syswakes) - 1;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	for (syswake = 0; status; status >>= 1, ++syswake) {
257*4882a593Smuzhiyun 		/* Has this sys_wake triggered? */
258*4882a593Smuzhiyun 		if (!(status & 1))
259*4882a593Smuzhiyun 			continue;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 		irq_no = irq_linear_revmap(priv->domain,
262*4882a593Smuzhiyun 					   syswake_to_hwirq(syswake));
263*4882a593Smuzhiyun 		generic_handle_irq(irq_no);
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
pdc_intc_setup(struct pdc_intc_priv * priv)267*4882a593Smuzhiyun static void pdc_intc_setup(struct pdc_intc_priv *priv)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int i;
270*4882a593Smuzhiyun 	unsigned int soc_sys_wake_regoff;
271*4882a593Smuzhiyun 	unsigned int soc_sys_wake;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	/*
274*4882a593Smuzhiyun 	 * Mask all syswake interrupts before routing, or we could receive an
275*4882a593Smuzhiyun 	 * interrupt before we're ready to handle it.
276*4882a593Smuzhiyun 	 */
277*4882a593Smuzhiyun 	pdc_write(priv, PDC_IRQ_ENABLE, 0);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	/*
280*4882a593Smuzhiyun 	 * Enable routing of all syswakes
281*4882a593Smuzhiyun 	 * Disable all wake sources
282*4882a593Smuzhiyun 	 */
283*4882a593Smuzhiyun 	priv->irq_route = ((PDC_IRQ_ROUTE_EXT_EN_SYS0 << priv->nr_syswakes) -
284*4882a593Smuzhiyun 				PDC_IRQ_ROUTE_EXT_EN_SYS0);
285*4882a593Smuzhiyun 	pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* Initialise syswake IRQ */
288*4882a593Smuzhiyun 	for (i = 0; i < priv->nr_syswakes; ++i) {
289*4882a593Smuzhiyun 		/* set the IRQ mode to none */
290*4882a593Smuzhiyun 		soc_sys_wake_regoff = PDC_SYS_WAKE_BASE + i*PDC_SYS_WAKE_STRIDE;
291*4882a593Smuzhiyun 		soc_sys_wake = PDC_SYS_WAKE_INT_NONE
292*4882a593Smuzhiyun 				<< PDC_SYS_WAKE_INT_MODE_SHIFT;
293*4882a593Smuzhiyun 		pdc_write(priv, soc_sys_wake_regoff, soc_sys_wake);
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
pdc_intc_probe(struct platform_device * pdev)297*4882a593Smuzhiyun static int pdc_intc_probe(struct platform_device *pdev)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct pdc_intc_priv *priv;
300*4882a593Smuzhiyun 	struct device_node *node = pdev->dev.of_node;
301*4882a593Smuzhiyun 	struct resource *res_regs;
302*4882a593Smuzhiyun 	struct irq_chip_generic *gc;
303*4882a593Smuzhiyun 	unsigned int i;
304*4882a593Smuzhiyun 	int irq, ret;
305*4882a593Smuzhiyun 	u32 val;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (!node)
308*4882a593Smuzhiyun 		return -ENOENT;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	/* Get registers */
311*4882a593Smuzhiyun 	res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
312*4882a593Smuzhiyun 	if (res_regs == NULL) {
313*4882a593Smuzhiyun 		dev_err(&pdev->dev, "cannot find registers resource\n");
314*4882a593Smuzhiyun 		return -ENOENT;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	/* Allocate driver data */
318*4882a593Smuzhiyun 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
319*4882a593Smuzhiyun 	if (!priv) {
320*4882a593Smuzhiyun 		dev_err(&pdev->dev, "cannot allocate device data\n");
321*4882a593Smuzhiyun 		return -ENOMEM;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 	raw_spin_lock_init(&priv->lock);
324*4882a593Smuzhiyun 	platform_set_drvdata(pdev, priv);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	/* Ioremap the registers */
327*4882a593Smuzhiyun 	priv->pdc_base = devm_ioremap(&pdev->dev, res_regs->start,
328*4882a593Smuzhiyun 				      resource_size(res_regs));
329*4882a593Smuzhiyun 	if (!priv->pdc_base)
330*4882a593Smuzhiyun 		return -EIO;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* Get number of peripherals */
333*4882a593Smuzhiyun 	ret = of_property_read_u32(node, "num-perips", &val);
334*4882a593Smuzhiyun 	if (ret) {
335*4882a593Smuzhiyun 		dev_err(&pdev->dev, "No num-perips node property found\n");
336*4882a593Smuzhiyun 		return -EINVAL;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 	if (val > SYS0_HWIRQ) {
339*4882a593Smuzhiyun 		dev_err(&pdev->dev, "num-perips (%u) out of range\n", val);
340*4882a593Smuzhiyun 		return -EINVAL;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 	priv->nr_perips = val;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	/* Get number of syswakes */
345*4882a593Smuzhiyun 	ret = of_property_read_u32(node, "num-syswakes", &val);
346*4882a593Smuzhiyun 	if (ret) {
347*4882a593Smuzhiyun 		dev_err(&pdev->dev, "No num-syswakes node property found\n");
348*4882a593Smuzhiyun 		return -EINVAL;
349*4882a593Smuzhiyun 	}
350*4882a593Smuzhiyun 	if (val > SYS0_HWIRQ) {
351*4882a593Smuzhiyun 		dev_err(&pdev->dev, "num-syswakes (%u) out of range\n", val);
352*4882a593Smuzhiyun 		return -EINVAL;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 	priv->nr_syswakes = val;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	/* Get peripheral IRQ numbers */
357*4882a593Smuzhiyun 	priv->perip_irqs = devm_kcalloc(&pdev->dev, 4, priv->nr_perips,
358*4882a593Smuzhiyun 					GFP_KERNEL);
359*4882a593Smuzhiyun 	if (!priv->perip_irqs) {
360*4882a593Smuzhiyun 		dev_err(&pdev->dev, "cannot allocate perip IRQ list\n");
361*4882a593Smuzhiyun 		return -ENOMEM;
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun 	for (i = 0; i < priv->nr_perips; ++i) {
364*4882a593Smuzhiyun 		irq = platform_get_irq(pdev, 1 + i);
365*4882a593Smuzhiyun 		if (irq < 0)
366*4882a593Smuzhiyun 			return irq;
367*4882a593Smuzhiyun 		priv->perip_irqs[i] = irq;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 	/* check if too many were provided */
370*4882a593Smuzhiyun 	if (platform_get_irq(pdev, 1 + i) >= 0) {
371*4882a593Smuzhiyun 		dev_err(&pdev->dev, "surplus perip IRQs detected\n");
372*4882a593Smuzhiyun 		return -EINVAL;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	/* Get syswake IRQ number */
376*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
377*4882a593Smuzhiyun 	if (irq < 0)
378*4882a593Smuzhiyun 		return irq;
379*4882a593Smuzhiyun 	priv->syswake_irq = irq;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/* Set up an IRQ domain */
382*4882a593Smuzhiyun 	priv->domain = irq_domain_add_linear(node, 16, &irq_generic_chip_ops,
383*4882a593Smuzhiyun 					     priv);
384*4882a593Smuzhiyun 	if (unlikely(!priv->domain)) {
385*4882a593Smuzhiyun 		dev_err(&pdev->dev, "cannot add IRQ domain\n");
386*4882a593Smuzhiyun 		return -ENOMEM;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/*
390*4882a593Smuzhiyun 	 * Set up 2 generic irq chips with 2 chip types.
391*4882a593Smuzhiyun 	 * The first one for peripheral irqs (only 1 chip type used)
392*4882a593Smuzhiyun 	 * The second one for syswake irqs (edge and level chip types)
393*4882a593Smuzhiyun 	 */
394*4882a593Smuzhiyun 	ret = irq_alloc_domain_generic_chips(priv->domain, 8, 2, "pdc",
395*4882a593Smuzhiyun 					     handle_level_irq, 0, 0,
396*4882a593Smuzhiyun 					     IRQ_GC_INIT_NESTED_LOCK);
397*4882a593Smuzhiyun 	if (ret)
398*4882a593Smuzhiyun 		goto err_generic;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	/* peripheral interrupt chip */
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	gc = irq_get_domain_generic_chip(priv->domain, 0);
403*4882a593Smuzhiyun 	gc->unused	= ~(BIT(priv->nr_perips) - 1);
404*4882a593Smuzhiyun 	gc->reg_base	= priv->pdc_base;
405*4882a593Smuzhiyun 	/*
406*4882a593Smuzhiyun 	 * IRQ_ROUTE contains wake bits, so we can't use the generic versions as
407*4882a593Smuzhiyun 	 * they cache the mask
408*4882a593Smuzhiyun 	 */
409*4882a593Smuzhiyun 	gc->chip_types[0].regs.mask		= PDC_IRQ_ROUTE;
410*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_mask		= perip_irq_mask;
411*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_unmask	= perip_irq_unmask;
412*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_set_wake	= pdc_irq_set_wake;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/* syswake interrupt chip */
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	gc = irq_get_domain_generic_chip(priv->domain, 8);
417*4882a593Smuzhiyun 	gc->unused	= ~(BIT(priv->nr_syswakes) - 1);
418*4882a593Smuzhiyun 	gc->reg_base	= priv->pdc_base;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	/* edge interrupts */
421*4882a593Smuzhiyun 	gc->chip_types[0].type			= IRQ_TYPE_EDGE_BOTH;
422*4882a593Smuzhiyun 	gc->chip_types[0].handler		= handle_edge_irq;
423*4882a593Smuzhiyun 	gc->chip_types[0].regs.ack		= PDC_IRQ_CLEAR;
424*4882a593Smuzhiyun 	gc->chip_types[0].regs.mask		= PDC_IRQ_ENABLE;
425*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_ack		= irq_gc_ack_set_bit;
426*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_mask		= irq_gc_mask_clr_bit;
427*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_unmask	= irq_gc_mask_set_bit;
428*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_set_type	= syswake_irq_set_type;
429*4882a593Smuzhiyun 	gc->chip_types[0].chip.irq_set_wake	= pdc_irq_set_wake;
430*4882a593Smuzhiyun 	/* for standby we pass on to the shared syswake IRQ */
431*4882a593Smuzhiyun 	gc->chip_types[0].chip.flags		= IRQCHIP_MASK_ON_SUSPEND;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	/* level interrupts */
434*4882a593Smuzhiyun 	gc->chip_types[1].type			= IRQ_TYPE_LEVEL_MASK;
435*4882a593Smuzhiyun 	gc->chip_types[1].handler		= handle_level_irq;
436*4882a593Smuzhiyun 	gc->chip_types[1].regs.ack		= PDC_IRQ_CLEAR;
437*4882a593Smuzhiyun 	gc->chip_types[1].regs.mask		= PDC_IRQ_ENABLE;
438*4882a593Smuzhiyun 	gc->chip_types[1].chip.irq_ack		= irq_gc_ack_set_bit;
439*4882a593Smuzhiyun 	gc->chip_types[1].chip.irq_mask		= irq_gc_mask_clr_bit;
440*4882a593Smuzhiyun 	gc->chip_types[1].chip.irq_unmask	= irq_gc_mask_set_bit;
441*4882a593Smuzhiyun 	gc->chip_types[1].chip.irq_set_type	= syswake_irq_set_type;
442*4882a593Smuzhiyun 	gc->chip_types[1].chip.irq_set_wake	= pdc_irq_set_wake;
443*4882a593Smuzhiyun 	/* for standby we pass on to the shared syswake IRQ */
444*4882a593Smuzhiyun 	gc->chip_types[1].chip.flags		= IRQCHIP_MASK_ON_SUSPEND;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	/* Set up the hardware to enable interrupt routing */
447*4882a593Smuzhiyun 	pdc_intc_setup(priv);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	/* Setup chained handlers for the peripheral IRQs */
450*4882a593Smuzhiyun 	for (i = 0; i < priv->nr_perips; ++i) {
451*4882a593Smuzhiyun 		irq = priv->perip_irqs[i];
452*4882a593Smuzhiyun 		irq_set_chained_handler_and_data(irq, pdc_intc_perip_isr,
453*4882a593Smuzhiyun 						 priv);
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	/* Setup chained handler for the syswake IRQ */
457*4882a593Smuzhiyun 	irq_set_chained_handler_and_data(priv->syswake_irq,
458*4882a593Smuzhiyun 					 pdc_intc_syswake_isr, priv);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	dev_info(&pdev->dev,
461*4882a593Smuzhiyun 		 "PDC IRQ controller initialised (%u perip IRQs, %u syswake IRQs)\n",
462*4882a593Smuzhiyun 		 priv->nr_perips,
463*4882a593Smuzhiyun 		 priv->nr_syswakes);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	return 0;
466*4882a593Smuzhiyun err_generic:
467*4882a593Smuzhiyun 	irq_domain_remove(priv->domain);
468*4882a593Smuzhiyun 	return ret;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
pdc_intc_remove(struct platform_device * pdev)471*4882a593Smuzhiyun static int pdc_intc_remove(struct platform_device *pdev)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	struct pdc_intc_priv *priv = platform_get_drvdata(pdev);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	irq_domain_remove(priv->domain);
476*4882a593Smuzhiyun 	return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun static const struct of_device_id pdc_intc_match[] = {
480*4882a593Smuzhiyun 	{ .compatible = "img,pdc-intc" },
481*4882a593Smuzhiyun 	{}
482*4882a593Smuzhiyun };
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun static struct platform_driver pdc_intc_driver = {
485*4882a593Smuzhiyun 	.driver = {
486*4882a593Smuzhiyun 		.name		= "pdc-intc",
487*4882a593Smuzhiyun 		.of_match_table	= pdc_intc_match,
488*4882a593Smuzhiyun 	},
489*4882a593Smuzhiyun 	.probe = pdc_intc_probe,
490*4882a593Smuzhiyun 	.remove = pdc_intc_remove,
491*4882a593Smuzhiyun };
492*4882a593Smuzhiyun 
pdc_intc_init(void)493*4882a593Smuzhiyun static int __init pdc_intc_init(void)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	return platform_driver_register(&pdc_intc_driver);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun core_initcall(pdc_intc_init);
498