Blame view

drivers/irqchip/irq-renesas-intc-irqpin.c 16.6 KB
443580486   Magnus Damm   irqchip: Renesas ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Renesas INTC External IRQ Pin Driver
   *
   *  Copyright (C) 2013 Magnus Damm
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
19
  #include <linux/clk.h>
443580486   Magnus Damm   irqchip: Renesas ...
20
  #include <linux/init.h>
894db1642   Guennadi Liakhovetski   irqchip: renesas-...
21
  #include <linux/of.h>
443580486   Magnus Damm   irqchip: Renesas ...
22
23
24
25
26
27
28
29
30
31
  #include <linux/platform_device.h>
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
  #include <linux/ioport.h>
  #include <linux/io.h>
  #include <linux/irq.h>
  #include <linux/irqdomain.h>
  #include <linux/err.h>
  #include <linux/slab.h>
  #include <linux/module.h>
e03f9088e   Magnus Damm   irqchip: renesas-...
32
  #include <linux/of_device.h>
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
33
  #include <linux/pm_runtime.h>
443580486   Magnus Damm   irqchip: Renesas ...
34
35
36
37
38
39
40
41
  
  #define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
  
  #define INTC_IRQPIN_REG_SENSE 0 /* ICRn */
  #define INTC_IRQPIN_REG_PRIO 1 /* INTPRInn */
  #define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */
  #define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */
  #define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */
e03f9088e   Magnus Damm   irqchip: renesas-...
42
43
44
  #define INTC_IRQPIN_REG_NR_MANDATORY 5
  #define INTC_IRQPIN_REG_IRLM 5 /* ICR0 with IRLM bit (optional) */
  #define INTC_IRQPIN_REG_NR 6
443580486   Magnus Damm   irqchip: Renesas ...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  
  /* INTC external IRQ PIN hardware register access:
   *
   * SENSE is read-write 32-bit with 2-bits or 4-bits per IRQ (*)
   * PRIO is read-write 32-bit with 4-bits per IRQ (**)
   * SOURCE is read-only 32-bit or 8-bit with 1-bit per IRQ (***)
   * MASK is write-only 32-bit or 8-bit with 1-bit per IRQ (***)
   * CLEAR is write-only 32-bit or 8-bit with 1-bit per IRQ (***)
   *
   * (*) May be accessed by more than one driver instance - lock needed
   * (**) Read-modify-write access by one driver instance - lock needed
   * (***) Accessed by one driver instance only - no locking needed
   */
  
  struct intc_irqpin_iomem {
  	void __iomem *iomem;
  	unsigned long (*read)(void __iomem *iomem);
  	void (*write)(void __iomem *iomem, unsigned long data);
  	int width;
862d30988   Magnus Damm   irqchip: intc-irq...
64
  };
443580486   Magnus Damm   irqchip: Renesas ...
65
66
67
  
  struct intc_irqpin_irq {
  	int hw_irq;
33f958f2a   Magnus Damm   irqchip: intc-irq...
68
69
  	int requested_irq;
  	int domain_irq;
443580486   Magnus Damm   irqchip: Renesas ...
70
  	struct intc_irqpin_priv *p;
862d30988   Magnus Damm   irqchip: intc-irq...
71
  };
443580486   Magnus Damm   irqchip: Renesas ...
72
73
74
75
  
  struct intc_irqpin_priv {
  	struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR];
  	struct intc_irqpin_irq irq[INTC_IRQPIN_MAX];
f9551a9c0   Geert Uytterhoeven   irqchip/renesas-i...
76
  	unsigned int sense_bitfield_width;
443580486   Magnus Damm   irqchip: Renesas ...
77
78
79
  	struct platform_device *pdev;
  	struct irq_chip irq_chip;
  	struct irq_domain *irq_domain;
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
80
  	struct clk *clk;
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
81
82
  	unsigned shared_irqs:1;
  	unsigned needs_clk:1;
