Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 216048
b: refs/heads/master
c: a405f83
h: refs/heads/master
v: v3
  • Loading branch information
Greg Ungerer committed Oct 21, 2010
1 parent 86fdfb9 commit 96af47b
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 730251f27df1ed0177609d1e49817f0c3ada0b1a
refs/heads/master: a405f833f4cd6490caaf381efe58a5628b545733
56 changes: 51 additions & 5 deletions trunk/arch/m68knommu/platform/5272/intc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/coldfire.h>
Expand All @@ -29,6 +30,10 @@
* via a set of 4 "Interrupt Controller Registers" (ICR). There is a
* loose mapping of vector number to register and internal bits, but
* a table is the easiest and quickest way to map them.
*
* Note that the external interrupts are edge triggered (unlike the
* internal interrupt sources which are level triggered). Which means
* they also need acknowledgeing via acknowledge bits.
*/
struct irqmap {
unsigned char icr;
Expand Down Expand Up @@ -68,6 +73,11 @@ static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
/*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
};

/*
* The act of masking the interrupt also has a side effect of 'ack'ing
* an interrupt on this irq (for the external irqs). So this mask function
* is also an ack_mask function.
*/
static void intc_irq_mask(unsigned int irq)
{
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
Expand Down Expand Up @@ -95,29 +105,57 @@ static void intc_irq_ack(unsigned int irq)
irq -= MCFINT_VECBASE;
if (intc_irqmap[irq].ack) {
u32 v;
v = 0xd << intc_irqmap[irq].index;
v = readl(MCF_MBAR + intc_irqmap[irq].icr);
v &= (0x7 << intc_irqmap[irq].index);
v |= (0x8 << intc_irqmap[irq].index);
writel(v, MCF_MBAR + intc_irqmap[irq].icr);
}
}
}

static int intc_irq_set_type(unsigned int irq, unsigned int type)
{
/* We can set the edge type here for external interrupts */
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
irq -= MCFINT_VECBASE;
if (intc_irqmap[irq].ack) {
u32 v;
v = readl(MCF_MBAR + MCFSIM_PITR);
if (type == IRQ_TYPE_EDGE_FALLING)
v &= ~(0x1 << (32 - irq));
else
v |= (0x1 << (32 - irq));
writel(v, MCF_MBAR + MCFSIM_PITR);
}
}
return 0;
}

/*
* Simple flow handler to deal with the external edge triggered interrupts.
* We need to be careful with the masking/acking due to the side effects
* of masking an interrupt.
*/
static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
{
kstat_incr_irqs_this_cpu(irq, desc);
desc->status |= IRQ_INPROGRESS;
desc->chip->ack(irq);
handle_IRQ_event(irq, desc->action);
desc->status &= ~IRQ_INPROGRESS;
}

static struct irq_chip intc_irq_chip = {
.name = "CF-INTC",
.mask = intc_irq_mask,
.unmask = intc_irq_unmask,
.mask_ack = intc_irq_mask,
.ack = intc_irq_ack,
.set_type = intc_irq_set_type,
};

void __init init_IRQ(void)
{
int irq;
int irq, edge;

init_vectors();

Expand All @@ -129,8 +167,16 @@ void __init init_IRQ(void)

for (irq = 0; (irq < NR_IRQS); irq++) {
set_irq_chip(irq, &intc_irq_chip);
set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
set_irq_handler(irq, handle_level_irq);
edge = 0;
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
if (edge) {
set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
set_irq_handler(irq, intc_external_irq);
} else {
set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
set_irq_handler(irq, handle_level_irq);
}
}
}

0 comments on commit 96af47b

Please sign in to comment.