diff options
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/spear-shirq.c | 97 |
1 files changed, 45 insertions, 52 deletions
diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 8765aa7f7a15..169ef9a385d0 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c | |||
@@ -49,7 +49,8 @@ struct shirq_regs { | |||
49 | * virq_base: Base virtual interrupt number | 49 | * virq_base: Base virtual interrupt number |
50 | * nr_irqs: Number of interrupts handled by this block | 50 | * nr_irqs: Number of interrupts handled by this block |
51 | * offset: Bit offset of the first interrupt | 51 | * offset: Bit offset of the first interrupt |
52 | * disabled: Group is disabled, but accounted | 52 | * irq_chip: Interrupt controller chip used for this instance, |
53 | * if NULL group is disabled, but accounted | ||
53 | */ | 54 | */ |
54 | struct spear_shirq { | 55 | struct spear_shirq { |
55 | void __iomem *base; | 56 | void __iomem *base; |
@@ -58,19 +59,50 @@ struct spear_shirq { | |||
58 | u32 virq_base; | 59 | u32 virq_base; |
59 | u32 nr_irqs; | 60 | u32 nr_irqs; |
60 | u32 offset; | 61 | u32 offset; |
61 | bool disabled; | 62 | struct irq_chip *irq_chip; |
62 | }; | 63 | }; |
63 | 64 | ||
64 | static DEFINE_SPINLOCK(lock); | ||
65 | |||
66 | /* spear300 shared irq registers offsets and masks */ | 65 | /* spear300 shared irq registers offsets and masks */ |
67 | #define SPEAR300_INT_ENB_MASK_REG 0x54 | 66 | #define SPEAR300_INT_ENB_MASK_REG 0x54 |
68 | #define SPEAR300_INT_STS_MASK_REG 0x58 | 67 | #define SPEAR300_INT_STS_MASK_REG 0x58 |
69 | 68 | ||
69 | static DEFINE_RAW_SPINLOCK(shirq_lock); | ||
70 | |||
71 | static void shirq_irq_mask(struct irq_data *d) | ||
72 | { | ||
73 | struct spear_shirq *shirq = irq_data_get_irq_chip_data(d); | ||
74 | u32 val, shift = d->irq - shirq->virq_base + shirq->offset; | ||
75 | u32 __iomem *reg = shirq->base + shirq->regs.enb_reg; | ||
76 | |||
77 | raw_spin_lock(&shirq_lock); | ||
78 | val = readl(reg) & ~(0x1 << shift); | ||
79 | writel(val, reg); | ||
80 | raw_spin_unlock(&shirq_lock); | ||
81 | } | ||
82 | |||
83 | static void shirq_irq_unmask(struct irq_data *d) | ||
84 | { | ||
85 | struct spear_shirq *shirq = irq_data_get_irq_chip_data(d); | ||
86 | u32 val, shift = d->irq - shirq->virq_base + shirq->offset; | ||
87 | u32 __iomem *reg = shirq->base + shirq->regs.enb_reg; | ||
88 | |||
89 | raw_spin_lock(&shirq_lock); | ||
90 | val = readl(reg) | (0x1 << shift); | ||
91 | writel(val, reg); | ||
92 | raw_spin_unlock(&shirq_lock); | ||
93 | } | ||
94 | |||
95 | static struct irq_chip shirq_chip = { | ||
96 | .name = "spear-shirq", | ||
97 | .irq_mask = shirq_irq_mask, | ||
98 | .irq_unmask = shirq_irq_unmask, | ||
99 | }; | ||
100 | |||
70 | static struct spear_shirq spear300_shirq_ras1 = { | 101 | static struct spear_shirq spear300_shirq_ras1 = { |
71 | .offset = 0, | 102 | .offset = 0, |
72 | .nr_irqs = 9, | 103 | .nr_irqs = 9, |
73 | .mask = ((0x1 << 9) - 1) << 0, | 104 | .mask = ((0x1 << 9) - 1) << 0, |
105 | .irq_chip = &shirq_chip, | ||
74 | .regs = { | 106 | .regs = { |
75 | .enb_reg = SPEAR300_INT_ENB_MASK_REG, | 107 | .enb_reg = SPEAR300_INT_ENB_MASK_REG, |
76 | .status_reg = SPEAR300_INT_STS_MASK_REG, | 108 | .status_reg = SPEAR300_INT_STS_MASK_REG, |
@@ -88,8 +120,8 @@ static struct spear_shirq spear310_shirq_ras1 = { | |||
88 | .offset = 0, | 120 | .offset = 0, |
89 | .nr_irqs = 8, | 121 | .nr_irqs = 8, |
90 | .mask = ((0x1 << 8) - 1) << 0, | 122 | .mask = ((0x1 << 8) - 1) << 0, |
123 | .irq_chip = &dummy_irq_chip, | ||
91 | .regs = { | 124 | .regs = { |
92 | .enb_reg = -1, | ||
93 | .status_reg = SPEAR310_INT_STS_MASK_REG, | 125 | .status_reg = SPEAR310_INT_STS_MASK_REG, |
94 | }, | 126 | }, |
95 | }; | 127 | }; |
@@ -98,6 +130,7 @@ static struct spear_shirq spear310_shirq_ras2 = { | |||
98 | .offset = 8, | 130 | .offset = 8, |
99 | .nr_irqs = 5, | 131 | .nr_irqs = 5, |
100 | .mask = ((0x1 << 5) - 1) << 8, | 132 | .mask = ((0x1 << 5) - 1) << 8, |
133 | .irq_chip = &dummy_irq_chip, | ||
101 | .regs = { | 134 | .regs = { |
102 | .enb_reg = -1, | 135 | .enb_reg = -1, |
103 | .status_reg = SPEAR310_INT_STS_MASK_REG, | 136 | .status_reg = SPEAR310_INT_STS_MASK_REG, |
@@ -108,8 +141,8 @@ static struct spear_shirq spear310_shirq_ras3 = { | |||
108 | .offset = 13, | 141 | .offset = 13, |
109 | .nr_irqs = 1, | 142 | .nr_irqs = 1, |
110 | .mask = ((0x1 << 1) - 1) << 13, | 143 | .mask = ((0x1 << 1) - 1) << 13, |
144 | .irq_chip = &dummy_irq_chip, | ||
111 | .regs = { | 145 | .regs = { |
112 | .enb_reg = -1, | ||
113 | .status_reg = SPEAR310_INT_STS_MASK_REG, | 146 | .status_reg = SPEAR310_INT_STS_MASK_REG, |
114 | }, | 147 | }, |
115 | }; | 148 | }; |
@@ -118,8 +151,8 @@ static struct spear_shirq spear310_shirq_intrcomm_ras = { | |||
118 | .offset = 14, | 151 | .offset = 14, |
119 | .nr_irqs = 3, | 152 | .nr_irqs = 3, |
120 | .mask = ((0x1 << 3) - 1) << 14, | 153 | .mask = ((0x1 << 3) - 1) << 14, |
154 | .irq_chip = &dummy_irq_chip, | ||
121 | .regs = { | 155 | .regs = { |
122 | .enb_reg = -1, | ||
123 | .status_reg = SPEAR310_INT_STS_MASK_REG, | 156 | .status_reg = SPEAR310_INT_STS_MASK_REG, |
124 | }, | 157 | }, |
125 | }; | 158 | }; |
@@ -140,15 +173,14 @@ static struct spear_shirq spear320_shirq_ras3 = { | |||
140 | .offset = 0, | 173 | .offset = 0, |
141 | .nr_irqs = 7, | 174 | .nr_irqs = 7, |
142 | .mask = ((0x1 << 7) - 1) << 0, | 175 | .mask = ((0x1 << 7) - 1) << 0, |
143 | .disabled = 1, | ||
144 | }; | 176 | }; |
145 | 177 | ||
146 | static struct spear_shirq spear320_shirq_ras1 = { | 178 | static struct spear_shirq spear320_shirq_ras1 = { |
147 | .offset = 7, | 179 | .offset = 7, |
148 | .nr_irqs = 3, | 180 | .nr_irqs = 3, |
149 | .mask = ((0x1 << 3) - 1) << 7, | 181 | .mask = ((0x1 << 3) - 1) << 7, |
182 | .irq_chip = &dummy_irq_chip, | ||
150 | .regs = { | 183 | .regs = { |
151 | .enb_reg = -1, | ||
152 | .status_reg = SPEAR320_INT_STS_MASK_REG, | 184 | .status_reg = SPEAR320_INT_STS_MASK_REG, |
153 | }, | 185 | }, |
154 | }; | 186 | }; |
@@ -157,8 +189,8 @@ static struct spear_shirq spear320_shirq_ras2 = { | |||
157 | .offset = 10, | 189 | .offset = 10, |
158 | .nr_irqs = 1, | 190 | .nr_irqs = 1, |
159 | .mask = ((0x1 << 1) - 1) << 10, | 191 | .mask = ((0x1 << 1) - 1) << 10, |
192 | .irq_chip = &dummy_irq_chip, | ||
160 | .regs = { | 193 | .regs = { |
161 | .enb_reg = -1, | ||
162 | .status_reg = SPEAR320_INT_STS_MASK_REG, | 194 | .status_reg = SPEAR320_INT_STS_MASK_REG, |
163 | }, | 195 | }, |
164 | }; | 196 | }; |
@@ -167,8 +199,8 @@ static struct spear_shirq spear320_shirq_intrcomm_ras = { | |||
167 | .offset = 11, | 199 | .offset = 11, |
168 | .nr_irqs = 11, | 200 | .nr_irqs = 11, |
169 | .mask = ((0x1 << 11) - 1) << 11, | 201 | .mask = ((0x1 << 11) - 1) << 11, |
202 | .irq_chip = &dummy_irq_chip, | ||
170 | .regs = { | 203 | .regs = { |
171 | .enb_reg = -1, | ||
172 | .status_reg = SPEAR320_INT_STS_MASK_REG, | 204 | .status_reg = SPEAR320_INT_STS_MASK_REG, |
173 | }, | 205 | }, |
174 | }; | 206 | }; |
@@ -180,45 +212,6 @@ static struct spear_shirq *spear320_shirq_blocks[] = { | |||
180 | &spear320_shirq_intrcomm_ras, | 212 | &spear320_shirq_intrcomm_ras, |
181 | }; | 213 | }; |
182 | 214 | ||
183 | static void shirq_irq_mask_unmask(struct irq_data *d, bool mask) | ||
184 | { | ||
185 | struct spear_shirq *shirq = irq_data_get_irq_chip_data(d); | ||
186 | u32 val, offset = d->irq - shirq->virq_base; | ||
187 | unsigned long flags; | ||
188 | |||
189 | if (shirq->regs.enb_reg == -1) | ||
190 | return; | ||
191 | |||
192 | spin_lock_irqsave(&lock, flags); | ||
193 | val = readl(shirq->base + shirq->regs.enb_reg); | ||
194 | |||
195 | if (mask ^ shirq->regs.reset_to_enb) | ||
196 | val &= ~(0x1 << shirq->offset << offset); | ||
197 | else | ||
198 | val |= 0x1 << shirq->offset << offset; | ||
199 | |||
200 | writel(val, shirq->base + shirq->regs.enb_reg); | ||
201 | spin_unlock_irqrestore(&lock, flags); | ||
202 | |||
203 | } | ||
204 | |||
205 | static void shirq_irq_mask(struct irq_data *d) | ||
206 | { | ||
207 | shirq_irq_mask_unmask(d, 1); | ||
208 | } | ||
209 | |||
210 | static void shirq_irq_unmask(struct irq_data *d) | ||
211 | { | ||
212 | shirq_irq_mask_unmask(d, 0); | ||
213 | } | ||
214 | |||
215 | static struct irq_chip shirq_chip = { | ||
216 | .name = "spear-shirq", | ||
217 | .irq_ack = shirq_irq_mask, | ||
218 | .irq_mask = shirq_irq_mask, | ||
219 | .irq_unmask = shirq_irq_unmask, | ||
220 | }; | ||
221 | |||
222 | static void shirq_handler(unsigned irq, struct irq_desc *desc) | 215 | static void shirq_handler(unsigned irq, struct irq_desc *desc) |
223 | { | 216 | { |
224 | struct spear_shirq *shirq = irq_get_handler_data(irq); | 217 | struct spear_shirq *shirq = irq_get_handler_data(irq); |
@@ -240,7 +233,7 @@ static void __init spear_shirq_register(struct spear_shirq *shirq, | |||
240 | { | 233 | { |
241 | int i; | 234 | int i; |
242 | 235 | ||
243 | if (shirq->disabled) | 236 | if (!shirq->irq_chip) |
244 | return; | 237 | return; |
245 | 238 | ||
246 | irq_set_chained_handler(parent_irq, shirq_handler); | 239 | irq_set_chained_handler(parent_irq, shirq_handler); |
@@ -248,7 +241,7 @@ static void __init spear_shirq_register(struct spear_shirq *shirq, | |||
248 | 241 | ||
249 | for (i = 0; i < shirq->nr_irqs; i++) { | 242 | for (i = 0; i < shirq->nr_irqs; i++) { |
250 | irq_set_chip_and_handler(shirq->virq_base + i, | 243 | irq_set_chip_and_handler(shirq->virq_base + i, |
251 | &shirq_chip, handle_simple_irq); | 244 | shirq->irq_chip, handle_simple_irq); |
252 | set_irq_flags(shirq->virq_base + i, IRQF_VALID); | 245 | set_irq_flags(shirq->virq_base + i, IRQF_VALID); |
253 | irq_set_chip_data(shirq->virq_base + i, shirq); | 246 | irq_set_chip_data(shirq->virq_base + i, shirq); |
254 | } | 247 | } |