427cc7202   Bastian Hecht   irqchip: intc-irq...
83
  	u8 shared_irq_mask;
443580486   Magnus Damm   irqchip: Renesas ...
84
  };
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
85
  struct intc_irqpin_config {
e03f9088e   Magnus Damm   irqchip: renesas-...
86
  	unsigned int irlm_bit;
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
87
88
  	unsigned needs_irlm:1;
  	unsigned needs_clk:1;
e03f9088e   Magnus Damm   irqchip: renesas-...
89
  };
443580486   Magnus Damm   irqchip: Renesas ...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  static unsigned long intc_irqpin_read32(void __iomem *iomem)
  {
  	return ioread32(iomem);
  }
  
  static unsigned long intc_irqpin_read8(void __iomem *iomem)
  {
  	return ioread8(iomem);
  }
  
  static void intc_irqpin_write32(void __iomem *iomem, unsigned long data)
  {
  	iowrite32(data, iomem);
  }
  
  static void intc_irqpin_write8(void __iomem *iomem, unsigned long data)
  {
  	iowrite8(data, iomem);
  }
  
  static inline unsigned long intc_irqpin_read(struct intc_irqpin_priv *p,
  					     int reg)
  {
  	struct intc_irqpin_iomem *i = &p->iomem[reg];
862d30988   Magnus Damm   irqchip: intc-irq...
114

443580486   Magnus Damm   irqchip: Renesas ...
115
116
117
118
119
120
121
  	return i->read(i->iomem);
  }
  
  static inline void intc_irqpin_write(struct intc_irqpin_priv *p,
  				     int reg, unsigned long data)
  {
  	struct intc_irqpin_iomem *i = &p->iomem[reg];
862d30988   Magnus Damm   irqchip: intc-irq...
122

443580486   Magnus Damm   irqchip: Renesas ...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	i->write(i->iomem, data);
  }
  
  static inline unsigned long intc_irqpin_hwirq_mask(struct intc_irqpin_priv *p,
  						   int reg, int hw_irq)
  {
  	return BIT((p->iomem[reg].width - 1) - hw_irq);
  }
  
  static inline void intc_irqpin_irq_write_hwirq(struct intc_irqpin_priv *p,
  					       int reg, int hw_irq)
  {
  	intc_irqpin_write(p, reg, intc_irqpin_hwirq_mask(p, reg, hw_irq));
  }
  
  static DEFINE_RAW_SPINLOCK(intc_irqpin_lock); /* only used by slow path */
  
  static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p,
  					  int reg, int shift,
  					  int width, int value)
  {
  	unsigned long flags;
  	unsigned long tmp;
  
  	raw_spin_lock_irqsave(&intc_irqpin_lock, flags);
  
  	tmp = intc_irqpin_read(p, reg);
  	tmp &= ~(((1 << width) - 1) << shift);
  	tmp |= value << shift;
  	intc_irqpin_write(p, reg, tmp);
  
  	raw_spin_unlock_irqrestore(&intc_irqpin_lock, flags);
  }
  
  static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p,
  					 int irq, int do_mask)
  {
e55bc5586   Laurent Pinchart   irqchip: renesas-...
160
161
162
  	/* The PRIO register is assumed to be 32-bit with fixed 4-bit fields. */
  	int bitfield_width = 4;
  	int shift = 32 - (irq + 1) * bitfield_width;
443580486   Magnus Damm   irqchip: Renesas ...
163
164
165
166
167
168
169
170
  
  	intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO,
  				      shift, bitfield_width,
  				      do_mask ? 0 : (1 << bitfield_width) - 1);
  }
  
  static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value)
  {
e55bc5586   Laurent Pinchart   irqchip: renesas-...
171
  	/* The SENSE register is assumed to be 32-bit. */
f9551a9c0   Geert Uytterhoeven   irqchip/renesas-i...
172
  	int bitfield_width = p->sense_bitfield_width;
e55bc5586   Laurent Pinchart   irqchip: renesas-...
173
  	int shift = 32 - (irq + 1) * bitfield_width;
443580486   Magnus Damm   irqchip: Renesas ...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  
  	dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d
  ", irq, value);
  
  	if (value >= (1 << bitfield_width))
  		return -EINVAL;
  
  	intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_SENSE, shift,
  				      bitfield_width, value);
  	return 0;
  }
  
  static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str)
  {
  	dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)
  ",
