[PATCH 4/5] irqchip: add sa1100 driver
Add an irqchip driver for Intel StrongARM SA-11x0 family of chips. For now it is just a copy of the current arch/arm/mach-sa1100/irq.c driver. Signed-off-by: Dmitry Eremin-Solenikov --- drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sa11x0.c | 185 + include/linux/irqchip/irq-sa11x0.h | 18 3 files changed, 204 insertions(+) create mode 100644 drivers/irqchip/irq-sa11x0.c create mode 100644 include/linux/irqchip/irq-sa11x0.h diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 9516a32..b0d1dde 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o obj-$(CONFIG_ARCH_MEDIATEK)+= irq-mtk-sysirq.o +obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c new file mode 100644 index 000..c840187 --- /dev/null +++ b/drivers/irqchip/irq-sa11x0.c @@ -0,0 +1,185 @@ +/* + * drivers/irqchip/irq-sa11x0.c + * + * Copyright (C) 1999-2001 Nicolas Pitre + * + * Generic IRQ handling for the SA11x0. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ICIP 0x00 /* IC IRQ Pending reg. */ +#define ICMR 0x04 /* IC Mask Reg.*/ +#define ICLR 0x08 /* IC Level Reg. */ +#define ICCR 0x0C /* IC Control Reg. */ +#define ICFP 0x10 /* IC FIQ Pending reg. */ +#define ICPR 0x20 /* IC Pending Reg. */ + +static void __iomem *iobase; +static DEFINE_RAW_SPINLOCK(lock); + +/* + * We don't need to ACK IRQs on the SA1100 unless they're GPIOs + * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. + */ +static void sa1100_mask_irq(struct irq_data *d) +{ + u32 reg; + unsigned long flags; + + raw_spin_lock_irqsave(, flags); + + reg = readl_relaxed(iobase + ICMR); + reg &= ~BIT(d->hwirq); + writel_relaxed(reg, iobase + ICMR); + + raw_spin_unlock_irqrestore(, flags); +} + +static void sa1100_unmask_irq(struct irq_data *d) +{ + u32 reg; + unsigned long flags; + + raw_spin_lock_irqsave(, flags); + + reg = readl_relaxed(iobase + ICMR); + reg |= BIT(d->hwirq); + writel_relaxed(reg, iobase + ICMR); + + raw_spin_unlock_irqrestore(, flags); +} + +static int sa1100_set_wake(struct irq_data *d, unsigned int on) +{ + return sa11x0_sc_set_wake(d->hwirq, on); +} + +static struct irq_chip sa1100_normal_chip = { + .name = "SC", + .irq_ack= sa1100_mask_irq, + .irq_mask = sa1100_mask_irq, + .irq_unmask = sa1100_unmask_irq, + .irq_set_wake = sa1100_set_wake, +}; + +static int sa1100_normal_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, _normal_chip, +handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops sa1100_normal_irqdomain_ops = { + .map = sa1100_normal_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_domain *sa1100_normal_irqdomain; + +static struct sa1100irq_state { + unsigned intsaved; + unsigned inticmr; + unsigned inticlr; + unsigned inticcr; +} sa1100irq_state; + +static int sa1100irq_suspend(void) +{ + struct sa1100irq_state *st = _state; + + st->saved = 1; + st->icmr = readl_relaxed(iobase + ICMR); + st->iclr = readl_relaxed(iobase + ICLR); + st->iccr = readl_relaxed(iobase + ICCR); + + /* +* Disable all GPIO-based interrupts. +*/ + writel_relaxed(st->icmr & 0xf000, iobase + ICMR); + + return 0; +} + +static void sa1100irq_resume(void) +{ + struct sa1100irq_state *st = _state; + + if (st->saved) { + writel_relaxed(st->iccr, iobase + ICCR); + writel_relaxed(st->iclr, iobase + ICLR); + + writel_relaxed(st->icmr, iobase + ICMR); + } +} + +static struct syscore_ops sa1100irq_syscore_ops = { + .suspend= sa1100irq_suspend, + .resume = sa1100irq_resume, +}; + +static int __init sa1100irq_init_devicefs(void) +{ + register_syscore_ops(_syscore_ops); + return 0; +} + +device_initcall(sa1100irq_init_devicefs); + +static asmlinkage void __exception_irq_entry +sa1100_handle_irq(struct pt_regs *regs) +{ + uint32_t icip, icmr, mask; + + do { + icip = readl_relaxed(iobase + ICIP); + icmr =
[PATCH 4/5] irqchip: add sa1100 driver
Add an irqchip driver for Intel StrongARM SA-11x0 family of chips. For now it is just a copy of the current arch/arm/mach-sa1100/irq.c driver. Signed-off-by: Dmitry Eremin-Solenikov dbarysh...@gmail.com --- drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sa11x0.c | 185 + include/linux/irqchip/irq-sa11x0.h | 18 3 files changed, 204 insertions(+) create mode 100644 drivers/irqchip/irq-sa11x0.c create mode 100644 include/linux/irqchip/irq-sa11x0.h diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 9516a32..b0d1dde 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o obj-$(CONFIG_ARCH_MEDIATEK)+= irq-mtk-sysirq.o +obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c new file mode 100644 index 000..c840187 --- /dev/null +++ b/drivers/irqchip/irq-sa11x0.c @@ -0,0 +1,185 @@ +/* + * drivers/irqchip/irq-sa11x0.c + * + * Copyright (C) 1999-2001 Nicolas Pitre + * + * Generic IRQ handling for the SA11x0. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include linux/init.h +#include linux/module.h +#include linux/interrupt.h +#include linux/io.h +#include linux/irq.h +#include linux/irqdomain.h +#include linux/syscore_ops.h +#include linux/irqchip/irq-sa11x0.h + +#include asm/exception.h + +#define ICIP 0x00 /* IC IRQ Pending reg. */ +#define ICMR 0x04 /* IC Mask Reg.*/ +#define ICLR 0x08 /* IC Level Reg. */ +#define ICCR 0x0C /* IC Control Reg. */ +#define ICFP 0x10 /* IC FIQ Pending reg. */ +#define ICPR 0x20 /* IC Pending Reg. */ + +static void __iomem *iobase; +static DEFINE_RAW_SPINLOCK(lock); + +/* + * We don't need to ACK IRQs on the SA1100 unless they're GPIOs + * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. + */ +static void sa1100_mask_irq(struct irq_data *d) +{ + u32 reg; + unsigned long flags; + + raw_spin_lock_irqsave(lock, flags); + + reg = readl_relaxed(iobase + ICMR); + reg = ~BIT(d-hwirq); + writel_relaxed(reg, iobase + ICMR); + + raw_spin_unlock_irqrestore(lock, flags); +} + +static void sa1100_unmask_irq(struct irq_data *d) +{ + u32 reg; + unsigned long flags; + + raw_spin_lock_irqsave(lock, flags); + + reg = readl_relaxed(iobase + ICMR); + reg |= BIT(d-hwirq); + writel_relaxed(reg, iobase + ICMR); + + raw_spin_unlock_irqrestore(lock, flags); +} + +static int sa1100_set_wake(struct irq_data *d, unsigned int on) +{ + return sa11x0_sc_set_wake(d-hwirq, on); +} + +static struct irq_chip sa1100_normal_chip = { + .name = SC, + .irq_ack= sa1100_mask_irq, + .irq_mask = sa1100_mask_irq, + .irq_unmask = sa1100_unmask_irq, + .irq_set_wake = sa1100_set_wake, +}; + +static int sa1100_normal_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, sa1100_normal_chip, +handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops sa1100_normal_irqdomain_ops = { + .map = sa1100_normal_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_domain *sa1100_normal_irqdomain; + +static struct sa1100irq_state { + unsigned intsaved; + unsigned inticmr; + unsigned inticlr; + unsigned inticcr; +} sa1100irq_state; + +static int sa1100irq_suspend(void) +{ + struct sa1100irq_state *st = sa1100irq_state; + + st-saved = 1; + st-icmr = readl_relaxed(iobase + ICMR); + st-iclr = readl_relaxed(iobase + ICLR); + st-iccr = readl_relaxed(iobase + ICCR); + + /* +* Disable all GPIO-based interrupts. +*/ + writel_relaxed(st-icmr 0xf000, iobase + ICMR); + + return 0; +} + +static void sa1100irq_resume(void) +{ + struct sa1100irq_state *st = sa1100irq_state; + + if (st-saved) { + writel_relaxed(st-iccr, iobase + ICCR); + writel_relaxed(st-iclr, iobase + ICLR); + + writel_relaxed(st-icmr, iobase + ICMR); + } +} + +static struct syscore_ops sa1100irq_syscore_ops = { + .suspend= sa1100irq_suspend, + .resume = sa1100irq_resume, +}; + +static int __init sa1100irq_init_devicefs(void) +{ + register_syscore_ops(sa1100irq_syscore_ops); + return 0; +} + +device_initcall(sa1100irq_init_devicefs); + +static asmlinkage