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