33f958f2a   Magnus Damm   irqchip: intc-irq...
190
  		str, i->requested_irq, i->hw_irq, i->domain_irq);
443580486   Magnus Damm   irqchip: Renesas ...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  }
  
  static void intc_irqpin_irq_enable(struct irq_data *d)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
  	int hw_irq = irqd_to_hwirq(d);
  
  	intc_irqpin_dbg(&p->irq[hw_irq], "enable");
  	intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq);
  }
  
  static void intc_irqpin_irq_disable(struct irq_data *d)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
  	int hw_irq = irqd_to_hwirq(d);
  
  	intc_irqpin_dbg(&p->irq[hw_irq], "disable");
  	intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
  }
427cc7202   Bastian Hecht   irqchip: intc-irq...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
  static void intc_irqpin_shared_irq_enable(struct irq_data *d)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
  	int hw_irq = irqd_to_hwirq(d);
  
  	intc_irqpin_dbg(&p->irq[hw_irq], "shared enable");
  	intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq);
  
  	p->shared_irq_mask &= ~BIT(hw_irq);
  }
  
  static void intc_irqpin_shared_irq_disable(struct irq_data *d)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
  	int hw_irq = irqd_to_hwirq(d);
  
  	intc_irqpin_dbg(&p->irq[hw_irq], "shared disable");
  	intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
  
  	p->shared_irq_mask |= BIT(hw_irq);
  }
443580486   Magnus Damm   irqchip: Renesas ...
231
232
233
  static void intc_irqpin_irq_enable_force(struct irq_data *d)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
33f958f2a   Magnus Damm   irqchip: intc-irq...
234
  	int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
443580486   Magnus Damm   irqchip: Renesas ...
235
236
  
  	intc_irqpin_irq_enable(d);
d1b6aecde   Magnus Damm   irqchip: intc-irq...
237
238
239
240
241
  
  	/* enable interrupt through parent interrupt controller,
  	 * assumes non-shared interrupt with 1:1 mapping
  	 * needed for busted IRQs on some SoCs like sh73a0
  	 */
443580486   Magnus Damm   irqchip: Renesas ...
242
243
244
245
246
247
  	irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
  }
  
  static void intc_irqpin_irq_disable_force(struct irq_data *d)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
33f958f2a   Magnus Damm   irqchip: intc-irq...
248
  	int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
443580486   Magnus Damm   irqchip: Renesas ...
249

d1b6aecde   Magnus Damm   irqchip: intc-irq...
250
251
252
253
  	/* disable interrupt through parent interrupt controller,
  	 * assumes non-shared interrupt with 1:1 mapping
  	 * needed for busted IRQs on some SoCs like sh73a0
  	 */
443580486   Magnus Damm   irqchip: Renesas ...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  	irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq));
  	intc_irqpin_irq_disable(d);
  }
  
  #define INTC_IRQ_SENSE_VALID 0x10
  #define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID)
  
  static unsigned char intc_irqpin_sense[IRQ_TYPE_SENSE_MASK + 1] = {
  	[IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x00),
  	[IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x01),
  	[IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x02),
  	[IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x03),
  	[IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x04),
  };
  
  static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type)
  {
  	unsigned char value = intc_irqpin_sense[type & IRQ_TYPE_SENSE_MASK];
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
  
  	if (!(value & INTC_IRQ_SENSE_VALID))
  		return -EINVAL;
  
  	return intc_irqpin_set_sense(p, irqd_to_hwirq(d),
  				     value ^ INTC_IRQ_SENSE_VALID);
  }
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
280
281
282
  static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on)
  {
  	struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
f4e209cdc   Geert Uytterhoeven   irqchip/renesas-i...
283
284
285
  	int hw_irq = irqd_to_hwirq(d);
  
  	irq_set_irq_wake(p->irq[hw_irq].requested_irq, on);
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
286
287
288
289
290
291
292
293
294
295
296
  
  	if (!p->clk)
  		return 0;
  
  	if (on)
  		clk_enable(p->clk);
  	else
  		clk_disable(p->clk);
  
  	return 0;
  }
