Blame view
drivers/irqchip/irq-sa11x0.c
3.89 KB
1da177e4c
|
1 |
/* |
85e6f0978
|
2 |
* Copyright (C) 2015 Dmitry Eremin-Solenikov |
1da177e4c
|
3 4 |
* Copyright (C) 1999-2001 Nicolas Pitre * |
85e6f0978
|
5 |
* Generic IRQ handling for the SA11x0. |
1da177e4c
|
6 7 8 9 10 11 12 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/module.h> |
119c641c9
|
13 |
#include <linux/interrupt.h> |
3169663ac
|
14 |
#include <linux/io.h> |
119c641c9
|
15 |
#include <linux/irq.h> |
1eca42b49
|
16 |
#include <linux/irqdomain.h> |
905339807
|
17 |
#include <linux/syscore_ops.h> |
85e6f0978
|
18 |
#include <linux/irqchip/irq-sa11x0.h> |
1da177e4c
|
19 |
|
a657d7f67
|
20 |
#include <soc/sa1100/pwer.h> |
1da177e4c
|
21 |
|
affcab32e
|
22 |
#include <asm/exception.h> |
1da177e4c
|
23 |
|
60c06c4c6
|
24 25 26 27 28 29 |
#define ICIP 0x00 /* IC IRQ Pending reg. */ #define ICMR 0x04 /* IC Mask Reg. */ #define ICLR 0x08 /* IC Level Reg. */ #define ICCR 0x0C /* IC Control Reg. */ #define ICFP 0x10 /* IC FIQ Pending reg. */ #define ICPR 0x20 /* IC Pending Reg. */ |
1da177e4c
|
30 |
|
60c06c4c6
|
31 |
static void __iomem *iobase; |
1da177e4c
|
32 33 |
/* |
ab71f99fd
|
34 35 36 37 38 |
* We don't need to ACK IRQs on the SA1100 unless they're GPIOs * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. */ static void sa1100_mask_irq(struct irq_data *d) { |
60c06c4c6
|
39 40 41 42 43 |
u32 reg; reg = readl_relaxed(iobase + ICMR); reg &= ~BIT(d->hwirq); writel_relaxed(reg, iobase + ICMR); |
ab71f99fd
|
44 45 46 47 |
} static void sa1100_unmask_irq(struct irq_data *d) { |
60c06c4c6
|
48 49 50 51 52 |
u32 reg; reg = readl_relaxed(iobase + ICMR); reg |= BIT(d->hwirq); writel_relaxed(reg, iobase + ICMR); |
ab71f99fd
|
53 |
} |
ab71f99fd
|
54 55 |
static int sa1100_set_wake(struct irq_data *d, unsigned int on) { |
a657d7f67
|
56 |
return sa11x0_sc_set_wake(d->hwirq, on); |
ab71f99fd
|
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
} static struct irq_chip sa1100_normal_chip = { .name = "SC", .irq_ack = sa1100_mask_irq, .irq_mask = sa1100_mask_irq, .irq_unmask = sa1100_unmask_irq, .irq_set_wake = sa1100_set_wake, }; static int sa1100_normal_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { irq_set_chip_and_handler(irq, &sa1100_normal_chip, handle_level_irq); |
ab71f99fd
|
72 73 74 |
return 0; } |
9827e8e55
|
75 |
static const struct irq_domain_ops sa1100_normal_irqdomain_ops = { |
ab71f99fd
|
76 77 78 79 80 |
.map = sa1100_normal_irqdomain_map, .xlate = irq_domain_xlate_onetwocell, }; static struct irq_domain *sa1100_normal_irqdomain; |
1da177e4c
|
81 82 83 84 85 86 |
static struct sa1100irq_state { unsigned int saved; unsigned int icmr; unsigned int iclr; unsigned int iccr; } sa1100irq_state; |
905339807
|
87 |
static int sa1100irq_suspend(void) |
1da177e4c
|
88 89 90 91 |
{ struct sa1100irq_state *st = &sa1100irq_state; st->saved = 1; |
60c06c4c6
|
92 93 94 |
st->icmr = readl_relaxed(iobase + ICMR); st->iclr = readl_relaxed(iobase + ICLR); st->iccr = readl_relaxed(iobase + ICCR); |
1da177e4c
|
95 96 97 98 |
/* * Disable all GPIO-based interrupts. */ |
60c06c4c6
|
99 |
writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR); |
1da177e4c
|
100 |
|
1da177e4c
|
101 102 |
return 0; } |
905339807
|
103 |
static void sa1100irq_resume(void) |
1da177e4c
|
104 105 106 107 |
{ struct sa1100irq_state *st = &sa1100irq_state; if (st->saved) { |
60c06c4c6
|
108 109 |
writel_relaxed(st->iccr, iobase + ICCR); writel_relaxed(st->iclr, iobase + ICLR); |
1da177e4c
|
110 |
|
60c06c4c6
|
111 |
writel_relaxed(st->icmr, iobase + ICMR); |
1da177e4c
|
112 |
} |
1da177e4c
|
113 |
} |
905339807
|
114 |
static struct syscore_ops sa1100irq_syscore_ops = { |
1da177e4c
|
115 116 117 |
.suspend = sa1100irq_suspend, .resume = sa1100irq_resume, }; |
1da177e4c
|
118 119 |
static int __init sa1100irq_init_devicefs(void) { |
905339807
|
120 121 |
register_syscore_ops(&sa1100irq_syscore_ops); return 0; |
1da177e4c
|
122 123 124 |
} device_initcall(sa1100irq_init_devicefs); |
affcab32e
|
125 126 127 128 129 130 |
static asmlinkage void __exception_irq_entry sa1100_handle_irq(struct pt_regs *regs) { uint32_t icip, icmr, mask; do { |
60c06c4c6
|
131 132 |
icip = readl_relaxed(iobase + ICIP); icmr = readl_relaxed(iobase + ICMR); |
affcab32e
|
133 134 135 136 |
mask = icip & icmr; if (mask == 0) break; |
364e38691
|
137 138 |
handle_domain_irq(sa1100_normal_irqdomain, ffs(mask) - 1, regs); |
affcab32e
|
139 140 |
} while (1); } |
85e6f0978
|
141 |
void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start) |
1da177e4c
|
142 |
{ |
85e6f0978
|
143 |
iobase = ioremap(io_start, SZ_64K); |
60c06c4c6
|
144 145 |
if (WARN_ON(!iobase)) return; |
1da177e4c
|
146 147 |
/* disable all IRQs */ |
60c06c4c6
|
148 |
writel_relaxed(0, iobase + ICMR); |
1da177e4c
|
149 150 |
/* all IRQs are IRQ, not FIQ */ |
60c06c4c6
|
151 |
writel_relaxed(0, iobase + ICLR); |
1da177e4c
|
152 |
|
1da177e4c
|
153 154 155 156 |
/* * Whatever the doc says, this has to be set for the wait-on-irq * instruction to work... on a SA1100 rev 9 at least. */ |
60c06c4c6
|
157 |
writel_relaxed(1, iobase + ICCR); |
1da177e4c
|
158 |
|
a82be3f0f
|
159 |
sa1100_normal_irqdomain = irq_domain_add_simple(NULL, |
85e6f0978
|
160 |
32, irq_start, |
83508093f
|
161 |
&sa1100_normal_irqdomain_ops, NULL); |
affcab32e
|
162 |
set_handle_irq(sa1100_handle_irq); |
1da177e4c
|
163 |
} |