[PATCH 4/5] irqchip: add sa1100 driver

2015-01-15 Thread Dmitry Eremin-Solenikov
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

2015-01-15 Thread Dmitry Eremin-Solenikov
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