443580486   Magnus Damm   irqchip: Renesas ...
297
298
299
300
301
302
303
304
305
306
307
308
  static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id)
  {
  	struct intc_irqpin_irq *i = dev_id;
  	struct intc_irqpin_priv *p = i->p;
  	unsigned long bit;
  
  	intc_irqpin_dbg(i, "demux1");
  	bit = intc_irqpin_hwirq_mask(p, INTC_IRQPIN_REG_SOURCE, i->hw_irq);
  
  	if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) {
  		intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, ~bit);
  		intc_irqpin_dbg(i, "demux2");
33f958f2a   Magnus Damm   irqchip: intc-irq...
309
  		generic_handle_irq(i->domain_irq);
443580486   Magnus Damm   irqchip: Renesas ...
310
311
312
313
  		return IRQ_HANDLED;
  	}
  	return IRQ_NONE;
  }
427cc7202   Bastian Hecht   irqchip: intc-irq...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id)
  {
  	struct intc_irqpin_priv *p = dev_id;
  	unsigned int reg_source = intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE);
  	irqreturn_t status = IRQ_NONE;
  	int k;
  
  	for (k = 0; k < 8; k++) {
  		if (reg_source & BIT(7 - k)) {
  			if (BIT(k) & p->shared_irq_mask)
  				continue;
  
  			status |= intc_irqpin_irq_handler(irq, &p->irq[k]);
  		}
  	}
  
  	return status;
  }
769b5cf78   Geert Uytterhoeven   irqchip/renesas-i...
332
333
334
335
336
  /*
   * This lock class tells lockdep that INTC External IRQ Pin irqs are in a
   * different category than their parents, so it won't report false recursion.
   */
  static struct lock_class_key intc_irqpin_irq_lock_class;
443580486   Magnus Damm   irqchip: Renesas ...
337
338
339
340
  static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq,
  				      irq_hw_number_t hw)
  {
  	struct intc_irqpin_priv *p = h->host_data;
33f958f2a   Magnus Damm   irqchip: intc-irq...
341
342
  	p->irq[hw].domain_irq = virq;
  	p->irq[hw].hw_irq = hw;
443580486   Magnus Damm   irqchip: Renesas ...
343
344
  	intc_irqpin_dbg(&p->irq[hw], "map");
  	irq_set_chip_data(virq, h->host_data);
769b5cf78   Geert Uytterhoeven   irqchip/renesas-i...
345
  	irq_set_lockdep_class(virq, &intc_irqpin_irq_lock_class);
443580486   Magnus Damm   irqchip: Renesas ...
346
  	irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
443580486   Magnus Damm   irqchip: Renesas ...
347
348
  	return 0;
  }
