summaryrefslogtreecommitdiff
path: root/arch/arm/mach-at91
diff options
context:
space:
mode:
authorLudovic Desroches <ludovic.desroches@atmel.com>2012-06-20 16:13:30 +0200
committerNicolas Ferre <nicolas.ferre@atmel.com>2012-07-02 14:26:58 +0200
commitf8a073ee378b9893aee0749c3868a6ecfb0c1636 (patch)
tree7d51d97410bb03bc6ca8b431b3df8592b206b7f7 /arch/arm/mach-at91
parentc65739437045c351a2a0ddb834719b9d616d4d47 (diff)
ARM: at91: add of irq priorities support
Add a third cell to define irq priority. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Reviewed-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'arch/arm/mach-at91')
-rw-r--r--arch/arm/mach-at91/include/mach/at91_aic.h3
-rw-r--r--arch/arm/mach-at91/irq.c34
2 files changed, 34 insertions, 3 deletions
diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
index c1413ed1172d..3af7272a4060 100644
--- a/arch/arm/mach-at91/include/mach/at91_aic.h
+++ b/arch/arm/mach-at91/include/mach/at91_aic.h
@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
.extern at91_aic_base
#endif
+#define AT91_AIC_IRQ_MIN_PRIORITY 0
+#define AT91_AIC_IRQ_MAX_PRIORITY 7
+
#define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
#define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
#define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index df8605fd7bad..db8e14112eda 100644
--- a/arch/arm/mach-at91/irq.c
+++ b/arch/arm/mach-at91/irq.c
@@ -30,6 +30,7 @@
#include <linux/of_irq.h>
#include <linux/irqdomain.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -42,6 +43,7 @@
void __iomem *at91_aic_base;
static struct irq_domain *at91_aic_domain;
static struct device_node *at91_aic_np;
+static unsigned int *at91_aic_irq_priorities;
static void at91_aic_mask_irq(struct irq_data *d)
{
@@ -177,8 +179,9 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
/* Put virq number in Source Vector Register */
at91_aic_write(AT91_AIC_SVR(hw), virq);
- /* Active Low interrupt, without priority */
- at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+ /* Active Low interrupt, with priority */
+ at91_aic_write(AT91_AIC_SMR(hw),
+ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
@@ -186,9 +189,28 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
return 0;
}
+static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+{
+ if (WARN_ON(intsize < 3))
+ return -EINVAL;
+ if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
+ return -EINVAL;
+ if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
+ || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
+ return -EINVAL;
+
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+ at91_aic_irq_priorities[*out_hwirq] = intspec[2];
+
+ return 0;
+}
+
static struct irq_domain_ops at91_aic_irq_ops = {
.map = at91_aic_irq_map,
- .xlate = irq_domain_xlate_twocell,
+ .xlate = at91_aic_irq_domain_xlate,
};
int __init at91_aic_of_init(struct device_node *node,
@@ -198,6 +220,12 @@ int __init at91_aic_of_init(struct device_node *node,
const __be32 *p;
u32 val;
+ at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
+ * sizeof(*at91_aic_irq_priorities),
+ GFP_KERNEL);
+ if (!at91_aic_irq_priorities)
+ return -ENOMEM;
+
at91_aic_base = of_iomap(node, 0);
at91_aic_np = node;