diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 18:01:16 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 18:01:16 +0900 |
commit | ba463937ef75bceaf3943edf01f849257c68623a (patch) | |
tree | 42d8d401e2710b76d40943c4c45beab5cd084541 /arch/sh/kernel | |
parent | 5a4053b23262afefa748e1e4c439931d4c27693b (diff) | |
download | lwn-ba463937ef75bceaf3943edf01f849257c68623a.tar.gz lwn-ba463937ef75bceaf3943edf01f849257c68623a.zip |
sh: maskreg IRQ support.
Formerly implemented by ADX, we can use this generically,
so move it over.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/irq/Makefile | 5 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/irq/maskreg.c | 99 |
2 files changed, 102 insertions, 2 deletions
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index e3cccea15e1d..1c034c283f59 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile @@ -3,5 +3,6 @@ # obj-y += ipr.o imask.o -obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o -obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o +obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o +obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o +obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c new file mode 100644 index 000000000000..1cc0de15e4a6 --- /dev/null +++ b/arch/sh/kernel/cpu/irq/maskreg.c @@ -0,0 +1,99 @@ +/* + * Interrupt handling for Simple external interrupt mask register + * + * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp> + * + * This is for the machine which have single 16 bit register + * for masking external IRQ individually. + * Each bit of the register is for masking each interrupt. + * + * This file may be copied or modified under the terms of the GNU + * General Public License. See linux/COPYING for more information. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <asm/system.h> +#include <asm/io.h> + +/* address of external interrupt mask register */ +unsigned long irq_mask_register; + +/* forward declaration */ +static unsigned int startup_maskreg_irq(unsigned int irq); +static void shutdown_maskreg_irq(unsigned int irq); +static void enable_maskreg_irq(unsigned int irq); +static void disable_maskreg_irq(unsigned int irq); +static void mask_and_ack_maskreg(unsigned int); +static void end_maskreg_irq(unsigned int irq); + +/* hw_interrupt_type */ +static struct hw_interrupt_type maskreg_irq_type = { + .typename = "Mask Register", + .startup = startup_maskreg_irq, + .shutdown = shutdown_maskreg_irq, + .enable = enable_maskreg_irq, + .disable = disable_maskreg_irq, + .ack = mask_and_ack_maskreg, + .end = end_maskreg_irq +}; + +/* actual implementatin */ +static unsigned int startup_maskreg_irq(unsigned int irq) +{ + enable_maskreg_irq(irq); + return 0; /* never anything pending */ +} + +static void shutdown_maskreg_irq(unsigned int irq) +{ + disable_maskreg_irq(irq); +} + +static void disable_maskreg_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short val, mask = 0x01 << irq; + + BUG_ON(!irq_mask_register); + + /* Set "irq"th bit */ + local_irq_save(flags); + val = ctrl_inw(irq_mask_register); + val |= mask; + ctrl_outw(val, irq_mask_register); + local_irq_restore(flags); +} + +static void enable_maskreg_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short val, mask = ~(0x01 << irq); + + BUG_ON(!irq_mask_register); + + /* Clear "irq"th bit */ + local_irq_save(flags); + val = ctrl_inw(irq_mask_register); + val &= mask; + ctrl_outw(val, irq_mask_register); + local_irq_restore(flags); +} + +static void mask_and_ack_maskreg(unsigned int irq) +{ + disable_maskreg_irq(irq); +} + +static void end_maskreg_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_maskreg_irq(irq); +} + +void make_maskreg_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &maskreg_irq_type; + disable_maskreg_irq(irq); +} |