960097365   Krzysztof Kozlowski   irqchip: Constify...
349
  static const struct irq_domain_ops intc_irqpin_irq_domain_ops = {
443580486   Magnus Damm   irqchip: Renesas ...
350
  	.map	= intc_irqpin_irq_domain_map,
9d833bbe4   Magnus Damm   irqchip: intc-irq...
351
  	.xlate  = irq_domain_xlate_twocell,
443580486   Magnus Damm   irqchip: Renesas ...
352
  };
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
353
  static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = {
e03f9088e   Magnus Damm   irqchip: renesas-...
354
  	.irlm_bit = 23, /* ICR0.IRLM0 */
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
355
356
357
358
359
360
361
  	.needs_irlm = 1,
  	.needs_clk = 0,
  };
  
  static const struct intc_irqpin_config intc_irqpin_rmobile = {
  	.needs_irlm = 0,
  	.needs_clk = 1,
e03f9088e   Magnus Damm   irqchip: renesas-...
362
363
364
365
  };
  
  static const struct of_device_id intc_irqpin_dt_ids[] = {
  	{ .compatible = "renesas,intc-irqpin", },
26c21dd98   Ulrich Hecht   irqchip/renesas-i...
366
367
  	{ .compatible = "renesas,intc-irqpin-r8a7778",
  	  .data = &intc_irqpin_irlm_r8a777x },
e03f9088e   Magnus Damm   irqchip: renesas-...
368
  	{ .compatible = "renesas,intc-irqpin-r8a7779",
26c21dd98   Ulrich Hecht   irqchip/renesas-i...
369
  	  .data = &intc_irqpin_irlm_r8a777x },
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
370
371
372
373
  	{ .compatible = "renesas,intc-irqpin-r8a7740",
  	  .data = &intc_irqpin_rmobile },
  	{ .compatible = "renesas,intc-irqpin-sh73a0",
  	  .data = &intc_irqpin_rmobile },
e03f9088e   Magnus Damm   irqchip: renesas-...
374
375
376
  	{},
  };
  MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
