Blame view
drivers/irqchip/irq-renesas-intc-irqpin.c
16.6 KB
443580486 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 irqchip: renesas-... |
19 |
#include <linux/clk.h> |
443580486 irqchip: Renesas ... |
20 |
#include <linux/init.h> |
894db1642 irqchip: renesas-... |
21 |
#include <linux/of.h> |
443580486 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 irqchip: renesas-... |
32 |
#include <linux/of_device.h> |
705bc96c2 irqchip: renesas-... |
33 |
#include <linux/pm_runtime.h> |
443580486 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 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 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 irqchip: intc-irq... |
64 |
}; |
443580486 irqchip: Renesas ... |
65 66 67 |
struct intc_irqpin_irq { int hw_irq; |
33f958f2a irqchip: intc-irq... |
68 69 |
int requested_irq; int domain_irq; |
443580486 irqchip: Renesas ... |
70 |
struct intc_irqpin_priv *p; |
862d30988 irqchip: intc-irq... |
71 |
}; |
443580486 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 irqchip/renesas-i... |
76 |
unsigned int sense_bitfield_width; |
443580486 irqchip: Renesas ... |
77 78 79 |
struct platform_device *pdev; struct irq_chip irq_chip; struct irq_domain *irq_domain; |
705bc96c2 irqchip: renesas-... |
80 |
struct clk *clk; |
86e57ca73 irqchip/renesas-i... |
81 82 |
unsigned shared_irqs:1; unsigned needs_clk:1; |
427cc7202 irqchip: intc-irq... |
83 |
u8 shared_irq_mask; |
443580486 irqchip: Renesas ... |
84 |
}; |
86e57ca73 irqchip/renesas-i... |
85 |
struct intc_irqpin_config { |
e03f9088e irqchip: renesas-... |
86 |
unsigned int irlm_bit; |
86e57ca73 irqchip/renesas-i... |
87 88 |
unsigned needs_irlm:1; unsigned needs_clk:1; |
e03f9088e irqchip: renesas-... |
89 |
}; |
443580486 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 irqchip: intc-irq... |
114 |
|
443580486 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 irqchip: intc-irq... |
122 |
|
443580486 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 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 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 irqchip: renesas-... |
171 |
/* The SENSE register is assumed to be 32-bit. */ |
f9551a9c0 irqchip/renesas-i... |
172 |
int bitfield_width = p->sense_bitfield_width; |
e55bc5586 irqchip: renesas-... |
173 |
int shift = 32 - (irq + 1) * bitfield_width; |
443580486 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 irqchip: intc-irq... |
190 |
str, i->requested_irq, i->hw_irq, i->domain_irq); |
443580486 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 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 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 irqchip: intc-irq... |
234 |
int irq = p->irq[irqd_to_hwirq(d)].requested_irq; |
443580486 irqchip: Renesas ... |
235 236 |
intc_irqpin_irq_enable(d); |
d1b6aecde 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 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 irqchip: intc-irq... |
248 |
int irq = p->irq[irqd_to_hwirq(d)].requested_irq; |
443580486 irqchip: Renesas ... |
249 |
|
d1b6aecde 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 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 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 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 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 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 irqchip: intc-irq... |
309 |
generic_handle_irq(i->domain_irq); |
443580486 irqchip: Renesas ... |
310 311 312 313 |
return IRQ_HANDLED; } return IRQ_NONE; } |
427cc7202 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 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 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 irqchip: intc-irq... |
341 342 |
p->irq[hw].domain_irq = virq; p->irq[hw].hw_irq = hw; |
443580486 irqchip: Renesas ... |
343 344 |
intc_irqpin_dbg(&p->irq[hw], "map"); irq_set_chip_data(virq, h->host_data); |
769b5cf78 irqchip/renesas-i... |
345 |
irq_set_lockdep_class(virq, &intc_irqpin_irq_lock_class); |
443580486 irqchip: Renesas ... |
346 |
irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); |
443580486 irqchip: Renesas ... |
347 348 |
return 0; } |
960097365 irqchip: Constify... |
349 |
static const struct irq_domain_ops intc_irqpin_irq_domain_ops = { |
443580486 irqchip: Renesas ... |
350 |
.map = intc_irqpin_irq_domain_map, |
9d833bbe4 irqchip: intc-irq... |
351 |
.xlate = irq_domain_xlate_twocell, |
443580486 irqchip: Renesas ... |
352 |
}; |
86e57ca73 irqchip/renesas-i... |
353 |
static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = { |
e03f9088e irqchip: renesas-... |
354 |
.irlm_bit = 23, /* ICR0.IRLM0 */ |
86e57ca73 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 irqchip: renesas-... |
362 363 364 365 |
}; static const struct of_device_id intc_irqpin_dt_ids[] = { { .compatible = "renesas,intc-irqpin", }, |
26c21dd98 irqchip/renesas-i... |
366 367 |
{ .compatible = "renesas,intc-irqpin-r8a7778", .data = &intc_irqpin_irlm_r8a777x }, |
e03f9088e irqchip: renesas-... |
368 |
{ .compatible = "renesas,intc-irqpin-r8a7779", |
26c21dd98 irqchip/renesas-i... |
369 |
.data = &intc_irqpin_irlm_r8a777x }, |
86e57ca73 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 irqchip: renesas-... |
374 375 376 |
{}, }; MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids); |
443580486 irqchip: Renesas ... |
377 378 |
static int intc_irqpin_probe(struct platform_device *pdev) { |
86e57ca73 irqchip/renesas-i... |
379 |
const struct intc_irqpin_config *config = NULL; |
36845f1b5 irqchip: renesas-... |
380 |
struct device *dev = &pdev->dev; |
e03f9088e irqchip: renesas-... |
381 |
const struct of_device_id *of_id; |
443580486 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 irqchip: renesas-... |
389 |
const char *name = dev_name(dev); |
f9551a9c0 irqchip/renesas-i... |
390 |
bool control_parent; |
1affe5946 irqchip/renesas-i... |
391 |
unsigned int nirqs; |
427cc7202 irqchip: intc-irq... |
392 |
int ref_irq; |
443580486 irqchip: Renesas ... |
393 394 |
int ret; int k; |
36845f1b5 irqchip: renesas-... |
395 |
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); |
443580486 irqchip: Renesas ... |
396 |
if (!p) { |
36845f1b5 irqchip: renesas-... |
397 398 |
dev_err(dev, "failed to allocate driver data "); |
705bc96c2 irqchip: renesas-... |
399 |
return -ENOMEM; |
443580486 irqchip: Renesas ... |
400 401 402 |
} /* deal with driver instance configuration */ |
f9551a9c0 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 irqchip: Renesas ... |
408 409 410 |
p->pdev = pdev; platform_set_drvdata(pdev, p); |
86e57ca73 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 irqchip: renesas-... |
416 417 |
p->clk = devm_clk_get(dev, NULL); if (IS_ERR(p->clk)) { |
86e57ca73 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 irqchip: renesas-... |
424 425 426 427 428 |
p->clk = NULL; } pm_runtime_enable(dev); pm_runtime_get_sync(dev); |
e03f9088e irqchip: renesas-... |
429 430 |
/* get hold of register banks */ memset(io, 0, sizeof(io)); |
443580486 irqchip: Renesas ... |
431 432 |
for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k); |
e03f9088e irqchip: renesas-... |
433 |
if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) { |
36845f1b5 irqchip: renesas-... |
434 435 |
dev_err(dev, "not enough IOMEM resources "); |
443580486 irqchip: Renesas ... |
436 |
ret = -EINVAL; |
08eba5ba4 irqchip: intc-irq... |
437 |
goto err0; |
443580486 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 irqchip: Renesas ... |
446 |
p->irq[k].p = p; |
33f958f2a irqchip: intc-irq... |
447 |
p->irq[k].requested_irq = irq->start; |
443580486 irqchip: Renesas ... |
448 |
} |
1affe5946 irqchip/renesas-i... |
449 450 |
nirqs = k; if (nirqs < 1) { |
36845f1b5 irqchip: renesas-... |
451 452 |
dev_err(dev, "not enough IRQ resources "); |
443580486 irqchip: Renesas ... |
453 |
ret = -EINVAL; |
08eba5ba4 irqchip: intc-irq... |
454 |
goto err0; |
443580486 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 irqchip: renesas-... |
460 461 462 |
/* handle optional registers */ if (!io[k]) continue; |
443580486 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 irqchip: renesas-... |
475 476 |
dev_err(dev, "IOMEM size mismatch "); |
443580486 irqchip: Renesas ... |
477 |
ret = -EINVAL; |
08eba5ba4 irqchip: intc-irq... |
478 |
goto err0; |
443580486 irqchip: Renesas ... |
479 |
} |
36845f1b5 irqchip: renesas-... |
480 |
i->iomem = devm_ioremap_nocache(dev, io[k]->start, |
08eba5ba4 irqchip: intc-irq... |
481 |
resource_size(io[k])); |
443580486 irqchip: Renesas ... |
482 |
if (!i->iomem) { |
36845f1b5 irqchip: renesas-... |
483 484 |
dev_err(dev, "failed to remap IOMEM "); |
443580486 irqchip: Renesas ... |
485 |
ret = -ENXIO; |
08eba5ba4 irqchip: intc-irq... |
486 |
goto err0; |
443580486 irqchip: Renesas ... |
487 488 |
} } |
e03f9088e irqchip: renesas-... |
489 |
/* configure "individual IRQ mode" where needed */ |
86e57ca73 irqchip/renesas-i... |
490 |
if (config && config->needs_irlm) { |
e03f9088e irqchip: renesas-... |
491 492 |
if (io[INTC_IRQPIN_REG_IRLM]) intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM, |
86e57ca73 irqchip/renesas-i... |
493 |
config->irlm_bit, 1, 1); |
e03f9088e irqchip: renesas-... |
494 495 496 497 |
else dev_warn(dev, "unable to select IRLM mode "); } |
443580486 irqchip: Renesas ... |
498 |
/* mask all interrupts using priority */ |
1affe5946 irqchip/renesas-i... |
499 |
for (k = 0; k < nirqs; k++) |
443580486 irqchip: Renesas ... |
500 |
intc_irqpin_mask_unmask_prio(p, k, 1); |
427cc7202 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 irqchip/renesas-i... |
506 |
p->shared_irqs = 1; |
1affe5946 irqchip/renesas-i... |
507 |
for (k = 1; k < nirqs; k++) { |
427cc7202 irqchip: intc-irq... |
508 |
if (ref_irq != p->irq[k].requested_irq) { |
86e57ca73 irqchip/renesas-i... |
509 |
p->shared_irqs = 0; |
427cc7202 irqchip: intc-irq... |
510 511 512 |
break; } } |
443580486 irqchip: Renesas ... |
513 |
/* use more severe masking method if requested */ |
f9551a9c0 irqchip/renesas-i... |
514 |
if (control_parent) { |
443580486 irqchip: Renesas ... |
515 516 |
enable_fn = intc_irqpin_irq_enable_force; disable_fn = intc_irqpin_irq_disable_force; |
427cc7202 irqchip: intc-irq... |
517 |
} else if (!p->shared_irqs) { |
443580486 irqchip: Renesas ... |
518 519 |
enable_fn = intc_irqpin_irq_enable; disable_fn = intc_irqpin_irq_disable; |
427cc7202 irqchip: intc-irq... |
520 521 522 |
} else { enable_fn = intc_irqpin_shared_irq_enable; disable_fn = intc_irqpin_shared_irq_disable; |
443580486 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 irqchip: Renesas ... |
529 |
irq_chip->irq_set_type = intc_irqpin_irq_set_type; |
705bc96c2 irqchip: renesas-... |
530 531 |
irq_chip->irq_set_wake = intc_irqpin_irq_set_wake; irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; |
443580486 irqchip: Renesas ... |
532 |
|
1affe5946 irqchip/renesas-i... |
533 534 |
p->irq_domain = irq_domain_add_simple(dev->of_node, nirqs, 0, &intc_irqpin_irq_domain_ops, p); |
443580486 irqchip: Renesas ... |
535 536 |
if (!p->irq_domain) { ret = -ENXIO; |
36845f1b5 irqchip: renesas-... |
537 538 |
dev_err(dev, "cannot initialize irq domain "); |
08eba5ba4 irqchip: intc-irq... |
539 |
goto err0; |
443580486 irqchip: Renesas ... |
540 |
} |
427cc7202 irqchip: intc-irq... |
541 542 |
if (p->shared_irqs) { /* request one shared interrupt */ |
36845f1b5 irqchip: renesas-... |
543 |
if (devm_request_irq(dev, p->irq[0].requested_irq, |
427cc7202 irqchip: intc-irq... |
544 545 |
intc_irqpin_shared_irq_handler, IRQF_SHARED, name, p)) { |
36845f1b5 irqchip: renesas-... |
546 547 |
dev_err(dev, "failed to request low IRQ "); |
443580486 irqchip: Renesas ... |
548 |
ret = -ENOENT; |
08eba5ba4 irqchip: intc-irq... |
549 |
goto err1; |
443580486 irqchip: Renesas ... |
550 |
} |
427cc7202 irqchip: intc-irq... |
551 552 |
} else { /* request interrupts one by one */ |
1affe5946 irqchip/renesas-i... |
553 |
for (k = 0; k < nirqs; k++) { |
36845f1b5 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 irqchip: intc-irq... |
559 560 561 562 |
ret = -ENOENT; goto err1; } } |
443580486 irqchip: Renesas ... |
563 |
} |
427cc7202 irqchip: intc-irq... |
564 |
/* unmask all interrupts on prio level */ |
1affe5946 irqchip/renesas-i... |
565 |
for (k = 0; k < nirqs; k++) |
427cc7202 irqchip: intc-irq... |
566 |
intc_irqpin_mask_unmask_prio(p, k, 0); |
1affe5946 irqchip/renesas-i... |
567 568 |
dev_info(dev, "driving %d irqs ", nirqs); |
443580486 irqchip: Renesas ... |
569 |
|
443580486 irqchip: Renesas ... |
570 |
return 0; |
443580486 irqchip: Renesas ... |
571 |
err1: |
08eba5ba4 irqchip: intc-irq... |
572 |
irq_domain_remove(p->irq_domain); |
443580486 irqchip: Renesas ... |
573 |
err0: |
705bc96c2 irqchip: renesas-... |
574 575 |
pm_runtime_put(dev); pm_runtime_disable(dev); |
443580486 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 irqchip: Renesas ... |
582 583 |
irq_domain_remove(p->irq_domain); |
705bc96c2 irqchip: renesas-... |
584 585 |
pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); |
443580486 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 irqchip: intc-irq... |
594 |
.of_match_table = intc_irqpin_dt_ids, |
443580486 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"); |