443580486   Magnus Damm   irqchip: Renesas ...
377
378
  static int intc_irqpin_probe(struct platform_device *pdev)
  {
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
379
  	const struct intc_irqpin_config *config = NULL;
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
380
  	struct device *dev = &pdev->dev;
e03f9088e   Magnus Damm   irqchip: renesas-...
381
  	const struct of_device_id *of_id;
443580486   Magnus Damm   irqchip: Renesas ...
382
383
384
385
386
387
388
  	struct intc_irqpin_priv *p;
  	struct intc_irqpin_iomem *i;
  	struct resource *io[INTC_IRQPIN_REG_NR];
  	struct resource *irq;
  	struct irq_chip *irq_chip;
  	void (*enable_fn)(struct irq_data *d);
  	void (*disable_fn)(struct irq_data *d);
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
389
  	const char *name = dev_name(dev);
f9551a9c0   Geert Uytterhoeven   irqchip/renesas-i...
390
  	bool control_parent;
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
391
  	unsigned int nirqs;
427cc7202   Bastian Hecht   irqchip: intc-irq...
392
  	int ref_irq;
443580486   Magnus Damm   irqchip: Renesas ...
393
394
  	int ret;
  	int k;
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
395
  	p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
443580486   Magnus Damm   irqchip: Renesas ...
396
  	if (!p) {
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
397
398
  		dev_err(dev, "failed to allocate driver data
  ");
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
399
  		return -ENOMEM;
443580486   Magnus Damm   irqchip: Renesas ...
400
401
402
  	}
  
  	/* deal with driver instance configuration */
f9551a9c0   Geert Uytterhoeven   irqchip/renesas-i...
403
404
405
406
407
  	of_property_read_u32(dev->of_node, "sense-bitfield-width",
  			     &p->sense_bitfield_width);
  	control_parent = of_property_read_bool(dev->of_node, "control-parent");
  	if (!p->sense_bitfield_width)
  		p->sense_bitfield_width = 4; /* default to 4 bits */
443580486   Magnus Damm   irqchip: Renesas ...
408
409
410
  
  	p->pdev = pdev;
  	platform_set_drvdata(pdev, p);
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
411
412
413
414
415
  	of_id = of_match_device(intc_irqpin_dt_ids, dev);
  	if (of_id && of_id->data) {
  		config = of_id->data;
  		p->needs_clk = config->needs_clk;
  	}
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
416
417
  	p->clk = devm_clk_get(dev, NULL);
  	if (IS_ERR(p->clk)) {
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
418
419
420
421
422
423
  		if (p->needs_clk) {
  			dev_err(dev, "unable to get clock
  ");
  			ret = PTR_ERR(p->clk);
  			goto err0;
  		}
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
424
425
426
427
428
  		p->clk = NULL;
  	}
  
  	pm_runtime_enable(dev);
  	pm_runtime_get_sync(dev);
e03f9088e   Magnus Damm   irqchip: renesas-...
429
430
  	/* get hold of register banks */
  	memset(io, 0, sizeof(io));
443580486   Magnus Damm   irqchip: Renesas ...
431
432
  	for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
  		io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
e03f9088e   Magnus Damm   irqchip: renesas-...
433
  		if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) {
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
434
435
  			dev_err(dev, "not enough IOMEM resources
  ");
443580486   Magnus Damm   irqchip: Renesas ...
436
  			ret = -EINVAL;
08eba5ba4   Magnus Damm   irqchip: intc-irq...
437
  			goto err0;
443580486   Magnus Damm   irqchip: Renesas ...
438
439
440
441
442
443
444
445
  		}
  	}
  
  	/* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */
  	for (k = 0; k < INTC_IRQPIN_MAX; k++) {
  		irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
  		if (!irq)
  			break;
443580486   Magnus Damm   irqchip: Renesas ...
446
  		p->irq[k].p = p;
33f958f2a   Magnus Damm   irqchip: intc-irq...
447
  		p->irq[k].requested_irq = irq->start;
443580486   Magnus Damm   irqchip: Renesas ...
448
  	}
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
449
450
  	nirqs = k;
  	if (nirqs < 1) {
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
451
452
  		dev_err(dev, "not enough IRQ resources
  ");
443580486   Magnus Damm   irqchip: Renesas ...
453
  		ret = -EINVAL;
08eba5ba4   Magnus Damm   irqchip: intc-irq...
454
  		goto err0;
443580486   Magnus Damm   irqchip: Renesas ...
455
456
457
458
459
  	}
  
  	/* ioremap IOMEM and setup read/write callbacks */
  	for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
  		i = &p->iomem[k];
e03f9088e   Magnus Damm   irqchip: renesas-...
460
461
462
  		/* handle optional registers */
  		if (!io[k])
  			continue;
443580486   Magnus Damm   irqchip: Renesas ...
463
464
465
466
467
468
469
470
471
472
473
474
  		switch (resource_size(io[k])) {
  		case 1:
  			i->width = 8;
  			i->read = intc_irqpin_read8;
  			i->write = intc_irqpin_write8;
  			break;
  		case 4:
  			i->width = 32;
  			i->read = intc_irqpin_read32;
  			i->write = intc_irqpin_write32;
  			break;
  		default:
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
475
476
  			dev_err(dev, "IOMEM size mismatch
  ");
443580486   Magnus Damm   irqchip: Renesas ...
477
  			ret = -EINVAL;
08eba5ba4   Magnus Damm   irqchip: intc-irq...
478
  			goto err0;
443580486   Magnus Damm   irqchip: Renesas ...
479
  		}
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
480
  		i->iomem = devm_ioremap_nocache(dev, io[k]->start,
08eba5ba4   Magnus Damm   irqchip: intc-irq...
481
  						resource_size(io[k]));
443580486   Magnus Damm   irqchip: Renesas ...
482
  		if (!i->iomem) {
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
483
484
  			dev_err(dev, "failed to remap IOMEM
  ");
443580486   Magnus Damm   irqchip: Renesas ...
485
  			ret = -ENXIO;
08eba5ba4   Magnus Damm   irqchip: intc-irq...
486
  			goto err0;
443580486   Magnus Damm   irqchip: Renesas ...
487
488
  		}
  	}
e03f9088e   Magnus Damm   irqchip: renesas-...
489
  	/* configure "individual IRQ mode" where needed */
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
490
  	if (config && config->needs_irlm) {
e03f9088e   Magnus Damm   irqchip: renesas-...
491
492
  		if (io[INTC_IRQPIN_REG_IRLM])
  			intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
493
  						      config->irlm_bit, 1, 1);
e03f9088e   Magnus Damm   irqchip: renesas-...
494
495
496
497
  		else
  			dev_warn(dev, "unable to select IRLM mode
  ");
  	}
443580486   Magnus Damm   irqchip: Renesas ...
498
  	/* mask all interrupts using priority */
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
499
  	for (k = 0; k < nirqs; k++)
443580486   Magnus Damm   irqchip: Renesas ...
500
  		intc_irqpin_mask_unmask_prio(p, k, 1);
427cc7202   Bastian Hecht   irqchip: intc-irq...
501
502
503
504
505
  	/* clear all pending interrupts */
  	intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, 0x0);
  
  	/* scan for shared interrupt lines */
  	ref_irq = p->irq[0].requested_irq;
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
506
  	p->shared_irqs = 1;
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
507
  	for (k = 1; k < nirqs; k++) {
427cc7202   Bastian Hecht   irqchip: intc-irq...
508
  		if (ref_irq != p->irq[k].requested_irq) {
86e57ca73   Geert Uytterhoeven   irqchip/renesas-i...
509
  			p->shared_irqs = 0;
427cc7202   Bastian Hecht   irqchip: intc-irq...
510
511
512
  			break;
  		}
  	}
443580486   Magnus Damm   irqchip: Renesas ...
513
  	/* use more severe masking method if requested */
f9551a9c0   Geert Uytterhoeven   irqchip/renesas-i...
514
  	if (control_parent) {
443580486   Magnus Damm   irqchip: Renesas ...
515
516
  		enable_fn = intc_irqpin_irq_enable_force;
  		disable_fn = intc_irqpin_irq_disable_force;
427cc7202   Bastian Hecht   irqchip: intc-irq...
517
  	} else if (!p->shared_irqs) {
443580486   Magnus Damm   irqchip: Renesas ...
518
519
  		enable_fn = intc_irqpin_irq_enable;
  		disable_fn = intc_irqpin_irq_disable;
427cc7202   Bastian Hecht   irqchip: intc-irq...
520
521
522
  	} else {
  		enable_fn = intc_irqpin_shared_irq_enable;
  		disable_fn = intc_irqpin_shared_irq_disable;
443580486   Magnus Damm   irqchip: Renesas ...
523
524
525
526
527
528
  	}
  
  	irq_chip = &p->irq_chip;
  	irq_chip->name = name;
  	irq_chip->irq_mask = disable_fn;
  	irq_chip->irq_unmask = enable_fn;
443580486   Magnus Damm   irqchip: Renesas ...
529
  	irq_chip->irq_set_type = intc_irqpin_irq_set_type;
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
530
531
  	irq_chip->irq_set_wake = intc_irqpin_irq_set_wake;
  	irq_chip->flags	= IRQCHIP_MASK_ON_SUSPEND;
443580486   Magnus Damm   irqchip: Renesas ...
532

1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
533
534
  	p->irq_domain = irq_domain_add_simple(dev->of_node, nirqs, 0,
  					      &intc_irqpin_irq_domain_ops, p);
443580486   Magnus Damm   irqchip: Renesas ...
535
536
  	if (!p->irq_domain) {
  		ret = -ENXIO;
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
537
538
  		dev_err(dev, "cannot initialize irq domain
  ");
08eba5ba4   Magnus Damm   irqchip: intc-irq...
539
  		goto err0;
443580486   Magnus Damm   irqchip: Renesas ...
540
  	}
427cc7202   Bastian Hecht   irqchip: intc-irq...
541
542
  	if (p->shared_irqs) {
  		/* request one shared interrupt */
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
543
  		if (devm_request_irq(dev, p->irq[0].requested_irq,
427cc7202   Bastian Hecht   irqchip: intc-irq...
544
545
  				intc_irqpin_shared_irq_handler,
  				IRQF_SHARED, name, p)) {
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
546
547
  			dev_err(dev, "failed to request low IRQ
  ");
443580486   Magnus Damm   irqchip: Renesas ...
548
  			ret = -ENOENT;
08eba5ba4   Magnus Damm   irqchip: intc-irq...
549
  			goto err1;
443580486   Magnus Damm   irqchip: Renesas ...
550
  		}
427cc7202   Bastian Hecht   irqchip: intc-irq...
551
552
  	} else {
  		/* request interrupts one by one */
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
553
  		for (k = 0; k < nirqs; k++) {
36845f1b5   Geert Uytterhoeven   irqchip: renesas-...
554
555
556
557
558
  			if (devm_request_irq(dev, p->irq[k].requested_irq,
  					     intc_irqpin_irq_handler, 0, name,
  					     &p->irq[k])) {
  				dev_err(dev, "failed to request low IRQ
  ");
427cc7202   Bastian Hecht   irqchip: intc-irq...
559
560
561
562
  				ret = -ENOENT;
  				goto err1;
  			}
  		}
443580486   Magnus Damm   irqchip: Renesas ...
563
  	}
427cc7202   Bastian Hecht   irqchip: intc-irq...
564
  	/* unmask all interrupts on prio level */
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
565
  	for (k = 0; k < nirqs; k++)
427cc7202   Bastian Hecht   irqchip: intc-irq...
566
  		intc_irqpin_mask_unmask_prio(p, k, 0);
1affe5946   Geert Uytterhoeven   irqchip/renesas-i...
567
568
  	dev_info(dev, "driving %d irqs
  ", nirqs);
443580486   Magnus Damm   irqchip: Renesas ...
569

443580486   Magnus Damm   irqchip: Renesas ...
570
  	return 0;
443580486   Magnus Damm   irqchip: Renesas ...
571
  err1:
08eba5ba4   Magnus Damm   irqchip: intc-irq...
572
  	irq_domain_remove(p->irq_domain);
443580486   Magnus Damm   irqchip: Renesas ...
573
  err0:
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
574
575
  	pm_runtime_put(dev);
  	pm_runtime_disable(dev);
443580486   Magnus Damm   irqchip: Renesas ...
576
577
578
579
580
581
  	return ret;
  }
  
  static int intc_irqpin_remove(struct platform_device *pdev)
  {
  	struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
443580486   Magnus Damm   irqchip: Renesas ...
582
583
  
  	irq_domain_remove(p->irq_domain);
705bc96c2   Geert Uytterhoeven   irqchip: renesas-...
584
585
  	pm_runtime_put(&pdev->dev);
  	pm_runtime_disable(&pdev->dev);
443580486   Magnus Damm   irqchip: Renesas ...
586
587
588
589
590
591
592
593
  	return 0;
  }
  
  static struct platform_driver intc_irqpin_device_driver = {
  	.probe		= intc_irqpin_probe,
  	.remove		= intc_irqpin_remove,
  	.driver		= {
  		.name	= "renesas_intc_irqpin",
9d833bbe4   Magnus Damm   irqchip: intc-irq...
594
  		.of_match_table = intc_irqpin_dt_ids,
443580486   Magnus Damm   irqchip: Renesas ...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  	}
  };
  
  static int __init intc_irqpin_init(void)
  {
  	return platform_driver_register(&intc_irqpin_device_driver);
  }
  postcore_initcall(intc_irqpin_init);
  
  static void __exit intc_irqpin_exit(void)
  {
  	platform_driver_unregister(&intc_irqpin_device_driver);
  }
  module_exit(intc_irqpin_exit);
  
  MODULE_AUTHOR("Magnus Damm");
  MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver");
  MODULE_LICENSE("GPL v2");